Merge "Fix ast_(v)asprintf() malloc failure usage conditions."
[asterisk/asterisk.git] / res / res_pjsip_transport_websocket.c
index a52b42d..22ec195 100644 (file)
@@ -39,6 +39,7 @@
 #include "asterisk/taskprocessor.h"
 
 static int transport_type_wss;
+static int transport_type_wss_ipv6;
 
 /*!
  * \brief Wrapper for pjsip_transport, for storing the WebSocket session
@@ -144,6 +145,7 @@ static int transport_create(void *data)
 {
        struct transport_create_data *create_data = data;
        struct ws_transport *newtransport = NULL;
+       pjsip_tp_state_callback state_cb;
 
        pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
        struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt);
@@ -160,6 +162,10 @@ static int transport_create(void *data)
                goto on_error;
        }
 
+       /* Give websocket transport a unique name for its lifetime */
+       snprintf(newtransport->transport.obj_name, PJ_MAX_OBJ_NAME, "ws%p",
+               &newtransport->transport);
+
        newtransport->transport.endpt = endpt;
 
        if (!(pool = pjsip_endpt_create_pool(endpt, "ws", 512, 512))) {
@@ -198,21 +204,27 @@ static int transport_create(void *data)
                newtransport->transport.type_name, ws_addr_str);
 
        pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr);
-       newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET();
-       newtransport->transport.key.type = transport_type_wss;
+       if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) {
+               newtransport->transport.key.type = transport_type_wss_ipv6;
+               newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN);
+               pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN, 0);
+       } else {
+               newtransport->transport.key.type = transport_type_wss;
+               newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET_ADDRSTRLEN);
+               pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET_ADDRSTRLEN, 0);
+       }
 
        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, 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);
 
        newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type);
        newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64);
 
+       newtransport->transport.dir = PJSIP_TP_DIR_INCOMING;
        newtransport->transport.tpmgr = tpmgr;
        newtransport->transport.send_msg = &ws_send_msg;
        newtransport->transport.destroy = &ws_destroy;
@@ -236,6 +248,16 @@ static int transport_create(void *data)
        }
 
        create_data->transport = newtransport;
+
+       /* Notify application of transport state */
+       state_cb = pjsip_tpmgr_get_state_cb(newtransport->transport.tpmgr);
+       if (state_cb) {
+               pjsip_transport_state_info state_info;
+
+               memset(&state_info, 0, sizeof(state_info));
+               state_cb(&newtransport->transport, PJSIP_TP_STATE_CONNECTED, &state_info);
+       }
+
        return 0;
 
 on_error:
@@ -271,8 +293,6 @@ static int transport_read(void *data)
        rdata->pkt_info.zero = 0;
 
        pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(session))), &rdata->pkt_info.src_addr);
-       rdata->pkt_info.src_addr.addr.sa_family = pj_AF_INET();
-
        rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr);
 
        pj_ansi_strcpy(rdata->pkt_info.src_name, ast_sockaddr_stringify_host(ast_websocket_remote_address(session)));
@@ -298,10 +318,14 @@ static int get_write_timeout(void)
 
                for (; (transport_state = ao2_iterator_next(&it_transport_states)); ao2_cleanup(transport_state)) {
                        struct ast_sip_transport *transport;
+
                        if (transport_state->type != AST_TRANSPORT_WS && transport_state->type != AST_TRANSPORT_WSS) {
                                continue;
                        }
                        transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id);
+                       if (!transport) {
+                               continue;
+                       }
                        ast_debug(5, "Found %s transport with write timeout: %d\n",
                                transport->type == AST_TRANSPORT_WS ? "WS" : "WSS",
                                transport->write_timeout);
@@ -357,6 +381,7 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par
 
        if (ast_sip_push_task_synchronous(serializer, transport_create, &create_data)) {
                ast_log(LOG_ERROR, "Could not create WebSocket transport.\n");
+               ast_taskprocessor_unreference(serializer);
                ast_websocket_unref(session);
                return;
        }
@@ -395,7 +420,7 @@ static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata)
 
        long type = rdata->tp_info.transport->key.type;
 
-       if (type != (long) transport_type_wss) {
+       if (type != (long) transport_type_wss && type != (long) transport_type_wss_ipv6) {
                return PJ_FALSE;
        }
 
@@ -451,15 +476,17 @@ static int load_module(void)
        CHECK_PJSIP_MODULE_LOADED();
 
        /*
-        * We only need one transport type defined.  Firefox and Chrome
-        * do not support anything other than secure websockets anymore.
+        * We only need one transport type name (ws) defined.  Firefox
+        * and Chrome do not support anything other than secure websockets
+        * anymore.
         *
         * Also we really cannot have two transports with the same name
-        * because it would be ambiguous.  Outgoing requests may try to
-        * find the transport by name and pjproject only finds the first
-        * one registered.
+        * and address family because it would be ambiguous.  Outgoing
+        * requests may try to find the transport by name and pjproject
+        * only finds the first one registered.
         */
        pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "ws", 5060, &transport_type_wss);
+       pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_IPV6, "ws", 5060, &transport_type_wss_ipv6);
 
        if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) {
                return AST_MODULE_LOAD_DECLINE;