diff options
-rwxr-xr-x | acl.c | 117 | ||||
-rwxr-xr-x | channels/chan_iax2.c | 167 | ||||
-rwxr-xr-x | channels/iax2-parser.h | 2 | ||||
-rwxr-xr-x | configs/iax.conf.sample | 6 | ||||
-rwxr-xr-x | include/asterisk/acl.h | 20 | ||||
-rwxr-xr-x | include/asterisk/astobj.h | 1 |
6 files changed, 230 insertions, 83 deletions
@@ -21,6 +21,7 @@ #include <asterisk/acl.h> #include <asterisk/logger.h> #include <asterisk/channel.h> +#include <asterisk/options.h> #include <asterisk/utils.h> #include <asterisk/lock.h> #include <asterisk/srv.h> @@ -42,6 +43,13 @@ AST_MUTEX_DEFINE_STATIC(routeseq_lock); #include <sys/sockio.h> #endif +struct ast_netsock { + ASTOBJ_COMPONENTS(struct ast_netsock); + struct sockaddr_in bindaddr; + int sockfd; + int *ioref; + struct io_context *ioc; +}; struct ast_ha { @@ -222,7 +230,8 @@ int ast_get_ip(struct sockaddr_in *sin, const char *value) } /* iface is the interface (e.g. eth0); address is the return value */ -int ast_lookup_iface(char *iface, struct in_addr *address) { +int ast_lookup_iface(char *iface, struct in_addr *address) +{ int mysock, res = 0; struct my_ifreq ifreq; @@ -254,8 +263,8 @@ int ast_ouraddrfor(struct in_addr *them, struct in_addr *us) ast_log(LOG_WARNING, "Cannot create socket\n"); return -1; } - sin.sin_family = AF_INET; - sin.sin_port = 5060; + sin.sin_family = AF_INET; + sin.sin_port = 5060; sin.sin_addr = *them; if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) { ast_log(LOG_WARNING, "Cannot connect\n"); @@ -272,3 +281,105 @@ int ast_ouraddrfor(struct in_addr *them, struct in_addr *us) *us = sin.sin_addr; return 0; } + +int ast_netsock_sockfd(struct ast_netsock *ns) +{ + if (ns) + return ns->sockfd; + return -1; +} + +struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct sockaddr_in *bindaddr, int tos, ast_io_cb callback, void *data) +{ + int netsocket = -1; + int *ioref; + char iabuf[INET_ADDRSTRLEN]; + + struct ast_netsock *ns; + + /* Make a UDP socket */ + netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + + if (netsocket < 0) { + ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); + return NULL; + } + if (bind(netsocket,(struct sockaddr *)bindaddr, sizeof(struct sockaddr_in))) { + ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr->sin_addr), ntohs(bindaddr->sin_port), strerror(errno)); + close(netsocket); + return NULL; + } + if (option_verbose > 1) + ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos); + + if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) + ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos); + + /* Establish I/O callback for socket read */ + ioref = ast_io_add(ioc, netsocket, callback, AST_IO_IN, data); + if (!ioref) { + ast_log(LOG_WARNING, "Out of memory!\n"); + close(netsocket); + return NULL; + } + + ns = malloc(sizeof(struct ast_netsock)); + if (ns) { + ASTOBJ_INIT(ns); + ns->ioref = ioref; + ns->ioc = ioc; + ns->sockfd = netsocket; + memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr)); + ASTOBJ_CONTAINER_LINK(list, ns); + } else { + ast_log(LOG_WARNING, "Out of memory!\n"); + ast_io_remove(ioc, ioref); + close(netsocket); + } + return ns; +} + +static void ast_netsock_destroy(struct ast_netsock *netsock) +{ + ast_io_remove(netsock->ioc, netsock->ioref); + close(netsock->sockfd); + free(netsock); +} + +int ast_netsock_init(struct ast_netsock_list *list) +{ + memset(list, 0, sizeof(struct ast_netsock_list)); + ASTOBJ_CONTAINER_INIT(list); + return 0; +} + +int ast_netsock_release(struct ast_netsock_list *list) +{ + ASTOBJ_CONTAINER_DESTROYALL(list, ast_netsock_destroy); + ASTOBJ_CONTAINER_DESTROY(list); + return 0; +} + +struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_context *ioc, const char *bindinfo, int defaultport, int tos, ast_io_cb callback, void *data) +{ + struct sockaddr_in sin; + char *tmp; + char *port; + int portno; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(defaultport); + tmp = ast_strdupa(bindinfo); + if (tmp) { + port = strchr(tmp, ':'); + if (port) { + *port = '\0'; + port++; + if ((portno = atoi(port)) > 0) + sin.sin_port = htons(portno); + } + return ast_netsock_bindaddr(list, ioc, &sin, tos, callback, data); + } else + ast_log(LOG_WARNING, "Out of memory!\n"); + return NULL; +} diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 73fef3be2..f04e5f9cd 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -128,14 +128,15 @@ static int iaxdefaultdpcache=10 * 60; /* Cache dialplan entries for 10 minutes b static int iaxdefaulttimeout = 5; /* Default to wait no more than 5 seconds for a reply to come back */ -static int netsocket = -1; - static int tos = 0; static int expirey = IAX_DEFAULT_REG_EXPIRE; static int timingfd = -1; /* Timing file descriptor */ +static struct ast_netsock_list netsock; +static int defaultsockfd = -1; + static int usecnt; AST_MUTEX_DEFINE_STATIC(usecnt_lock); @@ -242,6 +243,7 @@ struct iax2_peer { struct ast_codec_pref prefs; struct sockaddr_in addr; int formats; + int sockfd; /* Socket to use for transmission */ struct in_addr mask; unsigned int flags; @@ -274,6 +276,7 @@ struct iax2_peer { static struct iax2_trunk_peer { ast_mutex_t lock; + int sockfd; struct sockaddr_in addr; struct timeval txtrunktime; /* Transmit trunktime */ struct timeval rxtrunktime; /* Receive trunktime */ @@ -351,9 +354,8 @@ static int max_jitter_buffer = MAX_JITTER_BUFFER; static int min_jitter_buffer = MIN_JITTER_BUFFER; struct chan_iax2_pvt { - /* Pipes for communication. pipe[1] belongs to the - network thread (write), and pipe[0] belongs to the individual - channel (read) */ + /* Socket to send/receive on for this call */ + int sockfd; /* Last received voice format */ int voiceformat; /* Last received voice format */ @@ -865,7 +867,7 @@ static int make_trunk(unsigned short callno, int locked) return res; } -static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer) +static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd) { int res = 0; int x; @@ -915,6 +917,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc if (iaxs[x]) { if (option_debug) ast_log(LOG_DEBUG, "Creating new call structure %d\n", x); + iaxs[x]->sockfd = sockfd; iaxs[x]->addr.sin_port = sin->sin_port; iaxs[x]->addr.sin_family = sin->sin_family; iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr; @@ -1292,10 +1295,10 @@ static int handle_error(void) return 0; } -static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin) +static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin, int sockfd) { int res; - res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)sin, + res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin, sizeof(*sin)); if (res < 0) { if (option_debug) @@ -1325,12 +1328,12 @@ static int send_packet(struct iax_frame *f) if (f->transfer) { if (iaxdebug) iax_showframe(f, NULL, 0, &iaxs[f->callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr)); - res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->transfer, + res = sendto(iaxs[f->callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->transfer, sizeof(iaxs[f->callno]->transfer)); } else { if (iaxdebug) iax_showframe(f, NULL, 0, &iaxs[f->callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr)); - res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->addr, + res = sendto(iaxs[f->callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->addr, sizeof(iaxs[f->callno]->addr)); } if (res < 0) { @@ -2218,7 +2221,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk, int *notransfer, int *usejitterbuf, int *encmethods, char *username, int usernlen, char *secret, int seclen, - int *ofound, char *peercontext, char *timezone, int tzlen, char *pref_str, size_t pref_size) + int *ofound, char *peercontext, char *timezone, int tzlen, char *pref_str, size_t pref_size, + int *sockfd) { struct ast_hostent ahp; struct hostent *hp; struct iax2_peer *p; @@ -2229,6 +2233,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, *maxtime = 0; if (trunk) *trunk = 0; + if (sockfd) + *sockfd = defaultsockfd; sin->sin_family = AF_INET; ast_mutex_lock(&peerl.lock); p = peerl.peers; @@ -2272,6 +2278,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, sin->sin_addr = p->defaddr.sin_addr; sin->sin_port = p->defaddr.sin_port; } + if (sockfd) + *sockfd = p->sockfd; if (notransfer) *notransfer = ast_test_flag(p, IAX_NOTRANSFER); if (usejitterbuf) @@ -2425,7 +2433,7 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout) strsep(&stringp, ":"); portno = strsep(&stringp, ":"); } - if (create_addr(&sin, NULL, NULL, NULL, hname, context, NULL, NULL, NULL, &encmethods, storedusern, sizeof(storedusern) - 1, storedsecret, sizeof(storedsecret) - 1, NULL, peercontext, tz, sizeof(tz), out_prefs, sizeof(out_prefs))) { + if (create_addr(&sin, NULL, NULL, NULL, hname, context, NULL, NULL, NULL, &encmethods, storedusern, sizeof(storedusern) - 1, storedsecret, sizeof(storedsecret) - 1, NULL, peercontext, tz, sizeof(tz), out_prefs, sizeof(out_prefs), NULL)) { ast_log(LOG_WARNING, "No address associated with '%s'\n", hname); return -1; } @@ -3119,7 +3127,7 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset) return ms; } -static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin) +static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd) { struct iax2_trunk_peer *tpeer; char iabuf[INET_ADDRSTRLEN]; @@ -3144,6 +3152,7 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin) gettimeofday(&tpeer->trunkact, NULL); ast_mutex_lock(&tpeer->lock); tpeer->next = tpeers; + tpeer->sockfd = fd; tpeers = tpeer; ast_log(LOG_DEBUG, "Created trunk peer for '%s:%d'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port)); } @@ -3158,7 +3167,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct ast_frame *f) void *tmp, *ptr; struct ast_iax2_meta_trunk_entry *met; char iabuf[INET_ADDRSTRLEN]; - tpeer = find_tpeer(&pvt->addr); + tpeer = find_tpeer(&pvt->addr, pvt->sockfd); if (tpeer) { if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) { /* Need to reallocate space */ @@ -4148,7 +4157,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies return res; } -static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst) +static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst, int sockfd) { struct ast_iax2_full_hdr fh; char iabuf[INET_ADDRSTRLEN]; @@ -4164,7 +4173,7 @@ static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned shor #endif ast_log(LOG_DEBUG, "Raw Hangup %s:%d, src=%d, dst=%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), src, dst); - return sendto(netsocket, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin)); + return sendto(sockfd, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin)); } static void merge_encryption(struct chan_iax2_pvt *p, unsigned int enc) @@ -4849,7 +4858,7 @@ static void reg_source_db(struct iax2_peer *p) } } -static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype) +static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype, int fd) { /* Called from IAX thread only, with proper iaxsl lock */ struct iax_ie_data ied; @@ -4893,6 +4902,8 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char /* Verify that the host is really there */ iax2_poke_peer(p, callno); } + /* Store socket fd */ + p->sockfd = fd; /* Setup the expirey */ if (p->expire > -1) ast_sched_del(sched, p->expire); @@ -5161,7 +5172,7 @@ static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now) #if 0 ast_log(LOG_DEBUG, "Trunking %d calls in %d bytes, ts=%d\n", calls, fr->datalen, ntohl(mth->ts)); #endif - res = transmit_trunk(fr, &tpeer->addr); + res = transmit_trunk(fr, &tpeer->addr, tpeer->sockfd); calls = tpeer->calls; /* Reset transmit trunk side data */ tpeer->trunkdatalen = 0; @@ -5462,7 +5473,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata) dblbuf[0] = 0; /* Keep GCC from whining */ fr.callno = 0; - res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len); + res = recvfrom(fd, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len); if (res < 0) { if (errno != ECONNREFUSED) ast_log(LOG_WARNING, "Error: %s\n", strerror(errno)); @@ -5475,7 +5486,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata) } if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) { /* This is a video frame, get call number */ - fr.callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, 1); + fr.callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, 1, fd); minivid = 1; } else if (meta->zeros == 0) { /* This is a meta header */ @@ -5489,7 +5500,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata) ts = ntohl(mth->ts); res -= (sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr)); ptr = mth->data; - tpeer = find_tpeer(&sin); + tpeer = find_tpeer(&sin, fd); if (!tpeer) { ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); return 1; @@ -5510,7 +5521,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata) /* Stop if we don't have enough data */ if (len > res) break; - fr.callno = find_callno(ntohs(mte->callno) & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1); + fr.callno = find_callno(ntohs(mte->callno) & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1, fd); if (fr.callno) { ast_mutex_lock(&iaxsl[fr.callno]); /* If it's a valid call, deliver the contents. If not, we @@ -5590,7 +5601,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata) } if (!fr.callno) - fr.callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, 1); + fr.callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, 1, fd); if (fr.callno > 0) ast_mutex_lock(&iaxsl[fr.callno]); @@ -5605,8 +5616,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata) (f.subclass != IAX_COMMAND_TXACC) && (f.subclass != IAX_COMMAND_FWDOWNL))|| (f.frametype != AST_FRAME_IAX)) - raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL - ); + raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL, + fd); } if (fr.callno > 0) ast_mutex_unlock(&iaxsl[fr.callno]); @@ -6355,7 +6366,7 @@ retryowner2: if ((ast_strlen_zero(iaxs[fr.callno]->secret) && ast_strlen_zero(iaxs[fr.callno]->inkeys)) || (iaxs[fr.callno]->state & IAX_STATE_AUTHENTICATED)) { if (f.subclass == IAX_COMMAND_REGREL) memset(&sin, 0, sizeof(sin)); - if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype)) + if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype, fd)) ast_log(LOG_WARNING, "Registry error\n"); if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) check_provisioning(&sin, ies.serviceident, ies.provver); @@ -6585,7 +6596,7 @@ static int iax2_do_register(struct iax2_registry *reg) if (!reg->callno) { if (option_debug) ast_log(LOG_DEBUG, "Allocate call number\n"); - reg->callno = find_callno(0, 0, ®->addr, NEW_FORCE, 1); + reg->callno = find_callno(0, 0, ®->addr, NEW_FORCE, 1, defaultsockfd); if (reg->callno < 1) { ast_log(LOG_WARNING, "Unable to create call for registration\n"); return -1; @@ -6623,6 +6634,7 @@ static int iax2_provision(struct sockaddr_in *end, char *dest, const char *templ unsigned int sig; struct sockaddr_in sin; int callno; + int sockfd = defaultsockfd; if (option_debug) ast_log(LOG_DEBUG, "Provisioning '%s' from template '%s'\n", dest, template); if (iax_provision_build(&provdata, &sig, template, force)) { @@ -6632,14 +6644,14 @@ static int iax2_provision(struct sockaddr_in *end, char *dest, const char *templ if (end) memcpy(&sin, end, sizeof(sin)); else { - if (create_addr(&sin, NULL, NULL, NULL, dest, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0)) + if (create_addr(&sin, NULL, NULL, NULL, dest, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0, &sockfd)) return -1; } /* Build the rest of the message */ memset(&ied, 0, sizeof(ied)); iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos); - callno = find_callno(0, 0, &sin, NEW_FORCE, 1); + callno = find_callno(0, 0, &sin, NEW_FORCE, 1, sockfd); if (!callno) return -1; ast_mutex_lock(&iaxsl[callno]); @@ -6760,7 +6772,7 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall) } if (heldcall) ast_mutex_unlock(&iaxsl[heldcall]); - peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, 0); + peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, 0, peer->sockfd); if (heldcall) ast_mutex_lock(&iaxsl[heldcall]); if (peer->callno < 1) { @@ -6803,6 +6815,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data char *portno=NULL; int capability = iax2_capability; int trunk; + int sockfd = defaultsockfd; int notransfer = ast_test_flag((&globalflags), IAX_NOTRANSFER); int usejitterbuf = ast_test_flag((&globalflags), IAX_USEJITTERBUF); strncpy(s, (char *)data, sizeof(s)-1); @@ -6826,14 +6839,14 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data } /* Populate our address from the given */ - if (create_addr(&sin, &capability, &sendani, &maxtime, hostname, NULL, &trunk, ¬ransfer, &usejitterbuf, NULL, NULL, 0, NULL, 0, &found, NULL, NULL, 0, NULL, 0)) { + if (create_addr(&sin, &capability, &sendani, &maxtime, hostname, NULL, &trunk, ¬ransfer, &usejitterbuf, NULL, NULL, 0, NULL, 0, &found, NULL, NULL, 0, NULL, 0, &sockfd)) { *cause = AST_CAUSE_UNREGISTERED; return NULL; } if (portno) { sin.sin_port = htons(atoi(portno)); } - callno = find_callno(0, 0, &sin, NEW_FORCE, 1); + callno = find_callno(0, 0, &sin, NEW_FORCE, 1, sockfd); if (callno < 1) { ast_log(LOG_WARNING, "Unable to create call\n"); *cause = AST_CAUSE_CONGESTION; @@ -6880,8 +6893,6 @@ static void *network_thread(void *ignore) from the network, and queue them for delivery to the channels */ int res; struct iax_frame *f, *freeme; - /* Establish I/O callback for socket read */ - ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL); if (timingfd > -1) ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL); for(;;) { @@ -6998,6 +7009,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in memset(peer, 0, sizeof(struct iax2_peer)); peer->expire = -1; peer->pokeexpire = -1; + peer->sockfd = defaultsockfd; } } if (peer) { @@ -7403,16 +7415,19 @@ static void set_timing(void) } -static int set_config(char *config_file, struct sockaddr_in* sin){ +static int set_config(char *config_file, int reload) +{ struct ast_config *cfg; int capability=iax2_capability; struct ast_variable *v; char *cat; char *utype; int format; + int portno = IAX_DEFAULT_PORTNO; int x; struct iax2_user *user; struct iax2_peer *peer; + struct ast_netsock *ns; #if 0 static unsigned short int last_port=0; #endif @@ -7427,19 +7442,11 @@ static int set_config(char *config_file, struct sockaddr_in* sin){ v = ast_variable_browse(cfg, "general"); while(v) { if (!strcasecmp(v->name, "bindport")){ - sin->sin_port = ntohs(atoi(v->value)); -#if 0 - if(last_port==0){ - last_port=sin->sin_port; -#if 0 - ast_verbose("setting last port\n"); -#endif - } - else if(sin->sin_port != last_port) - ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); -#endif - } - else if (!strcasecmp(v->name, "pingtime")) + if (reload) + ast_log(LOG_NOTICE, "Ignoring bindport on reload\n"); + else + portno = atoi(v->value); + } else if (!strcasecmp(v->name, "pingtime")) ping_time = atoi(v->value); else if (!strcasecmp(v->name, "maxjitterbuffer")) maxjitterbuffer = atoi(v->value); @@ -7453,9 +7460,24 @@ static int set_config(char *config_file, struct sockaddr_in* sin){ lagrq_time = atoi(v->value); else if (!strcasecmp(v->name, "dropcount")) iax2_dropcount = atoi(v->value); - else if (!strcasecmp(v->name, "bindaddr")) - inet_aton(v->value, &sin->sin_addr); - else if (!strcasecmp(v->name, "authdebug")) + else if (!strcasecmp(v->name, "bindaddr")) { + if (reload) { + ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n"); + } else { + if (!(ns = ast_netsock_bind(&netsock, io, v->value, portno, tos, socket_read, NULL))) { + ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno); + } else { + if (option_verbose > 1) { + if (strchr(v->value, ':')) + ast_verbose(VERBOSE_PREFIX_2 "Binding IAX2 to '%s'\n", v->value); + else + ast_verbose(VERBOSE_PREFIX_2 "Binding IAX2 to '%s:%d'\n", v->value, portno); + } + if (defaultsockfd < 0) + defaultsockfd = ast_netsock_sockfd(ns); + } + } + } else if (!strcasecmp(v->name, "authdebug")) authdebug = ast_true(v->value); else if (!strcasecmp(v->name, "encryption")) iax2_encryption = get_encrypt_methods(v->value); @@ -7574,7 +7596,6 @@ static int reload_config(void) { char *config = "iax.conf"; struct iax2_registry *reg; - struct sockaddr_in dead_sin; struct iax2_peer *peer; strncpy(accountcode, "", sizeof(accountcode)-1); strncpy(language, "", sizeof(language)-1); @@ -7584,7 +7605,7 @@ static int reload_config(void) ast_clear_flag((&globalflags), IAX_USEJITTERBUF); srand(time(NULL)); delete_users(); - set_config(config,&dead_sin); + set_config(config,1); prune_peers(); prune_users(); for (reg = registrations; reg; reg = reg->next) @@ -7608,6 +7629,7 @@ static int cache_get_callno_locked(const char *data) { struct sockaddr_in sin; int x; + int sockfd = defaultsockfd; char st[256], *s; char *host; char *username=NULL; @@ -7652,11 +7674,11 @@ static int cache_get_callno_locked(const char *data) host = st; } /* Populate our address from the given */ - if (create_addr(&sin, NULL, NULL, NULL, host, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0)) { + if (create_addr(&sin, NULL, NULL, NULL, host, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0, &sockfd)) { return -1; } ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context); - callno = find_callno(0, 0, &sin, NEW_FORCE, 1); + callno = find_callno(0, 0, &sin, NEW_FORCE, 1, sockfd); if (callno < 1) { ast_log(LOG_WARNING, "Unable to create call\n"); return -1; @@ -7973,7 +7995,7 @@ static int __unload_module(void) pthread_cancel(netthreadid); pthread_join(netthreadid, NULL); } - close(netsocket); + ast_netsock_release(&netsock); for (x=0;x<IAX_MAX_CALLS;x++) if (iaxs[x]) iax2_destroy(x); @@ -8017,8 +8039,8 @@ int load_module(void) struct iax2_registry *reg; struct iax2_peer *peer; + struct ast_netsock *ns; struct sockaddr_in sin; - iax_set_output(iax_debug_output); iax_set_error(iax_error_output); @@ -8055,6 +8077,8 @@ int load_module(void) ast_mutex_init(&userl.lock); ast_mutex_init(&peerl.lock); ast_mutex_init(&waresl.lock); + + ast_netsock_init(&netsock); ast_cli_register(&cli_show_users); ast_cli_register(&cli_show_channels); @@ -8074,7 +8098,7 @@ int load_module(void) ast_manager_register( "IAXpeers", 0, manager_iax2_show_peers, "List IAX Peers" ); - set_config(config,&sin); + set_config(config, 0); if (ast_channel_register(channeltype, tdesc, iax2_capability, iax2_request)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype); @@ -8085,23 +8109,16 @@ int load_module(void) if (ast_register_switch(&iax2_switch)) ast_log(LOG_ERROR, "Unable to register IAX switch\n"); - /* Make a UDP socket */ - netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - - if (netsocket < 0) { - ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); - return -1; - } - if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) { - ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), strerror(errno)); - return -1; + if (defaultsockfd < 0) { + if (!(ns = ast_netsock_bindaddr(&netsock, io, &sin, tos, socket_read, NULL))) { + ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); + return -1; + } else { + if (option_verbose > 1) + ast_verbose(VERBOSE_PREFIX_2 "Binding IAX2 to default address 0.0.0.0:%d", IAX_DEFAULT_PORTNO); + defaultsockfd = ast_netsock_sockfd(ns); + } } - - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos); - - if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) - ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos); if (!res) { res = start_network_thread(); @@ -8109,7 +8126,7 @@ int load_module(void) ast_verbose(VERBOSE_PREFIX_2 "IAX Ready and Listening on %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); } else { ast_log(LOG_ERROR, "Unable to start network thread\n"); - close(netsocket); + ast_netsock_release(&netsock); } for (reg = registrations; reg; reg = reg->next) iax2_do_register(reg); diff --git a/channels/iax2-parser.h b/channels/iax2-parser.h index a0afa7f9a..691c8aa32 100755 --- a/channels/iax2-parser.h +++ b/channels/iax2-parser.h @@ -70,6 +70,8 @@ struct iax_frame { #ifdef LIBIAX struct iax_session *session; struct iax_event *event; +#else + int sockfd; #endif /* /Our/ call number */ diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample index 93fede127..33eb02993 100755 --- a/configs/iax.conf.sample +++ b/configs/iax.conf.sample @@ -7,8 +7,10 @@ ; local addresses). ; [general] -;bindport=4569 -;bindaddr=192.168.0.1 +;bindport=4569 ; bindport and bindaddr may be specified +;bindaddr=192.168.0.1 ; more than once to bind to multiple +; ; addresses, but the first will be the +; ; default ; ; Set iaxcompat to yes if you plan to use layered ; switches. It incurs a small performance hit to enable it diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h index 87c89bd59..6a1f72b99 100755 --- a/include/asterisk/acl.h +++ b/include/asterisk/acl.h @@ -14,19 +14,27 @@ #ifndef _ASTERISK_ACL_H #define _ASTERISK_ACL_H -#define AST_SENSE_DENY 0 -#define AST_SENSE_ALLOW 1 - #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif #include <netinet/in.h> +#include <asterisk/io.h> +#include <asterisk/astobj.h> + +#define AST_SENSE_DENY 0 +#define AST_SENSE_ALLOW 1 /* Host based access control */ struct ast_ha; +struct ast_netsock; + +struct ast_netsock_list { + ASTOBJ_CONTAINER_COMPONENTS(struct ast_netsock); + struct io_context *ioc; +}; extern void ast_free_ha(struct ast_ha *ha); extern struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path); @@ -36,6 +44,12 @@ extern int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const c extern int ast_ouraddrfor(struct in_addr *them, struct in_addr *us); extern int ast_lookup_iface(char *iface, struct in_addr *address); extern struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original); +extern int ast_netsock_init(struct ast_netsock_list *list); +extern struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_context *ioc, const char *bindinfo, int defaultport, int tos, ast_io_cb callback, void *data); +extern struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct sockaddr_in *bindaddr, int tos, ast_io_cb callback, void *data); +extern int ast_netsock_free(struct ast_netsock_list *list, struct ast_netsock *netsock); +extern int ast_netsock_release(struct ast_netsock_list *list); +extern int ast_netsock_sockfd(struct ast_netsock *ns); //! Compares the source address and port of two sockaddr_in static inline int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2) diff --git a/include/asterisk/astobj.h b/include/asterisk/astobj.h index 03f66b9e5..4c4727cfb 100755 --- a/include/asterisk/astobj.h +++ b/include/asterisk/astobj.h @@ -15,6 +15,7 @@ #define _ASTERISK_ASTOBJ_H #include <string.h> +#include <asterisk/lock.h> /*! \file astobj.h |