summaryrefslogtreecommitdiffstats
path: root/tinySIP/src/transports
diff options
context:
space:
mode:
Diffstat (limited to 'tinySIP/src/transports')
-rwxr-xr-xtinySIP/src/transports/tsip_transport.c1707
-rwxr-xr-xtinySIP/src/transports/tsip_transport_ipsec.c781
-rwxr-xr-xtinySIP/src/transports/tsip_transport_layer.c2408
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(&quoted_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(&quoted_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;
OpenPOWER on IntegriCloud