aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2009-05-22 22:51:09 +0000
committerdvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2009-05-22 22:51:09 +0000
commitaa02a9711a0a5bb2c57dd8226b364f3cc59a40c3 (patch)
tree7b0f2a981299075a8844e5fc676ea58e233e6f4f
parent7949af7875dba9911878257a8d257ce8b6fe425b (diff)
Merged revisions 196416 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ........ r196416 | dvossel | 2009-05-22 16:09:45 -0500 (Fri, 22 May 2009) | 19 lines SIP set outbound transport type from Registration In sip.conf the transport option allows for the configuration of what transport types (udp, tcp, and tls) a peer will accept, but only the first type listed was used for outbound connections. This patch changes this. Now the default transport type is only used until the peer registers. When registration takes place the transport type is parsed out of the Contact header. If the Contact header's transport type is equal to one that the peer supports, the peer's default transport type for outbound connections is set to match the Contact header's type. If the Contact header's transport type is not present, then the peer's default transport type is set to match the one the peer registered with. When a peer unregisters or the registration expires, the default transport type for that peer is reset. (closes issue #12282) Reported by: rjain Patches: reg_patch_1.diff uploaded by dvossel (license 671) Tested by: dvossel (closes issue #14727) Reported by: pj Patches: reg_patch_3.diff uploaded by dvossel (license 671) Tested by: pj, dvossel Review: https://reviewboard.asterisk.org/r/249/ ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@196454 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--channels/chan_sip.c141
-rw-r--r--configs/sip.conf.sample11
2 files changed, 120 insertions, 32 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 5d917afad..03515d4bf 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1449,6 +1449,7 @@ struct sip_peer {
ASTOBJ_COMPONENTS(struct sip_peer); /*!< name, refcount, objflags, object pointers */
/*!< peer->name is the unique name of this object */
struct sip_socket socket; /*!< Socket used for this peer */
+ enum sip_transport default_outbound_transport; /*!< Peer Registration may change the default outbound transport. */
unsigned int transports:3; /*!< Transports (enum sip_transport) that are acceptable for this peer */
char secret[80]; /*!< Password */
char md5secret[80]; /*!< Password in MD5 */
@@ -1481,7 +1482,7 @@ struct sip_peer {
int lastmsgssent;
unsigned int sipoptions; /*!< Supported SIP options */
struct ast_flags flags[2]; /*!< SIP_ flags */
-
+
/*! Mailboxes that this peer cares about */
AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes;
@@ -1502,7 +1503,7 @@ struct sip_peer {
struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */
struct sockaddr_in addr; /*!< IP address of peer */
int maxcallbitrate; /*!< Maximum Bitrate for a video call */
-
+
/* Qualification */
struct sip_pvt *call; /*!< Call pointer */
int pokeexpire; /*!< When to expire poke (qualify= checking) */
@@ -2551,6 +2552,27 @@ static inline int sip_debug_test_pvt(struct sip_pvt *p)
return 0;
return sip_debug_test_addr(sip_real_dst(p));
}
+ /*! \brief Return int representing a bit field of transport types found in const char *transport */
+ static int get_transport_str2enum(const char *transport)
+ {
+ int res = 0;
+
+ if (ast_strlen_zero(transport)) {
+ return res;
+ }
+
+ if (!strcasecmp(transport, "udp")) {
+ res |= SIP_TRANSPORT_UDP;
+ }
+ if (!strcasecmp(transport, "tcp")) {
+ res |= SIP_TRANSPORT_TCP;
+ }
+ if (!strcasecmp(transport, "tls")) {
+ res |= SIP_TRANSPORT_TLS;
+ }
+
+ return res;
+}
static inline const char *get_transport_list(struct sip_peer *peer) {
switch (peer->transports) {
@@ -3338,7 +3360,7 @@ static char *get_in_brackets(char *tmp)
* \endverbatim
*/
static int parse_uri(char *uri, char *scheme,
- char **ret_name, char **pass, char **domain, char **port, char **options)
+ char **ret_name, char **pass, char **domain, char **port, char **options, char **transport)
{
char *name = NULL;
int error = 0;
@@ -3357,6 +3379,17 @@ static int parse_uri(char *uri, char *scheme,
error = -1;
}
}
+ if (transport) {
+ char *t, *type = "";
+ *transport = "";
+ if ((t = strstr(uri, "transport="))) {
+ strsep(&t, "=");
+ if ((type = strsep(&t, ";"))) {
+ *transport = type;
+ }
+ }
+ }
+
if (!domain) {
/* if we don't want to split around domain, keep everything as a name,
* so we need to do nothing here, except remember why.
@@ -9922,18 +9955,32 @@ static void destroy_association(struct sip_peer *peer)
}
}
+static void set_peer_transport(struct sip_peer *peer, 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;
+ }
+ }
+}
+
/*! \brief Expire registration of SIP peer */
static int expire_register(const void *data)
{
struct sip_peer *peer = (struct sip_peer *)data;
-
+
if (!peer) /* Hmmm. We have no peer. Weird. */
return 0;
memset(&peer->addr, 0, sizeof(peer->addr));
destroy_association(peer); /* remove registration data from storage */
-
+ set_peer_transport(peer, 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 */
peer->expire = -1;
@@ -10058,13 +10105,13 @@ static int __set_address_from_contact(const char *fullcontact, struct sockaddr_i
/* We have only the part in <brackets> here so we just need to parse a SIP URI.*/
if (tcp) {
- if (parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL)) {
- if (parse_uri(contact2, "sip:", &contact, NULL, &host, &pt, NULL))
+ if (parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL, NULL)) {
+ if (parse_uri(contact2, "sip:", &contact, NULL, &host, &pt, NULL, NULL))
ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact);
}
port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_TLS_PORT;
} else {
- if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, NULL))
+ if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, NULL, NULL))
ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact);
port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_SIP_PORT;
}
@@ -10100,12 +10147,13 @@ static int set_address_from_contact(struct sip_pvt *pvt)
/*! \brief Parse contact header and save registration (peer registration) */
static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req)
{
- char contact[SIPBUFSIZE];
+ char contact[SIPBUFSIZE];
char data[SIPBUFSIZE];
const char *expires = get_header(req, "Expires");
int expiry = atoi(expires);
- char *curi, *host, *pt, *curi2;
+ char *curi, *host, *pt, *curi2, *transport;
int port;
+ int transport_type;
const char *useragent;
struct hostent *hp;
struct ast_hostent ahp;
@@ -10125,8 +10173,6 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
}
}
- if (peer->socket.type == req->socket.type)
- copy_socket_data(&peer->socket, &req->socket);
copy_socket_data(&pvt->socket, &req->socket);
/* Look for brackets */
@@ -10148,10 +10194,11 @@ 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);
AST_SCHED_DEL(sched, peer->expire);
destroy_association(peer);
-
+
register_peer_exten(peer, FALSE); /* Remove extension from regexten= setting in sip.conf */
peer->fullcontact[0] = '\0';
peer->useragent[0] = '\0';
@@ -10172,17 +10219,36 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
/* Make sure it's a SIP URL */
if (pvt->socket.type == SIP_TRANSPORT_TLS) {
- if (parse_uri(curi, "sips:", &curi, NULL, &host, &pt, NULL)) {
- if (parse_uri(curi2, "sip:", &curi, NULL, &host, &pt, NULL))
+ if (parse_uri(curi, "sips:", &curi, NULL, &host, &pt, NULL, &transport)) {
+ if (parse_uri(curi2, "sip:", &curi, NULL, &host, &pt, NULL, &transport))
ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:) trying to use anyway\n");
}
port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_TLS_PORT;
} else {
- if (parse_uri(curi, "sip:", &curi, NULL, &host, &pt, NULL))
+ if (parse_uri(curi, "sip:", &curi, NULL, &host, &pt, NULL, &transport))
ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:) trying to use anyway\n");
port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_SIP_PORT;
}
+ /* 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. */
+ if (ast_strlen_zero(pt)) {
+ port = (transport_type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
+ }
+ } else {
+ transport_type = pvt->socket.type;
+ }
+
+ /* if the peer's socket type is different than the Registration
+ * 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);
+ }
+
oldsin = peer->addr;
/* Check that they're allowed to register at this IP */
@@ -10213,6 +10279,16 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
peer->addr = pvt->recv;
}
+ /* 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)){
+
+ copy_socket_data(&peer->socket, &pvt->socket);
+ }
+
/* Save SIP options profile */
peer->sipoptions = pvt->sipoptions;
@@ -10232,7 +10308,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
XXX WHY???? XXX
\todo check this
*/
- if (!peer->rt_fromcontact && (peer->socket.type & SIP_TRANSPORT_UDP))
+ 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\n", peer->name);
@@ -11987,12 +12063,12 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
/* ignore all fields but name */
if (p->socket.type == SIP_TRANSPORT_TLS) {
- if (parse_uri(of, "sips:", &of, &dummy, &domain, &dummy, &dummy)) {
- if (parse_uri(of2, "sip:", &of, &dummy, &domain, &dummy, &dummy))
+ if (parse_uri(of, "sips:", &of, &dummy, &domain, &dummy, &dummy, NULL)) {
+ if (parse_uri(of2, "sip:", &of, &dummy, &domain, &dummy, &dummy, NULL))
ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
}
} else {
- if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy))
+ if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy, NULL))
ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
}
@@ -20783,9 +20859,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
{
struct sip_peer *peer = NULL;
struct ast_ha *oldha = NULL;
- int found=0;
- int firstpass=1;
- int format=0; /* Ama flags */
+ int found = 0;
+ int firstpass = 1;
+ int format = 0; /* Ama flags */
time_t regseconds = 0;
struct ast_flags peerflags[2] = {{(0)}};
struct ast_flags mask[2] = {{(0)}};
@@ -20840,8 +20916,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
/* If we have realm authentication information, remove them (reload) */
clear_realm_authentication(peer->auth);
peer->auth = NULL;
+ peer->default_outbound_transport = 0;
peer->transports = 0;
- peer->socket.type = 0;
for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
if (handle_common_options(&peerflags[0], &mask[0], v))
@@ -20853,7 +20929,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
while ((trans = strsep(&val, ","))) {
trans = ast_skip_blanks(trans);
- if (!strncasecmp(trans, "udp", 3))
+ if (!strncasecmp(trans, "udp", 3))
peer->transports |= SIP_TRANSPORT_UDP;
else if (!strncasecmp(trans, "tcp", 3))
peer->transports |= SIP_TRANSPORT_TCP;
@@ -20862,9 +20938,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
else
ast_log(LOG_NOTICE, "'%s' is not a valid transport type. if no other is specified, udp will be used.\n", trans);
- if (!peer->socket.type) { /*!< The first transport listed should be used for outgoing */
- peer->socket.type = peer->transports;
- peer->socket.fd = -1;
+ if (!peer->default_outbound_transport) { /*!< The first transport listed should be default outbound */
+ peer->default_outbound_transport = peer->transports;
}
}
} else if (realtime && !strcasecmp(v->name, "regseconds")) {
@@ -21154,6 +21229,16 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
peer->socket.type = SIP_TRANSPORT_UDP;
}
+ /* The default transport type set during build_peer should only replace the socket.type when...
+ * 1. Registration is not present and the socket.type and default transport types are different.
+ * 2. The socket.type is not an acceptable transport type after rebuilding peer.
+ * 3. The socket.type is not set yet. */
+ 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);
+ }
+
if (fullcontact->used > 0) {
ast_copy_string(peer->fullcontact, fullcontact->str, sizeof(peer->fullcontact));
peer->rt_fromcontact = TRUE;
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index 15d5e2570..cb5bf7fe0 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -774,11 +774,14 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;secret=guessit
;defaultuser=yourusername ; Authentication user for outbound proxies
;fromuser=yourusername ; Many SIP providers require this!
-;fromdomain=provider.sip.domain
+;fromdomain=provider.sip.domain
;host=box.provider.com
-;transport=udp,tcp ; This sets the transport type to udp for outgoing, and will
-; ; accept both tcp and udp. Default is udp. The first transport
-; ; listed will always be used for outgoing connections.
+;transport=udp,tcp ; This sets the default transport type to udp for outgoing, and will
+; ; accept both tcp and udp. The default transport type is only used for
+; ; outbound messages until a Registration takes place. During the
+; ; peer Registration the transport type may change to another supported
+; ; type if the peer requests so.
+
;usereqphone=yes ; This provider requires ";user=phone" on URI
;callcounter=yes ; Enable call counter
;busylevel=2 ; Signal busy at 2 or more calls