plugin_trunk wip

This commit is contained in:
Thomas Ries 2015-09-19 12:56:27 +00:00
parent 36231e5d5c
commit 9c3dad1eb8
8 changed files with 241 additions and 112 deletions

View File

@ -83,8 +83,8 @@ static redirected_cache_element_t redirected_cache;
static int plugin_regex_init(void);
static int plugin_regex_process(sip_ticket_t *ticket);
static int plugin_regex_redirect(sip_ticket_t *ticket);
regmatch_t * rmatch (char *buf, int size, regex_t *re);
int rreplace (char *buf, int size, regex_t *re, regmatch_t pmatch[], char *rp);
static regmatch_t * rmatch (char *buf, int size, regex_t *re);
static int rreplace (char *buf, int size, regex_t *re, regmatch_t pmatch[], char *rp);
/*
@ -124,7 +124,7 @@ int PLUGIN_END(plugin_def_t *plugin_def){
/*
* Workload code
*/
int plugin_regex_init(void) {
static int plugin_regex_init(void) {
int i;
int sts, retsts;
int num_entries;
@ -370,7 +370,7 @@ static int plugin_regex_redirect(sip_ticket_t *ticket) {
* if a match is actually there.
*/
#define NMATCHES 10
regmatch_t * rmatch (char *buf, int size, regex_t *re) {
static regmatch_t * rmatch (char *buf, int size, regex_t *re) {
static regmatch_t pm[NMATCHES]; /* regoff_t is int so size is int */
/* perform the match */
@ -380,7 +380,7 @@ regmatch_t * rmatch (char *buf, int size, regex_t *re) {
return &pm[0];
}
int rreplace (char *buf, int size, regex_t *re, regmatch_t pmatch[], char *rp) {
static int rreplace (char *buf, int size, regex_t *re, regmatch_t pmatch[], char *rp) {
char *pos;
int sub, so, n;

View File

@ -24,6 +24,7 @@
#include "config.h"
#include <string.h>
#include <regex.h>
#include <sys/types.h>
#include <netinet/in.h>
@ -48,19 +49,26 @@ extern struct siproxd_config configuration;
static struct plugin_config {
stringa_t trunk_name;
stringa_t trunk_account;
stringa_t trunk_numbers;
stringa_t trunk_numbers_regex;
} plugin_cfg;
/* Instructions for config parser */
static cfgopts_t plugin_cfg_opts[] = {
{ "plugin_siptrunk_name", TYP_STRINGA,&plugin_cfg.trunk_name, {0, NULL} },
{ "plugin_siptrunk_account", TYP_STRINGA,&plugin_cfg.trunk_account, {0, NULL} },
{ "plugin_siptrunk_numbers", TYP_STRINGA,&plugin_cfg.trunk_numbers, {0, NULL} },
{ "plugin_siptrunk_numbers_regex", TYP_STRINGA,&plugin_cfg.trunk_numbers_regex, {0, NULL} },
{0, 0, 0}
};
/* local storage needed for regular expression handling */
static regex_t *re;
/* Prototypes */
static int sip_fix_topvia(sip_ticket_t *ticket);
static int plugin_siptrunk_init(void);
static int plugin_siptrunk_process(sip_ticket_t *ticket);
static regmatch_t * rmatch (char *buf, int size, regex_t *re);
//static int rreplace (char *buf, int size, regex_t *re, regmatch_t pmatch[], char *rp);
/*&&&+++
1) register
@ -119,8 +127,7 @@ int PLUGIN_INIT(plugin_def_t *plugin_def) {
return STS_FAILURE;
}
INFO("plugin_siptrunk is initialized");
return STS_SUCCESS;
return plugin_siptrunk_init();
}
/*
@ -129,43 +136,7 @@ int PLUGIN_INIT(plugin_def_t *plugin_def) {
*/
int PLUGIN_PROCESS(int stage, sip_ticket_t *ticket){
/* stage contains the PLUGIN_* value - the stage of SIP processing. */
int type;
osip_via_t *via;
struct sockaddr_in from;
type = ticket->direction;
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: type=%i", type);
/* Incoming SIP response? */
if (type == RESTYP_INCOMING) {
/* a Via header needs to be present in response */
if((via = osip_list_get(&(ticket->sipmsg->vias), 0)) == NULL) {
WARN("no Via header found in incoming SIP message");
return STS_SUCCESS;
}
/* check for Via IP in configured range */
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: processing VIA host [%s]",
via->host);
get_ip_by_host(via->host, &(from.sin_addr));
if ((plugin_cfg.networks != NULL) &&
(strcmp(plugin_cfg.networks, "") !=0) &&
(process_aclist(plugin_cfg.networks, ticket->from) == STS_SUCCESS) &&
(process_aclist(plugin_cfg.networks, from) == STS_SUCCESS)) {
/* VIA & Sender IP are in list, fix Via header */
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: replacing a bogus via");
if (sip_fix_topvia(ticket) == STS_FAILURE) {
ERROR("patching inbound Via failed!");
}
} else {
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: not match, returning.");
}
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: done");
}
return STS_SUCCESS;
return plugin_siptrunk_process(ticket);
}
/*
@ -175,39 +146,165 @@ DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: type=%i", type);
* connections, whatever the plugin messes around with)
*/
int PLUGIN_END(plugin_def_t *plugin_def){
INFO("plugin_siptrunk ends here");
return STS_SUCCESS;
}
/*--------------------------------------------------------------------*/
static int sip_fix_topvia(sip_ticket_t *ticket) {
osip_via_t *via;
int sts;
/*
* Workload code
*/
static int plugin_siptrunk_init(void) {
int i;
int sts, retsts;
int num_entries;
char errbuf[256];
if((via = osip_list_get(&(ticket->sipmsg->vias), 0)) != NULL) {
/* 1) IP of Via has been checked beforehand. */
retsts = STS_SUCCESS;
/* 2) remove broken via header */
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: removing topmost via");
sts = osip_list_remove(&(ticket->sipmsg->vias), 0);
osip_via_free (via);
via = NULL;
/* 3) add my via header */
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: adding new via");
if (ticket->direction == RESTYP_INCOMING) {
sts = sip_add_myvia(ticket, IF_OUTBOUND);
if (sts == STS_FAILURE) {
ERROR("adding my outbound via failed!");
}
} else {
sts = sip_add_myvia(ticket, IF_INBOUND);
if (sts == STS_FAILURE) {
ERROR("adding my inbound via failed!");
}
}
/* check for equal entries of trunk_name and trunk_account */
if (plugin_cfg.trunk_name.used != plugin_cfg.trunk_account.used) {
ERROR("Plugin '%s': number of trunks (%i) and number of "
"accounts (%i) differ!", name,
plugin_cfg.trunk_name.used, plugin_cfg.trunk_account.used);
return STS_FAILURE;
}
if (plugin_cfg.trunk_name.used != plugin_cfg.trunk_numbers_regex.used) {
ERROR("Plugin '%s': number of trunks (%i) and number of "
"number blocks (%i) differ!", name,
plugin_cfg.trunk_name.used, plugin_cfg.trunk_numbers_regex.used);
return STS_FAILURE;
}
/* allocate space for regexes and compile them */
num_entries = plugin_cfg.trunk_numbers_regex.used;
re = malloc(num_entries*sizeof(re[0]));
for (i=0; i < num_entries; i++) {
sts = regcomp (&re[i], plugin_cfg.trunk_numbers_regex.string[i],
REG_ICASE|REG_EXTENDED);
if (sts != 0) {
regerror(sts, &re[i], errbuf, sizeof(errbuf));
ERROR("Regular expression [%s] failed to compile: %s",
plugin_cfg.trunk_numbers_regex.string[i], errbuf);
retsts = STS_FAILURE;
}
}
return retsts;
}
static int plugin_siptrunk_process(sip_ticket_t *ticket) {
// int sts=STS_SUCCESS;
int i;
#define WORKSPACE_SIZE 128
// static char in[WORKSPACE_SIZE+1], rp[WORKSPACE_SIZE+1];
/* plugin loaded and not configured, return with success */
if (plugin_cfg.trunk_numbers_regex.used==0) return STS_SUCCESS;
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: type=%i", ticket->direction);
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: next hop was %s:%i",
utils_inet_ntoa(ticket->next_hop.sin_addr),
ticket->next_hop.sin_port);
#if 0
/* SIP request? && direction undetermined? */
if ((ticket->direction == DIRTYP_UNKNOWN)
&& MSG_IS_REQUEST(ticket->sipmsg)) {
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: processing DIRTYP_UNKNOWN REQ...");
// Loop through config array
for (i = 0; i < plugin_cfg.trunk_numbers_regex.used; i++) {
regmatch_t *pmatch = NULL;
// and check for regex match in To: header (or SIP URI?)
// if regex match, assume incoming request
pmatch = rmatch(url_string, WORKSPACE_SIZE, &re[i]);
if (pmatch == NULL) continue; /* no match, next */
/* have a match */
// set ticket->direction == REQTYPE_INCOMING
// eval next_hop (lookup internal UA) and set
// lookup internal target by account name from registration DB
// - ticket->next_hop.sin_addr
// - ticket->next_hop.sin_port
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: matched trunk on rule [%s]",
plugin_cfg.trunk_numbers_regex.string[i] );
/* only do first match, then break */
break;
}
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: next hop is now %s:%i",
utils_inet_ntoa(ticket->next_hop.sin_addr),
ticket->next_hop.sin_port);
} else {
DEBUGC(DBCLASS_PLUGIN, "plugin_siptrunk: not processing SIP message");
}
#endif
return STS_SUCCESS;
}
/*
* This regex replacement code has been proudly borrowed from
* http://www.daniweb.com/software-development/c/code/216955#
*
* buf: input string + output result
* rp: replacement string, will be destroyed during processing!
* size: size of buf and rp
* re: regex to process
*
* rmatch() performs the initial regexec match, and if a match is found
* it returns a pointer to the regmatch array which contains the result
* of the match.
* Afterwards rreplace() is to be called, providing this regmatch array.
*
* This eliminates the need to copy the 'rp' string before knowing
* if a match is actually there.
*/
#define NMATCHES 10
static regmatch_t * rmatch (char *buf, int size, regex_t *re) {
static regmatch_t pm[NMATCHES]; /* regoff_t is int so size is int */
/* perform the match */
if (regexec (re, buf, NMATCHES, pm, 0)) {
return NULL;
}
return &pm[0];
}
#if 0
static int rreplace (char *buf, int size, regex_t *re, regmatch_t pmatch[], char *rp) {
char *pos;
int sub, so, n;
/* match(es) found: */
for (pos = rp; *pos; pos++) {
/* back references \1 ... \9: expand them in 'rp' */
if (*pos == '\\' && *(pos + 1) > '0' && *(pos + 1) <= '9') {
so = pmatch[*(pos + 1) - 48].rm_so; /* pmatch[1..9] */
n = pmatch[*(pos + 1) - 48].rm_eo - so;
if (so < 0 || strlen (rp) + n - 1 > size) return STS_FAILURE;
memmove (pos + n, pos + 2, strlen (pos) - 1);
memmove (pos, buf + so, n);
pos = pos + n - 2;
}
}
sub = pmatch[1].rm_so; /* no repeated replace when sub >= 0 */
/* and replace rp in the input buffer */
for (pos = buf; !regexec (re, pos, 1, pmatch, 0); ) {
n = pmatch[0].rm_eo - pmatch[0].rm_so;
pos += pmatch[0].rm_so;
if (strlen (buf) - n + strlen (rp) > size) {
return STS_FAILURE;
}
memmove (pos + strlen (rp), pos + n, strlen (pos) - n + 1);
memmove (pos, rp, strlen (rp));
pos += strlen (rp);
if (sub >= 0) break;
}
return STS_SUCCESS;
}
#endif

View File

@ -79,8 +79,6 @@ int proxy_request (sip_ticket_t *ticket) {
int i;
int sts;
int type;
struct in_addr sendto_addr;
int port;
char *buffer;
size_t buflen;
osip_message_t *request;
@ -345,30 +343,37 @@ sts=sip_obscure_callid(ticket);
* Proxy Behavior - Determine Next-Hop Address
*/
/*&&&& priority probably should be:
* 1) Route header
* 2) fixed outbound proxy
* 3) SIP URI
* 1) an already defined next-hop in ticket->next_hop
* 2) Route header
* 3) fixed outbound proxy
* 4) SIP URI
*/
/* predefined next-hop present? */
if (is_empty_sockaddr(&ticket->next_hop) == STS_FAILURE) {
DEBUGC(DBCLASS_PROXY, "proxy_request: pre-set next-hop: %s:%i",
utils_inet_ntoa(ticket->next_hop.sin_addr), ticket->next_hop.sin_port);
/*
* Route present?
* If so, fetch address from topmost Route: header and remove it.
*/
if ((type == REQTYP_OUTGOING) &&
} else if ((type == REQTYP_OUTGOING) &&
(!osip_list_eol(&(request->routes), 0))) {
sts=route_determine_nexthop(ticket, &sendto_addr, &port);
sts=route_determine_nexthop(ticket, &ticket->next_hop.sin_addr,
&ticket->next_hop.sin_port);
if (sts == STS_FAILURE) {
DEBUGC(DBCLASS_PROXY, "proxy_request: route_determine_nexthop failed");
return STS_FAILURE;
}
DEBUGC(DBCLASS_PROXY, "proxy_request: have Route header to %s:%i",
utils_inet_ntoa(sendto_addr), port);
utils_inet_ntoa(ticket->next_hop.sin_addr), ticket->next_hop.sin_port);
/*
* fixed or domain outbound proxy defined ?
*/
} else if ((type == REQTYP_OUTGOING) &&
(sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) {
(sip_find_outbound_proxy(ticket, &ticket->next_hop.sin_addr, &ticket->next_hop.sin_port) == STS_SUCCESS)) {
DEBUGC(DBCLASS_PROXY, "proxy_request: have outbound proxy %s:%i",
utils_inet_ntoa(sendto_addr), port);
utils_inet_ntoa(ticket->next_hop.sin_addr), ticket->next_hop.sin_port);
/*
* destination from SIP URI
*/
@ -379,7 +384,7 @@ In a first implementation we may just try to get the lowest priority,
max weighted '_sip._udp.domain' entry and port number.
No load balancing and no failover are supported with this.
&&&*/
sts = get_ip_by_host(request->req_uri->host, &sendto_addr);
sts = get_ip_by_host(request->req_uri->host, &ticket->next_hop.sin_addr);
if (sts == STS_FAILURE) {
DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]",
request->req_uri->host);
@ -387,13 +392,15 @@ No load balancing and no failover are supported with this.
}
if (request->req_uri->port) {
port=atoi(request->req_uri->port);
if ((port<=0) || (port>65535)) port=SIP_PORT;
ticket->next_hop.sin_port=atoi(request->req_uri->port);
if (ticket->next_hop.sin_port != 0) {
ticket->next_hop.sin_port=SIP_PORT;
}
} else {
port=SIP_PORT;
ticket->next_hop.sin_port=SIP_PORT;
}
DEBUGC(DBCLASS_PROXY, "proxy_request: have SIP URI to %s:%i",
request->req_uri->host, port);
utils_inet_ntoa(ticket->next_hop.sin_addr), ticket->next_hop.sin_port);
}
/*
@ -432,7 +439,8 @@ No load balancing and no failover are supported with this.
return STS_FAILURE;
}
sipsock_send(sendto_addr, port, ticket->protocol, buffer, buflen);
sipsock_send(ticket->next_hop.sin_addr, ticket->next_hop.sin_port,
ticket->protocol, buffer, buflen);
osip_free (buffer);
/*
@ -469,9 +477,7 @@ No load balancing and no failover are supported with this.
int proxy_response (sip_ticket_t *ticket) {
int sts;
int type;
struct in_addr sendto_addr;
osip_via_t *via;
int port;
char *buffer;
size_t buflen;
osip_message_t *response;
@ -663,38 +669,45 @@ sts=sip_obscure_callid(ticket);
* Determine Next-Hop Address
*/
/*&&&& priority probably should be:
* 0) rport=;received= header (TCP only for now)
* 1) Route header
* 2) fixed outbound proxy
* 3) Via header
* 1) an already defined next-hop in ticket->next_hop
* 2) rport=;received= header (TCP only for now)
* 3) Route header
* 4) fixed outbound proxy
* 5) Via header
*/
/* predefined next-hop present? */
if (is_empty_sockaddr(&ticket->next_hop) == STS_FAILURE) {
DEBUGC(DBCLASS_PROXY, "proxy_request: pre-set next-hop: %s:%i",
utils_inet_ntoa(ticket->next_hop.sin_addr), ticket->next_hop.sin_port);
/*
* IF TCP, check for rport=x;received=y parameters in VIA
*/
if ((ticket->protocol == PROTO_TCP) &&
(sip_get_received_param(ticket, &sendto_addr, &port) == STS_SUCCESS)) {
} else if ((ticket->protocol == PROTO_TCP) &&
(sip_get_received_param(ticket, &ticket->next_hop.sin_addr, &ticket->next_hop.sin_port) == STS_SUCCESS)) {
DEBUGC(DBCLASS_PROXY, "proxy_response: have received/rport to %s:%i",
utils_inet_ntoa(sendto_addr), port);
utils_inet_ntoa(ticket->next_hop.sin_addr),
ticket->next_hop.sin_port);
/*
* Route present?
* If so, fetch address from topmost Route: header and remove it.
*/
} else if ((type == RESTYP_OUTGOING) &&
(!osip_list_eol(&(response->routes), 0))) {
sts=route_determine_nexthop(ticket, &sendto_addr, &port);
sts=route_determine_nexthop(ticket, &ticket->next_hop.sin_addr, &ticket->next_hop.sin_port);
if (sts == STS_FAILURE) {
DEBUGC(DBCLASS_PROXY, "proxy_response: route_determine_nexthop failed");
return STS_FAILURE;
}
DEBUGC(DBCLASS_PROXY, "proxy_response: have Route header to %s:%i",
utils_inet_ntoa(sendto_addr), port);
utils_inet_ntoa(ticket->next_hop.sin_addr),
ticket->next_hop.sin_port);
/*
* check if we need to send to an outbound proxy
*/
} else if ((type == RESTYP_OUTGOING) &&
(sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) {
(sip_find_outbound_proxy(ticket, &ticket->next_hop.sin_addr, &ticket->next_hop.sin_port) == STS_SUCCESS)) {
DEBUGC(DBCLASS_PROXY, "proxy_response: have outbound proxy %s:%i",
utils_inet_ntoa(sendto_addr), port);
utils_inet_ntoa(ticket->next_hop.sin_addr), ticket->next_hop.sin_port);
} else {
/* get target address and port from VIA header */
via = (osip_via_t *) osip_list_get (&(response->vias), 0);
@ -703,7 +716,7 @@ sts=sip_obscure_callid(ticket);
return STS_FAILURE;
}
sts = get_ip_by_host(via->host, &sendto_addr);
sts = get_ip_by_host(via->host, &ticket->next_hop.sin_addr);
if (sts == STS_FAILURE) {
DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve VIA [%s]",
via->host);
@ -711,10 +724,12 @@ sts=sip_obscure_callid(ticket);
}
if (via->port) {
port=atoi(via->port);
if ((port<=0) || (port>65535)) port=SIP_PORT;
ticket->next_hop.sin_port=atoi(via->port);
if (ticket->next_hop.sin_port != 0) {
ticket->next_hop.sin_port=SIP_PORT;
}
} else {
port=SIP_PORT;
ticket->next_hop.sin_port=SIP_PORT;
}
}
@ -730,7 +745,7 @@ sts=sip_obscure_callid(ticket);
return STS_FAILURE;
}
sipsock_send(sendto_addr, port, ticket->protocol, buffer, buflen);
sipsock_send(ticket->next_hop.sin_addr, ticket->next_hop.sin_port, ticket->protocol, buffer, buflen);
osip_free (buffer);
return STS_SUCCESS;
}

View File

@ -365,7 +365,7 @@ int route_purge_recordroute(sip_ticket_t *ticket){
* STS_SUCCESS on success
*/
int route_determine_nexthop(sip_ticket_t *ticket,
struct in_addr *dest, int *port){
struct in_addr *dest, in_port_t *port){
int sts;
osip_message_t *mymsg=ticket->sipmsg;
osip_route_t *route=NULL;

View File

@ -883,7 +883,7 @@ int sip_calculate_branch_id (sip_ticket_t *ticket, char *id) {
* STS_FAILURE if no outbound proxy to be used
*/
int sip_find_outbound_proxy(sip_ticket_t *ticket, struct in_addr *addr,
int *port) {
in_port_t *port) {
int i, sts;
char *domain=NULL;
osip_message_t *sipmsg;
@ -1450,7 +1450,7 @@ int sip_add_received_param(sip_ticket_t *ticket){
* STS_SUCCESS on success
*/
int sip_get_received_param(sip_ticket_t *ticket,
struct in_addr *dest, int *port) {
struct in_addr *dest, in_port_t *port) {
osip_via_t *via;
osip_generic_param_t *received=NULL;
osip_generic_param_t *rport=NULL;

View File

@ -386,6 +386,7 @@ int main (int argc, char *argv[])
buflen = (size_t)sts;
DEBUGC(DBCLASS_BABBLE,"received %zd bytes of data", buflen);
ticket.direction=0;
memset(&ticket.next_hop, 0, sizeof(ticket.next_hop));
buff[buflen]='\0';
/* pointers in ticket to raw message */

View File

@ -138,6 +138,7 @@ typedef struct {
#define RESTYP_INCOMING 3
#define RESTYP_OUTGOING 4
int direction; /* direction as determined by proxy */
struct sockaddr_in next_hop; /* next hop as determined by plugin or proxy */
} sip_ticket_t;
@ -191,7 +192,7 @@ int route_add_recordroute(sip_ticket_t *ticket); /*X*/
int route_purge_recordroute(sip_ticket_t *ticket); /*X*/
int route_postprocess(sip_ticket_t *ticket); /*X*/
int route_determine_nexthop(sip_ticket_t *ticket,
struct in_addr *dest, int *port); /*X*/
struct in_addr *dest, in_port_t *port); /*X*/
/* utils.c */
int get_ip_by_host(char *hostname, struct in_addr *addr); /*X*/
@ -203,6 +204,7 @@ char *utils_inet_ntoa(struct in_addr in);
int utils_inet_aton(const char *cp, struct in_addr *inp);
int createpidfile(char *pidfilename); /*X*/
int compare_client_id(client_id_t cid1, client_id_t cid2); /*X*/
int is_empty_sockaddr(struct sockaddr_in *sockaddr); /*X*/
/* sip_utils.c */
osip_message_t * msg_make_template_reply (sip_ticket_t *ticket, int code);
@ -217,13 +219,13 @@ int sip_del_myvia (sip_ticket_t *ticket); /*X*/
int sip_rewrite_contact (sip_ticket_t *ticket, int direction); /*X*/
int sip_calculate_branch_id (sip_ticket_t *ticket, char *id); /*X*/
int sip_find_outbound_proxy(sip_ticket_t *ticket, struct in_addr *addr,
int *port); /*X*/
in_port_t *port); /*X*/
int sip_find_direction(sip_ticket_t *ticket, int *urlidx); /*X*/
int sip_fixup_asterisk(char *buff, size_t *buflen); /*X*/
int sip_obscure_callid(sip_ticket_t *ticket); /*X*/
int sip_add_received_param(sip_ticket_t *ticket); /*X*/
int sip_get_received_param(sip_ticket_t *ticket,
struct in_addr *dest, int *port); /*X*/
struct in_addr *dest, in_port_t *port); /*X*/
/* readconf.c */
int read_config(char *name, int search, cfgopts_t cfgopts[], char *filter); /*X*/

View File

@ -678,3 +678,17 @@ int compare_client_id(client_id_t cid1, client_id_t cid2) {
DEBUGC(DBCLASS_BABBLE, "compare_client_id: no match");
return STS_FAILURE;
}
/*
* check a sockaddr_in structure for bein zero / non-zero
*/
int is_empty_sockaddr(struct sockaddr_in *sockaddr) {
int i;
char *p=(char*)sockaddr;
for (i=0; i < sizeof(struct sockaddr_in); i++) {
if (p[i] != 0x00) { return STS_FAILURE; }
}
return STS_SUCCESS;
}