Merged revisions 200946 via svnmerge from

https://origsvn.digium.com/svn/asterisk/trunk

........
  r200946 | dvossel | 2009-06-16 11:03:30 -0500 (Tue, 16 Jun 2009) | 32 lines
  
  SIP transport type issues
  
  What this patch addresses:
  1. ast_sip_ouraddrfor() by default binds to the UDP address/port
  reguardless if the sip->pvt is of type UDP or not.  Now when no
  remapping is required, ast_sip_ouraddrfor() checks the sip_pvt's
  transport type, attempting to set the address and port to the
  correct TCP/TLS bindings if necessary.
  2.  It is not necessary to send the port number in the Contact
  header unless the port is non-standard for the transport type.
  This patch fixes this and removes the todo note.
  3.  In sip_alloc(), the default dialog built always uses transport
  type UDP.  Now sip_alloc() looks at the sip_request (if present)
  and determines what transport type to use by default.
  4.  When changing the transport type of a sip_socket, the file
  descriptor must be set to -1 and in some cases the tcptls_session's
  ref count must be decremented and set to NULL.  I've encountered
  several issues associated with this process and have created a function,
  set_socket_transport(), to handle the setting of the socket type.
  
  
  (closes issue #13865)
  Reported by: st
  Patches:
        dont_add_port_if_tls.patch uploaded by Kristijan (license 753)
        13865.patch uploaded by mmichelson (license 60)
        tls_port_v5.patch uploaded by vrban (license 756)
        transport_issues.diff uploaded by dvossel (license 671)
  Tested by: mmichelson, Kristijan, vrban, jmacz, dvossel
  
  Review: https://reviewboard.asterisk.org/r/278/
........


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.0@200992 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.6.0
David Vossel 17 years ago
parent 64cfe299bd
commit c2d79c89bb

@ -1769,7 +1769,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e
/*--- 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);
@ -1964,6 +1964,7 @@ static void reg_source_db(struct sip_peer *peer);
static void destroy_association(struct sip_peer *peer);
static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
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, int expirey, int deprecated_username, int lastms);
@ -1975,7 +1976,7 @@ static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *
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;
@ -2247,14 +2248,14 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
req.ignore = 0;
req.debug = 0;
req.socket.fd = tcptls_session->fd;
if (tcptls_session->ssl) {
req.socket.type = SIP_TRANSPORT_TLS;
set_socket_transport(&req.socket, SIP_TRANSPORT_TLS);
req.socket.port = htons(ourport_tls);
} else {
req.socket.type = SIP_TRANSPORT_TCP;
set_socket_transport(&req.socket, SIP_TRANSPORT_TCP);
req.socket.port = htons(ourport_tcp);
}
req.socket.fd = tcptls_session->fd;
res = ast_wait_for_input(tcptls_session->fd, -1);
if (res < 0) {
ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
@ -2613,8 +2614,9 @@ static inline const char *get_transport(enum sip_transport t)
static inline const char *get_transport_pvt(struct sip_pvt *p)
{
if (p->outboundproxy && p->outboundproxy->transport)
p->socket.type = p->outboundproxy->transport;
if (p->outboundproxy && p->outboundproxy->transport) {
set_socket_transport(&p->socket, p->outboundproxy->transport);
}
return get_transport(p->socket.type);
}
@ -2689,7 +2691,7 @@ 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)
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
@ -2733,10 +2735,34 @@ static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us)
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 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.sin.sin_addr.s_addr) {
*us = sip_tcp_desc.sin;
} else {
us->sin_port = sip_tcp_desc.sin.sin_port;
}
break;
case SIP_TRANSPORT_TLS:
if (sip_tls_desc.sin.sin_addr.s_addr) {
*us = sip_tls_desc.sin;
} else {
us->sin_port = sip_tls_desc.sin.sin_port;
}
break;
case SIP_TRANSPORT_UDP:
/* fall through on purpose */
default:
if (bindaddr.sin_addr.s_addr) {
*us = bindaddr;
}
}
} else if (bindaddr.sin_addr.s_addr) {
*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));
}
/*! \brief Append to SIP dialog history with arg list */
@ -4226,7 +4252,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, int newdialog)
if (peer) {
int res;
if (newdialog) {
dialog->socket.type = 0;
set_socket_transport(&dialog->socket, 0);
}
res = create_addr_from_peer(dialog, peer);
unref_peer(peer);
@ -4281,7 +4307,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, int newdialog)
}
if (!dialog->socket.type)
dialog->socket.type = SIP_TRANSPORT_UDP;
set_socket_transport(&dialog->socket, SIP_TRANSPORT_UDP);
if (!dialog->socket.port)
dialog->socket.port = bindaddr.sin_port;
@ -5981,7 +6007,7 @@ static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p)
* 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;
@ -5995,8 +6021,13 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
ast_mutex_init(&p->pvt_lock);
if (req) {
set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
} else {
set_socket_transport(&p->socket, SIP_TRANSPORT_UDP);
}
p->socket.fd = -1;
p->socket.type = SIP_TRANSPORT_UDP;
p->method = intended_method;
p->initid = -1;
p->waitid = -1;
@ -6019,7 +6050,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
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. */
@ -6224,7 +6255,7 @@ restartsearch:
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 {
@ -8013,7 +8044,7 @@ static int transmit_response_using_temp(ast_string_field callid, struct sockaddr
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();
@ -8914,16 +8945,19 @@ 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);
if (p->socket.type & SIP_TRANSPORT_UDP) {
if (!sip_standard_port(p->socket.type, ourport))
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);
/* 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, S_OR(p->exten, "@"), ast_inet_ntoa(p->ourip.sin_addr), ourport);
else
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:%d;transport=%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type));
ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d;transport=%s>", p->exten, S_OR(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, "<sip:%s%s%s>", p->exten, S_OR(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, S_OR(p->exten, "@"), ast_inet_ntoa(p->ourip.sin_addr), get_transport(p->socket.type));
}
}
/*! \brief Build the Remote Party-ID & From using callingpres options */
@ -9677,7 +9711,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
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;
}
@ -9733,7 +9767,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
ast_string_field_set(p, exten, r->callback);
/* Set transport and port so the correct contact is built */
p->socket.type = r->transport;
set_socket_transport(&p->socket, r->transport);
if (r->transport == SIP_TRANSPORT_TLS || r->transport == SIP_TRANSPORT_TCP) {
p->socket.port = sip_tcp_desc.sin.sin_port;
}
@ -9742,7 +9776,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);
ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
build_contact(p);
}
@ -10048,16 +10082,15 @@ static void destroy_association(struct sip_peer *peer)
}
}
}
static void set_peer_transport(struct sip_peer *peer, int transport)
static void set_socket_transport(struct sip_socket *socket, int transport)
{
/* if the transport type changes, clear all socket data */
if (peer->socket.type != transport) {
peer->socket.type = transport;
peer->socket.fd = -1;
if (peer->socket.tcptls_session) {
ao2_ref(peer->socket.tcptls_session, -1);
peer->socket.tcptls_session = NULL;
if (socket->type != transport) {
socket->fd = -1;
socket->type = transport;
if (socket->tcptls_session) {
ao2_ref(socket->tcptls_session, -1);
socket->tcptls_session = NULL;
}
}
}
@ -10073,7 +10106,7 @@ static int expire_register(const void *data)
memset(&peer->addr, 0, sizeof(peer->addr));
destroy_association(peer); /* remove registration data from storage */
set_peer_transport(peer, peer->default_outbound_transport);
set_socket_transport(&peer->socket, peer->default_outbound_transport);
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
register_peer_exten(peer, FALSE); /* Remove regexten */
@ -10288,7 +10321,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
} else if (!strcasecmp(curi, "*") || !expiry) { /* Unregister this peer */
/* This means remove all registrations and return OK */
memset(&peer->addr, 0, sizeof(peer->addr));
set_peer_transport(peer, peer->default_outbound_transport);
set_socket_transport(&peer->socket, peer->default_outbound_transport);
AST_SCHED_DEL(sched, peer->expire);
destroy_association(peer);
@ -10340,7 +10373,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
* transport type, change it. If it got this far, it is a
* supported type, but check just in case */
if ((peer->socket.type != transport_type) && (peer->transports & transport_type)) {
set_peer_transport(peer, transport_type);
set_socket_transport(&peer->socket, transport_type);
}
oldsin = peer->addr;
@ -14546,7 +14579,7 @@ static char *sip_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
struct sip_request req;
struct ast_variable *var;
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;
}
@ -14567,7 +14600,7 @@ static char *sip_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
}
/* 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);
build_callid_pvt(p);
ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n", a->argv[2], a->argv[i]);
@ -19174,7 +19207,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
req.len = res;
req.socket.fd = sipsock;
req.socket.type = SIP_TRANSPORT_UDP;
set_socket_transport(&req.socket, SIP_TRANSPORT_UDP);
req.socket.tcptls_session = NULL;
req.socket.port = bindaddr.sin_port;
@ -19509,7 +19542,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e
p = dialog_ref(peer->mwipvt);
} 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 (create_addr_from_peer(p, peer)) {
/* Maybe they're not registered, etc. */
@ -19517,7 +19550,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);
ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
build_via(p);
build_callid_pvt(p);
/* Destroy this session after 32 secs */
@ -20095,7 +20128,7 @@ static int sip_poke_peer(struct sip_peer *peer)
ast_log(LOG_NOTICE, "Still have a QUALIFY dialog active, deleting\n");
peer->call = sip_destroy(peer->call);
}
if (!(p = peer->call = sip_alloc(NULL, NULL, 0, SIP_OPTIONS)))
if (!(p = peer->call = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL)))
return -1;
p->sa = peer->addr;
@ -20114,7 +20147,7 @@ static int sip_poke_peer(struct sip_peer *peer)
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);
build_callid_pvt(p);
@ -20280,7 +20313,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
}
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;
@ -20347,8 +20380,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
host = tmp;
}
p->socket.fd = -1;
p->socket.type = transport;
set_socket_transport(&p->socket, transport);
/* We now have
host = peer name, DNS host name or DNS domain (for SRV)
@ -20364,7 +20396,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
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);
build_callid_pvt(p);
@ -20885,8 +20917,7 @@ static void set_peer_defaults(struct sip_peer *peer)
peer->expire = -1;
peer->pokeexpire = -1;
peer->addr.sin_port = htons(STANDARD_SIP_PORT);
peer->socket.type = SIP_TRANSPORT_UDP;
peer->socket.fd = -1;
set_socket_transport(&peer->socket, SIP_TRANSPORT_UDP);
}
ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
@ -21357,7 +21388,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
if (((peer->socket.type != peer->default_outbound_transport) && (peer->expire == -1)) ||
!(peer->socket.type & peer->transports) || !(peer->socket.type)) {
set_peer_transport(peer, peer->default_outbound_transport);
set_socket_transport(&peer->socket, peer->default_outbound_transport);
}
if (fullcontact->used > 0) {

Loading…
Cancel
Save