Index: chan_sip.c =================================================================== --- chan_sip.c (revision 190186) +++ chan_sip.c (working copy) @@ -2321,7 +2321,7 @@ /*--- Dialog management */ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, - int useglobal_nat, const int intended_method); + int useglobal_nat, const int intended_method, struct sip_request *req); static int __sip_autodestruct(const void *data); static void sip_scheddestroy(struct sip_pvt *p, int ms); static int sip_cancel_destroy(struct sip_pvt *p); @@ -2529,7 +2529,7 @@ 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); +static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *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; @@ -3365,7 +3365,7 @@ * 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) +static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p) { struct sockaddr_in theirs; /* Set want_remap to non-zero if we want to remap 'us' to an externally @@ -3386,7 +3386,7 @@ /* now ask the system what would it use to talk to 'them' */ ast_ouraddrfor(them, &us->sin_addr); theirs.sin_addr = *them; - + want_remap = localaddr && (externip.sin_addr.s_addr || stunaddr.sin_addr.s_addr) && ast_apply_ha(localaddr, &theirs) == AST_SENSE_ALLOW ; @@ -3409,9 +3409,29 @@ 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)); - } else if (bindaddr.sin_addr.s_addr) { + } else { /* no remapping, but we bind to a specific address, so use it. */ - *us = bindaddr; + switch (p->socket.type) { + case (SIP_TRANSPORT_TCP): + if (sip_tcp_desc.local_address.sin_addr.s_addr) { + *us = sip_tcp_desc.local_address; + } else { + us->sin_port = sip_tcp_desc.local_address.sin_port; + } + case SIP_TRANSPORT_TLS: + if (sip_tls_desc.local_address.sin_addr.s_addr) { + *us = sip_tls_desc.local_address; + } else { + us->sin_port = sip_tls_desc.local_address.sin_port; + } + case (SIP_TRANSPORT_UDP): + /* fall through on purpose */ + default: + if (bindaddr.sin_addr.s_addr) { + *us = bindaddr; + } + ast_debug(3, "Allocating SIP_TRANSPORT_%s with address %s:%d\n", get_transport(p->socket.type), ast_inet_ntoa(us->sin_addr), ntohs(us->sin_port)); + } } } @@ -6794,7 +6814,7 @@ * remember to release the reference. */ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin, - int useglobal_nat, const int intended_method) + int useglobal_nat, const int intended_method, struct sip_request *req) { struct sip_pvt *p; @@ -6807,7 +6827,11 @@ } p->socket.fd = -1; - p->socket.type = SIP_TRANSPORT_UDP; + if(req) + p->socket.type = req->socket.type; /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */ + else + p->socket.type = SIP_TRANSPORT_UDP; + p->method = intended_method; p->initid = -1; p->waitid = -1; @@ -6830,7 +6854,7 @@ p->ourip = internip; else { p->sa = *sin; - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); } /* Copy global flags to this PVT at setup. */ @@ -7035,7 +7059,7 @@ transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event"); } else { /* Ok, time to create a new SIP dialog object, a pvt */ - if ((p = sip_alloc(callid, sin, 1, intended_method))) { + if ((p = sip_alloc(callid, sin, 1, intended_method, req))) { /* Ok, we've created a dialog, let's go and process it */ sip_pvt_lock(p); } else { @@ -8907,7 +8931,7 @@ p->ourip = internip; else { p->sa = *sin; - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); } p->branch = ast_random(); @@ -9918,15 +9942,17 @@ { int ourport = ntohs(p->ourip.sin_port); - - if (p->socket.type & SIP_TRANSPORT_UDP) { - if (!sip_standard_port(p->socket.type, ourport)) + + if (!sip_standard_port(p->socket.type, ourport)) { + if (p->socket.type & SIP_TRANSPORT_UDP) ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport); else + ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type)); + } else { + if (p->socket.type & SIP_TRANSPORT_UDP) ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr)); - } else { - /*! \todo We should not always add port here. Port is only added if it's non-standard (see code above) */ - ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type)); + else + ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), get_transport(p->socket.type)); } } @@ -10293,7 +10319,7 @@ } /* Create a dialog that we will use for the subscription */ - if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE))) { + if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL))) { return -1; } @@ -10333,7 +10359,7 @@ } mwi->call->socket.type = mwi->transport; mwi->call->socket.port = htons(mwi->portno); - ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip); + ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip, mwi->call); build_contact(mwi->call); build_via(mwi->call); build_callid_pvt(mwi->call); @@ -10710,7 +10736,7 @@ channame += 4; } - if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) { + if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) { astman_send_error(s, m, "Unable to build sip pvt data for notify (memory/socket error)"); return 0; } @@ -10728,7 +10754,7 @@ ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -10989,7 +11015,7 @@ r->callid_valid = TRUE; } /* Allocate SIP dialog for registration */ - if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER))) { + if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER, NULL))) { ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n"); return 0; } @@ -11066,7 +11092,7 @@ 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); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); build_contact(p); } @@ -16372,7 +16398,7 @@ for (i = 3; i < a->argc; i++) { struct sip_pvt *p; - if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) { + if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) { ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n"); return CLI_FAILURE; } @@ -16390,7 +16416,7 @@ ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -21846,7 +21872,7 @@ p = dialog_ref(peer->mwipvt, "sip_send_mwi_to_peer: Setting dialog ptr p from peer->mwipvt-- should this be done?"); } else { /* Build temporary dialog for this message */ - if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) + if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) return -1; /* If we don't set the socket type to 0, then create_addr_from_peer will fail immediately if the peer * uses any transport other than UDP. We set the type to 0 here and then let create_addr_from_peer copy @@ -21861,7 +21887,7 @@ return 0; } /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -22419,7 +22445,7 @@ peer->call = dialog_unref(peer->call, "unref dialog peer->call"); /* peer->call = sip_destroy(peer->call); */ } - if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS))) { + if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL))) { return -1; } peer->call = dialog_ref(p, "copy sip alloc from p to peer->call"); @@ -22440,7 +22466,7 @@ ast_string_field_set(p, tohost, ast_inet_ntoa(peer->addr.sin_addr)); /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p); @@ -22614,7 +22640,7 @@ } ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), oldformat)); - if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE))) { + if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE, NULL))) { ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", dest); *cause = AST_CAUSE_SWITCH_CONGESTION; return NULL; @@ -22702,7 +22728,7 @@ 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); + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p); build_via(p); ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name"); build_callid_pvt(p);