diff --git a/CHANGES b/CHANGES index c46d4c7e4ef5f19390775dc8c1570e8ffb69306e..387ac7c54a602e723364452f1b213f8a696ac2c9 100644 --- a/CHANGES +++ b/CHANGES @@ -69,6 +69,8 @@ SIP Changes Charge messages to snom phones. * Added support for G.719 media streams. * Added support for 16khz signed linear media streams. + * SIP is now able to bind to and communicate with IPv6 addresses. In addition, + RTP has been outfitted with the same abilities. IAX2 Changes ----------- diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index 0024b596c44542030748f885635d76e31a7c3628..f088e9c58d7de25037ba42a46e5181d13acfbf18 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -460,6 +460,7 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) { struct ooh323_pvt *pvt = NULL; struct sockaddr_in ouraddr; + struct ast_sockaddr tmp; struct in_addr ipAddr; if (gH323Debug) ast_verbose("--- ooh323_alloc\n"); @@ -481,8 +482,10 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) return NULL; } + ouraddr.sin_family = AF_INET; ouraddr.sin_addr = ipAddr; - if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &ouraddr, NULL))) { + tmp = ast_sockaddr_from_sin(ouraddr); + if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) { ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno)); ast_mutex_unlock(&pvt->lock); @@ -3803,6 +3806,7 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance struct ooh323_pvt *p; struct sockaddr_in them; struct sockaddr_in us; + struct ast_sockaddr tmp; int mode; if (gH323Debug) @@ -3818,8 +3822,10 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance ast_log(LOG_ERROR, "No Private Structure, this is bad\n"); return -1; } - ast_rtp_instance_get_remote_address(rtp, &them); - ast_rtp_instance_get_local_address(rtp, &us); + ast_rtp_instance_get_remote_address(rtp, &tmp); + ast_sockaddr_to_sin(&tmp, &them); + ast_rtp_instance_get_local_address(rtp, &tmp); + ast_sockaddr_to_sin(&tmp, &us); return 0; } @@ -3829,6 +3835,7 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) { struct sockaddr_in us; + struct ast_sockaddr tmp; ooMediaInfo mediaInfo; int x; format_t format = 0; @@ -3849,7 +3856,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0); } /* figure out our local RTP port and tell the H.323 stack about it*/ - ast_rtp_instance_get_local_address(p->rtp, &us); + ast_rtp_instance_get_local_address(p->rtp, &tmp); + ast_sockaddr_to_sin(&tmp, &us); if (p->rtptimeout) { ast_rtp_instance_set_timeout(p->rtp, p->rtptimeout); @@ -3913,6 +3921,7 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp, { struct ooh323_pvt *p = NULL; struct sockaddr_in them; + struct ast_sockaddr tmp; if (gH323Debug) ast_verbose("--- setup_rtp_connection %s:%d\n", remoteIp, remotePort); @@ -3928,7 +3937,8 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp, them.sin_family = AF_INET; them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */ them.sin_port = htons(remotePort); - ast_rtp_instance_set_remote_address(p->rtp, &them); + tmp = ast_sockaddr_from_sin(&them); + ast_rtp_instance_set_remote_address(p->rtp, &tmp); if (p->writeformat & AST_FORMAT_G726_AAL2) ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, 2, diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c index 5e33cdd3d909f148c9953857f1661a4cb9c8ebc3..919815d730b30311c23fbd209e404850ccd21a91 100644 --- a/apps/app_externalivr.c +++ b/apps/app_externalivr.c @@ -492,6 +492,7 @@ static int app_exec(struct ast_channel *chan, const char *data) .name = "IVR", }; struct ast_hostent hp; + struct sockaddr_in remote_address_tmp; /*communicate through socket to server*/ ast_debug(1, "Parsing hostname:port for socket connect from \"%s\"\n", app_args[0]); @@ -506,9 +507,10 @@ static int app_exec(struct ast_channel *chan, const char *data) } ast_gethostbyname(hostname, &hp); - ivr_desc.remote_address.sin_family = AF_INET; - ivr_desc.remote_address.sin_port = htons(port); - memcpy(&ivr_desc.remote_address.sin_addr.s_addr, hp.hp.h_addr, sizeof(hp.hp.h_addr)); + remote_address_tmp.sin_family = AF_INET; + remote_address_tmp.sin_port = htons(port); + memcpy(&remote_address_tmp.sin_addr.s_addr, hp.hp.h_addr, sizeof(hp.hp.h_addr)); + ast_sockaddr_from_sin(&ivr_desc.remote_address, &remote_address_tmp); if (!(ser = ast_tcptls_client_create(&ivr_desc)) || !(ser = ast_tcptls_client_start(ser))) { goto exit; } diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c index 252e3fe20a54ef12edd7a110516f90dffaad98ef..1a964e75a372a5089306766ca8855db794aeda76 100644 --- a/channels/chan_gtalk.c +++ b/channels/chan_gtalk.c @@ -774,8 +774,10 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch struct aji_client *c = client->connection; struct gtalk_candidate *ours1 = NULL, *ours2 = NULL; struct sockaddr_in sin = { 0, }; + struct ast_sockaddr sin_tmp; + struct ast_sockaddr bindaddr_tmp; struct sockaddr_in dest; - struct in_addr us; + struct ast_sockaddr us; iks *iq, *gtalk, *candidate, *transport; char user[17], pass[17], preference[5], port[7]; char *lowerfrom = NULL; @@ -809,9 +811,11 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch goto safeout; } - ast_rtp_instance_get_local_address(p->rtp, &sin); - ast_find_ourip(&us, bindaddr); - if (!strcmp(ast_inet_ntoa(us), "127.0.0.1")) { + ast_rtp_instance_get_local_address(p->rtp, &sin_tmp); + ast_sockaddr_to_sin(&sin_tmp, &sin); + bindaddr_tmp = ast_sockaddr_from_sin(bindaddr); + ast_find_ourip(&us, &bindaddr_tmp); + if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) { ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute."); } @@ -823,7 +827,8 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random()); ast_copy_string(ours1->username, user, sizeof(ours1->username)); ast_copy_string(ours1->password, pass, sizeof(ours1->password)); - ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip)); + ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us), + sizeof(ours1->ip)); ours1->protocol = AJI_PROTOCOL_UDP; ours1->type = AJI_CONNECT_LOCAL; ours1->generation = 0; @@ -911,6 +916,7 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const struct aji_buddy *buddy; char idroster[200]; char *data, *exten = NULL; + struct ast_sockaddr bindaddr_tmp; ast_debug(1, "The client is %s for alloc\n", client->name); if (!sid && !strchr(them, '/')) { /* I started call! */ @@ -950,7 +956,8 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const tmp->initiator = 1; } /* clear codecs */ - if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL))) { + bindaddr_tmp = ast_sockaddr_from_sin(bindaddr); + if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) { ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n"); ast_free(tmp); return NULL; @@ -1263,6 +1270,8 @@ static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p) struct ast_hostent ahp; struct sockaddr_in sin = { 0, }; struct sockaddr_in aux = { 0, }; + struct ast_sockaddr sin_tmp; + struct ast_sockaddr aux_tmp; if (time(NULL) == p->laststun) return 0; @@ -1281,16 +1290,17 @@ static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p) p->ourcandidates->username); /* Find out the result of the STUN */ - ast_rtp_instance_get_remote_address(p->rtp, &aux); + ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp); + ast_sockaddr_to_sin(&aux_tmp, &aux); /* If the STUN result is different from the IP of the hostname, lock on the stun IP of the hostname advertised by the remote client */ if (aux.sin_addr.s_addr && aux.sin_addr.s_addr != sin.sin_addr.s_addr) - ast_rtp_instance_stun_request(p->rtp, &aux, username); + ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username); else - ast_rtp_instance_stun_request(p->rtp, &sin, username); + ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username); if (aux.sin_addr.s_addr) { ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip); @@ -2057,6 +2067,9 @@ static int gtalk_load_config(void) /*! \brief Load module into PBX, register channel */ static int load_module(void) { + struct ast_sockaddr bindaddr_tmp; + struct ast_sockaddr ourip_tmp; + char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0); free(jabber_loaded); if (!jabber_loaded) { @@ -2083,10 +2096,12 @@ static int load_module(void) if (!io) ast_log(LOG_WARNING, "Unable to create I/O context\n"); - if (ast_find_ourip(&__ourip, bindaddr)) { + bindaddr_tmp = ast_sockaddr_from_sin(bindaddr); + if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp)) { ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n"); return 0; } + __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp)); ast_rtp_glue_register(>alk_rtp_glue); ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli)); diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 10234199a5eb01aa3da713e9c89d4976f3938d5a..cf41acc698ece25dd7e956e35b324e675e33d997 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -954,15 +954,20 @@ static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) static int __oh323_rtp_create(struct oh323_pvt *pvt) { - struct sockaddr_in our_addr; + struct ast_sockaddr our_addr; if (pvt->rtp) return 0; - if (ast_find_ourip(&our_addr.sin_addr, bindaddr)) { - ast_mutex_unlock(&pvt->lock); - ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n"); - return -1; + { + struct ast_sockaddr tmp; + + tmp = ast_sockaddr_from_sin(bindaddr); + if (ast_find_ourip(&our_addr, &tmp)) { + ast_mutex_unlock(&pvt->lock); + ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n"); + return -1; + } } pvt->rtp = ast_rtp_instance_new("asterisk", sched, &our_addr, NULL); if (!pvt->rtp) { @@ -1408,9 +1413,14 @@ static struct oh323_user *build_user(const char *name, struct ast_variable *v, s ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n"); ASTOBJ_UNREF(user, oh323_destroy_user); return NULL; - } else if (ast_get_ip(&user->addr, v->value)) { - ASTOBJ_UNREF(user, oh323_destroy_user); - return NULL; + } else { + struct ast_sockaddr tmp; + + if (ast_get_ip(&tmp, v->value)) { + ASTOBJ_UNREF(user, oh323_destroy_user); + return NULL; + } + ast_sockaddr_to_sin(&tmp, &user->addr); } /* Let us know we need to use ip authentication */ user->host = 1; @@ -1522,10 +1532,15 @@ static struct oh323_peer *build_peer(const char *name, struct ast_variable *v, s ASTOBJ_UNREF(peer, oh323_destroy_peer); return NULL; } - if (ast_get_ip(&peer->addr, v->value)) { - ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value); - ASTOBJ_UNREF(peer, oh323_destroy_peer); - return NULL; + { + struct ast_sockaddr tmp; + + if (ast_get_ip(&tmp, v->value)) { + ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value); + ASTOBJ_UNREF(peer, oh323_destroy_peer); + return NULL; + } + ast_sockaddr_to_sin(&tmp, &peer->addr); } } else if (!strcasecmp(v->name, "port")) { peer->addr.sin_port = htons(atoi(v->value)); @@ -1922,7 +1937,12 @@ static struct rtp_info *external_rtp_create(unsigned call_reference, const char return NULL; } /* figure out our local RTP port and tell the H.323 stack about it */ - ast_rtp_instance_get_local_address(pvt->rtp, &us); + { + struct ast_sockaddr tmp; + + ast_rtp_instance_get_local_address(pvt->rtp, &tmp); + ast_sockaddr_to_sin(&tmp, &us); + } ast_mutex_unlock(&pvt->lock); ast_copy_string(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr)); @@ -1971,7 +1991,12 @@ static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, them.sin_port = htons(remotePort); if (them.sin_addr.s_addr) { - ast_rtp_instance_set_remote_address(pvt->rtp, &them); + { + struct ast_sockaddr tmp; + + tmp = ast_sockaddr_from_sin(them); + ast_rtp_instance_set_remote_address(pvt->rtp, &tmp); + } if (pvt->recvonly) { pvt->recvonly = 0; rtp_change = NEED_UNHOLD; @@ -3204,8 +3229,14 @@ static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance ast_log(LOG_ERROR, "No Private Structure, this is bad\n"); return -1; } - ast_rtp_instance_get_remote_address(rtp, &them); - ast_rtp_instance_get_local_address(rtp, &us); + { + struct ast_sockaddr tmp; + + ast_rtp_instance_get_remote_address(rtp, &tmp); + ast_sockaddr_to_sin(&tmp, &them); + ast_rtp_instance_get_local_address(rtp, &tmp); + ast_sockaddr_to_sin(&tmp, &us); + } #if 0 /* Native bridge still isn't ready */ h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode); #endif diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index ba482a06568fdc6a38ae697d80a82b5f6dc7fc96..7880e719de3cdaf1c1f2cc6a8f8195a5b041193f 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -4441,11 +4441,15 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka sin->sin_family = AF_INET; if (!(peer = find_peer(peername, 1))) { + struct ast_sockaddr sin_tmp; + cai->found = 0; - if (ast_get_ip_or_srv(sin, peername, srvlookup ? "_iax._udp" : NULL)) { + sin_tmp.ss.ss_family = AF_INET; + if (ast_get_ip_or_srv(&sin_tmp, peername, srvlookup ? "_iax._udp" : NULL)) { ast_log(LOG_WARNING, "No such host: %s\n", peername); return -1; } + ast_sockaddr_to_sin(&sin_tmp, sin); sin->sin_port = htons(IAX_DEFAULT_PORTNO); /* use global iax prefs for unknown peer/user */ /* But move the calling channel's native codec to the top of the preference list */ @@ -8312,14 +8316,18 @@ static int iax2_append_register(const char *hostname, const char *username, const char *secret, const char *porta) { struct iax2_registry *reg; + struct ast_sockaddr reg_addr_tmp; if (!(reg = ast_calloc(1, sizeof(*reg)))) return -1; - if (ast_dnsmgr_lookup(hostname, ®->addr, ®->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) { + reg->addr.sin_family = AF_INET; + ast_sockaddr_from_sin(®_addr_tmp, ®->addr); + if (ast_dnsmgr_lookup(hostname, ®_addr_tmp, ®->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) { ast_free(reg); return -1; } + ast_sockaddr_to_sin(®_addr_tmp, ®->addr); ast_copy_string(reg->username, username, sizeof(reg->username)); @@ -11991,6 +11999,7 @@ static int check_srcaddr(struct sockaddr *sa, socklen_t salen) static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr) { struct sockaddr_in sin; + struct ast_sockaddr sin_tmp; int nonlocal = 1; int port = IAX_DEFAULT_PORTNO; int sockfd = defaultsockfd; @@ -12010,10 +12019,11 @@ static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr) port = IAX_DEFAULT_PORTNO; } - if (!ast_get_ip(&sin, addr)) { + if (!ast_get_ip(&sin_tmp, addr)) { struct ast_netsock *sock; int res; + ast_sockaddr_to_sin(&sin_tmp, &sin); sin.sin_port = 0; sin.sin_family = AF_INET; res = check_srcaddr((struct sockaddr *) &sin, sizeof(sin)); @@ -12212,19 +12222,29 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st } } } else { + struct ast_sockaddr peer_addr_tmp; + /* Non-dynamic. Make sure we become that way if we're not */ ast_sched_thread_del(sched, peer->expire); ast_clear_flag64(peer, IAX_DYNAMIC); - if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL)) + peer_addr_tmp.ss.ss_family = AF_INET; + if (ast_dnsmgr_lookup(v->value, &peer_addr_tmp, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL)) return peer_unref(peer); + ast_sockaddr_to_sin(&peer_addr_tmp, + &peer->addr); if (!peer->addr.sin_port) peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO); } if (!maskfound) inet_aton("255.255.255.255", &peer->mask); } else if (!strcasecmp(v->name, "defaultip")) { - if (ast_get_ip(&peer->defaddr, v->value)) + struct ast_sockaddr peer_defaddr_tmp; + + if (ast_get_ip(&peer_defaddr_tmp, v->value)) { return peer_unref(peer); + } + ast_sockaddr_to_sin(&peer_defaddr_tmp, + &peer->defaddr); } else if (!strcasecmp(v->name, "sourceaddress")) { peer_set_srcaddr(peer, v->value); } else if (!strcasecmp(v->name, "permit") || diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c index b876dfd0d87b311e3cda580a3a7eb5b6cecd47dd..35618b1fa3e8368cd9de7581adac1962464a0e11 100644 --- a/channels/chan_jingle.c +++ b/channels/chan_jingle.c @@ -581,6 +581,9 @@ static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, struct aji_client *c = client->connection; struct jingle_candidate *ours1 = NULL, *ours2 = NULL; struct sockaddr_in sin = { 0, }; + struct ast_sockaddr sin_tmp; + struct ast_sockaddr us_tmp; + struct ast_sockaddr bindaddr_tmp; struct sockaddr_in dest; struct in_addr us; struct in_addr externaddr; @@ -617,8 +620,11 @@ static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, goto safeout; } - ast_rtp_instance_get_local_address(p->rtp, &sin); - ast_find_ourip(&us, bindaddr); + ast_rtp_instance_get_local_address(p->rtp, &sin_tmp); + ast_sockaddr_to_sin(&sin_tmp, &sin); + bindaddr_tmp = ast_sockaddr_from_sin(bindaddr); + ast_find_ourip(&us_tmp, &bindaddr_tmp); + us.s_addr = htonl(ast_sockaddr_ipv4(&us_tmp)); /* Setup our first jingle candidate */ ours1->component = 1; @@ -739,6 +745,7 @@ static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, struct aji_resource *resources = NULL; struct aji_buddy *buddy; char idroster[200]; + struct ast_sockaddr bindaddr_tmp; ast_debug(1, "The client is %s for alloc\n", client->name); if (!sid && !strchr(from, '/')) { /* I started call! */ @@ -775,7 +782,8 @@ static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, ast_copy_string(tmp->them, idroster, sizeof(tmp->them)); tmp->initiator = 1; } - tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL); + bindaddr_tmp = ast_sockaddr_from_sin(bindaddr); + tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL); tmp->parent = client; if (!tmp->rtp) { ast_log(LOG_WARNING, "Out of RTP sessions?\n"); @@ -1061,6 +1069,7 @@ static int jingle_update_stun(struct jingle *client, struct jingle_pvt *p) struct hostent *hp; struct ast_hostent ahp; struct sockaddr_in sin; + struct ast_sockaddr sin_tmp; if (time(NULL) == p->laststun) return 0; @@ -1075,7 +1084,8 @@ static int jingle_update_stun(struct jingle *client, struct jingle_pvt *p) sin.sin_port = htons(tmp->port); snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag); - ast_rtp_instance_stun_request(p->rtp, &sin, username); + sin_tmp = ast_sockaddr_from_sin(sin); + ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username); tmp = tmp->next; } return 1; @@ -1867,6 +1877,9 @@ static int jingle_load_config(void) /*! \brief Load module into PBX, register channel */ static int load_module(void) { + struct ast_sockaddr ourip_tmp; + struct ast_sockaddr bindaddr_tmp; + char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0); free(jabber_loaded); if (!jabber_loaded) { @@ -1893,10 +1906,12 @@ static int load_module(void) if (!io) ast_log(LOG_WARNING, "Unable to create I/O context\n"); - if (ast_find_ourip(&__ourip, bindaddr)) { + bindaddr_tmp = ast_sockaddr_from_sin(bindaddr); + if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp)) { ast_log(LOG_WARNING, "Unable to get own IP address, Jingle disabled\n"); return 0; } + __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp)); ast_rtp_glue_register(&jingle_rtp_glue); ast_cli_register_multiple(jingle_cli, ARRAY_LEN(jingle_cli)); diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 420bc51a8fd6f962663d0d0c171ada92e32e55be..63dcb936d665176047869ba1c9c4041798157cd8 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -1769,8 +1769,19 @@ static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, s if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) || (g->addr.sin_port != sin->sin_port)) { memcpy(&g->addr, sin, sizeof(g->addr)); - if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip)) - memcpy(&g->ourip, &__ourip, sizeof(g->ourip)); + { + struct ast_sockaddr tmp1, tmp2; + struct sockaddr_in tmp3 = {0,}; + + tmp3.sin_addr = g->ourip; + ast_sockaddr_from_sin(&tmp1, &g->addr); + ast_sockaddr_from_sin(&tmp2, &tmp3); + if (ast_ouraddrfor(&tmp1, &tmp2)) { + memcpy(&g->ourip, &__ourip, sizeof(g->ourip)); + } + ast_sockaddr_to_sin(&tmp2, &tmp3); + g->ourip = tmp3.sin_addr; + } ast_verb(3, "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port)); } /* not dynamic, check if the name matches */ @@ -1934,6 +1945,7 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) format_t peercapability; int peerNonCodecCapability; struct sockaddr_in sin; + struct ast_sockaddr sin_tmp; char *codecs; struct ast_hostent ahp; struct hostent *hp; int codec, codec_count=0; @@ -1965,7 +1977,8 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) sin.sin_family = AF_INET; memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); sin.sin_port = htons(portno); - ast_rtp_instance_set_remote_address(sub->rtp, &sin); + ast_sockaddr_from_sin(&sin_tmp, &sin); + ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp); ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); /* Scan through the RTP payload types specified in a "m=" line: */ ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp); @@ -2148,6 +2161,7 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc int codec; char costr[80]; struct sockaddr_in sin; + struct ast_sockaddr sin_tmp; char v[256]; char s[256]; char o[256]; @@ -2157,6 +2171,7 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc char a[1024] = ""; format_t x; struct sockaddr_in dest = { 0, }; + struct ast_sockaddr dest_tmp; struct mgcp_endpoint *p = sub->parent; /* XXX We break with the "recommendation" and send our IP, in order that our peer doesn't have to ast_gethostbyname() us XXX */ @@ -2165,9 +2180,11 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n"); return -1; } - ast_rtp_instance_get_local_address(sub->rtp, &sin); + ast_rtp_instance_get_local_address(sub->rtp, &sin_tmp); + ast_sockaddr_to_sin(&sin_tmp, &sin); if (rtp) { - ast_rtp_instance_get_remote_address(sub->rtp, &dest); + ast_rtp_instance_get_remote_address(sub->rtp, &dest_tmp); + ast_sockaddr_to_sin(&dest_tmp, &dest); } else { if (sub->tmpdest.sin_addr.s_addr) { dest.sin_addr = sub->tmpdest.sin_addr; @@ -2240,11 +2257,13 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_ char tmp[80]; struct mgcp_endpoint *p = sub->parent; format_t x; + struct ast_sockaddr sub_tmpdest_tmp; if (ast_strlen_zero(sub->cxident) && rtp) { /* We don't have a CXident yet, store the destination and wait a bit */ - ast_rtp_instance_get_remote_address(rtp, &sub->tmpdest); + ast_rtp_instance_get_remote_address(rtp, &sub_tmpdest_tmp); + ast_sockaddr_to_sin(&sub_tmpdest_tmp, &sub->tmpdest); return 0; } ast_copy_string(local, "e:on, s:off, p:20", sizeof(local)); @@ -2876,6 +2895,8 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub static void start_rtp(struct mgcp_subchannel *sub) { + struct ast_sockaddr bindaddr_tmp; + ast_mutex_lock(&sub->lock); /* check again to be on the safe side */ if (sub->rtp) { @@ -2883,7 +2904,8 @@ static void start_rtp(struct mgcp_subchannel *sub) sub->rtp = NULL; } /* Allocate the RTP now */ - sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL); + ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); + sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL); if (sub->rtp && sub->owner) ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0)); if (sub->rtp) { @@ -3967,22 +3989,32 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) /* Non-dynamic. Make sure we become that way if we're not */ AST_SCHED_DEL(sched, gw->expire); gw->dynamic = 0; - if (ast_get_ip(&gw->addr, v->value)) { - if (!gw_reload) { - ast_mutex_destroy(&gw->msgs_lock); - ast_free(gw); + { + struct ast_sockaddr tmp; + + ast_sockaddr_from_sin(&tmp, &gw->addr); + if (ast_get_ip(&tmp, v->value)) { + if (!gw_reload) { + ast_mutex_destroy(&gw->msgs_lock); + ast_free(gw); + } + return NULL; } - return NULL; + ast_sockaddr_to_sin(&tmp, &gw->addr); } } } else if (!strcasecmp(v->name, "defaultip")) { - if (ast_get_ip(&gw->defaddr, v->value)) { + struct ast_sockaddr tmp; + + ast_sockaddr_from_sin(&tmp, &gw->defaddr); + if (ast_get_ip(&tmp, v->value)) { if (!gw_reload) { ast_mutex_destroy(&gw->msgs_lock); ast_free(gw); } return NULL; } + ast_sockaddr_to_sin(&tmp, &gw->defaddr); } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL); @@ -4325,8 +4357,19 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port)) { gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT); } - if (gw->addr.sin_addr.s_addr && ast_ouraddrfor(&gw->addr.sin_addr, &gw->ourip)) { - memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip)); + { + struct ast_sockaddr tmp1, tmp2; + struct sockaddr_in tmp3 = {0,}; + + tmp3.sin_addr = gw->ourip; + ast_sockaddr_from_sin(&tmp1, &gw->addr); + ast_sockaddr_from_sin(&tmp2, &tmp3); + if (gw->addr.sin_addr.s_addr && ast_ouraddrfor(&tmp1, &tmp2)) { + memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip)); + } else { + ast_sockaddr_to_sin(&tmp2, &tmp3); + gw->ourip = tmp3.sin_addr; + } } } diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c index 24c073215307ab262443f4a07cb0e74259dfac0f..f385d4467df73a36ad1e466adc1ee43455f576ff 100644 --- a/channels/chan_multicast_rtp.c +++ b/channels/chan_multicast_rtp.c @@ -111,7 +111,8 @@ static struct ast_channel *multicast_rtp_request(const char *type, format_t form { char *tmp = ast_strdupa(data), *multicast_type = tmp, *destination, *control; struct ast_rtp_instance *instance; - struct sockaddr_in control_address = { .sin_family = AF_INET, }, destination_address = { .sin_family = AF_INET, }; + struct ast_sockaddr control_address; + struct ast_sockaddr destination_address; struct ast_channel *chan; format_t fmt = ast_best_codec(format); @@ -125,13 +126,15 @@ static struct ast_channel *multicast_rtp_request(const char *type, format_t form } *destination++ = '\0'; - if (ast_parse_arg(destination, PARSE_INADDR | PARSE_PORT_REQUIRE, &destination_address)) { + if (!ast_sockaddr_parse(&destination_address, destination, + PARSE_PORT_REQUIRE)) { goto failure; } if ((control = strchr(destination, '/'))) { *control++ = '\0'; - if (ast_parse_arg(control, PARSE_INADDR | PARSE_PORT_REQUIRE, &control_address)) { + if (!ast_sockaddr_parse(&control_address, control, + PARSE_PORT_REQUIRE)) { goto failure; } } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index c65d85b9f59d927a41cac0d9927464224262d944..d0c131f13841d191441a643907ee8fe1a2d8785e 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -252,7 +252,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/dnsmgr.h" #include "asterisk/devicestate.h" #include "asterisk/monitor.h" -#include "asterisk/netsock.h" +#include "asterisk/netsock2.h" #include "asterisk/localtime.h" #include "asterisk/abstract_jb.h" #include "asterisk/threadstorage.h" @@ -1117,7 +1117,7 @@ static struct sip_auth *authl = NULL; */ static int sipsock = -1; -struct sockaddr_in bindaddr; /*!< UDP: The address we bind to */ +struct ast_sockaddr bindaddr; /*!< UDP: The address we bind to */ /*! \brief our (internal) default address/port to put in SIP/SDP messages * internip is initialized picking a suitable address from one of the @@ -1125,7 +1125,7 @@ struct sockaddr_in bindaddr; /*!< UDP: The address we bind to */ * default address/port in SIP messages, and as the default address * (but not port) in SDP messages. */ -static struct sockaddr_in internip; +static struct ast_sockaddr internip; /*! \brief our external IP address/port for SIP sessions. * externip.sin_addr is only set when we know we might be behind @@ -1145,8 +1145,8 @@ static struct sockaddr_in internip; * Other variables (externhost, externexpire, externrefresh) are used * to support the above functions. */ -static struct sockaddr_in externip; /*!< External IP address if we are behind NAT */ -static struct sockaddr_in media_address; /*!< External RTP IP address if we are behind NAT */ +static struct ast_sockaddr externip; /*!< External IP address if we are behind NAT */ +static struct ast_sockaddr media_address; /*!< External RTP IP address if we are behind NAT */ static char externhost[MAXHOSTNAMELEN]; /*!< External host name */ static time_t externexpire; /*!< Expiration counter for re-resolving external host name in dynamic DNS */ @@ -1165,7 +1165,7 @@ static struct ast_ha *localaddr; /*!< List of local networks, on the same sid static int ourport_tcp; /*!< The port used for TCP connections */ static int ourport_tls; /*!< The port used for TCP/TLS connections */ -static struct sockaddr_in debugaddr; +static struct ast_sockaddr debugaddr; static struct ast_config *notify_types = NULL; /*!< The list of manual NOTIFY types we know how to send */ @@ -1201,9 +1201,10 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen); static const char *sip_get_callid(struct ast_channel *chan); -static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin); +static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr); static int sip_standard_port(enum sip_transport type, int port); static int sip_prepare_socket(struct sip_pvt *p); +static int get_address_family_filter(const struct ast_sockaddr *addr); /*--- Transmitting responses and requests */ static int sipsock_read(int *id, int fd, short events, void *ignore); @@ -1212,7 +1213,7 @@ static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct as static void add_cc_call_info_to_response(struct sip_pvt *p, struct sip_request *resp); static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); static int retrans_pkt(const void *data); -static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg); +static int transmit_response_using_temp(ast_string_field callid, struct ast_sockaddr *addr, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg); static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req); static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req); static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req); @@ -1248,11 +1249,11 @@ static int __sip_autodestruct(const void *data); static void *registry_unref(struct sip_registry *reg, char *tag); static int update_call_counter(struct sip_pvt *fup, int event); static int auto_congest(const void *arg); -static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method); +static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method); static void free_old_route(struct sip_route *route); static void list_route(struct sip_route *route); static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards); -static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin, +static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr, struct sip_request *req, const char *uri); static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag); static void check_pendings(struct sip_pvt *p); @@ -1268,7 +1269,7 @@ static char get_sdp_line(int *start, int stop, struct sip_request *req, const ch static int find_sdp(struct sip_request *req); static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action); static int process_sdp_o(const char *o, struct sip_pvt *p); -static int process_sdp_c(const char *c, struct ast_hostent *hp); +static int process_sdp_c(const char *c, struct ast_sockaddr *addr); static int process_sdp_a_sendonly(const char *a, int *sendonly); static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec); static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec); @@ -1292,8 +1293,8 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request * const char *uri, enum xmittype reliable, int ignore); static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, - struct sockaddr_in *sin, struct sip_peer **authpeer); -static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct sockaddr_in *sin); + struct ast_sockaddr *addr, struct sip_peer **authpeer); +static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct ast_sockaddr *addr); /*--- Domain handling */ static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */ @@ -1375,13 +1376,17 @@ static int sip_dtmfmode(struct ast_channel *chan, const char *data); static int sip_addheader(struct ast_channel *chan, const char *data); static int sip_do_reload(enum channelreloadreason reason); static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); +static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, + const char *name, int flag, int family); +static int ast_sockaddr_resolve_first(struct ast_sockaddr *addr, + const char *name, int flag); /*--- Debugging Functions for enabling debug per IP or fully, or enabling history logging for a SIP dialog */ static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to debuglog at end of dialog, before destroying data */ -static inline int sip_debug_test_addr(const struct sockaddr_in *addr); +static inline int sip_debug_test_addr(const struct ast_sockaddr *addr); static inline int sip_debug_test_pvt(struct sip_pvt *p); static void append_history_full(struct sip_pvt *p, const char *fmt, ...); static void sip_dump_history(struct sip_pvt *dialog); @@ -1394,7 +1399,7 @@ static void sip_destroy_peer_fn(void *peer); static void set_peer_defaults(struct sip_peer *peer); static struct sip_peer *temp_peer(const char *name); static void register_peer_exten(struct sip_peer *peer, int onoff); -static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int forcenamematch, int devstate_only, int transport); +static struct sip_peer *find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int forcenamematch, int devstate_only, int transport); static int sip_poke_peer_s(const void *data); static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req); static void reg_source_db(struct sip_peer *peer); @@ -1404,15 +1409,15 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask static void set_socket_transport(struct sip_socket *socket, int transport); /* Realtime device support */ -static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms); +static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms); static void update_peer(struct sip_peer *p, int expire); static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config); static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername); -static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin, int devstate_only); +static struct sip_peer *realtime_peer(const char *peername, struct ast_sockaddr *sin, int devstate_only); static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); /*--- Internal UA client handling (outbound registrations) */ -static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p); +static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us, struct sip_pvt *p); static void sip_registry_destroy(struct sip_registry *reg); static int sip_register(const char *value, int lineno); static const char *regstate2str(enum sipregistrystate regstate) attribute_const; @@ -1469,13 +1474,13 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho static int init_resp(struct sip_request *resp, const char *msg); static inline int resp_needs_contact(const char *msg, enum sipmethod method); static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req); -static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p); +static const struct ast_sockaddr *sip_real_dst(const struct sip_pvt *p); static void build_via(struct sip_pvt *p); static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer); -static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog, struct sockaddr_in *remote_address); +static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog, struct ast_sockaddr *remote_address); static char *generate_random_string(char *buf, size_t size); static void build_callid_pvt(struct sip_pvt *pvt); -static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain); +static void build_callid_registry(struct sip_registry *reg, const struct ast_sockaddr *ourip, const char *fromdomain); static void make_our_tag(char *tagbuf, size_t len); static int add_header(struct sip_request *req, const char *var, const char *value); static int add_content(struct sip_request *req, const char *line); @@ -1493,19 +1498,19 @@ static void append_date(struct sip_request *req); static void build_contact(struct sip_pvt *p); /*------Request handling functions */ -static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock); +static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock); static int handle_request_update(struct sip_pvt *p, struct sip_request *req); -static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, const char *e, int *nounlock); +static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *recount, const char *e, int *nounlock); static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, int *nounlock); static int handle_request_bye(struct sip_pvt *p, struct sip_request *req); -static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const char *e); +static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *sin, const char *e); static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req); static int handle_request_message(struct sip_pvt *p, struct sip_request *req); -static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e); +static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e); static void handle_request_info(struct sip_pvt *p, struct sip_request *req); static int handle_request_options(struct sip_pvt *p, struct sip_request *req); -static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *nounlock); -static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e); +static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *nounlock); +static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e); static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno, int *nounlock); /*------Response handling functions */ @@ -1877,7 +1882,7 @@ static int sip_cc_monitor_request_cc(struct ast_cc_monitor *monitor, int *availa sip_pvt_lock(monitor_instance->subscription_pvt); create_addr(monitor_instance->subscription_pvt, monitor_instance->peername, 0, 1, NULL); - ast_sip_ouraddrfor(&monitor_instance->subscription_pvt->sa.sin_addr, &monitor_instance->subscription_pvt->ourip, monitor_instance->subscription_pvt); + ast_sip_ouraddrfor(&monitor_instance->subscription_pvt->sa, &monitor_instance->subscription_pvt->ourip, monitor_instance->subscription_pvt); monitor_instance->subscription_pvt->subscribed = CALL_COMPLETION; monitor_instance->subscription_pvt->expiry = when; @@ -2793,14 +2798,19 @@ static int proxy_update(struct sip_proxy *proxy) { /* if it's actually an IP address and not a name, there's no need for a managed lookup */ - if (!inet_aton(proxy->name, &proxy->ip.sin_addr)) { + if (!ast_sockaddr_parse(&proxy->ip, proxy->name, 0)) { /* Ok, not an IP address, then let's check if it's a domain or host */ /* XXX Todo - if we have proxy port, don't do SRV */ + proxy->ip.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */ if (ast_get_ip_or_srv(&proxy->ip, proxy->name, sip_cfg.srvlookup ? "_sip._udp" : NULL) < 0) { - ast_log(LOG_WARNING, "Unable to locate host '%s'\n", proxy->name); - return FALSE; + ast_log(LOG_WARNING, "Unable to locate host '%s'\n", proxy->name); + return FALSE; } + } + + ast_sockaddr_set_port(&proxy->ip, proxy->port); + proxy->last_dnsupdate = time(NULL); return TRUE; } @@ -2819,26 +2829,6 @@ unsigned int port_str2int(const char *pt, unsigned int standard) return port; } -/*! \brief Allocate and initialize sip proxy */ -static struct sip_proxy *proxy_allocate(char *name, char *port, int force) -{ - struct sip_proxy *proxy; - - if (ast_strlen_zero(name)) { - return NULL; - } - - proxy = ao2_alloc(sizeof(*proxy), NULL); - if (!proxy) - return NULL; - proxy->force = force; - ast_copy_string(proxy->name, name, sizeof(proxy->name)); - proxy->ip.sin_port = htons(port_str2int(port, STANDARD_SIP_PORT)); - proxy->ip.sin_family = AF_INET; - proxy_update(proxy); - return proxy; -} - /*! \brief Get default outbound proxy or global proxy */ static struct sip_proxy *obproxy_get(struct sip_pvt *dialog, struct sip_peer *peer) { @@ -2889,21 +2879,13 @@ static int find_sip_method(const char *msg) } /*! \brief See if we pass debug IP filter */ -static inline int sip_debug_test_addr(const struct sockaddr_in *addr) +static inline int sip_debug_test_addr(const struct ast_sockaddr *addr) { - if (!sipdebug) - return 0; - if (debugaddr.sin_addr.s_addr) { - if (((ntohs(debugaddr.sin_port) != 0) - && (debugaddr.sin_port != addr->sin_port)) - || (debugaddr.sin_addr.s_addr != addr->sin_addr.s_addr)) - return 0; - } - return 1; + return sipdebug && !ast_sockaddr_isnull(addr) && !ast_sockaddr_cmp_addr(&debugaddr, addr); } /*! \brief The real destination address for a write */ -static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p) +static const struct ast_sockaddr *sip_real_dst(const struct sip_pvt *p) { if (p->outboundproxy) return &p->outboundproxy->ip; @@ -3007,15 +2989,15 @@ static inline const char *get_transport_pvt(struct sip_pvt *p) static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len) { int res = 0; - const struct sockaddr_in *dst = sip_real_dst(p); + const struct ast_sockaddr *dst = sip_real_dst(p); - ast_debug(2, "Trying to put '%.11s' onto %s socket destined for %s:%d\n", data->str, get_transport_pvt(p), ast_inet_ntoa(dst->sin_addr), htons(dst->sin_port)); + ast_debug(2, "Trying to put '%.11s' onto %s socket destined for %s\n", data->str, get_transport_pvt(p), ast_sockaddr_stringify(dst)); if (sip_prepare_socket(p) < 0) return XMIT_ERROR; if (p->socket.type == SIP_TRANSPORT_UDP) { - res = sendto(p->socket.fd, data->str, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in)); + res = ast_sendto(p->socket.fd, data->str, len, 0, dst); } else if (p->socket.tcptls_session) { res = sip_tcptls_write(p->socket.tcptls_session, data->str, len); } else { @@ -3034,7 +3016,7 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len) } } if (res != len) - ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno)); + ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_sockaddr_stringify(dst), res, strerror(errno)); return res; } @@ -3046,10 +3028,10 @@ static void build_via(struct sip_pvt *p) const char *rport = (ast_test_flag(&p->flags[0], SIP_NAT_FORCE_RPORT) || ast_test_flag(&p->flags[0], SIP_NAT_RPORT_PRESENT)) ? ";rport" : ""; /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - snprintf(p->via, sizeof(p->via), "SIP/2.0/%s %s:%d;branch=z9hG4bK%08x%s", + snprintf(p->via, sizeof(p->via), "SIP/2.0/%s %s;branch=z9hG4bK%08x%s", get_transport_pvt(p), - ast_inet_ntoa(p->ourip.sin_addr), - ntohs(p->ourip.sin_port), (int) p->branch, rport); + ast_sockaddr_stringify(&p->ourip), + (int) p->branch, rport); } /*! \brief NAT fix - decide which IP address to use for Asterisk server? @@ -3059,9 +3041,11 @@ static void build_via(struct sip_pvt *p) * externip or can get away with our internal bindaddr * 'us' is always overwritten. */ -static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p) +static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us, struct sip_pvt *p) { - struct sockaddr_in theirs; + struct ast_sockaddr theirs; + struct sockaddr_in theirs_sin, externip_sin, us_sin; + /* Set want_remap to non-zero if we want to remap 'us' to an externally * reachable IP address and port. This is done if: * 1. we have a localaddr list (containing 'internal' addresses marked @@ -3074,76 +3058,100 @@ static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, str * when passed to ast_apply_ha() so it does need to be remapped. * This fourth condition is checked later. */ - int want_remap; + int want_remap = 0; - *us = internip; /* starting guess for the internal address */ + ast_sockaddr_copy(us, &internip); /* starting guess for the internal address */ /* now ask the system what would it use to talk to 'them' */ - ast_ouraddrfor(them, &us->sin_addr); - theirs.sin_addr = *them; + ast_ouraddrfor(them, us); + ast_sockaddr_copy(&theirs, them); - want_remap = localaddr && - (externip.sin_addr.s_addr || stunaddr.sin_addr.s_addr) && - ast_apply_ha(localaddr, &theirs) == AST_SENSE_ALLOW ; + if (ast_sockaddr_is_ipv6(&theirs)) { + if (localaddr && !ast_sockaddr_isnull(&externip)) { + ast_log(LOG_WARNING, "Address remapping activated in sip.conf " + "but we're using IPv6, which doesn't need it. Please " + "remove \"localnet\" and/or \"externip\" settings.\n"); + } + } else { + ast_sockaddr_to_sin(&theirs, &theirs_sin); + ast_sockaddr_to_sin(us, &us_sin); + + want_remap = localaddr && + !(ast_sockaddr_isnull(&externip) && stunaddr.sin_addr.s_addr) && + ast_apply_ha(localaddr, &theirs_sin) == AST_SENSE_ALLOW ; + } if (want_remap && - (!sip_cfg.matchexterniplocally || !ast_apply_ha(localaddr, us)) ) { + (!sip_cfg.matchexterniplocally || !ast_apply_ha(localaddr, &us_sin)) ) { /* if we used externhost or stun, see if it is time to refresh the info */ if (externexpire && time(NULL) >= externexpire) { if (stunaddr.sin_addr.s_addr) { - ast_stun_request(sipsock, &stunaddr, NULL, &externip); + ast_sockaddr_to_sin(&externip, &externip_sin); + ast_stun_request(sipsock, &stunaddr, NULL, &externip_sin); } else { - if (ast_parse_arg(externhost, PARSE_INADDR, &externip)) + if (ast_sockaddr_resolve_first(&externip, externhost, 0)) { ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost); + } + externexpire = time(NULL); } externexpire = time(NULL) + externrefresh; } - if (externip.sin_addr.s_addr) { - *us = externip; + if (ast_sockaddr_isnull(&externip)) { + ast_sockaddr_copy(us, &externip); switch (p->socket.type) { case SIP_TRANSPORT_TCP: - us->sin_port = htons(externtcpport); + if (!externtcpport && ast_sockaddr_port(&externip)) { + /* for consistency, default to the externip port */ + externtcpport = ast_sockaddr_port(&externip); + } + ast_sockaddr_set_port(us, externtcpport); break; case SIP_TRANSPORT_TLS: - us->sin_port = htons(externtlsport); + ast_sockaddr_set_port(us, externtlsport); break; case SIP_TRANSPORT_UDP: break; /* fall through */ default: - us->sin_port = htons(STANDARD_SIP_PORT); /* we should never get here */ + /* we should never get here */ + ast_sockaddr_set_port(us, STANDARD_SIP_PORT); } } - else + else { ast_log(LOG_WARNING, "stun failed\n"); + } ast_debug(1, "Target address %s is not local, substituting externip\n", - ast_inet_ntoa(*(struct in_addr *)&them->s_addr)); + ast_sockaddr_stringify(them)); } else if (p) { /* no remapping, but we bind to a specific address, so use it. */ switch (p->socket.type) { case SIP_TRANSPORT_TCP: - if (sip_tcp_desc.local_address.sin_addr.s_addr) { - *us = sip_tcp_desc.local_address; + if (!ast_sockaddr_is_any(&sip_tcp_desc.local_address)) { + ast_sockaddr_copy(us, + &sip_tcp_desc.local_address); } else { - us->sin_port = sip_tcp_desc.local_address.sin_port; + ast_sockaddr_set_port(us, + ast_sockaddr_port(&sip_tcp_desc.local_address)); } break; case SIP_TRANSPORT_TLS: - if (sip_tls_desc.local_address.sin_addr.s_addr) { - *us = sip_tls_desc.local_address; + if (!ast_sockaddr_is_any(&sip_tls_desc.local_address)) { + ast_sockaddr_copy(us, + &sip_tls_desc.local_address); } else { - us->sin_port = sip_tls_desc.local_address.sin_port; + ast_sockaddr_set_port(us, + ast_sockaddr_port(&sip_tls_desc.local_address)); } - break; + break; case SIP_TRANSPORT_UDP: /* fall through on purpose */ default: - if (bindaddr.sin_addr.s_addr) { - *us = bindaddr; + if (!ast_sockaddr_is_any(&bindaddr)) { + ast_sockaddr_copy(us, &bindaddr); } } - } else if (bindaddr.sin_addr.s_addr) { - *us = bindaddr; + } else if (!ast_sockaddr_is_any(&bindaddr)) { + ast_sockaddr_copy(us, &bindaddr); } - ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s:%d\n", get_transport(p->socket.type), ast_inet_ntoa(us->sin_addr), ntohs(us->sin_port)); + ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s\n", get_transport(p->socket.type), ast_sockaddr_stringify(us)); } /*! \brief Append to SIP dialog history with arg list */ @@ -3231,11 +3239,11 @@ static int retrans_pkt(const void *data) } if (sip_debug_test_pvt(pkt->owner)) { - const struct sockaddr_in *dst = sip_real_dst(pkt->owner); - ast_verbose("Retransmitting #%d (%s) to %s:%d:\n%s\n---\n", + const struct ast_sockaddr *dst = sip_real_dst(pkt->owner); + ast_verbose("Retransmitting #%d (%s) to %s:\n%s\n---\n", pkt->retrans, sip_nat_mode(pkt->owner), - ast_inet_ntoa(dst->sin_addr), - ntohs(dst->sin_port), pkt->data->str); + ast_sockaddr_stringify(dst), + pkt->data->str); } append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data->str); @@ -3709,12 +3717,12 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty finalize_content(req); add_blank(req); if (sip_debug_test_pvt(p)) { - const struct sockaddr_in *dst = sip_real_dst(p); + const struct ast_sockaddr *dst = sip_real_dst(p); - ast_verbose("\n<--- %sTransmitting (%s) to %s:%d --->\n%s\n<------------>\n", + ast_verbose("\n<--- %sTransmitting (%s) to %s --->\n%s\n<------------>\n", reliable ? "Reliably " : "", sip_nat_mode(p), - ast_inet_ntoa(dst->sin_addr), - ntohs(dst->sin_port), req->data->str); + ast_sockaddr_stringify(dst), + req->data->str); } if (p->do_history) { struct sip_request tmp = { .rlPart1 = 0, }; @@ -3755,10 +3763,11 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp finalize_content(req); add_blank(req); if (sip_debug_test_pvt(p)) { - if (ast_test_flag(&p->flags[0], SIP_NAT_FORCE_RPORT)) - ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port), req->data->str); - else - ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port), req->data->str); + if (ast_test_flag(&p->flags[0], SIP_NAT_FORCE_RPORT)) { + ast_verbose("%sTransmitting (NAT) to %s:\n%s\n---\n", reliable ? "Reliably " : "", ast_sockaddr_stringify(&p->recv), req->data->str); + } else { + ast_verbose("%sTransmitting (no NAT) to %s:\n%s\n---\n", reliable ? "Reliably " : "", ast_sockaddr_stringify(&p->sa), req->data->str); + } } if (p->do_history) { struct sip_request tmp = { .rlPart1 = 0, }; @@ -4012,7 +4021,7 @@ static int sip_sendtext(struct ast_channel *ast, const char *text) that name and store that in the "regserver" field in the sippeers table to facilitate multi-server setups. */ -static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms) +static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms) { char port[10]; char ipaddr[INET_ADDRSTRLEN]; @@ -4033,9 +4042,9 @@ static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, snprintf(str_lastms, sizeof(str_lastms), "%d", lastms); snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime); /* Expiration time */ - ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr)); - snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port)); - + ast_copy_string(ipaddr, ast_sockaddr_stringify_addr(addr), sizeof(ipaddr)); + ast_copy_string(port, ast_sockaddr_stringify_port(addr), sizeof(port)); + if (ast_strlen_zero(sysname)) /* No system name, disable this */ sysname = NULL; else if (sip_cfg.rtsave_sysname) @@ -4209,7 +4218,7 @@ static const char *get_name_from_variable(struct ast_variable *var, const char * * This returns a pointer to a peer and because we use build_peer, we can rest * assured that the refcount is bumped. */ -static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin, int devstate_only) +static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockaddr *addr, int devstate_only) { struct sip_peer *peer; struct ast_variable *var = NULL; @@ -4219,7 +4228,6 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i char ipaddr[INET_ADDRSTRLEN]; char portstring[6]; /*up to 5 digits plus null terminator*/ char *cat = NULL; - unsigned short portnum; int realtimeregs = ast_check_realtime("sipregs"); /* First check on peer name */ @@ -4228,8 +4236,9 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL); var = ast_load_realtime("sippeers", "name", newpeername, "host", "dynamic", SENTINEL); - if (!var && sin) - var = ast_load_realtime("sippeers", "name", newpeername, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL); + if (!var && addr) { + var = ast_load_realtime("sippeers", "name", newpeername, "host", ast_sockaddr_stringify_addr(addr), SENTINEL); + } if (!var) { var = ast_load_realtime("sippeers", "name", newpeername, SENTINEL); /*!\note @@ -4238,16 +4247,21 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i * is because we only have the IP address and the host field might be * set as a name (and the reverse PTR might not match). */ - if (var && sin) { + if (var && addr) { for (tmp = var; tmp; tmp = tmp->next) { if (!strcasecmp(tmp->name, "host")) { - struct hostent *hp; - struct ast_hostent ahp; - if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) { + struct ast_sockaddr *addrs = NULL; + + if (ast_sockaddr_resolve(&addrs, + tmp->value, + PARSE_PORT_FORBID, + get_address_family_filter(&bindaddr)) <= 0 || + ast_sockaddr_cmp(&addrs[0], addr)) { /* No match */ ast_variables_destroy(var); var = NULL; } + ast_free(addrs); break; } } @@ -4255,10 +4269,9 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i } } - if (!var && sin) { /* Then check on IP address for dynamic peers */ - ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr)); - portnum = ntohs(sin->sin_port); - sprintf(portstring, "%u", portnum); + if (!var && addr) { /* Then check on IP address for dynamic peers */ + ast_copy_string(ipaddr, ast_sockaddr_stringify_addr(addr), sizeof(ipaddr)); + ast_copy_string(portstring, ast_sockaddr_stringify_port(addr), sizeof(portstring)); var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL); /* First check for fixed IP hosts */ if (var) { if (realtimeregs) { @@ -4368,7 +4381,7 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i ref_peer(peer, "add registration ref")); } ao2_t_link(peers, peer, "link peer into peers table"); - if (peer->addr.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&peer->addr)) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } } @@ -4425,7 +4438,7 @@ static int find_by_name(void *obj, void *arg, void *data, int flags) * \note Avoid using this function in new functions if there is a way to avoid it, * since it might cause a database lookup. */ -static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int which_objects, int devstate_only, int transport) +static struct sip_peer *find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int which_objects, int devstate_only, int transport) { struct sip_peer *p = NULL; struct sip_peer tmp_peer; @@ -4433,9 +4446,8 @@ static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int if (peer) { ast_copy_string(tmp_peer.name, peer, sizeof(tmp_peer.name)); p = ao2_t_callback_data(peers, OBJ_POINTER, find_by_name, &tmp_peer, &which_objects, "ao2_find in peers table"); - } else if (sin) { /* search by addr? */ - tmp_peer.addr.sin_addr.s_addr = sin->sin_addr.s_addr; - tmp_peer.addr.sin_port = sin->sin_port; + } else if (addr) { /* search by addr? */ + ast_sockaddr_copy(&tmp_peer.addr, addr); tmp_peer.flags[0].flags = 0; tmp_peer.transports = transport; p = ao2_t_find(peers_by_ip, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_ip table"); /* WAS: p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); */ @@ -4449,7 +4461,7 @@ static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int } if (!p && (realtime || devstate_only)) { - p = realtime_peer(peer, sin, devstate_only); + p = realtime_peer(peer, addr, devstate_only); if (p) { switch (which_objects) { case FINDUSERS: @@ -4582,17 +4594,20 @@ static void copy_socket_data(struct sip_socket *to_sock, const struct sip_socket */ static int dialog_initialize_rtp(struct sip_pvt *dialog) { + struct ast_sockaddr bindaddr_tmp; + if (!sip_methods[dialog->method].need_rtp) { return 0; } - if (!(dialog->rtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr, NULL))) { + ast_sockaddr_copy(&bindaddr_tmp, &bindaddr); + if (!(dialog->rtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) { return -1; } if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) || (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (dialog->capability & AST_FORMAT_VIDEO_MASK))) { - if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr, NULL))) { + if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) { return -1; } ast_rtp_instance_set_timeout(dialog->vrtp, global_rtptimeout); @@ -4602,7 +4617,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) } if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_TEXTSUPPORT)) { - if (!(dialog->trtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr, NULL))) { + if (!(dialog->trtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) { return -1; } ast_rtp_instance_set_timeout(dialog->trtp, global_rtptimeout); @@ -4634,7 +4649,6 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) */ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) { - /* this checks that the dialog is contacting the peer on a valid * transport type based on the peers transport configuration, * otherwise, this function bails out */ @@ -4642,9 +4656,9 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) return -1; copy_socket_data(&dialog->socket, &peer->socket); - if ((peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr) && + if (!(ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr)) && (!peer->maxms || ((peer->lastms >= 0) && (peer->lastms <= peer->maxms)))) { - dialog->sa = (peer->addr.sin_addr.s_addr) ? peer->addr : peer->defaddr; + dialog->sa = ast_sockaddr_isnull(&peer->addr) ? peer->defaddr : peer->addr; dialog->recv = dialog->sa; } else return -1; @@ -4656,8 +4670,11 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) dialog->capability = peer->capability; dialog->prefs = peer->prefs; if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) { + struct sockaddr_in bindaddr_tmp; + /* t38pt_udptl was enabled in the peer and not in [general] */ - if (dialog->udptl || (!dialog->udptl && (dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr)))) { + ast_sockaddr_to_sin(&bindaddr, &bindaddr_tmp); + if (dialog->udptl || (!dialog->udptl && (dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr_tmp.sin_addr)))) { dialog->t38_maxdatagram = peer->t38_maxdatagram; set_t38_capabilities(dialog); } else { @@ -4723,7 +4740,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) dialog->disallowed_methods = peer->disallowed_methods; ast_cc_copy_config_params(dialog->cc_params, peer->cc_params); if (ast_strlen_zero(dialog->tohost)) - ast_string_field_set(dialog, tohost, ast_inet_ntoa(dialog->sa.sin_addr)); + ast_string_field_set(dialog, tohost, ast_sockaddr_stringify_host(&dialog->sa)); if (!ast_strlen_zero(peer->fromdomain)) { ast_string_field_set(dialog, fromdomain, peer->fromdomain); if (!dialog->initreq.headers) { @@ -4779,24 +4796,27 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) /*! \brief create address structure from device name * Or, if peer not found, find it in the global DNS * returns TRUE (-1) on failure, FALSE on success */ -static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog, struct sockaddr_in *remote_address) +static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog, struct ast_sockaddr *remote_address) { - struct hostent *hp; - struct ast_hostent ahp; struct sip_peer *peer; - char *port; - int portno = 0; - char host[MAXHOSTNAMELEN], *hostn; - char peername[256]; + char *peername, *peername2, *hostn; + char host[MAXHOSTNAMELEN]; + char service[MAXHOSTNAMELEN]; int srv_ret = 0; + int tportno; - ast_copy_string(peername, opeer, sizeof(peername)); - port = strchr(peername, ':'); - if (port) { - *port++ = '\0'; + AST_DECLARE_APP_ARGS(hostport, + AST_APP_ARG(host); + AST_APP_ARG(port); + ); + + peername = ast_strdupa(opeer); + peername2 = ast_strdupa(opeer); + AST_NONSTANDARD_RAW_ARGS(hostport, peername2, ':'); + + if (hostport.port) dialog->portinuri = 1; - } - dialog->sa.sin_family = AF_INET; + dialog->timer_t1 = global_t1; /* Default SIP retransmission timer T1 (RFC 3261) */ dialog->timer_b = global_timer_b; /* Default SIP transaction timer B (RFC 3261) */ peer = find_peer(peername, NULL, TRUE, FINDPEERS, FALSE, 0); @@ -4807,12 +4827,8 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd set_socket_transport(&dialog->socket, 0); } res = create_addr_from_peer(dialog, peer); - if (remote_address && remote_address->sin_addr.s_addr) { - dialog->sa = dialog->recv = *remote_address; - } else if (!ast_strlen_zero(port)) { - if ((portno = atoi(port))) { - dialog->sa.sin_port = dialog->recv.sin_port = htons(portno); - } + if (!ast_sockaddr_isnull(remote_address)) { + ast_sockaddr_copy(&dialog->sa, remote_address); } dialog->relatedpeer = ref_peer(peer, "create_addr: setting dialog's relatedpeer pointer"); unref_peer(peer, "create_addr: unref peer from find_peer hashtab lookup"); @@ -4823,20 +4839,15 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd return -1; } - ast_string_field_set(dialog, tohost, peername); + ast_string_field_set(dialog, tohost, hostport.host); dialog->allowed_methods &= ~sip_cfg.disallowed_methods; /* Get the outbound proxy information */ ref_proxy(dialog, obproxy_get(dialog, NULL)); - if (sin) { + if (addr) { /* This address should be updated using dnsmgr */ - memcpy(&dialog->sa.sin_addr, &sin->sin_addr, sizeof(dialog->sa.sin_addr)); - if (!sin->sin_port) { - portno = port_str2int(port, (dialog->socket.type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT); - } else { - portno = ntohs(sin->sin_port); - } + ast_sockaddr_copy(&dialog->sa, addr); } else { /* Let's see if we can find the host in DNS. First try DNS SRV records, @@ -4848,33 +4859,35 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd /* Section 4.2 of RFC 3263 specifies that if a port number is specified, then * an A record lookup should be used instead of SRV. */ - if (!port && sip_cfg.srvlookup) { - char service[MAXHOSTNAMELEN]; - int tportno; - + if (!hostport.port && sip_cfg.srvlookup) { snprintf(service, sizeof(service), "_sip._%s.%s", get_transport(dialog->socket.type), peername); - srv_ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service); - if (srv_ret > 0) { + if ((srv_ret = ast_get_srv(NULL, host, sizeof(host), &tportno, + service)) > 0) { hostn = host; - portno = tportno; } } - if (!portno) - portno = port_str2int(port, (dialog->socket.type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT); - hp = ast_gethostbyname(hostn, &ahp); - if (!hp) { + + if (ast_sockaddr_resolve_first(&dialog->sa, hostn, 0)) { ast_log(LOG_WARNING, "No such host: %s\n", peername); - return -1; } - memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr)); + + if (srv_ret > 0) { + ast_sockaddr_set_port(&dialog->sa, tportno); + } } if (!dialog->socket.type) set_socket_transport(&dialog->socket, SIP_TRANSPORT_UDP); - if (!dialog->socket.port) - dialog->socket.port = bindaddr.sin_port; - dialog->sa.sin_port = htons(portno); - dialog->recv = dialog->sa; + if (!dialog->socket.port) { + dialog->socket.port = htons(ast_sockaddr_port(&bindaddr)); + } + + if (!ast_sockaddr_port(&dialog->sa)) { + ast_sockaddr_set_port(&dialog->sa, + (dialog->socket.type == SIP_TRANSPORT_TLS) ? + STANDARD_TLS_PORT : STANDARD_SIP_PORT); + } + ast_sockaddr_copy(&dialog->recv, &dialog->sa); return 0; } @@ -6800,16 +6813,12 @@ static char *generate_random_string(char *buf, size_t size) static char *generate_uri(struct sip_pvt *pvt, char *buf, size_t size) { struct ast_str *uri = ast_str_alloca(size); - int ourport = ntohs(pvt->ourip.sin_port); ast_str_set(&uri, 0, "%s", pvt->socket.type == SIP_TRANSPORT_TLS ? "sips:" : "sip:"); /* Here would be a great place to generate a UUID, but for now we'll * use the handy random string generation function we already have */ ast_str_append(&uri, 0, "%s", generate_random_string(buf, size)); - ast_str_append(&uri, 0, "@%s", ast_inet_ntoa(pvt->ourip.sin_addr)); - if (!sip_standard_port(pvt->socket.type, ourport)) { - ast_str_append(&uri, 0, ":%d", ourport); - } + ast_str_append(&uri, 0, "@%s", ast_sockaddr_stringify(&pvt->ourip)); ast_copy_string(buf, ast_str_buffer(uri), size); return buf; } @@ -6819,18 +6828,18 @@ static void build_callid_pvt(struct sip_pvt *pvt) { char buf[33]; - const char *host = S_OR(pvt->fromdomain, ast_inet_ntoa(pvt->ourip.sin_addr)); + const char *host = S_OR(pvt->fromdomain, ast_sockaddr_stringify(&pvt->ourip)); ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host); } /*! \brief Build SIP Call-ID value for a REGISTER transaction */ -static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain) +static void build_callid_registry(struct sip_registry *reg, const struct ast_sockaddr *ourip, const char *fromdomain) { char buf[33]; - const char *host = S_OR(fromdomain, ast_inet_ntoa(ourip)); + const char *host = S_OR(fromdomain, ast_sockaddr_stringify_host(ourip)); ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host); } @@ -6865,7 +6874,7 @@ static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p) * Returns a reference to the object so whoever uses it later must * remember to release the reference. */ -struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, +struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, int useglobal_nat, const int intended_method, struct sip_request *req) { struct sip_pvt *p; @@ -6909,11 +6918,11 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, p->timer_b = global_timer_b; /* Default SIP transaction timer B (RFC 3261) */ } - if (!sin) + if (!addr) { p->ourip = internip; - else { - p->sa = *sin; - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); + } else { + ast_sockaddr_copy(&p->sa, addr); + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); } /* Copy global flags to this PVT at setup. */ @@ -6930,7 +6939,10 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, if (sip_methods[intended_method].need_rtp) { if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) { - if ((p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) { + struct sockaddr_in bindaddr_tmp; + + ast_sockaddr_to_sin(&bindaddr, &bindaddr_tmp); + if ((p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr_tmp.sin_addr))) { ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio); p->t38_maxdatagram = global_t38_maxdatagram; } else { @@ -6943,10 +6955,11 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, p->autoframing = global_autoframing; } - if (useglobal_nat && sin) { + if (useglobal_nat && addr) { /* Setup NAT structure according to global settings if we have an address */ ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT_FORCE_RPORT); - p->recv = *sin; + ast_sockaddr_copy(&p->recv, addr); + do_setnat(p); } @@ -6990,7 +7003,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, * Returns a reference to the sip_pvt object, remember to give it back once done. * Called by handle_incoming(), sipsock_read */ -static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method) +static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method) { struct sip_pvt *p = NULL; char *tag = ""; /* note, tag is never NULL */ @@ -7009,7 +7022,8 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si /* RFC 3261 section 24.4.1. Send a 400 Bad Request if the request is malformed. */ if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK) { - transmit_response_using_temp(callid, sin, 1, intended_method, req, "400 Bad Request"); + transmit_response_using_temp(callid, addr, 1, intended_method, + req, "400 Bad Request"); } return NULL; /* Invalid packet */ } @@ -7096,10 +7110,10 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) { if (intended_method == SIP_REFER) { /* We do support REFER, but not outside of a dialog yet */ - transmit_response_using_temp(callid, sin, 1, intended_method, req, "603 Declined (no dialog)"); + transmit_response_using_temp(callid, addr, 1, intended_method, req, "603 Declined (no dialog)"); } else { /* Ok, time to create a new SIP dialog object, a pvt */ - if ((p = sip_alloc(callid, sin, 1, intended_method, req))) { + if ((p = sip_alloc(callid, addr, 1, intended_method, req))) { /* Ok, we've created a dialog, let's go and process it */ sip_pvt_lock(p); } else { @@ -7111,18 +7125,18 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si Sorry, we apologize for the inconvienience */ - transmit_response_using_temp(callid, sin, 1, intended_method, req, "500 Server internal error"); + transmit_response_using_temp(callid, addr, 1, intended_method, req, "500 Server internal error"); ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n"); } } return p; /* can be NULL */ } else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) { /* A method we do not support, let's take it on the volley */ - transmit_response_using_temp(callid, sin, 1, intended_method, req, "501 Method Not Implemented"); + transmit_response_using_temp(callid, addr, 1, intended_method, req, "501 Method Not Implemented"); ast_debug(2, "Got a request with unsupported SIP method.\n"); } else if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK) { /* This is a request outside of a dialog that we don't know about */ - transmit_response_using_temp(callid, sin, 1, intended_method, req, "481 Call leg/transaction does not exist"); + transmit_response_using_temp(callid, addr, 1, intended_method, req, "481 Call leg/transaction does not exist"); ast_debug(2, "That's odd... Got a request in unknown dialog. Callid %s\n", callid ? callid : "<unknown>"); } /* We do not respond to responses for dialogs that we don't know about, we just drop @@ -7572,7 +7586,7 @@ static int find_sdp(struct sip_request *req) } -static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct sockaddr_in *sin) +static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct ast_sockaddr *addr) { const char *m; const char *c; @@ -7581,14 +7595,13 @@ static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_ty int x = 0; int numberofports; int len; - char host[258] = ""; /*Initialize to empty so we will know if we have any input */ - struct ast_hostent audiohp; - struct hostent *hp; + int af; + char proto[4], host[258] = ""; /*Initialize to empty so we will know if we have any input */ c = get_sdp_iterate(&citerator, req, "c"); - if (sscanf(c, "IN IP4 %256s", host) != 1) { - ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c); - /* Continue since there may be a valid host in a c= line specific to the audio stream */ + if (sscanf(c, "IN %3s %256s", proto, host) != 2) { + ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c); + /* Continue since there may be a valid host in a c= line specific to the audio stream */ } /* We only want the m and c lines for audio */ for (m = get_sdp_iterate(&miterator, req, "m"); !ast_strlen_zero(m); m = get_sdp_iterate(&miterator, req, "m")) { @@ -7602,25 +7615,31 @@ static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_ty */ c = get_sdp_iterate(&citerator, req, "c"); if (!ast_strlen_zero(c)) { - sscanf(c, "IN IP4 %256s", host); + sscanf(c, "IN %3s %256s", proto, host); } break; } } + if (!strcmp("IP4", proto)) { + af = AF_INET; + } else if (!strcmp("IP6", proto)) { + af = AF_INET6; + } else { + ast_log(LOG_WARNING, "Unknown protocol '%s'.\n", proto); + return -1; + } + if (ast_strlen_zero(host) || x == 0) { ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video"); return -1; } - hp = ast_gethostbyname(host, &audiohp); - if (!hp) { + if (ast_sockaddr_resolve_first_af(addr, host, 0, af)) { ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video"); return -1; } - memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); - sin->sin_port = htons(x); return 0; } @@ -7644,23 +7663,20 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int len = -1; /* Host information */ - struct ast_hostent sessionhp; - struct ast_hostent audiohp; - struct ast_hostent videohp; - struct ast_hostent texthp; - struct ast_hostent imagehp; - struct hostent *hp = NULL; /*!< RTP Audio host IP */ - struct hostent *vhp = NULL; /*!< RTP video host IP */ - struct hostent *thp = NULL; /*!< RTP text host IP */ - struct hostent *ihp = NULL; /*!< UDPTL host ip */ + struct ast_sockaddr sessionsa; + struct ast_sockaddr audiosa; + struct ast_sockaddr videosa; + struct ast_sockaddr textsa; + struct ast_sockaddr imagesa; + struct ast_sockaddr *sa = NULL; /*!< RTP Audio host IP */ + struct ast_sockaddr *vsa = NULL; /*!< RTP video host IP */ + struct ast_sockaddr *tsa = NULL; /*!< RTP text host IP */ + struct ast_sockaddr *isa = NULL; /*!< UDPTL host ip */ int portno = -1; /*!< RTP Audio port number */ int vportno = -1; /*!< RTP Video port number */ int tportno = -1; /*!< RTP Text port number */ int udptlportno = -1; /*!< UDPTL Image port number */ - struct sockaddr_in sin; /*!< media socket address */ - struct sockaddr_in vsin; /*!< video socket address */ struct sockaddr_in isin; /*!< image socket address */ - struct sockaddr_in tsin; /*!< text socket address */ /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */ format_t peercapability = 0, vpeercapability = 0, tpeercapability = 0; @@ -7741,12 +7757,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action return (p->session_modify == FALSE) ? 0 : -1; break; case 'c': - if (process_sdp_c(value, &sessionhp)) { + if (process_sdp_c(value, &sessionsa)) { processed = TRUE; - hp = &sessionhp.hp; - vhp = hp; - thp = hp; - ihp = hp; + sa = &sessionsa; + vsa = sa; + tsa = sa; + isa = sa; } break; case 'a': @@ -7891,24 +7907,24 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action switch (type) { case 'c': if (audio) { - if (process_sdp_c(value, &audiohp)) { + if (process_sdp_c(value, &audiosa)) { processed = TRUE; - hp = &audiohp.hp; + sa = &audiosa; } } else if (video) { - if (process_sdp_c(value, &videohp)) { + if (process_sdp_c(value, &videosa)) { processed = TRUE; - vhp = &videohp.hp; + vsa = &videosa; } } else if (text) { - if (process_sdp_c(value, &texthp)) { + if (process_sdp_c(value, &textsa)) { processed = TRUE; - thp = &texthp.hp; + tsa = &textsa; } } else if (image) { - if (process_sdp_c(value, &imagehp)) { + if (process_sdp_c(value, &imagesa)) { processed = TRUE; - ihp = &imagehp.hp; + isa = &imagesa; } } break; @@ -7956,7 +7972,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Sanity checks */ - if (!hp && !vhp && !thp && !ihp) { + if (!sa && !vsa && !tsa && !isa) { ast_log(LOG_WARNING, "Insufficient information in SDP (c=)...\n"); return -1; } @@ -8042,13 +8058,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Setup audio address and port */ if (p->rtp) { if (portno > 0) { - sin.sin_family = AF_INET; - sin.sin_port = htons(portno); - memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); - ast_rtp_instance_set_remote_address(p->rtp, &sin); - if (debug) - ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); - /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since + ast_sockaddr_set_port(sa, portno); + ast_rtp_instance_set_remote_address(p->rtp, sa); + if (debug) { + ast_verbose("Peer audio RTP is at port %s\n", + ast_sockaddr_stringify(sa)); + } + /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since they are acceptable */ p->jointcapability = newjointcapability; /* Our joint codec profile for this call */ p->peercapability = newpeercapability; /* The other sides capability in latest offer */ @@ -8085,12 +8101,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Setup video address and port */ if (p->vrtp) { if (vportno > 0) { - vsin.sin_family = AF_INET; - vsin.sin_port = htons(vportno); - memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr)); - ast_rtp_instance_set_remote_address(p->vrtp, &vsin); - if (debug) - ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port)); + ast_sockaddr_set_port(vsa, vportno); + ast_rtp_instance_set_remote_address(p->vrtp, vsa); + if (debug) { + ast_verbose("Peer video RTP is at port %s\n", + ast_sockaddr_stringify(vsa)); + } ast_rtp_codecs_payloads_copy(&newvideortp, ast_rtp_instance_get_codecs(p->vrtp), p->vrtp); } else { ast_rtp_instance_stop(p->vrtp); @@ -8102,12 +8118,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Setup text address and port */ if (p->trtp) { if (tportno > 0) { - tsin.sin_family = AF_INET; - tsin.sin_port = htons(tportno); - memcpy(&tsin.sin_addr, thp->h_addr, sizeof(tsin.sin_addr)); - ast_rtp_instance_set_remote_address(p->trtp, &tsin); - if (debug) - ast_verbose("Peer T.140 RTP is at port %s:%d\n", ast_inet_ntoa(tsin.sin_addr), ntohs(tsin.sin_port)); + ast_sockaddr_set_port(tsa, tportno); + ast_rtp_instance_set_remote_address(p->trtp, tsa); + if (debug) { + ast_verbose("Peer T.140 RTP is at port %s\n", + ast_sockaddr_stringify(tsa)); + } if ((p->jointcapability & AST_FORMAT_T140RED)) { p->red = 1; ast_rtp_red_init(p->trtp, 300, red_data_pt, 2); @@ -8128,7 +8144,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action isin.sin_port = htons(udptlportno); if (ast_test_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) { struct sockaddr_in remote_address = { 0, }; - ast_rtp_instance_get_remote_address(p->rtp, &remote_address); + struct ast_sockaddr remote_address_tmp; + + ast_rtp_instance_get_remote_address(p->rtp, + &remote_address_tmp); + ast_sockaddr_to_sin(&remote_address_tmp, + &remote_address); if (remote_address.sin_addr.s_addr) { memcpy(&isin, &remote_address, sizeof(isin)); if (debug) { @@ -8136,7 +8157,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } } } else { - memcpy(&isin.sin_addr, ihp->h_addr, sizeof(isin.sin_addr)); + ast_sockaddr_to_sin(isa, &isin); } ast_udptl_set_peer(p->udptl, &isin); if (debug) @@ -8207,7 +8228,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_set_write_format(p->owner, p->owner->writeformat); } - if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && sin.sin_addr.s_addr && (!sendonly || sendonly == -1)) { + if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && !ast_sockaddr_isnull(sa) && (!sendonly || sendonly == -1)) { ast_queue_control(p->owner, AST_CONTROL_UNHOLD); /* Activate a re-invite */ ast_queue_frame(p->owner, &ast_null_frame); @@ -8223,7 +8244,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (sip_cfg.notifyhold) sip_peer_hold(p, FALSE); ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */ - } else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1)) { + } else if (ast_sockaddr_isnull(sa) || (sendonly && sendonly != -1)) { int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); ast_queue_control_data(p->owner, AST_CONTROL_HOLD, S_OR(p->mohsuggest, NULL), @@ -8335,21 +8356,29 @@ static int process_sdp_o(const char *o, struct sip_pvt *p) return TRUE; } -static int process_sdp_c(const char *c, struct ast_hostent *ast_hp) +static int process_sdp_c(const char *c, struct ast_sockaddr *addr) { - char host[258]; - struct hostent *hp; + char proto[4], host[258]; + int af; /* Check for Media-description-level-address */ - if (sscanf(c, "IN IP4 %255s", host) != 1) { - ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c); - return FALSE; - } else { - if (!(hp = ast_gethostbyname(host, ast_hp))) { + if (sscanf(c, "IN %3s %255s", proto, host) == 2) { + if (!strcmp("IP4", proto)) { + af = AF_INET; + } else if (!strcmp("IP6", proto)) { + af = AF_INET6; + } else { + ast_log(LOG_WARNING, "Unknown protocol '%s'.\n", proto); + return FALSE; + } + if (ast_sockaddr_resolve_first_af(addr, host, 0, af)) { ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in c= line, '%s'\n", c); return FALSE; } return TRUE; + } else { + ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c); + return FALSE; } return FALSE; } @@ -8791,13 +8820,13 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st /* Add rport to first VIA header if requested */ snprintf(new, sizeof(new), "%s;received=%s;rport=%d%s%s", - leftmost, ast_inet_ntoa(p->recv.sin_addr), - ntohs(p->recv.sin_port), + leftmost, ast_sockaddr_stringify_addr(&p->recv), + ast_sockaddr_port(&p->recv), others ? "," : "", others ? others : ""); } else { /* We should *always* add a received to the topmost via */ snprintf(new, sizeof(new), "%s;received=%s%s%s", - leftmost, ast_inet_ntoa(p->recv.sin_addr), + leftmost, ast_sockaddr_stringify_addr(&p->recv), others ? "," : "", others ? others : ""); } oh = new; /* the header to copy */ @@ -8852,12 +8881,9 @@ static void add_route(struct sip_request *req, struct sip_route *route) static void set_destination(struct sip_pvt *p, char *uri) { char *h, *maddr, hostname[256]; - int port, hn; - struct hostent *hp; - struct ast_hostent ahp; + int hn; int debug=sip_debug_test_pvt(p); int tls_on = FALSE; - int use_dns = sip_cfg.srvlookup; if (debug) ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri); @@ -8875,44 +8901,53 @@ static void set_destination(struct sip_pvt *p, char *uri) tls_on = TRUE; } } - hn = strcspn(h, ":;>") + 1; + hn = strcspn(h, ";>") + 1; if (hn > sizeof(hostname)) hn = sizeof(hostname); ast_copy_string(hostname, h, hn); /* XXX bug here if string has been trimmed to sizeof(hostname) */ h += hn - 1; - /* Is "port" present? if not default to STANDARD_SIP_PORT */ - if (*h == ':') { - /* Parse port */ - ++h; - port = strtol(h, &h, 10); - use_dns = FALSE; - } else - port = tls_on ? STANDARD_TLS_PORT : STANDARD_SIP_PORT; + /*! \todo XXX If we have sip_cfg.srvlookup on, then look for NAPTR/SRV, + * otherwise, just look for A records */ + if (ast_sockaddr_resolve_first(&p->sa, hostname, 0)) { + ast_log(LOG_WARNING, "Can't find address for host '%s'\n", hostname); + return; + } - /* Got the hostname:port - but maybe there's a "maddr=" to override address? */ + /* Got the hostname - but maybe there's a "maddr=" to override address? */ maddr = strstr(h, "maddr="); if (maddr) { + int port; + maddr += 6; - hn = strspn(maddr, "0123456789.") + 1; + hn = strspn(maddr, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789-.:[]") + 1; if (hn > sizeof(hostname)) hn = sizeof(hostname); ast_copy_string(hostname, maddr, hn); + + port = ast_sockaddr_port(&p->sa); + + /*! \todo XXX If we have sip_cfg.srvlookup on, then look for + * NAPTR/SRV, otherwise, just look for A records */ + if (ast_sockaddr_resolve_first(&p->sa, hostname, PARSE_PORT_FORBID)) { + ast_log(LOG_WARNING, "Can't find address for host '%s'\n", hostname); + return; + } + + ast_sockaddr_set_port(&p->sa, port); } - /*! \todo XXX If we have use_dns on, then look for NAPTR/SRV, otherwise, just look for A records */ - - hp = ast_gethostbyname(hostname, &ahp); - if (hp == NULL) { - ast_log(LOG_WARNING, "Can't find address for host '%s'\n", hostname); - return; + if (!ast_sockaddr_port(&p->sa)) { + ast_sockaddr_set_port(&p->sa, tls_on ? + STANDARD_TLS_PORT : STANDARD_SIP_PORT); + } + + if (debug) { + ast_verbose("set_destination: set destination to %s\n", + ast_sockaddr_stringify(&p->sa)); } - p->sa.sin_family = AF_INET; - memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr)); - p->sa.sin_port = htons(port); - if (debug) - ast_verbose("set_destination: set destination to %s, port %d\n", ast_inet_ntoa(p->sa.sin_addr), port); } /*! \brief Initialize SIP response, based on SIP request */ @@ -9320,7 +9355,7 @@ static void temp_pvt_cleanup(void *data) } /*! \brief Transmit response, no retransmits, using a temporary pvt structure */ -static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg) +static int transmit_response_using_temp(ast_string_field callid, struct ast_sockaddr *addr, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg) { struct sip_pvt *p = NULL; @@ -9339,20 +9374,20 @@ static int transmit_response_using_temp(ast_string_field callid, struct sockaddr /* Initialize the bare minimum */ p->method = intended_method; - if (!sin) - p->ourip = internip; - else { - p->sa = *sin; - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); + if (!addr) { + ast_sockaddr_copy(&p->ourip, &internip); + } else { + ast_sockaddr_copy(&p->sa, addr); + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); } p->branch = ast_random(); make_our_tag(p->tag, sizeof(p->tag)); p->ocseq = INITIAL_CSEQ; - if (useglobal_nat && sin) { + if (useglobal_nat && addr) { ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT_FORCE_RPORT); - p->recv = *sin; + ast_sockaddr_copy(&p->recv, addr); do_setnat(p); } @@ -9620,7 +9655,7 @@ static int add_rpid(struct sip_request *req, struct sip_pvt *p) return 0; if (ast_strlen_zero(lid_name)) lid_name = lid_num; - fromdomain = S_OR(p->fromdomain, ast_strdupa(ast_inet_ntoa(p->ourip.sin_addr))); + fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip)); lid_num = ast_uri_encode(lid_num, tmp2, sizeof(tmp2), 1); @@ -9857,21 +9892,23 @@ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, \note called from add_sdp() */ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext, - struct sockaddr_in *sin, struct sockaddr_in *vsin, struct sockaddr_in *tsin, - struct sockaddr_in *dest, struct sockaddr_in *vdest, struct sockaddr_in *tdest) + struct ast_sockaddr *addr, struct ast_sockaddr *vaddr, + struct ast_sockaddr *taddr, struct ast_sockaddr *dest, + struct ast_sockaddr *vdest, struct ast_sockaddr *tdest) { /* First, get our address */ - ast_rtp_instance_get_local_address(p->rtp, sin); - if (p->vrtp) - ast_rtp_instance_get_local_address(p->vrtp, vsin); - if (p->trtp) - ast_rtp_instance_get_local_address(p->trtp, tsin); + ast_rtp_instance_get_local_address(p->rtp, addr); + if (p->vrtp) { + ast_rtp_instance_get_local_address(p->vrtp, vaddr); + } + if (p->trtp) { + ast_rtp_instance_get_local_address(p->trtp, taddr); + } /* Now, try to figure out where we want them to send data */ /* Is this a re-invite to move the media out, then use the original offer from caller */ - if (p->redirip.sin_addr.s_addr) { /* If we have a redirection IP, use it */ - dest->sin_port = p->redirip.sin_port; - dest->sin_addr = p->redirip.sin_addr; + if (!ast_sockaddr_isnull(&p->redirip)) { /* If we have a redirection IP, use it */ + ast_sockaddr_copy(dest, &p->redirip); } else { /* * Audio Destination IP: @@ -9884,15 +9921,17 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext * * 1. Provided by the RTP engine. */ - dest->sin_addr = media_address.sin_addr.s_addr ? media_address.sin_addr : - (sin->sin_addr.s_addr ? sin->sin_addr : p->ourip.sin_addr); - dest->sin_port = sin->sin_port; + ast_sockaddr_copy(dest, + !ast_sockaddr_isnull(&media_address) ? &media_address : + !ast_sockaddr_is_any(addr) ? addr : + &p->ourip); + ast_sockaddr_set_port(dest, ast_sockaddr_port(addr)); } + if (needvideo) { /* Determine video destination */ - if (p->vredirip.sin_addr.s_addr) { - vdest->sin_addr = p->vredirip.sin_addr; - vdest->sin_port = p->vredirip.sin_port; + if (!ast_sockaddr_isnull(&p->vredirip)) { + ast_sockaddr_copy(vdest, &p->vredirip); } else { /* * Video Destination IP: @@ -9905,16 +9944,18 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext * * 1. Provided by the RTP engine. */ - vdest->sin_addr = media_address.sin_addr.s_addr ? media_address.sin_addr : - (vsin->sin_addr.s_addr ? vsin->sin_addr : p->ourip.sin_addr); - vdest->sin_port = vsin->sin_port; + ast_sockaddr_copy(vdest, + !ast_sockaddr_isnull(&media_address) ? &media_address : + !ast_sockaddr_is_any(vaddr) ? vaddr : + &p->ourip); + ast_sockaddr_set_port(vdest, ast_sockaddr_port(vaddr)); } } + if (needtext) { /* Determine text destination */ - if (p->tredirip.sin_addr.s_addr) { - tdest->sin_addr = p->tredirip.sin_addr; - tdest->sin_port = p->tredirip.sin_port; + if (!ast_sockaddr_isnull(&p->tredirip)) { + ast_sockaddr_copy(tdest, &p->tredirip); } else { /* * Text Destination IP: @@ -9927,9 +9968,11 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext * * 1. Provided by the RTP engine. */ - tdest->sin_addr = media_address.sin_addr.s_addr ? media_address.sin_addr : - (tsin->sin_addr.s_addr ? tsin->sin_addr : p->ourip.sin_addr); - tdest->sin_port = tsin->sin_port; + ast_sockaddr_copy(tdest, + !ast_sockaddr_isnull(&media_address) ? &media_address : + !ast_sockaddr_is_any(taddr) ? taddr : + &p->ourip); + ast_sockaddr_set_port(tdest, ast_sockaddr_port(taddr)); } } } @@ -9961,13 +10004,14 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int { format_t alreadysent = 0; - struct sockaddr_in sin = { 0, }; - struct sockaddr_in vsin = { 0, }; - struct sockaddr_in tsin = { 0, }; - struct sockaddr_in dest = { 0, }; + struct ast_sockaddr addr = { {0,} }; + struct ast_sockaddr vaddr = { {0,} }; + struct ast_sockaddr taddr = { {0,} }; + struct ast_sockaddr dest = { {0,} }; + struct ast_sockaddr vdest = { {0,} }; + struct ast_sockaddr tdest = { {0,} }; + struct sockaddr_in dest_tmp; struct sockaddr_in udptlsin = { 0, }; - struct sockaddr_in vdest = { 0, }; - struct sockaddr_in tdest = { 0, }; struct sockaddr_in udptldest = { 0, }; /* SDP fields */ @@ -10048,11 +10092,19 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int } } - get_our_media_address(p, needvideo, needtext, &sin, &vsin, &tsin, &dest, &vdest, &tdest); + get_our_media_address(p, needvideo, needtext, &addr, &vaddr, &taddr, &dest, &vdest, &tdest); - snprintf(owner, sizeof(owner), "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr)); + snprintf(owner, sizeof(owner), "o=%s %d %d IN %s %s\r\n", + ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, + p->sessionid, p->sessionversion, + (ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ? + "IP6" : "IP4", + ast_sockaddr_stringify_addr(&dest)); - snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr)); + snprintf(connection, sizeof(connection), "c=IN %s %s\r\n", + (ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ? + "IP6" : "IP4", + ast_sockaddr_stringify_addr(&dest)); if (add_audio) { capability = p->jointcapability; @@ -10066,21 +10118,23 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int if (capability & AST_FORMAT_AUDIO_MASK) needaudio = TRUE; - if (debug) - ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(sin.sin_port)); + if (debug) { + ast_verbose("Audio is at %s\n", ast_sockaddr_stringify_port(&p->ourip)); + } /* Ok, we need video. Let's add what we need for video and set codecs. Video is handled differently than audio since we can not transcode. */ if (needvideo) { get_crypto_attrib(p->vsrtp, &v_a_crypto); - ast_str_append(&m_video, 0, "m=video %d RTP/%s", ntohs(vdest.sin_port), + ast_str_append(&m_video, 0, "m=video %d RTP/%s", ast_sockaddr_port(&vdest), v_a_crypto ? "SAVP" : "AVP"); /* Build max bitrate string */ if (p->maxcallbitrate) snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate); - if (debug) - ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vdest.sin_port)); + if (debug) { + ast_verbose("Video is at %s\n", ast_sockaddr_stringify(&p->ourip)); + } } /* Ok, we need text. Let's add what we need for text and set codecs. @@ -10089,11 +10143,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int if (sipdebug_text) ast_verbose("Lets set up the text sdp\n"); get_crypto_attrib(p->tsrtp, &t_a_crypto); - ast_str_append(&m_text, 0, "m=text %d RTP/%s", ntohs(tdest.sin_port), + ast_str_append(&m_text, 0, "m=text %d RTP/%s", ast_sockaddr_port(&tdest), t_a_crypto ? "SAVP" : "AVP"); - if (debug) /* XXX should I use tdest below ? */ - ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port)); - + if (debug) { /* XXX should I use tdest below ? */ + ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&p->ourip)); + } } /* Start building generic SDP headers */ @@ -10102,7 +10156,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int peer doesn't have to ast_gethostbyname() us */ get_crypto_attrib(p->srtp, &a_crypto); - ast_str_append(&m_audio, 0, "m=audio %d RTP/%s", ntohs(dest.sin_port), + ast_str_append(&m_audio, 0, "m=audio %d RTP/%s", ast_sockaddr_port(&dest), a_crypto ? "SAVP" : "AVP"); if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) @@ -10200,19 +10254,21 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int udptldest.sin_port = p->udptlredirip.sin_port; udptldest.sin_addr = p->udptlredirip.sin_addr; } else { - udptldest.sin_addr = p->ourip.sin_addr; + ast_sockaddr_to_sin(&p->ourip, &udptldest); udptldest.sin_port = udptlsin.sin_port; } - if (debug) - ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(udptlsin.sin_port)); + if (debug) { + ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_sockaddr_stringify_addr(&p->ourip), ntohs(udptlsin.sin_port)); + } /* We break with the "recommendation" and send our IP, in order that our peer doesn't have to ast_gethostbyname() us */ ast_str_append(&m_modem, 0, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port)); - if (udptldest.sin_addr.s_addr != dest.sin_addr.s_addr) { + ast_sockaddr_to_sin(&dest, &dest_tmp); + if (udptldest.sin_addr.s_addr != dest_tmp.sin_addr.s_addr) { ast_str_append(&m_modem, 0, "c=IN IP4 %s\r\n", ast_inet_ntoa(udptldest.sin_addr)); } @@ -10551,19 +10607,13 @@ static void extract_uri(struct sip_pvt *p, struct sip_request *req) /*! \brief Build contact header - the contact header we send out */ static void build_contact(struct sip_pvt *p) { - - int ourport = ntohs(p->ourip.sin_port); - /* only add port if it's non-standard for the transport type */ - if (!sip_standard_port(p->socket.type, ourport)) { - if (p->socket.type == SIP_TRANSPORT_UDP) - ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport); - else - ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d;transport=%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type)); + if (p->socket.type == SIP_TRANSPORT_UDP) { + ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, + ast_strlen_zero(p->exten) ? "" : "@", ast_sockaddr_stringify(&p->ourip)); } else { - if (p->socket.type == SIP_TRANSPORT_UDP) - ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr)); - else - ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), get_transport(p->socket.type)); + ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", p->exten, + ast_strlen_zero(p->exten) ? "" : "@", ast_sockaddr_stringify(&p->ourip), + get_transport(p->socket.type)); } } @@ -10603,7 +10653,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text); - d = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); + d = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip)); if (p->owner && (p->owner->connected.id.number_presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) { l = p->owner->connected.id.number; n = p->owner->connected.id.name; @@ -10647,13 +10697,12 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho l = tmp_l; } - ourport = (p->fromdomainport) ? p->fromdomainport : ntohs(p->ourip.sin_port); + ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip); if (!sip_standard_port(p->socket.type, ourport)) snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, d, ourport, p->tag); else snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, d, p->tag); - if (!ast_strlen_zero(explicit_uri)) { ast_str_set(&invite, 0, "%s", explicit_uri); } else { @@ -10673,8 +10722,9 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho ast_str_append(&invite, 0, "%s@", n); } ast_str_append(&invite, 0, "%s", p->tohost); - if (p->portinuri) - ast_str_append(&invite, 0, ":%d", ntohs(p->sa.sin_port)); + if (p->portinuri) { + ast_str_append(&invite, 0, ":%d", ast_sockaddr_port(&p->sa)); + } ast_str_append(&invite, 0, "%s", urioptions); } } @@ -10759,9 +10809,12 @@ static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt) /* We at least have a number to place in the Diversion header, which is enough */ if (ast_strlen_zero(diverting_name)) { - snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason); + snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number, + ast_sockaddr_stringify_host(&pvt->ourip), reason); } else { - snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s", diverting_name, diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason); + snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s", + diverting_name, diverting_number, + ast_sockaddr_stringify_host(&pvt->ourip), reason); } add_header(req, "Diversion", header_text); @@ -10784,7 +10837,7 @@ static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_ty dialog_unlink_all(pvt, TRUE, TRUE); dialog_unref(pvt, "create_addr failed in transmit_publish. Unref dialog"); } - ast_sip_ouraddrfor(&pvt->sa.sin_addr, &pvt->ourip, pvt); + ast_sip_ouraddrfor(&pvt->sa, &pvt->ourip, pvt); ast_set_flag(&pvt->flags[0], SIP_OUTGOING); expires = (publish_type == SIP_PUBLISH_REMOVE) ? 0 : DEFAULT_PUBLISH_EXPIRES; pvt->expiry = expires; @@ -10986,6 +11039,8 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi) if (!mwi->dnsmgr) { char transport[MAXHOSTNAMELEN]; snprintf(transport, sizeof(transport), "_sip._%s", get_transport(mwi->transport)); + + mwi->us.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */ ast_dnsmgr_lookup(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL); } @@ -11002,8 +11057,8 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi) ref_proxy(mwi->call, obproxy_get(mwi->call, NULL)); - if (!mwi->us.sin_port && mwi->portno) { - mwi->us.sin_port = htons(mwi->portno); + if (!ast_sockaddr_port(&mwi->us) && mwi->portno) { + ast_sockaddr_set_port(&mwi->us, mwi->portno); } /* Setup the destination of our subscription */ @@ -11016,10 +11071,10 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi) mwi->call->expiry = mwi_expiry; if (!mwi->dnsmgr && mwi->portno) { - mwi->call->sa.sin_port = htons(mwi->portno); - mwi->call->recv.sin_port = htons(mwi->portno); + ast_sockaddr_set_port(&mwi->call->sa, mwi->portno); + ast_sockaddr_set_port(&mwi->call->recv, mwi->portno); } else { - mwi->portno = ntohs(mwi->call->sa.sin_port); + mwi->portno = ast_sockaddr_port(&mwi->call->sa); } /* Set various other information */ @@ -11038,7 +11093,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi) } set_socket_transport(&mwi->call->socket, mwi->transport); mwi->call->socket.port = htons(mwi->portno); - ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip, mwi->call); + ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call); build_contact(mwi->call); build_via(mwi->call); build_callid_pvt(mwi->call); @@ -11353,8 +11408,8 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, { struct sip_request req; struct ast_str *out = ast_str_alloca(500); - int ourport = (p->fromdomainport) ? p->fromdomainport : ntohs(p->ourip.sin_port); - const char *domain = S_OR(p->fromdomain,ast_inet_ntoa(p->ourip.sin_addr)); + int ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip); + const char *domain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip)); const char *exten = S_OR(vmexten, default_vmexten); initreqprep(&req, p, SIP_NOTIFY, NULL); @@ -11697,6 +11752,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * char transport[MAXHOSTNAMELEN]; peer = find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0); snprintf(transport, sizeof(transport), "_sip._%s", get_transport(r->transport)); /* have to use static get_transport function */ + r->us.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */ ast_dnsmgr_lookup(peer ? peer->tohost : r->hostname, &r->us, &r->dnsmgr, sip_cfg.srvlookup ? transport : NULL); if (peer) { peer = unref_peer(peer, "removing peer ref for dnsmgr_lookup"); @@ -11715,7 +11771,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * } else { /* Build callid for registration if we haven't registered before */ if (!r->callid_valid) { - build_callid_registry(r, internip.sin_addr, default_fromdomain); + build_callid_registry(r, &internip, default_fromdomain); r->callid_valid = TRUE; } /* Allocate SIP dialog for registration */ @@ -11728,8 +11784,9 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname); /* Use port number specified if no SRV record was found */ - if (!r->us.sin_port && r->portno) - r->us.sin_port = htons(r->portno); + if (!ast_sockaddr_port(&r->us) && r->portno) { + ast_sockaddr_set_port(&r->us, r->portno); + } /* Find address to hostname */ if (create_addr(p, S_OR(r->peername, r->hostname), &r->us, 0, NULL)) { @@ -11755,15 +11812,15 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * ast_string_field_set(r, callid, p->callid); if (!r->dnsmgr && r->portno) { - p->sa.sin_port = htons(r->portno); - p->recv.sin_port = htons(r->portno); + ast_sockaddr_set_port(&p->sa, r->portno); + ast_sockaddr_set_port(&p->recv, r->portno); } if (!ast_strlen_zero(p->fromdomain)) { portno = (p->fromdomainport) ? p->fromdomainport : STANDARD_SIP_PORT; } else if (!ast_strlen_zero(r->regdomain)) { portno = (r->regdomainport) ? r->regdomainport : STANDARD_SIP_PORT; } else { - portno = ntohs(p->sa.sin_port); + portno = ast_sockaddr_port(&p->sa); } ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Registration is outgoing call */ @@ -11793,7 +11850,8 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * /* Set transport and port so the correct contact is built */ set_socket_transport(&p->socket, r->transport); if (r->transport == SIP_TRANSPORT_TLS || r->transport == SIP_TRANSPORT_TCP) { - p->socket.port = sip_tcp_desc.local_address.sin_port; + p->socket.port = + htons(ast_sockaddr_port(&sip_tcp_desc.local_address)); } /* @@ -11801,7 +11859,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * based on whether the remote host is on the external or internal network so we can register through nat */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); build_contact(p); } @@ -12196,7 +12254,7 @@ static int expire_register(const void *data) if (peer->selfdestruct || ast_test_flag(&peer->flags[1], SIP_PAGE2_RTAUTOCLEAR)) { ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table"); - if (peer->addr.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&peer->addr)) { ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table"); } } @@ -12224,30 +12282,28 @@ static int sip_poke_peer_s(const void *data) static void reg_source_db(struct sip_peer *peer) { char data[256]; - struct in_addr in; + struct ast_sockaddr sa; int expire; - int port; - char *scan, *addr, *port_str, *expiry_str, *username, *contact; + char *scan, *addr, *expiry_str, *username, *contact; if (peer->rt_fromcontact) return; if (ast_db_get("SIP/Registry", peer->name, data, sizeof(data))) return; - scan = data; - addr = strsep(&scan, ":"); - port_str = strsep(&scan, ":"); + addr = scan = data; + if ('[' == scan[0]) { + /* It must be a bracket enclosed IPv6 address */ + scan = strchr(scan, ']') + 1; + } + scan = strchr(scan, ':') + 1; expiry_str = strsep(&scan, ":"); username = strsep(&scan, ":"); contact = scan; /* Contact include sip: and has to be the last part of the database entry as long as we use : as a separator */ - if (!inet_aton(addr, &in)) - return; - - if (port_str) - port = atoi(port_str); - else + if (!ast_sockaddr_parse(&sa, addr, 0)) { return; + } if (expiry_str) expire = atoi(expiry_str); @@ -12259,13 +12315,10 @@ static void reg_source_db(struct sip_peer *peer) if (contact) ast_string_field_set(peer, fullcontact, contact); - ast_debug(2, "SIP Seeding peer from astdb: '%s' at %s@%s:%d for %d\n", - peer->name, peer->username, ast_inet_ntoa(in), port, expire); + ast_debug(2, "SIP Seeding peer from astdb: '%s' at %s@%s for %d\n", + peer->name, peer->username, ast_sockaddr_stringify_host(&sa), expire); - memset(&peer->addr, 0, sizeof(peer->addr)); - peer->addr.sin_family = AF_INET; - peer->addr.sin_addr = in; - peer->addr.sin_port = htons(port); + ast_sockaddr_copy(&peer->addr, &sa); if (sipsock < 0) { /* SIP isn't up yet, so schedule a poke only, pretty soon */ AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, ast_random() % 5000 + 1, sip_poke_peer_s, peer, @@ -12303,12 +12356,9 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req) return TRUE; } -static int __set_address_from_contact(const char *fullcontact, struct sockaddr_in *sin, int tcp) +static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp) { - struct hostent *hp; - struct ast_hostent ahp; - int port = STANDARD_SIP_PORT; - char *host, *pt, *transport; + char *domain, *transport; char contact_buf[256]; char *contact; @@ -12323,32 +12373,32 @@ static int __set_address_from_contact(const char *fullcontact, struct sockaddr_i * We still need to be able to send to the remote agent through the proxy. */ - if (parse_uri(contact, "sip:,sips:", &contact, NULL, &host, &pt, &transport)) { + if (parse_uri(contact, "sip:,sips:", &contact, NULL, &domain, + &transport)) { ast_log(LOG_WARNING, "Invalid contact uri %s (missing sip: or sips:), attempting to use anyway\n", fullcontact); } - /* set port */ - if (((get_transport_str2enum(transport) == SIP_TRANSPORT_TLS)) || !(strncasecmp(fullcontact, "sips", 4))) { - port = port_str2int(pt, STANDARD_TLS_PORT); - } else { - port = port_str2int(pt, STANDARD_SIP_PORT); - } - - /* XXX This could block for a long time XXX */ /* We should only do this if it's a name, not an IP */ /* \todo - if there's no PORT number in contact - we are required to check NAPTR/SRV records to find transport, port address and hostname. If there's a port number, we have to assume that the domain part is a host name and only look for an A/AAAA record in DNS. */ - hp = ast_gethostbyname(host, &ahp); - if (!hp) { - ast_log(LOG_WARNING, "Invalid host name in Contact: (can't resolve in DNS) : '%s'\n", host); + + if (ast_sockaddr_resolve_first(addr, domain, 0)) { + ast_log(LOG_WARNING, "Invalid host name in Contact: (can't " + "resolve in DNS) : '%s'\n", domain); return -1; } - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); - sin->sin_port = htons(port); + + /* set port */ + if (!ast_sockaddr_port(addr)) { + ast_sockaddr_set_port(addr, + (get_transport_str2enum(transport) == + SIP_TRANSPORT_TLS || + !strncasecmp(fullcontact, "sips", 4)) ? + STANDARD_TLS_PORT : STANDARD_SIP_PORT); + } return 0; } @@ -12374,14 +12424,11 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st char data[SIPBUFSIZE]; const char *expires = get_header(req, "Expires"); int expire = atoi(expires); - char *curi, *host, *pt, *transport; - int port; + char *curi, *domain, *transport; int transport_type; const char *useragent; - struct hostent *hp; - struct ast_hostent ahp; - struct sockaddr_in oldsin, testsin; - + struct ast_sockaddr oldsin, testsa; + struct sockaddr_in testsin; ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); @@ -12445,23 +12492,12 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st ast_string_field_build(pvt, our_contact, "<%s>", curi); /* Make sure it's a SIP URL */ - if (parse_uri(curi, "sip:,sips:", &curi, NULL, &host, &pt, &transport)) { + if (parse_uri(curi, "sip:,sips:", &curi, NULL, &domain, &transport)) { ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:) trying to use anyway\n"); } - /* If we have a port number in the given URI, make sure we do remember to not check for NAPTR/SRV records. - The domain part is actually a host. */ - peer->portinuri = !ast_strlen_zero(pt) ? TRUE : FALSE; - /* handle the transport type specified in Contact header. */ - if ((transport_type = get_transport_str2enum(transport))) { - /* if the port is not specified but the transport is, make sure to set the - * default port to match the specified transport. This may or may not be the - * same transport used by the pvt struct for the Register dialog. */ - - port = port_str2int(pt, (transport_type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT); - } else { - port = port_str2int(pt, STANDARD_SIP_PORT); + if (!(transport_type = get_transport_str2enum(transport))) { transport_type = pvt->socket.type; } @@ -12475,25 +12511,32 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st oldsin = peer->addr; /* If we were already linked into the peers_by_ip container unlink ourselves so nobody can find us */ - if (peer->addr.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&peer->addr)) { ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table"); } if (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) && !ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT)) { - /* use the data provided in the Contact header for call routing */ + /* use the data provided in the Contact header for call routing */ ast_debug(1, "Store REGISTER's Contact header for call routing.\n"); /* XXX This could block for a long time XXX */ /*! \todo Check NAPTR/SRV if we have not got a port in the URI */ - hp = ast_gethostbyname(host, &ahp); - if (!hp) { - ast_log(LOG_WARNING, "Invalid host '%s'\n", host); + if (ast_sockaddr_resolve_first(&testsa, domain, 0)) { + ast_log(LOG_WARNING, "Invalid domain '%s'\n", domain); ast_string_field_set(peer, fullcontact, ""); ast_string_field_set(pvt, our_contact, ""); return PARSE_REGISTER_FAILED; } - peer->addr.sin_family = AF_INET; - memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr)); - peer->addr.sin_port = htons(port); + ast_sockaddr_copy(&peer->addr, &testsa); + + /* If we have a port number in the given URI, make sure we do remember to not check for NAPTR/SRV records. + The domain part is actually a host. */ + peer->portinuri = ast_sockaddr_port(&testsa) ? TRUE : FALSE; + + if (!ast_sockaddr_port(&testsa)) { + ast_sockaddr_set_port(&testsa, + transport_type == SIP_TRANSPORT_TLS ? + STANDARD_TLS_PORT : STANDARD_SIP_PORT); + } } else { /* Don't trust the contact field. Just use what they came to us with */ @@ -12502,22 +12545,23 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st } /* Check that they're allowed to register at this IP */ - memcpy(&testsin.sin_addr, &peer->addr.sin_addr, sizeof(testsin.sin_addr)); - if (ast_apply_ha(sip_cfg.contact_ha, &testsin) != AST_SENSE_ALLOW || - ast_apply_ha(peer->contactha, &testsin) != AST_SENSE_ALLOW) { - ast_log(LOG_WARNING, "Host '%s' disallowed by contact ACL (violating IP %s)\n", host, ast_inet_ntoa(testsin.sin_addr)); - ast_string_field_set(peer, fullcontact, ""); - ast_string_field_set(pvt, our_contact, ""); - return PARSE_REGISTER_DENIED; + if (!ast_sockaddr_is_ipv6(&peer->addr)) { + ast_sockaddr_to_sin(&peer->addr, &testsin); + if (ast_apply_ha(sip_cfg.contact_ha, &testsin) != AST_SENSE_ALLOW || + ast_apply_ha(peer->contactha, &testsin) != AST_SENSE_ALLOW) { + ast_log(LOG_WARNING, "Domain '%s' disallowed by contact ACL (violating IP %s)\n", domain, + ast_sockaddr_stringify_addr(&testsa)); + ast_string_field_set(peer, fullcontact, ""); + ast_string_field_set(pvt, our_contact, ""); + return PARSE_REGISTER_DENIED; + } } /* if the Contact header information copied into peer->addr matches the * received address, and the transport types are the same, then copy socket * data into the peer struct */ if ((peer->socket.type == pvt->socket.type) && - (peer->addr.sin_addr.s_addr == pvt->recv.sin_addr.s_addr) && - (peer->addr.sin_port == pvt->recv.sin_port)){ - + !ast_sockaddr_cmp(&peer->addr, &pvt->recv)) { copy_socket_data(&peer->socket, &pvt->socket); } @@ -12547,18 +12591,20 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st } } pvt->expiry = expire; - snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port), expire, peer->username, peer->fullcontact); + snprintf(data, sizeof(data), "%s:%d:%s:%s", ast_sockaddr_stringify(&peer->addr), + expire, peer->username, peer->fullcontact); /* Saving TCP connections is useless, we won't be able to reconnect XXX WHY???? XXX \todo Fix this immediately. */ if (!peer->rt_fromcontact && (peer->socket.type & SIP_TRANSPORT_UDP)) ast_db_put("SIP/Registry", peer->name, data); - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\nPort: %d\r\n", peer->name, ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port)); + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name, ast_sockaddr_stringify(&peer->addr)); /* Is this a new IP address for us? */ - if (VERBOSITY_ATLEAST(2) && inaddrcmp(&peer->addr, &oldsin)) { - ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s port %d\n", peer->name, ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port)); + if (VERBOSITY_ATLEAST(2) && ast_sockaddr_cmp(&peer->addr, &oldsin)) { + ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s\n", peer->name, + ast_sockaddr_stringify(&peer->addr)); } sip_poke_peer(peer, 0); register_peer_exten(peer, 1); @@ -13084,7 +13130,7 @@ static char *terminate_uri(char *uri) to get a challenge (nonce) then a second one with auth - Registration requests are only matched with peers that are marked as "dynamic" */ -static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin, +static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr, struct sip_request *req, const char *uri) { enum check_auth_result res = AUTH_NOT_FOUND; @@ -13100,8 +13146,8 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr c = get_in_brackets(tmp); c = remove_uri_parameters(c); - if (parse_uri(c, "sip:,sips:", &name, &dummy, &domain, &dummy, NULL)) { - ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(sin->sin_addr)); + if (parse_uri(c, "sip:,sips:", &name, &dummy, &domain, NULL)) { + ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_sockaddr_stringify_addr(addr)); return -1; } @@ -13136,14 +13182,20 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr } } peer = find_peer(name, NULL, TRUE, FINDPEERS, FALSE, 0); - if (!(peer && ast_apply_ha(peer->ha, sin))) { - /* Peer fails ACL check */ - if (peer) { - unref_peer(peer, "register_verify: unref_peer: from find_peer operation"); - peer = NULL; - res = AUTH_ACL_FAILED; - } else - res = AUTH_NOT_FOUND; + + if (!ast_sockaddr_is_ipv6(addr)) { + struct sockaddr_in sin_tmp; + + ast_sockaddr_to_sin(addr, &sin_tmp); + if (!(peer && ast_apply_ha(peer->ha, &sin_tmp))) { + /* Peer fails ACL check */ + if (peer) { + unref_peer(peer, "register_verify: unref_peer: from find_peer operation"); + peer = NULL; + res = AUTH_ACL_FAILED; + } else + res = AUTH_NOT_FOUND; + } } if (peer) { @@ -13207,7 +13259,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr peer = temp_peer(name); if (peer) { ao2_t_link(peers, peer, "link peer into peer table"); - if (peer->addr.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&peer->addr)) { ao2_t_link(peers_by_ip, peer, "link peer into peers-by-ip table"); } ao2_lock(peer); @@ -13236,7 +13288,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr ast_string_field_set(p, fullcontact, peer->fullcontact); /* Say OK and ask subsystem to retransmit msg counter */ transmit_response_with_date(p, "200 OK", req); - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\nPort: %d\r\n", peer->name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name, ast_sockaddr_stringify(addr)); peer->lastmsgssent = -1; res = 0; break; @@ -13260,9 +13312,17 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr case AUTH_SECRET_FAILED: /* Wrong password in authentication. Go away, don't try again until you fixed it */ transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); - if (global_authfailureevents) - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Rejected\r\nCause: AUTH_SECRET_FAILED\r\nAddress: %s\r\nPort: %d\r\n", - name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); + if (global_authfailureevents) { + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", + "ChannelType: SIP\r\n" + "Peer: SIP/%s\r\n" + "PeerStatus: Rejected\r\n" + "Cause: AUTH_SECRET_FAILED\r\n" + "Address: %s\r\n" + "Port: %s\r\n", + name, ast_sockaddr_stringify_addr(addr), + ast_sockaddr_stringify_port(addr)); + } break; case AUTH_USERNAME_MISMATCH: /* Username and digest username does not match. @@ -13275,9 +13335,17 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr if (sip_cfg.alwaysauthreject) { transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE); if (global_authfailureevents) { - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Rejected\r\nCause: %s\r\nAddress: %s\r\nPort: %d\r\n", - name, res == AUTH_PEER_NOT_DYNAMIC ? "AUTH_PEER_NOT_DYNAMIC" : "URI_NOT_FOUND", - ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", + "ChannelType: SIP\r\n" + "Peer: SIP/%s\r\n" + "PeerStatus: Rejected\r\n" + "Cause: %s\r\n" + "Address: %s\r\n" + "Port: %s\r\n", + name, + res == AUTH_PEER_NOT_DYNAMIC ? "AUTH_PEER_NOT_DYNAMIC" : "URI_NOT_FOUND", + ast_sockaddr_stringify_addr(addr), + ast_sockaddr_stringify_port(addr)); } } else { /* URI not found */ @@ -13290,8 +13358,10 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr "PeerStatus: Rejected\r\n" "Cause: AUTH_PEER_NOT_DYNAMIC\r\n" "Address: %s\r\n" - "Port: %d\r\n", - name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); + "Port: %s\r\n", + name, + ast_sockaddr_stringify_addr(addr), + ast_sockaddr_stringify_port(addr)); } } else { transmit_response(p, "404 Not found", &p->initreq); @@ -13302,9 +13372,11 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr "PeerStatus: Rejected\r\n" "Cause: %s\r\n" "Address: %s\r\n" - "Port: %d\r\n", - name, (res == AUTH_USERNAME_MISMATCH) ? "AUTH_USERNAME_MISMATCH" : "URI_NOT_FOUND", - ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); + "Port: %s\r\n", + name, + (res == AUTH_USERNAME_MISMATCH) ? "AUTH_USERNAME_MISMATCH" : "URI_NOT_FOUND", + ast_sockaddr_stringify_addr(addr), + ast_sockaddr_stringify_port(addr)); } } } @@ -13645,7 +13717,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re uri = ast_strdupa(get_in_brackets(tmp)); - if (parse_uri(uri, "sip:,sips:", &uri, &dummy, &domain, &dummy, NULL)) { + if (parse_uri(uri, "sip:,sips:", &uri, &dummy, &domain, NULL)) { ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri); return SIP_GET_DEST_INVALID_URI; } @@ -13662,7 +13734,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf)); if (!ast_strlen_zero(tmpf)) { from = get_in_brackets(tmpf); - if (parse_uri(from, "sip:,sips:", &from, NULL, &domain, NULL, NULL)) { + if (parse_uri(from, "sip:,sips:", &from, NULL, &domain, NULL)) { ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from); return SIP_GET_DEST_INVALID_URI; } @@ -14033,7 +14105,7 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq) ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp)); c = get_in_brackets(tmp); - if (parse_uri(c, "sip:,sips:", &c, NULL, &a, NULL, NULL)) { + if (parse_uri(c, "sip:,sips:", &c, NULL, &a, NULL)) { ast_log(LOG_WARNING, "Huh? Not a SIP header in Also: transfer (%s)?\n", c); return -1; } @@ -14104,9 +14176,9 @@ static attribute_unused void check_via_response(struct sip_pvt *p, struct sip_re if (!strncmp(cur, "rport=", 6)) { int port = strtol(cur+6, NULL, 10); /* XXX add error checking */ - p->ourip.sin_port = ntohs(port); + ast_sockaddr_set_port(&p->ourip, port); } else if (!strncmp(cur, "received=", 9)) { - if (ast_parse_arg(cur+9, PARSE_INADDR, &p->ourip)) + if (ast_parse_arg(cur + 9, PARSE_ADDR, &p->ourip)) ; /* XXX add error checking */ } } @@ -14127,14 +14199,17 @@ static void check_via(struct sip_pvt *p, struct sip_request *req) /* Check for rport */ c = strstr(via, ";rport"); - if (c && (c[6] != '=')) /* rport query, not answer */ + if (c && (c[6] != '=')) { /* rport query, not answer */ ast_set_flag(&p->flags[1], SIP_PAGE2_RPORT_PRESENT); + ast_set_flag(&p->flags[0], SIP_NAT_RPORT_PRESENT); + } /* Check for maddr */ maddr = strstr(via, "maddr="); if (maddr) { maddr += 6; - c = maddr + strspn(maddr, "0123456789."); + c = maddr + strspn(maddr, "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.:[]"); *c = '\0'; } @@ -14144,9 +14219,6 @@ static void check_via(struct sip_pvt *p, struct sip_request *req) c = strchr(via, ' '); if (c) { - struct hostent *hp; - struct ast_hostent ahp; - *c = '\0'; c = ast_skip_blanks(c+1); if (strcasecmp(via, "SIP/2.0/UDP") && strcasecmp(via, "SIP/2.0/TCP") && strcasecmp(via, "SIP/2.0/TLS")) { @@ -14157,28 +14229,28 @@ static void check_via(struct sip_pvt *p, struct sip_request *req) if (pt) *pt++ = '\0'; /* remember port pointer */ - if (maddr && (hp = ast_gethostbyname(maddr, &ahp))) { - memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr)); - } else { + if (maddr && ast_sockaddr_resolve_first(&p->sa, maddr, 0)) { p->sa = p->recv; } - p->sa.sin_port = htons(port_str2int(pt, STANDARD_SIP_PORT)); + + ast_sockaddr_set_port(&p->sa, port_str2int(pt, STANDARD_SIP_PORT)); if (sip_debug_test_pvt(p)) { - const struct sockaddr_in *dst = sip_real_dst(p); - ast_verbose("Sending to %s : %d (%s)\n", ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), sip_nat_mode(p)); + ast_verbose("Sending to %s (%s)\n", + ast_sockaddr_stringify(sip_real_dst(p)), + sip_nat_mode(p)); } } } /*! \brief Validate device authentication */ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, - struct sip_request *req, int sipmethod, struct sockaddr_in *sin, + struct sip_request *req, int sipmethod, struct ast_sockaddr *addr, struct sip_peer **authpeer, enum xmittype reliable, char *calleridname, char *uri2) { enum check_auth_result res; - int debug=sip_debug_test_addr(sin); + int debug = sip_debug_test_addr(addr); struct sip_peer *peer; if (sipmethod == SIP_SUBSCRIBE) { @@ -14197,19 +14269,25 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, } if (!peer) { - if (debug) - ast_verbose("No matching peer for '%s' from '%s:%d'\n", - of, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + if (debug) { + ast_verbose("No matching peer for '%s' from '%s'\n", + of, ast_sockaddr_stringify(&p->recv)); + } return AUTH_DONT_KNOW; } - if (!ast_apply_ha(peer->ha, sin)) { - ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of); - unref_peer(peer, "unref_peer: check_peer_ok: from find_peer call, early return of AUTH_ACL_FAILED"); - return AUTH_ACL_FAILED; + if (!ast_sockaddr_is_ipv6(addr)) { + struct sockaddr_in sin_tmp; + + ast_sockaddr_to_sin(addr, &sin_tmp); + if (!ast_apply_ha(peer->ha, &sin_tmp)) { + ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of); + unref_peer(peer, "unref_peer: check_peer_ok: from find_peer call, early return of AUTH_ACL_FAILED"); + return AUTH_ACL_FAILED; + } } if (debug) - ast_verbose("Found peer '%s' for '%s' from %s:%d\n", - peer->name, of, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + ast_verbose("Found peer '%s' for '%s' from %s\n", + peer->name, of, ast_sockaddr_stringify(&p->recv)); /* XXX what about p->prefs = peer->prefs; ? */ /* Set Frame packetization */ @@ -14346,7 +14424,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, */ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, - struct sockaddr_in *sin, struct sip_peer **authpeer) + struct ast_sockaddr *addr, struct sip_peer **authpeer) { char from[256] = { 0, }; char *dummy = NULL; /* dummy return value for parse_uri */ @@ -14392,7 +14470,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ ast_string_field_set(p, from, of); /* ignore all fields but name */ - if (parse_uri(of, "sip:,sips:", &of, &dummy, &domain, &dummy, NULL)) { + if (parse_uri(of, "sip:,sips:", &of, &dummy, &domain, NULL)) { ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n"); } @@ -14438,7 +14516,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ } } - res = check_peer_ok(p, of, req, sipmethod, sin, + res = check_peer_ok(p, of, req, sipmethod, addr, authpeer, reliable, calleridname, uri2); if (res != AUTH_DONT_KNOW) return res; @@ -14467,9 +14545,9 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ /*! \brief Find user If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced */ -static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct sockaddr_in *sin) +static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct ast_sockaddr *addr) { - return check_user_full(p, req, sipmethod, uri, reliable, sin, NULL); + return check_user_full(p, req, sipmethod, uri, reliable, addr, NULL); } /*! \brief Get text out of a SIP MESSAGE packet */ @@ -14674,8 +14752,8 @@ static char *sip_show_tcp(struct ast_cli_entry *e, int cmd, struct ast_cli_args struct sip_threadinfo *th; struct ao2_iterator i; -#define FORMAT2 "%-30.30s %3.6s %9.9s %6.6s\n" -#define FORMAT "%-30.30s %-6d %-9.9s %-6.6s\n" +#define FORMAT2 "%-47.47s %9.9s %6.6s\n" +#define FORMAT "%-47.47s %-9.9s %-6.6s\n" switch (cmd) { case CLI_INIT: @@ -14691,12 +14769,12 @@ static char *sip_show_tcp(struct ast_cli_entry *e, int cmd, struct ast_cli_args if (a->argc != 3) return CLI_SHOWUSAGE; - ast_cli(a->fd, FORMAT2, "Host", "Port", "Transport", "Type"); + ast_cli(a->fd, FORMAT2, "Address", "Transport", "Type"); i = ao2_iterator_init(threadt, 0); while ((th = ao2_t_iterator_next(&i, "iterate through tcp threads for 'sip show tcp'"))) { - ast_cli(a->fd, FORMAT, ast_inet_ntoa(th->tcptls_session->remote_address.sin_addr), - ntohs(th->tcptls_session->remote_address.sin_port), + ast_cli(a->fd, FORMAT, + ast_sockaddr_stringify(&th->tcptls_session->remote_address), get_transport(th->type), (th->tcptls_session->client ? "Client" : "Server")); ao2_t_ref(th, -1, "decrement ref from iterator"); @@ -14890,8 +14968,8 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str struct ao2_iterator i; /* the last argument is left-aligned, so we don't need a size anyways */ -#define FORMAT2 "%-25.25s %-15.15s %-3.3s %-10.10s %-3.3s %-8s %-10s %s\n" -#define FORMAT "%-25.25s %-15.15s %-3.3s %-3.3s %-3.3s %-8d %-10s %s\n" +#define FORMAT2 "%-25.25s %-39.39s %-3.3s %-10.10s %-3.3s %-8s %-10s %s\n" +#define FORMAT "%-25.25s %-39.39s %-3.3s %-3.3s %-3.3s %-8d %-10s %s\n" char name[256]; int total_peers = 0; @@ -14982,28 +15060,29 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str else if (pstatus == 0) peers_mon_offline++; else { - if (peer->addr.sin_port == 0) + if (ast_sockaddr_isnull(&peer->addr) || + !ast_sockaddr_port(&peer->addr)) { peers_unmon_offline++; - else + } else { peers_unmon_online++; + } } snprintf(srch, sizeof(srch), FORMAT, name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", + ast_sockaddr_isnull(&peer->addr) ? "(Unspecified)" : ast_sockaddr_stringify_addr(&peer->addr), peer->host_dynamic ? " D " : " ", /* Dynamic or not? */ ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */ peer->ha ? " A " : " ", /* permit/deny */ - ntohs(peer->addr.sin_port), status, + ast_sockaddr_isnull(&peer->addr) ? 0 : ast_sockaddr_port(&peer->addr), status, realtimepeers ? (peer->is_realtime ? "Cached RT":"") : ""); if (!s) {/* Normal CLI list */ ast_cli(fd, FORMAT, name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", + ast_sockaddr_isnull(&peer->addr) ? "(Unspecified)" : ast_sockaddr_stringify_addr(&peer->addr), peer->host_dynamic ? " D " : " ", /* Dynamic or not? */ ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */ peer->ha ? " A " : " ", /* permit/deny */ - - ntohs(peer->addr.sin_port), status, + ast_sockaddr_isnull(&peer->addr) ? 0 : ast_sockaddr_port(&peer->addr), status, realtimepeers ? (peer->is_realtime ? "Cached RT":"") : ""); } else { /* Manager format */ /* The names here need to be the same as other channels */ @@ -15023,8 +15102,8 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str "RealtimeDevice: %s\r\n\r\n", idtext, peer->name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "-none-", - ntohs(peer->addr.sin_port), + ast_sockaddr_isnull(&peer->addr) ? "-none-" : ast_sockaddr_stringify(&peer->addr), + ast_sockaddr_isnull(&peer->addr) ? 0 : ast_sockaddr_port(&peer->addr), peer->host_dynamic ? "yes" : "no", /* Dynamic or not? */ ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? "yes" : "no", /* NAT=yes? */ ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "yes" : "no", /* VIDEOSUPPORT=yes? */ @@ -15361,17 +15440,16 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli struct sip_peer tmp; ast_copy_string(tmp.name, name, sizeof(tmp.name)); if ((peer = ao2_t_find(peers, &tmp, OBJ_POINTER | OBJ_UNLINK, "finding to unlink from peers"))) { - if (peer->addr.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&peer->addr)) { ao2_t_unlink(peers_by_ip, peer, "unlinking peer from peers_by_ip also"); } if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) { ast_cli(a->fd, "Peer '%s' is not a Realtime peer, cannot be pruned.\n", name); /* put it back! */ ao2_t_link(peers, peer, "link peer into peer table"); - if (peer->addr.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&peer->addr)) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } - } else ast_cli(a->fd, "Peer '%s' pruned.\n", name); unref_peer(peer, "sip_prune_realtime: unref_peer: tossing temp peer ptr"); @@ -15675,8 +15753,8 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, " Timer T1 : %d\n", peer->timer_t1); ast_cli(fd, " Timer B : %d\n", peer->timer_b); ast_cli(fd, " ToHost : %s\n", peer->tohost); - ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port)); - ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port)); + ast_cli(fd, " Addr->IP : %s\n", ast_sockaddr_stringify(&peer->addr)); + ast_cli(fd, " Defaddr->IP : %s\n", ast_sockaddr_stringify(&peer->defaddr)); ast_cli(fd, " Prim.Transp. : %s\n", get_transport(peer->socket.type)); ast_cli(fd, " Allowed.Trsp : %s\n", get_transport_list(peer->transports)); if (!ast_strlen_zero(sip_cfg.regcontext)) @@ -15781,8 +15859,8 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct /* - is enumerated */ astman_append(s, "SIP-DTMFmode: %s\r\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF))); astman_append(s, "ToHost: %s\r\n", peer->tohost); - astman_append(s, "Address-IP: %s\r\nAddress-Port: %d\r\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "", ntohs(peer->addr.sin_port)); - astman_append(s, "Default-addr-IP: %s\r\nDefault-addr-port: %d\r\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port)); + astman_append(s, "Address-IP: %s\r\nAddress-Port: %d\r\n", ast_sockaddr_stringify_addr(&peer->addr), ast_sockaddr_port(&peer->addr)); + astman_append(s, "Default-addr-IP: %s\r\nDefault-addr-port: %d\r\n", ast_sockaddr_stringify_addr(&peer->defaddr), ast_sockaddr_port(&peer->defaddr)); astman_append(s, "Default-Username: %s\r\n", peer->username); if (!ast_strlen_zero(sip_cfg.regcontext)) astman_append(s, "RegExtension: %s\r\n", peer->regexten); @@ -15983,8 +16061,8 @@ static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_arg /*! \brief Show SIP Registry (registrations with other SIP proxies */ static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define FORMAT2 "%-30.30s %-6.6s %-12.12s %8.8s %-20.20s %-25.25s\n" -#define FORMAT "%-30.30s %-6.6s %-12.12s %8d %-20.20s %-25.25s\n" +#define FORMAT2 "%-39.39s %-6.6s %-12.12s %8.8s %-20.20s %-25.25s\n" +#define FORMAT "%-39.39s %-6.6s %-12.12s %8d %-20.20s %-25.25s\n" char host[80]; char user[80]; char tmpdat[256]; @@ -16090,8 +16168,12 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags) return 0; /* don't care, we scan all channels */ if (!cur->rtp) { - if (sipdebug) - ast_cli(fd, "%-15.15s %-11.11s (inv state: %s) -- %s\n", ast_inet_ntoa(cur->sa.sin_addr), cur->callid, invitestate2string[cur->invitestate].desc, "-- No RTP active"); + if (sipdebug) { + ast_cli(fd, "%-15.15s %-11.11s (inv state: %s) -- %s\n", + ast_sockaddr_stringify_addr(&cur->sa), cur->callid, + invitestate2string[cur->invitestate].desc, + "-- No RTP active"); + } return 0; /* don't care, we scan all channels */ } @@ -16108,7 +16190,7 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags) } ast_cli(fd, FORMAT, - ast_inet_ntoa(cur->sa.sin_addr), + ast_sockaddr_stringify_addr(&cur->sa), cur->callid, durbuf, stats.rxcount > (unsigned int) 100000 ? (unsigned int) (stats.rxcount)/(unsigned int) 1000 : stats.rxcount, @@ -16183,22 +16265,15 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ return CLI_SHOWUSAGE; ast_cli(a->fd, "\n\nGlobal Settings:\n"); ast_cli(a->fd, "----------------\n"); - ast_cli(a->fd, " UDP SIP Port: %d\n", ntohs(bindaddr.sin_port)); - ast_cli(a->fd, " UDP Bindaddress: %s\n", ast_inet_ntoa(bindaddr.sin_addr)); - ast_cli(a->fd, " TCP SIP Port: "); - if (sip_tcp_desc.local_address.sin_family == AF_INET) { - ast_cli(a->fd, "%d\n", ntohs(sip_tcp_desc.local_address.sin_port)); - ast_cli(a->fd, " TCP Bindaddress: %s\n", ast_inet_ntoa(sip_tcp_desc.local_address.sin_addr)); - } else { - ast_cli(a->fd, "Disabled\n"); - } - ast_cli(a->fd, " TLS SIP Port: "); - if (default_tls_cfg.enabled != FALSE) { - ast_cli(a->fd, "%d\n", ntohs(sip_tls_desc.local_address.sin_port)); - ast_cli(a->fd, " TLS Bindaddress: %s\n", ast_inet_ntoa(sip_tls_desc.local_address.sin_addr)); - } else { - ast_cli(a->fd, "Disabled\n"); - } + ast_cli(a->fd, " UDP Bindaddress: %s\n", ast_sockaddr_stringify(&bindaddr)); + ast_cli(a->fd, " TCP SIP Bindaddress: %s\n", + sip_cfg.tcp_enabled != FALSE ? + ast_sockaddr_stringify(&sip_tcp_desc.local_address) : + "Disabled"); + ast_cli(a->fd, " TLS SIP Bindaddress: %s\n", + default_tls_cfg.enabled != FALSE ? + ast_sockaddr_stringify(&sip_tls_desc.local_address) : + "Disabled"); ast_cli(a->fd, " Videosupport: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT))); ast_cli(a->fd, " Textsupport: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT))); ast_cli(a->fd, " Ignore SDP sess. ver.: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_IGNORESDPVERSION))); @@ -16263,8 +16338,8 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ /* determine if/how SIP address can be remapped */ if (localaddr == NULL) msg = "Disabled, no localnet list"; - else if (externip.sin_addr.s_addr == 0) - msg = "Disabled, externip is 0.0.0.0"; + else if (ast_sockaddr_isnull(&externip)) + msg = "Disabled"; else if (stunaddr.sin_addr.s_addr != 0) msg = "Enabled using STUN"; else if (!ast_strlen_zero(externhost)) @@ -16273,9 +16348,9 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ msg = "Enabled using externip"; ast_cli(a->fd, " SIP address remapping: %s\n", msg); ast_cli(a->fd, " Externhost: %s\n", S_OR(externhost, "<none>")); - ast_cli(a->fd, " Externip: %s:%d\n", ast_inet_ntoa(externip.sin_addr), ntohs(externip.sin_port)); + ast_cli(a->fd, " Externip: %s\n", ast_sockaddr_stringify(&externip)); ast_cli(a->fd, " Externrefresh: %d\n", externrefresh); - ast_cli(a->fd, " Internal IP: %s:%d\n", ast_inet_ntoa(internip.sin_addr), ntohs(internip.sin_port)); + ast_cli(a->fd, " Internal IP: %s\n", ast_sockaddr_stringify(&internip)); { struct ast_ha *d; const char *prefix = "Localnet:"; @@ -16437,7 +16512,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) { struct sip_pvt *cur = __cur; struct __show_chan_arg *arg = __arg; - const struct sockaddr_in *dst = sip_real_dst(cur); + const struct ast_sockaddr *dst = sip_real_dst(cur); /* XXX indentation preserved to reduce diff. Will be fixed later */ if (cur->subscribed == NONE && !arg->subscriptions) { @@ -16445,7 +16520,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) const char *referstatus = cur->refer ? referstatus2str(cur->refer->status) : ""; char formatbuf[SIPBUFSIZE/2]; - ast_cli(arg->fd, FORMAT, ast_inet_ntoa(dst->sin_addr), + ast_cli(arg->fd, FORMAT, ast_sockaddr_stringify_addr(dst), S_OR(cur->username, S_OR(cur->cid_num, "(None)")), cur->callid, ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0), @@ -16461,7 +16536,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) struct ast_str *mailbox_str = ast_str_alloca(512); if (cur->subscribed == MWI_NOTIFICATION && cur->relatedpeer) peer_mailboxes_to_str(&mailbox_str, cur->relatedpeer); - ast_cli(arg->fd, FORMAT4, ast_inet_ntoa(dst->sin_addr), + ast_cli(arg->fd, FORMAT4, ast_sockaddr_stringify_addr(dst), S_OR(cur->username, S_OR(cur->cid_num, "(None)")), cur->callid, /* the 'complete' exten/context is hidden in the refer_to field for subscriptions */ @@ -16704,11 +16779,19 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_cli(a->fd, " T.38 support %s\n", AST_CLI_YESNO(cur->udptl != NULL)); ast_cli(a->fd, " Video support %s\n", AST_CLI_YESNO(cur->vrtp != NULL)); ast_cli(a->fd, " MaxCallBR: %d kbps\n", cur->maxcallbitrate); - ast_cli(a->fd, " Theoretical Address: %s:%d\n", ast_inet_ntoa(cur->sa.sin_addr), ntohs(cur->sa.sin_port)); - ast_cli(a->fd, " Received Address: %s:%d\n", ast_inet_ntoa(cur->recv.sin_addr), ntohs(cur->recv.sin_port)); + ast_cli(a->fd, " Theoretical Address: %s\n", ast_sockaddr_stringify(&cur->sa)); + ast_cli(a->fd, " Received Address: %s\n", ast_sockaddr_stringify(&cur->recv)); ast_cli(a->fd, " SIP Transfer mode: %s\n", transfermode2str(cur->allowtransfer)); ast_cli(a->fd, " Force rport: %s\n", AST_CLI_YESNO(ast_test_flag(&cur->flags[0], SIP_NAT_FORCE_RPORT))); - ast_cli(a->fd, " Audio IP: %s %s\n", ast_inet_ntoa(cur->redirip.sin_addr.s_addr ? cur->redirip.sin_addr : cur->ourip.sin_addr), cur->redirip.sin_addr.s_addr ? "(Outside bridge)" : "(local)" ); + if (ast_sockaddr_isnull(&cur->redirip)) { + ast_cli(a->fd, + " Audio IP: %s (local)\n", + ast_sockaddr_stringify_addr(&cur->ourip)); + } else { + ast_cli(a->fd, + " Audio IP: %s (Outside bridge)\n", + ast_sockaddr_stringify_addr(&cur->redirip)); + } ast_cli(a->fd, " Our Tag: %s\n", cur->tag); ast_cli(a->fd, " Their Tag: %s\n", cur->theirtag); ast_cli(a->fd, " SIP User agent: %s\n", cur->useragent); @@ -17045,27 +17128,11 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req) /*! \brief Enable SIP Debugging for a single IP */ static char *sip_do_debug_ip(int fd, const char *arg) { - struct hostent *hp; - struct ast_hostent ahp; - int port = 0; - char *p; - - p = ast_strdupa(arg); - strsep(&p, ":"); - if (p) - port = atoi(p); - hp = ast_gethostbyname(arg, &ahp); - if (hp == NULL) + if (ast_sockaddr_resolve_first(&debugaddr, arg, 0)) { return CLI_SHOWUSAGE; + } - debugaddr.sin_family = AF_INET; - memcpy(&debugaddr.sin_addr, hp->h_addr, sizeof(debugaddr.sin_addr)); - debugaddr.sin_port = htons(port); - if (port == 0) - ast_cli(fd, "SIP Debugging Enabled for IP: %s\n", ast_inet_ntoa(debugaddr.sin_addr)); - else - ast_cli(fd, "SIP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(debugaddr.sin_addr), port); - + ast_cli(fd, "SIP Debugging Enabled for IP: %s\n", ast_sockaddr_stringify_addr(&debugaddr)); sipdebug |= sip_debug_console; return CLI_SUCCESS; @@ -17077,14 +17144,11 @@ static char *sip_do_debug_peer(int fd, const char *arg) struct sip_peer *peer = find_peer(arg, NULL, TRUE, FINDPEERS, FALSE, 0); if (!peer) ast_cli(fd, "No such peer '%s'\n", arg); - else if (peer->addr.sin_addr.s_addr == 0) + else if (ast_sockaddr_isnull(&peer->addr)) ast_cli(fd, "Unable to get IP address of peer '%s'\n", arg); else { - debugaddr.sin_family = AF_INET; - debugaddr.sin_addr = peer->addr.sin_addr; - debugaddr.sin_port = peer->addr.sin_port; - ast_cli(fd, "SIP Debugging Enabled for IP: %s:%d\n", - ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port)); + ast_sockaddr_copy(&debugaddr, &peer->addr); + ast_cli(fd, "SIP Debugging Enabled for IP: %s\n", ast_sockaddr_stringify_addr(&debugaddr)); sipdebug |= sip_debug_console; } if (peer) @@ -17394,7 +17458,7 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d else if (!ast_strlen_zero(p->uri)) ast_copy_string(uri, p->uri, sizeof(uri)); else - snprintf(uri, sizeof(uri), "sip:%s@%s", p->username, ast_inet_ntoa(p->sa.sin_addr)); + snprintf(uri, sizeof(uri), "sip:%s@%s", p->username, ast_sockaddr_stringify_host(&p->sa)); snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random()); @@ -17548,9 +17612,9 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat return -1; if (!strcasecmp(colname, "ip")) { - ast_copy_string(buf, peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "", len); + ast_copy_string(buf, ast_sockaddr_stringify_addr(&peer->addr), len); } else if (!strcasecmp(colname, "port")) { - snprintf(buf, len, "%d", ntohs(peer->addr.sin_port)); + snprintf(buf, len, "%d", ast_sockaddr_port(&peer->addr)); } else if (!strcasecmp(colname, "status")) { peer_status(peer, buf, len); } else if (!strcasecmp(colname, "language")) { @@ -17659,9 +17723,9 @@ static int function_sipchaninfo_read(struct ast_channel *chan, const char *cmd, } if (!strcasecmp(data, "peerip")) { - ast_copy_string(buf, p->sa.sin_addr.s_addr ? ast_inet_ntoa(p->sa.sin_addr) : "", len); + ast_copy_string(buf, ast_sockaddr_stringify_addr(&p->sa), len); } else if (!strcasecmp(data, "recvip")) { - ast_copy_string(buf, p->recv.sin_addr.s_addr ? ast_inet_ntoa(p->recv.sin_addr) : "", len); + ast_copy_string(buf, ast_sockaddr_stringify_addr(&p->recv), len); } else if (!strcasecmp(data, "from")) { ast_copy_string(buf, p->from, len); } else if (!strcasecmp(data, "uri")) { @@ -18458,7 +18522,7 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest } ast_string_field_set(p, theirtag, NULL); if (ast_strlen_zero(p->authname)) { - ast_log(LOG_WARNING, "Asked to authenticate NOTIFY to %s:%d but we have no matching peer or realm auth!\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + ast_log(LOG_WARNING, "Asked to authenticate NOTIFY to %s but we have no matching peer or realm auth!\n", ast_sockaddr_stringify(&p->recv)); pvt_set_needdestroy(p, "unable to authenticate NOTIFY"); } if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_NOTIFY, 0)) { @@ -18553,8 +18617,8 @@ static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, case 401: /* Not www-authorized on SIP method */ case 407: /* Proxy auth */ if (ast_strlen_zero(p->authname)) { - ast_log(LOG_WARNING, "Asked to authenticate REFER to %s:%d but we have no matching peer or realm auth!\n", - ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + ast_log(LOG_WARNING, "Asked to authenticate REFER to %s but we have no matching peer or realm auth!\n", + ast_sockaddr_stringify(&p->recv)); if (p->owner) { ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); } @@ -18985,8 +19049,8 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc if (p->options) p->options->auth_type = resp; if (ast_strlen_zero(p->authname)) { - ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n", - msg, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + ast_log(LOG_WARNING, "Asked to authenticate %s, to %s but we have no matching peer!\n", + msg, ast_sockaddr_stringify(&p->recv)); pvt_set_needdestroy(p, "unable to authenticate BYE"); } else if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp, sipmethod, 0)) { ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From")); @@ -19093,7 +19157,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc else if (sipmethod == SIP_REFER) handle_response_refer(p, resp, rest, req, seqno); else - ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_inet_ntoa(p->sa.sin_addr), msg); + ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_sockaddr_stringify(&p->sa), msg); break; case 603: /* Declined transfer */ if (sipmethod == SIP_REFER) { @@ -19105,7 +19169,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc if ((resp >= 300) && (resp < 700)) { /* Fatal response */ if ((resp != 487)) - ast_verb(3, "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr)); + ast_verb(3, "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_sockaddr_stringify(&p->sa)); if (sipmethod == SIP_INVITE) stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */ @@ -19177,7 +19241,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc } } } else - ast_log(LOG_NOTICE, "Don't know how to handle a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_inet_ntoa(p->sa.sin_addr)); + ast_log(LOG_NOTICE, "Don't know how to handle a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_sockaddr_stringify(&p->sa)); } } else { /* Responses to OUTGOING SIP requests on INCOMING calls @@ -19286,7 +19350,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc } if ((resp >= 300) && (resp < 700)) { if ((resp != 487)) - ast_verb(3, "Incoming call: Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr)); + ast_verb(3, "Incoming call: Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_sockaddr_stringify(&p->sa)); switch(resp) { case 415: /* Unsupported media type */ case 488: /* Not acceptable here - codec error */ @@ -19637,7 +19701,7 @@ static int handle_cc_notify(struct sip_pvt *pvt, struct sip_request *req) } /*! \brief Handle incoming notifications */ -static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e) +static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e) { /* This is mostly a skeleton for future improvements */ /* Mostly created to return proper answers on notifications on outbound REFER's */ @@ -19867,7 +19931,7 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req) handle_request_do(), we unlock p->owner before the masq. By setting nounlock we are indicating to handle_request_do() that we have already unlocked the owner. */ -static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *nounlock) +static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *nounlock) { int earlyreplace = 0; int oneleggedreplace = 0; /* Call with no bridge, propably IVR or voice message */ @@ -20356,7 +20420,7 @@ static int handle_request_update(struct sip_pvt *p, struct sip_request *req) * plan but try to find the active call and masquerade * into it */ -static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, const char *e, int *nounlock) +static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *recount, const char *e, int *nounlock) { int res = 1; int gotdest; @@ -20382,7 +20446,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int char exten[AST_MAX_EXTENSION]; char context[AST_MAX_CONTEXT]; } pickup = { - .exten = "", + .exten = "", }; st_ref = SESSION_TIMER_REFRESHER_AUTO; @@ -20485,17 +20549,17 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* We already have a pending invite. Sorry. You are on hold. */ p->glareinvite = seqno; if (p->rtp && find_sdp(req)) { - struct sockaddr_in sin; - if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &sin)) { + struct ast_sockaddr addr; + if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &addr)) { ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n"); } else { - ast_rtp_instance_set_alt_remote_address(p->rtp, &sin); + ast_rtp_instance_set_alt_remote_address(p->rtp, &addr); } if (p->vrtp) { - if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &sin)) { + if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &addr)) { ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n"); } else { - ast_rtp_instance_set_alt_remote_address(p->vrtp, &sin); + ast_rtp_instance_set_alt_remote_address(p->vrtp, &addr); } } } @@ -20700,7 +20764,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* Handle authentication if this is our first invite */ int cc_recall_core_id = -1; set_pvt_allowed_methods(p, req); - res = check_user_full(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin, &authpeer); + res = check_user_full(p, req, SIP_INVITE, e, XMIT_RELIABLE, addr, &authpeer); if (res == AUTH_CHALLENGE_SENT) { p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */ res = 0; @@ -20728,7 +20792,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int p->relatedpeer = ref_peer(authpeer, "setting dialog's relatedpeer pointer"); /* If T38 is needed but not present, then make it magically appear */ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && !p->udptl) { - if ((p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) { + struct sockaddr_in bindaddr_sin_tmp; + + ast_sockaddr_to_sin(&bindaddr, &bindaddr_sin_tmp); + if ((p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr_sin_tmp.sin_addr))) { p->t38_maxdatagram = global_t38_maxdatagram; set_t38_capabilities(p); } else { @@ -21030,7 +21097,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* Go and take over the target call */ if (sipdebug) ast_debug(4, "Sending this call to the invite/replcaes handler %s\n", p->callid); - res = handle_invite_replaces(p, req, debug, seqno, sin, nounlock); + res = handle_invite_replaces(p, req, debug, seqno, addr, nounlock); refer_locked = 0; goto request_invite_cleanup; } @@ -21892,7 +21959,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) if (!ast_strlen_zero(get_header(req, "Also"))) { ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method. Ask vendor to support REFER instead\n", - ast_inet_ntoa(p->recv.sin_addr)); + ast_sockaddr_stringify(&p->recv)); if (ast_strlen_zero(p->context)) ast_string_field_set(p, context, sip_cfg.default_context); res = get_also_info(p, req); @@ -21910,7 +21977,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) ast_queue_hangup(p->owner); } } else { - ast_log(LOG_WARNING, "Invalid transfer information from '%s'\n", ast_inet_ntoa(p->recv.sin_addr)); + ast_log(LOG_WARNING, "Invalid transfer information from '%s'\n", ast_sockaddr_stringify(&p->recv)); if (p->owner) ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR); } @@ -22361,7 +22428,7 @@ static int handle_sip_publish_remove(struct sip_pvt *p, struct sip_request *req, return res; } -static int handle_request_publish(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const int seqno, const char *uri) +static int handle_request_publish(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const int seqno, const char *uri) { const char *etag = get_header(req, "SIP-If-Match"); const char *event = get_header(req, "Event"); @@ -22382,7 +22449,7 @@ static int handle_request_publish(struct sip_pvt *p, struct sip_request *req, st return -1; } - auth_result = check_user(p, req, SIP_PUBLISH, uri, XMIT_RELIABLE, sin); + auth_result = check_user(p, req, SIP_PUBLISH, uri, XMIT_RELIABLE, addr); if (auth_result == AUTH_CHALLENGE_SENT) { p->lastinvite = seqno; return 0; @@ -22501,7 +22568,7 @@ static int handle_cc_subscribe(struct sip_pvt *p, struct sip_request *req) } /*! \brief Handle incoming SUBSCRIBE request */ -static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e) +static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e) { int gotdest = 0; int res = 0; @@ -22582,7 +22649,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, event = (char *) eventheader; /* XXX is this legal ? */ /* Handle authentication */ - res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, sin, &authpeer); + res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, addr, &authpeer); /* if an authentication response was sent, we are done here */ if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */ return 0; @@ -22782,7 +22849,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) { - ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_inet_ntoa(p->sa.sin_addr)); + ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_sockaddr_stringify(&p->sa)); transmit_response(p, "404 Not found", req); pvt_set_needdestroy(p, "no extension for SUBSCRIBE"); return 0; @@ -22836,7 +22903,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, } /*! \brief Handle incoming REGISTER request */ -static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const char *e) +static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e) { enum check_auth_result res; @@ -22845,7 +22912,7 @@ static int handle_request_register(struct sip_pvt *p, struct sip_request *req, s if (sipdebug) ast_debug(4, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid); check_via(p, req); - if ((res = register_verify(p, sin, req, e)) < 0) { + if ((res = register_verify(p, addr, req, e)) < 0) { const char *reason; switch (res) { @@ -22875,7 +22942,7 @@ static int handle_request_register(struct sip_pvt *p, struct sip_request *req, s break; } ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s' - %s\n", - get_header(req, "To"), ast_inet_ntoa(sin->sin_addr), + get_header(req, "To"), ast_sockaddr_stringify(addr), reason); append_history(p, "RegRequest", "Failed : Account %s : %s", get_header(req, "To"), reason); } else @@ -22892,7 +22959,7 @@ static int handle_request_register(struct sip_pvt *p, struct sip_request *req, s /*! \brief Handle incoming SIP requests (methods) \note This is where all incoming requests go first */ /* called with p and p->owner locked */ -static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock) +static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock) { /* Called with p->lock held, as well as p->owner->lock if appropriate, keeping things relatively static */ @@ -23069,7 +23136,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so res = handle_request_options(p, req); break; case SIP_INVITE: - res = handle_request_invite(p, req, debug, seqno, sin, recount, e, nounlock); + res = handle_request_invite(p, req, debug, seqno, addr, recount, e, nounlock); break; case SIP_REFER: res = handle_request_refer(p, req, debug, seqno, nounlock); @@ -23084,13 +23151,13 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so res = handle_request_message(p, req); break; case SIP_PUBLISH: - res = handle_request_publish(p, req, sin, seqno, e); + res = handle_request_publish(p, req, addr, seqno, e); break; case SIP_SUBSCRIBE: - res = handle_request_subscribe(p, req, sin, seqno, e); + res = handle_request_subscribe(p, req, addr, seqno, e); break; case SIP_REGISTER: - res = handle_request_register(p, req, sin, e); + res = handle_request_register(p, req, addr, e); break; case SIP_INFO: if (req->debug) @@ -23101,7 +23168,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so transmit_response(p, "200 OK", req); break; case SIP_NOTIFY: - res = handle_request_notify(p, req, sin, seqno, e); + res = handle_request_notify(p, req, addr, seqno, e); break; case SIP_UPDATE: res = handle_request_update(p, req); @@ -23134,7 +23201,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so default: transmit_response_with_allow(p, "501 Method Not Implemented", req, 0); ast_log(LOG_NOTICE, "Unknown SIP command '%s' from '%s'\n", - cmd, ast_inet_ntoa(p->sa.sin_addr)); + cmd, ast_sockaddr_stringify(&p->sa)); /* If this is some new method, and we don't have a call, destroy it now */ if (!p->initreq.headers) { pvt_set_needdestroy(p, "unimplemented method"); @@ -23241,13 +23308,12 @@ static int queue_request(struct sip_pvt *p, const struct sip_request *req) static int sipsock_read(int *id, int fd, short events, void *ignore) { struct sip_request req; - struct sockaddr_in sin = { 0, }; + struct ast_sockaddr addr; int res; - socklen_t len = sizeof(sin); static char readbuf[65535]; memset(&req, 0, sizeof(req)); - res = recvfrom(fd, readbuf, sizeof(readbuf) - 1, 0, (struct sockaddr *)&sin, &len); + res = ast_recvfrom(fd, readbuf, sizeof(readbuf) - 1, 0, &addr); if (res < 0) { #if !defined(__FreeBSD__) if (errno == EAGAIN) @@ -23273,9 +23339,9 @@ static int sipsock_read(int *id, int fd, short events, void *ignore) req.socket.fd = sipsock; set_socket_transport(&req.socket, SIP_TRANSPORT_UDP); req.socket.tcptls_session = NULL; - req.socket.port = bindaddr.sin_port; + req.socket.port = htons(ast_sockaddr_port(&bindaddr)); - handle_request_do(&req, &sin); + handle_request_do(&req, &addr); deinit_req(&req); return 1; @@ -23285,21 +23351,20 @@ static int sipsock_read(int *id, int fd, short events, void *ignore) This is used for all transports (udp, tcp and tcp/tls) */ -static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin) +static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr) { struct sip_pvt *p; int recount = 0; int nounlock = 0; int lockretry; - if (sip_debug_test_addr(sin)) /* Set the debug flag early on packet level */ + if (sip_debug_test_addr(addr)) /* Set the debug flag early on packet level */ req->debug = 1; if (sip_cfg.pedanticsipchecking) req->len = lws2sws(req->data->str, req->len); /* Fix multiline headers */ if (req->debug) { - ast_verbose("\n<--- SIP read from %s:%s:%d --->\n%s\n<------------->\n", - get_transport(req->socket.type), ast_inet_ntoa(sin->sin_addr), - ntohs(sin->sin_port), req->data->str); + ast_verbose("\n<--- SIP read from %s:%s --->\n%s\n<------------->\n", + get_transport(req->socket.type), ast_sockaddr_stringify(addr), req->data->str); } if (parse_request(req) == -1) { /* Bad packet, can't parse */ @@ -23321,7 +23386,7 @@ static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin) ast_mutex_lock(&netlock); /* Find the active SIP dialog or create a new one */ - p = find_call(req, sin, req->method); /* returns p locked */ + p = find_call(req, addr, req->method); /* returns p locked */ if (p == NULL) { ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req->len); ast_mutex_unlock(&netlock); @@ -23343,7 +23408,7 @@ static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin) usleep(1); } } - p->recv = *sin; + ast_sockaddr_copy(&p->recv, addr); if (p->do_history) /* This is a request or response, note what it was for */ append_history(p, "Rx", "%s / %s / %s", req->data->str, get_header(req, "CSeq"), REQ_OFFSET_TO_STR(req, rlPart2)); @@ -23378,7 +23443,7 @@ static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin) process_request_queue(p, &recount, &nounlock); } - if (handle_incoming(p, req, sin, &recount, &nounlock) == -1) { + if (handle_incoming(p, req, addr, &recount, &nounlock) == -1) { /* Request failed */ ast_debug(1, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>"); } @@ -23411,9 +23476,9 @@ static int sip_standard_port(enum sip_transport type, int port) static int threadinfo_locate_cb(void *obj, void *arg, int flags) { struct sip_threadinfo *th = obj; - struct sockaddr_in *s = arg; + struct ast_sockaddr *s = arg; - if (!inaddrcmp(&th->tcptls_session->remote_address, s)) { + if (!ast_sockaddr_cmp(s, &th->tcptls_session->remote_address)) { return CMP_MATCH | CMP_STOP; } @@ -23425,7 +23490,7 @@ static int threadinfo_locate_cb(void *obj, void *arg, int flags) * * \note This function returns an astobj2 reference */ -static struct ast_tcptls_session_instance *sip_tcp_locate(struct sockaddr_in *s) +static struct ast_tcptls_session_instance *sip_tcp_locate(struct ast_sockaddr *s) { struct sip_threadinfo *th; struct ast_tcptls_session_instance *tcptls_instance = NULL; @@ -23438,6 +23503,20 @@ static struct ast_tcptls_session_instance *sip_tcp_locate(struct sockaddr_in *s) return tcptls_instance; } +/*! + * \brief Helper for dns resolution to filter by address family. + * + * \note return 0 if addr is [::] else it returns addr's family. + */ +int get_address_family_filter(const struct ast_sockaddr *addr) +{ + if (ast_sockaddr_is_ipv6(addr) && ast_sockaddr_is_any(addr)) { + return 0; + } + + return addr->ss.ss_family; +} + /*! \todo Get socket for dialog, prepare if needed, and return file handle */ static int sip_prepare_socket(struct sip_pvt *p) { @@ -23445,11 +23524,8 @@ static int sip_prepare_socket(struct sip_pvt *p) static const char name[] = "SIP socket"; struct sip_threadinfo *th = NULL; struct ast_tcptls_session_instance *tcptls_session; - struct ast_tcptls_session_args tmp_ca = { - .name = name, - .accept_fd = -1, - }; struct ast_tcptls_session_args *ca; + struct ast_sockaddr sa_tmp; /* check to see if a socket is already active */ if ((s->fd != -1) && (s->type == SIP_TRANSPORT_UDP)) { @@ -23483,8 +23559,8 @@ static int sip_prepare_socket(struct sip_pvt *p) */ /* 1. check for existing threads */ - tmp_ca.remote_address = *(sip_real_dst(p)); - if ((tcptls_session = sip_tcp_locate(&tmp_ca.remote_address))) { + ast_sockaddr_copy(&sa_tmp, sip_real_dst(p)); + if ((tcptls_session = sip_tcp_locate(&sa_tmp))) { s->fd = tcptls_session->fd; if (s->tcptls_session) { ao2_ref(s->tcptls_session, -1); @@ -23504,7 +23580,7 @@ static int sip_prepare_socket(struct sip_pvt *p) goto create_tcptls_session_fail; } ca->accept_fd = -1; - ca->remote_address = *(sip_real_dst(p)); + ast_sockaddr_copy(&ca->remote_address,sip_real_dst(p)); /* if type is TLS, we need to create a tls cfg for this session arg */ if (s->type == SIP_TRANSPORT_TLS) { if (!(ca->tls_cfg = ast_calloc(1, sizeof(*ca->tls_cfg)))) { @@ -23606,7 +23682,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e return 0; /* Do we have an IP address? If not, skip this peer */ - if (!peer->addr.sin_addr.s_addr && !peer->defaddr.sin_addr.s_addr) + if (ast_sockaddr_isnull(&peer->addr) || ast_sockaddr_isnull(&peer->defaddr)) return 0; if (event) { @@ -23642,7 +23718,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e return 0; } /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -23672,7 +23748,7 @@ static void check_rtp_timeout(struct sip_pvt *dialog, time_t t) return; /* If the call is not in UP state or redirected outside Asterisk, no need to check timers */ - if (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr) + if (dialog->owner->_state != AST_STATE_UP || !ast_sockaddr_isnull(&dialog->redirip)) return; /* If the call is involved in a T38 fax session do not check RTP timeout */ @@ -24179,7 +24255,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force) struct sip_pvt *p; int xmitres = 0; - if ((!peer->maxms && !force) || !peer->addr.sin_addr.s_addr) { + if ((!peer->maxms && !force) || ast_sockaddr_isnull(&peer->addr)) { /* IF we have no IP, or this isn't to be monitored, return immediately after clearing things out */ AST_SCHED_DEL_UNREF(sched, peer->pokeexpire, @@ -24218,10 +24294,10 @@ static int sip_poke_peer(struct sip_peer *peer, int force) if (!ast_strlen_zero(peer->tohost)) ast_string_field_set(p, tohost, peer->tohost); else - ast_string_field_set(p, tohost, ast_inet_ntoa(peer->addr.sin_addr)); + ast_string_field_set(p, tohost, ast_sockaddr_stringify_host(&peer->addr)); /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -24309,7 +24385,7 @@ static int sip_devicestate(void *data) * hosts out of memory. */ if ((p = find_peer(host, NULL, FALSE, FINDALLDEVICES, TRUE, 0))) { - if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) { + if (!(ast_sockaddr_isnull(&p->addr) && ast_sockaddr_isnull(&p->defaddr))) { /* we have an address for the peer */ /* Check status in this order @@ -24380,7 +24456,7 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c char dialstring[256]; char *remote_address; enum sip_transport transport = 0; - struct sockaddr_in remote_address_sin = { .sin_family = AF_INET }; + struct ast_sockaddr remote_address_sa = { {0,} }; format_t oldformat = format; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(peerorhost); @@ -24482,25 +24558,15 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c } if (!ast_strlen_zero(remote_address)) { - struct hostent *hp; - struct ast_hostent ahp; - char *port; - unsigned short port_num = transport & SIP_TRANSPORT_TLS ? STANDARD_TLS_PORT : STANDARD_SIP_PORT; - - port = strchr(remote_address, ':'); - if (port) { - *port++ = '\0'; - if (sscanf(port, "%hu", &port_num) != 1) { - ast_log(LOG_WARNING, "Invalid port number provided in remote address. Using %hu\n", port_num); - } - } - - hp = ast_gethostbyname(remote_address, &ahp); - if (!hp) { + if (ast_sockaddr_resolve_first(&remote_address_sa, remote_address, 0)) { ast_log(LOG_WARNING, "Unable to find IP address for host %s. We will not use this remote IP address\n", remote_address); } else { - memcpy(&remote_address_sin.sin_addr, hp->h_addr, sizeof(remote_address_sin.sin_addr)); - remote_address_sin.sin_port = htons(port_num); + if (!ast_sockaddr_port(&remote_address_sa)) { + ast_sockaddr_set_port(&remote_address_sa, + transport & SIP_TRANSPORT_TLS ? + STANDARD_TLS_PORT : + STANDARD_SIP_PORT); + } } } @@ -24511,7 +24577,7 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c ext = extension (user part of URI) dnid = destination of the call (applies to the To: header) */ - if (create_addr(p, host, NULL, 1, &remote_address_sin)) { + if (create_addr(p, host, NULL, 1, &remote_address_sa)) { *cause = AST_CAUSE_UNREGISTERED; ast_debug(3, "Cant create SIP call - target device not registered\n"); dialog_unlink_all(p, TRUE, TRUE); @@ -24522,7 +24588,7 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c if (ast_strlen_zero(p->peername) && ext) ast_string_field_set(p, peername, ext); /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -24961,7 +25027,6 @@ static void set_peer_defaults(struct sip_peer *peer) */ peer->expire = -1; peer->pokeexpire = -1; - peer->addr.sin_port = htons(STANDARD_SIP_PORT); set_socket_transport(&peer->socket, SIP_TRANSPORT_UDP); } peer->type = SIP_TYPE_PEER; @@ -24974,8 +25039,8 @@ static void set_peer_defaults(struct sip_peer *peer) ast_string_field_set(peer, mohinterpret, default_mohinterpret); ast_string_field_set(peer, mohsuggest, default_mohsuggest); ast_string_field_set(peer, engine, default_engine); - peer->addr.sin_family = AF_INET; - peer->defaddr.sin_family = AF_INET; + ast_sockaddr_setnull(&peer->addr); + ast_sockaddr_setnull(&peer->defaddr); peer->capability = sip_cfg.capability; peer->maxcallbitrate = default_maxcallbitrate; peer->rtptimeout = global_rtptimeout; @@ -25262,41 +25327,58 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "fromuser")) { ast_string_field_set(peer, fromuser, v->value); } else if (!strcasecmp(v->name, "outboundproxy")) { - char *port, *next, *force, *proxyname; - int forceopt = FALSE; - /* Set peer channel variable */ - next = proxyname = ast_strdupa(v->value); - if ((port = strchr(proxyname, ':'))) { - *port++ = '\0'; - next = port; + char *tok, *proxyname; + + if (ast_strlen_zero(v->value)) { + ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf.", v->lineno); + continue; } - if ((force = strchr(next, ','))) { - *force++ = '\0'; - forceopt = strcmp(force, "force"); + + peer->outboundproxy = + ao2_alloc(sizeof(*peer->outboundproxy), NULL); + + tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); + + sip_parse_host(tok, v->lineno, &proxyname, + &peer->outboundproxy->port, + &peer->outboundproxy->transport); + + tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); + + if ((tok = strtok(NULL, ","))) { + peer->outboundproxy->force = !strncasecmp(ast_skip_blanks(tok), "force", 5); + } else { + peer->outboundproxy->force = FALSE; + } + + if (ast_strlen_zero(proxyname)) { + ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf.", v->lineno); + sip_cfg.outboundproxy.name[0] = '\0'; + continue; } - /* Allocate proxy object */ - peer->outboundproxy = proxy_allocate(proxyname, port, forceopt); + + ast_copy_string(peer->outboundproxy->name, proxyname, sizeof(peer->outboundproxy->name)); + + proxy_update(peer->outboundproxy); } else if (!strcasecmp(v->name, "host")) { if (!strcasecmp(v->value, "dynamic")) { /* They'll register with us */ if (!found || !peer->host_dynamic) { /* Initialize stuff if this is a new peer, or if it used to * not be dynamic before the reload. */ - memset(&peer->addr.sin_addr, 0, 4); - peer->addr.sin_port = 0; + ast_sockaddr_setnull(&peer->addr); } peer->host_dynamic = TRUE; } else { /* Non-dynamic. Make sure we become that way if we're not */ AST_SCHED_DEL_UNREF(sched, peer->expire, unref_peer(peer, "removing register expire ref")); - /* the port will either be set to a default value or a config specified value once all option parsing is complete */ - peer->addr.sin_port = 0; peer->host_dynamic = FALSE; srvlookup = v->value; if (global_dynamic_exclude_static) { int err = 0; - sip_cfg.contact_ha = ast_append_ha("deny", (char *)ast_inet_ntoa(peer->addr.sin_addr), sip_cfg.contact_ha, &err); + sip_cfg.contact_ha = ast_append_ha("deny", ast_sockaddr_stringify(&peer->addr), + sip_cfg.contact_ha, &err); if (err) { ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value); } @@ -25504,7 +25586,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (realtime && !strcasecmp(v->name, "lastms")) { sscanf(v->value, "%30d", &peer->lastms); } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) { - inet_aton(v->value, &(peer->addr.sin_addr)); + ast_sockaddr_parse(&peer->addr, v->value, PARSE_PORT_FORBID); } else if (realtime && !strcasecmp(v->name, "fullcontact")) { if (alt_fullcontact && !alt) { /* Reset, because the alternate also has a fullcontact and we @@ -25605,12 +25687,6 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str set_socket_transport(&peer->socket, peer->default_outbound_transport); } - if (port && !realtime && peer->host_dynamic) { - peer->defaddr.sin_port = htons(port); - } else if (port) { - peer->addr.sin_port = htons(port); - } - if (ast_str_strlen(fullcontact)) { ast_string_field_set(peer, fullcontact, ast_str_buffer(fullcontact)); peer->rt_fromcontact = TRUE; @@ -25622,7 +25698,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str * specified, use that address instead. */ /* XXX May need to revisit the final argument; does the realtime DB store whether * the original contact was over TLS or not? XXX */ - if (!ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT) || !peer->addr.sin_addr.s_addr) { + if (!ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT) || ast_sockaddr_isnull(&peer->addr)) { __set_address_from_contact(fullcontact->str, &peer->addr, 0); } } @@ -25639,20 +25715,32 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str snprintf(transport, sizeof(transport), "_sip._%s", get_transport(peer->socket.type)); + peer->addr.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */ if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup && !peer->portinuri ? transport : NULL)) { ast_log(LOG_ERROR, "srvlookup failed for host: %s, on peer %s, removing peer\n", _srvlookup, peer->name); unref_peer(peer, "getting rid of a peer pointer"); return NULL; } - ast_string_field_set(peer, tohost, srvlookup); + ast_string_field_set(peer, tohost, peer->dnsmgr ? srvlookup : + ast_sockaddr_stringify_host(&peer->addr)); + } + + if (port && !realtime && peer->host_dynamic) { + ast_sockaddr_set_port(&peer->defaddr, port); + } else if (port) { + ast_sockaddr_set_port(&peer->addr, port); } - if (!peer->addr.sin_port) { - peer->addr.sin_port = htons(((peer->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT)); + if (ast_sockaddr_port(&peer->addr) == 0) { + ast_sockaddr_set_port(&peer->addr, + (peer->socket.type & SIP_TRANSPORT_TLS) ? + STANDARD_TLS_PORT : STANDARD_SIP_PORT); } - if (!peer->defaddr.sin_port) { - peer->defaddr.sin_port = htons(((peer->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT)); + if (ast_sockaddr_port(&peer->defaddr) == 0) { + ast_sockaddr_set_port(&peer->defaddr, + (peer->socket.type & SIP_TRANSPORT_TLS) ? + STANDARD_TLS_PORT : STANDARD_SIP_PORT); } if (!peer->socket.port) { peer->socket.port = htons(((peer->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT)); @@ -25735,12 +25823,14 @@ static int reload_config(enum channelreloadreason reason) struct ast_flags dummy[2]; struct ast_flags config_flags = { reason == CHANNEL_MODULE_LOAD ? 0 : ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) ? 0 : CONFIG_FLAG_FILEUNCHANGED }; int auto_sip_domains = FALSE; - struct sockaddr_in old_bindaddr = bindaddr; + struct ast_sockaddr old_bindaddr = bindaddr; int registry_count = 0, peer_count = 0, timerb_set = 0, timert1_set = 0; time_t run_start, run_end; - + struct sockaddr_in externip_sin; + int bindport = 0; + run_start = time(0); - ast_unload_realtime("sipregs"); + ast_unload_realtime("sipregs"); ast_unload_realtime("sippeers"); cfg = ast_config_load(config, config_flags); @@ -25775,18 +25865,11 @@ static int reload_config(enum channelreloadreason reason) } } - /* Initialize tcp sockets */ - memset(&sip_tcp_desc.local_address, 0, sizeof(sip_tcp_desc.local_address)); - memset(&sip_tls_desc.local_address, 0, sizeof(sip_tls_desc.local_address)); - ast_free_ha(sip_cfg.contact_ha); sip_cfg.contact_ha = NULL; default_tls_cfg.enabled = FALSE; /* Default: Disable TLS */ - sip_tcp_desc.local_address.sin_port = htons(STANDARD_SIP_PORT); - sip_tls_desc.local_address.sin_port = htons(STANDARD_TLS_PORT); - if (reason != CHANNEL_MODULE_LOAD) { ast_debug(4, "--------------- SIP reload started\n"); @@ -25845,7 +25928,7 @@ static int reload_config(enum channelreloadreason reason) ast_clear_flag(&global_flags[1], AST_FLAGS_ALL); /* Reset IP addresses */ - memset(&bindaddr, 0, sizeof(bindaddr)); + ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0); memset(&stunaddr, 0, sizeof(stunaddr)); memset(&internip, 0, sizeof(internip)); @@ -25856,16 +25939,13 @@ static int reload_config(enum channelreloadreason reason) memset(&media_address, 0, sizeof(media_address)); memset(&default_prefs, 0 , sizeof(default_prefs)); memset(&sip_cfg.outboundproxy, 0, sizeof(struct sip_proxy)); - sip_cfg.outboundproxy.ip.sin_port = htons(STANDARD_SIP_PORT); - sip_cfg.outboundproxy.ip.sin_family = AF_INET; /*!< Type of address: IPv4 */ sip_cfg.outboundproxy.force = FALSE; /*!< Don't force proxy usage, use route: headers */ default_transports = 0; /*!< Reset default transport to zero here, default value later on */ default_primary_transport = 0; /*!< Reset default primary transport to zero here, default value later on */ ourport_tcp = STANDARD_SIP_PORT; ourport_tls = STANDARD_TLS_PORT; - externtcpport = 0; - externtlsport = 0; - bindaddr.sin_port = htons(STANDARD_SIP_PORT); + externtcpport = STANDARD_SIP_PORT; + externtlsport = STANDARD_TLS_PORT; sip_cfg.srvlookup = DEFAULT_SRVLOOKUP; global_tos_sip = DEFAULT_TOS_SIP; global_tos_audio = DEFAULT_TOS_AUDIO; @@ -25920,6 +26000,7 @@ static int reload_config(enum channelreloadreason reason) ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP); /* Default for all devices: TRUE */ sip_cfg.peer_rtupdate = TRUE; global_dynamic_exclude_static = 0; /* Exclude static peers */ + sip_cfg.tcp_enabled = FALSE; /* Session-Timers */ global_st_mode = SESSION_TIMER_MODE_ACCEPT; @@ -26056,14 +26137,18 @@ static int reload_config(enum channelreloadreason reason) } } } else if (!strcasecmp(v->name, "tcpenable")) { - sip_tcp_desc.local_address.sin_family = ast_false(v->value) ? 0 : AF_INET; - ast_debug(2, "Enabling TCP socket for listening\n"); + if (!ast_false(v->value)) { + ast_debug(2, "Enabling TCP socket for listening\n"); + sip_cfg.tcp_enabled = TRUE; + } } else if (!strcasecmp(v->name, "tcpbindaddr")) { - int family = sip_tcp_desc.local_address.sin_family; - if (ast_parse_arg(v->value, PARSE_INADDR, &sip_tcp_desc.local_address)) - ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config); - sip_tcp_desc.local_address.sin_family = family; - ast_debug(2, "Setting TCP socket address to %s\n", v->value); + if (ast_parse_arg(v->value, PARSE_ADDR, + &sip_tcp_desc.local_address)) { + ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", + v->name, v->value, v->lineno, config); + } + ast_debug(2, "Setting TCP socket address to %s\n", + ast_sockaddr_stringify(&sip_tcp_desc.local_address)); } else if (!strcasecmp(v->name, "dynamic_exclude_static") || !strcasecmp(v->name, "dynamic_excludes_static")) { global_dynamic_exclude_static = ast_true(v->value); } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny")) { @@ -26155,7 +26240,6 @@ static int reload_config(enum channelreloadreason reason) default_fromdomainport = STANDARD_SIP_PORT; } } else if (!strcasecmp(v->name, "outboundproxy")) { - int portnum; char *tok, *proxyname; if (ast_strlen_zero(v->value)) { @@ -26165,10 +26249,10 @@ static int reload_config(enum channelreloadreason reason) tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - sip_parse_host(tok, v->lineno, &proxyname, &portnum, &sip_cfg.outboundproxy.transport); + sip_parse_host(tok, v->lineno, &proxyname, + &sip_cfg.outboundproxy.port, + &sip_cfg.outboundproxy.transport); - sip_cfg.outboundproxy.ip.sin_port = htons(portnum); - if ((tok = strtok(NULL, ","))) { sip_cfg.outboundproxy.force = !strncasecmp(ast_skip_blanks(tok), "force", 5); } else { @@ -26227,8 +26311,9 @@ static int reload_config(enum channelreloadreason reason) ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value); externexpire = time(NULL); } else if (!strcasecmp(v->name, "bindaddr") || !strcasecmp(v->name, "udpbindaddr")) { - if (ast_parse_arg(v->value, PARSE_INADDR, &bindaddr)) + if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) { ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); + } } else if (!strcasecmp(v->name, "localnet")) { struct ast_ha *na; int ha_error = 0; @@ -26240,23 +26325,21 @@ static int reload_config(enum channelreloadreason reason) if (ha_error) ast_log(LOG_ERROR, "Bad localnet configuration value line %d : %s\n", v->lineno, v->value); } else if (!strcasecmp(v->name, "media_address")) { - if (ast_parse_arg(v->value, PARSE_INADDR, &media_address)) + if (ast_parse_arg(v->value, PARSE_ADDR, &media_address)) ast_log(LOG_WARNING, "Invalid address for media_address keyword: %s\n", v->value); } else if (!strcasecmp(v->name, "externip")) { - if (ast_parse_arg(v->value, PARSE_INADDR, &externip)) - ast_log(LOG_WARNING, "Invalid address for externip keyword: %s\n", v->value); + if (ast_parse_arg(v->value, PARSE_ADDR, &externip)) { + ast_log(LOG_WARNING, + "Invalid address for externip keyword: %s\n", + v->value); + } externexpire = 0; - /* If no port was specified use the value of bindport */ - if (!externip.sin_port) - externip.sin_port = bindaddr.sin_port; } else if (!strcasecmp(v->name, "externhost")) { ast_copy_string(externhost, v->value, sizeof(externhost)); - if (ast_parse_arg(externhost, PARSE_INADDR, &externip)) + if (ast_sockaddr_resolve_first(&externip, externhost, 0)) { ast_log(LOG_WARNING, "Invalid address for externhost keyword: %s\n", externhost); + } externexpire = time(NULL); - /* If no port was specified use the value of bindport */ - if (!externip.sin_port) - externip.sin_port = bindaddr.sin_port; } else if (!strcasecmp(v->name, "externrefresh")) { if (sscanf(v->value, "%30d", &externrefresh) != 1) { ast_log(LOG_WARNING, "Invalid externrefresh value '%s', must be an integer >0 at line %d\n", v->value, v->lineno); @@ -26264,13 +26347,12 @@ static int reload_config(enum channelreloadreason reason) } } else if (!strcasecmp(v->name, "externtcpport")) { if (!(externtcpport = port_str2int(v->value, 0))) { - ast_log(LOG_WARNING, "Invalid externtcpport value, must be a positive integer between 1 and 65535 at line %d\n", v->lineno); - externtcpport = ntohs(sip_tcp_desc.local_address.sin_port); + ast_log(LOG_WARNING, "Invalid externtcpport value, must be a positive integer between 1 and 65535 at line %d\n", v->lineno); + externtcpport = 0; } } else if (!strcasecmp(v->name, "externtlsport")) { - if (!(externtlsport = port_str2int(v->value, 0))) { + if (!(externtlsport = port_str2int(v->value, STANDARD_TLS_PORT))) { ast_log(LOG_WARNING, "Invalid externtlsport value, must be a positive integer between 1 and 65535 at line %d\n", v->lineno); - externtlsport = ntohs(sip_tls_desc.local_address.sin_port); } } else if (!strcasecmp(v->name, "allow")) { int error = ast_parse_allow_disallow(&default_prefs, &sip_cfg.capability, v->value, TRUE); @@ -26331,12 +26413,8 @@ static int reload_config(enum channelreloadreason reason) if (ast_str2cos(v->value, &global_cos_text)) ast_log(LOG_WARNING, "Invalid cos_text value at line %d, refer to QoS documentation\n", v->lineno); } else if (!strcasecmp(v->name, "bindport")) { - int i; - if (sscanf(v->value, "%5d", &i) == 1) { - bindaddr.sin_port = htons(i); - } else { + if (sscanf(v->value, "%5d", &bindport) != 1) ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config); - } } else if (!strcasecmp(v->name, "qualify")) { if (!strcasecmp(v->value, "no")) { default_qualify = 0; @@ -26449,13 +26527,6 @@ static int reload_config(enum channelreloadreason reason) default_transports = default_primary_transport = SIP_TRANSPORT_UDP; } - /* if not configured, set the defaults for externtcpport and externtlsport */ - if (!externtcpport) { - externtcpport = ntohs(externip.sin_port); /* for consistency, default to the externip port */ - } - if (!externtlsport) { - externtlsport = STANDARD_TLS_PORT; - } /* Build list of authentication to various SIP realms, i.e. service providers */ for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) { /* Format for authentication is auth = username:password@realm */ @@ -26482,7 +26553,7 @@ static int reload_config(enum channelreloadreason reason) /* user.conf entries are always of type friend */ peer->type = SIP_TYPE_USER | SIP_TYPE_PEER; ao2_t_link(peers, peer, "link peer into peer table"); - if ((peer->type & SIP_TYPE_PEER) && peer->addr.sin_addr.s_addr) { + if ((peer->type & SIP_TYPE_PEER) && !ast_sockaddr_isnull(&peer->addr)) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } @@ -26552,7 +26623,7 @@ static int reload_config(enum channelreloadreason reason) peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0, 0); if (peer) { ao2_t_link(peers, peer, "link peer into peers table"); - if ((peer->type & SIP_TYPE_PEER) && peer->addr.sin_addr.s_addr) { + if ((peer->type & SIP_TYPE_PEER) && !ast_sockaddr_isnull(&peer->addr)) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } unref_peer(peer, "unref the result of the build_peer call. Now, the links from the tables are the only ones left."); @@ -26560,22 +26631,34 @@ static int reload_config(enum channelreloadreason reason) } } } - + + if (bindport) { + if (ast_sockaddr_port(&bindaddr)) { + ast_log(LOG_WARNING, "bindport is also specified in bindaddr. " + "Using %d.\n", bindport); + } + ast_sockaddr_set_port(&bindaddr, bindport); + } + + if (!ast_sockaddr_port(&bindaddr)) { + ast_sockaddr_set_port(&bindaddr, STANDARD_SIP_PORT); + } + /* Set UDP address and open socket */ - bindaddr.sin_family = AF_INET; - internip = bindaddr; - if (ast_find_ourip(&internip.sin_addr, bindaddr)) { + ast_sockaddr_copy(&internip, &bindaddr); + if (ast_find_ourip(&internip, &bindaddr)) { ast_log(LOG_WARNING, "Unable to get own IP address, SIP disabled\n"); ast_config_destroy(cfg); return 0; } ast_mutex_lock(&netlock); - if ((sipsock > -1) && (memcmp(&old_bindaddr, &bindaddr, sizeof(struct sockaddr_in)))) { + if ((sipsock > -1) && (ast_sockaddr_cmp(&old_bindaddr, &bindaddr))) { close(sipsock); sipsock = -1; } if (sipsock < 0) { - sipsock = socket(AF_INET, SOCK_DGRAM, 0); + sipsock = socket(ast_sockaddr_is_ipv6(&bindaddr) ? + AF_INET6 : AF_INET, SOCK_DGRAM, 0); if (sipsock < 0) { ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno)); ast_config_destroy(cfg); @@ -26590,35 +26673,43 @@ static int reload_config(enum channelreloadreason reason) ast_enable_packet_fragmentation(sipsock); - if (bind(sipsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) { - ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n", - ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port), - strerror(errno)); + if (ast_bind(sipsock, &bindaddr) < 0) { + ast_log(LOG_WARNING, "Failed to bind to %s: %s\n", + ast_sockaddr_stringify(&bindaddr), strerror(errno)); close(sipsock); sipsock = -1; } else { - ast_verb(2, "SIP Listening on %s:%d\n", - ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port)); - ast_netsock_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP"); + ast_verb(2, "SIP Listening on %s\n", ast_sockaddr_stringify(&bindaddr)); + ast_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP"); } } } if (stunaddr.sin_addr.s_addr != 0) { ast_debug(1, "stun to %s:%d\n", ast_inet_ntoa(stunaddr.sin_addr) , ntohs(stunaddr.sin_port)); + ast_sockaddr_to_sin(&externip, &externip_sin); ast_stun_request(sipsock, &stunaddr, - NULL, &externip); - ast_debug(1, "STUN sees us at %s:%d\n", - ast_inet_ntoa(externip.sin_addr) , ntohs(externip.sin_port)); + NULL, &externip_sin); + ast_debug(1, "STUN sees us at %s\n", + ast_sockaddr_stringify(&externip)); } ast_mutex_unlock(&netlock); /* Start TCP server */ + if (sip_cfg.tcp_enabled) { + if (ast_sockaddr_isnull(&sip_tcp_desc.local_address)) { + ast_sockaddr_copy(&sip_tcp_desc.local_address, &bindaddr); + } + if (!ast_sockaddr_port(&sip_tcp_desc.local_address)) { + ast_sockaddr_set_port(&sip_tcp_desc.local_address, STANDARD_SIP_PORT); + } + } else { + ast_sockaddr_setnull(&sip_tcp_desc.local_address); + } ast_tcptls_server_start(&sip_tcp_desc); - if (sip_tcp_desc.accept_fd == -1 && sip_tcp_desc.local_address.sin_family == AF_INET) { + if (sip_cfg.tcp_enabled && sip_tcp_desc.accept_fd == -1) { /* TCP server start failed. Tell the admin */ ast_log(LOG_ERROR, "SIP TCP Server start failed. Not listening on TCP socket.\n"); - sip_tcp_desc.local_address.sin_family = 0; } else { ast_debug(2, "SIP TCP server started\n"); } @@ -26627,6 +26718,15 @@ static int reload_config(enum channelreloadreason reason) memcpy(sip_tls_desc.tls_cfg, &default_tls_cfg, sizeof(default_tls_cfg)); if (ast_ssl_setup(sip_tls_desc.tls_cfg)) { + if (ast_sockaddr_isnull(&sip_tls_desc.local_address)) { + ast_sockaddr_copy(&sip_tls_desc.local_address, &bindaddr); + ast_sockaddr_set_port(&sip_tls_desc.local_address, + STANDARD_TLS_PORT); + } + if (!ast_sockaddr_port(&sip_tls_desc.local_address)) { + ast_sockaddr_set_port(&sip_tls_desc.local_address, + STANDARD_TLS_PORT); + } ast_tcptls_server_start(&sip_tls_desc); if (default_tls_cfg.enabled && sip_tls_desc.accept_fd == -1) { ast_log(LOG_ERROR, "TLS Server start failed. Not listening on TLS socket.\n"); @@ -26647,26 +26747,36 @@ static int reload_config(enum channelreloadreason reason) char temp[MAXHOSTNAMELEN]; /* First our default IP address */ - if (bindaddr.sin_addr.s_addr) { - add_sip_domain(ast_inet_ntoa(bindaddr.sin_addr), SIP_DOMAIN_AUTO, NULL); - } else if (internip.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&bindaddr)) { + add_sip_domain(ast_sockaddr_stringify(&bindaddr), SIP_DOMAIN_AUTO, NULL); + } else if (!ast_sockaddr_isnull(&internip)) { /* Our internal IP address, if configured */ - add_sip_domain(ast_inet_ntoa(internip.sin_addr), SIP_DOMAIN_AUTO, NULL); + add_sip_domain(ast_sockaddr_stringify(&internip), SIP_DOMAIN_AUTO, NULL); } else { ast_log(LOG_NOTICE, "Can't add wildcard IP address to domain list, please add IP address to domain manually.\n"); } /* If TCP is running on a different IP than UDP, then add it too */ - if (sip_tcp_desc.local_address.sin_addr.s_addr && !inaddrcmp(&bindaddr, &sip_tcp_desc.local_address)) - add_sip_domain(ast_inet_ntoa(sip_tcp_desc.local_address.sin_addr), SIP_DOMAIN_AUTO, NULL); + if (!ast_sockaddr_isnull(&sip_tcp_desc.local_address) && + !ast_sockaddr_cmp(&bindaddr, &sip_tcp_desc.local_address)) { + add_sip_domain(ast_sockaddr_stringify(&sip_tcp_desc.local_address), + SIP_DOMAIN_AUTO, NULL); + } - /* If TLS is running on a differen IP than UDP and TCP, then add that too */ - if (sip_tls_desc.local_address.sin_addr.s_addr && !inaddrcmp(&bindaddr, &sip_tls_desc.local_address) && inaddrcmp(&sip_tcp_desc.local_address, &sip_tls_desc.local_address)) - add_sip_domain(ast_inet_ntoa(sip_tls_desc.local_address.sin_addr), SIP_DOMAIN_AUTO, NULL); + /* If TLS is running on a different IP than UDP and TCP, then add that too */ + if (!ast_sockaddr_isnull(&sip_tls_desc.local_address) && + !ast_sockaddr_cmp(&bindaddr, &sip_tls_desc.local_address) && + !ast_sockaddr_cmp(&sip_tcp_desc.local_address, + &sip_tls_desc.local_address)) { + add_sip_domain(ast_sockaddr_stringify(&sip_tcp_desc.local_address), + SIP_DOMAIN_AUTO, NULL); + } /* Our extern IP address, if configured */ - if (externip.sin_addr.s_addr) - add_sip_domain(ast_inet_ntoa(externip.sin_addr), SIP_DOMAIN_AUTO, NULL); + if (!ast_sockaddr_isnull(&externip)) { + add_sip_domain(ast_sockaddr_stringify(&externip), SIP_DOMAIN_AUTO, + NULL); + } /* Extern host name (NAT traversal support) */ if (!ast_strlen_zero(externhost)) @@ -26698,15 +26808,23 @@ static int reload_config(enum channelreloadreason reason) static int apply_directmedia_ha(struct sip_pvt *p, const char *op) { - struct sockaddr_in us = {0,}, them = {0,}; - int res; + struct ast_sockaddr us = { { 0, }, }, them = { { 0, }, }; + struct sockaddr_in them_sin; + int res = AST_SENSE_ALLOW; ast_rtp_instance_get_remote_address(p->rtp, &them); ast_rtp_instance_get_local_address(p->rtp, &us); - if (!(res = ast_apply_ha(p->directmediaha, &them))) { + /* Currently ast_apply_ha doesn't support IPv6 */ + if (ast_sockaddr_is_ipv6(&them)) { + return res; + } + + ast_sockaddr_to_sin(&them, &them_sin); + + if ((res = ast_apply_ha(p->directmediaha, &them_sin)) == AST_SENSE_DENY) { ast_debug(3, "Reinvite %s to %s denied by directmedia ACL on %s\n", - op, ast_inet_ntoa(them.sin_addr), ast_inet_ntoa(us.sin_addr)); + op, ast_sockaddr_stringify(&them), ast_sockaddr_stringify(&us)); } return res; @@ -26744,11 +26862,14 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl) else memset(&p->udptlredirip, 0, sizeof(p->udptlredirip)); if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) { + struct sockaddr_in ourip_sin; + ast_sockaddr_to_sin(&p->ourip, &ourip_sin); if (!p->pendinginvite) { - ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(udptl ? p->udptlredirip.sin_addr : p->ourip.sin_addr), udptl ? ntohs(p->udptlredirip.sin_port) : 0); + ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(udptl ? p->udptlredirip.sin_addr : ourip_sin.sin_addr), udptl ? ntohs(p->udptlredirip.sin_port) : 0); + transmit_reinvite_with_sdp(p, TRUE, FALSE); } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) { - ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(udptl ? p->udptlredirip.sin_addr : p->ourip.sin_addr), udptl ? ntohs(p->udptlredirip.sin_port) : 0); + ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(udptl ? p->udptlredirip.sin_addr : ourip_sin.sin_addr), udptl ? ntohs(p->udptlredirip.sin_port) : 0); ast_set_flag(&p->flags[0], SIP_NEEDREINVITE); } } @@ -26886,19 +27007,19 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i if (instance) { changed |= ast_rtp_instance_get_remote_address(instance, &p->redirip); - } else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) { + } else if (!ast_sockaddr_isnull(&p->redirip)) { memset(&p->redirip, 0, sizeof(p->redirip)); changed = 1; } if (vinstance) { changed |= ast_rtp_instance_get_remote_address(vinstance, &p->vredirip); - } else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) { + } else if (!ast_sockaddr_isnull(&p->vredirip)) { memset(&p->vredirip, 0, sizeof(p->vredirip)); changed = 1; } if (tinstance) { changed |= ast_rtp_instance_get_remote_address(tinstance, &p->tredirip); - } else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) { + } else if (!ast_sockaddr_isnull(&p->tredirip)) { memset(&p->tredirip, 0, sizeof(p->tredirip)); changed = 1; } @@ -26910,12 +27031,12 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i if (chan->_state != AST_STATE_UP) { /* We are in early state */ if (p->do_history) append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal."); - ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr)); + ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_sockaddr_stringify(instance ? &p->redirip : &p->ourip)); } else if (!p->pendinginvite) { /* We are up, and have no outstanding invite */ - ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr)); + ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_sockaddr_stringify(instance ? &p->redirip : &p->ourip)); transmit_reinvite_with_sdp(p, FALSE, FALSE); } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) { - ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr)); + ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_sockaddr_stringify(instance ? &p->redirip : &p->ourip)); /* We have a pending Invite. Send re-invite when we're done with the invite */ ast_set_flag(&p->flags[0], SIP_NEEDREINVITE); } @@ -27321,6 +27442,40 @@ static int reload(void) return 1; } +/*! \brief Return the first entry from ast_sockaddr_resolve filtered by address family + * + * \warn Using this function probably means you have a faulty design. + */ +static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, + const char* name, int flag, int family) +{ + struct ast_sockaddr *addrs; + int addrs_cnt; + + addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family); + if (addrs_cnt <= 0) { + return 1; + } + if (addrs_cnt > 1) { + ast_log(LOG_DEBUG, "Multiple addresses, using the first one only\n"); + } + + ast_sockaddr_copy(addr, &addrs[0]); + + ast_free(addrs); + return 0; +} + +/*! \brief Return the first entry from ast_sockaddr_resolve filtered by family of binddaddr + * + * \warn Using this function probably means you have a faulty design. + */ +static int ast_sockaddr_resolve_first(struct ast_sockaddr *addr, + const char* name, int flag) +{ + return ast_sockaddr_resolve_first_af(addr, name, flag, get_address_family_filter(&bindaddr)); +} + /*! \brief * \note The only member of the peer used here is the name field */ @@ -27342,16 +27497,26 @@ static int peer_cmp_cb(void *obj, void *arg, int flags) } /*! - * \note the peer's ip address field is used to create key. + * Hash function based on the the peer's ip address. For IPv6, we use the end + * of the address. + * \todo Find a better hashing function */ static int peer_iphash_cb(const void *obj, const int flags) { const struct sip_peer *peer = obj; - int ret1 = peer->addr.sin_addr.s_addr; - if (ret1 < 0) - ret1 = -ret1; + int ret = 0; + + if (ast_sockaddr_isnull(&peer->addr)) { + ast_log(LOG_ERROR, "Empty address\n"); + } - return ret1; + ret = ast_sockaddr_hash(&peer->addr); + + if (ret < 0) { + ret = -ret; + } + + return ret; } /*! @@ -27376,7 +27541,7 @@ static int peer_ipcmp_cb(void *obj, void *arg, int flags) { struct sip_peer *peer = obj, *peer2 = arg; - if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr) { + if (ast_sockaddr_cmp_addr(&peer->addr, &peer2->addr)) { /* IP doesn't match */ return 0; } @@ -27393,7 +27558,8 @@ static int peer_ipcmp_cb(void *obj, void *arg, int flags) } /* Now only return a match if the port matches, as well. */ - return peer->addr.sin_port == peer2->addr.sin_port ? (CMP_MATCH | CMP_STOP) : 0; + return ast_sockaddr_port(&peer->addr) == ast_sockaddr_port(&peer2->addr) ? + (CMP_MATCH | CMP_STOP) : 0; } @@ -27401,7 +27567,7 @@ static int threadt_hash_cb(const void *obj, const int flags) { const struct sip_threadinfo *th = obj; - return (int) th->tcptls_session->remote_address.sin_addr.s_addr; + return ast_sockaddr_hash(&th->tcptls_session->remote_address); } static int threadt_cmp_cb(void *obj, void *arg, int flags) diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 2c0224a7cde8ead53c2457ba76b113b791023d6d..6ddc3f0cf767280af78f74ee102e08e6dd893b6d 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -2804,6 +2804,8 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r struct ast_format_list fmt; struct sockaddr_in us = { 0, }; struct sockaddr_in them = { 0, }; + struct ast_sockaddr them_tmp; + struct ast_sockaddr us_tmp; sub = c->tech_pvt; @@ -2818,7 +2820,8 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r d = l->device; if (rtp){ - ast_rtp_instance_get_remote_address(rtp, &them); + ast_rtp_instance_get_remote_address(rtp, &them_tmp); + ast_sockaddr_to_sin(&them_tmp, &them); /* Shutdown any early-media or previous media on re-invite */ transmit_stopmediatransmission(d, sub); @@ -2832,7 +2835,8 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(fmt.bits), fmt.cur_ms); if (!(l->directmedia) || (l->nat)){ - ast_rtp_instance_get_local_address(rtp, &us); + ast_rtp_instance_get_local_address(rtp, &us_tmp); + ast_sockaddr_to_sin(&us_tmp, &us); us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr; transmit_startmediatransmission(d, sub, us, fmt); } else { @@ -3702,12 +3706,14 @@ static void start_rtp(struct skinny_subchannel *sub) struct skinny_line *l = sub->parent; struct skinny_device *d = l->device; int hasvideo = 0; + struct ast_sockaddr bindaddr_tmp; ast_mutex_lock(&sub->lock); /* Allocate the RTP */ - sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL); + ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); + sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL); if (hasvideo) - sub->vrtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL); + sub->vrtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL); if (sub->rtp) { ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1); @@ -5603,6 +5609,8 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc struct ast_format_list fmt; struct sockaddr_in sin = { 0, }; struct sockaddr_in us = { 0, }; + struct ast_sockaddr sin_tmp; + struct ast_sockaddr us_tmp; uint32_t addr; int port; int status; @@ -5629,8 +5637,10 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc l = sub->parent; if (sub->rtp) { - ast_rtp_instance_set_remote_address(sub->rtp, &sin); - ast_rtp_instance_get_local_address(sub->rtp, &us); + ast_sockaddr_from_sin(&sin_tmp, &sin); + ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp); + ast_rtp_instance_get_local_address(sub->rtp, &us_tmp); + ast_sockaddr_to_sin(&us_tmp, &us); us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr; } else { ast_log(LOG_ERROR, "No RTP structure, this is very bad\n"); @@ -6802,9 +6812,13 @@ static struct ast_channel *skinny_request(const char *type, format_t format, con } } else if (!strcasecmp(v->name, "host")) { if (type & (TYPE_DEVICE)) { - if (ast_get_ip(&CDEV->addr, v->value)) { + struct ast_sockaddr CDEV_addr_tmp; + + if (ast_get_ip(&CDEV_addr_tmp, v->value)) { ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno); } + ast_sockaddr_to_sin(&CDEV_addr_tmp, + &CDEV->addr); continue; } } else if (!strcasecmp(v->name, "port")) { diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 0ebf879a1c566de7e48de1a6d86b1dbc7c91bfc8..18b76c5e846b6f9112063300eb1503e5fb8ed172 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -2038,6 +2038,9 @@ static void start_rtp(struct unistim_subchannel *sub) struct sockaddr_in sin = { 0, }; format_t codec; struct sockaddr_in sout = { 0, }; + struct ast_sockaddr us_tmp; + struct ast_sockaddr sin_tmp; + struct ast_sockaddr sout_tmp; /* Sanity checks */ if (!sub) { @@ -2062,7 +2065,8 @@ static void start_rtp(struct unistim_subchannel *sub) /* Allocate the RTP */ if (unistimdebug) ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr)); - sub->rtp = ast_rtp_instance_new("asterisk", sched, &sout, NULL); + ast_sockaddr_from_sin(&sout_tmp, &sout); + sub->rtp = ast_rtp_instance_new("asterisk", sched, &sout_tmp, NULL); if (!sub->rtp) { ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n", strerror(errno), ast_inet_ntoa(sout.sin_addr)); @@ -2078,13 +2082,15 @@ static void start_rtp(struct unistim_subchannel *sub) ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->parent->parent->nat); /* Create the RTP connection */ - ast_rtp_instance_get_local_address(sub->rtp, &us); + ast_rtp_instance_get_local_address(sub->rtp, &us_tmp); + ast_sockaddr_to_sin(&us_tmp, &us); sin.sin_family = AF_INET; /* Setting up RTP for our side */ memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr, sizeof(sin.sin_addr)); sin.sin_port = htons(sub->parent->parent->rtp_port); - ast_rtp_instance_set_remote_address(sub->rtp, &sin); + ast_sockaddr_from_sin(&sin_tmp, &sin); + ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp); if (!(sub->owner->nativeformats & sub->owner->readformat)) { format_t fmt; char tmp[256]; diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index d09627ed8c440e6fd1a9d247d43ed452e93c1f3e..6e1f65b84fa5a11052cad59d6fef41e6f54e6070 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -62,9 +62,9 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p } if (!strcasecmp(args.param, "peerip")) { - ast_copy_string(buf, p->sa.sin_addr.s_addr ? ast_inet_ntoa(p->sa.sin_addr) : "", buflen); + ast_copy_string(buf, ast_sockaddr_isnull(&p->sa) ? "" : ast_sockaddr_stringify_addr(&p->sa), buflen); } else if (!strcasecmp(args.param, "recvip")) { - ast_copy_string(buf, p->recv.sin_addr.s_addr ? ast_inet_ntoa(p->recv.sin_addr) : "", buflen); + ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_addr(&p->recv), buflen); } else if (!strcasecmp(args.param, "from")) { ast_copy_string(buf, p->from, buflen); } else if (!strcasecmp(args.param, "uri")) { @@ -76,7 +76,7 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p } else if (!strcasecmp(args.param, "t38passthrough")) { ast_copy_string(buf, (p->t38.state == T38_DISABLED) ? "0" : "1", buflen); } else if (!strcasecmp(args.param, "rtpdest")) { - struct sockaddr_in sin; + struct ast_sockaddr addr; struct ast_rtp_instance *stream; if (ast_strlen_zero(args.type)) @@ -96,10 +96,10 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p return 0; } - ast_rtp_instance_get_remote_address(stream, &sin); - snprintf(buf, buflen, "%s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + ast_rtp_instance_get_remote_address(stream, &addr); + snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&addr)); } else if (!strcasecmp(args.param, "rtpsource")) { - struct sockaddr_in sin; + struct ast_sockaddr sa; struct ast_rtp_instance *stream; if (ast_strlen_zero(args.type)) @@ -119,15 +119,15 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p return 0; } - ast_rtp_instance_get_local_address(stream, &sin); + ast_rtp_instance_get_local_address(stream, &sa); - if (!sin.sin_addr.s_addr) { - struct sockaddr_in dest_sin; - ast_rtp_instance_get_remote_address(stream, &dest_sin); - ast_ouraddrfor(&dest_sin.sin_addr, &sin.sin_addr); + if (ast_sockaddr_isnull(&sa)) { + struct ast_sockaddr dest_sa; + ast_rtp_instance_get_remote_address(stream, &dest_sa); + ast_ouraddrfor(&dest_sa, &sa); } - snprintf(buf, buflen, "%s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&sa)); } else if (!strcasecmp(args.param, "rtpqos")) { struct ast_rtp_instance *rtp = NULL; @@ -225,7 +225,7 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p } #ifdef TEST_FRAMEWORK -static int test_sip_rtpqos_1_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data) +static int test_sip_rtpqos_1_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct ast_sockaddr *addr, void *data) { /* Needed to pass sanity checks */ ast_rtp_instance_set_data(instance, data); @@ -268,7 +268,7 @@ AST_TEST_DEFINE(test_sip_rtpqos_1) .write = test_sip_rtpqos_1_write, .get_stat = test_sip_rtpqos_1_get_stat, }; - struct sockaddr_in sin = { .sin_port = 31337, .sin_addr = { .s_addr = 4 * 16777216 + 3 * 65536 + 2 * 256 + 1 } }; + struct ast_sockaddr sa = { {0, } }; struct ast_rtp_instance_stats mine = { 0, }; struct sip_pvt *p = NULL; struct ast_channel *chan = NULL; @@ -331,11 +331,12 @@ AST_TEST_DEFINE(test_sip_rtpqos_1) res = AST_TEST_NOT_RUN; goto done; } + if (!(p->rtp = ast_rtp_instance_new("test", sched, &bindaddr, &mine))) { res = AST_TEST_NOT_RUN; goto done; } - ast_rtp_instance_set_remote_address(p->rtp, &sin); + ast_rtp_instance_set_remote_address(p->rtp, &sa); if (!(chan = ast_dummy_channel_alloc())) { res = AST_TEST_NOT_RUN; goto done; diff --git a/channels/sip/include/dialog.h b/channels/sip/include/dialog.h index 8972c02d97e4abed9dfde819846f3143be9cb00c..ed31b77742cf50d0ccbaa8c068f1b952cf21c1d0 100644 --- a/channels/sip/include/dialog.h +++ b/channels/sip/include/dialog.h @@ -34,7 +34,7 @@ struct sip_pvt *dialog_ref_debug(struct sip_pvt *p, char *tag, char *file, int line, const char *func); struct sip_pvt *dialog_unref_debug(struct sip_pvt *p, char *tag, char *file, int line, const char *func); -struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, +struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *sin, int useglobal_nat, const int intended_method, struct sip_request *req); void sip_scheddestroy_final(struct sip_pvt *p, int ms); void sip_scheddestroy(struct sip_pvt *p, int ms); diff --git a/channels/sip/include/globals.h b/channels/sip/include/globals.h index 0d7131d87c6ee1ca9cbae7a5d6f0c896bdaa026b..414d2189b55bf15960e266e6b059b0770918857d 100644 --- a/channels/sip/include/globals.h +++ b/channels/sip/include/globals.h @@ -24,7 +24,7 @@ #ifndef _SIP_GLOBALS_H #define _SIP_GLOBALS_H -extern struct sockaddr_in bindaddr; /*!< UDP: The address we bind to */ +extern struct ast_sockaddr bindaddr; /*!< UDP: The address we bind to */ extern struct sched_context *sched; /*!< The scheduling context */ /*! \brief Definition of this channel for PBX channel registration */ diff --git a/channels/sip/include/reqresp_parser.h b/channels/sip/include/reqresp_parser.h index 58784a621c2ccdd2c2289a576fa4d24d72fe7907..d8631c9820fffaf3a1c1d5a228ee37c0b0235cb4 100644 --- a/channels/sip/include/reqresp_parser.h +++ b/channels/sip/include/reqresp_parser.h @@ -28,7 +28,7 @@ * \note * - Multiple scheme's can be specified ',' delimited. ex: "sip:,sips:" * - If a component is not requested, do not split around it. This means - * that if we don't have domain, we cannot split name:pass and domain:port. + * that if we don't have domain, we cannot split name:pass. * - It is safe to call with ret_name, pass, domain, port pointing all to * the same place. * - If no secret parameter is provided, ret_name will return with both parts, user:secret @@ -42,7 +42,8 @@ * general form we are expecting is sip:user:password;user-parameters@host:port;uri-parameters?headers * \endverbatim */ -int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass, char **domain, char **port, char **transport); +int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass, + char **domain, char **transport); /*! * \brief parses a URI in to all of its components and any trailing residue @@ -51,7 +52,9 @@ int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass, char * \retval -1 on error. * */ -int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **residue); +int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, + char **domain, struct uriparams *params, char **headers, + char **residue); /*! * \brief Get caller id name from SIP headers, copy into output buffer @@ -100,7 +103,10 @@ int get_in_brackets_full(char *tmp, char **out, char **residue); * \retval 0 success * \retval -1 failure */ -int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **remander); +int parse_name_andor_addr(char *uri, const char *scheme, char **name, + char **user, char **pass, char **domain, + struct uriparams *params, char **headers, + char **remander); /*! \brief Parse all contact header contacts * \retval 0 success diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 13527517f19b811e0ce1fe825a783b080bbc3881..92fa68e82e5e8f4f818b3415727b1b2b67f97f72 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -646,7 +646,8 @@ enum sip_tcptls_alert { */ struct sip_proxy { char name[MAXHOSTNAMELEN]; /*!< DNS name of domain/host or IP */ - struct sockaddr_in ip; /*!< Currently used IP address and port */ + struct ast_sockaddr ip; /*!< Currently used IP address and port */ + int port; time_t last_dnsupdate; /*!< When this was resolved */ enum sip_transport transport; int force; /*!< If it's an outbound proxy, Force use of this outbound proxy for all outbound requests */ @@ -702,6 +703,7 @@ struct sip_settings { char default_subscribecontext[AST_MAX_CONTEXT]; struct ast_ha *contact_ha; /*! \brief Global list of addresses dynamic peers are not allowed to use */ format_t capability; /*!< Supported codecs */ + int tcp_enabled; }; /*! \brief The SIP socket definition */ @@ -1008,16 +1010,16 @@ struct sip_pvt { long invite_branch; /*!< The branch used when we sent the initial INVITE */ int64_t sessionversion_remote; /*!< Remote UA's SDP Session Version */ unsigned int portinuri:1; /*!< Non zero if a port has been specified, will also disable srv lookups */ - struct sockaddr_in sa; /*!< Our peer */ - struct sockaddr_in redirip; /*!< Where our RTP should be going if not to us */ - struct sockaddr_in vredirip; /*!< Where our Video RTP should be going if not to us */ - struct sockaddr_in tredirip; /*!< Where our Text RTP should be going if not to us */ + struct ast_sockaddr sa; /*!< Our peer */ + struct ast_sockaddr redirip; /*!< Where our RTP should be going if not to us */ + struct ast_sockaddr vredirip; /*!< Where our Video RTP should be going if not to us */ + struct ast_sockaddr tredirip; /*!< Where our Text RTP should be going if not to us */ time_t lastrtprx; /*!< Last RTP received */ time_t lastrtptx; /*!< Last RTP sent */ int rtptimeout; /*!< RTP timeout time */ struct ast_ha *directmediaha; /*!< Which IPs are allowed to interchange direct media with this peer - copied from sip_peer */ - struct sockaddr_in recv; /*!< Received as */ - struct sockaddr_in ourip; /*!< Our IP (as seen from the outside) */ + struct ast_sockaddr recv; /*!< Received as */ + struct ast_sockaddr ourip; /*!< Our IP (as seen from the outside) */ enum transfermodes allowtransfer; /*!< REFER: restriction scheme */ struct ast_channel *owner; /*!< Who owns us (if we have an owner) */ struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */ @@ -1209,7 +1211,7 @@ struct sip_peer { ast_group_t pickupgroup; /*!< Pickup group */ struct sip_proxy *outboundproxy;/*!< Outbound proxy for this peer */ struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */ - struct sockaddr_in addr; /*!< IP address of peer */ + struct ast_sockaddr addr; /*!< IP address of peer */ unsigned int portinuri:1; /*!< Whether the port should be included in the URI */ struct sip_pvt *call; /*!< Call pointer */ int pokeexpire; /*!< Qualification: When to expire poke (qualify= checking) */ @@ -1217,7 +1219,7 @@ struct sip_peer { int maxms; /*!< Qualification: Max ms we will accept for the host to be up, 0 to not monitor */ int qualifyfreq; /*!< Qualification: Qualification: How often to check for the host to be up */ struct timeval ps; /*!< Qualification: Time for sending SIP OPTION in sip_pke_peer() */ - struct sockaddr_in defaddr; /*!< Default IP address, used until registration */ + struct ast_sockaddr defaddr; /*!< Default IP address, used until registration */ struct ast_ha *ha; /*!< Access control list */ struct ast_ha *contactha; /*!< Restrict what IPs are allowed in the Contact header (for registration) */ struct ast_ha *directmediaha; /*!< Restrict what IPs are allowed to interchange direct media with */ @@ -1281,7 +1283,7 @@ struct sip_registry { int callid_valid; /*!< 0 means we haven't chosen callid for this registry yet. */ unsigned int ocseq; /*!< Sequence number we got to for REGISTERs for this registry */ struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for register */ - struct sockaddr_in us; /*!< Who the server thinks we are */ + struct ast_sockaddr us; /*!< Who the server thinks we are */ int noncecount; /*!< Nonce-count */ char lastmsg[256]; /*!< Last Message sent/received */ }; @@ -1321,7 +1323,7 @@ struct sip_subscription_mwi { unsigned int subscribed:1; /*!< Whether we are currently subscribed or not */ struct sip_pvt *call; /*!< Outbound subscription dialog */ struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for subscription */ - struct sockaddr_in us; /*!< Who the server thinks we are */ + struct ast_sockaddr us; /*!< Who the server thinks we are */ }; /*! @@ -1697,8 +1699,7 @@ struct contact { char *name; char *user; char *pass; - char *host; - char *port; + char *domain; struct uriparams params; char *headers; char *expires; diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index bf35bc22638d831d584275dbbaa5512b3dacd11c..59cefaa46f064cd0bf155e6fb2c559cab9194eb0 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -28,7 +28,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "include/reqresp_parser.h" /*! \brief * parses a URI in its components.*/ -int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **residue) +int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, + char **domain, struct uriparams *params, char **headers, + char **residue) { char *userinfo = NULL; char *parameters = NULL; @@ -58,31 +60,24 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char } } - if (!host) { - /* if we don't want to split around host, keep everything as a userinfo - cos thats how old parse_uri operated*/ + if (!domain) { + /* if we don't want to split around domain, keep everything as a + * userinfo - cos thats how old parse_uri operated*/ userinfo = uri; } else { - char *hostport; + char *dom = ""; if ((c = strchr(uri, '@'))) { *c++ = '\0'; - hostport = c; + dom = c; userinfo = uri; - uri = hostport; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */ + uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */ } else { /* domain-only URI, according to the SIP RFC. */ - hostport = uri; + dom = uri; userinfo = ""; } - if (port && (c = strchr(hostport, ':'))) { /* Remove :port */ - *c++ = '\0'; - *port = c; - uri = c; - } else if (port) { - *port = ""; - } - - *host = hostport; + *domain = dom; } if (pass && (c = strchr(userinfo, ':'))) { /* user:password */ @@ -201,7 +196,7 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) { int res = AST_TEST_PASS; char uri[1024]; - char *user, *pass, *host, *port, *headers, *residue; + char *user, *pass, *domain, *headers, *residue; struct uriparams params; struct testdata { @@ -209,15 +204,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) char *uri; char **userptr; char **passptr; - char **hostptr; - char **portptr; + char **domainptr; char **headersptr; char **residueptr; struct uriparams *paramsptr; char *user; char *pass; - char *host; - char *port; + char *domain; char *headers; char *residue; struct uriparams params; @@ -234,17 +227,15 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", - .residue = "param2=residue", + .residue = "param2=residue", .params.transport = "tcp", .params.lr = 0, .params.user = "" @@ -255,15 +246,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "header=blah&header2=blah2", .residue = "param3=residue", .params.transport = "tcp", @@ -276,15 +265,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "-_.!~*'()&=+$,;?/", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", .residue = "", .params.transport = "tcp", @@ -297,15 +284,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "-_.!~*'()&=+$,", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", .residue = "", .params.transport = "tcp", @@ -318,15 +303,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@1-1.a-1.:5060;transport=tcp", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "1-1.a-1.", - .port = "5060", + .domain = "1-1.a-1.:5060", .headers = "", .residue = "", .params.transport = "tcp", @@ -339,15 +322,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", .residue = "", .params.transport = "tcp", @@ -360,15 +341,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "header=blah&header2=blah2", .residue = "-_.!~*'()[]/:&+$=residue", .params.transport = "", @@ -381,15 +360,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "header=blah", .residue = "", .params.transport = "", @@ -402,15 +379,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "header=blah", .residue = "", .params.transport = "", @@ -423,15 +398,13 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah", .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "header=blah", .residue = "", .params.transport = "", @@ -466,16 +439,19 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) } AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { - user = pass = host = port = headers = residue = NULL; + user = pass = domain = headers = residue = NULL; params.transport = params.user = params.method = params.ttl = params.maddr = NULL; params.lr = 0; ast_copy_string(uri,testdataptr->uri,sizeof(uri)); - if (parse_uri_full(uri, "sip:,sips:", testdataptr->userptr, testdataptr->passptr, testdataptr->hostptr, testdataptr->portptr, testdataptr->paramsptr, testdataptr->headersptr, testdataptr->residueptr) || + if (parse_uri_full(uri, "sip:,sips:", testdataptr->userptr, + testdataptr->passptr, testdataptr->domainptr, + testdataptr->paramsptr, + testdataptr->headersptr, + testdataptr->residueptr) || ((testdataptr->userptr) && strcmp(testdataptr->user, user)) || ((testdataptr->passptr) && strcmp(testdataptr->pass, pass)) || - ((testdataptr->hostptr) && strcmp(testdataptr->host, host)) || - ((testdataptr->portptr) && strcmp(testdataptr->port, port)) || + ((testdataptr->domainptr) && strcmp(testdataptr->domain, domain)) || ((testdataptr->headersptr) && strcmp(testdataptr->headers, headers)) || ((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) || ((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) || @@ -492,13 +468,14 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) } -int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **host, char **port, char **transport) { +int parse_uri(char *uri, const char *scheme, char **user, char **pass, + char **domain, char **transport) { int ret; char *headers; struct uriparams params; headers = NULL; - ret = parse_uri_full(uri, scheme, user, pass, host, port, ¶ms, &headers, NULL); + ret = parse_uri_full(uri, scheme, user, pass, domain, ¶ms, &headers, NULL); if (transport) { *transport=params.transport; } @@ -508,7 +485,7 @@ int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **ho AST_TEST_DEFINE(sip_parse_uri_test) { int res = AST_TEST_PASS; - char *name, *pass, *domain, *port, *transport; + char *name, *pass, *domain, *transport; char uri1[] = "sip:name@host"; char uri2[] = "sip:name@host;transport=tcp"; char uri3[] = "sip:name:secret@host;transport=tcp"; @@ -535,70 +512,66 @@ AST_TEST_DEFINE(sip_parse_uri_test) } /* Test 1, simple URI */ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri1, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (parse_uri(uri1, "sip:,sips:", &name, &pass, &domain, &transport) || strcmp(name, "name") || !ast_strlen_zero(pass) || strcmp(domain, "host") || - !ast_strlen_zero(port) || !ast_strlen_zero(transport)) { ast_test_status_update(test, "Test 1: simple uri failed. \n"); res = AST_TEST_FAIL; } /* Test 2, add tcp transport */ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri2, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (parse_uri(uri2, "sip:,sips:", &name, &pass, &domain, &transport) || strcmp(name, "name") || !ast_strlen_zero(pass) || strcmp(domain, "host") || - !ast_strlen_zero(port) || strcmp(transport, "tcp")) { ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n"); res = AST_TEST_FAIL; } /* Test 3, add secret */ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri3, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (parse_uri(uri3, "sip:,sips:", &name, &pass, &domain, &transport) || strcmp(name, "name") || strcmp(pass, "secret") || strcmp(domain, "host") || - !ast_strlen_zero(port) || strcmp(transport, "tcp")) { ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n"); res = AST_TEST_FAIL; } /* Test 4, add port and unparsed header field*/ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri4, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (parse_uri(uri4, "sip:,sips:", &name, &pass, &domain, &transport) || strcmp(name, "name") || strcmp(pass, "secret") || - strcmp(domain, "host") || - strcmp(port, "port") || + strcmp(domain, "host:port") || strcmp(transport, "tcp")) { ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n"); res = AST_TEST_FAIL; } /* Test 5, verify parse_uri does not crash when given a NULL uri */ - name = pass = domain = port = transport = NULL; - if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &domain, &port, &transport)) { + name = pass = domain = transport = NULL; + if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &domain, &transport)) { ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n"); res = AST_TEST_FAIL; } /* Test 6, verify parse_uri does not crash when given a NULL output parameters */ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL, NULL)) { + name = pass = domain = transport = NULL; + if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) { ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n"); res = AST_TEST_FAIL; } - /* Test 7, verify parse_uri returns user:secret and domain:port when no port or secret output parameters are supplied. */ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri7, "sip:,sips:", &name, NULL, &domain, NULL, NULL) || + /* Test 7, verify parse_uri returns user:secret and domain when no port or secret output parameters are supplied. */ + name = pass = domain = transport = NULL; + if (parse_uri(uri7, "sip:,sips:", &name, NULL, &domain, NULL) || strcmp(name, "name:secret") || strcmp(domain, "host:port")) { @@ -607,8 +580,8 @@ AST_TEST_DEFINE(sip_parse_uri_test) } /* Test 8, verify parse_uri can handle a domain only uri */ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri8, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (parse_uri(uri8, "sip:,sips:", &name, &pass, &domain, &transport) || strcmp(domain, "host") || !ast_strlen_zero(name)) { ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n"); @@ -616,12 +589,11 @@ AST_TEST_DEFINE(sip_parse_uri_test) } /* Test 9, add port and unparsed header field with domain only uri*/ - name = pass = domain = port = transport = NULL; - if (parse_uri(uri9, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (parse_uri(uri9, "sip:,sips:", &name, &pass, &domain, &transport) || !ast_strlen_zero(name) || !ast_strlen_zero(pass) || strcmp(domain, "host") || - strcmp(port, "port") || strcmp(transport, "tcp")) { ast_test_status_update(test, "Test 9: domain only uri failed \n"); res = AST_TEST_FAIL; @@ -630,12 +602,11 @@ AST_TEST_DEFINE(sip_parse_uri_test) /* Test 10, handle invalid/missing "sip:,sips:" scheme * we expect parse_uri to return an error, but still parse * the results correctly here */ - name = pass = domain = port = transport = NULL; - if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &domain, &transport) || !ast_strlen_zero(name) || !ast_strlen_zero(pass) || strcmp(domain, "host") || - strcmp(port, "port") || strcmp(transport, "tcp")) { ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n"); res = AST_TEST_FAIL; @@ -644,12 +615,11 @@ AST_TEST_DEFINE(sip_parse_uri_test) /* Test 11, simple domain only URI with missing scheme * we expect parse_uri to return an error, but still parse * the results correctly here */ - name = pass = domain = port = transport = NULL; - if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &domain, &port, &transport) || + name = pass = domain = transport = NULL; + if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &domain, &transport) || !ast_strlen_zero(name) || !ast_strlen_zero(pass) || strcmp(domain, "host") || - !ast_strlen_zero(port) || !ast_strlen_zero(transport)) { ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n"); res = AST_TEST_FAIL; @@ -871,7 +841,7 @@ int get_name_and_number(const char *hdr, char **name, char **number) tmp_number = get_in_brackets(header); /* parse out the number here */ - if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &domain, &dummy, NULL) || ast_strlen_zero(tmp_number)) { + if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &domain, NULL) || ast_strlen_zero(tmp_number)) { ast_log(LOG_ERROR, "can not parse name and number from sip header.\n"); return -1; } @@ -1149,7 +1119,10 @@ AST_TEST_DEFINE(get_in_brackets_test) } -int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **residue) +int parse_name_andor_addr(char *uri, const char *scheme, char **name, + char **user, char **pass, char **domain, + struct uriparams *params, char **headers, + char **residue) { static char buf[1024]; char **residue2=residue; @@ -1164,14 +1137,15 @@ int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **use residue2 = NULL; } - return parse_uri_full(uri, scheme, user, pass, host, port, params, headers, residue2); + return parse_uri_full(uri, scheme, user, pass, domain, params, headers, + residue2); } AST_TEST_DEFINE(parse_name_andor_addr_test) { int res = AST_TEST_PASS; char uri[1024]; - char *name, *user, *pass, *host, *port, *headers, *residue; + char *name, *user, *pass, *domain, *headers, *residue; struct uriparams params; struct testdata { @@ -1180,16 +1154,14 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) char **nameptr; char **userptr; char **passptr; - char **hostptr; - char **portptr; + char **domainptr; char **headersptr; char **residueptr; struct uriparams *paramsptr; char *name; char *user; char *pass; - char *host; - char *port; + char *domain; char *headers; char *residue; struct uriparams params; @@ -1206,16 +1178,14 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) .nameptr = &name, .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .name = "name :@ ", .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", .residue = "tag=tag", .params.transport = "tcp", @@ -1229,16 +1199,14 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) .nameptr = &name, .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .name = "givenname familyname", .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", .residue = "expires=3600", .params.transport = "tcp", @@ -1252,16 +1220,14 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) .nameptr = &name, .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .name = "", .user = "user", .pass = "secret", - .host = "host", - .port = "5060", + .domain = "host:5060", .headers = "", .residue = "q=1", .params.transport = "tcp", @@ -1275,16 +1241,14 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) .nameptr = &name, .userptr = &user, .passptr = &pass, - .hostptr = &host, - .portptr = &port, + .domainptr = &domain, .headersptr = &headers, .residueptr = &residue, .paramsptr = ¶ms, .name = "", .user = "", .pass = "", - .host = "host", - .port = "", + .domain = "host", .headers = "", .residue = "", .params.transport = "", @@ -1313,16 +1277,22 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) } AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { - name = user = pass = host = port = headers = residue = NULL; + name = user = pass = domain = headers = residue = NULL; params.transport = params.user = params.method = params.ttl = params.maddr = NULL; params.lr = 0; ast_copy_string(uri,testdataptr->uri,sizeof(uri)); - if (parse_name_andor_addr(uri, "sip:,sips:", testdataptr->nameptr, testdataptr->userptr, testdataptr->passptr, testdataptr->hostptr, testdataptr->portptr, testdataptr->paramsptr, testdataptr->headersptr, testdataptr->residueptr) || + if (parse_name_andor_addr(uri, "sip:,sips:", + testdataptr->nameptr, + testdataptr->userptr, + testdataptr->passptr, + testdataptr->domainptr, + testdataptr->paramsptr, + testdataptr->headersptr, + testdataptr->residueptr) || ((testdataptr->nameptr) && strcmp(testdataptr->name, name)) || ((testdataptr->userptr) && strcmp(testdataptr->user, user)) || ((testdataptr->passptr) && strcmp(testdataptr->pass, pass)) || - ((testdataptr->hostptr) && strcmp(testdataptr->host, host)) || - ((testdataptr->portptr) && strcmp(testdataptr->port, port)) || + ((testdataptr->domainptr) && strcmp(testdataptr->domain, domain)) || ((testdataptr->headersptr) && strcmp(testdataptr->headers, headers)) || ((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) || ((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) || @@ -1391,7 +1361,11 @@ int parse_contact_header(char *contactheader, struct contactliststruct *contactl AST_LIST_HEAD_SET_NOLOCK(contactlist, contact); while ((last = get_comma(contactheader,&comma)) != -1) { - res = parse_name_andor_addr(contactheader,"sip:,sips:",&contact->name,&contact->user,&contact->pass,&contact->host,&contact->port,&contact->params,&contact->headers,&residue); + res = parse_name_andor_addr(contactheader, "sip:,sips:", + &contact->name, &contact->user, + &contact->pass, &contact->domain, + &contact->params, &contact->headers, + &residue); if (res == -1) { return res; } @@ -1462,8 +1436,7 @@ AST_TEST_DEFINE(parse_contact_header_test) .name = "name :@;?&,", .user = "user", .pass = "secret", - .host = "host", - .port = "5082", + .domain = "host:5082", .params.transport = "tcp", .params.ttl = "", .params.lr = 0, @@ -1482,8 +1455,7 @@ AST_TEST_DEFINE(parse_contact_header_test) .name = "", .user = ",user1,", .pass = ",secret1,", - .host = "host1", - .port = "", + .domain = "host1", .params.transport = "", .params.ttl = "7", .params.lr = 0, @@ -1495,8 +1467,7 @@ AST_TEST_DEFINE(parse_contact_header_test) .name = "", .user = "", .pass = "", - .host = "host2", - .port = "", + .domain = "host2", .params.transport = "", .params.ttl = "", .params.lr = 0, @@ -1552,8 +1523,7 @@ AST_TEST_DEFINE(parse_contact_header_test) strcmp(tdcontactptr->name, contactptr->name) || strcmp(tdcontactptr->user, contactptr->user) || strcmp(tdcontactptr->pass, contactptr->pass) || - strcmp(tdcontactptr->host, contactptr->host) || - strcmp(tdcontactptr->port, contactptr->port) || + strcmp(tdcontactptr->domain, contactptr->domain) || strcmp(tdcontactptr->headers, contactptr->headers) || strcmp(tdcontactptr->expires, contactptr->expires) || strcmp(tdcontactptr->q, contactptr->q) || diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 0ed59e8f97214a3d982f8cb0cdee5ca89bd23d35..598ce920fd9f25eaf2f06611adcb2bc543f87697 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -665,8 +665,8 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; a. "externip = hostname[:port]" specifies a static address[:port] to ; be used in SIP and SDP messages. ; The hostname is looked up only once, when [re]loading sip.conf . -; If a port number is not present, use the "bindport" value (which is -; not guaranteed to work correctly, because a NAT box might remap the +; If a port number is not present, use the port specified in the "udpbindaddr" +; (which is not guaranteed to work correctly, because a NAT box might remap the ; port number as well as the address). ; This approach can be useful if you have a NAT device where you can ; configure the mapping statically. Examples: diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h index c8916a68ae4c061fe02da8585da4ee0eeafb5d70..2c4f6205189ee296a401cd25b3f9957155a51e86 100644 --- a/include/asterisk/acl.h +++ b/include/asterisk/acl.h @@ -29,6 +29,7 @@ extern "C" { #endif #include "asterisk/network.h" +#include "asterisk/netsock2.h" #include "asterisk/io.h" #define AST_SENSE_DENY 0 @@ -124,12 +125,12 @@ int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin); * of getting an entire hostent structure, you instead are given * only the IP address inserted into a sockaddr_in structure. * - * \param[out] sin The IP address is written into sin->sin_addr + * \param[out] addr The IP address is written into sin->sin_addr * \param value The hostname to look up * \retval 0 Success * \retval -1 Failure */ -int ast_get_ip(struct sockaddr_in *sin, const char *value); +int ast_get_ip(struct ast_sockaddr *addr, const char *value); /*! * \brief Get the IP address given a hostname and optional service @@ -141,14 +142,17 @@ int ast_get_ip(struct sockaddr_in *sin, const char *value); * an SRV lookup will be done for "_sip._udp.example.com". If service is NULL, * then this function acts exactly like a call to ast_get_ip. * - * \param[out] sin The IP address is written into sin->sin_addr + * \param addr The IP address found. The address family is used as an input parameter to + * filter the returned adresses. if it is 0, both IPv4 and IPv6 addresses + * can be returned. + * * \param value The hostname to look up * \param service A specific service provided by the host. A NULL service results * in an A-record lookup instead of an SRV lookup * \retval 0 Success * \retval -1 Failure */ -int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service); +int ast_get_ip_or_srv(struct ast_sockaddr *addr, const char *value, const char *service); /*! * \brief Get our local IP address when contacting a remote host @@ -164,7 +168,7 @@ int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *se * \retval -1 Failure * \retval 0 Success */ -int ast_ouraddrfor(struct in_addr *them, struct in_addr *us); +int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us); /*! * \brief Find an IP address associated with a specific interface @@ -219,7 +223,7 @@ struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original); * \retval 0 Success * \retval -1 Failure */ -int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr); +int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindaddr); /*! * \brief Convert a string to the appropriate COS value diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 47de725739acc59abc046636d098e75cf825da73..fdaeb0e3e766d45286039c37fd52829d55e51085 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -592,6 +592,14 @@ enum ast_parse_flags { PARSE_INT16 = 0x0004, PARSE_UINT16 = 0x0005, #endif + + /* Returns a struct ast_sockaddr, with optional default value + * (passed by reference) and port handling (accept, ignore, + * require, forbid). The format is 'ipaddress[:port]'. IPv6 address + * literals need square brackets around them if a port is specified. + */ + PARSE_ADDR = 0x000e, + /* Returns a struct sockaddr_in, with optional default value * (passed by reference) and port handling (accept, ignore, * require, forbid). The format is 'host.name[:port]' @@ -614,7 +622,7 @@ enum ast_parse_flags { PARSE_IN_RANGE = 0x0020, /* accept values inside a range */ PARSE_OUT_RANGE = 0x0040, /* accept values outside a range */ - /* Port handling, for sockaddr_in. accept/ignore/require/forbid + /* Port handling, for ast_sockaddr. accept/ignore/require/forbid * port number after the hostname or address. */ PARSE_PORT_MASK = 0x0300, /* 0x000: accept port if present */ diff --git a/include/asterisk/dnsmgr.h b/include/asterisk/dnsmgr.h index bf960536d0fe60d24f8e32e578628a9a7089f063..2c96d8e409b149db03e0471d30df25aa32e3002d 100644 --- a/include/asterisk/dnsmgr.h +++ b/include/asterisk/dnsmgr.h @@ -27,7 +27,7 @@ extern "C" { #endif -#include "asterisk/network.h" +#include "asterisk/netsock2.h" #include "asterisk/srv.h" /*! @@ -51,8 +51,9 @@ struct ast_dnsmgr_entry; * * \return a DNS manager entry * \version 1.6.1 result changed from struct in_addr to struct sockaddr_in to store port number + * \version 1.8.0 result changed from struct ast_sockaddr_in to ast_sockaddr for IPv6 support */ -struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service); +struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct ast_sockaddr *result, const char *service); /*! * \brief Free a DNS manager entry @@ -67,7 +68,8 @@ void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry); * \brief Allocate and initialize a DNS manager entry * * \param name the hostname - * \param result where to store the IP address as the DNS manager refreshes it + * \param result where to store the IP address as the DNS manager refreshes it. The address family + * is used as an input parameter to filter the returned adresses. if it is 0, both IPv4 * and IPv6 addresses can be returned. * \param dnsmgr Where to store the allocate DNS manager entry * \param service * @@ -79,7 +81,7 @@ void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry); * \retval non-zero failure * \version 1.6.1 result changed from struct in_addr to struct aockaddr_in to store port number */ -int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service); +int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service); /*! * \brief Force a refresh of a dnsmgr entry diff --git a/include/asterisk/netsock2.h b/include/asterisk/netsock2.h new file mode 100644 index 0000000000000000000000000000000000000000..dd4fba97eea2a0fa60e45f2323abe003bac0a840 --- /dev/null +++ b/include/asterisk/netsock2.h @@ -0,0 +1,523 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Viagénie <asteriskv6@viagenie.ca> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * \brief Network socket handling + */ + +#ifndef _ASTERISK_NETSOCK2_H +#define _ASTERISK_NETSOCK2_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include <sys/socket.h> + +#include <netinet/in.h> + +/*! + * Values for address families that we support. This is reproduced from socket.h + * because we do not want users to include that file. Only netsock2.c should + * ever include socket.h. + */ +enum { + AST_AF_UNSPEC = 0, + AST_AF_INET = 2, + AST_AF_INET6 = 10, +}; + +/*! + * Socket address structure. The first member is big enough to contain addresses + * of any family. The second member contains the length (in bytes) used in the + * first member. + * + * Some BSDs have the length embedded in sockaddr structs. We ignore them. + * (This is the right thing to do.) + */ +struct ast_sockaddr { + struct sockaddr_storage ss; + socklen_t len; +}; + +/*! + * \since 1.8 + * + * \brief + * Checks if the ast_sockaddr is null. "null" in this sense essentially + * means uninitialized, or having a 0 length. + * + * \param addr Pointer to the ast_sockaddr we wish to check + * \retval 1 \a addr is null + * \retval 0 \a addr is non-null. + */ +static inline int ast_sockaddr_isnull(const struct ast_sockaddr *addr) +{ + return addr->len == 0; +} + +/*! + * \since 1.8 + * + * \brief + * Sets address \a addr to null. + * + * \retval void + */ +static inline void ast_sockaddr_setnull(struct ast_sockaddr *addr) +{ + addr->len = 0; +} + +/*! + * \since 1.8 + * + * \brief + * Copies the data from one ast_sockaddr to another + * + * \param dst The destination ast_sockaddr + * \param src The source ast_sockaddr + * \retval void + */ +static inline void ast_sockaddr_copy(struct ast_sockaddr *dst, + const struct ast_sockaddr *src) +{ + memcpy(dst, src, src->len); + dst->len = src->len; +}; + +/*! + * \since 1.8 + * + * \brief + * Compares two ast_sockaddr structures + * + * \retval -1 \a a is lexicographically smaller than \a b + * \retval 0 \a a is equal to \a b + * \retval 1 \a b is lexicographically smaller than \a a + */ +int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b); + +/*! + * \since 1.8 + * + * \brief + * Compares the addresses of two ast_sockaddr structures. + * + * \retval -1 \a a is lexicographically smaller than \a b + * \retval 0 \a a is equal to \a b + * \retval 1 \a b is lexicographically smaller than \a a + */ +int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b); + +#define AST_SOCKADDR_STR_ADDR (1 << 0) +#define AST_SOCKADDR_STR_PORT (1 << 1) +#define AST_SOCKADDR_STR_BRACKETS (1 << 2) +#define AST_SOCKADDR_STR_HOST AST_SOCKADDR_STR_ADDR | AST_SOCKADDR_STR_BRACKETS +#define AST_SOCKADDR_STR_DEFAULT AST_SOCKADDR_STR_ADDR | AST_SOCKADDR_STR_PORT + +/*! + * \since 1.8 + * + * \brief + * Convert a socket address to a string. + * + * \details + * This will be of the form a.b.c.d:xyz + * for IPv4 and [a:b:c:...:d]:xyz for IPv6. + * + * This function is thread-safe. The returned string is on static + * thread-specific storage. + * + * \param addr The input to be stringified + * \param format one of the following: + * AST_SOCKADDR_STR_DEFAULT: + * a.b.c.d:xyz for IPv4 + * [a:b:c:...:d]:xyz for IPv6. + * AST_SOCKADDR_STR_ADDR: address only + * a.b.c.d for IPv4 + * a:b:c:...:d for IPv6. + * AST_SOCKADDR_STR_HOST: address only, suitable for a URL + * a.b.c.d for IPv4 + * [a:b:c:...:d] for IPv6. + * AST_SOCKADDR_STR_PORT: port only + * \retval "(null)" \a addr is null + * \retval "" An error occurred during processing + * \retval string The stringified form of the address + */ +char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *addr, int format); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around ast_sockaddr_stringify_fmt() with default format + * + * \return same as ast_sockaddr_stringify_fmt() + */ +static inline char *ast_sockaddr_stringify(const struct ast_sockaddr *addr) +{ + return ast_sockaddr_stringify_fmt(addr, AST_SOCKADDR_STR_DEFAULT); +} + +/*! + * \since 1.8 + * + * \brief + * Wrapper around ast_sockaddr_stringify_fmt() to return an address only + * + * \return same as ast_sockaddr_stringify_fmt() + */ +static inline char *ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr) +{ + return ast_sockaddr_stringify_fmt(addr, AST_SOCKADDR_STR_ADDR); +} + +/*! + * \since 1.8 + * + * \brief + * Wrapper around ast_sockaddr_stringify_fmt() to return an address only, + * suitable for a URL (with brackets for IPv6). + * + * \return same as ast_sockaddr_stringify_fmt() + */ +static inline char *ast_sockaddr_stringify_host(const struct ast_sockaddr *addr) +{ + return ast_sockaddr_stringify_fmt(addr, AST_SOCKADDR_STR_HOST); +} + +/*! + * \since 1.8 + * + * \brief + * Wrapper around ast_sockaddr_stringify_fmt() to return a port only + * + * \return same as ast_sockaddr_stringify_fmt() + */ +static inline char *ast_sockaddr_stringify_port(const struct ast_sockaddr *addr) +{ + return ast_sockaddr_stringify_fmt(addr, AST_SOCKADDR_STR_PORT); +} + +/*! + * \since 1.8 + * + * \brief + * Parse an IPv4 or IPv6 address string. + * + * \details + * Parses a string containing an IPv4 or IPv6 address followed by an optional + * port (separated by a colon) into a struct ast_sockaddr. The allowed formats + * are the following: + * + * a.b.c.d + * a.b.c.d:port + * a:b:c:...:d + * [a:b:c:...:d] + * [a:b:c:...:d]:port + * + * Host names are NOT allowed. + * + * \param[out] addr The resulting ast_sockaddr + * \param str The string to parse + * \param flags If set to zero, a port MAY be present. If set to + * PARSE_PORT_IGNORE, a port MAY be present but will be ignored. If set to + * PARSE_PORT_REQUIRE, a port MUST be present. If set to PARSE_PORT_FORBID, a + * port MUST NOT be present. + * + * \retval 1 Success + * \retval 0 Failure + */ +int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags); + +/*! + * \since 1.8 + * + * \brief + * Parses a string with an IPv4 or IPv6 address and place results into an array + * + * \details + * Parses a string containing a host name or an IPv4 or IPv6 address followed + * by an optional port (separated by a colon). The result is returned into a + * array of struct ast_sockaddr. Allowed formats for str are the following: + * + * hostname:port + * host.example.com:port + * a.b.c.d + * a.b.c.d:port + * a:b:c:...:d + * [a:b:c:...:d] + * [a:b:c:...:d]:port + * + * \param[out] addrs The resulting array of ast_sockaddrs + * \param str The string to parse + * \param flags If set to zero, a port MAY be present. If set to + * PARSE_PORT_IGNORE, a port MAY be present but will be ignored. If set to + * PARSE_PORT_REQUIRE, a port MUST be present. If set to PARSE_PORT_FORBID, a + * port MUST NOT be present. + * + * \param family Only addresses of the given family will be returned. Use 0 or + * AST_SOCKADDR_UNSPEC to get addresses of all families. + * + * \retval 0 Failure + * \retval non-zero The number of elements in addrs array. + */ +int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, + int flags, int family); + +/*! + * \since 1.8 + * + * \brief + * Get the port number of a socket address. + * + * \warning Do not use this function unless you really know what you are doing. + * And "I want the port number" is not knowing what you are doing. + * + * \retval 0 Address is null + * \retval non-zero The port number of the ast_sockaddr + */ +uint16_t ast_sockaddr_port(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Sets the port number of a socket address. + * + * \warning Do not use this function unless you really know what you are doing. + * And "I want the port number" is not knowing what you are doing. + * + * \param addr Address on which to set the port + * \param port The port you wish to set the address to use + * \retval void + */ +void ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port); + +/*! + * \since 1.8 + * + * \brief + * Get an IPv4 address of an ast_sockaddr + * + * \warning You should rarely need this function. Only use if you know what + * you're doing. + * \return IPv4 address in network byte order + */ +uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Determine if the address is an IPv4 address + * + * \warning You should rarely need this function. Only use if you know what + * you're doing. + * \retval 1 This is an IPv4 address + * \retval 0 This is an IPv6 or IPv4-mapped IPv6 address + */ +int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Determine if this is an IPv4-mapped IPv6 address + * + * \warning You should rarely need this function. Only use if you know what + * you're doing. + * + * \retval 1 This is an IPv4-mapped IPv6 address. + * \retval 0 This is not an IPv4-mapped IPv6 address. + */ +int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Determine if this is an IPv6 address + * + * \warning You should rarely need this function. Only use if you know what + * you're doing. + * + * \retval 1 This is an IPv6 or IPv4-mapped IPv6 address. + * \retval 0 This is an IPv4 address. + */ +int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Determine if the address type is unspecified, or "any" address. + * + * \details + * For IPv4, this would be the address 0.0.0.0, and for IPv6, + * this would be the address ::. The port number is ignored. + * + * \retval 1 This is an "any" address + * \retval 0 This is not an "any" address + */ +int ast_sockaddr_is_any(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Computes a hash value from the address. The port is ignored. + * + * \retval 0 Unknown address family + * \retval other A 32-bit hash derived from the address + */ +int ast_sockaddr_hash(const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around accept(2) that uses struct ast_sockaddr. + * + * \details + * For parameter and return information, see the man page for + * accept(2). + */ +int ast_accept(int sockfd, struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around bind(2) that uses struct ast_sockaddr. + * + * \details + * For parameter and return information, see the man page for + * bind(2). + */ +int ast_bind(int sockfd, const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around connect(2) that uses struct ast_sockaddr. + * + * \details + * For parameter and return information, see the man page for + * connect(2). + */ +int ast_connect(int sockfd, const struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around getsockname(2) that uses struct ast_sockaddr. + * + * \details + * For parameter and return information, see the man page for + * getsockname(2). + */ +int ast_getsockname(int sockfd, struct ast_sockaddr *addr); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around recvfrom(2) that uses struct ast_sockaddr. + * + * \details + * For parameter and return information, see the man page for + * recvfrom(2). + */ +ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags, + struct ast_sockaddr *src_addr); + +/*! + * \since 1.8 + * + * \brief + * Wrapper around sendto(2) that uses ast_sockaddr. + * + * \details + * For parameter and + * return information, see the man page for sendto(2) + */ +ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags, + const struct ast_sockaddr *dest_addr); + +/*! + * \since 1.8 + * + * \brief + * Set type of service + * + * \details + * Set ToS ("Type of Service for IPv4 and "Traffic Class for IPv6) and + * CoS (Linux's SO_PRIORITY) + * + * \param sockfd File descriptor for socket on which to set the parameters + * \param tos The type of service for the socket + * \param cos The cost of service for the socket + * \param desc A text description of the socket in question. + * \retval 0 Success + * \retval -1 Error, with errno set to an appropriate value + */ +int ast_set_qos(int sockfd, int tos, int cos, const char *desc); + +/*! + * These are backward compatibility functions that may be used by subsystems + * that have not yet been converted to IPv6. They will be removed when all + * subsystems are IPv6-ready. + */ +/*@{*/ + +/*! + * \since 1.8 + * + * \brief + * Converts a struct ast_sockaddr to a struct sockaddr_in. + * + * \param addr The ast_sockaddr to convert + * \param[out] sin The resulting sockaddr_in struct + * \retval nonzero Success + * \retval zero Failure + */ +int ast_sockaddr_to_sin(const struct ast_sockaddr *addr, + struct sockaddr_in *sin); + +/*! + * \since 1.8 + * + * \brief + * Converts a struct sockaddr_in to a struct ast_sockaddr. + * + * \param sin The sockaddr_in to convert + * \return an ast_sockaddr structure + */ +void ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin); + +/*@}*/ + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* _ASTERISK_NETSOCK2_H */ diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index cccf06a9628e7e936b4b90caa255ec6f7674af19..0a2fe772608831c9a3c7199cbdb5bbe46a7eff33 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -71,7 +71,7 @@ extern "C" { #include "asterisk/astobj2.h" #include "asterisk/frame.h" -#include "asterisk/netsock.h" +#include "asterisk/netsock2.h" #include "asterisk/sched.h" #include "asterisk/res_srtp.h" @@ -313,7 +313,7 @@ struct ast_rtp_engine { /*! Module this RTP engine came from, used for reference counting */ struct ast_module *mod; /*! Callback for setting up a new RTP instance */ - int (*new)(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data); + int (*new)(struct ast_rtp_instance *instance, struct sched_context *sched, struct ast_sockaddr *sa, void *data); /*! Callback for destroying an RTP instance */ int (*destroy)(struct ast_rtp_instance *instance); /*! Callback for writing out a frame */ @@ -339,9 +339,9 @@ struct ast_rtp_engine { /*! Callback for setting packetization preferences */ void (*packetization_set)(struct ast_rtp_instance *instance, struct ast_codec_pref *pref); /*! Callback for setting the remote address that RTP is to be sent to */ - void (*remote_address_set)(struct ast_rtp_instance *instance, struct sockaddr_in *sin); + void (*remote_address_set)(struct ast_rtp_instance *instance, struct ast_sockaddr *sa); /*! Callback for setting an alternate remote address */ - void (*alt_remote_address_set)(struct ast_rtp_instance *instance, struct sockaddr_in *sin); + void (*alt_remote_address_set)(struct ast_rtp_instance *instance, struct ast_sockaddr *sa); /*! Callback for changing DTMF mode */ int (*dtmf_mode_set)(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode); /*! Callback for retrieving statistics */ @@ -369,7 +369,7 @@ struct ast_rtp_engine { /*! Callback to indicate that packets will now flow */ int (*activate)(struct ast_rtp_instance *instance); /*! Callback to request that the RTP engine send a STUN BIND request */ - void (*stun_request)(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username); + void (*stun_request)(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username); /*! Callback to get the transcodeable formats supported */ int (*available_formats)(struct ast_rtp_instance *instance, format_t to_endpoint, format_t to_asterisk); /*! Linked list information */ @@ -519,7 +519,7 @@ int ast_rtp_glue_unregister(struct ast_rtp_glue *glue); * * \param engine_name Name of the engine to use for the RTP instance * \param sched Scheduler context that the RTP engine may want to use - * \param sin Address we want to bind to + * \param sa Address we want to bind to * \param data Unique data for the engine * * \retval non-NULL success @@ -533,14 +533,16 @@ int ast_rtp_glue_unregister(struct ast_rtp_glue *glue); * \endcode * * This creates a new RTP instance using the default engine and asks the RTP engine to bind to the address given - * in the sin structure. + * in the address structure. * * \note The RTP engine does not have to use the address provided when creating an RTP instance. It may choose to use * another depending on it's own configuration. * * \since 1.8 */ -struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, struct sockaddr_in *sin, void *data); +struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, + struct sched_context *sched, const struct ast_sockaddr *sa, + void *data); /*! * \brief Destroy an RTP instance @@ -663,7 +665,8 @@ struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int r * * \since 1.8 */ -int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address); +int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address); + /*! * \brief Set the address of an an alternate RTP address to receive from @@ -677,7 +680,7 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struc * Example usage: * * \code - * ast_rtp_instance_set_alt_remote_address(instance, &sin); + * ast_rtp_instance_set_alt_remote_address(instance, &address); * \endcode * * This changes the alternate remote address that RTP will be sent to on instance to the address given in the sin @@ -685,7 +688,7 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struc * * \since 1.8 */ -int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address); +int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address); /*! * \brief Set the address that we are expecting to receive RTP on @@ -707,7 +710,8 @@ int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, s * * \since 1.8 */ -int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address); +int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address); /*! * \brief Get the local address that we are expecting RTP on @@ -721,15 +725,15 @@ int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, struct * Example usage: * * \code - * struct sockaddr_in sin; - * ast_rtp_instance_get_local_address(instance, &sin); + * struct ast_sockaddr address; + * ast_rtp_instance_get_local_address(instance, &address); * \endcode * - * This gets the local address that we are expecting RTP on and stores it in the 'sin' structure. + * This gets the local address that we are expecting RTP on and stores it in the 'address' structure. * * \since 1.8 */ -int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address); +int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address); /*! * \brief Get the address of the remote endpoint that we are sending RTP to @@ -743,16 +747,16 @@ int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct * Example usage: * * \code - * struct sockaddr_in sin; - * ast_rtp_instance_get_remote_address(instance, &sin); + * struct ast_sockaddr address; + * ast_rtp_instance_get_remote_address(instance, &address); * \endcode * * This retrieves the current remote address set on the instance pointed to by instance and puts the value - * into the sin structure. + * into the address structure. * * \since 1.8 */ -int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address); +int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address); /*! * \brief Set the value of an RTP instance extended property @@ -1598,7 +1602,7 @@ int ast_rtp_instance_activate(struct ast_rtp_instance *instance); * * \since 1.8 */ -void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username); +void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username); /*! * \brief Set the RTP timeout value diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h index ad0438583479cd2f83b1801050266fbfc8f38fda..2cc2c0fa3e912ed37a6b389c5305171401560eee 100644 --- a/include/asterisk/tcptls.h +++ b/include/asterisk/tcptls.h @@ -48,6 +48,7 @@ #ifndef _ASTERISK_TCPTLS_H #define _ASTERISK_TCPTLS_H +#include "asterisk/netsock2.h" #include "asterisk/utils.h" #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE)) @@ -120,9 +121,9 @@ struct ast_tls_config { * arguments for the accepting thread */ struct ast_tcptls_session_args { - struct sockaddr_in local_address; - struct sockaddr_in old_address; /*!< copy of the local or remote address depending on if its a client or server session */ - struct sockaddr_in remote_address; + struct ast_sockaddr local_address; + struct ast_sockaddr old_address; /*!< copy of the local or remote address depending on if its a client or server session */ + struct ast_sockaddr remote_address; char hostname[MAXHOSTNAMELEN]; /*!< only necessary for SSL clients so we can compare to common name */ struct ast_tls_config *tls_cfg; /*!< points to the SSL configuration if any */ int accept_fd; @@ -143,7 +144,7 @@ struct ast_tcptls_session_instance { SSL *ssl; /* ssl state */ /* iint (*ssl_setup)(SSL *); */ int client; - struct sockaddr_in remote_address; + struct ast_sockaddr remote_address; struct ast_tcptls_session_args *parent; ast_mutex_t lock; }; diff --git a/main/acl.c b/main/acl.c index caa1d56f0268b577583338358d1ae0ef849d17ab..082048a16506b7e3600de6425e7f20aa50c29a52 100644 --- a/main/acl.c +++ b/main/acl.c @@ -48,7 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/srv.h" #if (!defined(SOLARIS) && !defined(HAVE_GETIFADDRS)) -static int get_local_address(struct in_addr *ourip) +static int get_local_address(struct ast_sockaddr *ourip) { return -1; } @@ -112,7 +112,7 @@ static void score_address(const struct sockaddr_in *sin, struct in_addr *best_ad } } -static int get_local_address(struct in_addr *ourip) +static int get_local_address(struct ast_sockaddr *ourip) { int s, res = -1; #ifdef SOLARIS @@ -207,7 +207,9 @@ static int get_local_address(struct in_addr *ourip) #endif /* BSD_OR_LINUX */ if (res == 0 && ourip) { - memcpy(ourip, &best_addr, sizeof(*ourip)); + ast_sockaddr_setnull(ourip); + ourip->ss.ss_family = AF_INET; + ((struct sockaddr_in *)&ourip->ss)->sin_addr = best_addr; } return res; } @@ -372,27 +374,49 @@ int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin) return res; } -int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service) +static int resolve_first(struct ast_sockaddr *addr, const char *name, int flag, + int family) +{ + struct ast_sockaddr *addrs; + int addrs_cnt; + + addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family); + if (addrs_cnt > 0) { + if (addrs_cnt > 1) { + ast_debug(1, "Multiple addresses. Using the first only\n"); + } + ast_sockaddr_copy(addr, &addrs[0]); + ast_free(addrs); + } else { + ast_log(LOG_WARNING, "Unable to lookup '%s'\n", name); + return -1; + } + + return 0; +} + +int ast_get_ip_or_srv(struct ast_sockaddr *addr, const char *value, const char *service) { - struct hostent *hp; - struct ast_hostent ahp; char srv[256]; char host[256]; - int tportno = ntohs(sin->sin_port); + int srv_ret = 0; + int tportno; + if (service) { snprintf(srv, sizeof(srv), "%s.%s", service, value); - if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) { - sin->sin_port = htons(tportno); + if ((srv_ret = ast_get_srv(NULL, host, sizeof(host), &tportno, srv)) > 0) { value = host; } } - if ((hp = ast_gethostbyname(value, &ahp))) { - sin->sin_family = hp->h_addrtype; - memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); - } else { - ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value); + + if (resolve_first(addr, value, PARSE_PORT_FORBID, addr->ss.ss_family) != 0) { return -1; } + + if (srv_ret > 0) { + ast_sockaddr_set_port(addr, tportno); + } + return 0; } @@ -474,51 +498,53 @@ const char *ast_tos2str(unsigned int tos) return "unknown"; } -int ast_get_ip(struct sockaddr_in *sin, const char *value) +int ast_get_ip(struct ast_sockaddr *addr, const char *value) { - return ast_get_ip_or_srv(sin, value, NULL); + return ast_get_ip_or_srv(addr, value, NULL); } -int ast_ouraddrfor(struct in_addr *them, struct in_addr *us) +int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us) { + int port; int s; - struct sockaddr_in sin; - socklen_t slen; - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + port = ast_sockaddr_port(us); + + if ((s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET, + SOCK_DGRAM, 0)) < 0) { ast_log(LOG_ERROR, "Cannot create socket\n"); return -1; } - sin.sin_family = AF_INET; - sin.sin_port = htons(5060); - sin.sin_addr = *them; - if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) { + + if (ast_connect(s, them)) { ast_log(LOG_WARNING, "Cannot connect\n"); close(s); return -1; } - slen = sizeof(sin); - if (getsockname(s, (struct sockaddr *)&sin, &slen)) { + if (ast_getsockname(s, us)) { + ast_log(LOG_WARNING, "Cannot get socket name\n"); close(s); return -1; } close(s); - ast_debug(3, "Found IP address for this socket\n"); - *us = sin.sin_addr; + ast_debug(3, "For destination '%s', our source address is '%s'.\n", + ast_sockaddr_stringify_addr(them), + ast_sockaddr_stringify_addr(us)); + + ast_sockaddr_set_port(us, port); + return 0; } -int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr) +int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindaddr) { char ourhost[MAXHOSTNAMELEN] = ""; - struct ast_hostent ahp; - struct hostent *hp; - struct in_addr saddr; + struct ast_sockaddr root; /* just use the bind address if it is nonzero */ - if (ntohl(bindaddr.sin_addr.s_addr)) { - memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip)); + if (!ast_sockaddr_is_any(bindaddr)) { + ast_sockaddr_copy(ourip, bindaddr); ast_debug(3, "Attached to given IP address\n"); return 0; } @@ -526,15 +552,14 @@ int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr) if (gethostname(ourhost, sizeof(ourhost) - 1)) { ast_log(LOG_WARNING, "Unable to get hostname\n"); } else { - if ((hp = ast_gethostbyname(ourhost, &ahp))) { - memcpy(ourip, hp->h_addr, sizeof(*ourip)); - ast_debug(3, "Found one IP address based on local hostname %s.\n", ourhost); + if (resolve_first(ourip, ourhost, PARSE_PORT_FORBID, 0) == 0) { return 0; } } ast_debug(3, "Trying to check A.ROOT-SERVERS.NET and get our IP address for that connection\n"); /* A.ROOT-SERVERS.NET. */ - if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip)) { + if (!resolve_first(&root, "A.ROOT-SERVERS.NET", PARSE_PORT_FORBID, 0) && + !ast_ouraddrfor(&root, ourip)) { return 0; } return get_local_address(ourip); diff --git a/main/app.c b/main/app.c index a171f26110f358d282b5a4f04258995365d3ffd0..050c4e2389924d533d74298d1557231839da786e 100644 --- a/main/app.c +++ b/main/app.c @@ -1190,7 +1190,7 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch { int argc; char *scan, *wasdelim = NULL; - int paren = 0, quote = 0; + int paren = 0, quote = 0, bracket = 0; if (!array || !arraylen) { return 0; @@ -1213,6 +1213,12 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch if (paren) { paren--; } + } else if (*scan == '[') { + bracket++; + } else if (*scan == ']') { + if (bracket) { + bracket--; + } } else if (*scan == '"' && delim != '"') { quote = quote ? 0 : 1; if (remove_chars) { @@ -1227,7 +1233,7 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch } else { scan++; } - } else if ((*scan == delim) && !paren && !quote) { + } else if ((*scan == delim) && !paren && !quote && !bracket) { wasdelim = scan; *scan++ = '\0'; break; diff --git a/main/config.c b/main/config.c index 9400abd8ce664a620136c959035235c20de18aa7..e1c51dcd645326eae49fec5300b07974be741786 100644 --- a/main/config.c +++ b/main/config.c @@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/astobj2.h" #include "asterisk/strings.h" /* for the ast_str_*() API */ +#include "asterisk/netsock2.h" #define MAX_NESTED_COMMENTS 128 #define COMMENT_START ";--" @@ -2386,7 +2387,20 @@ int ast_parse_arg(const char *arg, enum ast_parse_flags flags, result ? *result : x, error); break; } - case PARSE_INADDR: + case PARSE_ADDR: + { + struct ast_sockaddr *addr = (struct ast_sockaddr *)p_result; + + if (!ast_sockaddr_parse(addr, arg, flags & PARSE_PORT_MASK)) { + error = 1; + } + + ast_debug(3, "extract addr from %s gives %s(%d)\n", + arg, ast_sockaddr_stringify(addr), error); + + break; + } + case PARSE_INADDR: /* TODO Remove this (use PARSE_ADDR instead). */ { char *port, *buf; struct sockaddr_in _sa_buf; /* buffer for the result */ diff --git a/main/dnsmgr.c b/main/dnsmgr.c index ca181e3f2db49e12286a35bf4a620ecbe1de27d3..29ac4e30f9d457f2fd473f2fcdbabcfc1d7272cd 100644 --- a/main/dnsmgr.c +++ b/main/dnsmgr.c @@ -51,7 +51,7 @@ static pthread_t refresh_thread = AST_PTHREADT_NULL; struct ast_dnsmgr_entry { /*! where we will store the resulting IP address and port number */ - struct sockaddr_in *result; + struct ast_sockaddr *result; /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */ char *service; /*! Set to 1 if the entry changes */ @@ -83,7 +83,7 @@ static struct refresh_info master_refresh_info = { .verbose = 0, }; -struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service) +struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct ast_sockaddr *result, const char *service) { struct ast_dnsmgr_entry *entry; int total_size = sizeof(*entry) + strlen(name) + (service ? strlen(service) + 1 : 0); @@ -120,10 +120,7 @@ void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry) ast_free(entry); } -/* - * Allocate a new DNS manager entry and perform the initial lookup before returning - */ -int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service) +int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service) { if (ast_strlen_zero(name) || !result || !dnsmgr) return -1; @@ -131,13 +128,6 @@ int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_d if (*dnsmgr && !strcasecmp((*dnsmgr)->name, name)) return 0; - /* if it's actually an IP address and not a name, - there's no need for a managed lookup */ - if (inet_aton(name, &result->sin_addr)) { - result->sin_family = AF_INET; - return 0; - } - ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name); /* do a lookup now but add a manager so it will automagically get updated in the background */ @@ -157,25 +147,26 @@ int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_d */ static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose) { - char iabuf[INET_ADDRSTRLEN]; - char iabuf2[INET_ADDRSTRLEN]; - struct sockaddr_in tmp; + struct ast_sockaddr tmp; int changed = 0; - + ast_mutex_lock(&entry->lock); if (verbose) ast_verb(3, "refreshing '%s'\n", entry->name); memset(&tmp, 0, sizeof(tmp)); - tmp.sin_port = entry->result->sin_port; - - if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, entry->result)) { - ast_copy_string(iabuf, ast_inet_ntoa(entry->result->sin_addr), sizeof(iabuf)); - ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2)); - ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n", - entry->name, iabuf, ntohs(entry->result->sin_port), iabuf2, ntohs(tmp.sin_port)); - *entry->result = tmp; - changed = entry->changed = 1; + + if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service)) { + if (!ast_sockaddr_port(&tmp)) + ast_sockaddr_set_port(&tmp, ast_sockaddr_port(entry->result)); + if (ast_sockaddr_cmp(&tmp, entry->result)) { + ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s to %s\n", + entry->name, ast_sockaddr_stringify(entry->result), + ast_sockaddr_stringify(&tmp)); + + ast_sockaddr_copy(entry->result, &tmp); + changed = entry->changed = 1; + } } ast_mutex_unlock(&entry->lock); diff --git a/main/http.c b/main/http.c index dcbfc4d665022db3c238d46d77aa60082aeac98a..6390297e5676eaddc2e52143b77a1fe204bd1af8 100644 --- a/main/http.c +++ b/main/http.c @@ -316,12 +316,12 @@ static int httpstatus_callback(struct ast_tcptls_session_instance *ser, ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix); ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n", - ast_inet_ntoa(http_desc.old_address.sin_addr)); - ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n", - ntohs(http_desc.old_address.sin_port)); + ast_sockaddr_stringify_addr(&http_desc.old_address)); + ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n", + ast_sockaddr_stringify_port(&http_desc.old_address)); if (http_tls_cfg.enabled) { - ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n", - ntohs(https_desc.old_address.sin_port)); + ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n", + ast_sockaddr_stringify_port(&https_desc.old_address)); } ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); for (v = get_vars; v; v = v->next) { @@ -989,6 +989,8 @@ static int __ast_http_load(int reload) char newprefix[MAX_PREFIX] = ""; struct http_uri_redirect *redirect; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + struct sockaddr_in tmp = {0,}; + struct sockaddr_in tmp2 = {0,}; cfg = ast_config_load2("http.conf", "http", config_flags); if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { @@ -996,11 +998,13 @@ static int __ast_http_load(int reload) } /* default values */ - memset(&http_desc.local_address, 0, sizeof(http_desc.local_address)); - http_desc.local_address.sin_port = htons(8088); + tmp.sin_family = AF_INET; + tmp.sin_port = htons(8088); + ast_sockaddr_from_sin(&http_desc.local_address, &tmp); - memset(&https_desc.local_address, 0, sizeof(https_desc.local_address)); - https_desc.local_address.sin_port = htons(8089); + tmp2.sin_family = AF_INET; + tmp2.sin_port = htons(8089); + ast_sockaddr_from_sin(&https_desc.local_address, &tmp2); http_tls_cfg.enabled = 0; if (http_tls_cfg.certfile) { @@ -1038,10 +1042,15 @@ static int __ast_http_load(int reload) } else if (!strcasecmp(v->name, "enablestatic")) { newenablestatic = ast_true(v->value); } else if (!strcasecmp(v->name, "bindport")) { - http_desc.local_address.sin_port = htons(atoi(v->value)); + ast_sockaddr_set_port(&http_desc.local_address, + atoi(v->value)); } else if (!strcasecmp(v->name, "bindaddr")) { if ((hp = ast_gethostbyname(v->value, &ahp))) { - memcpy(&http_desc.local_address.sin_addr, hp->h_addr, sizeof(http_desc.local_address.sin_addr)); + ast_sockaddr_to_sin(&http_desc.local_address, + &tmp); + memcpy(&tmp.sin_addr, hp->h_addr, sizeof(tmp.sin_addr)); + ast_sockaddr_from_sin(&http_desc.local_address, + &tmp); } else { ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value); } @@ -1062,11 +1071,15 @@ static int __ast_http_load(int reload) ast_config_destroy(cfg); } /* if the https addres has not been set, default is the same as non secure http */ - if (!https_desc.local_address.sin_addr.s_addr) { - https_desc.local_address.sin_addr = http_desc.local_address.sin_addr; + ast_sockaddr_to_sin(&http_desc.local_address, &tmp); + ast_sockaddr_to_sin(&https_desc.local_address, &tmp2); + if (!tmp2.sin_addr.s_addr) { + tmp2.sin_addr = tmp.sin_addr; + ast_sockaddr_from_sin(&https_desc.local_address, &tmp2); } - if (enabled) { - http_desc.local_address.sin_family = https_desc.local_address.sin_family = AF_INET; + if (!enabled) { + http_desc.local_address.ss.ss_family = 0; + https_desc.local_address.ss.ss_family = 0; } if (strcmp(prefix, newprefix)) { ast_copy_string(prefix, newprefix, sizeof(prefix)); @@ -1084,6 +1097,7 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a { struct ast_http_uri *urih; struct http_uri_redirect *redirect; + struct sockaddr_in tmp; switch (cmd) { case CLI_INIT: @@ -1101,16 +1115,17 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a } ast_cli(a->fd, "HTTP Server Status:\n"); ast_cli(a->fd, "Prefix: %s\n", prefix); - if (!http_desc.old_address.sin_family) { + ast_sockaddr_to_sin(&http_desc.old_address, &tmp); + if (!tmp.sin_family) { ast_cli(a->fd, "Server Disabled\n\n"); } else { ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n", - ast_inet_ntoa(http_desc.old_address.sin_addr), - ntohs(http_desc.old_address.sin_port)); + ast_inet_ntoa(tmp.sin_addr), ntohs(tmp.sin_port)); if (http_tls_cfg.enabled) { + ast_sockaddr_to_sin(&https_desc.old_address, &tmp); ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n", - ast_inet_ntoa(https_desc.old_address.sin_addr), - ntohs(https_desc.old_address.sin_port)); + ast_inet_ntoa(tmp.sin_addr), + ntohs(tmp.sin_port)); } } diff --git a/main/manager.c b/main/manager.c index dffe92a15f985f7e74aac81c3ce01aba70523641..5c8f893af7f742e169e196116b22b87b362b92d8 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1984,7 +1984,8 @@ static enum ast_security_event_transport_type mansession_get_transport(const str static struct sockaddr_in *mansession_encode_sin_local(const struct mansession *s, struct sockaddr_in *sin_local) { - *sin_local = s->tcptls_session->parent->local_address; + ast_sockaddr_to_sin(&s->tcptls_session->parent->local_address, + sin_local); return sin_local; } @@ -4598,14 +4599,18 @@ static int do_message(struct mansession *s) static void *session_do(void *data) { struct ast_tcptls_session_instance *ser = data; - struct mansession_session *session = build_mansession(ser->remote_address); + struct mansession_session *session; struct mansession s = { .tcptls_session = data, }; int flags; int res; + struct sockaddr_in ser_remote_address_tmp; struct protoent *p; + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + session = build_mansession(ser_remote_address_tmp); + if (session == NULL) { goto done; } @@ -4640,7 +4645,7 @@ static void *session_do(void *data) /* these fields duplicate those in the 'ser' structure */ session->fd = s.fd = ser->fd; session->f = s.f = ser->f; - session->sin = ser->remote_address; + session->sin = ser_remote_address_tmp; s.session = session; AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); @@ -5912,17 +5917,35 @@ out_401: static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return generic_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return generic_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return generic_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static struct ast_http_uri rawmanuri = { @@ -5953,17 +5976,35 @@ static struct ast_http_uri managerxmluri = { /* Callback with Digest authentication */ static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return auth_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return auth_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return auth_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static struct ast_http_uri arawmanuri = { @@ -6049,12 +6090,10 @@ static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, stru ast_cli(a->fd, "----------------\n"); ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled)); ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled)); - ast_cli(a->fd, FORMAT, "TCP Bindaddress:", ast_inet_ntoa(ami_desc.local_address.sin_addr)); - ast_cli(a->fd, FORMAT2, "TCP Port:", ntohs(ami_desc.local_address.sin_port)); + ast_cli(a->fd, FORMAT, "TCP Bindaddress:", ast_sockaddr_stringify(&ami_desc.local_address)); ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout); ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled)); - ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ast_inet_ntoa(amis_desc.local_address.sin_addr)); - ast_cli(a->fd, FORMAT2, "TLS Port:", ntohs(amis_desc.local_address.sin_port)); + ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ast_sockaddr_stringify(&amis_desc.local_address)); ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile); ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile); ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher); @@ -6093,6 +6132,8 @@ static int __init_manager(int reload) struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; char a1[256]; char a1_hash[256]; + struct sockaddr_in ami_desc_local_address_tmp = { 0, }; + struct sockaddr_in amis_desc_local_address_tmp = { 0, }; manager_enabled = 0; @@ -6151,10 +6192,8 @@ static int __init_manager(int reload) /* default values */ ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); - memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in)); - memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address)); - amis_desc.local_address.sin_port = htons(5039); - ami_desc.local_address.sin_port = htons(DEFAULT_MANAGER_PORT); + amis_desc_local_address_tmp.sin_port = htons(5039); + ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT); ami_tls_cfg.enabled = 0; if (ami_tls_cfg.certfile) { @@ -6186,11 +6225,12 @@ static int __init_manager(int reload) } else if (!strcasecmp(var->name, "webenabled")) { webmanager_enabled = ast_true(val); } else if (!strcasecmp(var->name, "port")) { - ami_desc.local_address.sin_port = htons(atoi(val)); + ami_desc_local_address_tmp.sin_port = htons(atoi(val)); } else if (!strcasecmp(var->name, "bindaddr")) { - if (!inet_aton(val, &ami_desc.local_address.sin_addr)) { + if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) { ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); - memset(&ami_desc.local_address.sin_addr, 0, sizeof(ami_desc.local_address.sin_addr)); + memset(&ami_desc_local_address_tmp.sin_addr, 0, + sizeof(ami_desc_local_address_tmp.sin_addr)); } } else if (!strcasecmp(var->name, "brokeneventsaction")) { broken_events_action = ast_true(val); @@ -6228,15 +6268,18 @@ static int __init_manager(int reload) } if (manager_enabled) { - ami_desc.local_address.sin_family = AF_INET; + ami_desc_local_address_tmp.sin_family = AF_INET; } /* if the amis address has not been set, default is the same as non secure ami */ - if (!amis_desc.local_address.sin_addr.s_addr) { - amis_desc.local_address.sin_addr = ami_desc.local_address.sin_addr; + if (!amis_desc_local_address_tmp.sin_addr.s_addr) { + amis_desc_local_address_tmp.sin_addr = + ami_desc_local_address_tmp.sin_addr; } if (ami_tls_cfg.enabled) { - amis_desc.local_address.sin_family = AF_INET; + amis_desc_local_address_tmp.sin_family = AF_INET; } + ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp); + ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp); AST_RWLIST_WRLOCK(&users); diff --git a/main/netsock2.c b/main/netsock2.c new file mode 100644 index 0000000000000000000000000000000000000000..4d93a911bdc1de5bcc68e5fa2eb1cb03cb8115d0 --- /dev/null +++ b/main/netsock2.c @@ -0,0 +1,499 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Viagénie <asteriskv6@viagenie.ca> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Network socket handling + * + * \author Viagénie <asteriskv6@viagenie.ca> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/config.h" +#include "asterisk/netsock2.h" +#include "asterisk/utils.h" +#include "asterisk/threadstorage.h" + +static int ast_sockaddr_ipv4_mapped(const struct ast_sockaddr *addr, struct ast_sockaddr *ast_mapped) +{ + const struct sockaddr_in6 *sin6; + struct sockaddr_in sin4; + + if (!ast_sockaddr_is_ipv6(addr)) { + return 0; + } + + if (!ast_sockaddr_is_ipv4_mapped(addr)) { + return 0; + } + + sin6 = (const struct sockaddr_in6*)&addr->ss; + + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; + sin4.sin_port = sin6->sin6_port; + sin4.sin_addr.s_addr = ((uint32_t *)&sin6->sin6_addr)[3]; + + ast_sockaddr_from_sin(ast_mapped, &sin4); + + return 1; +} + + +AST_THREADSTORAGE(ast_sockaddr_stringify_buf); + +char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format) +{ + struct ast_sockaddr sa_ipv4; + const struct ast_sockaddr *sa_tmp; + char host[NI_MAXHOST]; + char port[NI_MAXSERV]; + struct ast_str *str; + int e; + static const size_t size = sizeof(host) - 1 + sizeof(port) - 1 + 4; + + + if (ast_sockaddr_isnull(sa)) { + return "(null)"; + } + + if (!(str = ast_str_thread_get(&ast_sockaddr_stringify_buf, size))) { + return ""; + } + + if (ast_sockaddr_ipv4_mapped(sa, &sa_ipv4)) { + sa_tmp = &sa_ipv4; + } else { + sa_tmp = sa; + } + + if ((e = getnameinfo((struct sockaddr *)&sa_tmp->ss, sa->len, + format & AST_SOCKADDR_STR_ADDR ? host : NULL, + format & AST_SOCKADDR_STR_ADDR ? sizeof(host) : 0, + format & AST_SOCKADDR_STR_PORT ? port : 0, + format & AST_SOCKADDR_STR_PORT ? sizeof(port): 0, + NI_NUMERICHOST | NI_NUMERICSERV))) { + ast_log(LOG_ERROR, "getnameinfo(): %s\n", gai_strerror(e)); + return ""; + } + + switch (format) { + case AST_SOCKADDR_STR_DEFAULT: + ast_str_set(&str, 0, sa_tmp->ss.ss_family == AF_INET6 ? + "[%s]:%s" : "%s:%s", host, port); + break; + case AST_SOCKADDR_STR_ADDR: + ast_str_set(&str, 0, "%s", host); + break; + case AST_SOCKADDR_STR_HOST: + ast_str_set(&str, 0, + sa_tmp->ss.ss_family == AF_INET6 ? "[%s]" : "%s", host); + break; + case AST_SOCKADDR_STR_PORT: + ast_str_set(&str, 0, "%s", port); + break; + default: + ast_log(LOG_ERROR, "Invalid format\n"); + return ""; + } + + return ast_str_buffer(str); +} + +int static _ast_sockaddr_parse(char *str, char **host, char **port, int flags) +{ + char *s = str; + + ast_debug(5, "Splitting '%s' gives...\n", str); + *host = NULL; + *port = NULL; + if (*s == '[') { + *host = ++s; + for (; *s && *s != ']'; ++s) { + } + if (*s == ']') { + *s++ = '\0'; + } + if (*s == ':') { + *port = s + 1; + } + } else { + *host = s; + for (; *s; ++s) { + if (*s == ':') { + if (*port) { + *port = NULL; + break; + } else { + *port = s; + } + } + } + if (*port) { + **port = '\0'; + ++*port; + } + } + ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port); + + switch (flags & PARSE_PORT_MASK) { + case PARSE_PORT_IGNORE: + *port = NULL; + break; + case PARSE_PORT_REQUIRE: + if (*port == NULL) { + ast_log(LOG_WARNING, "missing port\n"); + return 0; + } + break; + case PARSE_PORT_FORBID: + if (*port != NULL) { + ast_log(LOG_WARNING, "port disallowed\n"); + return 0; + } + break; + } + + return 1; +} + + + +int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags) +{ + struct addrinfo hints; + struct addrinfo *res; + char *s; + char *host; + char *port; + int e; + + s = ast_strdupa(str); + if (!_ast_sockaddr_parse(s, &host, &port, flags)) { + return 0; + } + + memset(&hints, 0, sizeof(hints)); + /* Hint to get only one entry from getaddrinfo */ + hints.ai_socktype = SOCK_DGRAM; + + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + if ((e = getaddrinfo(host, port, &hints, &res))) { + ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n", + host, S_OR(port, "(null)"), gai_strerror(e)); + return 0; + } + + /* + * I don't see how this could be possible since we're not resolving host + * names. But let's be careful... + */ + if (res->ai_next != NULL) { + ast_log(LOG_WARNING, "getaddrinfo() returned multiple " + "addresses. Ignoring all but the first.\n"); + } + + addr->len = res->ai_addrlen; + memcpy(&addr->ss, res->ai_addr, addr->len); + + freeaddrinfo(res); + + return 1; +} + +int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, + int flags, int family) +{ + struct addrinfo hints, *res, *ai; + char *s, *host, *port; + int e, i, res_cnt; + + s = ast_strdupa(str); + if (!_ast_sockaddr_parse(s, &host, &port, flags)) { + return 0; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_DGRAM; + + if ((e = getaddrinfo(host, port, &hints, &res))) { + ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n", + host, S_OR(port, "(null)"), gai_strerror(e)); + return 0; + } + + res_cnt = 0; + for (ai = res; ai; ai = ai->ai_next) { + res_cnt++; + } + + if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) { + res_cnt = 0; + goto cleanup; + } + + i = 0; + for (ai = res; ai; ai = ai->ai_next) { + (*addrs)[i].len = ai->ai_addrlen; + memcpy(&(*addrs)[i].ss, ai->ai_addr, ai->ai_addrlen); + ++i; + } + +cleanup: + freeaddrinfo(res); + return res_cnt; +} + +int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b) +{ + const struct ast_sockaddr *a_tmp, *b_tmp; + struct ast_sockaddr ipv4_mapped; + + a_tmp = a; + b_tmp = b; + + if (a_tmp->len != b_tmp->len) { + if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) { + a_tmp = &ipv4_mapped; + } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) { + b_tmp = &ipv4_mapped; + } + } + + if (a_tmp->len < b_tmp->len) { + return -1; + } else if (a_tmp->len > b_tmp->len) { + return 1; + } + + return memcmp(&a_tmp->ss, &b_tmp->ss, a_tmp->len); +} + +int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b) +{ + const struct ast_sockaddr *a_tmp, *b_tmp; + struct ast_sockaddr ipv4_mapped; + const struct in_addr *ip4a, *ip4b; + const struct in6_addr *ip6a, *ip6b; + int ret = -1; + + a_tmp = a; + b_tmp = b; + + if (a_tmp->len != b_tmp->len) { + if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) { + a_tmp = &ipv4_mapped; + } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) { + b_tmp = &ipv4_mapped; + } + } + + if (a->len < b->len) { + ret = -1; + } else if (a->len > b->len) { + ret = 1; + } + + switch (a_tmp->ss.ss_family) { + case AF_INET: + ip4a = &((const struct sockaddr_in*)&a_tmp->ss)->sin_addr; + ip4b = &((const struct sockaddr_in*)&b_tmp->ss)->sin_addr; + ret = memcmp(ip4a, ip4b, sizeof(*ip4a)); + break; + case AF_INET6: + ip6a = &((const struct sockaddr_in6*)&a_tmp->ss)->sin6_addr; + ip6b = &((const struct sockaddr_in6*)&b_tmp->ss)->sin6_addr; + ret = memcmp(ip6a, ip6b, sizeof(*ip6a)); + break; + } + return ret; +} + +uint16_t ast_sockaddr_port(const struct ast_sockaddr *addr) +{ + if (addr->ss.ss_family == AF_INET && + addr->len == sizeof(struct sockaddr_in)) { + return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port); + } else if (addr->ss.ss_family == AF_INET6 && + addr->len == sizeof(struct sockaddr_in6)) { + return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port); + } + ast_log(LOG_ERROR, "Not an IPv4 nor IPv6 address, cannot get port.\n"); + return 0; +} + +void ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port) +{ + if (addr->ss.ss_family == AF_INET && + addr->len == sizeof(struct sockaddr_in)) { + ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port); + } else if (addr->ss.ss_family == AF_INET6 && + addr->len == sizeof(struct sockaddr_in6)) { + ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port); + } else { + ast_log(LOG_ERROR, + "Not an IPv4 nor IPv6 address, cannot set port.\n"); + } +} + +uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr) +{ + const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss; + return ntohl(sin->sin_addr.s_addr); +} + +int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr) +{ + return addr->ss.ss_family == AF_INET && + addr->len == sizeof(struct sockaddr_in); +} + +int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr) +{ + const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss; + return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr); +} + +int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr) +{ + return addr->ss.ss_family == AF_INET6 && + addr->len == sizeof(struct sockaddr_in6); +} + +int ast_sockaddr_is_any(const struct ast_sockaddr *addr) +{ + return (ast_sockaddr_is_ipv4(addr) && + ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr == + INADDR_ANY) || + (ast_sockaddr_is_ipv6(addr) && + IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)); +} + +int ast_sockaddr_hash(const struct ast_sockaddr *addr) +{ + /* + * For IPv4, return the IP address as-is. For IPv6, return the last 32 + * bits. + */ + switch (addr->ss.ss_family) { + case AF_INET: + return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr; + case AF_INET6: + return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3]; + default: + ast_log(LOG_ERROR, "Unknown address family '%d'.\n", + addr->ss.ss_family); + return 0; + } +} + +int ast_accept(int sockfd, struct ast_sockaddr *addr) +{ + addr->len = sizeof(addr->ss); + return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len); +} + +int ast_bind(int sockfd, const struct ast_sockaddr *addr) +{ + return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len); +} + +int ast_connect(int sockfd, const struct ast_sockaddr *addr) +{ + return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len); +} + +int ast_getsockname(int sockfd, struct ast_sockaddr *addr) +{ + addr->len = sizeof(addr->ss); + return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len); +} + +ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags, + struct ast_sockaddr *src_addr) +{ + src_addr->len = sizeof(src_addr->ss); + return recvfrom(sockfd, buf, len, flags, + (struct sockaddr *)&src_addr->ss, &src_addr->len); +} + +ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags, + const struct ast_sockaddr *dest_addr) +{ + return sendto(sockfd, buf, len, flags, + (const struct sockaddr *)&dest_addr->ss, dest_addr->len); +} + +int ast_set_qos(int sockfd, int tos, int cos, const char *desc) +{ + int res; + + if ((res = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) { + ast_log(LOG_WARNING, "Unable to set %s TOS to %d (may be you have no " + "root privileges): %s\n", desc, tos, strerror(errno)); + } else if (tos) { + ast_verb(2, "Using %s TOS bits %d\n", desc, tos); + } + +#ifdef linux + if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) { + ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos, + strerror(errno)); + } else if (cos) { + ast_verb(2, "Using %s CoS mark %d\n", desc, cos); + } +#endif + + return res; +} + +int ast_sockaddr_to_sin(const struct ast_sockaddr *addr, + struct sockaddr_in *sin) +{ + if (ast_sockaddr_isnull(addr)) { + memset(sin, 0, sizeof(*sin)); + return 1; + } + + if (addr->len != sizeof(*sin)) { + ast_log(LOG_ERROR, "Bad address cast to IPv4\n"); + return 0; + } + + if (addr->ss.ss_family != AF_INET) { + ast_log(LOG_DEBUG, "Address family is not AF_INET\n"); + } + + *sin = *(struct sockaddr_in *)&addr->ss; + return 1; +} + +void ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin) +{ + *((struct sockaddr_in *)&addr->ss) = *sin; + + if (addr->ss.ss_family != AF_INET) { + ast_log(LOG_DEBUG, "Address family is not AF_INET\n"); + } + + addr->len = sizeof(*sin); +} diff --git a/main/rtp_engine.c b/main/rtp_engine.c index eeaa008a8b0aac21cfefa6e67fbdb805dae1e9d4..d23056b5f9dd8fac5037d8c3468c6d7076c32698 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/pbx.h" #include "asterisk/translate.h" +#include "asterisk/netsock2.h" struct ast_srtp_res *res_srtp = NULL; struct ast_srtp_policy_res *res_srtp_policy = NULL; @@ -51,11 +52,11 @@ struct ast_rtp_instance { /*! RTP properties that have been set and their value */ int properties[AST_RTP_PROPERTY_MAX]; /*! Address that we are expecting RTP to come in to */ - struct sockaddr_in local_address; + struct ast_sockaddr local_address; /*! Address that we are sending RTP to */ - struct sockaddr_in remote_address; + struct ast_sockaddr remote_address; /*! Alternate address that we are receiving RTP from */ - struct sockaddr_in alt_remote_address; + struct ast_sockaddr alt_remote_address; /*! Instance that we are bridged to if doing remote or local bridging */ struct ast_rtp_instance *bridged; /*! Payload and packetization information */ @@ -294,9 +295,11 @@ int ast_rtp_instance_destroy(struct ast_rtp_instance *instance) return 0; } -struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, struct sockaddr_in *sin, void *data) +struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, + struct sched_context *sched, const struct ast_sockaddr *sa, + void *data) { - struct sockaddr_in address = { 0, }; + struct ast_sockaddr address = {{0,}}; struct ast_rtp_instance *instance = NULL; struct ast_rtp_engine *engine = NULL; @@ -331,11 +334,8 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sc return NULL; } instance->engine = engine; - instance->local_address.sin_family = AF_INET; - instance->local_address.sin_addr = sin->sin_addr; - instance->remote_address.sin_family = AF_INET; - address.sin_family = AF_INET; - address.sin_addr = sin->sin_addr; + ast_sockaddr_copy(&instance->local_address, sa); + ast_sockaddr_copy(&address, sa); ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance); @@ -371,17 +371,17 @@ struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int r return instance->engine->read(instance, rtcp); } -int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { - instance->local_address.sin_addr = address->sin_addr; - instance->local_address.sin_port = address->sin_port; + ast_sockaddr_copy(&instance->local_address, address); return 0; } -int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { - instance->remote_address.sin_addr = address->sin_addr; - instance->remote_address.sin_port = address->sin_port; + ast_sockaddr_copy(&instance->remote_address, address); /* moo */ @@ -392,10 +392,10 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struc return 0; } -int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { - instance->alt_remote_address.sin_addr = address->sin_addr; - instance->alt_remote_address.sin_port = address->sin_port; + ast_sockaddr_copy(&instance->alt_remote_address, address); /* oink */ @@ -406,24 +406,22 @@ int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, s return 0; } -int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, + struct ast_sockaddr *address) { - if ((address->sin_family != AF_INET) || - (address->sin_port != instance->local_address.sin_port) || - (address->sin_addr.s_addr != instance->local_address.sin_addr.s_addr)) { - memcpy(address, &instance->local_address, sizeof(*address)); + if (ast_sockaddr_cmp(address, &instance->local_address) != 0) { + ast_sockaddr_copy(address, &instance->local_address); return 1; } return 0; } -int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, + struct ast_sockaddr *address) { - if ((address->sin_family != AF_INET) || - (address->sin_port != instance->remote_address.sin_port) || - (address->sin_addr.s_addr != instance->remote_address.sin_addr.s_addr)) { - memcpy(address, &instance->remote_address, sizeof(*address)); + if (ast_sockaddr_cmp(address, &instance->remote_address) != 0) { + ast_sockaddr_copy(address, &instance->remote_address); return 1; } @@ -959,8 +957,8 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct enum ast_bridge_result res = AST_BRIDGE_FAILED; struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, }; format_t oldcodec0 = codec0, oldcodec1 = codec1; - struct sockaddr_in ac1 = {0,}, vac1 = {0,}, tac1 = {0,}, ac0 = {0,}, vac0 = {0,}, tac0 = {0,}; - struct sockaddr_in t1 = {0,}, vt1 = {0,}, tt1 = {0,}, t0 = {0,}, vt0 = {0,}, tt0 = {0,}; + struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}}; + struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}}; struct ast_frame *fr = NULL; /* Test the first channel */ @@ -1035,44 +1033,59 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct codec0 = glue0->get_codec(c0); } - if ((inaddrcmp(&t1, &ac1)) || - (vinstance1 && inaddrcmp(&vt1, &vac1)) || - (tinstance1 && inaddrcmp(&tt1, &tac1)) || + if ((ast_sockaddr_cmp(&t1, &ac1)) || + (vinstance1 && ast_sockaddr_cmp(&vt1, &vac1)) || + (tinstance1 && ast_sockaddr_cmp(&tt1, &tac1)) || (codec1 != oldcodec1)) { - ast_debug(1, "Oooh, '%s' changed end address to %s:%d (format %s)\n", - c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), ast_getformatname(codec1)); - ast_debug(1, "Oooh, '%s' changed end vaddress to %s:%d (format %s)\n", - c1->name, ast_inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), ast_getformatname(codec1)); - ast_debug(1, "Oooh, '%s' changed end taddress to %s:%d (format %s)\n", - c1->name, ast_inet_ntoa(tt1.sin_addr), ntohs(tt1.sin_port), ast_getformatname(codec1)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), ast_getformatname(oldcodec1)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), ast_getformatname(oldcodec1)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c1->name, ast_inet_ntoa(tac1.sin_addr), ntohs(tac1.sin_port), ast_getformatname(oldcodec1)); - if (glue0->update_peer(c0, t1.sin_addr.s_addr ? instance1 : NULL, vt1.sin_addr.s_addr ? vinstance1 : NULL, tt1.sin_addr.s_addr ? tinstance1 : NULL, codec1, 0)) { + ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n", + c1->name, ast_sockaddr_stringify(&t1), + ast_getformatname(codec1)); + ast_debug(1, "Oooh, '%s' changed end vaddress to %s (format %s)\n", + c1->name, ast_sockaddr_stringify(&vt1), + ast_getformatname(codec1)); + ast_debug(1, "Oooh, '%s' changed end taddress to %s (format %s)\n", + c1->name, ast_sockaddr_stringify(&tt1), + ast_getformatname(codec1)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c1->name, ast_sockaddr_stringify(&ac1), + ast_getformatname(oldcodec1)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c1->name, ast_sockaddr_stringify(&vac1), + ast_getformatname(oldcodec1)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c1->name, ast_sockaddr_stringify(&tac1), + ast_getformatname(oldcodec1)); + if (glue0->update_peer(c0, + ast_sockaddr_isnull(&t1) ? NULL : instance1, + ast_sockaddr_isnull(&vt1) ? NULL : vinstance1, + ast_sockaddr_isnull(&tt1) ? NULL : tinstance1, + codec1, 0)) { ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name); } - memcpy(&ac1, &t1, sizeof(ac1)); - memcpy(&vac1, &vt1, sizeof(vac1)); - memcpy(&tac1, &tt1, sizeof(tac1)); + ast_sockaddr_copy(&ac1, &t1); + ast_sockaddr_copy(&vac1, &vt1); + ast_sockaddr_copy(&tac1, &tt1); oldcodec1 = codec1; } - if ((inaddrcmp(&t0, &ac0)) || - (vinstance0 && inaddrcmp(&vt0, &vac0)) || - (tinstance0 && inaddrcmp(&tt0, &tac0)) || + if ((ast_sockaddr_cmp(&t0, &ac0)) || + (vinstance0 && ast_sockaddr_cmp(&vt0, &vac0)) || + (tinstance0 && ast_sockaddr_cmp(&tt0, &tac0)) || (codec0 != oldcodec0)) { - ast_debug(1, "Oooh, '%s' changed end address to %s:%d (format %s)\n", - c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), ast_getformatname(codec0)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), ast_getformatname(oldcodec0)); - if (glue1->update_peer(c1, t0.sin_addr.s_addr ? instance0 : NULL, vt0.sin_addr.s_addr ? vinstance0 : NULL, tt0.sin_addr.s_addr ? tinstance0 : NULL, codec0, 0)) { + ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n", + c0->name, ast_sockaddr_stringify(&t0), + ast_getformatname(codec0)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c0->name, ast_sockaddr_stringify(&ac0), + ast_getformatname(oldcodec0)); + if (glue1->update_peer(c1, t0.len ? instance0 : NULL, + vt0.len ? vinstance0 : NULL, + tt0.len ? tinstance0 : NULL, + codec0, 0)) { ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name); } - memcpy(&ac0, &t0, sizeof(ac0)); - memcpy(&vac0, &vt0, sizeof(vac0)); - memcpy(&tac0, &tt0, sizeof(tac0)); + ast_sockaddr_copy(&ac0, &t0); + ast_sockaddr_copy(&vac0, &vt0); + ast_sockaddr_copy(&tac0, &tt0); oldcodec0 = codec0; } @@ -1122,9 +1135,9 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct } /* Update local address information */ ast_rtp_instance_get_remote_address(instance0, &t0); - memcpy(&ac0, &t0, sizeof(ac0)); + ast_sockaddr_copy(&ac0, &t0); ast_rtp_instance_get_remote_address(instance1, &t1); - memcpy(&ac1, &t1, sizeof(ac1)); + ast_sockaddr_copy(&ac1, &t1); /* Update codec information */ if (glue0->get_codec && c0->tech_pvt) { oldcodec0 = codec0 = glue0->get_codec(c0); @@ -1201,6 +1214,7 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as *vinstance0 = NULL, *vinstance1 = NULL, *tinstance0 = NULL, *tinstance1 = NULL; struct ast_rtp_glue *glue0, *glue1; + struct ast_sockaddr addr1, addr2; enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID; enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID; enum ast_bridge_result res = AST_BRIDGE_FAILED; @@ -1249,6 +1263,17 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as goto done; } + + /* If address families differ, force a local bridge */ + ast_rtp_instance_get_remote_address(instance0, &addr1); + ast_rtp_instance_get_remote_address(instance1, &addr2); + + if (addr1.ss.ss_family != addr2.ss.ss_family || + (ast_sockaddr_is_ipv4_mapped(&addr1) != ast_sockaddr_is_ipv4_mapped(&addr2))) { + audio_glue0_res = AST_RTP_GLUE_RESULT_LOCAL; + audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; + } + /* If we need to get DTMF see if we can do it outside of the RTP stream itself */ if ((flags & AST_BRIDGE_DTMF_CHANNEL_0) && instance0->properties[AST_RTP_PROPERTY_DTMF]) { res = AST_BRIDGE_FAILED_NOWARN; @@ -1640,7 +1665,9 @@ int ast_rtp_instance_activate(struct ast_rtp_instance *instance) return instance->engine->activate ? instance->engine->activate(instance) : 0; } -void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username) +void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, + struct ast_sockaddr *suggestion, + const char *username) { if (instance->engine->stun_request) { instance->engine->stun_request(instance, suggestion, username); diff --git a/main/tcptls.c b/main/tcptls.c index 8c95502e7f4b0caf18e50cc3309032ea4a58e5b4..b505f2a019bba340f65c438d7fb889d4d3d60e20 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -235,8 +235,7 @@ void *ast_tcptls_server_root(void *data) { struct ast_tcptls_session_args *desc = data; int fd; - struct sockaddr_in sin; - socklen_t sinlen; + struct ast_sockaddr addr; struct ast_tcptls_session_instance *tcptls_session; pthread_t launched; @@ -248,8 +247,7 @@ void *ast_tcptls_server_root(void *data) i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); if (i <= 0) continue; - sinlen = sizeof(sin); - fd = accept(desc->accept_fd, (struct sockaddr *) &sin, &sinlen); + fd = ast_accept(desc->accept_fd, &addr); if (fd < 0) { if ((errno != EAGAIN) && (errno != EINTR)) ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); @@ -268,7 +266,7 @@ void *ast_tcptls_server_root(void *data) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); tcptls_session->fd = fd; tcptls_session->parent = desc; - memcpy(&tcptls_session->remote_address, &sin, sizeof(tcptls_session->remote_address)); + ast_sockaddr_copy(&tcptls_session->remote_address, &addr); tcptls_session->client = 0; @@ -373,10 +371,10 @@ struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_se goto client_start_error; } - if (connect(desc->accept_fd, (const struct sockaddr *) &desc->remote_address, sizeof(desc->remote_address))) { - ast_log(LOG_ERROR, "Unable to connect %s to %s:%d: %s\n", + if (ast_connect(desc->accept_fd, &desc->remote_address)) { + ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", desc->name, - ast_inet_ntoa(desc->remote_address.sin_addr), ntohs(desc->remote_address.sin_port), + ast_sockaddr_stringify(&desc->remote_address), strerror(errno)); goto client_start_error; } @@ -407,17 +405,18 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s struct ast_tcptls_session_instance *tcptls_session = NULL; /* Do nothing if nothing has changed */ - if (!memcmp(&desc->old_address, &desc->remote_address, sizeof(desc->old_address))) { + if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return NULL; } - desc->old_address = desc->remote_address; + ast_sockaddr_copy(&desc->old_address, &desc->remote_address); if (desc->accept_fd != -1) close(desc->accept_fd); - desc->accept_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? + AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if (desc->accept_fd < 0) { ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); @@ -426,12 +425,12 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s /* if a local address was specified, bind to it so the connection will originate from the desired address */ - if (desc->local_address.sin_family != 0) { + if (!ast_sockaddr_isnull(&desc->local_address)) { setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); - if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) { - ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n", - desc->name, - ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port), + if (ast_bind(desc->accept_fd, &desc->local_address)) { + ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", + desc->name, + ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } @@ -445,7 +444,8 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s tcptls_session->fd = desc->accept_fd; tcptls_session->parent = desc; tcptls_session->parent->worker_fn = NULL; - memcpy(&tcptls_session->remote_address, &desc->remote_address, sizeof(tcptls_session->remote_address)); + ast_sockaddr_copy(&tcptls_session->remote_address, + &desc->remote_address); return tcptls_session; @@ -463,12 +463,12 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) int x = 1; /* Do nothing if nothing has changed */ - if (!memcmp(&desc->old_address, &desc->local_address, sizeof(desc->old_address))) { + if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return; } - desc->old_address = desc->local_address; + ast_sockaddr_copy(&desc->old_address, &desc->local_address); /* Shutdown a running server if there is one */ if (desc->master != AST_PTHREADT_NULL) { @@ -481,22 +481,23 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) close(desc->accept_fd); /* If there's no new server, stop here */ - if (desc->local_address.sin_family == 0) { + if (ast_sockaddr_isnull(&desc->local_address)) { ast_debug(2, "Server disabled: %s\n", desc->name); return; } - desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0); + desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? + AF_INET6 : AF_INET, SOCK_STREAM, 0); if (desc->accept_fd < 0) { ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); return; } setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); - if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) { - ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n", + if (ast_bind(desc->accept_fd, &desc->local_address)) { + ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", desc->name, - ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port), + ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } @@ -507,9 +508,9 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) flags = fcntl(desc->accept_fd, F_GETFL); fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { - ast_log(LOG_ERROR, "Unable to launch thread for %s on %s:%d: %s\n", + ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", desc->name, - ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port), + ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } @@ -537,7 +538,6 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_ { if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { tls_cfg->enabled = ast_true(value) ? 1 : 0; - tls_desc->local_address.sin_family = AF_INET; } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { ast_free(tls_cfg->certfile); tls_cfg->certfile = ast_strdup(value); @@ -558,10 +558,8 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_ } else if (!strcasecmp(varname, "tlsdontverifyserver")) { ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { - if (ast_parse_arg(value, PARSE_INADDR, &tls_desc->local_address)) + if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); - } else if (!strcasecmp(varname, "tlsbindport") || !strcasecmp(varname, "sslbindport")) { - tls_desc->local_address.sin_port = htons(atoi(value)); } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { if (!strcasecmp(value, "tlsv1")) { ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index b896d64fa786e308413ae72f74ed2ade7b479711..4ab06e4fbabe50b3d7106cd6fa273ebf8d28a6c3 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -35,7 +35,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <sys/time.h> #include <signal.h> #include <fcntl.h> -#include <math.h> #include "asterisk/stun.h" #include "asterisk/pbx.h" @@ -45,7 +44,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/config.h" #include "asterisk/lock.h" #include "asterisk/utils.h" -#include "asterisk/netsock.h" #include "asterisk/cli.h" #include "asterisk/manager.h" #include "asterisk/unaligned.h" @@ -87,8 +85,8 @@ static int rtpdebug; /*!< Are we debugging? */ static int rtcpdebug; /*!< Are we debugging RTCP? */ static int rtcpstats; /*!< Are we debugging RTCP? */ static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */ -static struct sockaddr_in rtpdebugaddr; /*!< Debug packets to/from this host */ -static struct sockaddr_in rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */ +static struct ast_sockaddr rtpdebugaddr; /*!< Debug packets to/from this host */ +static struct ast_sockaddr rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */ #ifdef SO_NO_CHECK static int nochecksums; #endif @@ -168,8 +166,8 @@ struct ast_rtp { struct ast_rtp *bridged; /*!< Who we are Packet bridged to */ enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */ - struct sockaddr_in strict_rtp_address; /*!< Remote address information for strict RTP purposes */ - struct sockaddr_in alt_rtp_address; /*!<Alternate remote address information */ + struct ast_sockaddr strict_rtp_address; /*!< Remote address information for strict RTP purposes */ + struct ast_sockaddr alt_rtp_address; /*!<Alternate remote address information */ struct rtp_red *red; }; @@ -187,8 +185,8 @@ struct ast_rtp { struct ast_rtcp { int rtcp_info; int s; /*!< Socket */ - struct sockaddr_in us; /*!< Socket representation of the local endpoint. */ - struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */ + struct ast_sockaddr us; /*!< Socket representation of the local endpoint. */ + struct ast_sockaddr them; /*!< Socket representation of the remote endpoint. */ unsigned int soc; /*!< What they told us */ unsigned int spc; /*!< What they told us */ unsigned int themrxlsr; /*!< The middle 32 bits of the NTP timestamp in the last received SR*/ @@ -253,7 +251,7 @@ struct rtp_red { AST_LIST_HEAD_NOLOCK(frame_list, ast_frame); /* Forward Declarations */ -static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data); +static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct ast_sockaddr *addr, void *data); static int ast_rtp_destroy(struct ast_rtp_instance *instance); static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit); static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit); @@ -263,14 +261,14 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp); static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value); static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp); -static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin); -static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin); +static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr); +static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr); static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations); static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame); static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1); static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat); static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1); -static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username); +static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username); static void ast_rtp_stop(struct ast_rtp_instance *instance); /* RTP Engine Declaration */ @@ -297,45 +295,31 @@ static struct ast_rtp_engine asterisk_rtp_engine = { .stop = ast_rtp_stop, }; -static inline int rtp_debug_test_addr(struct sockaddr_in *addr) +static inline int rtp_debug_test_addr(struct ast_sockaddr *addr) { if (!rtpdebug) { return 0; } - if (rtpdebugaddr.sin_addr.s_addr) { - if (((ntohs(rtpdebugaddr.sin_port) != 0) - && (rtpdebugaddr.sin_port != addr->sin_port)) - || (rtpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr)) - return 0; - } - - return 1; + return ast_sockaddr_cmp(&rtpdebugaddr, addr) == 0; } -static inline int rtcp_debug_test_addr(struct sockaddr_in *addr) +static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr) { if (!rtcpdebug) { return 0; } - if (rtcpdebugaddr.sin_addr.s_addr) { - if (((ntohs(rtcpdebugaddr.sin_port) != 0) - && (rtcpdebugaddr.sin_port != addr->sin_port)) - || (rtcpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr)) - return 0; - } - - return 1; + return ast_sockaddr_cmp(&rtcpdebugaddr, addr) == 0; } -static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct sockaddr *sa, socklen_t *salen, int rtcp) +static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp) { int len; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance); - if ((len = recvfrom(rtcp ? rtp->rtcp->s : rtp->s, buf, size, flags, sa, salen)) < 0) { + if ((len = ast_recvfrom(rtcp ? rtp->rtcp->s : rtp->s, buf, size, flags, sa)) < 0) { return len; } @@ -346,17 +330,17 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s return len; } -static int rtcp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct sockaddr *sa, socklen_t *salen) +static int rtcp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) { - return __rtp_recvfrom(instance, buf, size, flags, sa, salen, 1); + return __rtp_recvfrom(instance, buf, size, flags, sa, 1); } -static int rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct sockaddr *sa, socklen_t *salen) +static int rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) { - return __rtp_recvfrom(instance, buf, size, flags, sa, salen, 0); + return __rtp_recvfrom(instance, buf, size, flags, sa, 0); } -static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct sockaddr *sa, socklen_t salen, int rtcp) +static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp) { int len = size; void *temp = buf; @@ -367,17 +351,17 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz return -1; } - return sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa, salen); + return ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa); } -static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct sockaddr *sa, socklen_t salen) +static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) { - return __rtp_sendto(instance, buf, size, flags, sa, salen, 1); + return __rtp_sendto(instance, buf, size, flags, sa, 1); } -static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct sockaddr *sa, socklen_t salen) +static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) { - return __rtp_sendto(instance, buf, size, flags, sa, salen, 0); + return __rtp_sendto(instance, buf, size, flags, sa, 0); } static int rtp_get_rate(format_t subclass) @@ -423,9 +407,9 @@ static double stddev_compute(double stddev, double sample, double normdev, doubl #undef SQUARE } -static int create_new_socket(const char *type) +static int create_new_socket(const char *type, int af) { - int sock = socket(AF_INET, SOCK_DGRAM, 0); + int sock = socket(af, SOCK_DGRAM, 0); if (sock < 0) { if (!type) { @@ -445,7 +429,9 @@ static int create_new_socket(const char *type) return sock; } -static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data) +static int ast_rtp_new(struct ast_rtp_instance *instance, + struct sched_context *sched, struct ast_sockaddr *addr, + void *data) { struct ast_rtp *rtp = NULL; int x, startplace; @@ -461,7 +447,10 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context * rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); /* Create a new socket for us to listen on and use */ - if ((rtp->s = create_new_socket("RTP")) < 0) { + if ((rtp->s = + create_new_socket("RTP", + ast_sockaddr_is_ipv4(addr) ? AF_INET : + ast_sockaddr_is_ipv6(addr) ? AF_INET6 : -1)) < 0) { ast_debug(1, "Failed to create a new socket for RTP instance '%p'\n", instance); ast_free(rtp); return -1; @@ -473,11 +462,11 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context * startplace = x; for (;;) { - sin->sin_port = htons(x); + ast_sockaddr_set_port(addr, x); /* Try to bind, this will tell us whether the port is available or not */ - if (!bind(rtp->s, (struct sockaddr *)sin, sizeof(*sin))) { + if (!ast_bind(rtp->s, addr)) { ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance); - ast_rtp_instance_set_local_address(instance, sin); + ast_rtp_instance_set_local_address(instance, addr); break; } @@ -538,7 +527,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; int hdrlen = 12, res = 0, i = 0, payload = 101; char data[256]; unsigned int *rtpheader = (unsigned int*)data; @@ -546,7 +535,7 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) ast_rtp_instance_get_remote_address(instance, &remote_address); /* If we have no remote address information bail out now */ - if (!remote_address.sin_addr.s_addr || !remote_address.sin_port) { + if (ast_sockaddr_isnull(&remote_address)) { return -1; } @@ -581,15 +570,16 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) /* Actually send the packet */ for (i = 0; i < 2; i++) { rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration)); - res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &remote_address, sizeof(remote_address)); + res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, &remote_address); if (res < 0) { - ast_log(LOG_ERROR, "RTP Transmission error to %s:%u: %s\n", - ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno)); + ast_log(LOG_ERROR, "RTP Transmission error to %s: %s\n", + ast_sockaddr_stringify(&remote_address), + strerror(errno)); } if (rtp_debug_test_addr(&remote_address)) { - ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", - ast_inet_ntoa(remote_address.sin_addr), - ntohs(remote_address.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen); + ast_verbose("Sent RTP DTMF packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", + ast_sockaddr_stringify(&remote_address), + payload, rtp->seqno, rtp->lastdigitts, res - hdrlen); } rtp->seqno++; rtp->send_duration += 160; @@ -607,7 +597,7 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; int hdrlen = 12, res = 0; char data[256]; unsigned int *rtpheader = (unsigned int*)data; @@ -615,7 +605,7 @@ static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance) ast_rtp_instance_get_remote_address(instance, &remote_address); /* Make sure we know where the other side is so we can send them the packet */ - if (!remote_address.sin_addr.s_addr || !remote_address.sin_port) { + if (ast_sockaddr_isnull(&remote_address)) { return -1; } @@ -627,17 +617,17 @@ static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance) rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno)); /* Boom, send it on out */ - res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &remote_address, sizeof(remote_address)); + res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, &remote_address); if (res < 0) { - ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n", - ast_inet_ntoa(remote_address.sin_addr), - ntohs(remote_address.sin_port), strerror(errno)); + ast_log(LOG_ERROR, "RTP Transmission error to %s: %s\n", + ast_sockaddr_stringify(&remote_address), + strerror(errno)); } if (rtp_debug_test_addr(&remote_address)) { - ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", - ast_inet_ntoa(remote_address.sin_addr), - ntohs(remote_address.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen); + ast_verbose("Sent RTP DTMF packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", + ast_sockaddr_stringify(&remote_address), + rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen); } /* And now we increment some values for the next time we swing by */ @@ -650,7 +640,7 @@ static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance) static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; int hdrlen = 12, res = 0, i = 0; char data[256]; unsigned int *rtpheader = (unsigned int*)data; @@ -658,7 +648,7 @@ static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit) ast_rtp_instance_get_remote_address(instance, &remote_address); /* Make sure we know where the remote side is so we can send them the packet we construct */ - if (!remote_address.sin_addr.s_addr || !remote_address.sin_port) { + if (ast_sockaddr_isnull(&remote_address)) { return -1; } @@ -690,16 +680,16 @@ static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit) /* Send it 3 times, that's the magical number */ for (i = 0; i < 3; i++) { - res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &remote_address, sizeof(remote_address)); + res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, &remote_address); if (res < 0) { - ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n", - ast_inet_ntoa(remote_address.sin_addr), - ntohs(remote_address.sin_port), strerror(errno)); + ast_log(LOG_ERROR, "RTP Transmission error to %s: %s\n", + ast_sockaddr_stringify(&remote_address), + strerror(errno)); } if (rtp_debug_test_addr(&remote_address)) { - ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", - ast_inet_ntoa(remote_address.sin_addr), - ntohs(remote_address.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen); + ast_verbose("Sent RTP DTMF packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", + ast_sockaddr_stringify(&remote_address), + rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen); } } @@ -785,10 +775,10 @@ static int ast_rtcp_write_rr(struct ast_rtp_instance *instance) double rxlost_current; - if (!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0)) + if (!rtp || !rtp->rtcp) return 0; - if (!rtp->rtcp->them.sin_addr.s_addr) { + if (ast_sockaddr_isnull(&rtp->rtcp->them)) { ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted\n"); AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid); return 0; @@ -841,7 +831,7 @@ static int ast_rtcp_write_rr(struct ast_rtp_instance *instance) rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */ len += 12; - res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them)); + res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them); if (res < 0) { ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno)); @@ -852,13 +842,12 @@ static int ast_rtcp_write_rr(struct ast_rtp_instance *instance) rtp->rtcp->rr_count++; if (rtcp_debug_test_addr(&rtp->rtcp->them)) { - ast_verbose("\n* Sending RTCP RR to %s:%d\n" + ast_verbose("\n* Sending RTCP RR to %s\n" " Our SSRC: %u\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n" " IA jitter: %.4f\n" " Their last SR: %u\n" " DLSR: %4.4f (sec)\n\n", - ast_inet_ntoa(rtp->rtcp->them.sin_addr), - ntohs(rtp->rtcp->them.sin_port), + ast_sockaddr_stringify(&rtp->rtcp->them), rtp->ssrc, rtp->themssrc, fraction, lost, rtp->rxjitter, rtp->rtcp->themrxlsr, @@ -888,11 +877,10 @@ static int ast_rtcp_write_sr(struct ast_rtp_instance *instance) struct timeval dlsr; char bdata[512]; - /* Commented condition is always not NULL if rtp->rtcp is not NULL */ - if (!rtp || !rtp->rtcp/* || (&rtp->rtcp->them.sin_addr == 0)*/) + if (!rtp || !rtp->rtcp) return 0; - if (!rtp->rtcp->them.sin_addr.s_addr) { /* This'll stop rtcp for this rtp session */ + if (ast_sockaddr_isnull(&rtp->rtcp->them)) { /* This'll stop rtcp for this rtp session */ ast_verbose("RTCP SR transmission error, rtcp halted\n"); AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid); return 0; @@ -941,9 +929,11 @@ static int ast_rtcp_write_sr(struct ast_rtp_instance *instance) rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */ len += 12; - res =rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them)); + res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them); if (res < 0) { - ast_log(LOG_ERROR, "RTCP SR transmission error to %s:%d, rtcp halted %s\n",ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port), strerror(errno)); + ast_log(LOG_ERROR, "RTCP SR transmission error to %s, rtcp halted %s\n", + ast_sockaddr_stringify(&rtp->rtcp->them), + strerror(errno)); AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid); return 0; } @@ -955,7 +945,7 @@ static int ast_rtcp_write_sr(struct ast_rtp_instance *instance) rtp->rtcp->lastsrtxcount = rtp->txcount; if (rtcp_debug_test_addr(&rtp->rtcp->them)) { - ast_verbose("* Sent RTCP SR to %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port)); + ast_verbose("* Sent RTCP SR to %s\n", ast_sockaddr_stringify(&rtp->rtcp->them)); ast_verbose(" Our SSRC: %u\n", rtp->ssrc); ast_verbose(" Sent(NTP): %u.%010u\n", (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096); ast_verbose(" Sent(RTP): %u\n", rtp->lastts); @@ -968,7 +958,7 @@ static int ast_rtcp_write_sr(struct ast_rtp_instance *instance) ast_verbose(" Their last SR: %u\n", rtp->rtcp->themrxlsr); ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(ntohl(rtcpheader[12])/65536.0)); } - manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To %s:%d\r\n" + manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To %s\r\n" "OurSSRC: %u\r\n" "SentNTP: %u.%010u\r\n" "SentRTP: %u\r\n" @@ -980,7 +970,7 @@ static int ast_rtcp_write_sr(struct ast_rtp_instance *instance) "IAJitter: %.4f\r\n" "TheirLastSR: %u\r\n" "DLSR: %4.4f (sec)\r\n", - ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port), + ast_sockaddr_stringify(&rtp->rtcp->them), rtp->ssrc, (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096, rtp->lastts, @@ -1019,7 +1009,7 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); int pred, mark = 0; unsigned int ms = calc_txstamp(rtp, &frame->delivery); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; int rate = rtp_get_rate(frame->subclass.codec) / 1000; if (frame->subclass.codec == AST_FORMAT_G722) { @@ -1094,7 +1084,7 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame ast_rtp_instance_get_remote_address(instance, &remote_address); /* If we know the remote address construct a packet and send it out */ - if (remote_address.sin_port && remote_address.sin_addr.s_addr) { + if (!ast_sockaddr_isnull(&remote_address)) { int hdrlen = 12, res; unsigned char *rtpheader = (unsigned char *)(frame->data.ptr - hdrlen); @@ -1102,13 +1092,17 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts)); put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc)); - if ((res = rtp_sendto(instance, (void *)rtpheader, frame->datalen + hdrlen, 0, (struct sockaddr *)&remote_address, sizeof(remote_address))) < 0) { + if ((res = rtp_sendto(instance, (void *)rtpheader, frame->datalen + hdrlen, 0, &remote_address)) < 0) { if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) { - ast_debug(1, "RTP Transmission error of packet %d to %s:%d: %s\n", rtp->seqno, ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno)); + ast_debug(1, "RTP Transmission error of packet %d to %s: %s\n", + rtp->seqno, + ast_sockaddr_stringify(&remote_address), + strerror(errno)); } else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) { /* Only give this error message once if we are not RTP debugging */ if (option_debug || rtpdebug) - ast_debug(0, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port)); + ast_debug(0, "RTP NAT: Can't write RTP to private address %s, waiting for other end to send audio...\n", + ast_sockaddr_stringify(&remote_address)); ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN); } } else { @@ -1122,8 +1116,9 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame } if (rtp_debug_test_addr(&remote_address)) { - ast_verbose("Sent RTP packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", - ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), codec, rtp->seqno, rtp->lastts, res - hdrlen); + ast_verbose("Sent RTP packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", + ast_sockaddr_stringify(&remote_address), + codec, rtp->seqno, rtp->lastts, res - hdrlen); } } @@ -1172,13 +1167,13 @@ static struct ast_frame *red_t140_to_red(struct rtp_red *red) { static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; format_t codec, subclass; ast_rtp_instance_get_remote_address(instance, &remote_address); /* If we don't actually know the remote address don't even bother doing anything */ - if (!remote_address.sin_addr.s_addr) { + if (ast_sockaddr_isnull(&remote_address)) { ast_debug(1, "No remote address on RTP instance '%p' so dropping frame\n", instance); return 0; } @@ -1341,17 +1336,19 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; ast_rtp_instance_get_remote_address(instance, &remote_address); if (((compensate && type == AST_FRAME_DTMF_END) || (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) { - ast_debug(1, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(remote_address.sin_addr)); + ast_debug(1, "Ignore potential DTMF echo from '%s'\n", + ast_sockaddr_stringify(&remote_address)); rtp->resp = 0; rtp->dtmfsamples = 0; return &ast_null_frame; } - ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(remote_address.sin_addr)); + ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, + ast_sockaddr_stringify(&remote_address)); if (rtp->resp == 'X') { rtp->f.frametype = AST_FRAME_CONTROL; rtp->f.subclass.integer = AST_CONTROL_FLASH; @@ -1368,10 +1365,10 @@ static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, en return &rtp->f; } -static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark, struct frame_list *frames) +static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark, struct frame_list *frames) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; unsigned int event, event_end, samples; char resp = 0; struct ast_frame *f = NULL; @@ -1388,8 +1385,9 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha samples &= 0xFFFF; if (rtp_debug_test_addr(&remote_address)) { - ast_verbose("Got RTP RFC2833 from %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", ast_inet_ntoa(remote_address.sin_addr), - ntohs(remote_address.sin_port), payloadtype, seqno, timestamp, len, (mark?1:0), event, ((event_end & 0x80)?1:0), samples); + ast_verbose("Got RTP RFC2833 from %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", + ast_sockaddr_stringify(&remote_address), + payloadtype, seqno, timestamp, len, (mark?1:0), event, ((event_end & 0x80)?1:0), samples); } /* Print out debug if turned on */ @@ -1492,7 +1490,7 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha return; } -static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark) +static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); unsigned int event, flags, power; @@ -1571,7 +1569,7 @@ static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, u return f; } -static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark) +static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1582,12 +1580,12 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u ast_debug(0, "- RTP 3389 Comfort noise event: Level %" PRId64 " (len = %d)\n", rtp->lastrxformat, len); if (ast_test_flag(rtp, FLAG_3389_WARNING)) { - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; ast_rtp_instance_get_remote_address(instance, &remote_address); - ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s\n", - ast_inet_ntoa(remote_address.sin_addr)); + ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client address: %s\n", + ast_sockaddr_stringify(&remote_address)); ast_set_flag(rtp, FLAG_3389_WARNING); } @@ -1615,15 +1613,16 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in sin; - socklen_t len = sizeof(sin); + struct ast_sockaddr addr; unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET]; unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET); int res, packetwords, position = 0; struct ast_frame *f = &ast_null_frame; /* Read in RTCP data from the socket */ - if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET, sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET, 0, (struct sockaddr *)&sin, &len)) < 0) { + if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET, + sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET, + 0, &addr)) < 0) { ast_assert(errno != EBADF); if (errno != EAGAIN) { ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", strerror(errno)); @@ -1636,11 +1635,11 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { /* Send to whoever sent to us */ - if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) || - (rtp->rtcp->them.sin_port != sin.sin_port)) { - memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them)); + if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) { + ast_sockaddr_copy(&rtp->rtcp->them, &addr); if (option_debug || rtpdebug) - ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port)); + ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", + ast_sockaddr_stringify(&rtp->rtcp->them)); } } @@ -1665,8 +1664,9 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) return &ast_null_frame; } - if (rtcp_debug_test_addr(&sin)) { - ast_verbose("\n\nGot RTCP from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + if (rtcp_debug_test_addr(&addr)) { + ast_verbose("\n\nGot RTCP from %s\n", + ast_sockaddr_stringify(&addr)); ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown"); ast_verbose("Reception reports: %d\n", rc); ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]); @@ -1685,7 +1685,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) rtp->rtcp->soc = ntohl(rtcpheader[i + 4]); rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/ - if (rtcp_debug_test_addr(&sin)) { + if (rtcp_debug_test_addr(&addr)) { ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096); ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2])); ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4])); @@ -1735,7 +1735,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) rtp->rtcp->normdevrtt = normdevrtt_current; rtp->rtcp->rtt_count++; - } else if (rtcp_debug_test_addr(&sin)) { + } else if (rtcp_debug_test_addr(&addr)) { ast_verbose("Internal RTCP NTP clock skew detected: " "lsr=%u, now=%u, dlsr=%u (%d:%03dms), " "diff=%d\n", @@ -1784,7 +1784,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) rtp->rtcp->reported_jitter_count++; - if (rtcp_debug_test_addr(&sin)) { + if (rtcp_debug_test_addr(&addr)) { ast_verbose(" Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24)); ast_verbose(" Packets lost so far: %d\n", rtp->rtcp->reported_lost); ast_verbose(" Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff)); @@ -1796,7 +1796,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) ast_verbose(" RTT: %lu(sec)\n", (unsigned long) rtt); } if (rtt) { - manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s:%d\r\n" + manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s\r\n" "PT: %d(%s)\r\n" "ReceptionReports: %d\r\n" "SenderSSRC: %u\r\n" @@ -1808,7 +1808,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) "LastSR: %lu.%010lu\r\n" "DLSR: %4.4f(sec)\r\n" "RTT: %llu(sec)\r\n", - ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), + ast_sockaddr_stringify(&addr), pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown", rc, rtcpheader[i + 1], @@ -1821,7 +1821,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) ntohl(rtcpheader[i + 5])/65536.0, (unsigned long long)rtt); } else { - manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s:%d\r\n" + manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s\r\n" "PT: %d(%s)\r\n" "ReceptionReports: %d\r\n" "SenderSSRC: %u\r\n" @@ -1832,7 +1832,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) "IAJitter: %u\r\n" "LastSR: %lu.%010lu\r\n" "DLSR: %4.4f(sec)\r\n", - ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), + ast_sockaddr_stringify(&addr), pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown", rc, rtcpheader[i + 1], @@ -1847,7 +1847,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) } break; case RTCP_PT_FUR: - if (rtcp_debug_test_addr(&sin)) + if (rtcp_debug_test_addr(&addr)) ast_verbose("Received an RTCP Fast Update Request\n"); rtp->f.frametype = AST_FRAME_CONTROL; rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE; @@ -1858,15 +1858,18 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) f = &rtp->f; break; case RTCP_PT_SDES: - if (rtcp_debug_test_addr(&sin)) - ast_verbose("Received an SDES from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port)); + if (rtcp_debug_test_addr(&addr)) + ast_verbose("Received an SDES from %s\n", + ast_sockaddr_stringify(&rtp->rtcp->them)); break; case RTCP_PT_BYE: - if (rtcp_debug_test_addr(&sin)) - ast_verbose("Received a BYE from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port)); + if (rtcp_debug_test_addr(&addr)) + ast_verbose("Received a BYE from %s\n", + ast_sockaddr_stringify(&rtp->rtcp->them)); break; default: - ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s:%d\n", pt, ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port)); + ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s\n", + pt, ast_sockaddr_stringify(&rtp->rtcp->them)); break; } position += (length + 1); @@ -1884,7 +1887,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int int res = 0, payload = 0, bridged_payload = 0, mark; struct ast_rtp_payload_type payload_type; int reconstruct = ntohl(rtpheader[0]); - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; /* Get fields from packet */ payload = (reconstruct & 0x7f0000) >> 16; @@ -1916,18 +1919,27 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int ast_rtp_instance_get_remote_address(instance1, &remote_address); /* Send the packet back out */ - res = rtp_sendto(instance1, (void *)rtpheader, len, 0, (struct sockaddr *)&remote_address, sizeof(remote_address)); + res = rtp_sendto(instance1, (void *)rtpheader, len, 0, &remote_address); if (res < 0) { if (!ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_NAT) && (ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) { - ast_debug(1, "RTP Transmission error of packet to %s:%d: %s\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno)); + ast_log(LOG_WARNING, + "RTP Transmission error of packet to %s: %s\n", + ast_sockaddr_stringify(&remote_address), + strerror(errno)); } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) { if (option_debug || rtpdebug) - ast_debug(0, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port)); + ast_log(LOG_WARNING, + "RTP NAT: Can't write RTP to private " + "address %s, waiting for other end to " + "send audio...\n", + ast_sockaddr_stringify(&remote_address)); ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN); } return 0; } else if (rtp_debug_test_addr(&remote_address)) { - ast_verbose("Sent RTP P2P packet to %s:%u (type %-2.2d, len %-6.6u)\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), bridged_payload, len - hdrlen); + ast_verbose("Sent RTP P2P packet to %s (type %-2.2d, len %-6.6u)\n", + ast_sockaddr_stringify(&remote_address), + bridged_payload, len - hdrlen); } return 0; @@ -1936,12 +1948,11 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in sin; - socklen_t len = sizeof(sin); + struct ast_sockaddr addr; int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno; unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp; struct ast_rtp_payload_type payload; - struct sockaddr_in remote_address = { 0, }; + struct ast_sockaddr remote_address = { {0,} }; struct frame_list frames; /* If this is actually RTCP let's hop on over and handle it */ @@ -1958,7 +1969,9 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } /* Actually read in the data from the socket */ - if ((res = rtp_recvfrom(instance, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0, (struct sockaddr*)&sin, &len)) < 0) { + if ((res = rtp_recvfrom(instance, rtp->rawdata + AST_FRIENDLY_OFFSET, + sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0, + &addr)) < 0) { ast_assert(errno != EBADF); if (errno != EAGAIN) { ast_log(LOG_WARNING, "RTP Read error: %s. Hanging up.\n", strerror(errno)); @@ -1975,16 +1988,19 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */ if (rtp->strict_rtp_state == STRICT_RTP_LEARN) { - memcpy(&rtp->strict_rtp_address, &sin, sizeof(rtp->strict_rtp_address)); + ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); rtp->strict_rtp_state = STRICT_RTP_CLOSED; } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) { - if ((rtp->strict_rtp_address.sin_addr.s_addr != sin.sin_addr.s_addr) || (rtp->strict_rtp_address.sin_port != sin.sin_port)) { + if (ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { /* Hmm, not the strict addres. Perhaps we're getting audio from the alternate? */ - if ((rtp->alt_rtp_address.sin_addr.s_addr == sin.sin_addr.s_addr) && (rtp->alt_rtp_address.sin_port == sin.sin_port)) { + if (!ast_sockaddr_cmp(&rtp->alt_rtp_address, &addr)) { /* ooh, we did! You're now the new expected address, son! */ - rtp->strict_rtp_address = sin; + ast_sockaddr_copy(&rtp->strict_rtp_address, + &addr); } else { - ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port)); + ast_debug(1, "Received RTP packet from %s, dropping due to strict RTP protection. Expected it to be from %s\n", + ast_sockaddr_stringify(&addr), + ast_sockaddr_stringify(&rtp->strict_rtp_address)); return &ast_null_frame; } } @@ -1996,27 +2012,30 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc ast_rtp_instance_get_remote_address(instance, &remote_address); if (!(version = (seqno & 0xC0000000) >> 30)) { - if ((ast_stun_handle_packet(rtp->s, &sin, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) && - (!remote_address.sin_port && !remote_address.sin_addr.s_addr)) { - ast_rtp_instance_set_remote_address(instance, &sin); + struct sockaddr_in addr_tmp; + ast_sockaddr_to_sin(&addr, &addr_tmp); + if ((ast_stun_handle_packet(rtp->s, &addr_tmp, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) && + ast_sockaddr_isnull(&remote_address)) { + ast_sockaddr_from_sin(&addr, &addr_tmp); + ast_rtp_instance_set_remote_address(instance, &addr); } return &ast_null_frame; } /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { - if ((remote_address.sin_addr.s_addr != sin.sin_addr.s_addr) || - (remote_address.sin_port != sin.sin_port)) { - ast_rtp_instance_set_remote_address(instance, &sin); - memcpy(&remote_address, &sin, sizeof(remote_address)); + if (ast_sockaddr_cmp(&remote_address, &addr)) { + ast_rtp_instance_set_remote_address(instance, &addr); + ast_sockaddr_copy(&remote_address, &addr); if (rtp->rtcp) { - memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them)); - rtp->rtcp->them.sin_port = htons(ntohs(sin.sin_port)+1); + ast_sockaddr_copy(&rtp->rtcp->them, &addr); + ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1); } rtp->rxseqno = 0; ast_set_flag(rtp, FLAG_NAT_ACTIVE); if (option_debug || rtpdebug) - ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s:%d\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port)); + ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s\n", + ast_sockaddr_stringify(&remote_address)); } } @@ -2097,7 +2116,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } /* Do not schedule RR if RTCP isn't run */ - if (rtp->rtcp && rtp->rtcp->them.sin_addr.s_addr && rtp->rtcp->schedid < 1) { + if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 1) { /* Schedule transmission of Receiver Report */ rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance); } @@ -2111,9 +2130,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */ } - if (rtp_debug_test_addr(&sin)) { - ast_verbose("Got RTP packet from %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", - ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen); + if (rtp_debug_test_addr(&addr)) { + ast_verbose("Got RTP packet from %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n", + ast_sockaddr_stringify(&addr), + payloadtype, seqno, timestamp,res - hdrlen); } payload = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payloadtype); @@ -2126,13 +2146,15 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc * by passing the pointer to the frame list to it so that the method * can append frames to the list as needed. */ - process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark, &frames); + process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames); } else if (payload.code == AST_RTP_CISCO_DTMF) { - f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark); + f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); } else if (payload.code == AST_RTP_CN) { - f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark); + f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); } else { - ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(remote_address.sin_addr)); + ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", + payloadtype, + ast_sockaddr_stringify(&remote_address)); } if (f) { @@ -2283,19 +2305,26 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro if (!(rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp)))) { return; } - if ((rtp->rtcp->s = create_new_socket("RTCP")) < 0) { + + /* Grab the IP address and port we are going to use */ + ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us); + ast_sockaddr_set_port(&rtp->rtcp->us, + ast_sockaddr_port(&rtp->rtcp->us) + 1); + + if ((rtp->rtcp->s = + create_new_socket("RTCP", + ast_sockaddr_is_ipv4(&rtp->rtcp->us) ? + AF_INET : + ast_sockaddr_is_ipv6(&rtp->rtcp->us) ? + AF_INET6 : -1)) < 0) { ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance); ast_free(rtp->rtcp); rtp->rtcp = NULL; return; } - /* Grab the IP address and port we are going to use */ - ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us); - rtp->rtcp->us.sin_port = htons(ntohs(rtp->rtcp->us.sin_port) + 1); - /* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */ - if (bind(rtp->rtcp->s, (struct sockaddr*)&rtp->rtcp->us, sizeof(rtp->rtcp->us))) { + if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) { ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance); close(rtp->rtcp->s); ast_free(rtp->rtcp); @@ -2319,14 +2348,17 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp) return rtcp ? (rtp->rtcp ? rtp->rtcp->s : -1) : rtp->s; } -static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin) +static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); if (rtp->rtcp) { ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance); - memcpy(&rtp->rtcp->them, sin, sizeof(rtp->rtcp->them)); - rtp->rtcp->them.sin_port = htons(ntohs(sin->sin_port) + 1); + ast_sockaddr_copy(&rtp->rtcp->them, addr); + if (!ast_sockaddr_isnull(addr)) { + ast_sockaddr_set_port(&rtp->rtcp->them, + ast_sockaddr_port(addr) + 1); + } } rtp->rxseqno = 0; @@ -2338,14 +2370,14 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct return; } -static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin) +static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); /* No need to futz with rtp->rtcp here because ast_rtcp_read is already able to adjust if receiving * RTCP from an "unexpected" source */ - rtp->alt_rtp_address = *sin; + ast_sockaddr_copy(&rtp->alt_rtp_address, addr); return; } @@ -2485,17 +2517,20 @@ static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_ins (!chan0->tech->send_digit_begin != !chan1->tech->send_digit_begin)) ? 0 : 1); } -static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username) +static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct sockaddr_in suggestion_tmp; - ast_stun_request(rtp->s, suggestion, username, NULL); + ast_sockaddr_to_sin(suggestion, &suggestion_tmp); + ast_stun_request(rtp->s, &suggestion_tmp, username, NULL); + ast_sockaddr_from_sin(suggestion, &suggestion_tmp); } static void ast_rtp_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct sockaddr_in sin = { 0, }; + struct ast_sockaddr addr = { {0,} }; if (rtp->rtcp) { AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid); @@ -2506,10 +2541,9 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance) rtp->red = NULL; } - ast_rtp_instance_set_remote_address(instance, &sin); + ast_rtp_instance_set_remote_address(instance, &addr); if (rtp->rtcp) { - memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->rtcp->them.sin_addr)); - memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->rtcp->them.sin_port)); + ast_sockaddr_setnull(&rtp->rtcp->them); } ast_set_flag(rtp, FLAG_NEED_MARKER_BIT); @@ -2517,60 +2551,28 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance) static char *rtp_do_debug_ip(struct ast_cli_args *a) { - struct hostent *hp; - struct ast_hostent ahp; - int port = 0; - char *p, *arg = ast_strdupa(a->argv[4]); - - p = strstr(arg, ":"); - if (p) { - *p = '\0'; - p++; - port = atoi(p); - } - hp = ast_gethostbyname(arg, &ahp); - if (hp == NULL) { + char *arg = ast_strdupa(a->argv[4]); + + if (!ast_sockaddr_parse(&rtpdebugaddr, arg, 0)) { ast_cli(a->fd, "Lookup failed for '%s'\n", arg); return CLI_FAILURE; } - rtpdebugaddr.sin_family = AF_INET; - memcpy(&rtpdebugaddr.sin_addr, hp->h_addr, sizeof(rtpdebugaddr.sin_addr)); - rtpdebugaddr.sin_port = htons(port); - if (port == 0) { - ast_cli(a->fd, "RTP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtpdebugaddr.sin_addr)); - } else { - ast_cli(a->fd, "RTP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtpdebugaddr.sin_addr), port); - } + ast_cli(a->fd, "RTP Debugging Enabled for address: %s\n", + ast_sockaddr_stringify(&rtpdebugaddr)); rtpdebug = 1; return CLI_SUCCESS; } static char *rtcp_do_debug_ip(struct ast_cli_args *a) { - struct hostent *hp; - struct ast_hostent ahp; - int port = 0; - char *p, *arg = ast_strdupa(a->argv[4]); - - p = strstr(arg, ":"); - if (p) { - *p = '\0'; - p++; - port = atoi(p); - } - hp = ast_gethostbyname(arg, &ahp); - if (hp == NULL) { + char *arg = ast_strdupa(a->argv[4]); + + if (!ast_sockaddr_parse(&rtcpdebugaddr, arg, 0)) { ast_cli(a->fd, "Lookup failed for '%s'\n", arg); return CLI_FAILURE; } - rtcpdebugaddr.sin_family = AF_INET; - memcpy(&rtcpdebugaddr.sin_addr, hp->h_addr, sizeof(rtcpdebugaddr.sin_addr)); - rtcpdebugaddr.sin_port = htons(port); - if (port == 0) { - ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr)); - } else { - ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr), port); - } + ast_cli(a->fd, "RTCP Debugging Enabled for address: %s\n", + ast_sockaddr_stringify(&rtcpdebugaddr)); rtcpdebug = 1; return CLI_SUCCESS; } diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index b58f4b36e7472e1020b3dfe70fcb17362cf0dc7b..19d21bcfbc9606ac6738d3c7e0e4aa6ea2aa47cc 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -44,7 +44,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/config.h" #include "asterisk/lock.h" #include "asterisk/utils.h" -#include "asterisk/netsock.h" #include "asterisk/cli.h" #include "asterisk/manager.h" #include "asterisk/unaligned.h" @@ -90,7 +89,7 @@ struct multicast_rtp { }; /* Forward Declarations */ -static int multicast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data); +static int multicast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct ast_sockaddr *addr, void *data); static int multicast_rtp_activate(struct ast_rtp_instance *instance); static int multicast_rtp_destroy(struct ast_rtp_instance *instance); static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame); @@ -107,7 +106,7 @@ static struct ast_rtp_engine multicast_rtp_engine = { }; /*! \brief Function called to create a new multicast instance */ -static int multicast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data) +static int multicast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct ast_sockaddr *addr, void *data) { struct multicast_rtp *multicast; const char *type = data; @@ -143,22 +142,30 @@ static int multicast_send_control_packet(struct ast_rtp_instance *instance, stru struct multicast_control_packet control_packet = { .unique_id = htonl((u_long)time(NULL)), .command = htonl(command), }; - struct sockaddr_in control_address, remote_address; + struct ast_sockaddr control_address, remote_address; ast_rtp_instance_get_local_address(instance, &control_address); ast_rtp_instance_get_remote_address(instance, &remote_address); /* Ensure the user of us have given us both the control address and destination address */ - if (!control_address.sin_addr.s_addr || !remote_address.sin_addr.s_addr) { + if (ast_sockaddr_isnull(&control_address) || + ast_sockaddr_isnull(&remote_address)) { return -1; } - control_packet.ip = remote_address.sin_addr.s_addr; - control_packet.port = htonl(ntohs(remote_address.sin_port)); + /* The protocol only supports IPv4. */ + if (ast_sockaddr_is_ipv6(&remote_address)) { + ast_log(LOG_WARNING, "Cannot send control packet for IPv6 " + "remote address.\n"); + return -1; + } + + control_packet.ip = htonl(ast_sockaddr_ipv4(&remote_address)); + control_packet.port = htonl(ast_sockaddr_port(&remote_address)); /* Based on a recommendation by Brian West who did the FreeSWITCH implementation we send control packets twice */ - sendto(multicast->socket, &control_packet, sizeof(control_packet), 0, (struct sockaddr *)&control_address, sizeof(control_address)); - sendto(multicast->socket, &control_packet, sizeof(control_packet), 0, (struct sockaddr *)&control_address, sizeof(control_address)); + ast_sendto(multicast->socket, &control_packet, sizeof(control_packet), 0, &control_address); + ast_sendto(multicast->socket, &control_packet, sizeof(control_packet), 0, &control_address); return 0; } @@ -196,7 +203,7 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra { struct multicast_rtp *multicast = ast_rtp_instance_get_data(instance); struct ast_frame *f = frame; - struct sockaddr_in remote_address; + struct ast_sockaddr remote_address; int hdrlen = 12, res, codec; unsigned char *rtpheader; @@ -223,11 +230,12 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra /* Finally send it out to the eager phones listening for us */ ast_rtp_instance_get_remote_address(instance, &remote_address); - res = sendto(multicast->socket, (void *) rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *) &remote_address, sizeof(remote_address)); + res = ast_sendto(multicast->socket, (void *) rtpheader, f->datalen + hdrlen, 0, &remote_address); if (res < 0) { - ast_log(LOG_ERROR, "Multicast RTP Transmission error to %s:%u: %s\n", - ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno)); + ast_log(LOG_ERROR, "Multicast RTP Transmission error to %s: %s\n", + ast_sockaddr_stringify(&remote_address), + strerror(errno)); } /* If we were forced to duplicate the frame free the new one */