1 /*
2   The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3   Copyright (C) 2001-2020 Aymeric MOIZARD amoizard@antisip.com
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <osip2/internal.h>
21 #include <osip2/osip.h>
22 
23 #include "fsm.h"
24 #include "xixt.h"
25 
__osip_ict_init(osip_ict_t ** ict,osip_t * osip,osip_message_t * invite)26 int __osip_ict_init(osip_ict_t **ict, osip_t *osip, osip_message_t *invite) {
27   osip_route_t *route;
28   int i;
29 
30   OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO2, NULL, "allocating ICT context\n"));
31 
32   *ict = (osip_ict_t *) osip_malloc(sizeof(osip_ict_t));
33 
34   if (*ict == NULL)
35     return OSIP_NOMEM;
36 
37   memset(*ict, 0, sizeof(osip_ict_t));
38   /* for INVITE retransmissions */
39   {
40     osip_via_t *via;
41     char *proto;
42 
43     i = osip_message_get_via(invite, 0, &via); /* get top via */
44 
45     if (i < 0) {
46       osip_free(*ict);
47       return i;
48     }
49 
50     proto = via_get_protocol(via);
51 
52     if (proto == NULL) {
53       osip_free(*ict);
54       return OSIP_SYNTAXERROR;
55     }
56 
57 #ifdef USE_BLOCKINGSOCKET
58 
59     if (osip_strcasecmp(proto, "TCP") != 0 && osip_strcasecmp(proto, "TLS") != 0 && osip_strcasecmp(proto, "SCTP") != 0) {
60       /* for other reliable protocol than TCP, the timer
61       must be desactived by the external application */
62       (*ict)->timer_a_length = DEFAULT_T1;
63 
64       if (64 * DEFAULT_T1 < 32000)
65         (*ict)->timer_d_length = 32000;
66 
67       else
68         (*ict)->timer_d_length = 64 * DEFAULT_T1;
69 
70       osip_gettimeofday(&(*ict)->timer_a_start, NULL);
71       add_gettimeofday(&(*ict)->timer_a_start, (*ict)->timer_a_length);
72       (*ict)->timer_d_start.tv_sec = -1; /* not started */
73 
74     } else {                             /* reliable protocol is used: */
75       (*ict)->timer_a_length = -1;       /* A is not ACTIVE */
76       (*ict)->timer_d_length = 0;        /* MUST do the transition immediatly */
77       (*ict)->timer_a_start.tv_sec = -1; /* not started */
78       (*ict)->timer_d_start.tv_sec = -1; /* not started */
79     }
80   }
81 #else
82 
83     if (osip_strcasecmp(proto, "TCP") != 0 && osip_strcasecmp(proto, "TLS") != 0 && osip_strcasecmp(proto, "SCTP") != 0) {
84       /* for other reliable protocol than TCP, the timer
85       must be desactived by the external application */
86       (*ict)->timer_a_length = DEFAULT_T1;
87 
88       if (64 * DEFAULT_T1 < 32000)
89         (*ict)->timer_d_length = 32000;
90 
91       else
92         (*ict)->timer_d_length = 64 * DEFAULT_T1;
93 
94       osip_gettimeofday(&(*ict)->timer_a_start, NULL);
95       add_gettimeofday(&(*ict)->timer_a_start, (*ict)->timer_a_length);
96       (*ict)->timer_d_start.tv_sec = -1; /* not started */
97 
98     } else { /* reliable protocol is used: */
99       (*ict)->timer_a_length = DEFAULT_T1;
100       (*ict)->timer_d_length = 0; /* MUST do the transition immediatly */
101       osip_gettimeofday(&(*ict)->timer_a_start, NULL);
102       add_gettimeofday(&(*ict)->timer_a_start, (*ict)->timer_a_length);
103       (*ict)->timer_d_start.tv_sec = -1; /* not started */
104     }
105   }
106 #endif
107 
108   /* for PROXY, the destination MUST be set by the application layer,
109      this one may not be correct. */
110   osip_message_get_route(invite, 0, &route);
111 
112   if (route != NULL && route->url != NULL) {
113     osip_uri_param_t *lr_param;
114 
115     osip_uri_uparam_get_byname(route->url, "lr", &lr_param);
116 
117     if (lr_param == NULL) {
118       /* using uncompliant proxy: destination is the request-uri */
119       route = NULL;
120     }
121   }
122 
123   if (route != NULL && route->url != NULL) {
124     int port = 5060;
125 
126     if (route->url->port != NULL)
127       port = osip_atoi(route->url->port);
128 
129     osip_ict_set_destination((*ict), osip_strdup(route->url->host), port);
130 
131   } else {
132     int port = 5060;
133 
134     /* search for maddr parameter */
135     osip_uri_param_t *maddr_param = NULL;
136     osip_uri_param_t *obr_param = NULL;
137     osip_uri_param_t *obp_param = NULL;
138 
139     port = 5060;
140 
141     if (invite->req_uri->port != NULL)
142       port = osip_atoi(invite->req_uri->port);
143 
144     /* if ob was used in Contact, then exosip adds "x-obr" and "x-obp", thus, when
145        processing request, the ip/port destination are re-used here */
146     osip_uri_uparam_get_byname(invite->req_uri, "x-obr", &obr_param);
147     osip_uri_uparam_get_byname(invite->req_uri, "x-obp", &obp_param);
148 
149     osip_uri_uparam_get_byname(invite->req_uri, "maddr", &maddr_param);
150 
151     if (maddr_param != NULL && maddr_param->gvalue != NULL)
152       osip_ict_set_destination((*ict), osip_strdup(maddr_param->gvalue), port);
153 
154     else if (obr_param != NULL && obr_param->gvalue != NULL && obp_param != NULL && obp_param->gvalue != NULL)
155       osip_ict_set_destination((*ict), osip_strdup(obr_param->gvalue), osip_atoi(obp_param->gvalue));
156 
157     else
158       osip_ict_set_destination((*ict), osip_strdup(invite->req_uri->host), port);
159   }
160 
161   (*ict)->timer_b_length = 64 * DEFAULT_T1;
162   osip_gettimeofday(&(*ict)->timer_b_start, NULL);
163   add_gettimeofday(&(*ict)->timer_b_start, (*ict)->timer_b_length);
164 
165   /* Oups! A bug! */
166   /*  (*ict)->port  = 5060; */
167 
168   return OSIP_SUCCESS;
169 }
170 
__osip_ict_free(osip_ict_t * ict)171 int __osip_ict_free(osip_ict_t *ict) {
172   if (ict == NULL)
173     return OSIP_SUCCESS;
174 
175   OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO2, NULL, "free ict resource\n"));
176 
177   osip_free(ict->destination);
178   osip_free(ict);
179   return OSIP_SUCCESS;
180 }
181 
osip_ict_set_destination(osip_ict_t * ict,char * destination,int port)182 int osip_ict_set_destination(osip_ict_t *ict, char *destination, int port) {
183   if (ict == NULL)
184     return OSIP_BADPARAMETER;
185 
186   if (ict->destination != NULL)
187     osip_free(ict->destination);
188 
189   ict->destination = destination;
190   ict->port = port;
191   return OSIP_SUCCESS;
192 }
193 
__osip_ict_need_timer_a_event(osip_ict_t * ict,state_t state,int transactionid)194 osip_event_t *__osip_ict_need_timer_a_event(osip_ict_t *ict, state_t state, int transactionid) {
195   return __osip_transaction_need_timer_x_event(ict, &ict->timer_a_start, state == ICT_CALLING, transactionid, TIMEOUT_A);
196 }
197 
__osip_ict_need_timer_b_event(osip_ict_t * ict,state_t state,int transactionid)198 osip_event_t *__osip_ict_need_timer_b_event(osip_ict_t *ict, state_t state, int transactionid) {
199   return __osip_transaction_need_timer_x_event(ict, &ict->timer_b_start, state == ICT_CALLING, transactionid, TIMEOUT_B);
200 }
201 
__osip_ict_need_timer_d_event(osip_ict_t * ict,state_t state,int transactionid)202 osip_event_t *__osip_ict_need_timer_d_event(osip_ict_t *ict, state_t state, int transactionid) {
203   return __osip_transaction_need_timer_x_event(ict, &ict->timer_d_start, state == ICT_COMPLETED, transactionid, TIMEOUT_D);
204 }
205