diff options
Diffstat (limited to 'tinySIP/src/transports')
-rwxr-xr-x | tinySIP/src/transports/tsip_transport.c | 1707 | ||||
-rwxr-xr-x | tinySIP/src/transports/tsip_transport_ipsec.c | 781 | ||||
-rwxr-xr-x | tinySIP/src/transports/tsip_transport_layer.c | 2408 |
3 files changed, 2441 insertions, 2455 deletions
diff --git a/tinySIP/src/transports/tsip_transport.c b/tinySIP/src/transports/tsip_transport.c index f86f718..e9d2473 100755 --- a/tinySIP/src/transports/tsip_transport.c +++ b/tinySIP/src/transports/tsip_transport.c @@ -8,12 +8,12 @@ * 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. * @@ -56,68 +56,67 @@ static const char* __null_callid = tsk_null; -static const tsip_transport_idx_xt _tsip_transport_idxs_xs[TSIP_TRANSPORT_IDX_MAX] = -{ - { TSIP_TRANSPORT_IDX_UDP, "UDP", TNET_SOCKET_TYPE_UDP }, - { TSIP_TRANSPORT_IDX_DTLS, "DTLS", TNET_SOCKET_TYPE_DTLS }, - { TSIP_TRANSPORT_IDX_TCP, "TCP", TNET_SOCKET_TYPE_TCP }, - { TSIP_TRANSPORT_IDX_TLS, "TLS", TNET_SOCKET_TYPE_TLS }, - { TSIP_TRANSPORT_IDX_WS, "WS", TNET_SOCKET_TYPE_WS }, - { TSIP_TRANSPORT_IDX_WSS, "WSS", TNET_SOCKET_TYPE_WSS }, +static const tsip_transport_idx_xt _tsip_transport_idxs_xs[TSIP_TRANSPORT_IDX_MAX] = { + { TSIP_TRANSPORT_IDX_UDP, "UDP", TNET_SOCKET_TYPE_UDP }, + { TSIP_TRANSPORT_IDX_DTLS, "DTLS", TNET_SOCKET_TYPE_DTLS }, + { TSIP_TRANSPORT_IDX_TCP, "TCP", TNET_SOCKET_TYPE_TCP }, + { TSIP_TRANSPORT_IDX_TLS, "TLS", TNET_SOCKET_TYPE_TLS }, + { TSIP_TRANSPORT_IDX_WS, "WS", TNET_SOCKET_TYPE_WS }, + { TSIP_TRANSPORT_IDX_WSS, "WSS", TNET_SOCKET_TYPE_WSS }, }; const tsip_transport_idx_xt* tsip_transport_get_by_name(const char* name) { - int i; - if(!name) { - return tsk_null; - } - for(i = 0; i < TSIP_TRANSPORT_IDX_MAX; ++i) { - if(tsk_striequals(_tsip_transport_idxs_xs[i].name, name)){ - return &_tsip_transport_idxs_xs[i]; - } - } - return tsk_null; + int i; + if(!name) { + return tsk_null; + } + for(i = 0; i < TSIP_TRANSPORT_IDX_MAX; ++i) { + if(tsk_striequals(_tsip_transport_idxs_xs[i].name, name)) { + return &_tsip_transport_idxs_xs[i]; + } + } + return tsk_null; } // returns -1 if not exist int tsip_transport_get_idx_by_name(const char* name) { - const tsip_transport_idx_xt* t_idx = tsip_transport_get_by_name(name); - return t_idx ? t_idx->idx : -1; + const tsip_transport_idx_xt* t_idx = tsip_transport_get_by_name(name); + return t_idx ? t_idx->idx : -1; } enum tnet_socket_type_e tsip_transport_get_type_by_name(const char* name) { - const tsip_transport_idx_xt* t_idx = tsip_transport_get_by_name(name); - return t_idx ? t_idx->type : tnet_socket_type_invalid; + const tsip_transport_idx_xt* t_idx = tsip_transport_get_by_name(name); + return t_idx ? t_idx->type : tnet_socket_type_invalid; } /*== Predicate function to find a peer by local id */ static int _pred_find_stream_peer_by_local_fd(const tsk_list_item_t *item, const void *local_fd) { - if(item && item->data){ - const tsip_transport_stream_peer_t *peer = (const tsip_transport_stream_peer_t*)item->data; - return (peer->local_fd - *((tnet_fd_t*)local_fd)); - } - return -1; + if(item && item->data) { + const tsip_transport_stream_peer_t *peer = (const tsip_transport_stream_peer_t*)item->data; + return (peer->local_fd - *((tnet_fd_t*)local_fd)); + } + return -1; } /* creates new SIP transport */ tsip_transport_t* tsip_transport_create(tsip_stack_t* stack, const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description) { - tsip_transport_t* transport; - if((transport = tsk_object_new(tsip_transport_def_t, stack, host, port, type, description))){ - int i; - for(i = 0; i < sizeof(_tsip_transport_idxs_xs)/sizeof(_tsip_transport_idxs_xs[0]); ++i){ - if(_tsip_transport_idxs_xs[i].type & type){ - transport->idx = _tsip_transport_idxs_xs[i].idx; - break; - } - } - } - return transport; + tsip_transport_t* transport; + if((transport = tsk_object_new(tsip_transport_def_t, stack, host, port, type, description))) { + int i; + for(i = 0; i < sizeof(_tsip_transport_idxs_xs)/sizeof(_tsip_transport_idxs_xs[0]); ++i) { + if(_tsip_transport_idxs_xs[i].type & type) { + transport->idx = _tsip_transport_idxs_xs[i].idx; + break; + } + } + } + return transport; } /* add Via header using the transport config @@ -125,866 +124,868 @@ must be called after update_aor() */ int tsip_transport_addvia(const tsip_transport_t* self, const char *branch, tsip_message_t *msg) { - tnet_ip_t ip = { '\0' }; - tnet_port_t port; - int ret; - int32_t transport_idx; - - if((transport_idx = tsip_transport_get_idx_by_name(self->protocol)) == -1){ - transport_idx = self->stack->network.transport_idx_default; - } - - /* we always use same port to send() and recv() msg which means Via and Contact headers are identical */ - if(TNET_SOCKET_TYPE_IS_IPSEC(self->type) && ((tsip_transport_ipsec_t*)self)->asso_active){ - memcpy(ip, ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->ip, sizeof(tnet_ip_t)); - port = ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->port; - } - else if(self->stack->network.aor.ip[transport_idx] && self->stack->network.aor.port[transport_idx]){ - memcpy(ip, self->stack->network.aor.ip[transport_idx], TSK_MIN(tsk_strlen(self->stack->network.aor.ip[transport_idx]), sizeof(ip))); - port = self->stack->network.aor.port[transport_idx]; - } - else if((ret = tsip_transport_get_ip_n_port(self, &ip, &port))){ - return ret; - } - - /* is there a Via header? */ - if(!msg->firstVia){ - /* RFC 3261 - 18.1.1 Sending Requests - Before a request is sent, the client transport MUST insert a value of - the "sent-by" field into the Via header field. This field contains - an IP address or host name, and port. The usage of an FQDN is - RECOMMENDED. This field is used for sending responses under certain - conditions, described below. If the port is absent, the default - value depends on the transport. It is 5060 for UDP, TCP and SCTP, - 5061 for TLS. - */ - msg->firstVia = tsip_header_Via_create(TSIP_HEADER_VIA_PROTO_NAME_DEFAULT, TSIP_HEADER_VIA_PROTO_VERSION_DEFAULT, self->via_protocol, ip, port); - TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "rport", tsk_null); - } - else if(msg->update && self->stack->network.mode == tsip_stack_mode_webrtc2sip){ - if(TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type)){ - const tsip_transport_t* ws_transport = tsip_transport_layer_find_by_type(self->stack->layer_transport, msg->src_net_type); - if(ws_transport){ - tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_local_fd(TSIP_TRANSPORT(ws_transport), msg->local_fd); - if(peer){ - // hack the first Via as many servers fail to parse "WS" or "WSS" as valid transpors - //if(tsk_striequals(msg->firstVia->transport, "WS") || tsk_striequals(msg->firstVia->transport, "WSS")){ - TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "ws-hacked", TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type) ? "WSS" : "WS"); - tsk_strupdate(&msg->firstVia->transport, "TCP"); - tsk_strupdate(&msg->firstVia->host, peer->remote_ip); - msg->firstVia->port = peer->remote_port; - //} - TSK_OBJECT_SAFE_FREE(peer); - - // replace first Via with ours - tsip_message_add_header(msg, (const tsip_header_t *)msg->firstVia); - TSK_OBJECT_SAFE_FREE(msg->firstVia); - msg->firstVia = tsip_header_Via_create(TSIP_HEADER_VIA_PROTO_NAME_DEFAULT, TSIP_HEADER_VIA_PROTO_VERSION_DEFAULT, self->via_protocol, ip, port); - TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "rport", tsk_null); - } - } - } - } - - /* updates the branch */ - if(branch){ - tsk_strupdate(&msg->firstVia->branch, branch); - } - else{ /* Probably ACK sent from Dialog Layer */ - TSK_FREE(msg->firstVia->branch); - if((msg->firstVia->branch = tsk_strdup(TSIP_TRANSAC_MAGIC_COOKIE))){ - tsk_istr_t _branch; - tsk_strrandom(&_branch); - tsk_strcat_2(&msg->firstVia->branch, "-%s", _branch); - } - } - - /* multicast case */ - if(tsk_false){ - /* RFC 3261 - 18.1.1 Sending Requests (FIXME) - A client that sends a request to a multicast address MUST add the - "maddr" parameter to its Via header field value containing the - destination multicast address, and for IPv4, SHOULD add the "ttl" - parameter with a value of 1. Usage of IPv6 multicast is not defined - in this specification, and will be a subject of future - standardization when the need arises. - */ - } - - /* - * comp=sigcomp; sigcomp-id= - */ - - return 0; + tnet_ip_t ip = { '\0' }; + tnet_port_t port; + int ret; + int32_t transport_idx; + + if((transport_idx = tsip_transport_get_idx_by_name(self->protocol)) == -1) { + transport_idx = self->stack->network.transport_idx_default; + } + + /* we always use same port to send() and recv() msg which means Via and Contact headers are identical */ + if(TNET_SOCKET_TYPE_IS_IPSEC(self->type) && ((tsip_transport_ipsec_t*)self)->asso_active) { + memcpy(ip, ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->ip, sizeof(tnet_ip_t)); + port = ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->port; + } + else if(self->stack->network.aor.ip[transport_idx] && self->stack->network.aor.port[transport_idx]) { + memcpy(ip, self->stack->network.aor.ip[transport_idx], TSK_MIN(tsk_strlen(self->stack->network.aor.ip[transport_idx]), sizeof(ip))); + port = self->stack->network.aor.port[transport_idx]; + } + else if((ret = tsip_transport_get_ip_n_port(self, &ip, &port))) { + return ret; + } + + /* is there a Via header? */ + if(!msg->firstVia) { + /* RFC 3261 - 18.1.1 Sending Requests + Before a request is sent, the client transport MUST insert a value of + the "sent-by" field into the Via header field. This field contains + an IP address or host name, and port. The usage of an FQDN is + RECOMMENDED. This field is used for sending responses under certain + conditions, described below. If the port is absent, the default + value depends on the transport. It is 5060 for UDP, TCP and SCTP, + 5061 for TLS. + */ + msg->firstVia = tsip_header_Via_create(TSIP_HEADER_VIA_PROTO_NAME_DEFAULT, TSIP_HEADER_VIA_PROTO_VERSION_DEFAULT, self->via_protocol, ip, port); + TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "rport", tsk_null); + } + else if(msg->update && self->stack->network.mode == tsip_stack_mode_webrtc2sip) { + if(TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type)) { + const tsip_transport_t* ws_transport = tsip_transport_layer_find_by_type(self->stack->layer_transport, msg->src_net_type); + if(ws_transport) { + tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_local_fd(TSIP_TRANSPORT(ws_transport), msg->local_fd); + if(peer) { + // hack the first Via as many servers fail to parse "WS" or "WSS" as valid transpors + //if(tsk_striequals(msg->firstVia->transport, "WS") || tsk_striequals(msg->firstVia->transport, "WSS")){ + TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "ws-hacked", TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type) ? "WSS" : "WS"); + tsk_strupdate(&msg->firstVia->transport, "TCP"); + tsk_strupdate(&msg->firstVia->host, peer->remote_ip); + msg->firstVia->port = peer->remote_port; + //} + TSK_OBJECT_SAFE_FREE(peer); + + // replace first Via with ours + tsip_message_add_header(msg, (const tsip_header_t *)msg->firstVia); + TSK_OBJECT_SAFE_FREE(msg->firstVia); + msg->firstVia = tsip_header_Via_create(TSIP_HEADER_VIA_PROTO_NAME_DEFAULT, TSIP_HEADER_VIA_PROTO_VERSION_DEFAULT, self->via_protocol, ip, port); + TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "rport", tsk_null); + } + } + } + } + + /* updates the branch */ + if(branch) { + tsk_strupdate(&msg->firstVia->branch, branch); + } + else { /* Probably ACK sent from Dialog Layer */ + TSK_FREE(msg->firstVia->branch); + if((msg->firstVia->branch = tsk_strdup(TSIP_TRANSAC_MAGIC_COOKIE))) { + tsk_istr_t _branch; + tsk_strrandom(&_branch); + tsk_strcat_2(&msg->firstVia->branch, "-%s", _branch); + } + } + + /* multicast case */ + if(tsk_false) { + /* RFC 3261 - 18.1.1 Sending Requests (FIXME) + A client that sends a request to a multicast address MUST add the + "maddr" parameter to its Via header field value containing the + destination multicast address, and for IPv4, SHOULD add the "ttl" + parameter with a value of 1. Usage of IPv6 multicast is not defined + in this specification, and will be a subject of future + standardization when the need arises. + */ + } + + /* + * comp=sigcomp; sigcomp-id= + */ + + return 0; } int tsip_transport_msg_update_aor(tsip_transport_t* self, tsip_message_t *msg) { - int ret = 0; - int32_t transport_idx; - - /* already updtated (e.g. retrans)? */ - if(!msg->update){ - return 0; - } - - if((transport_idx = tsip_transport_get_idx_by_name(self->protocol)) == -1){ - transport_idx = self->stack->network.transport_idx_default; - } - - /* retrieves the transport ip address and port */ - if(!self->stack->network.aor.ip[transport_idx] && !self->stack->network.aor.port[transport_idx]){ - tnet_ip_t ip = {0}; - tnet_port_t port = 0; - - if((ret = tsip_transport_get_public_ip_n_port(self, &ip, &port))){ - TSK_DEBUG_ERROR("Failed to get public IP"); - return ret; - } - else{ - ((tsip_stack_t*)self->stack)->network.aor.ip[transport_idx] = tsk_strdup(ip); - ((tsip_stack_t*)self->stack)->network.aor.port[transport_idx] = port; - } - } - - /* === Host and port === */ - if(msg->Contact && msg->Contact->uri){ - tsk_strupdate(&(msg->Contact->uri->scheme), self->scheme); - msg->Contact->uri->host_type = TNET_SOCKET_TYPE_IS_IPV6(self->type) ? host_ipv6 : host_ipv4; /* for serializer ...who know? */ - tsk_params_add_param(&msg->Contact->uri->params, "transport", self->protocol); - - // IPSec - if(TNET_SOCKET_TYPE_IS_IPSEC(self->type) && ((tsip_transport_ipsec_t*)self)->asso_active){ - tsk_strupdate(&(msg->Contact->uri->host), ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->ip); - msg->Contact->uri->port = ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->port; - } - else { - tsk_strupdate(&(msg->Contact->uri->host), self->stack->network.aor.ip[transport_idx]); - msg->Contact->uri->port = self->stack->network.aor.port[transport_idx]; - } - - /* Add extra params for message received over WebSocket transport */ - if((TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type)) && msg->local_fd > 0){ - tnet_ip_t ws_src_ip; - tnet_port_t ws_src_port; - if(tnet_get_ip_n_port(msg->local_fd, tsk_false/*remote*/, &ws_src_ip, &ws_src_port) == 0){ - tsk_params_add_param(&msg->Contact->uri->params, "ws-src-ip", ws_src_ip); - tsk_params_add_param_3(&msg->Contact->uri->params, "ws-src-port", (int64_t)ws_src_port); - tsk_params_add_param(&msg->Contact->uri->params, "ws-src-proto", TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) ? "ws" : "wss"); - } - } - } - - return 0; + int ret = 0; + int32_t transport_idx; + + /* already updtated (e.g. retrans)? */ + if(!msg->update) { + return 0; + } + + if((transport_idx = tsip_transport_get_idx_by_name(self->protocol)) == -1) { + transport_idx = self->stack->network.transport_idx_default; + } + + /* retrieves the transport ip address and port */ + if(!self->stack->network.aor.ip[transport_idx] && !self->stack->network.aor.port[transport_idx]) { + tnet_ip_t ip = {0}; + tnet_port_t port = 0; + + if((ret = tsip_transport_get_public_ip_n_port(self, &ip, &port))) { + TSK_DEBUG_ERROR("Failed to get public IP"); + return ret; + } + else { + ((tsip_stack_t*)self->stack)->network.aor.ip[transport_idx] = tsk_strdup(ip); + ((tsip_stack_t*)self->stack)->network.aor.port[transport_idx] = port; + } + } + + /* === Host and port === */ + if(msg->Contact && msg->Contact->uri) { + tsk_strupdate(&(msg->Contact->uri->scheme), self->scheme); + msg->Contact->uri->host_type = TNET_SOCKET_TYPE_IS_IPV6(self->type) ? host_ipv6 : host_ipv4; /* for serializer ...who know? */ + tsk_params_add_param(&msg->Contact->uri->params, "transport", self->protocol); + + // IPSec + if(TNET_SOCKET_TYPE_IS_IPSEC(self->type) && ((tsip_transport_ipsec_t*)self)->asso_active) { + tsk_strupdate(&(msg->Contact->uri->host), ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->ip); + msg->Contact->uri->port = ((tsip_transport_ipsec_t*)self)->asso_active->socket_us->port; + } + else { + tsk_strupdate(&(msg->Contact->uri->host), self->stack->network.aor.ip[transport_idx]); + msg->Contact->uri->port = self->stack->network.aor.port[transport_idx]; + } + + /* Add extra params for message received over WebSocket transport */ + if((TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type)) && msg->local_fd > 0) { + tnet_ip_t ws_src_ip; + tnet_port_t ws_src_port; + if(tnet_get_ip_n_port(msg->local_fd, tsk_false/*remote*/, &ws_src_ip, &ws_src_port) == 0) { + tsk_params_add_param(&msg->Contact->uri->params, "ws-src-ip", ws_src_ip); + tsk_params_add_param_3(&msg->Contact->uri->params, "ws-src-port", (int64_t)ws_src_port); + tsk_params_add_param(&msg->Contact->uri->params, "ws-src-proto", TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) ? "ws" : "wss"); + } + } + } + + return 0; } /* update the entire message (IPSec headers, SigComp, ....) */ int tsip_transport_msg_update(const tsip_transport_t* self, tsip_message_t *msg) { - int ret = 0; - - /* already updtated (e.g. retrans)? */ - if(!msg->update){ - return 0; - } - - /* === IPSec headers (Security-Client, Security-Verify, Sec-Agree ...) === */ - if(TNET_SOCKET_TYPE_IS_IPSEC(self->type)){ - ret = tsip_transport_ipsec_updateMSG(TSIP_TRANSPORT_IPSEC(self), msg); - } - - /* === SigComp === */ - if(msg->sigcomp_id){ - /* Via */ - if(msg->firstVia){ - char* quoted_id = tsk_null; - TSIP_HEADER_ADD_PARAM(msg->firstVia, "comp", "sigcomp"); - tsk_sprintf("ed_id, "\"%s\"", msg->sigcomp_id); - TSIP_HEADER_ADD_PARAM(msg->firstVia, "sigcomp-id", quoted_id); - TSK_FREE(quoted_id); - } - /* Contact */ - if(msg->Contact && msg->Contact->uri){ - tsk_params_add_param(&msg->Contact->uri->params, "sigcomp-id", msg->sigcomp_id); - } - } - /* === WebRTC2SIP === */ - if(TSIP_MESSAGE_IS_REQUEST(msg)) { - if(self->stack->network.mode == tsip_stack_mode_webrtc2sip) { - // Request Uri (Fix: https://code.google.com/p/webrtc2sip/issues/detail?id=56) - if(tsk_params_have_param(msg->line.request.uri->params, "transport")){ - tsk_params_add_param(&msg->line.request.uri->params, "transport", self->protocol); - } - } - } - - - msg->update = tsk_false; /* To avoid to update retrans. */ - - return ret; + int ret = 0; + + /* already updtated (e.g. retrans)? */ + if(!msg->update) { + return 0; + } + + /* === IPSec headers (Security-Client, Security-Verify, Sec-Agree ...) === */ + if(TNET_SOCKET_TYPE_IS_IPSEC(self->type)) { + ret = tsip_transport_ipsec_updateMSG(TSIP_TRANSPORT_IPSEC(self), msg); + } + + /* === SigComp === */ + if(msg->sigcomp_id) { + /* Via */ + if(msg->firstVia) { + char* quoted_id = tsk_null; + TSIP_HEADER_ADD_PARAM(msg->firstVia, "comp", "sigcomp"); + tsk_sprintf("ed_id, "\"%s\"", msg->sigcomp_id); + TSIP_HEADER_ADD_PARAM(msg->firstVia, "sigcomp-id", quoted_id); + TSK_FREE(quoted_id); + } + /* Contact */ + if(msg->Contact && msg->Contact->uri) { + tsk_params_add_param(&msg->Contact->uri->params, "sigcomp-id", msg->sigcomp_id); + } + } + /* === WebRTC2SIP === */ + if(TSIP_MESSAGE_IS_REQUEST(msg)) { + if(self->stack->network.mode == tsip_stack_mode_webrtc2sip) { + // Request Uri (Fix: https://code.google.com/p/webrtc2sip/issues/detail?id=56) + if(tsk_params_have_param(msg->line.request.uri->params, "transport")) { + tsk_params_add_param(&msg->line.request.uri->params, "transport", self->protocol); + } + } + } + + + msg->update = tsk_false; /* To avoid to update retrans. */ + + return ret; } // "udp", "tcp" or "tls" tsk_size_t tsip_transport_send_raw(const tsip_transport_t* self, const char* dst_host, tnet_port_t dst_port, const void* data, tsk_size_t size, const char* callid) { - tsk_size_t ret = 0; - - TSK_DEBUG_INFO("\n\nSEND: %.*s\n\n", size, (const char*)data); - - if(TNET_SOCKET_TYPE_IS_DGRAM(self->type)){// "udp" or "dtls" - const struct sockaddr_storage* to = &self->pcscf_addr; - struct sockaddr_storage dst_addr; // must be local scope - if(!tsk_strnullORempty(dst_host) && dst_port){ - if(tnet_sockaddr_init(dst_host, dst_port, self->type, &dst_addr) == 0){ - to = &dst_addr; - } - } - if(!(ret = tnet_transport_sendto(self->net_transport, self->connectedFD, (const struct sockaddr*)to, data, size))){ - TSK_DEBUG_ERROR("Send(%u) returns zero", size); - } - } - else{// "sctp", "tcp" or "tls" - tsip_transport_stream_peer_t* peer = tsk_null; - tnet_ip_t dst_ip; - - if(tsk_strnullORempty(dst_host) || !dst_port){ - if(tnet_get_sockip_n_port((const struct sockaddr *)&self->pcscf_addr, &dst_ip, &dst_port) != 0){ - TSK_DEBUG_ERROR("Failed to get Proxy-CSCF IP address and port"); - return 0; - } - } - else{ - // get IP address and port - // we use ip/port instead of fqdn because this what "tsip_transport_add_stream_peer()" requires it - if(tnet_resolve(dst_host, dst_port, self->type, &dst_ip, &dst_port) != 0){ - TSK_DEBUG_ERROR("Failed to resolve(%s/%d)", dst_host, dst_port); - return 0; - } - } - - if(!(peer = tsip_transport_find_stream_peer_by_remote_ip(TSIP_TRANSPORT(self), dst_ip, dst_port, self->type))){ - tnet_fd_t fd; - TSK_DEBUG_INFO("Cannot find peer with remote IP/Port=%s/%d, connecting to the destination...", dst_ip, dst_port); - // connect to the destination + tsk_size_t ret = 0; + + TSK_DEBUG_INFO("\n\nSEND: %.*s\n\n", size, (const char*)data); + + if(TNET_SOCKET_TYPE_IS_DGRAM(self->type)) { // "udp" or "dtls" + const struct sockaddr_storage* to = &self->pcscf_addr; + struct sockaddr_storage dst_addr; // must be local scope + if(!tsk_strnullORempty(dst_host) && dst_port) { + if(tnet_sockaddr_init(dst_host, dst_port, self->type, &dst_addr) == 0) { + to = &dst_addr; + } + } + if(!(ret = tnet_transport_sendto(self->net_transport, self->connectedFD, (const struct sockaddr*)to, data, size))) { + TSK_DEBUG_ERROR("Send(%u) returns zero", size); + } + } + else { // "sctp", "tcp" or "tls" + tsip_transport_stream_peer_t* peer = tsk_null; + tnet_ip_t dst_ip; + + if(tsk_strnullORempty(dst_host) || !dst_port) { + if(tnet_get_sockip_n_port((const struct sockaddr *)&self->pcscf_addr, &dst_ip, &dst_port) != 0) { + TSK_DEBUG_ERROR("Failed to get Proxy-CSCF IP address and port"); + return 0; + } + } + else { + // get IP address and port + // we use ip/port instead of fqdn because this what "tsip_transport_add_stream_peer()" requires it + if(tnet_resolve(dst_host, dst_port, self->type, &dst_ip, &dst_port) != 0) { + TSK_DEBUG_ERROR("Failed to resolve(%s/%d)", dst_host, dst_port); + return 0; + } + } + + if(!(peer = tsip_transport_find_stream_peer_by_remote_ip(TSIP_TRANSPORT(self), dst_ip, dst_port, self->type))) { + tnet_fd_t fd; + TSK_DEBUG_INFO("Cannot find peer with remote IP/Port=%s/%d, connecting to the destination...", dst_ip, dst_port); + // connect to the destination // stream with the new "fd" will be added later, make sure that no other thread (e.g. network callback) will manipulate the peers tsip_transport_stream_peers_lock(TSIP_TRANSPORT(self)); - if((fd = tnet_transport_connectto_2(TSIP_TRANSPORT(self)->net_transport, dst_ip, dst_port)) == TNET_INVALID_FD){ - TSK_DEBUG_ERROR("Failed to connect to %s/%d", dst_ip, dst_port); + if((fd = tnet_transport_connectto_2(TSIP_TRANSPORT(self)->net_transport, dst_ip, dst_port)) == TNET_INVALID_FD) { + TSK_DEBUG_ERROR("Failed to connect to %s/%d", dst_ip, dst_port); tsip_transport_stream_peers_unlock(TSIP_TRANSPORT(self)); - return 0; - } + return 0; + } // only clients will have connected fd == EVAL. For servers, it will be equal to master's fd // connected fd value will be set to EVAL when "disconnected" event is received if (TSIP_TRANSPORT(self)->connectedFD == TNET_INVALID_FD) { TSIP_TRANSPORT(self)->connectedFD = fd; } - - if(tsip_transport_add_stream_peer_2(TSIP_TRANSPORT(self), fd, self->type, tsk_false, dst_ip, dst_port) != 0){ - TSK_DEBUG_ERROR("Failed to add stream peer local fd = %d, remote IP/Port=%s/%d", fd, dst_ip, dst_port); + + if(tsip_transport_add_stream_peer_2(TSIP_TRANSPORT(self), fd, self->type, tsk_false, dst_ip, dst_port) != 0) { + TSK_DEBUG_ERROR("Failed to add stream peer local fd = %d, remote IP/Port=%s/%d", fd, dst_ip, dst_port); tsip_transport_stream_peers_unlock(TSIP_TRANSPORT(self)); - return 0; - } + return 0; + } tsip_transport_stream_peers_unlock(TSIP_TRANSPORT(self)); - - // retrieve the peer - if(!(peer = tsip_transport_find_stream_peer_by_local_fd(TSIP_TRANSPORT(self), fd))){ - TSK_DEBUG_INFO("Cannot find peer with remote IP/Port=%s/%d. Cancel data sending", dst_ip, dst_port); - return 0; - } - } - // store call-id - if(callid != __null_callid && tsip_dialog_layer_have_dialog_with_callid(self->stack->layer_dialog, callid)){ - ret = tsip_transport_stream_peer_add_callid(peer, callid); - } - // send() data - if(peer->connected){ - ret = tnet_transport_send(self->net_transport, peer->local_fd, data, size); - } - else{ - TSK_DEBUG_INFO("Data send requested but peer not connected yet...saving data"); - tsk_buffer_append(peer->snd_buff_stream, data, size); - ret = 0; // nothing sent - } - TSK_OBJECT_SAFE_FREE(peer); - } - - return ret; + + // retrieve the peer + if(!(peer = tsip_transport_find_stream_peer_by_local_fd(TSIP_TRANSPORT(self), fd))) { + TSK_DEBUG_INFO("Cannot find peer with remote IP/Port=%s/%d. Cancel data sending", dst_ip, dst_port); + return 0; + } + } + // store call-id + if(callid != __null_callid && tsip_dialog_layer_have_dialog_with_callid(self->stack->layer_dialog, callid)) { + ret = tsip_transport_stream_peer_add_callid(peer, callid); + } + // send() data + if(peer->connected) { + ret = tnet_transport_send(self->net_transport, peer->local_fd, data, size); + } + else { + TSK_DEBUG_INFO("Data send requested but peer not connected yet...saving data"); + tsk_buffer_append(peer->snd_buff_stream, data, size); + ret = 0; // nothing sent + } + TSK_OBJECT_SAFE_FREE(peer); + } + + return ret; } // "ws" or "wss" tsk_size_t tsip_transport_send_raw_ws(const tsip_transport_t* self, tnet_fd_t local_fd, const void* data, tsk_size_t size, const char* callid) { - /*static const uint8_t __ws_first_byte = 0x82;*/ - const uint8_t* pdata = (const uint8_t*)data; - uint64_t data_size = 1 + 1 + size; - uint64_t lsize = (uint64_t)size; - uint8_t* pws_snd_buffer; - tsip_transport_stream_peer_t* peer; - tsk_size_t ret; - - if(!(peer = tsip_transport_find_stream_peer_by_local_fd(TSIP_TRANSPORT(self), local_fd))){ - TSK_DEBUG_ERROR("Failed to find peer with local fd equal to %d", local_fd); - return 0; - } - - if(lsize > 0x7D && lsize <= 0xFFFF){ - data_size += 2; - } - else if(lsize > 0xFFFF){ - data_size += 8; - } - if(peer->ws.snd_buffer_size < data_size){ - if(!(peer->ws.snd_buffer = tsk_realloc(peer->ws.snd_buffer, (tsk_size_t)data_size))){ - TSK_DEBUG_ERROR("Failed to allocate buffer with size = %llu", data_size); - peer->ws.snd_buffer_size = 0; - TSK_OBJECT_SAFE_FREE(peer); - return 0; - } - peer->ws.snd_buffer_size = data_size; - } - pws_snd_buffer = (uint8_t*)peer->ws.snd_buffer; - - pws_snd_buffer[0] = 0x82; - if(lsize <= 0x7D){ - pws_snd_buffer[1] = (uint8_t)lsize; - pws_snd_buffer = &pws_snd_buffer[2]; - } - else if(lsize <= 0xFFFF){ - pws_snd_buffer[1] = 0x7E; - pws_snd_buffer[2] = (lsize >> 8) & 0xFF; - pws_snd_buffer[3] = (lsize & 0xFF); - pws_snd_buffer = &pws_snd_buffer[4]; - } - else{ - pws_snd_buffer[1] = 0x7F; - pws_snd_buffer[2] = (lsize >> 56) & 0xFF; - pws_snd_buffer[3] = (lsize >> 48) & 0xFF; - pws_snd_buffer[4] = (lsize >> 40) & 0xFF; - pws_snd_buffer[5] = (lsize >> 32) & 0xFF; - pws_snd_buffer[6] = (lsize >> 24) & 0xFF; - pws_snd_buffer[7] = (lsize >> 16) & 0xFF; - pws_snd_buffer[8] = (lsize >> 8) & 0xFF; - pws_snd_buffer[9] = (lsize & 0xFF); - pws_snd_buffer = &pws_snd_buffer[10]; - } - - memcpy(pws_snd_buffer, pdata, (size_t)lsize); - - // store call-id - if(callid != __null_callid && tsip_dialog_layer_have_dialog_with_callid(self->stack->layer_dialog, callid)){ - ret = tsip_transport_stream_peer_add_callid(peer, callid); - } - // send() data - ret = tnet_transport_send(self->net_transport, local_fd, peer->ws.snd_buffer, (tsk_size_t)data_size); - - TSK_OBJECT_SAFE_FREE(peer); - - return ret; + /*static const uint8_t __ws_first_byte = 0x82;*/ + const uint8_t* pdata = (const uint8_t*)data; + uint64_t data_size = 1 + 1 + size; + uint64_t lsize = (uint64_t)size; + uint8_t* pws_snd_buffer; + tsip_transport_stream_peer_t* peer; + tsk_size_t ret; + + if(!(peer = tsip_transport_find_stream_peer_by_local_fd(TSIP_TRANSPORT(self), local_fd))) { + TSK_DEBUG_ERROR("Failed to find peer with local fd equal to %d", local_fd); + return 0; + } + + if(lsize > 0x7D && lsize <= 0xFFFF) { + data_size += 2; + } + else if(lsize > 0xFFFF) { + data_size += 8; + } + if(peer->ws.snd_buffer_size < data_size) { + if(!(peer->ws.snd_buffer = tsk_realloc(peer->ws.snd_buffer, (tsk_size_t)data_size))) { + TSK_DEBUG_ERROR("Failed to allocate buffer with size = %llu", data_size); + peer->ws.snd_buffer_size = 0; + TSK_OBJECT_SAFE_FREE(peer); + return 0; + } + peer->ws.snd_buffer_size = data_size; + } + pws_snd_buffer = (uint8_t*)peer->ws.snd_buffer; + + pws_snd_buffer[0] = 0x82; + if(lsize <= 0x7D) { + pws_snd_buffer[1] = (uint8_t)lsize; + pws_snd_buffer = &pws_snd_buffer[2]; + } + else if(lsize <= 0xFFFF) { + pws_snd_buffer[1] = 0x7E; + pws_snd_buffer[2] = (lsize >> 8) & 0xFF; + pws_snd_buffer[3] = (lsize & 0xFF); + pws_snd_buffer = &pws_snd_buffer[4]; + } + else { + pws_snd_buffer[1] = 0x7F; + pws_snd_buffer[2] = (lsize >> 56) & 0xFF; + pws_snd_buffer[3] = (lsize >> 48) & 0xFF; + pws_snd_buffer[4] = (lsize >> 40) & 0xFF; + pws_snd_buffer[5] = (lsize >> 32) & 0xFF; + pws_snd_buffer[6] = (lsize >> 24) & 0xFF; + pws_snd_buffer[7] = (lsize >> 16) & 0xFF; + pws_snd_buffer[8] = (lsize >> 8) & 0xFF; + pws_snd_buffer[9] = (lsize & 0xFF); + pws_snd_buffer = &pws_snd_buffer[10]; + } + + memcpy(pws_snd_buffer, pdata, (size_t)lsize); + + // store call-id + if(callid != __null_callid && tsip_dialog_layer_have_dialog_with_callid(self->stack->layer_dialog, callid)) { + ret = tsip_transport_stream_peer_add_callid(peer, callid); + } + // send() data + ret = tnet_transport_send(self->net_transport, local_fd, peer->ws.snd_buffer, (tsk_size_t)data_size); + + TSK_OBJECT_SAFE_FREE(peer); + + return ret; } -/* sends a request +/* sends a request * all callers of this function should provide a sigcomp-id */ tsk_size_t tsip_transport_send(const tsip_transport_t* self, const char *branch, tsip_message_t *msg, const char* destIP, int32_t destPort) { - tsk_size_t ret = 0; - if(self){ - tsk_buffer_t *buffer = tsk_null; - const char* callid = msg->Call_ID ? msg->Call_ID->value : __null_callid; - - /* Add Via and update AOR, IPSec headers, SigComp ... - * ACK sent from the transaction layer will contains a Via header and should not be updated - * CANCEL will have the same Via and Contact headers as the request it cancel - * Any request received from WS/WSS transport layer have to be updated regardless above rules - */ - if(TSIP_MESSAGE_IS_REQUEST(msg)){ - const tsk_bool_t update = ( (!TSIP_REQUEST_IS_ACK(msg) || (TSIP_REQUEST_IS_ACK(msg) && !msg->firstVia)) && !TSIP_REQUEST_IS_CANCEL(msg) ) - || ( TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type) ); - if(update){ - /* AoR: Contact header */ - tsip_transport_msg_update_aor((tsip_transport_t*)self, msg); - /* should be done before tsip_transport_msg_update() which could use the Via header - must be done after update_aor() - */ - tsip_transport_addvia(self, branch, msg); - tsip_transport_msg_update(self, msg); /* IPSec, SigComp, ... */ - } - } - else if(TSIP_MESSAGE_IS_RESPONSE(msg)){ - /* AoR for responses which have a contact header (e.g. 183/200 INVITE) */ - if(msg->Contact){ - tsip_transport_msg_update_aor((tsip_transport_t*)self, msg); - } - /* 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. - */ - if(msg->firstVia->rport == 0){ - /* As the response message has been built from the request ...then it's first via is the same as - the request's first via. - */ - msg->firstVia->rport = msg->firstVia->port; - } - } - - if((buffer = tsk_buffer_create_null())){ - tsip_message_tostring(msg, buffer); - - if(buffer->size >1300){ - /* RFC 3261 - 18.1.1 Sending Requests (FIXME) - If a request is within 200 bytes of the path MTU, or if it is larger - than 1300 bytes and the path MTU is unknown, the request MUST be sent - using an RFC 2914 [43] congestion controlled transport protocol, such - as TCP. If this causes a change in the transport protocol from the - one indicated in the top Via, the value in the top Via MUST be - changed. This prevents fragmentation of messages over UDP and - provides congestion control for larger messages. However, - implementations MUST be able to handle messages up to the maximum - datagram packet size. For UDP, this size is 65,535 bytes, including - IP and UDP headers. - */ - } - - /* === SigComp === */ - if(msg->sigcomp_id){ - if(self->stack->sigcomp.handle){ - tsk_size_t out_size; - char SigCompBuffer[TSIP_SIGCOMP_MAX_BUFF_SIZE]; - - out_size = tsip_sigcomp_handler_compress(self->stack->sigcomp.handle, msg->sigcomp_id, TNET_SOCKET_TYPE_IS_STREAM(self->type), - buffer->data, buffer->size, SigCompBuffer, sizeof(SigCompBuffer)); - if(out_size){ - tsk_buffer_cleanup(buffer); - tsk_buffer_append(buffer, SigCompBuffer, out_size); - } - } - else{ - TSK_DEBUG_ERROR("The outgoing message should be compressed using SigComp but there is not compartment"); - } - } - - /* === Send the message === */ - if(TNET_SOCKET_TYPE_IS_WS(self->type) || TNET_SOCKET_TYPE_IS_WSS(self->type)){ - //if(!TNET_SOCKET_TYPE_IS_WS(msg->net_type) && !TNET_SOCKET_TYPE_IS_WSS(msg->net_type)){ - // message not received over WS/WS tranport but have to be sent over WS/WS - tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_remote_ip(TSIP_TRANSPORT(self), destIP, destPort, self->type); - if(peer){ - ret = tsip_transport_send_raw_ws(self, peer->local_fd, buffer->data, buffer->size, callid); - TSK_OBJECT_SAFE_FREE(peer); - } - else if(msg->local_fd > 0) - //} - //else{ - ret = tsip_transport_send_raw_ws(self, msg->local_fd, buffer->data, buffer->size, callid); - //} - } - else if(TNET_SOCKET_TYPE_IS_IPSEC(self->type)){ - tnet_fd_t fd = tsip_transport_ipsec_getFD(TSIP_TRANSPORT_IPSEC(self), TSIP_MESSAGE_IS_REQUEST(msg)); - // "fd == TNET_INVALID_FD" means IPSec SAs not up yet - ret = (fd != TNET_INVALID_FD) - ? tnet_sockfd_send(fd, buffer->data, buffer->size, 0) - : tsip_transport_send_raw(self, destIP, destPort, buffer->data, buffer->size, callid); - } - else{ - ret = tsip_transport_send_raw(self, destIP, destPort, buffer->data, buffer->size, callid); - } + tsk_size_t ret = 0; + if(self) { + tsk_buffer_t *buffer = tsk_null; + const char* callid = msg->Call_ID ? msg->Call_ID->value : __null_callid; + + /* Add Via and update AOR, IPSec headers, SigComp ... + * ACK sent from the transaction layer will contains a Via header and should not be updated + * CANCEL will have the same Via and Contact headers as the request it cancel + * Any request received from WS/WSS transport layer have to be updated regardless above rules + */ + if(TSIP_MESSAGE_IS_REQUEST(msg)) { + const tsk_bool_t update = ( (!TSIP_REQUEST_IS_ACK(msg) || (TSIP_REQUEST_IS_ACK(msg) && !msg->firstVia)) && !TSIP_REQUEST_IS_CANCEL(msg) ) + || ( TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type) ); + if(update) { + /* AoR: Contact header */ + tsip_transport_msg_update_aor((tsip_transport_t*)self, msg); + /* should be done before tsip_transport_msg_update() which could use the Via header + must be done after update_aor() + */ + tsip_transport_addvia(self, branch, msg); + tsip_transport_msg_update(self, msg); /* IPSec, SigComp, ... */ + } + } + else if(TSIP_MESSAGE_IS_RESPONSE(msg)) { + /* AoR for responses which have a contact header (e.g. 183/200 INVITE) */ + if(msg->Contact) { + tsip_transport_msg_update_aor((tsip_transport_t*)self, msg); + } + /* 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. + */ + if(msg->firstVia->rport == 0) { + /* As the response message has been built from the request ...then it's first via is the same as + the request's first via. + */ + msg->firstVia->rport = msg->firstVia->port; + } + } + + if((buffer = tsk_buffer_create_null())) { + tsip_message_tostring(msg, buffer); + + if(buffer->size >1300) { + /* RFC 3261 - 18.1.1 Sending Requests (FIXME) + If a request is within 200 bytes of the path MTU, or if it is larger + than 1300 bytes and the path MTU is unknown, the request MUST be sent + using an RFC 2914 [43] congestion controlled transport protocol, such + as TCP. If this causes a change in the transport protocol from the + one indicated in the top Via, the value in the top Via MUST be + changed. This prevents fragmentation of messages over UDP and + provides congestion control for larger messages. However, + implementations MUST be able to handle messages up to the maximum + datagram packet size. For UDP, this size is 65,535 bytes, including + IP and UDP headers. + */ + } + + /* === SigComp === */ + if(msg->sigcomp_id) { + if(self->stack->sigcomp.handle) { + tsk_size_t out_size; + char SigCompBuffer[TSIP_SIGCOMP_MAX_BUFF_SIZE]; + + out_size = tsip_sigcomp_handler_compress(self->stack->sigcomp.handle, msg->sigcomp_id, TNET_SOCKET_TYPE_IS_STREAM(self->type), + buffer->data, buffer->size, SigCompBuffer, sizeof(SigCompBuffer)); + if(out_size) { + tsk_buffer_cleanup(buffer); + tsk_buffer_append(buffer, SigCompBuffer, out_size); + } + } + else { + TSK_DEBUG_ERROR("The outgoing message should be compressed using SigComp but there is not compartment"); + } + } + + /* === Send the message === */ + if(TNET_SOCKET_TYPE_IS_WS(self->type) || TNET_SOCKET_TYPE_IS_WSS(self->type)) { + //if(!TNET_SOCKET_TYPE_IS_WS(msg->net_type) && !TNET_SOCKET_TYPE_IS_WSS(msg->net_type)){ + // message not received over WS/WS tranport but have to be sent over WS/WS + tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_remote_ip(TSIP_TRANSPORT(self), destIP, destPort, self->type); + if(peer) { + ret = tsip_transport_send_raw_ws(self, peer->local_fd, buffer->data, buffer->size, callid); + TSK_OBJECT_SAFE_FREE(peer); + } + else if(msg->local_fd > 0) + //} + //else{ + { + ret = tsip_transport_send_raw_ws(self, msg->local_fd, buffer->data, buffer->size, callid); + } + //} + } + else if(TNET_SOCKET_TYPE_IS_IPSEC(self->type)) { + tnet_fd_t fd = tsip_transport_ipsec_getFD(TSIP_TRANSPORT_IPSEC(self), TSIP_MESSAGE_IS_REQUEST(msg)); + // "fd == TNET_INVALID_FD" means IPSec SAs not up yet + ret = (fd != TNET_INVALID_FD) + ? tnet_sockfd_send(fd, buffer->data, buffer->size, 0) + : tsip_transport_send_raw(self, destIP, destPort, buffer->data, buffer->size, callid); + } + else { + ret = tsip_transport_send_raw(self, destIP, destPort, buffer->data, buffer->size, callid); + } //bail: - TSK_OBJECT_SAFE_FREE(buffer); - } - } + TSK_OBJECT_SAFE_FREE(buffer); + } + } - return ret; + return ret; } tsip_uri_t* tsip_transport_get_uri(const tsip_transport_t *self, tsk_bool_t lr) { - if(self){ - //tnet_ip_t ip; - //tnet_port_t port; - tsip_uri_t* uri = tsk_null; - - //if(!tnet_get_ip_n_port(self->connectedFD, &ip, &port)){ - char* uristring = tsk_null; - int ipv6 = TNET_SOCKET_TYPE_IS_IPV6(self->type); - - tsk_sprintf(&uristring, "%s:%s%s%s:%d;%s;transport=%s", - self->scheme, - ipv6 ? "[" : "", - ((tsip_stack_t*)self->stack)->network.aor.ip[self->idx], - ipv6 ? "]" : "", - ((tsip_stack_t*)self->stack)->network.aor.port[self->idx], - lr ? "lr" : "", - self->protocol); - if(uristring){ - if((uri = tsip_uri_parse(uristring, tsk_strlen(uristring)))){ - uri->host_type = ipv6 ? host_ipv6 : host_ipv4; - } - TSK_FREE(uristring); - } - //} - return uri; - } - return tsk_null; + if(self) { + //tnet_ip_t ip; + //tnet_port_t port; + tsip_uri_t* uri = tsk_null; + + //if(!tnet_get_ip_n_port(self->connectedFD, &ip, &port)){ + char* uristring = tsk_null; + int ipv6 = TNET_SOCKET_TYPE_IS_IPV6(self->type); + + tsk_sprintf(&uristring, "%s:%s%s%s:%d;%s;transport=%s", + self->scheme, + ipv6 ? "[" : "", + ((tsip_stack_t*)self->stack)->network.aor.ip[self->idx], + ipv6 ? "]" : "", + ((tsip_stack_t*)self->stack)->network.aor.port[self->idx], + lr ? "lr" : "", + self->protocol); + if(uristring) { + if((uri = tsip_uri_parse(uristring, tsk_strlen(uristring)))) { + uri->host_type = ipv6 ? host_ipv6 : host_ipv4; + } + TSK_FREE(uristring); + } + //} + return uri; + } + return tsk_null; } // remote ip should not be FQDN int tsip_transport_add_stream_peer_2(tsip_transport_t *self, tnet_fd_t local_fd, enum tnet_socket_type_e type, tsk_bool_t connected, const char* remote_host, tnet_port_t remote_port) { - tsip_transport_stream_peer_t* peer = tsk_null; - tnet_ip_t remote_ip; - int ret = 0; + tsip_transport_stream_peer_t* peer = tsk_null; + tnet_ip_t remote_ip; + int ret = 0; - if(!self || local_fd < 0){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self || local_fd < 0) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - tsip_transport_stream_peers_lock(self); + tsip_transport_stream_peers_lock(self); - if(tsip_transport_have_stream_peer_with_local_fd(self, local_fd)){ - TSK_DEBUG_INFO("Peer with local fd=%d already exist", local_fd); + if(tsip_transport_have_stream_peer_with_local_fd(self, local_fd)) { + TSK_DEBUG_INFO("Peer with local fd=%d already exist", local_fd); #if TSIP_UNDER_WINDOWS - // could happen if the closed socket haven't raised "close event" yet and new one added : Windows only - tsip_transport_remove_stream_peer_by_local_fd(self, local_fd); + // could happen if the closed socket haven't raised "close event" yet and new one added : Windows only + tsip_transport_remove_stream_peer_by_local_fd(self, local_fd); #else - peer = tsip_transport_pop_stream_peer_by_local_fd(self, local_fd); + peer = tsip_transport_pop_stream_peer_by_local_fd(self, local_fd); #endif - } - - if(tsk_strnullORempty(remote_host) || !remote_port){ - if(tnet_get_ip_n_port(local_fd, tsk_false/*remote*/, &remote_ip, &remote_port) != 0){ - TSK_DEBUG_ERROR("Failed to get remote peer ip and address for local fd = %d", local_fd); - ret = -2; - goto bail; - } - remote_host = (const char*)remote_ip; - } - else if((ret = tnet_resolve(remote_host, remote_port, type, &remote_ip, &remote_port))){ - TSK_DEBUG_ERROR("Failed to resolve(%s/%d)", remote_host, remote_port); - ret = -3; - goto bail; - } - - if(!peer && !(peer = tsk_object_new(tsip_transport_stream_peer_def_t))){ - TSK_DEBUG_ERROR("Failed to create network stream peer"); - ret = -4; - goto bail; - } - - peer->local_fd = local_fd; - peer->type = type; - peer->connected = connected; - peer->remote_port = remote_port; - memcpy(peer->remote_ip, remote_ip, sizeof(remote_ip)); - - tsip_transport_stream_peers_lock(self); - peer->time_latest_activity = tsk_time_now(); - peer->time_added = peer->time_latest_activity; - tsk_list_push_back_data(self->stream_peers, (void**)&peer); - ++self->stream_peers_count; - TSK_DEBUG_INFO("#%d peers in the '%s' transport", self->stream_peers_count, tsip_transport_get_description(self)); - tsip_transport_stream_peers_unlock(self); - - // Cleanup streams - if (self->stream_peers_count > TSIP_TRANSPORT_STREAM_PEERS_COUNT_BEFORE_CHECKING_TIMEOUT && self->stack->network.mode == tsip_stack_mode_webrtc2sip) { - ret = tsip_transport_stream_peers_cleanup(self); - } + } + + if(tsk_strnullORempty(remote_host) || !remote_port) { + if(tnet_get_ip_n_port(local_fd, tsk_false/*remote*/, &remote_ip, &remote_port) != 0) { + TSK_DEBUG_ERROR("Failed to get remote peer ip and address for local fd = %d", local_fd); + ret = -2; + goto bail; + } + remote_host = (const char*)remote_ip; + } + else if((ret = tnet_resolve(remote_host, remote_port, type, &remote_ip, &remote_port))) { + TSK_DEBUG_ERROR("Failed to resolve(%s/%d)", remote_host, remote_port); + ret = -3; + goto bail; + } + + if(!peer && !(peer = tsk_object_new(tsip_transport_stream_peer_def_t))) { + TSK_DEBUG_ERROR("Failed to create network stream peer"); + ret = -4; + goto bail; + } + + peer->local_fd = local_fd; + peer->type = type; + peer->connected = connected; + peer->remote_port = remote_port; + memcpy(peer->remote_ip, remote_ip, sizeof(remote_ip)); + + tsip_transport_stream_peers_lock(self); + peer->time_latest_activity = tsk_time_now(); + peer->time_added = peer->time_latest_activity; + tsk_list_push_back_data(self->stream_peers, (void**)&peer); + ++self->stream_peers_count; + TSK_DEBUG_INFO("#%d peers in the '%s' transport", self->stream_peers_count, tsip_transport_get_description(self)); + tsip_transport_stream_peers_unlock(self); + + // Cleanup streams + if (self->stream_peers_count > TSIP_TRANSPORT_STREAM_PEERS_COUNT_BEFORE_CHECKING_TIMEOUT && self->stack->network.mode == tsip_stack_mode_webrtc2sip) { + ret = tsip_transport_stream_peers_cleanup(self); + } bail: - TSK_OBJECT_SAFE_FREE(peer); - tsip_transport_stream_peers_unlock(self); - return ret; + TSK_OBJECT_SAFE_FREE(peer); + tsip_transport_stream_peers_unlock(self); + return ret; } // up to the caller to release the returned object tsip_transport_stream_peer_t* tsip_transport_find_stream_peer_by_local_fd(tsip_transport_t *self, tnet_fd_t local_fd) { - tsip_transport_stream_peer_t* peer = tsk_null; - tsk_list_item_t* item; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - tsip_transport_stream_peers_lock(self); - tsk_list_foreach(item, self->stream_peers){ - if(((tsip_transport_stream_peer_t*)item->data)->local_fd == local_fd){ - peer = tsk_object_ref(item->data); - break; - } - } - tsip_transport_stream_peers_unlock(self); - return peer; + tsip_transport_stream_peer_t* peer = tsk_null; + tsk_list_item_t* item; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + tsip_transport_stream_peers_lock(self); + tsk_list_foreach(item, self->stream_peers) { + if(((tsip_transport_stream_peer_t*)item->data)->local_fd == local_fd) { + peer = tsk_object_ref(item->data); + break; + } + } + tsip_transport_stream_peers_unlock(self); + return peer; } // up to the caller to release the returned object // calling this function will remove the peer from the list tsip_transport_stream_peer_t* tsip_transport_pop_stream_peer_by_local_fd(tsip_transport_t *self, tnet_fd_t local_fd) { - if(self){ - tsip_transport_stream_peer_t* peer = tsk_null; - tsk_list_item_t *item; - tsip_transport_stream_peers_lock(self); - if((item = tsk_list_pop_item_by_pred(self->stream_peers, _pred_find_stream_peer_by_local_fd, &local_fd))){ - peer = tsk_object_ref(item->data); - TSK_OBJECT_SAFE_FREE(item); - --self->stream_peers_count; - TSK_DEBUG_INFO("#%d peers in the '%s' transport", self->stream_peers_count, tsip_transport_get_description(self)); - } - tsip_transport_stream_peers_unlock(self); - return peer; - } - return tsk_null; + if(self) { + tsip_transport_stream_peer_t* peer = tsk_null; + tsk_list_item_t *item; + tsip_transport_stream_peers_lock(self); + if((item = tsk_list_pop_item_by_pred(self->stream_peers, _pred_find_stream_peer_by_local_fd, &local_fd))) { + peer = tsk_object_ref(item->data); + TSK_OBJECT_SAFE_FREE(item); + --self->stream_peers_count; + TSK_DEBUG_INFO("#%d peers in the '%s' transport", self->stream_peers_count, tsip_transport_get_description(self)); + } + tsip_transport_stream_peers_unlock(self); + return peer; + } + return tsk_null; } // up to the caller to release the returned object tsip_transport_stream_peer_t* tsip_transport_find_stream_peer_by_remote_ip(tsip_transport_t *self, const char* remote_ip, tnet_port_t remote_port, enum tnet_socket_type_e type) { - tsip_transport_stream_peer_t* peer = tsk_null; - tsk_list_item_t* item; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - tsip_transport_stream_peers_lock(self); - tsk_list_foreach(item, self->stream_peers){ - if(((tsip_transport_stream_peer_t*)item->data)->type == type && ((tsip_transport_stream_peer_t*)item->data)->remote_port == remote_port && tsk_striequals(((tsip_transport_stream_peer_t*)item->data)->remote_ip, remote_ip)){ - peer = tsk_object_ref(item->data); - break; - } - } - tsip_transport_stream_peers_unlock(self); - return peer; + tsip_transport_stream_peer_t* peer = tsk_null; + tsk_list_item_t* item; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + tsip_transport_stream_peers_lock(self); + tsk_list_foreach(item, self->stream_peers) { + if(((tsip_transport_stream_peer_t*)item->data)->type == type && ((tsip_transport_stream_peer_t*)item->data)->remote_port == remote_port && tsk_striequals(((tsip_transport_stream_peer_t*)item->data)->remote_ip, remote_ip)) { + peer = tsk_object_ref(item->data); + break; + } + } + tsip_transport_stream_peers_unlock(self); + return peer; } tsk_bool_t tsip_transport_have_stream_peer_with_remote_ip(tsip_transport_t *self, const char* remote_ip, tnet_port_t remote_port, enum tnet_socket_type_e type) { - if(self && !tsk_strnullORempty(remote_ip) && remote_port){ - tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_remote_ip(self, remote_ip, remote_port, type); - if(peer){ - TSK_OBJECT_SAFE_FREE(peer); - return tsk_true; - } - } - return tsk_false; + if(self && !tsk_strnullORempty(remote_ip) && remote_port) { + tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_remote_ip(self, remote_ip, remote_port, type); + if(peer) { + TSK_OBJECT_SAFE_FREE(peer); + return tsk_true; + } + } + return tsk_false; } tsk_bool_t tsip_transport_have_stream_peer_with_local_fd(tsip_transport_t *self, tnet_fd_t local_fd) { - tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_local_fd(self, local_fd); - tsk_bool_t ret = (peer != tsk_null); - TSK_OBJECT_SAFE_FREE(peer); - return ret; + tsip_transport_stream_peer_t* peer = tsip_transport_find_stream_peer_by_local_fd(self, local_fd); + tsk_bool_t ret = (peer != tsk_null); + TSK_OBJECT_SAFE_FREE(peer); + return ret; } int tsip_transport_remove_stream_peer_by_local_fd(tsip_transport_t *self, tnet_fd_t local_fd) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - tsip_transport_stream_peers_lock(self); - if (tsk_list_remove_item_by_pred(self->stream_peers, _pred_find_stream_peer_by_local_fd, &local_fd)) { - --self->stream_peers_count; - TSK_DEBUG_INFO("#%d peers in the '%s' transport", self->stream_peers_count, tsip_transport_get_description(self)); - } - tsip_transport_stream_peers_unlock(self); - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsip_transport_stream_peers_lock(self); + if (tsk_list_remove_item_by_pred(self->stream_peers, _pred_find_stream_peer_by_local_fd, &local_fd)) { + --self->stream_peers_count; + TSK_DEBUG_INFO("#%d peers in the '%s' transport", self->stream_peers_count, tsip_transport_get_description(self)); + } + tsip_transport_stream_peers_unlock(self); + + return 0; } int tsip_transport_remove_callid_from_stream_peers(tsip_transport_t *self, const char* callid, tsk_bool_t* removed) { - if(!self || !removed){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - *removed = tsk_false; - if(TNET_SOCKET_TYPE_IS_STREAM(self->type)){ - tsk_list_item_t *item; - tsip_transport_stream_peers_lock(self); - tsk_list_foreach(item, self->stream_peers){ - if(tsip_transport_stream_peer_remove_callid((tsip_transport_stream_peer_t*)item->data, callid, removed) == 0 && *removed){ - TSK_DEBUG_INFO("[Transport] Removed call-id = '%s' from transport with type = %d", callid, self->type); - break; - } - } - tsip_transport_stream_peers_unlock(self); - } - - return 0; + if(!self || !removed) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *removed = tsk_false; + if(TNET_SOCKET_TYPE_IS_STREAM(self->type)) { + tsk_list_item_t *item; + tsip_transport_stream_peers_lock(self); + tsk_list_foreach(item, self->stream_peers) { + if(tsip_transport_stream_peer_remove_callid((tsip_transport_stream_peer_t*)item->data, callid, removed) == 0 && *removed) { + TSK_DEBUG_INFO("[Transport] Removed call-id = '%s' from transport with type = %d", callid, self->type); + break; + } + } + tsip_transport_stream_peers_unlock(self); + } + + return 0; } tsk_bool_t tsip_transport_stream_peer_have_callid(const tsip_transport_stream_peer_t* self, const char* callid) { - tsk_bool_t have_cid = tsk_false; - if(self){ - const tsk_list_item_t* item; - - tsk_list_lock(self->dialogs_cids); - tsk_list_foreach(item, self->dialogs_cids){ - if(tsk_strequals(TSK_STRING_STR(item->data), callid)){ - have_cid = tsk_true; - break; - } - } - tsk_list_unlock(self->dialogs_cids); - } - return have_cid; + tsk_bool_t have_cid = tsk_false; + if(self) { + const tsk_list_item_t* item; + + tsk_list_lock(self->dialogs_cids); + tsk_list_foreach(item, self->dialogs_cids) { + if(tsk_strequals(TSK_STRING_STR(item->data), callid)) { + have_cid = tsk_true; + break; + } + } + tsk_list_unlock(self->dialogs_cids); + } + return have_cid; } int tsip_transport_stream_peer_add_callid(tsip_transport_stream_peer_t* self, const char* callid) { - if(self && !tsk_strnullORempty(callid)){ - tsk_list_lock(self->dialogs_cids); - if(!tsip_transport_stream_peer_have_callid(self, callid)){ - tsk_string_t* cid = tsk_string_create(callid); - if(cid){ - TSK_DEBUG_INFO("Add call-id = '%s' to peer with local fd = %d", callid, self->local_fd); - tsk_list_push_back_data(self->dialogs_cids, (void**)&cid); - TSK_OBJECT_SAFE_FREE(cid); - } - } - tsk_list_unlock(self->dialogs_cids); - return 0; - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self && !tsk_strnullORempty(callid)) { + tsk_list_lock(self->dialogs_cids); + if(!tsip_transport_stream_peer_have_callid(self, callid)) { + tsk_string_t* cid = tsk_string_create(callid); + if(cid) { + TSK_DEBUG_INFO("Add call-id = '%s' to peer with local fd = %d", callid, self->local_fd); + tsk_list_push_back_data(self->dialogs_cids, (void**)&cid); + TSK_OBJECT_SAFE_FREE(cid); + } + } + tsk_list_unlock(self->dialogs_cids); + return 0; + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } int tsip_transport_stream_peer_remove_callid(tsip_transport_stream_peer_t* self, const char* callid, tsk_bool_t *removed) { - if(self && removed){ - *removed = tsk_false; - tsk_list_lock(self->dialogs_cids); - if((*removed = tsk_list_remove_item_by_pred(self->dialogs_cids, tsk_string_pred_cmp, callid)) == tsk_true){ - TSK_DEBUG_INFO("[Stream] Removed call-id = '%s' from peer with local fd = %d", callid, self->local_fd); - } - tsk_list_unlock(self->dialogs_cids); - return 0; - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self && removed) { + *removed = tsk_false; + tsk_list_lock(self->dialogs_cids); + if((*removed = tsk_list_remove_item_by_pred(self->dialogs_cids, tsk_string_pred_cmp, callid)) == tsk_true) { + TSK_DEBUG_INFO("[Stream] Removed call-id = '%s' from peer with local fd = %d", callid, self->local_fd); + } + tsk_list_unlock(self->dialogs_cids); + return 0; + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } int tsip_transport_stream_peers_cleanup(tsip_transport_t *self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if (TNET_SOCKET_TYPE_IS_STREAM(self->type)) { - tsk_list_item_t *item; - tsip_transport_stream_peer_t *peer; - tnet_fd_t fd; - tsk_bool_t close; - uint64_t now = tsk_time_now(); - tsip_transport_stream_peers_lock(self); - tsk_list_foreach(item, self->stream_peers) { - if ((peer = (item->data))) { - close = ((now - TSIP_TRANSPORT_STREAM_PEER_TIMEOUT) > peer->time_latest_activity); - if (!close) { - close = !peer->got_valid_sip_msg && ((now - TSIP_TRANSPORT_STREAM_PEER_FIRST_MSG_TIMEOUT) > peer->time_added); - } - if (!close) { - if ((TNET_SOCKET_TYPE_IS_WS(peer->type) || TNET_SOCKET_TYPE_IS_WSS(peer->type)) && !peer->ws.handshaking_done) { - close = ((now - TSIP_TRANSPORT_STREAM_PEER_WS_HANDSHAKING_TIMEOUT) > peer->time_added); - } - } - if (close) { - fd = peer->local_fd; - TSK_DEBUG_INFO("Peer with fd=%d, type=%d, got_valid_sip_msg=%d, time_added=%llu, time_latest_activity=%llu, now=%llu in '%s' transport timedout", - fd, peer->type, peer->got_valid_sip_msg, peer->time_added, peer->time_latest_activity, now, tsip_transport_get_description(self)); - tsip_transport_remove_socket(self, (tnet_fd_t *)&fd); - } - } - } - tsip_transport_stream_peers_unlock(self); - } - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (TNET_SOCKET_TYPE_IS_STREAM(self->type)) { + tsk_list_item_t *item; + tsip_transport_stream_peer_t *peer; + tnet_fd_t fd; + tsk_bool_t close; + uint64_t now = tsk_time_now(); + tsip_transport_stream_peers_lock(self); + tsk_list_foreach(item, self->stream_peers) { + if ((peer = (item->data))) { + close = ((now - TSIP_TRANSPORT_STREAM_PEER_TIMEOUT) > peer->time_latest_activity); + if (!close) { + close = !peer->got_valid_sip_msg && ((now - TSIP_TRANSPORT_STREAM_PEER_FIRST_MSG_TIMEOUT) > peer->time_added); + } + if (!close) { + if ((TNET_SOCKET_TYPE_IS_WS(peer->type) || TNET_SOCKET_TYPE_IS_WSS(peer->type)) && !peer->ws.handshaking_done) { + close = ((now - TSIP_TRANSPORT_STREAM_PEER_WS_HANDSHAKING_TIMEOUT) > peer->time_added); + } + } + if (close) { + fd = peer->local_fd; + TSK_DEBUG_INFO("Peer with fd=%d, type=%d, got_valid_sip_msg=%d, time_added=%llu, time_latest_activity=%llu, now=%llu in '%s' transport timedout", + fd, peer->type, peer->got_valid_sip_msg, peer->time_added, peer->time_latest_activity, now, tsip_transport_get_description(self)); + tsip_transport_remove_socket(self, (tnet_fd_t *)&fd); + } + } + } + tsip_transport_stream_peers_unlock(self); + } + + return 0; } int tsip_transport_init(tsip_transport_t* self, tnet_socket_type_t type, const struct tsip_stack_s *stack, const char *host, tnet_port_t port, const char* description) { - if(!self || self->initialized){ - return -1; - } - - self->stack = stack; - self->type = type; - self->net_transport = tnet_transport_create(host, port, type, description); - - self->scheme = "sip"; - - if(TNET_SOCKET_TYPE_IS_STREAM(type)){ - if(TNET_SOCKET_TYPE_IS_TLS(type)){ - self->scheme = "sips"; - self->protocol = "tcp"; - self->via_protocol = "TLS"; - self->service = "SIPS+D2T"; - } - else if(TNET_SOCKET_TYPE_IS_WS(type)){ - self->protocol = "ws"; - self->via_protocol = "WS"; - self->service = "SIP+D2W"; - } - else if(TNET_SOCKET_TYPE_IS_WSS(type)){ - self->scheme = "sips"; - self->protocol = "wss"; - self->via_protocol = "WSS"; - self->service = "SIPS+D2W"; - } - else{ - self->protocol = "tcp"; - self->via_protocol = "TCP"; - self->service = "SIP+D2T"; - } - - /* Stream buffer */ - self->stream_peers = tsk_list_create(); + if(!self || self->initialized) { + return -1; + } + + self->stack = stack; + self->type = type; + self->net_transport = tnet_transport_create(host, port, type, description); + + self->scheme = "sip"; + + if(TNET_SOCKET_TYPE_IS_STREAM(type)) { + if(TNET_SOCKET_TYPE_IS_TLS(type)) { + self->scheme = "sips"; + self->protocol = "tcp"; + self->via_protocol = "TLS"; + self->service = "SIPS+D2T"; + } + else if(TNET_SOCKET_TYPE_IS_WS(type)) { + self->protocol = "ws"; + self->via_protocol = "WS"; + self->service = "SIP+D2W"; + } + else if(TNET_SOCKET_TYPE_IS_WSS(type)) { + self->scheme = "sips"; + self->protocol = "wss"; + self->via_protocol = "WSS"; + self->service = "SIPS+D2W"; + } + else { + self->protocol = "tcp"; + self->via_protocol = "TCP"; + self->service = "SIP+D2T"; + } + + /* Stream buffer */ + self->stream_peers = tsk_list_create(); if (!self->stream_peers) { return -1; } - } - else{ - if(TNET_SOCKET_TYPE_IS_DTLS(type)){ - self->scheme = "sips"; - self->protocol = "dtls-udp"; - self->via_protocol = "DTLS-UDP"; - self->service = "SIPS+D2U"; - } - else{ - self->protocol = "udp"; - self->via_protocol = "UDP"; - self->service = "SIP+D2U"; - } - } - self->connectedFD = TNET_INVALID_FD; - self->initialized = 1; - - return 0; + } + else { + if(TNET_SOCKET_TYPE_IS_DTLS(type)) { + self->scheme = "sips"; + self->protocol = "dtls-udp"; + self->via_protocol = "DTLS-UDP"; + self->service = "SIPS+D2U"; + } + else { + self->protocol = "udp"; + self->via_protocol = "UDP"; + self->service = "SIP+D2U"; + } + } + self->connectedFD = TNET_INVALID_FD; + self->initialized = 1; + + return 0; } int tsip_transport_deinit(tsip_transport_t* self) { - if(!self || !self->initialized){ - return -1; - } - - TSK_OBJECT_SAFE_FREE(self->net_transport); - TSK_OBJECT_SAFE_FREE(self->stream_peers); - - self->initialized = 0; - return 0; + if(!self || !self->initialized) { + return -1; + } + + TSK_OBJECT_SAFE_FREE(self->net_transport); + TSK_OBJECT_SAFE_FREE(self->stream_peers); + + self->initialized = 0; + return 0; } @@ -995,53 +996,52 @@ int tsip_transport_deinit(tsip_transport_t* self) // static tsk_object_t* tsip_transport_ctor(tsk_object_t * self, va_list * app) { - tsip_transport_t *transport = self; - if(transport){ - const tsip_stack_handle_t *stack = va_arg(*app, const tsip_stack_handle_t*); - const char *host = va_arg(*app, const char*); + tsip_transport_t *transport = self; + if(transport) { + const tsip_stack_handle_t *stack = va_arg(*app, const tsip_stack_handle_t*); + const char *host = va_arg(*app, const char*); #if defined(__GNUC__) - tnet_port_t port = (tnet_port_t)va_arg(*app, unsigned); + tnet_port_t port = (tnet_port_t)va_arg(*app, unsigned); #else - tnet_port_t port = va_arg(*app, tnet_port_t); + tnet_port_t port = va_arg(*app, tnet_port_t); #endif - tnet_socket_type_t type = va_arg(*app, tnet_socket_type_t); - const char *description = va_arg(*app, const char*); - - if(tsip_transport_init(transport, type, stack, host, port, description)){ - TSK_DEBUG_ERROR("Failed to initialize transport"); - return tsk_null; - } - } - return self; + tnet_socket_type_t type = va_arg(*app, tnet_socket_type_t); + const char *description = va_arg(*app, const char*); + + if(tsip_transport_init(transport, type, stack, host, port, description)) { + TSK_DEBUG_ERROR("Failed to initialize transport"); + return tsk_null; + } + } + return self; } static tsk_object_t* tsip_transport_dtor(tsk_object_t * self) -{ - tsip_transport_t *transport = self; - if(transport){ - tsip_transport_deinit(transport); - } - return self; +{ + tsip_transport_t *transport = self; + if(transport) { + tsip_transport_deinit(transport); + } + return self; } static int tsip_transport_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - const tsip_transport_t *transport1 = obj1; - const tsip_transport_t *transport2 = obj2; - if(transport1 && transport2){ - const char* desc1 = tsip_transport_get_description(transport1); - const char* desc2 = tsip_transport_get_description(transport2); - return tsk_stricmp(desc1, desc2); - } - return -1; + const tsip_transport_t *transport1 = obj1; + const tsip_transport_t *transport2 = obj2; + if(transport1 && transport2) { + const char* desc1 = tsip_transport_get_description(transport1); + const char* desc2 = tsip_transport_get_description(transport2); + return tsk_stricmp(desc1, desc2); + } + return -1; } -static const tsk_object_def_t tsip_transport_def_s = -{ - sizeof(tsip_transport_t), - tsip_transport_ctor, - tsip_transport_dtor, - tsip_transport_cmp, +static const tsk_object_def_t tsip_transport_def_s = { + sizeof(tsip_transport_t), + tsip_transport_ctor, + tsip_transport_dtor, + tsip_transport_cmp, }; const tsk_object_def_t *tsip_transport_def_t = &tsip_transport_def_s; @@ -1053,51 +1053,50 @@ const tsk_object_def_t *tsip_transport_def_t = &tsip_transport_def_s; // static tsk_object_t* tsip_transport_stream_peer_ctor(tsk_object_t * self, va_list * app) { - tsip_transport_stream_peer_t *peer = self; - if(peer){ - if (!(peer->rcv_buff_stream = tsk_buffer_create_null())) { + tsip_transport_stream_peer_t *peer = self; + if(peer) { + if (!(peer->rcv_buff_stream = tsk_buffer_create_null())) { return tsk_null; } - if (!(peer->snd_buff_stream = tsk_buffer_create_null())) { + if (!(peer->snd_buff_stream = tsk_buffer_create_null())) { return tsk_null; } - if (!(peer->dialogs_cids = tsk_list_create())){ + if (!(peer->dialogs_cids = tsk_list_create())) { return tsk_null; } - } - return self; + } + return self; } static tsk_object_t* tsip_transport_stream_peer_dtor(tsk_object_t * self) -{ - tsip_transport_stream_peer_t *peer = self; - if(peer){ - TSK_DEBUG_INFO("*** Stream Peer destroyed ***"); - TSK_OBJECT_SAFE_FREE(peer->rcv_buff_stream); - TSK_OBJECT_SAFE_FREE(peer->snd_buff_stream); - - TSK_SAFE_FREE(peer->ws.rcv_buffer); - peer->ws.rcv_buffer_size = 0; - TSK_SAFE_FREE(peer->ws.snd_buffer); - peer->ws.snd_buffer_size = 0; - - TSK_OBJECT_SAFE_FREE(peer->dialogs_cids); - } - return self; +{ + tsip_transport_stream_peer_t *peer = self; + if(peer) { + TSK_DEBUG_INFO("*** Stream Peer destroyed ***"); + TSK_OBJECT_SAFE_FREE(peer->rcv_buff_stream); + TSK_OBJECT_SAFE_FREE(peer->snd_buff_stream); + + TSK_SAFE_FREE(peer->ws.rcv_buffer); + peer->ws.rcv_buffer_size = 0; + TSK_SAFE_FREE(peer->ws.snd_buffer); + peer->ws.snd_buffer_size = 0; + + TSK_OBJECT_SAFE_FREE(peer->dialogs_cids); + } + return self; } static int tsip_transport_stream_peer_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - const tsip_transport_stream_peer_t *peer1 = obj1; - const tsip_transport_stream_peer_t *peer2 = obj2; - if(peer1 && peer2){ - return (peer1->local_fd - peer2->local_fd); - } - return -1; + const tsip_transport_stream_peer_t *peer1 = obj1; + const tsip_transport_stream_peer_t *peer2 = obj2; + if(peer1 && peer2) { + return (peer1->local_fd - peer2->local_fd); + } + return -1; } -static const tsk_object_def_t tsip_transport_stream_peer_def_s = -{ - sizeof(tsip_transport_stream_peer_t), - tsip_transport_stream_peer_ctor, - tsip_transport_stream_peer_dtor, - tsip_transport_stream_peer_cmp, +static const tsk_object_def_t tsip_transport_stream_peer_def_s = { + sizeof(tsip_transport_stream_peer_t), + tsip_transport_stream_peer_ctor, + tsip_transport_stream_peer_dtor, + tsip_transport_stream_peer_cmp, }; const tsk_object_def_t *tsip_transport_stream_peer_def_t = &tsip_transport_stream_peer_def_s; diff --git a/tinySIP/src/transports/tsip_transport_ipsec.c b/tinySIP/src/transports/tsip_transport_ipsec.c index 390e999..9e4ce95 100755 --- a/tinySIP/src/transports/tsip_transport_ipsec.c +++ b/tinySIP/src/transports/tsip_transport_ipsec.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. * @@ -46,318 +46,318 @@ TINYSIP_GEXTERN const tsk_object_def_t *tsip_ipsec_association_def_t; tsip_ipsec_association_t* tsip_ipsec_association_create(const tsip_transport_t* transport) { - return tsk_object_new(tsip_ipsec_association_def_t, transport); + return tsk_object_new(tsip_ipsec_association_def_t, transport); } tsip_transport_ipsec_t* tsip_transport_ipsec_create(struct tsip_stack_s* stack, const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description) { - return tsk_object_new(tsip_transport_ipsec_def_t, stack, host, port, type, description); + return tsk_object_new(tsip_transport_ipsec_def_t, stack, host, port, type, description); } int tsip_transport_ipsec_createTempSAs(tsip_transport_ipsec_t* self) { - int ret = -1; - - /* Check */ - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - /* Already have temporary SAs ? */ - if (self->asso_temporary) { - TSK_DEBUG_ERROR("IPSec transport layer already have temporary SAs"); - ret = -2; - goto bail; - } - - /* Create temporary association */ - if ((self->asso_temporary = tsip_ipsec_association_create(TSIP_TRANSPORT(self)))) { - if (self->asso_temporary->ctx && self->asso_temporary->ctx->state == tipsec_state_inbound) { - ret = 0; - } - else { - TSK_DEBUG_INFO("Failed to create new temporary SAs."); - ret = -3; - goto bail; - } - } - else { - TSK_DEBUG_INFO("Failed to create new temporary SAs."); - - ret = -4; - goto bail; - } + int ret = -1; + + /* Check */ + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + /* Already have temporary SAs ? */ + if (self->asso_temporary) { + TSK_DEBUG_ERROR("IPSec transport layer already have temporary SAs"); + ret = -2; + goto bail; + } + + /* Create temporary association */ + if ((self->asso_temporary = tsip_ipsec_association_create(TSIP_TRANSPORT(self)))) { + if (self->asso_temporary->ctx && self->asso_temporary->ctx->state == tipsec_state_inbound) { + ret = 0; + } + else { + TSK_DEBUG_INFO("Failed to create new temporary SAs."); + ret = -3; + goto bail; + } + } + else { + TSK_DEBUG_INFO("Failed to create new temporary SAs."); + + ret = -4; + goto bail; + } bail: - if (ret && ret != -1) { - TSK_OBJECT_SAFE_FREE(self->asso_temporary); - } - return ret; + if (ret && ret != -1) { + TSK_OBJECT_SAFE_FREE(self->asso_temporary); + } + return ret; } int tsip_transport_ipsec_ensureTempSAs(tsip_transport_ipsec_t* self, const tsip_response_t *r401_407, int64_t expires) { - int ret = -1; - struct sockaddr_storage to; - tsk_size_t index; - const tsip_header_Security_Server_t *ssHdr; - double maxQ = -2.0; /* The Q value in the SIP header will be equal to -1 by default. */ - int match = 0; - - - tipsec_spi_t spi_pc, spi_ps; - tipsec_port_t port_pc, port_ps; - tipsec_lifetime_t lifetime; - - if(!self || expires < 0){ - goto bail; - } - - lifetime = (tipsec_lifetime_t)expires; - - /* Already have temporary SAs ? */ - if(!self->asso_temporary){ - TSK_DEBUG_ERROR("Cannot ensure temporary SAs (No tempSAs)"); - ret = -2; - goto bail; - } - - /* Cleanup old Security-Verifies */ - TSK_OBJECT_SAFE_FREE(self->secVerifies); - - /* RFC 3329 - 2.3.1 Client Initiated - - When the client receives a response with a Security-Server header field, it MUST choose the security mechanism in the server's list - with the highest "q" value among all the mechanisms that are known to the client. - */ - for (index = 0; (ssHdr = (const tsip_header_Security_Server_t *)tsip_message_get_headerAt(r401_407, tsip_htype_Security_Server, index)); index++) { - tsip_header_Security_Verify_t* svHdr; - - if (maxQ > ssHdr->q || !tsk_striequals(ssHdr->mech, "ipsec-3gpp")){ - goto copy; - } - - if ((TIPSEC_ALG_FROM_STR(ssHdr->alg) == self->asso_temporary->ctx->alg) && - (TIPSEC_EALG_FROM_STR(ssHdr->ealg) == self->asso_temporary->ctx->ealg) && - (TIPSEC_PROTOCOL_FROM_STR(ssHdr->prot) == self->asso_temporary->ctx->protocol) && - (TIPSEC_MODE_FROM_STR(ssHdr->mod) == self->asso_temporary->ctx->mode)){ - - match = 1; - - maxQ = (ssHdr->q >= maxQ) ? ssHdr->q : maxQ; - spi_pc = ssHdr->spi_c; - spi_ps = ssHdr->spi_s; - port_pc = ssHdr->port_c; - port_ps = ssHdr->port_s; - } + int ret = -1; + struct sockaddr_storage to; + tsk_size_t index; + const tsip_header_Security_Server_t *ssHdr; + double maxQ = -2.0; /* The Q value in the SIP header will be equal to -1 by default. */ + int match = 0; + + + tipsec_spi_t spi_pc, spi_ps; + tipsec_port_t port_pc, port_ps; + tipsec_lifetime_t lifetime; + + if(!self || expires < 0) { + goto bail; + } + + lifetime = (tipsec_lifetime_t)expires; + + /* Already have temporary SAs ? */ + if(!self->asso_temporary) { + TSK_DEBUG_ERROR("Cannot ensure temporary SAs (No tempSAs)"); + ret = -2; + goto bail; + } + + /* Cleanup old Security-Verifies */ + TSK_OBJECT_SAFE_FREE(self->secVerifies); + + /* RFC 3329 - 2.3.1 Client Initiated + + When the client receives a response with a Security-Server header field, it MUST choose the security mechanism in the server's list + with the highest "q" value among all the mechanisms that are known to the client. + */ + for (index = 0; (ssHdr = (const tsip_header_Security_Server_t *)tsip_message_get_headerAt(r401_407, tsip_htype_Security_Server, index)); index++) { + tsip_header_Security_Verify_t* svHdr; + + if (maxQ > ssHdr->q || !tsk_striequals(ssHdr->mech, "ipsec-3gpp")) { + goto copy; + } + + if ((TIPSEC_ALG_FROM_STR(ssHdr->alg) == self->asso_temporary->ctx->alg) && + (TIPSEC_EALG_FROM_STR(ssHdr->ealg) == self->asso_temporary->ctx->ealg) && + (TIPSEC_PROTOCOL_FROM_STR(ssHdr->prot) == self->asso_temporary->ctx->protocol) && + (TIPSEC_MODE_FROM_STR(ssHdr->mod) == self->asso_temporary->ctx->mode)) { + + match = 1; + + maxQ = (ssHdr->q >= maxQ) ? ssHdr->q : maxQ; + spi_pc = ssHdr->spi_c; + spi_ps = ssHdr->spi_s; + port_pc = ssHdr->port_c; + port_ps = ssHdr->port_s; + } copy: - svHdr = tsip_header_Security_Verify_create_null(); - svHdr->mech = tsk_strdup(ssHdr->mech); - svHdr->alg = tsk_strdup(ssHdr->alg); - svHdr->prot = tsk_strdup(ssHdr->prot); - svHdr->mod = tsk_strdup(ssHdr->mod); - svHdr->ealg = tsk_strdup(ssHdr->ealg); - svHdr->port_c = ssHdr->port_c; - svHdr->port_s = ssHdr->port_s; - svHdr->spi_c = ssHdr->spi_c; - svHdr->spi_s = ssHdr->spi_s; - svHdr->q = ssHdr->q; - TSIP_HEADER_PARAMS(svHdr) = tsk_object_ref(TSIP_HEADER_PARAMS(ssHdr)); - if(!self->secVerifies){ - self->secVerifies = tsk_list_create(); - } - tsk_list_push_back_data(self->secVerifies, (void**)&svHdr); - } - - if(!match){ - TSK_DEBUG_ERROR("Failed to match security server<->security client."); - ret = -3; - goto bail; - } - - /* Set remote parameters received from 401/407 response. */ - if((ret = tipsec_ctx_set_remote(self->asso_temporary->ctx, spi_pc, spi_ps, port_pc, port_ps, lifetime))){ - TSK_DEBUG_ERROR("Failed to set remote IPSec parameters [%d]", ret); - goto bail; - } - - /* Connect Sockets: port_uc to port_ps*/ - if((ret = tnet_sockaddr_init(self->asso_temporary->ip_remote, self->asso_temporary->ctx->port_ps, TSIP_TRANSPORT(self)->type, &to))){ - TSK_DEBUG_ERROR("Invalid HOST/PORT [%s/%u].", (const char*)self->asso_temporary->ctx->addr_remote, self->asso_temporary->ctx->port_ps); - goto bail; - } - if((ret = tnet_sockfd_connectto(self->asso_temporary->socket_uc->fd, &to))){ - TSK_DEBUG_ERROR("Failed to connect port_uc to port_ps."); - goto bail; - } + svHdr = tsip_header_Security_Verify_create_null(); + svHdr->mech = tsk_strdup(ssHdr->mech); + svHdr->alg = tsk_strdup(ssHdr->alg); + svHdr->prot = tsk_strdup(ssHdr->prot); + svHdr->mod = tsk_strdup(ssHdr->mod); + svHdr->ealg = tsk_strdup(ssHdr->ealg); + svHdr->port_c = ssHdr->port_c; + svHdr->port_s = ssHdr->port_s; + svHdr->spi_c = ssHdr->spi_c; + svHdr->spi_s = ssHdr->spi_s; + svHdr->q = ssHdr->q; + TSIP_HEADER_PARAMS(svHdr) = tsk_object_ref(TSIP_HEADER_PARAMS(ssHdr)); + if(!self->secVerifies) { + self->secVerifies = tsk_list_create(); + } + tsk_list_push_back_data(self->secVerifies, (void**)&svHdr); + } + + if(!match) { + TSK_DEBUG_ERROR("Failed to match security server<->security client."); + ret = -3; + goto bail; + } + + /* Set remote parameters received from 401/407 response. */ + if((ret = tipsec_ctx_set_remote(self->asso_temporary->ctx, spi_pc, spi_ps, port_pc, port_ps, lifetime))) { + TSK_DEBUG_ERROR("Failed to set remote IPSec parameters [%d]", ret); + goto bail; + } + + /* Connect Sockets: port_uc to port_ps*/ + if((ret = tnet_sockaddr_init(self->asso_temporary->ip_remote, self->asso_temporary->ctx->port_ps, TSIP_TRANSPORT(self)->type, &to))) { + TSK_DEBUG_ERROR("Invalid HOST/PORT [%s/%u].", (const char*)self->asso_temporary->ctx->addr_remote, self->asso_temporary->ctx->port_ps); + goto bail; + } + if((ret = tnet_sockfd_connectto(self->asso_temporary->socket_uc->fd, &to))) { + TSK_DEBUG_ERROR("Failed to connect port_uc to port_ps."); + goto bail; + } bail: - return ret; + return ret; } int tsip_transport_ipsec_startSAs(tsip_transport_ipsec_t* self, const tipsec_key_t* ik, const tipsec_key_t* ck) { - int ret = -1; - - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - if (!self->asso_temporary) { - TSK_DEBUG_ERROR("Failed to find temporary SAs"); - ret = -2; - goto bail; - } - - /* Promote tempSAs (temp => active) */ - TSK_OBJECT_SAFE_FREE(self->asso_active); /* delete old active SAs */ - self->asso_active = tsk_object_ref((void*)self->asso_temporary); /* promote */ - TSK_OBJECT_SAFE_FREE(self->asso_temporary); /* delete old temp SAs */ - - if ((ret = tipsec_ctx_set_keys(self->asso_active->ctx, ik, ck)) == 0){ - ret = tipsec_ctx_start(self->asso_active->ctx); - } + int ret = -1; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + if (!self->asso_temporary) { + TSK_DEBUG_ERROR("Failed to find temporary SAs"); + ret = -2; + goto bail; + } + + /* Promote tempSAs (temp => active) */ + TSK_OBJECT_SAFE_FREE(self->asso_active); /* delete old active SAs */ + self->asso_active = tsk_object_ref((void*)self->asso_temporary); /* promote */ + TSK_OBJECT_SAFE_FREE(self->asso_temporary); /* delete old temp SAs */ + + if ((ret = tipsec_ctx_set_keys(self->asso_active->ctx, ik, ck)) == 0) { + ret = tipsec_ctx_start(self->asso_active->ctx); + } bail: - return ret; + return ret; } int tsip_transport_ipsec_cleanupSAs(tsip_transport_ipsec_t* self) { - int ret = -1; + int ret = -1; - if(!self){ - goto bail; - } + if(!self) { + goto bail; + } - TSK_OBJECT_SAFE_FREE(self->asso_temporary); - TSK_OBJECT_SAFE_FREE(self->asso_active); + TSK_OBJECT_SAFE_FREE(self->asso_temporary); + TSK_OBJECT_SAFE_FREE(self->asso_active); bail: - return ret; + return ret; } int tsip_transport_ipsec_updateMSG(tsip_transport_ipsec_t* self, tsip_message_t *msg) { - int ret = -1; - const tsip_ipsec_association_t* asso; - - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - asso = (self->asso_temporary && TSIP_REQUEST_IS_REGISTER(msg)) ? self->asso_temporary : self->asso_active; - if (!asso || !asso->ctx) { - TSK_DEBUG_ERROR("No IPSec association found."); - ret = -2; - goto bail; - } - - if (TSIP_MESSAGE_IS_RESPONSE(msg)) { - return 0; - } - - /* Security-Client, Require, Proxy-Require and Security Verify */ - switch(msg->line.request.request_type) { - case tsip_BYE: - case tsip_INVITE: - case tsip_OPTIONS: - case tsip_REGISTER: - case tsip_SUBSCRIBE: - case tsip_NOTIFY: - case tsip_REFER: - case tsip_INFO: - case tsip_UPDATE: - case tsip_MESSAGE: - case tsip_PUBLISH: - case tsip_PRACK: - { - const tsk_list_item_t *item; - TSIP_MESSAGE_ADD_HEADER(msg, TSIP_HEADER_SECURITY_CLIENT_VA_ARGS("ipsec-3gpp", - TIPSEC_ALG_TO_STR(asso->ctx->alg), - TIPSEC_PROTOCOL_TO_STR(asso->ctx->protocol), - TIPSEC_MODE_TO_STR(asso->ctx->mode), - TIPSEC_EALG_TO_STR(asso->ctx->ealg), - asso->ctx->port_uc, - asso->ctx->port_us, - asso->ctx->spi_uc, - asso->ctx->spi_us - )); - /* RFC 3329 - 2.3.1 Client Initiated - All the subsequent SIP requests sent by the client to that server - SHOULD make use of the security mechanism initiated in the previous - step. These requests MUST contain a Security-Verify header field - that mirrors the server's list received previously in the Security- - Server header field. These requests MUST also have both a Require - and Proxy-Require header fields with the value "sec-agree". - */ - tsk_list_foreach(item, self->secVerifies){ - tsip_message_add_header(msg, (const tsip_header_t*)item->data); - } - TSIP_MESSAGE_ADD_HEADER(msg, TSIP_HEADER_REQUIRE_VA_ARGS("sec-agree")); - TSIP_MESSAGE_ADD_HEADER(msg, TSIP_HEADER_PROXY_REQUIRE_VA_ARGS("sec-agree")); - break; - } - - default: break; - } - - ret = 0; - - /* Add Security-Server headers */ + int ret = -1; + const tsip_ipsec_association_t* asso; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + asso = (self->asso_temporary && TSIP_REQUEST_IS_REGISTER(msg)) ? self->asso_temporary : self->asso_active; + if (!asso || !asso->ctx) { + TSK_DEBUG_ERROR("No IPSec association found."); + ret = -2; + goto bail; + } + + if (TSIP_MESSAGE_IS_RESPONSE(msg)) { + return 0; + } + + /* Security-Client, Require, Proxy-Require and Security Verify */ + switch(msg->line.request.request_type) { + case tsip_BYE: + case tsip_INVITE: + case tsip_OPTIONS: + case tsip_REGISTER: + case tsip_SUBSCRIBE: + case tsip_NOTIFY: + case tsip_REFER: + case tsip_INFO: + case tsip_UPDATE: + case tsip_MESSAGE: + case tsip_PUBLISH: + case tsip_PRACK: { + const tsk_list_item_t *item; + TSIP_MESSAGE_ADD_HEADER(msg, TSIP_HEADER_SECURITY_CLIENT_VA_ARGS("ipsec-3gpp", + TIPSEC_ALG_TO_STR(asso->ctx->alg), + TIPSEC_PROTOCOL_TO_STR(asso->ctx->protocol), + TIPSEC_MODE_TO_STR(asso->ctx->mode), + TIPSEC_EALG_TO_STR(asso->ctx->ealg), + asso->ctx->port_uc, + asso->ctx->port_us, + asso->ctx->spi_uc, + asso->ctx->spi_us + )); + /* RFC 3329 - 2.3.1 Client Initiated + All the subsequent SIP requests sent by the client to that server + SHOULD make use of the security mechanism initiated in the previous + step. These requests MUST contain a Security-Verify header field + that mirrors the server's list received previously in the Security- + Server header field. These requests MUST also have both a Require + and Proxy-Require header fields with the value "sec-agree". + */ + tsk_list_foreach(item, self->secVerifies) { + tsip_message_add_header(msg, (const tsip_header_t*)item->data); + } + TSIP_MESSAGE_ADD_HEADER(msg, TSIP_HEADER_REQUIRE_VA_ARGS("sec-agree")); + TSIP_MESSAGE_ADD_HEADER(msg, TSIP_HEADER_PROXY_REQUIRE_VA_ARGS("sec-agree")); + break; + } + + default: + break; + } + + ret = 0; + + /* Add Security-Server headers */ bail: - return ret; + return ret; } tnet_fd_t tsip_transport_ipsec_getFD(tsip_transport_ipsec_t* self, int isRequest) { - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - return TNET_INVALID_FD; - } - - /* If no active SAs ca be found then use default connection. */ - if (!self->asso_active) { - return TNET_INVALID_FD; - // return TSIP_TRANSPORT(self)->connectedFD; - } - - /* IPSec ports management - For more information: http://betelco.blogspot.com/2008/09/ipsec-using-security-agreement-in-3gpp.html - */ - - if (TNET_SOCKET_TYPE_IS_DGRAM(TSIP_TRANSPORT(self)->type)) { - /* - === UDP === - port_uc -> REGISTER -> port_ps - port_ps <- 200 OK <- port_pc - */ - return self->asso_active->socket_uc->fd; - } - else { - /* - === TCP === - port_uc -> REGISTER -> port_ps - port_uc <- 200 OK <- port_ps - - port_us <- NOTIFY <- port_pc - port_us -> 200 OK -> port_pc - */ - if (isRequest) { - return self->asso_active->socket_uc->fd; - } - else { - return self->asso_active->socket_us->fd; - } - } - - return TNET_INVALID_FD; + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return TNET_INVALID_FD; + } + + /* If no active SAs ca be found then use default connection. */ + if (!self->asso_active) { + return TNET_INVALID_FD; + // return TSIP_TRANSPORT(self)->connectedFD; + } + + /* IPSec ports management + For more information: http://betelco.blogspot.com/2008/09/ipsec-using-security-agreement-in-3gpp.html + */ + + if (TNET_SOCKET_TYPE_IS_DGRAM(TSIP_TRANSPORT(self)->type)) { + /* + === UDP === + port_uc -> REGISTER -> port_ps + port_ps <- 200 OK <- port_pc + */ + return self->asso_active->socket_uc->fd; + } + else { + /* + === TCP === + port_uc -> REGISTER -> port_ps + port_uc <- 200 OK <- port_ps + + port_us <- NOTIFY <- port_pc + port_us -> 200 OK -> port_pc + */ + if (isRequest) { + return self->asso_active->socket_uc->fd; + } + else { + return self->asso_active->socket_us->fd; + } + } + + return TNET_INVALID_FD; } @@ -373,57 +373,56 @@ tnet_fd_t tsip_transport_ipsec_getFD(tsip_transport_ipsec_t* self, int isRequest // static tsk_object_t* tsip_transport_ipsec_ctor(tsk_object_t * self, va_list * app) { - tsip_transport_ipsec_t *transport = self; - if(transport){ - const struct tsip_stack_s *stack = va_arg(*app, const struct tsip_stack_s*); - const char *host = va_arg(*app, const char*); + tsip_transport_ipsec_t *transport = self; + if(transport) { + const struct tsip_stack_s *stack = va_arg(*app, const struct tsip_stack_s*); + const char *host = va_arg(*app, const char*); #if defined(__GNUC__) - tnet_port_t port = (tnet_port_t)va_arg(*app, unsigned); + tnet_port_t port = (tnet_port_t)va_arg(*app, unsigned); #else - tnet_port_t port = va_arg(*app, tnet_port_t); + tnet_port_t port = va_arg(*app, tnet_port_t); #endif - tnet_socket_type_t type = va_arg(*app, tnet_socket_type_t); - const char *description = va_arg(*app, const char*); - - /* init base */ - tsip_transport_init(TSIP_TRANSPORT(transport), type, stack, host, port, description); - } - return self; + tnet_socket_type_t type = va_arg(*app, tnet_socket_type_t); + const char *description = va_arg(*app, const char*); + + /* init base */ + tsip_transport_init(TSIP_TRANSPORT(transport), type, stack, host, port, description); + } + return self; } static tsk_object_t* tsip_transport_ipsec_dtor(tsk_object_t * self) -{ - tsip_transport_ipsec_t *transport = self; - if(transport){ - /* deinit base */ - tsip_transport_deinit(TSIP_TRANSPORT(transport)); - - /* deinit self */ - tsip_transport_ipsec_cleanupSAs(transport); - - TSK_OBJECT_SAFE_FREE(transport->secVerifies); - } - return self; +{ + tsip_transport_ipsec_t *transport = self; + if(transport) { + /* deinit base */ + tsip_transport_deinit(TSIP_TRANSPORT(transport)); + + /* deinit self */ + tsip_transport_ipsec_cleanupSAs(transport); + + TSK_OBJECT_SAFE_FREE(transport->secVerifies); + } + return self; } static int tsip_transport_ipsec_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - const tsip_transport_ipsec_t *transport1 = obj1; - const tsip_transport_ipsec_t *transport2 = obj2; - if(transport1 && transport2){ - const char* desc1 = tsip_transport_get_description(TSIP_TRANSPORT(transport1)); - const char* desc2 = tsip_transport_get_description(TSIP_TRANSPORT(transport2)); - return tsk_stricmp(desc1, desc2); - } - return -1; + const tsip_transport_ipsec_t *transport1 = obj1; + const tsip_transport_ipsec_t *transport2 = obj2; + if(transport1 && transport2) { + const char* desc1 = tsip_transport_get_description(TSIP_TRANSPORT(transport1)); + const char* desc2 = tsip_transport_get_description(TSIP_TRANSPORT(transport2)); + return tsk_stricmp(desc1, desc2); + } + return -1; } -static const tsk_object_def_t tsip_transport_ipsec_def_s = -{ - sizeof(tsip_transport_ipsec_t), - tsip_transport_ipsec_ctor, - tsip_transport_ipsec_dtor, - tsip_transport_ipsec_cmp, +static const tsk_object_def_t tsip_transport_ipsec_def_s = { + sizeof(tsip_transport_ipsec_t), + tsip_transport_ipsec_ctor, + tsip_transport_ipsec_dtor, + tsip_transport_ipsec_cmp, }; const tsk_object_def_t *tsip_transport_ipsec_def_t = &tsip_transport_ipsec_def_s; @@ -442,96 +441,92 @@ const tsk_object_def_t *tsip_transport_ipsec_def_t = &tsip_transport_ipsec_def_s // static tsk_object_t* tsip_ipsec_association_ctor(tsk_object_t * self, va_list * app) { - tsip_ipsec_association_t *association = self; - if(association){ - - const tsip_transport_t* transport = va_arg(*app, const tsip_transport_t *); - - /* Set transport */ - association->transport = transport; - - /* Get local IP and port. */ - tsip_transport_get_ip_n_port(transport, &association->ip_local, &association->port_local); - - /* Create IPSec context */ - if (tipsec_ctx_create( - TIPSEC_IPPROTO_FROM_STR(transport->protocol), - TNET_SOCKET_TYPE_IS_IPV6(transport->type), - TIPSEC_MODE_FROM_STR(transport->stack->security.ipsec.mode), - TIPSEC_EALG_FROM_STR(transport->stack->security.ipsec.ealg), - TIPSEC_ALG_FROM_STR(transport->stack->security.ipsec.alg), - TIPSEC_PROTOCOL_FROM_STR(transport->stack->security.ipsec.protocol), &association->ctx)) - { - TSK_DEBUG_ERROR("Failed to create IPSec context"); - return tsk_null; - } - - /* Create Both client and Server legs */ - association->socket_us = tnet_socket_create(association->ip_local, TNET_SOCKET_PORT_ANY, transport->type); - association->socket_uc = tnet_socket_create(association->ip_local, TNET_SOCKET_PORT_ANY, transport->type); - - /* Add Both sockets to the network transport */ - tsip_transport_add_socket(transport, association->socket_us->fd, transport->type, 0, 0); - tsip_transport_add_socket(transport, association->socket_uc->fd, transport->type, 0, 1); - - /* Set local */ - if (tnet_get_peerip(transport->connectedFD, &association->ip_remote) == 0) { /* Get remote IP string */ - if (tipsec_ctx_set_local(association->ctx, association->ip_local, association->ip_remote, association->socket_uc->port, association->socket_us->port)) { - TSK_DEBUG_ERROR("Failed to set IPSec local info:%s,%s,%u,%u", association->ip_local, association->ip_remote, association->socket_uc->port, association->socket_us->port); - return tsk_null; - } - } - else { - // Resolve the HostName because "tipsec_ctx_set_local()" requires IP address instead of FQDN. - if (tnet_resolve(transport->stack->network.proxy_cscf[transport->stack->network.transport_idx_default], - transport->stack->network.proxy_cscf_port[transport->stack->network.transport_idx_default], - transport->stack->network.proxy_cscf_type[transport->stack->network.transport_idx_default], - &association->ip_remote, tsk_null)) - { - return tsk_null; - } - if (tipsec_ctx_set_local(association->ctx, - association->ip_local, - association->ip_remote, - association->socket_uc->port, - association->socket_us->port)) - { - return tsk_null; - } - } - } - return self; + tsip_ipsec_association_t *association = self; + if(association) { + + const tsip_transport_t* transport = va_arg(*app, const tsip_transport_t *); + + /* Set transport */ + association->transport = transport; + + /* Get local IP and port. */ + tsip_transport_get_ip_n_port(transport, &association->ip_local, &association->port_local); + + /* Create IPSec context */ + if (tipsec_ctx_create( + TIPSEC_IPPROTO_FROM_STR(transport->protocol), + TNET_SOCKET_TYPE_IS_IPV6(transport->type), + TIPSEC_MODE_FROM_STR(transport->stack->security.ipsec.mode), + TIPSEC_EALG_FROM_STR(transport->stack->security.ipsec.ealg), + TIPSEC_ALG_FROM_STR(transport->stack->security.ipsec.alg), + TIPSEC_PROTOCOL_FROM_STR(transport->stack->security.ipsec.protocol), &association->ctx)) { + TSK_DEBUG_ERROR("Failed to create IPSec context"); + return tsk_null; + } + + /* Create Both client and Server legs */ + association->socket_us = tnet_socket_create(association->ip_local, TNET_SOCKET_PORT_ANY, transport->type); + association->socket_uc = tnet_socket_create(association->ip_local, TNET_SOCKET_PORT_ANY, transport->type); + + /* Add Both sockets to the network transport */ + tsip_transport_add_socket(transport, association->socket_us->fd, transport->type, 0, 0); + tsip_transport_add_socket(transport, association->socket_uc->fd, transport->type, 0, 1); + + /* Set local */ + if (tnet_get_peerip(transport->connectedFD, &association->ip_remote) == 0) { /* Get remote IP string */ + if (tipsec_ctx_set_local(association->ctx, association->ip_local, association->ip_remote, association->socket_uc->port, association->socket_us->port)) { + TSK_DEBUG_ERROR("Failed to set IPSec local info:%s,%s,%u,%u", association->ip_local, association->ip_remote, association->socket_uc->port, association->socket_us->port); + return tsk_null; + } + } + else { + // Resolve the HostName because "tipsec_ctx_set_local()" requires IP address instead of FQDN. + if (tnet_resolve(transport->stack->network.proxy_cscf[transport->stack->network.transport_idx_default], + transport->stack->network.proxy_cscf_port[transport->stack->network.transport_idx_default], + transport->stack->network.proxy_cscf_type[transport->stack->network.transport_idx_default], + &association->ip_remote, tsk_null)) { + return tsk_null; + } + if (tipsec_ctx_set_local(association->ctx, + association->ip_local, + association->ip_remote, + association->socket_uc->port, + association->socket_us->port)) { + return tsk_null; + } + } + } + return self; } static tsk_object_t* tsip_ipsec_association_dtor(tsk_object_t * self) -{ - tsip_ipsec_association_t *association = self; - if(association){ - TSK_OBJECT_SAFE_FREE(association->ctx); - - /* Remove Both sockets from the network transport and delete them. */ - if(association->socket_uc){ - tsip_transport_remove_socket(association->transport, &association->socket_uc->fd); - TSK_OBJECT_SAFE_FREE(association->socket_uc); - } - if(association->socket_us){ - tsip_transport_remove_socket(association->transport, &association->socket_us->fd); - TSK_OBJECT_SAFE_FREE(association->socket_us); - } - } - return self; +{ + tsip_ipsec_association_t *association = self; + if(association) { + TSK_OBJECT_SAFE_FREE(association->ctx); + + /* Remove Both sockets from the network transport and delete them. */ + if(association->socket_uc) { + tsip_transport_remove_socket(association->transport, &association->socket_uc->fd); + TSK_OBJECT_SAFE_FREE(association->socket_uc); + } + if(association->socket_us) { + tsip_transport_remove_socket(association->transport, &association->socket_us->fd); + TSK_OBJECT_SAFE_FREE(association->socket_us); + } + } + return self; } static int tsip_ipsec_association_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_ipsec_association_def_s = -{ - sizeof(tsip_ipsec_association_t), - tsip_ipsec_association_ctor, - tsip_ipsec_association_dtor, - tsip_ipsec_association_cmp, +static const tsk_object_def_t tsip_ipsec_association_def_s = { + sizeof(tsip_ipsec_association_t), + tsip_ipsec_association_ctor, + tsip_ipsec_association_dtor, + tsip_ipsec_association_cmp, }; const tsk_object_def_t *tsip_ipsec_association_def_t = &tsip_ipsec_association_def_s; 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; |