[asterisk-commits] qwell: branch qwell/fun_with_transports r385268 - in /team/qwell/fun_with_tra...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 10 16:23:53 CDT 2013


Author: qwell
Date: Wed Apr 10 16:23:52 2013
New Revision: 385268

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385268
Log:
Change how transport selection is done.

Modified:
    team/qwell/fun_with_transports/include/asterisk/res_sip.h
    team/qwell/fun_with_transports/res/res_sip.c
    team/qwell/fun_with_transports/res/res_sip.exports.in
    team/qwell/fun_with_transports/res/res_sip/location.c
    team/qwell/fun_with_transports/res/res_sip_registrar.c
    team/qwell/fun_with_transports/res/res_sip_session.c
    team/qwell/fun_with_transports/res/res_sip_transport_websocket.c

Modified: team/qwell/fun_with_transports/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/include/asterisk/res_sip.h?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/include/asterisk/res_sip.h (original)
+++ team/qwell/fun_with_transports/include/asterisk/res_sip.h Wed Apr 10 16:23:52 2013
@@ -148,8 +148,18 @@
 	);
 	/*! Absolute time that this contact is no longer valid after */
 	struct timeval expiration_time;
-	/*! Transport to use for all messages (some transport types require this) */
-	pjsip_transport *transport;
+};
+
+/*!
+ * \brief A transport to be used for messages to a contact
+ */
+struct ast_sip_contact_transport {
+        SORCERY_OBJECT(details);
+	AST_DECLARE_STRING_FIELDS(
+		/*! Full URI of the contact */
+		AST_STRING_FIELD(uri);
+	);
+        pjsip_transport *transport;
 };
 
 /*!
@@ -572,16 +582,6 @@
 struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor);
 
 /*!
- * \brief Retrieve a contact for an AOR
- *
- * \param aor Pointer to the AOR
- * \param contact_uri A URI to search for on the AOR
- * \retval NULL if contact not found
- * \retval non-NULL if contact found
- */
-struct ast_sip_contact *ast_sip_location_retrieve_aor_contact(const struct ast_sip_aor *aor, const char *contact_uri);
-
-/*!
  * \brief Retrieve all contacts currently available for an AOR
  *
  * \param aor Pointer to the AOR
@@ -595,11 +595,10 @@
  * \brief Retrieve a bound contact from a list of AORs
  *
  * \param aor_list A comma-separated list of AOR names
- * \param contact_uri Optional contact URI to search for
  * \retval NULL if no contacts available
  * \retval non-NULL if contacts available
  */
-struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list, const char *contact_uri);
+struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list);
 
 /*!
  * \brief Retrieve a named contact
@@ -610,6 +609,26 @@
  * \retval non-NULL if found
  */
 struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name);
+
+/*!
+ * \brief Retrieve a contact_transport, by URI
+ *
+ * \param contact_uri URI of the contact
+ *
+ * \retval NULL if not found
+ * \retval non-NULL if found
+ */
+struct ast_sip_contact_transport *ast_sip_location_retrieve_contact_transport_by_uri(const char *contact_uri);
+
+/*!
+ * \brief Retrieve a contact_transport, by transport
+ *
+ * \param transport transport the contact uses
+ *
+ * \retval NULL if not found
+ * \retval non-NULL if found
+ */
+struct ast_sip_contact_transport *ast_sip_location_retrieve_contact_transport_by_transport(pjsip_transport *transport);
 
 /*!
  * \brief Add a new contact to an AOR
@@ -621,7 +640,7 @@
  * \retval -1 failure
  * \retval 0 success
  */
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, pjsip_transport *transport);
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time);
 
 /*!
  * \brief Update a contact

Modified: team/qwell/fun_with_transports/res/res_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/res/res_sip.c?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/res/res_sip.c (original)
+++ team/qwell/fun_with_transports/res/res_sip.c Wed Apr 10 16:23:52 2013
@@ -328,6 +328,22 @@
 	return 0;
 }
 
+static int sip_get_tpselector_from_uri(const char *uri, pjsip_tpselector *selector)
+{
+	RAII_VAR(struct ast_sip_contact_transport *, contact_transport, NULL, ao2_cleanup);
+
+	contact_transport = ast_sip_location_retrieve_contact_transport_by_uri(uri);
+
+	if (!contact_transport) {
+		return -1;
+	}
+
+	selector->type = PJSIP_TPSELECTOR_TRANSPORT;
+	selector->u.transport = contact_transport->transport;
+
+	return 0;
+}
+
 pjsip_dialog *ast_sip_create_dialog(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user, pjsip_transport *request_transport)
 {
 	pj_str_t local_uri = { "sip:temp at temp", 13 }, remote_uri;
@@ -342,10 +358,7 @@
 		return NULL;
 	}
 
-	if (request_transport) {
-		/* Force a transport, if we're provided one. */
-		selector.type = PJSIP_TPSELECTOR_TRANSPORT;
-		selector.u.transport = request_transport;
+	if (!sip_get_tpselector_from_uri(uri, &selector)) {
 	} else if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
 		pjsip_dlg_terminate(dlg);
 		return NULL;
@@ -444,7 +457,7 @@
 	pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
 
 	if (ast_strlen_zero(uri)) {
-		contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors, NULL);
+		contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
 		if (!contact || ast_strlen_zero(contact->uri)) {
 			ast_log(LOG_ERROR, "Unable to retrieve contact for endpoint %s\n",
 					ast_sorcery_object_get_id(endpoint));

Modified: team/qwell/fun_with_transports/res/res_sip.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/res/res_sip.exports.in?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/res/res_sip.exports.in (original)
+++ team/qwell/fun_with_transports/res/res_sip.exports.in Wed Apr 10 16:23:52 2013
@@ -36,6 +36,8 @@
 		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact_from_aor_list;
 		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_aor_contacts;
 		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact;
+		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact_transport_by_uri;
+		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact_transport_by_transport;
 		LINKER_SYMBOL_PREFIXast_sip_location_add_contact;
 		LINKER_SYMBOL_PREFIXast_sip_location_update_contact;
 		LINKER_SYMBOL_PREFIXast_sip_location_delete_contact;

Modified: team/qwell/fun_with_transports/res/res_sip/location.c
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/res/res_sip/location.c?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/res/res_sip/location.c (original)
+++ team/qwell/fun_with_transports/res/res_sip/location.c Wed Apr 10 16:23:52 2013
@@ -64,6 +64,74 @@
 	return contact;
 }
 
+/*! \brief Destructor for contact_transport */
+static void contact_transport_destroy(void *obj)
+{
+	struct ast_sip_contact_transport *ct = obj;
+
+	ast_string_field_free_memory(ct);
+}
+
+static void *contact_transport_alloc(const char *name)
+{
+	struct ast_sip_contact_transport *ct = ao2_alloc_options(sizeof(*ct), contact_transport_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+
+	if (!ct) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(ct, 256)) {
+		ao2_cleanup(ct);
+		return NULL;
+	}
+
+	return ct;
+}
+
+/*! \brief Callback function for finding a contact_transport by URI */
+static int contact_transport_find_by_uri(void *obj, void *arg, int flags)
+{
+	struct ast_sip_contact_transport *ct = obj;
+	const char *contact_uri = arg;
+
+	return (!strcmp(ct->uri, contact_uri)) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+/*! \brief Callback function for finding a contact_transport by transport */
+static int contact_transport_find_by_transport(void *obj, void *arg, int flags)
+{
+	struct ast_sip_contact_transport *ct = obj;
+	pjsip_transport *transport = arg;
+
+	return (ct->transport == transport) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+struct ast_sip_contact_transport *ast_sip_location_retrieve_contact_transport_by_uri(const char *contact_uri)
+{
+	RAII_VAR(struct ao2_container *, cts, NULL, ao2_cleanup);
+	struct ast_sip_contact_transport *ct;
+
+	if (!(cts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact_transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
+		!(ct = ao2_callback(cts, 0, contact_transport_find_by_uri, (void *)contact_uri))) {
+		return NULL;
+	}
+
+	return ct;
+}
+
+struct ast_sip_contact_transport *ast_sip_location_retrieve_contact_transport_by_transport(pjsip_transport *transport)
+{
+	RAII_VAR(struct ao2_container *, cts, NULL, ao2_cleanup);
+	struct ast_sip_contact_transport *ct;
+
+	if (!(cts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact_transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
+		!(ct = ao2_callback(cts, 0, contact_transport_find_by_transport, transport))) {
+		return NULL;
+	}
+
+	return ct;
+}
+
 struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
 {
 	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
@@ -113,31 +181,6 @@
 	return contact;
 }
 
-static int contact_find_by_uri(void *obj, void *args, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	const char *uri = args;
-
-	if (!strcmp(contact->uri, uri)) {
-		return CMP_MATCH | CMP_STOP;
-	}
-	return 0;
-}
-
-struct ast_sip_contact *ast_sip_location_retrieve_aor_contact(const struct ast_sip_aor *aor, const char *contact_uri)
-{
-	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-	struct ast_sip_contact *contact;
-
-	contacts = ast_sip_location_retrieve_aor_contacts(aor);
-	if (!contacts || (ao2_container_count(contacts) == 0)) {
-		return NULL;
-	}
-
-	contact = ao2_callback(contacts, OBJ_NOLOCK, contact_find_by_uri, (void *)contact_uri);
-	return contact;
-}
-
 struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
 {
 	/* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
@@ -161,7 +204,7 @@
 	return contacts;
 }
 
-struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list, const char *contact_uri)
+struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
 {
 	char *aor_name;
 	char *rest;
@@ -180,11 +223,7 @@
 		if (!aor) {
 			continue;
 		}
-		if (!ast_strlen_zero(contact_uri)) {
-			contact = ast_sip_location_retrieve_aor_contact(aor, contact_uri);
-		} else {
-			contact = ast_sip_location_retrieve_first_aor_contact(aor);
-		}
+		contact = ast_sip_location_retrieve_first_aor_contact(aor);
 		/* If a valid contact is available use its URI for dialing */
 		if (contact) {
 			break;
@@ -199,7 +238,7 @@
 	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
 }
 
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, pjsip_transport *transport)
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time)
 {
 	char name[AST_UUID_STR_LEN];
 	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
@@ -212,7 +251,6 @@
 
 	ast_string_field_set(contact, uri, uri);
 	contact->expiration_time = expiration_time;
-	contact->transport = transport;
 
 	return ast_sorcery_create(ast_sip_get_sorcery(), contact);
 }
@@ -263,9 +301,11 @@
 {
 	ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar");
 	ast_sorcery_apply_default(sorcery, "aor", "config", "res_sip.conf,criteria=type=aor");
+	ast_sorcery_apply_default(sorcery, "contact_transport", "memory", NULL);
 
 	if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, NULL) ||
-		ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL)) {
+		ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL) ||
+		ast_sorcery_object_register(sorcery, "contact_transport", contact_transport_alloc, NULL, NULL)) {
 		return -1;
 	}
 
@@ -281,5 +321,7 @@
 	ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
 	ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, NULL, 0, 0);
 
+	ast_sorcery_object_field_register(sorcery, "contact_transport", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact_transport, uri));
+
 	return 0;
 }

Modified: team/qwell/fun_with_transports/res/res_sip_registrar.c
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/res/res_sip_registrar.c?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/res/res_sip_registrar.c (original)
+++ team/qwell/fun_with_transports/res/res_sip_registrar.c Wed Apr 10 16:23:52 2013
@@ -190,7 +190,6 @@
 	struct registrar_contact_details details = { 0, };
 	pjsip_tx_data *tdata;
 	pjsip_response_addr addr;
-	pjsip_transport *transport = NULL;
 
 	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
 		return PJ_FALSE;
@@ -205,10 +204,6 @@
 	if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
 		return PJ_TRUE;
-	}
-
-	if (!strcasecmp(rdata->tp_info.transport->type_name, "WS") || !strcasecmp(rdata->tp_info.transport->type_name, "WSS")) {
-		transport = rdata->tp_info.transport;
 	}
 
 	uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
@@ -303,14 +298,13 @@
 				continue;
 			}
 
-			ast_sip_location_add_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), transport);
+			ast_sip_location_add_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
 			ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
 				contact_uri, aor_name, expiration);
 		} else if (expiration) {
 			RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup);
 
 			updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
-			updated->transport = transport;
 
 			ast_sip_location_update_contact(updated);
 			ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",

Modified: team/qwell/fun_with_transports/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/res/res_sip_session.c?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/res/res_sip_session.c (original)
+++ team/qwell/fun_with_transports/res/res_sip_session.c Wed Apr 10 16:23:52 2013
@@ -976,26 +976,11 @@
 	/* If no location has been provided use the AOR list from the endpoint itself */
 	location = S_OR(location, endpoint->aors);
 
-	contact = ast_sip_location_retrieve_contact_from_aor_list(location, NULL);
-	if (contact && !ast_strlen_zero(contact->uri)) {
+	contact = ast_sip_location_retrieve_contact_from_aor_list(location);
+	if (!contact || ast_strlen_zero(contact->uri)) {
+		uri = location;
+	} else {
 		uri = contact->uri;
-		request_transport = contact->transport;
-	} else {
-		char *contact_uri;
-		char *rest = ast_strdupa(location);
-
-		while ((contact_uri = strsep(&rest, ","))) {
-			if ((contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors, contact_uri))) {
-				uri = contact->uri;
-				request_transport = contact->transport;
-				break;
-			}
-		}
-
-		/* If no URI was found using the provided AORs and contacts then use the location as provided as a last resort */
-		if (ast_strlen_zero(uri)) {
-			uri = location;
-		}
 	}
 
 	/* If we still have no URI to dial fail to create the session */

Modified: team/qwell/fun_with_transports/res/res_sip_transport_websocket.c
URL: http://svnview.digium.com/svn/asterisk/team/qwell/fun_with_transports/res/res_sip_transport_websocket.c?view=diff&rev=385268&r1=385267&r2=385268
==============================================================================
--- team/qwell/fun_with_transports/res/res_sip_transport_websocket.c (original)
+++ team/qwell/fun_with_transports/res/res_sip_transport_websocket.c Wed Apr 10 16:23:52 2013
@@ -41,17 +41,6 @@
 	struct ast_websocket *ws_session;
 };
 
-struct ws_create_data {
-	struct ws_transport *transport;
-	struct ast_websocket *ws_session;
-};
-
-struct ws_read_data {
-	struct ws_transport *transport;
-	char *payload;
-	uint64_t payload_len;
-};
-
 static pj_status_t ws_send_msg(pjsip_transport *transport,
                             pjsip_tx_data *tdata,
                             const pj_sockaddr_t *rem_addr,
@@ -90,14 +79,25 @@
 
 static int transport_shutdown(void *data)
 {
+	RAII_VAR(struct ast_sip_contact_transport *, ct, NULL, ao2_cleanup);
 	pjsip_transport *transport = data;
+
+	if ((ct = ast_sip_location_retrieve_contact_transport_by_transport(transport))) {
+		ast_sorcery_delete(ast_sip_get_sorcery(), ct);
+	}
+
 	pjsip_transport_shutdown(transport);
 	return 0;
 }
 
+struct transport_create_data {
+	struct ws_transport *transport;
+	struct ast_websocket *ws_session;
+};
+
 static int transport_create(void *data)
 {
-	struct ws_create_data *create_data = data;
+	struct transport_create_data *create_data = data;
 	struct ws_transport *newtransport;
 
 	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
@@ -115,13 +115,16 @@
 	pj_lock_create_recursive_mutex(pool, pool->obj_name, &newtransport->transport.lock);
 
 	newtransport->transport.pool = pool;
-	newtransport->transport.addr_len = sizeof(pj_sockaddr_in);
 	pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session))), &newtransport->transport.key.rem_addr);
 	newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET();
 	newtransport->transport.key.type = ast_websocket_is_secure(newtransport->ws_session) ? transport_type_wss : transport_type_ws;
 
+	newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr);
+
+	pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr);
+
 	newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, newtransport->transport.addr_len+4);
-	pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN+4, 0);
+	pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, newtransport->transport.addr_len+4, 0);
 	newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr);
 	newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr);
 
@@ -141,9 +144,15 @@
 	return 0;
 }
 
+struct transport_read_data {
+	struct ws_transport *transport;
+	char *payload;
+	uint64_t payload_len;
+};
+
 static int transport_read(void *data)
 {
-	struct ws_read_data *read_data = data;
+	struct transport_read_data *read_data = data;
 	struct ws_transport *newtransport = read_data->transport;
 	struct ast_websocket *session = newtransport->ws_session;
 
@@ -188,7 +197,7 @@
 	serializer = ast_sip_create_serializer();
 
 	while (ast_wait_for_input(ast_websocket_fd(session), -1) > 0) {
-		struct ws_read_data read_data;
+		struct transport_read_data read_data;
 		enum ast_websocket_opcode opcode;
 		int fragmented;
 
@@ -198,7 +207,7 @@
 
 		if (opcode == AST_WEBSOCKET_OPCODE_TEXT || opcode == AST_WEBSOCKET_OPCODE_BINARY) {
 			if (!transport) {
-				struct ws_create_data create_data;
+				struct transport_create_data create_data;
 				create_data.ws_session = session;
 
 				ast_sip_push_task_synchronous(serializer, transport_create, &create_data);
@@ -222,52 +231,107 @@
 	ast_websocket_unref(session);
 }
 
+#if 0
+/* XXX Probably not needed. */
 static int websocket_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 {
 	int type = rdata->tp_info.transport->key.type;
-	if (type == transport_type_ws || type == transport_type_wss) {
-		/* This is one of our transports.  We need to force it to use us on the dialog. */
+
+	if (type != transport_type_ws && type != transport_type_wss) {
+		return 0;
+	}
+
+	/* This is one of our transports.  We need to force it to use us on the dialog. */
+	pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_TRANSPORT, };
+
+	selector.u.transport = rdata->tp_info.transport;
+
+	pjsip_dlg_set_transport(session->inv_session->dlg, &selector);
+
+	return 0;
+}
+#endif
+
+static void websocket_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
+{
+	char contact_uri[PJSIP_MAX_URL_SIZE] = { 0, };
+	RAII_VAR(struct ast_sip_contact_transport *, ct, NULL, ao2_cleanup);
+
+	pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri, contact_uri, sizeof(contact_uri));
+
+	if ((ct = ast_sip_location_retrieve_contact_transport_by_uri(contact_uri))) {
 		pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_TRANSPORT, };
 
-		selector.u.transport = rdata->tp_info.transport;
-
-		pjsip_dlg_set_transport(session->inv_session->dlg, &selector);
-	}
-	return 0;
-}
-
-static void websocket_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	struct pjsip_transport *transport = (struct pjsip_transport*)session->inv_session->dlg->tp_sel.u.transport;
-
-	if (transport->key.type == transport_type_ws || transport->key.type == transport_type_wss) {
-		/* Avoid DNS resolution, so it doesn't try to resolve a bogus address. */
+		selector.u.transport = ct->transport;
+
+		pjsip_tx_data_set_transport(tdata, &selector);
+
 		tdata->dest_info.addr.count = 1;
-		tdata->dest_info.addr.entry[0].type = transport->key.type;
-		tdata->dest_info.addr.entry[0].addr = transport->key.rem_addr;
-		tdata->dest_info.addr.entry[0].addr_len = transport->addr_len;
+		tdata->dest_info.addr.entry[0].type = ct->transport->key.type;
+		tdata->dest_info.addr.entry[0].addr = ct->transport->key.rem_addr;
+		tdata->dest_info.addr.entry[0].addr_len = ct->transport->addr_len;
 	}
 }
 
 static struct ast_sip_session_supplement websocket_supplement = {
-	.incoming_request = websocket_incoming_request,
 	.outgoing_request = websocket_outgoing_request,
 };
 
+static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata)
+{
+	pjsip_contact_hdr *contact_hdr = NULL;
+
+	int type = rdata->tp_info.transport->key.type;
+
+	if (type != transport_type_ws && type != transport_type_wss) {
+		return 0;
+	}
+	
+	if ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL))) {
+		RAII_VAR(struct ast_sip_contact_transport *, ct, NULL, ao2_cleanup);
+		char contact_uri[PJSIP_MAX_URL_SIZE];
+
+		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, pjsip_uri_get_uri(contact_hdr->uri), contact_uri, sizeof(contact_uri));
+
+		if ((ct = ast_sip_location_retrieve_contact_transport_by_uri(contact_uri))) {
+			RAII_VAR(struct ast_sip_contact_transport *, ct_copy, ast_sorcery_copy(ast_sip_get_sorcery(), ct), ao2_cleanup);
+			ct_copy->transport = rdata->tp_info.transport;
+			ast_sorcery_update(ast_sip_get_sorcery(), ct_copy);
+		} else {
+			ct = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact_transport", NULL);
+			ast_string_field_set(ct, uri, contact_uri);
+			ct->transport = rdata->tp_info.transport;
+			ast_sorcery_create(ast_sip_get_sorcery(), ct);
+		}
+	}
+
+	return 0;
+}
+
+static pjsip_module websocket_module = {
+	.name = { "WebSocket Transport Module", 26 },
+	.priority = 0,
+	.on_rx_request = websocket_on_rx_msg,
+};
+
 static int load_module(void)
 {
-	ast_websocket_add_protocol("sip", websocket_cb);
-
 	pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WS", 5060, &transport_type_ws);
 	pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WSS", 5060, &transport_type_wss);
 
 	ast_sip_session_register_supplement(&websocket_supplement);
+	ast_sip_register_service(&websocket_module);
+
+	ast_websocket_add_protocol("sip", websocket_cb);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 static int unload_module(void)
 {
+	ast_sip_unregister_service(&websocket_module);
+	ast_websocket_remove_protocol("sip", websocket_cb);
+
 	return 0;
 }
 




More information about the asterisk-commits mailing list