diff options
author | Mamadou DIOP <bossiel@yahoo.fr> | 2016-02-23 22:00:35 +0100 |
---|---|---|
committer | Mamadou DIOP <bossiel@yahoo.fr> | 2016-02-23 22:00:35 +0100 |
commit | 50dfb4359619563012997bc3ddafb7667741066c (patch) | |
tree | db234c1edc3240a653363b5735fc4077af4b8720 /tinySIP/src/transports/tsip_transport_layer.c | |
parent | 94b2219209038e05dd26395f6fb700be4d1062c0 (diff) | |
download | doubango-50dfb4359619563012997bc3ddafb7667741066c.zip doubango-50dfb4359619563012997bc3ddafb7667741066c.tar.gz |
Add new QoS implementation
Code formatting
Diffstat (limited to 'tinySIP/src/transports/tsip_transport_layer.c')
-rwxr-xr-x | tinySIP/src/transports/tsip_transport_layer.c | 2408 |
1 files changed, 1200 insertions, 1208 deletions
diff --git a/tinySIP/src/transports/tsip_transport_layer.c b/tinySIP/src/transports/tsip_transport_layer.c index 93668b9..fc01c0e 100755 --- a/tinySIP/src/transports/tsip_transport_layer.c +++ b/tinySIP/src/transports/tsip_transport_layer.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org> -* +* * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. -* +* * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* +* * You should have received a copy of the GNU General Public License * along with DOUBANGO. * @@ -60,1199 +60,1190 @@ extern tsip_event_t* tsip_event_create(tsip_ssession_t* ss, short code, const ch tsip_transport_layer_t* tsip_transport_layer_create(tsip_stack_t *stack) { - return tsk_object_new(tsip_transport_layer_def_t, stack); + return tsk_object_new(tsip_transport_layer_def_t, stack); } const tsip_transport_t* tsip_transport_layer_find_by_type(const tsip_transport_layer_t* self, tnet_socket_type_t type) { - const tsk_list_item_t *item; - const tsip_transport_t* transport = tsk_null; + const tsk_list_item_t *item; + const tsip_transport_t* transport = tsk_null; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } - tsk_list_lock(self->transports); + tsk_list_lock(self->transports); - tsk_list_foreach(item, self->transports){ - if(((const tsip_transport_t*)item->data)->type == type){ - transport = ((const tsip_transport_t*)item->data); - break; - } - } + tsk_list_foreach(item, self->transports) { + if(((const tsip_transport_t*)item->data)->type == type) { + transport = ((const tsip_transport_t*)item->data); + break; + } + } - tsk_list_unlock(self->transports); + tsk_list_unlock(self->transports); - return transport; + return transport; } const tsip_transport_t* tsip_transport_layer_find_by_idx(const tsip_transport_layer_t* self, int32_t idx) { - const tsk_list_item_t *item; - const tsip_transport_t* transport = tsk_null; + const tsk_list_item_t *item; + const tsip_transport_t* transport = tsk_null; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } - tsk_list_lock(self->transports); + tsk_list_lock(self->transports); - tsk_list_foreach(item, self->transports){ - if(((const tsip_transport_t*)item->data)->idx == idx){ - transport = ((const tsip_transport_t*)item->data); - break; - } - } + tsk_list_foreach(item, self->transports) { + if(((const tsip_transport_t*)item->data)->idx == idx) { + transport = ((const tsip_transport_t*)item->data); + break; + } + } - tsk_list_unlock(self->transports); + tsk_list_unlock(self->transports); - return transport; + return transport; } int tsip_transport_layer_handle_incoming_msg(const tsip_transport_t *transport, tsip_message_t *message) { - int ret = -1; - - if(message){ - const tsip_transac_layer_t *layer_transac = transport->stack->layer_transac; - const tsip_dialog_layer_t *layer_dialog = transport->stack->layer_dialog; - - if((ret = tsip_transac_layer_handle_incoming_msg(layer_transac, message))){ - /* NO MATCHING TRANSACTION FOUND ==> LOOK INTO DIALOG LAYER */ - ret = tsip_dialog_layer_handle_incoming_msg(layer_dialog, message); - } - } - return ret; + int ret = -1; + + if(message) { + const tsip_transac_layer_t *layer_transac = transport->stack->layer_transac; + const tsip_dialog_layer_t *layer_dialog = transport->stack->layer_dialog; + + if((ret = tsip_transac_layer_handle_incoming_msg(layer_transac, message))) { + /* NO MATCHING TRANSACTION FOUND ==> LOOK INTO DIALOG LAYER */ + ret = tsip_dialog_layer_handle_incoming_msg(layer_dialog, message); + } + } + return ret; } /*== Non-blocking callback function (STREAM: TCP, TLS and SCTP) */ static int tsip_transport_layer_stream_cb(const tnet_transport_event_t* e) { - int ret = -1; - tsk_ragel_state_t state; - tsip_message_t *message = tsk_null; - int endOfheaders = -1; - tsip_transport_t *transport = (tsip_transport_t *)e->callback_data; - tsip_transport_stream_peer_t* peer; - - switch(e->type){ - case event_data: { - TSK_DEBUG_INFO("\n\nRECV:%.*s\n\n", e->size, (const char*)e->data); - break; - } - case event_closed: - case event_error: - case event_removed: - { - tsip_transport_stream_peer_t* peer; - TSK_DEBUG_INFO("Stream Peer closed - %d", e->local_fd); - // signal "peer disconnected" before "stack disconnected" - if((peer = tsip_transport_pop_stream_peer_by_local_fd(transport, e->local_fd))){ - tsip_dialog_layer_signal_peer_disconnected(TSIP_STACK(transport->stack)->layer_dialog, peer); - TSK_OBJECT_SAFE_FREE(peer); - } - else { - TSK_DEBUG_INFO("Closed peer with fd=%d not registered yet", e->local_fd); + int ret = -1; + tsk_ragel_state_t state; + tsip_message_t *message = tsk_null; + int endOfheaders = -1; + tsip_transport_t *transport = (tsip_transport_t *)e->callback_data; + tsip_transport_stream_peer_t* peer; + + switch(e->type) { + case event_data: { + TSK_DEBUG_INFO("\n\nRECV:%.*s\n\n", e->size, (const char*)e->data); + break; + } + case event_closed: + case event_error: + case event_removed: { + tsip_transport_stream_peer_t* peer; + TSK_DEBUG_INFO("Stream Peer closed - %d", e->local_fd); + // signal "peer disconnected" before "stack disconnected" + if((peer = tsip_transport_pop_stream_peer_by_local_fd(transport, e->local_fd))) { + tsip_dialog_layer_signal_peer_disconnected(TSIP_STACK(transport->stack)->layer_dialog, peer); + TSK_OBJECT_SAFE_FREE(peer); + } + else { + TSK_DEBUG_INFO("Closed peer with fd=%d not registered yet", e->local_fd); + } + // connectedFD== master's fd for servers + if(transport->connectedFD == e->local_fd || transport->connectedFD == TNET_INVALID_FD) { + TSK_DEBUG_INFO("SIP 'connectedFD' (%d) closed", transport->connectedFD); + if(transport->stack) { + tsip_event_t* e; + // signal to all dialogs that transport error raised + tsip_dialog_layer_signal_stack_disconnected(TSIP_STACK(transport->stack)->layer_dialog); + // signal to the end-user that the stack is disconnected + if((e = tsip_event_create(tsk_null, tsip_event_code_stack_disconnected, "Stack disconnected", tsk_null, tsip_event_stack))) { + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport->stack), e); } - // connectedFD== master's fd for servers - if(transport->connectedFD == e->local_fd || transport->connectedFD == TNET_INVALID_FD){ - TSK_DEBUG_INFO("SIP 'connectedFD' (%d) closed", transport->connectedFD); - if(transport->stack){ - tsip_event_t* e; - // signal to all dialogs that transport error raised - tsip_dialog_layer_signal_stack_disconnected(TSIP_STACK(transport->stack)->layer_dialog); - // signal to the end-user that the stack is disconnected - if((e = tsip_event_create(tsk_null, tsip_event_code_stack_disconnected, "Stack disconnected", tsk_null, tsip_event_stack))){ - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport->stack), e); - } - } - transport->connectedFD = TNET_INVALID_FD; - } - return 0; - } - case event_connected: - case event_accepted: - { - tsip_transport_stream_peer_t* peer; - TSK_DEBUG_INFO("Stream Peer accepted/connected - %d", e->local_fd); - // find peer - if((peer = tsip_transport_find_stream_peer_by_local_fd(transport, e->local_fd))){ - peer->connected = tsk_true; - if(peer->snd_buff_stream->data && peer->snd_buff_stream->size > 0){ // is there pending outgoing data postponed until socket get connected? - tnet_transport_send(transport->net_transport, peer->local_fd, peer->snd_buff_stream->data, peer->snd_buff_stream->size); - tsk_buffer_cleanup(peer->snd_buff_stream); - } - TSK_OBJECT_SAFE_FREE(peer); - } - else{ - // on iOS (cfsocket implementation) opening the master stream raise "connected" callback which is not correct. - // Ignoring the socket is not a problem as we'll get a callback event ("accepted") when a client connects to the master. - // The master cannot raise "connected" even as it's already in "listening" state + } + transport->connectedFD = TNET_INVALID_FD; + } + return 0; + } + case event_connected: + case event_accepted: { + tsip_transport_stream_peer_t* peer; + TSK_DEBUG_INFO("Stream Peer accepted/connected - %d", e->local_fd); + // find peer + if((peer = tsip_transport_find_stream_peer_by_local_fd(transport, e->local_fd))) { + peer->connected = tsk_true; + if(peer->snd_buff_stream->data && peer->snd_buff_stream->size > 0) { // is there pending outgoing data postponed until socket get connected? + tnet_transport_send(transport->net_transport, peer->local_fd, peer->snd_buff_stream->data, peer->snd_buff_stream->size); + tsk_buffer_cleanup(peer->snd_buff_stream); + } + TSK_OBJECT_SAFE_FREE(peer); + } + else { + // on iOS (cfsocket implementation) opening the master stream raise "connected" callback which is not correct. + // Ignoring the socket is not a problem as we'll get a callback event ("accepted") when a client connects to the master. + // The master cannot raise "connected" even as it's already in "listening" state #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000) - if(tnet_transport_get_master_fd(transport->net_transport) == e->local_fd){ - return 0; - } + if(tnet_transport_get_master_fd(transport->net_transport) == e->local_fd) { + return 0; + } #endif - return tsip_transport_add_stream_peer(transport, e->local_fd, transport->type, tsk_true); - } - } - default:{ - return 0; - } - } - - if(!(peer = tsip_transport_find_stream_peer_by_local_fd(transport, e->local_fd))){ - TSK_DEBUG_ERROR("Failed to find peer with local fd equal to %d", e->local_fd); - return -1; - } - - /* Update latest time activity */ - peer->time_latest_activity = tsk_time_now(); - - /* RFC 3261 - 7.5 Framing SIP Messages - - Unlike HTTP, SIP implementations can use UDP or other unreliable - datagram protocols. Each such datagram carries one request or - response. See Section 18 on constraints on usage of unreliable - transports. - - Implementations processing SIP messages over stream-oriented - transports MUST ignore any CRLF appearing before the start-line - [H4.1]. - - The Content-Length header field value is used to locate the end of - each SIP message in a stream. It will always be present when SIP - messages are sent over stream-oriented transports. - */ - - /* Check if buffer is too big to be valid (have we missed some chuncks?) */ - if(TSK_BUFFER_SIZE(peer->rcv_buff_stream) >= TSIP_MAX_STREAM_CHUNCK_SIZE){ - TSK_DEBUG_ERROR("TCP Buffer is too big to be valid"); - tsk_buffer_cleanup(peer->rcv_buff_stream); - } - - /* === SigComp === */ - if(TSIP_IS_SIGCOMP_DATA(e->data)){ - char SigCompBuffer[TSIP_SIGCOMP_MAX_BUFF_SIZE]; - //====== FIXME: This implmentation will always use the first SigComp-Id for decompression ===== - tsk_bool_t is_nack; - const char* comp_id; - void* nack_data = tsk_null; - tsk_size_t data_size, next_size; - - // First Pass - comp_id = tsip_sigcomp_handler_fixme_getcompid(transport->stack->sigcomp.handle); - data_size = tsip_sigcomp_handler_uncompressTCP(transport->stack->sigcomp.handle, comp_id, e->data, e->size, SigCompBuffer, sizeof(SigCompBuffer), &is_nack); - - if(data_size){ - if(is_nack){ - tsip_transport_send_raw(transport, tsk_null, 0, SigCompBuffer, data_size, __null_callid); - } - else{ - // append result - tsk_buffer_append(peer->rcv_buff_stream, SigCompBuffer, data_size); - } - } - else{ /* Partial message? */ - TSK_DEBUG_ERROR("SigComp decompression has failed"); - return 0; - } - // Query for all other chuncks - while((next_size = tsip_sigcomp_handler_uncompress_next(transport->stack->sigcomp.handle, comp_id, &nack_data, &is_nack)) || nack_data){ - if(is_nack){ - tsip_transport_send_raw(transport, tsk_null, 0, nack_data, next_size, __null_callid); - TSK_FREE(nack_data); - } - else{ - // append result - tsk_buffer_append(peer->rcv_buff_stream, SigCompBuffer, (next_size - data_size)); - data_size = next_size; - } - } - } - else{ - /* Append new content. */ - tsk_buffer_append(peer->rcv_buff_stream, e->data, e->size); - } - - /* Check if we have all SIP/WS headers. */ + return tsip_transport_add_stream_peer(transport, e->local_fd, transport->type, tsk_true); + } + } + default: { + return 0; + } + } + + if(!(peer = tsip_transport_find_stream_peer_by_local_fd(transport, e->local_fd))) { + TSK_DEBUG_ERROR("Failed to find peer with local fd equal to %d", e->local_fd); + return -1; + } + + /* Update latest time activity */ + peer->time_latest_activity = tsk_time_now(); + + /* RFC 3261 - 7.5 Framing SIP Messages + + Unlike HTTP, SIP implementations can use UDP or other unreliable + datagram protocols. Each such datagram carries one request or + response. See Section 18 on constraints on usage of unreliable + transports. + + Implementations processing SIP messages over stream-oriented + transports MUST ignore any CRLF appearing before the start-line + [H4.1]. + + The Content-Length header field value is used to locate the end of + each SIP message in a stream. It will always be present when SIP + messages are sent over stream-oriented transports. + */ + + /* Check if buffer is too big to be valid (have we missed some chuncks?) */ + if(TSK_BUFFER_SIZE(peer->rcv_buff_stream) >= TSIP_MAX_STREAM_CHUNCK_SIZE) { + TSK_DEBUG_ERROR("TCP Buffer is too big to be valid"); + tsk_buffer_cleanup(peer->rcv_buff_stream); + } + + /* === SigComp === */ + if(TSIP_IS_SIGCOMP_DATA(e->data)) { + char SigCompBuffer[TSIP_SIGCOMP_MAX_BUFF_SIZE]; + //====== FIXME: This implmentation will always use the first SigComp-Id for decompression ===== + tsk_bool_t is_nack; + const char* comp_id; + void* nack_data = tsk_null; + tsk_size_t data_size, next_size; + + // First Pass + comp_id = tsip_sigcomp_handler_fixme_getcompid(transport->stack->sigcomp.handle); + data_size = tsip_sigcomp_handler_uncompressTCP(transport->stack->sigcomp.handle, comp_id, e->data, e->size, SigCompBuffer, sizeof(SigCompBuffer), &is_nack); + + if(data_size) { + if(is_nack) { + tsip_transport_send_raw(transport, tsk_null, 0, SigCompBuffer, data_size, __null_callid); + } + else { + // append result + tsk_buffer_append(peer->rcv_buff_stream, SigCompBuffer, data_size); + } + } + else { /* Partial message? */ + TSK_DEBUG_ERROR("SigComp decompression has failed"); + return 0; + } + // Query for all other chuncks + while((next_size = tsip_sigcomp_handler_uncompress_next(transport->stack->sigcomp.handle, comp_id, &nack_data, &is_nack)) || nack_data) { + if(is_nack) { + tsip_transport_send_raw(transport, tsk_null, 0, nack_data, next_size, __null_callid); + TSK_FREE(nack_data); + } + else { + // append result + tsk_buffer_append(peer->rcv_buff_stream, SigCompBuffer, (next_size - data_size)); + data_size = next_size; + } + } + } + else { + /* Append new content. */ + tsk_buffer_append(peer->rcv_buff_stream, e->data, e->size); + } + + /* Check if we have all SIP/WS headers. */ parse_buffer: - if((endOfheaders = tsk_strindexOf(TSK_BUFFER_DATA(peer->rcv_buff_stream),TSK_BUFFER_SIZE(peer->rcv_buff_stream), "\r\n\r\n"/*2CRLF*/)) < 0){ - TSK_DEBUG_INFO("No all SIP headers in the TCP buffer."); - goto bail; - } - - /* If we are there this mean that we have all SIP headers. - * ==> Parse the SIP message without the content. - */ - tsk_ragel_state_init(&state, TSK_BUFFER_DATA(peer->rcv_buff_stream), endOfheaders + 4/*2CRLF*/); - if(tsip_message_parse(&state, &message, tsk_false/* do not extract the content */) == tsk_true){ - tsk_size_t clen = TSIP_MESSAGE_CONTENT_LENGTH(message); /* MUST have content-length header (see RFC 3261 - 7.5). If no CL header then the macro return zero. */ - if(clen == 0){ /* No content */ - tsk_buffer_remove(peer->rcv_buff_stream, 0, (endOfheaders + 4/*2CRLF*/)); /* Remove SIP headers and CRLF */ - } - else{ /* There is a content */ - if((endOfheaders + 4/*2CRLF*/ + clen) > TSK_BUFFER_SIZE(peer->rcv_buff_stream)){ /* There is content but not all the content. */ - TSK_DEBUG_INFO("No all SIP content in the TCP buffer (clen=%u and %u > %u).", clen, (endOfheaders + 4/*2CRLF*/ + clen), TSK_BUFFER_SIZE(peer->rcv_buff_stream)); - goto bail; - } - else{ - /* Add the content to the message. */ - tsip_message_add_content(message, tsk_null, TSK_BUFFER_TO_U8(peer->rcv_buff_stream) + endOfheaders + 4/*2CRLF*/, clen); - /* Remove SIP headers, CRLF and the content. */ - tsk_buffer_remove(peer->rcv_buff_stream, 0, (endOfheaders + 4/*2CRLF*/ + clen)); - } - } - } - else { - TSK_DEBUG_ERROR("Failed to parse pending stream....reset buffer"); - tsk_buffer_cleanup(peer->rcv_buff_stream); - } - - if(message && message->firstVia && message->Call_ID && message->CSeq && message->From && message->To){ - /* Signal we got at least one valid SIP message */ - peer->got_valid_sip_msg = tsk_true; - /* Set fd */ - message->local_fd = e->local_fd; - message->src_net_type = transport->type; - /* Alert transaction/dialog layer */ - ret = tsip_transport_layer_handle_incoming_msg(transport, message); - /* Parse next chunck */ - if(TSK_BUFFER_SIZE(peer->rcv_buff_stream) >= TSIP_MIN_STREAM_CHUNCK_SIZE){ - /* message already passed to the dialog/transac layers */ - TSK_OBJECT_SAFE_FREE(message); - goto parse_buffer; - } - } - else{ - TSK_DEBUG_ERROR("Failed to parse SIP message"); - ret = -15; - } + if((endOfheaders = tsk_strindexOf(TSK_BUFFER_DATA(peer->rcv_buff_stream),TSK_BUFFER_SIZE(peer->rcv_buff_stream), "\r\n\r\n"/*2CRLF*/)) < 0) { + TSK_DEBUG_INFO("No all SIP headers in the TCP buffer."); + goto bail; + } + + /* If we are there this mean that we have all SIP headers. + * ==> Parse the SIP message without the content. + */ + tsk_ragel_state_init(&state, TSK_BUFFER_DATA(peer->rcv_buff_stream), endOfheaders + 4/*2CRLF*/); + if(tsip_message_parse(&state, &message, tsk_false/* do not extract the content */) == tsk_true) { + tsk_size_t clen = TSIP_MESSAGE_CONTENT_LENGTH(message); /* MUST have content-length header (see RFC 3261 - 7.5). If no CL header then the macro return zero. */ + if(clen == 0) { /* No content */ + tsk_buffer_remove(peer->rcv_buff_stream, 0, (endOfheaders + 4/*2CRLF*/)); /* Remove SIP headers and CRLF */ + } + else { /* There is a content */ + if((endOfheaders + 4/*2CRLF*/ + clen) > TSK_BUFFER_SIZE(peer->rcv_buff_stream)) { /* There is content but not all the content. */ + TSK_DEBUG_INFO("No all SIP content in the TCP buffer (clen=%u and %u > %u).", clen, (endOfheaders + 4/*2CRLF*/ + clen), TSK_BUFFER_SIZE(peer->rcv_buff_stream)); + goto bail; + } + else { + /* Add the content to the message. */ + tsip_message_add_content(message, tsk_null, TSK_BUFFER_TO_U8(peer->rcv_buff_stream) + endOfheaders + 4/*2CRLF*/, clen); + /* Remove SIP headers, CRLF and the content. */ + tsk_buffer_remove(peer->rcv_buff_stream, 0, (endOfheaders + 4/*2CRLF*/ + clen)); + } + } + } + else { + TSK_DEBUG_ERROR("Failed to parse pending stream....reset buffer"); + tsk_buffer_cleanup(peer->rcv_buff_stream); + } + + if(message && message->firstVia && message->Call_ID && message->CSeq && message->From && message->To) { + /* Signal we got at least one valid SIP message */ + peer->got_valid_sip_msg = tsk_true; + /* Set fd */ + message->local_fd = e->local_fd; + message->src_net_type = transport->type; + /* Alert transaction/dialog layer */ + ret = tsip_transport_layer_handle_incoming_msg(transport, message); + /* Parse next chunck */ + if(TSK_BUFFER_SIZE(peer->rcv_buff_stream) >= TSIP_MIN_STREAM_CHUNCK_SIZE) { + /* message already passed to the dialog/transac layers */ + TSK_OBJECT_SAFE_FREE(message); + goto parse_buffer; + } + } + else { + TSK_DEBUG_ERROR("Failed to parse SIP message"); + ret = -15; + } bail: - TSK_OBJECT_SAFE_FREE(message); - TSK_OBJECT_SAFE_FREE(peer); + TSK_OBJECT_SAFE_FREE(message); + TSK_OBJECT_SAFE_FREE(peer); - return ret; + return ret; } /*== Non-blocking callback function (STREAM: WS, WSS) */ static int tsip_transport_layer_ws_cb(const tnet_transport_event_t* e) { - int ret = -1; - tsk_ragel_state_t state; - tsip_message_t *message = tsk_null; - int endOfheaders = -1; - tsip_transport_t *transport = (tsip_transport_t *)e->callback_data; - tsk_bool_t check_end_of_hdrs = tsk_true; - tsk_bool_t go_message = tsk_false; - uint64_t data_len = 0; - uint64_t pay_len = 0; - tsip_transport_stream_peer_t* peer; - - switch(e->type){ - case event_data: { - break; - } - case event_closed: - case event_error: - case event_removed: - { - tsip_transport_stream_peer_t* peer; - TSK_DEBUG_INFO("WebSocket Peer closed with fd = %d", e->local_fd); - if((peer = tsip_transport_pop_stream_peer_by_local_fd(transport, e->local_fd))){ - tsip_dialog_layer_signal_peer_disconnected(TSIP_STACK(transport->stack)->layer_dialog, peer); - TSK_OBJECT_SAFE_FREE(peer); - } - return 0; - } - case event_accepted: - case event_connected: - { - TSK_DEBUG_INFO("WebSocket Peer accepted/connected with fd = %d", e->local_fd); - return tsip_transport_add_stream_peer(transport, e->local_fd, transport->type, tsk_true); - } - default:{ - return 0; - } - } - - if(!(peer = tsip_transport_find_stream_peer_by_local_fd(transport, e->local_fd))){ - TSK_DEBUG_ERROR("Failed to find peer with local fd equal to %d", e->local_fd); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - return -1; - } - - /* Update latest time activity */ - peer->time_latest_activity = tsk_time_now(); - - /* Check if buffer is too big to be valid (have we missed some chuncks?) */ - if((TSK_BUFFER_SIZE(peer->rcv_buff_stream) + e->size) >= TSIP_MAX_STREAM_CHUNCK_SIZE){ - TSK_DEBUG_ERROR("TCP Buffer is too big to be valid"); - tsk_buffer_cleanup(peer->rcv_buff_stream); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - - // Append new content - tsk_buffer_append(peer->rcv_buff_stream, e->data, e->size); - - /* Check if WebSocket data */ - if(peer->rcv_buff_stream->size > 4){ - const uint8_t* pdata = (const uint8_t*)peer->rcv_buff_stream->data; - tsk_bool_t is_GET = (pdata[0] == 'G' && pdata[1] == 'E' && pdata[2] == 'T'); - if (!peer->ws.handshaking_done && !is_GET) { - TSK_DEBUG_ERROR("WS handshaking not done yet"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - check_end_of_hdrs = is_GET; - } - - /* Check if we have all HTTP/SIP/WS headers. */ + int ret = -1; + tsk_ragel_state_t state; + tsip_message_t *message = tsk_null; + int endOfheaders = -1; + tsip_transport_t *transport = (tsip_transport_t *)e->callback_data; + tsk_bool_t check_end_of_hdrs = tsk_true; + tsk_bool_t go_message = tsk_false; + uint64_t data_len = 0; + uint64_t pay_len = 0; + tsip_transport_stream_peer_t* peer; + + switch(e->type) { + case event_data: { + break; + } + case event_closed: + case event_error: + case event_removed: { + tsip_transport_stream_peer_t* peer; + TSK_DEBUG_INFO("WebSocket Peer closed with fd = %d", e->local_fd); + if((peer = tsip_transport_pop_stream_peer_by_local_fd(transport, e->local_fd))) { + tsip_dialog_layer_signal_peer_disconnected(TSIP_STACK(transport->stack)->layer_dialog, peer); + TSK_OBJECT_SAFE_FREE(peer); + } + return 0; + } + case event_accepted: + case event_connected: { + TSK_DEBUG_INFO("WebSocket Peer accepted/connected with fd = %d", e->local_fd); + return tsip_transport_add_stream_peer(transport, e->local_fd, transport->type, tsk_true); + } + default: { + return 0; + } + } + + if(!(peer = tsip_transport_find_stream_peer_by_local_fd(transport, e->local_fd))) { + TSK_DEBUG_ERROR("Failed to find peer with local fd equal to %d", e->local_fd); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + return -1; + } + + /* Update latest time activity */ + peer->time_latest_activity = tsk_time_now(); + + /* Check if buffer is too big to be valid (have we missed some chuncks?) */ + if((TSK_BUFFER_SIZE(peer->rcv_buff_stream) + e->size) >= TSIP_MAX_STREAM_CHUNCK_SIZE) { + TSK_DEBUG_ERROR("TCP Buffer is too big to be valid"); + tsk_buffer_cleanup(peer->rcv_buff_stream); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + + // Append new content + tsk_buffer_append(peer->rcv_buff_stream, e->data, e->size); + + /* Check if WebSocket data */ + if(peer->rcv_buff_stream->size > 4) { + const uint8_t* pdata = (const uint8_t*)peer->rcv_buff_stream->data; + tsk_bool_t is_GET = (pdata[0] == 'G' && pdata[1] == 'E' && pdata[2] == 'T'); + if (!peer->ws.handshaking_done && !is_GET) { + TSK_DEBUG_ERROR("WS handshaking not done yet"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + check_end_of_hdrs = is_GET; + } + + /* Check if we have all HTTP/SIP/WS headers. */ parse_buffer: - if(check_end_of_hdrs && (endOfheaders = tsk_strindexOf(TSK_BUFFER_DATA(peer->rcv_buff_stream),TSK_BUFFER_SIZE(peer->rcv_buff_stream), "\r\n\r\n"/*2CRLF*/)) < 0){ - TSK_DEBUG_INFO("No all headers in the WS buffer"); - goto bail; - } - - /* WebSocket handling*/ - if(peer->rcv_buff_stream->size > 4){ - const uint8_t* pdata = (const uint8_t*)peer->rcv_buff_stream->data; - - /* WebSocket Handshake */ - if(pdata[0] == 'G' && pdata[1] == 'E' && pdata[2] == 'T'){ - thttp_message_t *http_req = thttp_message_create(); - thttp_response_t *http_resp = tsk_null; - tsk_buffer_t *http_buff = tsk_null; - const thttp_header_Sec_WebSocket_Protocol_t* http_hdr_proto; - const thttp_header_Sec_WebSocket_Key_t* http_hdr_key; - const char* msg_start = (const char*)peer->rcv_buff_stream->data; - const char* msg_end = (msg_start + peer->rcv_buff_stream->size); - int32_t idx; - - if((idx = tsk_strindexOf(msg_start, (msg_end - msg_start), "\r\n")) > 2){ - TSK_DEBUG_INFO("WebSocket handshake message: %.*s", (msg_end - msg_start), msg_start); - msg_start += (idx + 2); // skip request header - while(msg_start < msg_end){ - if((idx = tsk_strindexOf(msg_start, (msg_end - msg_start), "\r\n")) <= 2){ - break; - } - idx+= 2; - tsk_ragel_state_init(&state, msg_start, idx); - if((ret = thttp_header_parse(&state, http_req))){ - TSK_DEBUG_ERROR("Failed to parse header: %s", msg_start); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - msg_start += idx; - } - } - - // get key header - if(!(http_hdr_key = (const thttp_header_Sec_WebSocket_Key_t*)thttp_message_get_header(http_req, thttp_htype_Sec_WebSocket_Key))){ - TSK_DEBUG_ERROR("No 'Sec-WebSocket-Key' header"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - - - if(http_hdr_key && (http_hdr_proto = (const thttp_header_Sec_WebSocket_Protocol_t*)thttp_message_get_header(http_req, thttp_htype_Sec_WebSocket_Protocol))){ - if(tsk_list_find_object_by_pred((const tsk_list_t*)http_hdr_proto->values, tsk_string_pred_icmp, "sip")){ - // send response - if((http_resp = thttp_response_new((short)101, "Switching Protocols", http_req))){ - // compute response key - thttp_auth_ws_keystring_t key_resp = {0}; - thttp_auth_ws_response(http_hdr_key->value, &key_resp); - - thttp_message_add_headers_2(http_resp, - THTTP_HEADER_DUMMY_VA_ARGS("Upgrade", "websocket"), - THTTP_HEADER_DUMMY_VA_ARGS("Connection", "Upgrade"), - THTTP_HEADER_SEC_WEBSOCKET_ACCEPT_VA_ARGS(key_resp), - THTTP_HEADER_SEC_WEBSOCKET_PROTOCOL_VA_ARGS("sip"), - THTTP_HEADER_SEC_WEBSOCKET_VERSION_VA_ARGS("13"), - tsk_null); - - // serialize response - if((http_buff = tsk_buffer_create_null())){ - thttp_message_serialize(http_resp, http_buff); - // TSK_DEBUG_INFO("WS response=%s", http_buff->data); - // send response - if((tnet_transport_send(transport->net_transport, e->local_fd, http_buff->data, http_buff->size)) != http_buff->size){ - TSK_DEBUG_ERROR("Failed to send reponse"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - } - else { - TSK_DEBUG_ERROR("Failed to create buffer"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - peer->ws.handshaking_done = tsk_true; // WS handshaking done - } - } - else{ - TSK_DEBUG_ERROR("Not SIP protocol"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - } - else{ - TSK_DEBUG_ERROR("No 'Sec-WebSocket-Protocol' header"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - goto bail; - } - - tsk_buffer_remove(peer->rcv_buff_stream, 0, (endOfheaders + 4/*2CRLF*/)); /* Remove HTTP headers and CRLF */ - TSK_OBJECT_SAFE_FREE(http_req); - TSK_OBJECT_SAFE_FREE(http_resp); - TSK_OBJECT_SAFE_FREE(http_buff); - } /* end-of WebSocket handshake */ - - /* WebSocket data */ - else{ - const uint8_t opcode = pdata[0] & 0x0F; - if((pdata[0] & 0x01)/* FIN */){ - const uint8_t mask_flag = (pdata[1] >> 7); // Must be "1" for "client -> server" - uint8_t mask_key[4] = { 0x00 }; - uint64_t pay_idx; - uint8_t* pws_rcv_buffer; - - if(pdata[0] & 0x40 || pdata[0] & 0x20 || pdata[0] & 0x10){ - TSK_DEBUG_ERROR("Unknown extension: %d", (pdata[0] >> 4) & 0x07); - tsk_buffer_cleanup(peer->rcv_buff_stream); - goto bail; - } - - pay_len = pdata[1] & 0x7F; - data_len = 2; - - if(pay_len == 126){ - if(peer->rcv_buff_stream->size < 4) { TSK_DEBUG_WARN("Too short"); goto bail; } - pay_len = (pdata[2] << 8 | pdata[3]); - pdata = &pdata[4]; - data_len += 2; - } - else if(pay_len == 127){ - if((peer->rcv_buff_stream->size - data_len) < 8) { TSK_DEBUG_WARN("Too short"); goto bail; } - pay_len = (((uint64_t)pdata[2]) << 56 | ((uint64_t)pdata[3]) << 48 | ((uint64_t)pdata[4]) << 40 | ((uint64_t)pdata[5]) << 32 | ((uint64_t)pdata[6]) << 24 | ((uint64_t)pdata[7]) << 16 | ((uint64_t)pdata[8]) << 8 || ((uint64_t)pdata[9])); - pdata = &pdata[10]; - data_len += 8; - } - else{ - pdata = &pdata[2]; - } - - if(mask_flag){ // must be "true" - if((peer->rcv_buff_stream->size - data_len) < 4) { TSK_DEBUG_WARN("Too short"); goto bail; } - mask_key[0] = pdata[0]; - mask_key[1] = pdata[1]; - mask_key[2] = pdata[2]; - mask_key[3] = pdata[3]; - pdata = &pdata[4]; - data_len += 4; - } - - if((peer->rcv_buff_stream->size - data_len) < pay_len){ - TSK_DEBUG_INFO("No all data in the WS buffer"); - goto bail; - } - - // create ws buffer tohold unmasked data - if(peer->ws.rcv_buffer_size < pay_len){ - if(!(peer->ws.rcv_buffer = tsk_realloc(peer->ws.rcv_buffer, (tsk_size_t)pay_len))){ - TSK_DEBUG_ERROR("Failed to allocate buffer of size %lld", pay_len); - peer->ws.rcv_buffer_size = 0; - goto bail; - } - peer->ws.rcv_buffer_size = (tsk_size_t)pay_len; - } - - pws_rcv_buffer = (uint8_t*)peer->ws.rcv_buffer; - data_len += pay_len; - - // unmasking the payload - for(pay_idx = 0; pay_idx < pay_len; ++pay_idx){ - pws_rcv_buffer[pay_idx] = (pdata[pay_idx] ^ mask_key[(pay_idx & 3)]); - } - - go_message = tsk_true; - } - else if(opcode == 0x08){ // RFC6455 - 5.5.1. Close - TSK_DEBUG_INFO("WebSocket opcode 0x8 (Close)"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - } - } - }/* end-of WebSocket handling */ - - // skip SIP message parsing if websocket transport - - if(!go_message){ - goto bail; - } - - // If we are there this mean that we have all SIP headers. - // ==> Parse the SIP message without the content. - TSK_DEBUG_INFO("Receiving SIP o/ WebSocket message: %.*s", pay_len, (const char*)peer->ws.rcv_buffer); - tsk_ragel_state_init(&state, peer->ws.rcv_buffer, (tsk_size_t)pay_len); - if (tsip_message_parse(&state, &message, tsk_false/* do not extract the content */) == tsk_true) { - const uint8_t* body_start = (const uint8_t*)state.eoh; - int64_t clen = (pay_len - (int64_t)(body_start - ((const uint8_t*)peer->ws.rcv_buffer))); - if (clen > 0) { - // Add the content to the message. */ - tsip_message_add_content(message, tsk_null, body_start, (tsk_size_t)clen); - } - tsk_buffer_remove(peer->rcv_buff_stream, 0, (tsk_size_t)data_len); - } - - if(message && message->firstVia && message->Call_ID && message->CSeq && message->From && message->To){ - /* Signal we got at least one valid SIP message */ - peer->got_valid_sip_msg = tsk_true; - /* Set fd */ - message->local_fd = e->local_fd; - message->src_net_type = transport->type; - /* Alert transaction/dialog layer */ - ret = tsip_transport_layer_handle_incoming_msg(transport, message); - /* Parse next chunck */ - if(TSK_BUFFER_SIZE(peer->rcv_buff_stream) >= TSIP_MIN_STREAM_CHUNCK_SIZE){ - /* message already passed to the dialog/transac layers */ - TSK_OBJECT_SAFE_FREE(message); - goto parse_buffer; - } - } - else{ - TSK_DEBUG_ERROR("Failed to parse SIP message"); - tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); - ret = -15; - goto bail; - } + if(check_end_of_hdrs && (endOfheaders = tsk_strindexOf(TSK_BUFFER_DATA(peer->rcv_buff_stream),TSK_BUFFER_SIZE(peer->rcv_buff_stream), "\r\n\r\n"/*2CRLF*/)) < 0) { + TSK_DEBUG_INFO("No all headers in the WS buffer"); + goto bail; + } + + /* WebSocket handling*/ + if(peer->rcv_buff_stream->size > 4) { + const uint8_t* pdata = (const uint8_t*)peer->rcv_buff_stream->data; + + /* WebSocket Handshake */ + if(pdata[0] == 'G' && pdata[1] == 'E' && pdata[2] == 'T') { + thttp_message_t *http_req = thttp_message_create(); + thttp_response_t *http_resp = tsk_null; + tsk_buffer_t *http_buff = tsk_null; + const thttp_header_Sec_WebSocket_Protocol_t* http_hdr_proto; + const thttp_header_Sec_WebSocket_Key_t* http_hdr_key; + const char* msg_start = (const char*)peer->rcv_buff_stream->data; + const char* msg_end = (msg_start + peer->rcv_buff_stream->size); + int32_t idx; + + if((idx = tsk_strindexOf(msg_start, (msg_end - msg_start), "\r\n")) > 2) { + TSK_DEBUG_INFO("WebSocket handshake message: %.*s", (msg_end - msg_start), msg_start); + msg_start += (idx + 2); // skip request header + while(msg_start < msg_end) { + if((idx = tsk_strindexOf(msg_start, (msg_end - msg_start), "\r\n")) <= 2) { + break; + } + idx+= 2; + tsk_ragel_state_init(&state, msg_start, idx); + if((ret = thttp_header_parse(&state, http_req))) { + TSK_DEBUG_ERROR("Failed to parse header: %s", msg_start); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + msg_start += idx; + } + } + + // get key header + if(!(http_hdr_key = (const thttp_header_Sec_WebSocket_Key_t*)thttp_message_get_header(http_req, thttp_htype_Sec_WebSocket_Key))) { + TSK_DEBUG_ERROR("No 'Sec-WebSocket-Key' header"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + + + if(http_hdr_key && (http_hdr_proto = (const thttp_header_Sec_WebSocket_Protocol_t*)thttp_message_get_header(http_req, thttp_htype_Sec_WebSocket_Protocol))) { + if(tsk_list_find_object_by_pred((const tsk_list_t*)http_hdr_proto->values, tsk_string_pred_icmp, "sip")) { + // send response + if((http_resp = thttp_response_new((short)101, "Switching Protocols", http_req))) { + // compute response key + thttp_auth_ws_keystring_t key_resp = {0}; + thttp_auth_ws_response(http_hdr_key->value, &key_resp); + + thttp_message_add_headers_2(http_resp, + THTTP_HEADER_DUMMY_VA_ARGS("Upgrade", "websocket"), + THTTP_HEADER_DUMMY_VA_ARGS("Connection", "Upgrade"), + THTTP_HEADER_SEC_WEBSOCKET_ACCEPT_VA_ARGS(key_resp), + THTTP_HEADER_SEC_WEBSOCKET_PROTOCOL_VA_ARGS("sip"), + THTTP_HEADER_SEC_WEBSOCKET_VERSION_VA_ARGS("13"), + tsk_null); + + // serialize response + if((http_buff = tsk_buffer_create_null())) { + thttp_message_serialize(http_resp, http_buff); + // TSK_DEBUG_INFO("WS response=%s", http_buff->data); + // send response + if((tnet_transport_send(transport->net_transport, e->local_fd, http_buff->data, http_buff->size)) != http_buff->size) { + TSK_DEBUG_ERROR("Failed to send reponse"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + } + else { + TSK_DEBUG_ERROR("Failed to create buffer"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + peer->ws.handshaking_done = tsk_true; // WS handshaking done + } + } + else { + TSK_DEBUG_ERROR("Not SIP protocol"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + } + else { + TSK_DEBUG_ERROR("No 'Sec-WebSocket-Protocol' header"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + goto bail; + } + + tsk_buffer_remove(peer->rcv_buff_stream, 0, (endOfheaders + 4/*2CRLF*/)); /* Remove HTTP headers and CRLF */ + TSK_OBJECT_SAFE_FREE(http_req); + TSK_OBJECT_SAFE_FREE(http_resp); + TSK_OBJECT_SAFE_FREE(http_buff); + } /* end-of WebSocket handshake */ + + /* WebSocket data */ + else { + const uint8_t opcode = pdata[0] & 0x0F; + if((pdata[0] & 0x01)/* FIN */) { + const uint8_t mask_flag = (pdata[1] >> 7); // Must be "1" for "client -> server" + uint8_t mask_key[4] = { 0x00 }; + uint64_t pay_idx; + uint8_t* pws_rcv_buffer; + + if(pdata[0] & 0x40 || pdata[0] & 0x20 || pdata[0] & 0x10) { + TSK_DEBUG_ERROR("Unknown extension: %d", (pdata[0] >> 4) & 0x07); + tsk_buffer_cleanup(peer->rcv_buff_stream); + goto bail; + } + + pay_len = pdata[1] & 0x7F; + data_len = 2; + + if(pay_len == 126) { + if(peer->rcv_buff_stream->size < 4) { + TSK_DEBUG_WARN("Too short"); + goto bail; + } + pay_len = (pdata[2] << 8 | pdata[3]); + pdata = &pdata[4]; + data_len += 2; + } + else if(pay_len == 127) { + if((peer->rcv_buff_stream->size - data_len) < 8) { + TSK_DEBUG_WARN("Too short"); + goto bail; + } + pay_len = (((uint64_t)pdata[2]) << 56 | ((uint64_t)pdata[3]) << 48 | ((uint64_t)pdata[4]) << 40 | ((uint64_t)pdata[5]) << 32 | ((uint64_t)pdata[6]) << 24 | ((uint64_t)pdata[7]) << 16 | ((uint64_t)pdata[8]) << 8 || ((uint64_t)pdata[9])); + pdata = &pdata[10]; + data_len += 8; + } + else { + pdata = &pdata[2]; + } + + if(mask_flag) { // must be "true" + if((peer->rcv_buff_stream->size - data_len) < 4) { + TSK_DEBUG_WARN("Too short"); + goto bail; + } + mask_key[0] = pdata[0]; + mask_key[1] = pdata[1]; + mask_key[2] = pdata[2]; + mask_key[3] = pdata[3]; + pdata = &pdata[4]; + data_len += 4; + } + + if((peer->rcv_buff_stream->size - data_len) < pay_len) { + TSK_DEBUG_INFO("No all data in the WS buffer"); + goto bail; + } + + // create ws buffer tohold unmasked data + if(peer->ws.rcv_buffer_size < pay_len) { + if(!(peer->ws.rcv_buffer = tsk_realloc(peer->ws.rcv_buffer, (tsk_size_t)pay_len))) { + TSK_DEBUG_ERROR("Failed to allocate buffer of size %lld", pay_len); + peer->ws.rcv_buffer_size = 0; + goto bail; + } + peer->ws.rcv_buffer_size = (tsk_size_t)pay_len; + } + + pws_rcv_buffer = (uint8_t*)peer->ws.rcv_buffer; + data_len += pay_len; + + // unmasking the payload + for(pay_idx = 0; pay_idx < pay_len; ++pay_idx) { + pws_rcv_buffer[pay_idx] = (pdata[pay_idx] ^ mask_key[(pay_idx & 3)]); + } + + go_message = tsk_true; + } + else if(opcode == 0x08) { // RFC6455 - 5.5.1. Close + TSK_DEBUG_INFO("WebSocket opcode 0x8 (Close)"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + } + } + }/* end-of WebSocket handling */ + + // skip SIP message parsing if websocket transport + + if(!go_message) { + goto bail; + } + + // If we are there this mean that we have all SIP headers. + // ==> Parse the SIP message without the content. + TSK_DEBUG_INFO("Receiving SIP o/ WebSocket message: %.*s", pay_len, (const char*)peer->ws.rcv_buffer); + tsk_ragel_state_init(&state, peer->ws.rcv_buffer, (tsk_size_t)pay_len); + if (tsip_message_parse(&state, &message, tsk_false/* do not extract the content */) == tsk_true) { + const uint8_t* body_start = (const uint8_t*)state.eoh; + int64_t clen = (pay_len - (int64_t)(body_start - ((const uint8_t*)peer->ws.rcv_buffer))); + if (clen > 0) { + // Add the content to the message. */ + tsip_message_add_content(message, tsk_null, body_start, (tsk_size_t)clen); + } + tsk_buffer_remove(peer->rcv_buff_stream, 0, (tsk_size_t)data_len); + } + + if(message && message->firstVia && message->Call_ID && message->CSeq && message->From && message->To) { + /* Signal we got at least one valid SIP message */ + peer->got_valid_sip_msg = tsk_true; + /* Set fd */ + message->local_fd = e->local_fd; + message->src_net_type = transport->type; + /* Alert transaction/dialog layer */ + ret = tsip_transport_layer_handle_incoming_msg(transport, message); + /* Parse next chunck */ + if(TSK_BUFFER_SIZE(peer->rcv_buff_stream) >= TSIP_MIN_STREAM_CHUNCK_SIZE) { + /* message already passed to the dialog/transac layers */ + TSK_OBJECT_SAFE_FREE(message); + goto parse_buffer; + } + } + else { + TSK_DEBUG_ERROR("Failed to parse SIP message"); + tsip_transport_remove_socket(transport, (tnet_fd_t *)&e->local_fd); + ret = -15; + goto bail; + } bail: - TSK_OBJECT_SAFE_FREE(message); - TSK_OBJECT_SAFE_FREE(peer); + TSK_OBJECT_SAFE_FREE(message); + TSK_OBJECT_SAFE_FREE(peer); - return ret; + return ret; } /*== Non-blocking callback function (DGRAM: UDP) */ static int tsip_transport_layer_dgram_cb(const tnet_transport_event_t* e) { - int ret = -1; - tsk_ragel_state_t state; - tsip_message_t *message = tsk_null; - const tsip_transport_t *transport = e->callback_data; - const char* data_ptr; - tsk_size_t data_size; - char SigCompBuffer[TSIP_SIGCOMP_MAX_BUFF_SIZE]; - - switch(e->type){ - case event_data: { - TSK_DEBUG_INFO("\n\nRECV:%.*s\n\n", e->size, (const char*)e->data); - break; - } - case event_closed: - case event_connected: - default:{ - return 0; - } - } - - /* === SigComp === */ - if(TSIP_IS_SIGCOMP_DATA(e->data)){ - //====== - // FIXME: This implmentation will always use the first SigComp-Id for decompression - // The destination addr will always be the pcscf which will not work for server mode - //===== - tsk_bool_t is_nack; - const char* comp_id; - - comp_id = tsip_sigcomp_handler_fixme_getcompid(transport->stack->sigcomp.handle); - data_size = tsip_sigcomp_handler_uncompressUDP(transport->stack->sigcomp.handle, comp_id, e->data, e->size, SigCompBuffer, sizeof(SigCompBuffer), &is_nack); - data_ptr = SigCompBuffer; - if(data_size){ - if(is_nack){ - tsip_transport_send_raw(transport, tsk_null, 0, data_ptr, data_size, __null_callid); - return 0; - } - } - else{ - TSK_DEBUG_ERROR("SigComp decompression has failed"); - return -2; - } - } - else{ - data_ptr = e->data; - data_size = e->size; - } - - if (data_size == 4 && ((data_ptr[0] == '\r' && data_ptr[1] == '\n'&& data_ptr[2] == '\r' && data_ptr[3] == '\n') || (data_ptr[0] == 0x00 && data_ptr[1] == 0x00 && data_ptr[2] == 0x00 && data_ptr[3] == 0x00))) { - TSK_DEBUG_INFO("2CRLF"); - tsip_transport_send_raw(transport, tsk_null, 0, data_ptr, data_size, __null_callid); - return 0; - } - - tsk_ragel_state_init(&state, data_ptr, data_size); - if(tsip_message_parse(&state, &message, tsk_true) == tsk_true - && message->firstVia && message->Call_ID && message->CSeq && message->From && message->To) - { - /* Set local fd used to receive the message and the address of the remote peer */ - message->local_fd = e->local_fd; - message->remote_addr = e->remote_addr; - message->src_net_type = transport->type; - - /* RFC 3581 - 4. Server Behavior - When a server compliant to this specification (which can be a proxy - or UAS) receives a request, it examines the topmost Via header field - value. If this Via header field value contains an "rport" parameter - with no value, it MUST set the value of the parameter to the source - port of the request. This is analogous to the way in which a server - will insert the "received" parameter into the topmost Via header - field value. In fact, the server MUST insert a "received" parameter - containing the source IP address that the request came from, even if - it is identical to the value of the "sent-by" component. Note that - this processing takes place independent of the transport protocol. - */ - if(TSIP_MESSAGE_IS_REQUEST(message) && TSIP_STACK_MODE_IS_SERVER(transport->stack)){ - if(message->firstVia->rport == 0){ // 0: exist with no value; -1: doesn't exist; other contains the rport value - tnet_ip_t ip; - tnet_port_t port; - if((ret = tnet_get_sockip_n_port((const struct sockaddr*)&e->remote_addr, &ip, &port)) == 0){ - message->firstVia->rport = (int32_t)port; - tsk_strupdate(&message->firstVia->received, (const char*)ip); - } - } - } - - - /* Alert transaction/dialog layer */ - ret = tsip_transport_layer_handle_incoming_msg(transport, message); - } - TSK_OBJECT_SAFE_FREE(message); - - return ret; + int ret = -1; + tsk_ragel_state_t state; + tsip_message_t *message = tsk_null; + const tsip_transport_t *transport = e->callback_data; + const char* data_ptr; + tsk_size_t data_size; + char SigCompBuffer[TSIP_SIGCOMP_MAX_BUFF_SIZE]; + + switch(e->type) { + case event_data: { + TSK_DEBUG_INFO("\n\nRECV:%.*s\n\n", e->size, (const char*)e->data); + break; + } + case event_closed: + case event_connected: + default: { + return 0; + } + } + + /* === SigComp === */ + if(TSIP_IS_SIGCOMP_DATA(e->data)) { + //====== + // FIXME: This implmentation will always use the first SigComp-Id for decompression + // The destination addr will always be the pcscf which will not work for server mode + //===== + tsk_bool_t is_nack; + const char* comp_id; + + comp_id = tsip_sigcomp_handler_fixme_getcompid(transport->stack->sigcomp.handle); + data_size = tsip_sigcomp_handler_uncompressUDP(transport->stack->sigcomp.handle, comp_id, e->data, e->size, SigCompBuffer, sizeof(SigCompBuffer), &is_nack); + data_ptr = SigCompBuffer; + if(data_size) { + if(is_nack) { + tsip_transport_send_raw(transport, tsk_null, 0, data_ptr, data_size, __null_callid); + return 0; + } + } + else { + TSK_DEBUG_ERROR("SigComp decompression has failed"); + return -2; + } + } + else { + data_ptr = e->data; + data_size = e->size; + } + + if (data_size == 4 && ((data_ptr[0] == '\r' && data_ptr[1] == '\n'&& data_ptr[2] == '\r' && data_ptr[3] == '\n') || (data_ptr[0] == 0x00 && data_ptr[1] == 0x00 && data_ptr[2] == 0x00 && data_ptr[3] == 0x00))) { + TSK_DEBUG_INFO("2CRLF"); + tsip_transport_send_raw(transport, tsk_null, 0, data_ptr, data_size, __null_callid); + return 0; + } + + tsk_ragel_state_init(&state, data_ptr, data_size); + if(tsip_message_parse(&state, &message, tsk_true) == tsk_true + && message->firstVia && message->Call_ID && message->CSeq && message->From && message->To) { + /* Set local fd used to receive the message and the address of the remote peer */ + message->local_fd = e->local_fd; + message->remote_addr = e->remote_addr; + message->src_net_type = transport->type; + + /* RFC 3581 - 4. Server Behavior + When a server compliant to this specification (which can be a proxy + or UAS) receives a request, it examines the topmost Via header field + value. If this Via header field value contains an "rport" parameter + with no value, it MUST set the value of the parameter to the source + port of the request. This is analogous to the way in which a server + will insert the "received" parameter into the topmost Via header + field value. In fact, the server MUST insert a "received" parameter + containing the source IP address that the request came from, even if + it is identical to the value of the "sent-by" component. Note that + this processing takes place independent of the transport protocol. + */ + if(TSIP_MESSAGE_IS_REQUEST(message) && TSIP_STACK_MODE_IS_SERVER(transport->stack)) { + if(message->firstVia->rport == 0) { // 0: exist with no value; -1: doesn't exist; other contains the rport value + tnet_ip_t ip; + tnet_port_t port; + if((ret = tnet_get_sockip_n_port((const struct sockaddr*)&e->remote_addr, &ip, &port)) == 0) { + message->firstVia->rport = (int32_t)port; + tsk_strupdate(&message->firstVia->received, (const char*)ip); + } + } + } + + + /* Alert transaction/dialog layer */ + ret = tsip_transport_layer_handle_incoming_msg(transport, message); + } + TSK_OBJECT_SAFE_FREE(message); + + return ret; } static const tsip_transport_t* tsip_transport_layer_find(const tsip_transport_layer_t* self, tsip_message_t *msg, char** destIP, int32_t *destPort) { - const tsip_transport_t* transport = tsk_null; - - if(!self || !destIP){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - // check whether the message already contains destination address (most likely retransmitted) - if(!tsk_strnullORempty(msg->dst_address) && msg->dst_port && TNET_SOCKET_TYPE_IS_VALID(msg->dst_net_type)){ - const tsk_list_item_t *item; - tsk_strupdate(destIP, msg->dst_address); - *destPort = msg->dst_port; - tsk_list_foreach(item, self->transports){ - if(((const tsip_transport_t*)item->data)->type == msg->dst_net_type){ - transport = ((const tsip_transport_t*)item->data); - goto bail; - } - } - } - - // use default values - tsk_strupdate(destIP, self->stack->network.proxy_cscf[self->stack->network.transport_idx_default]); - *destPort = self->stack->network.proxy_cscf_port[self->stack->network.transport_idx_default]; - - /* =========== Sending Request ========= - * - */ - if(TSIP_MESSAGE_IS_REQUEST(msg)){ - tsip_dialog_t* dialog; - tsk_list_item_t *item; - tsip_transport_t *curr; - tnet_socket_type_t destNetType = self->stack->network.transport_types[self->stack->network.transport_idx_default]; - /* RFC 3261 - 18.1.1 Sending Requests - If the port is absent, the default value depends on the transport. It is 5060 for UDP, TCP and SCTP, 5061 for TLS. */ - // int32_t destDefaultPort = TNET_SOCKET_TYPE_IS_TLS(destNetType) ? 5061 : 5060; - - /* If message received over WebSocket transport and stack is running in w2s mode then forward to the first route if available */ - if((self->stack->network.mode == tsip_stack_mode_webrtc2sip)){ - const tsip_header_Route_t *route_first; - if((route_first = (const tsip_header_Route_t*)tsip_message_get_header(msg, tsip_htype_Route)) && route_first->uri && !tsk_strnullORempty(route_first->uri->host)){ - const char* transport_str = tsk_params_get_param_value(route_first->uri->params, "transport"); - const tsip_header_Route_t *route; - tnet_port_t local_port; - const char *local_ip; - int t_idx = -1, route_i = 0; - if(!tsk_strnullORempty(transport_str)){ - t_idx = tsip_transport_get_idx_by_name(transport_str); - if(t_idx != -1){ - destNetType = self->stack->network.transport_types[t_idx]; - } - } - tsk_strupdate(destIP, route_first->uri->host); - *destPort = (route_first->uri->port ? route_first->uri->port : 5060); - - local_ip = self->stack->network.local_ip[t_idx == -1 ? self->stack->network.transport_idx_default : t_idx]; - local_port = self->stack->network.local_port[t_idx == -1 ? self->stack->network.transport_idx_default : t_idx]; + const tsip_transport_t* transport = tsk_null; + + if(!self || !destIP) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + // check whether the message already contains destination address (most likely retransmitted) + if(!tsk_strnullORempty(msg->dst_address) && msg->dst_port && TNET_SOCKET_TYPE_IS_VALID(msg->dst_net_type)) { + const tsk_list_item_t *item; + tsk_strupdate(destIP, msg->dst_address); + *destPort = msg->dst_port; + tsk_list_foreach(item, self->transports) { + if(((const tsip_transport_t*)item->data)->type == msg->dst_net_type) { + transport = ((const tsip_transport_t*)item->data); + goto bail; + } + } + } + + // use default values + tsk_strupdate(destIP, self->stack->network.proxy_cscf[self->stack->network.transport_idx_default]); + *destPort = self->stack->network.proxy_cscf_port[self->stack->network.transport_idx_default]; + + /* =========== Sending Request ========= + * + */ + if(TSIP_MESSAGE_IS_REQUEST(msg)) { + tsip_dialog_t* dialog; + tsk_list_item_t *item; + tsip_transport_t *curr; + tnet_socket_type_t destNetType = self->stack->network.transport_types[self->stack->network.transport_idx_default]; + /* RFC 3261 - 18.1.1 Sending Requests + If the port is absent, the default value depends on the transport. It is 5060 for UDP, TCP and SCTP, 5061 for TLS. */ + // int32_t destDefaultPort = TNET_SOCKET_TYPE_IS_TLS(destNetType) ? 5061 : 5060; + + /* If message received over WebSocket transport and stack is running in w2s mode then forward to the first route if available */ + if((self->stack->network.mode == tsip_stack_mode_webrtc2sip)) { + const tsip_header_Route_t *route_first; + if((route_first = (const tsip_header_Route_t*)tsip_message_get_header(msg, tsip_htype_Route)) && route_first->uri && !tsk_strnullORempty(route_first->uri->host)) { + const char* transport_str = tsk_params_get_param_value(route_first->uri->params, "transport"); + const tsip_header_Route_t *route; + tnet_port_t local_port; + const char *local_ip; + int t_idx = -1, route_i = 0; + if(!tsk_strnullORempty(transport_str)) { + t_idx = tsip_transport_get_idx_by_name(transport_str); + if(t_idx != -1) { + destNetType = self->stack->network.transport_types[t_idx]; + } + } + tsk_strupdate(destIP, route_first->uri->host); + *destPort = (route_first->uri->port ? route_first->uri->port : 5060); + + local_ip = self->stack->network.local_ip[t_idx == -1 ? self->stack->network.transport_idx_default : t_idx]; + local_port = self->stack->network.local_port[t_idx == -1 ? self->stack->network.transport_idx_default : t_idx]; clean_routes: - route_i = 0; - while((route = (const tsip_header_Route_t *)tsip_message_get_headerAt(msg, tsip_htype_Route, route_i++))){ - if(route && route->uri){ - if(tsk_params_have_param(route->uri->params, "sipml5-outbound") || (tsk_strequals(local_ip, route->uri->host) && local_port == route->uri->port)){ - tsk_list_remove_item_by_data(msg->headers, route); - goto clean_routes; - } - } - } - } - else if(!TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) && !TNET_SOCKET_TYPE_IS_WS(msg->src_net_type)){ - const char* ws_src_ip = tsk_params_get_param_value(msg->line.request.uri->params, "ws-src-ip"); - if(ws_src_ip){ - const char* ws_src_port = tsk_params_get_param_value(msg->line.request.uri->params, "ws-src-port"); - const char* ws_src_proto = tsk_params_get_param_value(msg->line.request.uri->params, "ws-src-proto"); - tsk_strupdate(destIP, ws_src_ip); - *destPort = atoi(ws_src_port); - destNetType = self->stack->network.transport_types[tsip_transport_get_idx_by_name(ws_src_proto)]; - } - } - } - else{ - /* Sends request to the first route or remote target */ - dialog = tsip_dialog_layer_find_by_callid(self->stack->layer_dialog, msg->Call_ID->value); - if(dialog){ - const tsip_header_Record_Route_t* route; - tsk_bool_t b_using_route = tsk_false; - tsk_list_foreach(item, dialog->record_routes){ - if(!(route = item->data)){ - continue; - } - if(route->uri && route->uri->host){ - tsk_strupdate(destIP, route->uri->host); - *destPort = route->uri->port > 0 ? route->uri->port : (TNET_SOCKET_TYPE_IS_TLS(destNetType) ? 5061 : 5060); - b_using_route = tsk_true; - break; - } - } - if(!b_using_route){ - // Client mode requires the port to be defined (dialog connected) while server mode doesn't. - if(dialog->uri_remote_target && dialog->uri_remote_target->host && (dialog->uri_remote_target->port || TSIP_STACK_MODE_IS_SERVER(self->stack))){ - const char* transport_name = tsk_params_get_param_value(dialog->uri_remote_target->params, "transport"); - tsk_strupdate(destIP, dialog->uri_remote_target->host); - *destPort = dialog->uri_remote_target->port ? dialog->uri_remote_target->port : (tsk_striequals(transport_name, "TLS") ? 5061 : 5060); - if(!tsk_strnullORempty(transport_name)) { - enum tnet_socket_type_e _destNetType = tsip_transport_get_type_by_name(transport_name); - if(TNET_SOCKET_TYPE_IS_VALID(_destNetType)) { - // _destNetType is UDP, TCP, WSSS...and not UDP-IPv4, TCP-IPv6, WSS-IPv4-IPsec...This is why closest match is used. - destNetType = _destNetType; - } - } - } - } - TSK_OBJECT_SAFE_FREE(dialog); - } - } - - /* Find the right transport using exact/closest match */ - { - const tsip_transport_t* transport_closest1 = tsk_null; - const tsip_transport_t* transport_closest2 = tsk_null; - tsk_list_foreach(item, self->transports){ - curr = item->data; - if(curr->type == destNetType){ - transport = curr; - break; - } - if((curr->type & destNetType) == destNetType){ - transport_closest1 = curr; - } - if(self->stack->network.transport_idx_default>= 0 && curr->type == self->stack->network.transport_types[self->stack->network.transport_idx_default]) { - transport_closest2 = curr; - } - } - if(!transport && (transport_closest1 || transport_closest2)) { - const tsip_transport_t* transport_closest = transport_closest1 ? transport_closest1 : transport_closest2; - // For example, UDP will match with UDP-IPv4-IPSec or UDP-IPv6 - TSK_DEBUG_INFO("Setting transport with closest match(%d->%d)", destNetType, transport_closest->type); - transport = transport_closest; - } - } - - - /* DNS NAPTR + SRV if the Proxy-CSCF is not defined and route set is empty */ - if(transport && !(*destIP) && !self->stack->network.proxy_cscf[self->stack->network.transport_idx_default]){ - tnet_port_t dstPort; - if(tnet_dns_query_naptr_srv(self->stack->dns_ctx, msg->To->uri->host, transport->service, destIP, &dstPort) == 0){ - *destPort = dstPort; - } - else{ - tsk_strupdate(destIP, msg->To->uri->host); - *destPort = 5060; - } - } - } - - - - /* =========== Sending Response ========= - * - */ - else if(msg->firstVia) - { - { /* Find the transport. */ - tsk_list_item_t *item; - tsip_transport_t *curr; - tsk_list_foreach(item, self->transports) - { - curr = item->data; - if(tsip_transport_have_socket(curr, msg->local_fd)) - { - transport = curr; - break; - } - } - } - - /* webrtc2sip mode */ - if(self->stack->network.mode == tsip_stack_mode_webrtc2sip){ - if(TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WS(msg->src_net_type)){ // response over WS or WSS - transport = tsip_transport_layer_find_by_idx(self, tsip_transport_get_idx_by_name(msg->firstVia->transport)); - if(transport){ - tsk_strupdate(destIP, msg->firstVia->host); - *destPort = msg->firstVia->port; - msg->dst_net_type = transport->type; - } - return transport; - } - else{ // response over UDP, TCP or TLS - const tsip_header_Via_t* via_2nd = (const tsip_header_Via_t*)tsip_message_get_headerAt(msg, tsip_htype_Via, 1); - tsk_bool_t via_ws_transport = via_2nd && (tsk_striequals(via_2nd->transport, "WS") || tsk_striequals(via_2nd->transport, "WSS")); - tsk_bool_t via_ws_hacked = via_2nd && TSIP_HEADER_HAVE_PARAM(via_2nd, "ws-hacked"); - if(via_2nd && (via_ws_transport || via_ws_hacked)){ - int t_idx = tsip_transport_get_idx_by_name(via_ws_transport ? via_2nd->transport : TSIP_HEADER_GET_PARAM_VALUE(via_2nd, "ws-hacked")); - const tsip_transport_t* ws_transport = tsip_transport_layer_find_by_idx(self, t_idx); - if(ws_transport){ - tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_remote_ip(TSIP_TRANSPORT(ws_transport), via_2nd->host, via_2nd->port, ws_transport->type); - if(peer){ - tsk_strupdate(destIP, peer->remote_ip); - *destPort = peer->remote_port; - msg->dst_net_type = ws_transport->type; - TSK_OBJECT_SAFE_FREE(peer); - return ws_transport; - } - } - - TSK_DEBUG_ERROR("Failed to match response expected to be forwarded via WebSocket transport"); - return tsk_null; - } - } - } - - if(TSIP_HEADER_VIA_RELIABLE_TRANS(msg->firstVia)) /*== RELIABLE ===*/ - { - /* RFC 3261 - 18.2.2 Sending Responses - If the "sent-protocol" is a reliable transport protocol such as - TCP or SCTP, or TLS over those, the response MUST be sent using - the existing connection to the source of the original request - that created the transaction, if that connection is still open. - This requires the server transport to maintain an association - between server transactions and transport connections. If that - connection is no longer open, the server SHOULD open a - connection to the IP address in the "received" parameter, if - present, using the port in the "sent-by" value, or the default - port for that transport, if no port is specified. If that - connection attempt fails, the server SHOULD use the procedures - in [4] for servers in order to determine the IP address and - port to open the connection and send the response to. - */ - if(tsk_strnullORempty(*destIP)){ - tnet_ip_t peer_ip; - tnet_port_t peer_port; - if(transport && tnet_get_peerip_n_port(msg->local_fd, &peer_ip, &peer_port) == 0){ // connection is still open ? - tsk_strupdate(destIP, peer_ip); - *destPort = peer_port; - } - else{ - if(msg->firstVia->received){ - tsk_strupdate(destIP, msg->firstVia->received); - *destPort = msg->firstVia->rport > 0 ? msg->firstVia->rport : msg->firstVia->port; - } - else{ - tsk_strupdate(destIP, msg->firstVia->host); - *destPort = msg->firstVia->port; - } - } - } - } - else - { - if(msg->firstVia->maddr) /*== UNRELIABLE MULTICAST ===*/ - { - /* RFC 3261 - 18.2.2 Sending Responses - Otherwise, if the Via header field value contains a "maddr" parameter, the - response MUST be forwarded to the address listed there, using - the port indicated in "sent-by", or port 5060 if none is present. - If the address is a multicast address, the response SHOULD be - sent using the TTL indicated in the "ttl" parameter, or with a - TTL of 1 if that parameter is not present. - */ - } - else /*=== UNRELIABLE UNICAST ===*/ - { - if(msg->firstVia->received) - { - if(msg->firstVia->rport > 0) - { - /* RFC 3581 - 4. Server Behavior - When a server attempts to send a response, it examines the topmost - Via header field value of that response. If the "sent-protocol" - component indicates an unreliable unicast transport protocol, such as - UDP, and there is no "maddr" parameter, but there is both a - "received" parameter and an "rport" parameter, the response MUST be - sent to the IP address listed in the "received" parameter, and the - port in the "rport" parameter. The response MUST be sent from the - same address and port that the corresponding request was received on. - This effectively adds a new processing step between bullets two and - three in Section 18.2.2 of SIP [1]. - */ - tsk_strupdate(destIP, msg->firstVia->received); - *destPort = msg->firstVia->rport; - } - else - { - /* RFC 3261 - 18.2.2 Sending Responses - Otherwise (for unreliable unicast transports), if the top Via - has a "received" parameter, the response MUST be sent to the - address in the "received" parameter, using the port indicated - in the "sent-by" value, or using port 5060 if none is specified - explicitly. If this fails, for example, elicits an ICMP "port - unreachable" response, the procedures of Section 5 of [4] - SHOULD be used to determine where to send the response. - */ - tsk_strupdate(destIP, msg->firstVia->received); - *destPort = msg->firstVia->port ? msg->firstVia->port : 5060; - } - } - else - { - /* RFC 3261 - 18.2.2 Sending Responses - Otherwise, if it is not receiver-tagged, the response MUST be - sent to the address indicated by the "sent-by" value, using the - procedures in Section 5 of [4]. - */ - tsk_strupdate(destIP, msg->firstVia->host); - if(msg->firstVia->port > 0) - { - *destPort = msg->firstVia->port; - } - } - } - } - } - - // update message to avoid destination address to avoid running the same algo for retransmissions - tsk_strupdate(&msg->dst_address, *destIP); - msg->dst_port = *destPort; - if(!TNET_SOCKET_TYPE_IS_VALID(msg->dst_net_type) && transport){ - msg->dst_net_type = transport->type; - } - + route_i = 0; + while((route = (const tsip_header_Route_t *)tsip_message_get_headerAt(msg, tsip_htype_Route, route_i++))) { + if(route && route->uri) { + if(tsk_params_have_param(route->uri->params, "sipml5-outbound") || (tsk_strequals(local_ip, route->uri->host) && local_port == route->uri->port)) { + tsk_list_remove_item_by_data(msg->headers, route); + goto clean_routes; + } + } + } + } + else if(!TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) && !TNET_SOCKET_TYPE_IS_WS(msg->src_net_type)) { + const char* ws_src_ip = tsk_params_get_param_value(msg->line.request.uri->params, "ws-src-ip"); + if(ws_src_ip) { + const char* ws_src_port = tsk_params_get_param_value(msg->line.request.uri->params, "ws-src-port"); + const char* ws_src_proto = tsk_params_get_param_value(msg->line.request.uri->params, "ws-src-proto"); + tsk_strupdate(destIP, ws_src_ip); + *destPort = atoi(ws_src_port); + destNetType = self->stack->network.transport_types[tsip_transport_get_idx_by_name(ws_src_proto)]; + } + } + } + else { + /* Sends request to the first route or remote target */ + dialog = tsip_dialog_layer_find_by_callid(self->stack->layer_dialog, msg->Call_ID->value); + if(dialog) { + const tsip_header_Record_Route_t* route; + tsk_bool_t b_using_route = tsk_false; + tsk_list_foreach(item, dialog->record_routes) { + if(!(route = item->data)) { + continue; + } + if(route->uri && route->uri->host) { + tsk_strupdate(destIP, route->uri->host); + *destPort = route->uri->port > 0 ? route->uri->port : (TNET_SOCKET_TYPE_IS_TLS(destNetType) ? 5061 : 5060); + b_using_route = tsk_true; + break; + } + } + if(!b_using_route) { + // Client mode requires the port to be defined (dialog connected) while server mode doesn't. + if(dialog->uri_remote_target && dialog->uri_remote_target->host && (dialog->uri_remote_target->port || TSIP_STACK_MODE_IS_SERVER(self->stack))) { + const char* transport_name = tsk_params_get_param_value(dialog->uri_remote_target->params, "transport"); + tsk_strupdate(destIP, dialog->uri_remote_target->host); + *destPort = dialog->uri_remote_target->port ? dialog->uri_remote_target->port : (tsk_striequals(transport_name, "TLS") ? 5061 : 5060); + if(!tsk_strnullORempty(transport_name)) { + enum tnet_socket_type_e _destNetType = tsip_transport_get_type_by_name(transport_name); + if(TNET_SOCKET_TYPE_IS_VALID(_destNetType)) { + // _destNetType is UDP, TCP, WSSS...and not UDP-IPv4, TCP-IPv6, WSS-IPv4-IPsec...This is why closest match is used. + destNetType = _destNetType; + } + } + } + } + TSK_OBJECT_SAFE_FREE(dialog); + } + } + + /* Find the right transport using exact/closest match */ + { + const tsip_transport_t* transport_closest1 = tsk_null; + const tsip_transport_t* transport_closest2 = tsk_null; + tsk_list_foreach(item, self->transports) { + curr = item->data; + if(curr->type == destNetType) { + transport = curr; + break; + } + if((curr->type & destNetType) == destNetType) { + transport_closest1 = curr; + } + if(self->stack->network.transport_idx_default>= 0 && curr->type == self->stack->network.transport_types[self->stack->network.transport_idx_default]) { + transport_closest2 = curr; + } + } + if(!transport && (transport_closest1 || transport_closest2)) { + const tsip_transport_t* transport_closest = transport_closest1 ? transport_closest1 : transport_closest2; + // For example, UDP will match with UDP-IPv4-IPSec or UDP-IPv6 + TSK_DEBUG_INFO("Setting transport with closest match(%d->%d)", destNetType, transport_closest->type); + transport = transport_closest; + } + } + + + /* DNS NAPTR + SRV if the Proxy-CSCF is not defined and route set is empty */ + if(transport && !(*destIP) && !self->stack->network.proxy_cscf[self->stack->network.transport_idx_default]) { + tnet_port_t dstPort; + if(tnet_dns_query_naptr_srv(self->stack->dns_ctx, msg->To->uri->host, transport->service, destIP, &dstPort) == 0) { + *destPort = dstPort; + } + else { + tsk_strupdate(destIP, msg->To->uri->host); + *destPort = 5060; + } + } + } + + + + /* =========== Sending Response ========= + * + */ + else if(msg->firstVia) { + { /* Find the transport. */ + tsk_list_item_t *item; + tsip_transport_t *curr; + tsk_list_foreach(item, self->transports) { + curr = item->data; + if(tsip_transport_have_socket(curr, msg->local_fd)) { + transport = curr; + break; + } + } + } + + /* webrtc2sip mode */ + if(self->stack->network.mode == tsip_stack_mode_webrtc2sip) { + if(TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WS(msg->src_net_type)) { // response over WS or WSS + transport = tsip_transport_layer_find_by_idx(self, tsip_transport_get_idx_by_name(msg->firstVia->transport)); + if(transport) { + tsk_strupdate(destIP, msg->firstVia->host); + *destPort = msg->firstVia->port; + msg->dst_net_type = transport->type; + } + return transport; + } + else { // response over UDP, TCP or TLS + const tsip_header_Via_t* via_2nd = (const tsip_header_Via_t*)tsip_message_get_headerAt(msg, tsip_htype_Via, 1); + tsk_bool_t via_ws_transport = via_2nd && (tsk_striequals(via_2nd->transport, "WS") || tsk_striequals(via_2nd->transport, "WSS")); + tsk_bool_t via_ws_hacked = via_2nd && TSIP_HEADER_HAVE_PARAM(via_2nd, "ws-hacked"); + if(via_2nd && (via_ws_transport || via_ws_hacked)) { + int t_idx = tsip_transport_get_idx_by_name(via_ws_transport ? via_2nd->transport : TSIP_HEADER_GET_PARAM_VALUE(via_2nd, "ws-hacked")); + const tsip_transport_t* ws_transport = tsip_transport_layer_find_by_idx(self, t_idx); + if(ws_transport) { + tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_remote_ip(TSIP_TRANSPORT(ws_transport), via_2nd->host, via_2nd->port, ws_transport->type); + if(peer) { + tsk_strupdate(destIP, peer->remote_ip); + *destPort = peer->remote_port; + msg->dst_net_type = ws_transport->type; + TSK_OBJECT_SAFE_FREE(peer); + return ws_transport; + } + } + + TSK_DEBUG_ERROR("Failed to match response expected to be forwarded via WebSocket transport"); + return tsk_null; + } + } + } + + if(TSIP_HEADER_VIA_RELIABLE_TRANS(msg->firstVia)) { /*== RELIABLE ===*/ + /* RFC 3261 - 18.2.2 Sending Responses + If the "sent-protocol" is a reliable transport protocol such as + TCP or SCTP, or TLS over those, the response MUST be sent using + the existing connection to the source of the original request + that created the transaction, if that connection is still open. + This requires the server transport to maintain an association + between server transactions and transport connections. If that + connection is no longer open, the server SHOULD open a + connection to the IP address in the "received" parameter, if + present, using the port in the "sent-by" value, or the default + port for that transport, if no port is specified. If that + connection attempt fails, the server SHOULD use the procedures + in [4] for servers in order to determine the IP address and + port to open the connection and send the response to. + */ + if(tsk_strnullORempty(*destIP)) { + tnet_ip_t peer_ip; + tnet_port_t peer_port; + if(transport && tnet_get_peerip_n_port(msg->local_fd, &peer_ip, &peer_port) == 0) { // connection is still open ? + tsk_strupdate(destIP, peer_ip); + *destPort = peer_port; + } + else { + if(msg->firstVia->received) { + tsk_strupdate(destIP, msg->firstVia->received); + *destPort = msg->firstVia->rport > 0 ? msg->firstVia->rport : msg->firstVia->port; + } + else { + tsk_strupdate(destIP, msg->firstVia->host); + *destPort = msg->firstVia->port; + } + } + } + } + else { + if(msg->firstVia->maddr) { /*== UNRELIABLE MULTICAST ===*/ + /* RFC 3261 - 18.2.2 Sending Responses + Otherwise, if the Via header field value contains a "maddr" parameter, the + response MUST be forwarded to the address listed there, using + the port indicated in "sent-by", or port 5060 if none is present. + If the address is a multicast address, the response SHOULD be + sent using the TTL indicated in the "ttl" parameter, or with a + TTL of 1 if that parameter is not present. + */ + } + else { /*=== UNRELIABLE UNICAST ===*/ + if(msg->firstVia->received) { + if(msg->firstVia->rport > 0) { + /* RFC 3581 - 4. Server Behavior + When a server attempts to send a response, it examines the topmost + Via header field value of that response. If the "sent-protocol" + component indicates an unreliable unicast transport protocol, such as + UDP, and there is no "maddr" parameter, but there is both a + "received" parameter and an "rport" parameter, the response MUST be + sent to the IP address listed in the "received" parameter, and the + port in the "rport" parameter. The response MUST be sent from the + same address and port that the corresponding request was received on. + This effectively adds a new processing step between bullets two and + three in Section 18.2.2 of SIP [1]. + */ + tsk_strupdate(destIP, msg->firstVia->received); + *destPort = msg->firstVia->rport; + } + else { + /* RFC 3261 - 18.2.2 Sending Responses + Otherwise (for unreliable unicast transports), if the top Via + has a "received" parameter, the response MUST be sent to the + address in the "received" parameter, using the port indicated + in the "sent-by" value, or using port 5060 if none is specified + explicitly. If this fails, for example, elicits an ICMP "port + unreachable" response, the procedures of Section 5 of [4] + SHOULD be used to determine where to send the response. + */ + tsk_strupdate(destIP, msg->firstVia->received); + *destPort = msg->firstVia->port ? msg->firstVia->port : 5060; + } + } + else { + /* RFC 3261 - 18.2.2 Sending Responses + Otherwise, if it is not receiver-tagged, the response MUST be + sent to the address indicated by the "sent-by" value, using the + procedures in Section 5 of [4]. + */ + tsk_strupdate(destIP, msg->firstVia->host); + if(msg->firstVia->port > 0) { + *destPort = msg->firstVia->port; + } + } + } + } + } + + // update message to avoid destination address to avoid running the same algo for retransmissions + tsk_strupdate(&msg->dst_address, *destIP); + msg->dst_port = *destPort; + if(!TNET_SOCKET_TYPE_IS_VALID(msg->dst_net_type) && transport) { + msg->dst_net_type = transport->type; + } + bail: - return transport; + return transport; } int tsip_transport_layer_add(tsip_transport_layer_t* self, const char* local_host, tnet_port_t local_port, tnet_socket_type_t type, const char* description) { - // FIXME: CHECK IF already exist - if(self && description) - { - tsip_transport_t *transport = - (TNET_SOCKET_TYPE_IS_IPSEC(type) || self->stack->security.enable_secagree_ipsec) ? - (tsip_transport_t *)tsip_transport_ipsec_create((tsip_stack_t*)self->stack, local_host, local_port, type, description) /* IPSec is a special case. All other are ok. */ - : tsip_transport_create((tsip_stack_t*)self->stack, local_host, local_port, type, description); /* UDP, SCTP, TCP, TLS, WS, WSS */ - - if(transport && transport->net_transport && self->stack){ - /* Set TLS certs */ - if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type) || TNET_SOCKET_TYPE_IS_DTLS(type) || self->stack->security.enable_secagree_tls){ - tsip_transport_tls_set_certs(transport, self->stack->security.tls.ca, self->stack->security.tls.pbk, self->stack->security.tls.pvk, self->stack->security.tls.verify); - } - /* Nat Traversal context */ - if(self->stack->natt.ctx){ - tnet_transport_set_natt_ctx(transport->net_transport, self->stack->natt.ctx); - } - tsk_list_push_back_data(self->transports, (void**)&transport); - return 0; - } - else { - return -2; - } - } - return -1; + // FIXME: CHECK IF already exist + if(self && description) { + tsip_transport_t *transport = + (TNET_SOCKET_TYPE_IS_IPSEC(type) || self->stack->security.enable_secagree_ipsec) ? + (tsip_transport_t *)tsip_transport_ipsec_create((tsip_stack_t*)self->stack, local_host, local_port, type, description) /* IPSec is a special case. All other are ok. */ + : tsip_transport_create((tsip_stack_t*)self->stack, local_host, local_port, type, description); /* UDP, SCTP, TCP, TLS, WS, WSS */ + + if(transport && transport->net_transport && self->stack) { + /* Set TLS certs */ + if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type) || TNET_SOCKET_TYPE_IS_DTLS(type) || self->stack->security.enable_secagree_tls) { + tsip_transport_tls_set_certs(transport, self->stack->security.tls.ca, self->stack->security.tls.pbk, self->stack->security.tls.pvk, self->stack->security.tls.verify); + } + /* Nat Traversal context */ + if(self->stack->natt.ctx) { + tnet_transport_set_natt_ctx(transport->net_transport, self->stack->natt.ctx); + } + tsk_list_push_back_data(self->transports, (void**)&transport); + return 0; + } + else { + return -2; + } + } + return -1; } int tsip_transport_layer_send(const tsip_transport_layer_t* self, const char *branch, tsip_message_t *msg) { - if(msg && self && self->stack){ - char* destIP = tsk_null; - int32_t destPort = 5060; - const tsip_transport_t *transport = tsip_transport_layer_find(self, msg, &destIP, &destPort); - int ret; - if(transport){ - if(tsip_transport_send(transport, branch, TSIP_MESSAGE(msg), destIP, destPort) > 0/* returns number of send bytes */){ - ret = 0; - } - else{ - ret = -3; - } - } - else{ - TSK_DEBUG_ERROR("Failed to find valid transport"); - ret = -2; - } - TSK_FREE(destIP); - return ret; - } - else{ - TSK_DEBUG_ERROR("Invalid Parameter"); - return -1; - } + if(msg && self && self->stack) { + char* destIP = tsk_null; + int32_t destPort = 5060; + const tsip_transport_t *transport = tsip_transport_layer_find(self, msg, &destIP, &destPort); + int ret; + if(transport) { + if(tsip_transport_send(transport, branch, TSIP_MESSAGE(msg), destIP, destPort) > 0/* returns number of send bytes */) { + ret = 0; + } + else { + ret = -3; + } + } + else { + TSK_DEBUG_ERROR("Failed to find valid transport"); + ret = -2; + } + TSK_FREE(destIP); + return ret; + } + else { + TSK_DEBUG_ERROR("Invalid Parameter"); + return -1; + } } int tsip_transport_createTempSAs(const tsip_transport_layer_t *self) { - int ret = -1; - - tsk_list_item_t *item; - tsip_transport_t* transport; - - if(!self){ - goto bail; - } - - tsk_list_foreach(item, self->transports){ - transport = item->data; - if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)){ - ret = tsip_transport_ipsec_createTempSAs(TSIP_TRANSPORT_IPSEC(transport)); - break; - } - } + int ret = -1; + + tsk_list_item_t *item; + tsip_transport_t* transport; + + if(!self) { + goto bail; + } + + tsk_list_foreach(item, self->transports) { + transport = item->data; + if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)) { + ret = tsip_transport_ipsec_createTempSAs(TSIP_TRANSPORT_IPSEC(transport)); + break; + } + } bail: - return ret; + return ret; } int tsip_transport_ensureTempSAs(const tsip_transport_layer_t *self, const tsip_response_t *r401_407, int64_t expires) { - int ret = -1; - - tsk_list_item_t *item; - tsip_transport_t* transport; - - if(!self){ - goto bail; - } - - tsk_list_foreach(item, self->transports){ - transport = item->data; - if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)){ - ret = tsip_transport_ipsec_ensureTempSAs(TSIP_TRANSPORT_IPSEC(transport), r401_407, expires); - break; - } - } + int ret = -1; + + tsk_list_item_t *item; + tsip_transport_t* transport; + + if(!self) { + goto bail; + } + + tsk_list_foreach(item, self->transports) { + transport = item->data; + if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)) { + ret = tsip_transport_ipsec_ensureTempSAs(TSIP_TRANSPORT_IPSEC(transport), r401_407, expires); + break; + } + } bail: - return ret; + return ret; } int tsip_transport_startSAs(const tsip_transport_layer_t* self, const void* ik, const void* ck) { - int ret = -1; - - tsk_list_item_t *item; - tsip_transport_t* transport; - - if(!self){ - goto bail; - } - - tsk_list_foreach(item, self->transports){ - transport = item->data; - if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)){ - ret = tsip_transport_ipsec_startSAs(TSIP_TRANSPORT_IPSEC(transport), (const tipsec_key_t*)ik, (const tipsec_key_t*)ck); - break; - } - } + int ret = -1; + + tsk_list_item_t *item; + tsip_transport_t* transport; + + if(!self) { + goto bail; + } + + tsk_list_foreach(item, self->transports) { + transport = item->data; + if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)) { + ret = tsip_transport_ipsec_startSAs(TSIP_TRANSPORT_IPSEC(transport), (const tipsec_key_t*)ik, (const tipsec_key_t*)ck); + break; + } + } bail: - return ret; + return ret; } int tsip_transport_cleanupSAs(const tsip_transport_layer_t *self) { - int ret = -1; - - tsk_list_item_t *item; - tsip_transport_t* transport; - - if(!self){ - goto bail; - } - - tsk_list_foreach(item, self->transports){ - transport = item->data; - if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)){ - ret = tsip_transport_ipsec_cleanupSAs(TSIP_TRANSPORT_IPSEC(transport)); - break; - } - } + int ret = -1; + + tsk_list_item_t *item; + tsip_transport_t* transport; + + if(!self) { + goto bail; + } + + tsk_list_foreach(item, self->transports) { + transport = item->data; + if(TNET_SOCKET_TYPE_IS_IPSEC(transport->type)) { + ret = tsip_transport_ipsec_cleanupSAs(TSIP_TRANSPORT_IPSEC(transport)); + break; + } + } bail: - return ret; + return ret; } int tsip_transport_layer_remove_callid_from_stream_peers(tsip_transport_layer_t *self, const char* callid) { - if(self && callid){ - int ret = 0; - tsk_bool_t removed = tsk_false; - tsip_transport_t* transport; - tsk_list_item_t* item; - tsk_list_lock(self->transports); - tsk_list_foreach(item, self->transports){ - if(!(transport = TSIP_TRANSPORT(item->data)) || !TNET_SOCKET_TYPE_IS_STREAM(transport->type)){ - continue; - } - if((ret = tsip_transport_remove_callid_from_stream_peers(transport, callid, &removed)) == 0 && removed){ - TSK_DEBUG_INFO("[Transport Layer] Removed call-id = '%s' from transport layer", callid); - break; - } - } - tsk_list_unlock(self->transports); - return ret; - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self && callid) { + int ret = 0; + tsk_bool_t removed = tsk_false; + tsip_transport_t* transport; + tsk_list_item_t* item; + tsk_list_lock(self->transports); + tsk_list_foreach(item, self->transports) { + if(!(transport = TSIP_TRANSPORT(item->data)) || !TNET_SOCKET_TYPE_IS_STREAM(transport->type)) { + continue; + } + if((ret = tsip_transport_remove_callid_from_stream_peers(transport, callid, &removed)) == 0 && removed) { + TSK_DEBUG_INFO("[Transport Layer] Removed call-id = '%s' from transport layer", callid); + break; + } + } + tsk_list_unlock(self->transports); + return ret; + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } tsk_bool_t tsip_transport_layer_have_stream_peer_with_remote_ip(const tsip_transport_layer_t *self, const char* remote_ip, tnet_port_t remote_port) { - if(self && remote_ip){ - const tsk_list_item_t* item; - tsk_bool_t found = tsk_false; - tsip_transport_t* transport; - tsk_list_lock(self->transports); - tsk_list_foreach(item, self->transports){ - if(!(transport = TSIP_TRANSPORT(item->data)) || !TNET_SOCKET_TYPE_IS_STREAM(transport->type)){ - continue; - } - if(tsip_transport_have_stream_peer_with_remote_ip(transport, remote_ip, remote_port, transport->type)){ - found = tsk_true; - break; - } - } - tsk_list_unlock(self->transports); - return found; - } - return tsk_false; + if(self && remote_ip) { + const tsk_list_item_t* item; + tsk_bool_t found = tsk_false; + tsip_transport_t* transport; + tsk_list_lock(self->transports); + tsk_list_foreach(item, self->transports) { + if(!(transport = TSIP_TRANSPORT(item->data)) || !TNET_SOCKET_TYPE_IS_STREAM(transport->type)) { + continue; + } + if(tsip_transport_have_stream_peer_with_remote_ip(transport, remote_ip, remote_port, transport->type)) { + found = tsk_true; + break; + } + } + tsk_list_unlock(self->transports); + return found; + } + return tsk_false; } @@ -1260,100 +1251,102 @@ tsk_bool_t tsip_transport_layer_have_stream_peer_with_remote_ip(const tsip_trans int tsip_transport_layer_start(tsip_transport_layer_t* self) { - if(self){ - if(!self->running){ - int ret = 0; - tsk_list_item_t *item; - tsip_transport_t* transport; - int32_t transport_idx = self->stack->network.transport_idx_default; - - /* start() */ - tsk_list_foreach(item, self->transports){ - transport = item->data; - if((ret = tsip_transport_start(transport))){ - return ret; - } - } - - /* connect() */ - tsk_list_foreach(item, self->transports){ - transport = item->data; - - // set callback - if(TNET_SOCKET_TYPE_IS_DGRAM(transport->type)){ - tsip_transport_set_callback(transport, TNET_TRANSPORT_CB_F(tsip_transport_layer_dgram_cb), transport); - } - else if(TNET_SOCKET_TYPE_IS_WS(transport->type) || TNET_SOCKET_TYPE_IS_WSS(transport->type)){ - tsip_transport_set_callback(transport, TNET_TRANSPORT_CB_F(tsip_transport_layer_ws_cb), transport); - } - else{ - tsip_transport_set_callback(transport, TNET_TRANSPORT_CB_F(tsip_transport_layer_stream_cb), transport); - } - - if((ret = tnet_sockaddr_init(self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx], transport->type, &transport->pcscf_addr))){ - TSK_DEBUG_ERROR("[%s:%u] is invalid address", self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx]); - return ret; - } - - if(TNET_SOCKET_TYPE_IS_STREAM(transport->type)){ - if(!TSIP_STACK_MODE_IS_SERVER(transport->stack)){ - // Between "tsip_transport_connectto_2()" and "tsip_transport_add_stream_peer_2()" the net callback could be called and - // off cource peer will not be found in the list. This is why the list is locked. + if(self) { + if(!self->running) { + int ret = 0; + tsk_list_item_t *item; + tsip_transport_t* transport; + int32_t transport_idx = self->stack->network.transport_idx_default; + + /* start() */ + tsk_list_foreach(item, self->transports) { + transport = item->data; + if((ret = tsip_transport_start(transport))) { + return ret; + } + } + + /* connect() */ + tsk_list_foreach(item, self->transports) { + transport = item->data; + + // set callback + if(TNET_SOCKET_TYPE_IS_DGRAM(transport->type)) { + tsip_transport_set_callback(transport, TNET_TRANSPORT_CB_F(tsip_transport_layer_dgram_cb), transport); + } + else if(TNET_SOCKET_TYPE_IS_WS(transport->type) || TNET_SOCKET_TYPE_IS_WSS(transport->type)) { + tsip_transport_set_callback(transport, TNET_TRANSPORT_CB_F(tsip_transport_layer_ws_cb), transport); + } + else { + tsip_transport_set_callback(transport, TNET_TRANSPORT_CB_F(tsip_transport_layer_stream_cb), transport); + } + + if((ret = tnet_sockaddr_init(self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx], transport->type, &transport->pcscf_addr))) { + TSK_DEBUG_ERROR("[%s:%u] is invalid address", self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx]); + return ret; + } + + if(TNET_SOCKET_TYPE_IS_STREAM(transport->type)) { + if(!TSIP_STACK_MODE_IS_SERVER(transport->stack)) { + // Between "tsip_transport_connectto_2()" and "tsip_transport_add_stream_peer_2()" the net callback could be called and + // off cource peer will not be found in the list. This is why the list is locked. tsip_transport_stream_peers_lock(transport); - if((transport->connectedFD = tsip_transport_connectto_2(transport, self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx])) == TNET_INVALID_FD){ - TSK_DEBUG_ERROR("Failed to connect the SIP transport"); - tsip_transport_stream_peers_unlock(transport); - return -3; - } + if((transport->connectedFD = tsip_transport_connectto_2(transport, self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx])) == TNET_INVALID_FD) { + TSK_DEBUG_ERROR("Failed to connect the SIP transport"); + tsip_transport_stream_peers_unlock(transport); + return -3; + } TSK_DEBUG_INFO("SIP transport fd=%d", transport->connectedFD); - // store peer - tsip_transport_add_stream_peer_2(transport, transport->connectedFD, transport->type, tsk_false, self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx]); - tsip_transport_stream_peers_unlock(transport); - // give the socket chance to connect - if((ret = tnet_sockfd_waitUntilWritable(transport->connectedFD, TSIP_CONNECT_TIMEOUT)) || (ret = tnet_sockfd_waitUntilReadable(transport->connectedFD, TSIP_CONNECT_TIMEOUT))){ - TSK_DEBUG_INFO("%d milliseconds elapsed and the socket is still not connected.", TSIP_CONNECT_TIMEOUT); - // dot not exit, store the outgoing data until connection succeed - } - } - } - + // store peer + tsip_transport_add_stream_peer_2(transport, transport->connectedFD, transport->type, tsk_false, self->stack->network.proxy_cscf[transport_idx], self->stack->network.proxy_cscf_port[transport_idx]); + tsip_transport_stream_peers_unlock(transport); + // give the socket chance to connect + if((ret = tnet_sockfd_waitUntilWritable(transport->connectedFD, TSIP_CONNECT_TIMEOUT)) || (ret = tnet_sockfd_waitUntilReadable(transport->connectedFD, TSIP_CONNECT_TIMEOUT))) { + TSK_DEBUG_INFO("%d milliseconds elapsed and the socket is still not connected.", TSIP_CONNECT_TIMEOUT); + // dot not exit, store the outgoing data until connection succeed + } + } + } + // set connectedFD=master for servers - if(transport->connectedFD == TNET_INVALID_FD){ - transport->connectedFD = tnet_transport_get_master_fd(transport->net_transport); - } - } - - self->running = tsk_true; - - return 0; - } - else return -2; - } - return -1; + if(transport->connectedFD == TNET_INVALID_FD) { + transport->connectedFD = tnet_transport_get_master_fd(transport->net_transport); + } + } + + self->running = tsk_true; + + return 0; + } + else { + return -2; + } + } + return -1; } int tsip_transport_layer_shutdown(tsip_transport_layer_t* self) { - if(self){ - if(!TSK_LIST_IS_EMPTY(self->transports)){ - //if(self->running){ - /*int ret = 0;*/ - tsk_list_item_t *item; - while((item = tsk_list_pop_first_item(self->transports))){ - TSK_OBJECT_SAFE_FREE(item); // Network transports are not reusable ==> (shutdow+remove) - } - self->running = tsk_false; - return 0; - } - else{ - return 0; /* not running */ - } - } - else{ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(self) { + if(!TSK_LIST_IS_EMPTY(self->transports)) { + //if(self->running){ + /*int ret = 0;*/ + tsk_list_item_t *item; + while((item = tsk_list_pop_first_item(self->transports))) { + TSK_OBJECT_SAFE_FREE(item); // Network transports are not reusable ==> (shutdow+remove) + } + self->running = tsk_false; + return 0; + } + else { + return 0; /* not running */ + } + } + else { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } } @@ -1366,38 +1359,37 @@ int tsip_transport_layer_shutdown(tsip_transport_layer_t* self) // static tsk_object_t* tsip_transport_layer_ctor(tsk_object_t * self, va_list * app) { - tsip_transport_layer_t *layer = self; - if(layer){ - layer->stack = va_arg(*app, const tsip_stack_t *); + tsip_transport_layer_t *layer = self; + if(layer) { + layer->stack = va_arg(*app, const tsip_stack_t *); - layer->transports = tsk_list_create(); - } - return self; + layer->transports = tsk_list_create(); + } + return self; } static tsk_object_t* tsip_transport_layer_dtor(tsk_object_t * self) -{ - tsip_transport_layer_t *layer = self; - if(layer){ - tsip_transport_layer_shutdown(self); +{ + tsip_transport_layer_t *layer = self; + if(layer) { + tsip_transport_layer_shutdown(self); - TSK_OBJECT_SAFE_FREE(layer->transports); + TSK_OBJECT_SAFE_FREE(layer->transports); - TSK_DEBUG_INFO("*** Transport Layer destroyed ***"); - } - return self; + TSK_DEBUG_INFO("*** Transport Layer destroyed ***"); + } + return self; } static int tsip_transport_layer_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_transport_layer_def_s = -{ - sizeof(tsip_transport_layer_t), - tsip_transport_layer_ctor, - tsip_transport_layer_dtor, - tsip_transport_layer_cmp, +static const tsk_object_def_t tsip_transport_layer_def_s = { + sizeof(tsip_transport_layer_t), + tsip_transport_layer_ctor, + tsip_transport_layer_dtor, + tsip_transport_layer_cmp, }; const tsk_object_def_t *tsip_transport_layer_def_t = &tsip_transport_layer_def_s; |