ims_usrloc_pcscf: fix value array size and compile warnings
[sip-router] / src / modules / ims_usrloc_pcscf / pcontact.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
6  * 
7  * The initial version of this code was written by Dragos Vingarzan
8  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
9  * Fruanhofer Institute. It was and still is maintained in a separate
10  * branch of the original SER. We are therefore migrating it to
11  * Kamailio/SR and look forward to maintaining it from here on out.
12  * 2011/2012 Smile Communications, Pty. Ltd.
13  * ported/maintained/improved by 
14  * Jason Penton (jason(dot)penton(at)smilecoms.com and
15  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
16  * effort to add full IMS support to Kamailio/SR using a new and
17  * improved architecture
18  * 
19  * NB: Alot of this code was originally part of OpenIMSCore,
20  * FhG Fokus. 
21  * Copyright (C) 2004-2006 FhG Fokus
22  * Thanks for great work! This is an effort to 
23  * break apart the various CSCF functions into logically separate
24  * components. We hope this will drive wider use. We also feel
25  * that in this way the architecture is more complete and thereby easier
26  * to manage in the Kamailio/SR environment
27  *
28  * This file is part of Kamailio, a free SIP server.
29  *
30  * Kamailio is free software; you can redistribute it and/or modify
31  * it under the terms of the GNU General Public License as published by
32  * the Free Software Foundation; either version 2 of the License, or
33  * (at your option) any later version
34  *
35  * Kamailio is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License 
41  * along with this program; if not, write to the Free Software 
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
43  * 
44  */
45
46 #include "pcontact.h"
47 #include <string.h>
48 #include "../../core/hashes.h"
49 #include "../../core/mem/shm_mem.h"
50 #include "../../core/dprint.h"
51 #include "../../core/ut.h"
52 #include "ims_usrloc_pcscf_mod.h"
53 #include "usrloc.h"
54 #include "utime.h"
55 #include "ul_callback.h"
56 #include "usrloc.h"
57 #include "../../lib/ims/useful_defs.h"
58 #include "usrloc_db.h"
59 #include "../../core/parser/parse_uri.h"
60
61 extern int db_mode;
62
63 extern int expires_grace;
64
65 /*! retransmission detection interval in seconds */
66 int cseq_delay = 20;
67
68 void insert_ppublic(struct pcontact* _c, ppublic_t* _p)
69 {
70         LM_DBG("linking IMPU <%.*s> to contact <%.*s>\n",
71                         _p->public_identity.len,_p->public_identity.s,
72                         _c->aor.len, _c->aor.s);
73
74         if (_c->head == 0) {//first entry
75                 _c->head = _c->tail = _p;
76         } else {
77                 _p->prev = _c->tail;
78                 _c->tail->next = _p;
79                 _c->tail = _p;
80         }
81 }
82 int new_ppublic(str* public_identity, int is_default, ppublic_t** _p)
83 {
84         *_p = (ppublic_t*)shm_malloc(sizeof(ppublic_t));
85         if (!*_p) {
86                 LM_ERR("no more shm memory\n");
87                 return -1;
88         }
89         (*_p)->next=(*_p)->prev=0;
90         (*_p)->public_identity.s = (char*)shm_malloc(public_identity->len);
91         if (!(*_p)->public_identity.s) {
92                 LM_ERR("no more shm memory\n");
93                 if (*_p) {
94                         shm_free(*_p);
95                 }
96                 return -1;
97         }
98
99         (*_p)->is_default = is_default;
100         memcpy((*_p)->public_identity.s, public_identity->s, public_identity->len);
101         (*_p)->public_identity.len = public_identity->len;
102         return 0;
103 }
104
105 void free_ppublic(ppublic_t* _p)
106 {
107         if (!_p)
108                 return;
109         if (_p->public_identity.s) {
110                 shm_free(_p->public_identity.s);
111         }
112         shm_free(_p);
113 }
114
115
116 // The same piece of code also lives in modules/ims_registrar_pcscf/sec_agree.c
117 // Function - parse_sec_agree()
118 // goto label - cleanup
119 // Keep them in sync!
120 void free_security(security_t* _p)
121 {
122     if (!_p) {
123         return;
124     }
125
126     if(_p->sec_header.s) {
127         shm_free(_p->sec_header.s);
128         }
129
130     switch (_p->type)
131     {
132         case SECURITY_IPSEC:
133                         if(_p->data.ipsec){
134                                 if(_p->data.ipsec->ealg.s)              shm_free(_p->data.ipsec->ealg.s);
135                                 if(_p->data.ipsec->r_ealg.s)    shm_free(_p->data.ipsec->r_ealg.s);
136                                 if(_p->data.ipsec->ck.s)                shm_free(_p->data.ipsec->ck.s);
137                                 if(_p->data.ipsec->alg.s)               shm_free(_p->data.ipsec->alg.s);
138                                 if(_p->data.ipsec->r_alg.s)             shm_free(_p->data.ipsec->r_alg.s);
139                                 if(_p->data.ipsec->ik.s)                shm_free(_p->data.ipsec->ik.s);
140                                 if(_p->data.ipsec->prot.s)              shm_free(_p->data.ipsec->prot.s);
141                                 if(_p->data.ipsec->mod.s)               shm_free(_p->data.ipsec->mod.s);
142
143                                 shm_free(_p->data.ipsec);
144                         }
145         break;
146
147         case SECURITY_TLS:
148                         if(_p->data.tls) {
149                                 shm_free(_p->data.tls);
150                         }
151         break;
152         
153         case SECURITY_NONE:
154             //Nothing to deallocate
155         break;
156     }
157
158     shm_free(_p);
159 }
160
161 int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _c)
162 {
163         int i, has_rinstance=0;
164         ppublic_t* ppublic_ptr;
165         int is_default = 1, params_len;
166         struct sip_uri sip_uri;
167         char* p, *params, *sep;
168         str rinstance = {0,0};
169         
170         *_c = (pcontact_t*)shm_malloc(sizeof(pcontact_t) + _contact->len + _ci->received_host.len + _ci->via_host.len);
171         if (*_c == 0) {
172                 LM_ERR("no more shared memory\n");
173                 return -1;
174         }
175         memset(*_c, 0, sizeof(pcontact_t));
176
177         LM_DBG("New contact [<%.*s>] with %d associated IMPUs in state: [%s]\n",
178                         _contact->len, _contact->s,
179                         _ci->num_public_ids,
180                         reg_state_to_string(_ci->reg_state));
181         
182         
183
184         p = (char*)((struct pcontact*)(*_c) + 1);
185         (*_c)->aor.s = p;
186         memcpy(p, _contact->s, _contact->len);
187         p += _contact->len;
188         (*_c)->aor.len = _contact->len;
189         (*_c)->domain = (str*)_d;
190
191         if (parse_uri((*_c)->aor.s, (*_c)->aor.len, &sip_uri) != 0) {
192                 LM_ERR("unable to determine contact host from uri [%.*s\n", (*_c)->aor.len, (*_c)->aor.s);
193                 shm_free((*_c)->aor.s);
194                 shm_free(*_c);
195                 *_c = 0;
196                 return -2;
197         }
198         
199         /* is there an rinstance param */
200         LM_DBG("checking for rinstance");
201         /*check for alias - NAT */
202         params = sip_uri.sip_params.s;
203         params_len = sip_uri.sip_params.len;
204         while (params_len >= RINSTANCE_LEN) {
205             if (strncmp(params, RINSTANCE, RINSTANCE_LEN) == 0) {
206                 has_rinstance = 1;
207                 break;
208             }
209             sep = memchr(params, 59 /* ; */, params_len);
210             if (sep == NULL) {
211                 LM_DBG("no rinstance param\n");
212                 break;
213             } else {
214                 params_len = params_len - (sep - params + 1);
215                 params = sep + 1;
216             }
217         }
218         if (has_rinstance) {
219             rinstance.s = params + RINSTANCE_LEN;
220             rinstance.len = params_len - RINSTANCE_LEN;
221             sep = (char*)memchr(rinstance.s, 59 /* ; */, rinstance.len);
222             if (sep != NULL){
223                 rinstance.len = (sep-rinstance.s);
224             }
225         }
226         (*_c)->rinstance.s = rinstance.s;
227         (*_c)->rinstance.len = rinstance.len;
228         (*_c)->contact_host.s = sip_uri.host.s;
229         (*_c)->contact_host.len = sip_uri.host.len;
230         (*_c)->contact_port = sip_uri.port_no?sip_uri.port_no:5060;
231         (*_c)->contact_user.s = sip_uri.user.s;
232         (*_c)->contact_user.len = sip_uri.user.len;
233
234         (*_c)->expires = _ci->expires;
235         (*_c)->reg_state = _ci->reg_state;
236
237         // Add received Info:
238         if (_ci->received_host.len > 0 && _ci->received_host.s) {
239         (*_c)->received_host.s = p;
240                 memcpy(p, _ci->received_host.s, _ci->received_host.len);
241                 p += _ci->received_host.len;
242                 (*_c)->received_host.len = _ci->received_host.len;
243                 (*_c)->received_port = _ci->received_port;
244                 (*_c)->received_proto = _ci->received_proto;
245         }
246         
247         if (_ci->via_host.len > 0 && _ci->via_host.s) {
248             (*_c)->via_host.s = p;
249             memcpy(p, _ci->via_host.s, _ci->via_host.len);
250             p += _ci->via_host.len;
251             (*_c)->via_host.len = _ci->via_host.len;
252             (*_c)->via_port = _ci->via_port;
253             (*_c)->via_proto = _ci->via_prot;
254         }
255         
256         (*_c)->aorhash = get_aor_hash(_d, &_ci->via_host, _ci->via_port, _ci->via_prot);
257
258         //setup public ids
259         for (i=0; i<_ci->num_public_ids; i++) {
260                 if (i>0) is_default = 0; //only the first one is default - P-Associated-uri (first one is default)
261                 if (new_ppublic(&_ci->public_ids[i], is_default, &ppublic_ptr)!=0) {
262                         LM_ERR("unable to create new ppublic\n");
263                 } else {
264                         insert_ppublic(*_c, ppublic_ptr);
265                 }
266         }
267         //add the service routes
268         if (_ci->num_service_routes > 0) {
269                 (*_c)->service_routes = shm_malloc(_ci->num_service_routes * sizeof(str));
270                 if (!(*_c)->service_routes) {
271                         LM_ERR("no more shm mem\n");
272                         goto out_of_memory;
273                 } else {
274                         for (i = 0; i < _ci->num_service_routes; i++) {
275                                 STR_SHM_DUP((*_c)->service_routes[i], _ci->service_routes[i], "new_pcontact");
276                         }
277                         (*_c)->num_service_routes = _ci->num_service_routes;
278                 }
279         }
280         
281         LM_DBG("New contact host:port [%.*s:%d]\n", (*_c)->contact_host.len, (*_c)->contact_host.s, (*_c)->contact_port);
282         LM_DBG("New contact via host:port:proto: [%.*s:%d:%d]\n", (*_c)->via_host.len, (*_c)->via_host.s, (*_c)->via_port, (*_c)->via_proto);
283         LM_DBG("New contact received host:port:proto: [%.*s:%d:%d]\n", (*_c)->received_host.len, (*_c)->received_host.s, (*_c)->received_port, (*_c)->received_proto);
284         LM_DBG("New contact aorhash [%u]\n", (*_c)->aorhash);
285         
286         return 0;
287
288 out_of_memory:
289         return -1;
290 }
291
292 void free_pcontact(pcontact_t* _c) {
293         ppublic_t* p, *tmp;
294         int i;
295
296         if (!_c)
297                 return;
298
299         /*free callbacks*/
300         if (_c->cbs.first) {
301                 destroy_ul_callbacks_list(_c->cbs.first);
302         }
303
304         LM_DBG("freeing pcontact: <%.*s>\n", _c->aor.len, _c->aor.s);
305         //free ppublics
306         p = _c->head;
307         while (p) {
308                 LM_DBG("freeing linked IMPI: <%.*s>\n", p->public_identity.len, p->public_identity.s);
309                 tmp = p->next;
310                 free_ppublic(p);
311                 p = tmp;
312         }
313         //free service_routes
314         if (_c->service_routes) { //remove old service routes
315                 for (i = 0; i < _c->num_service_routes; i++) {
316                         if (_c->service_routes[i].s)
317                                 shm_free(_c->service_routes[i].s);
318                 }
319                 shm_free(_c->service_routes);
320                 _c->service_routes = 0;
321                 _c->num_service_routes = 0;
322         }
323
324     // free_security() checks for NULL ptr
325     free_security(_c->security_temp);
326     free_security(_c->security);
327
328         if (_c->rx_session_id.len > 0 && _c->rx_session_id.s)
329                 shm_free(_c->rx_session_id.s);
330         shm_free(_c);
331 }
332
333 static inline void nodb_timer(pcontact_t* _c)
334 {
335         LM_DBG("Running nodb timer on <%.*s>, "
336                         "Reg state: %s, "
337                         "Expires: %d, "
338                         "Expires in: %d seconds, "
339                         "Received: %.*s:%d, "
340                         "Path: %.*s, "
341                         "Proto: %d, "
342                         "Hash: %u, " 
343                         "Slot: %u\n",
344                         _c->aor.len, _c->aor.s,
345                         reg_state_to_string(_c->reg_state),
346                         (int)_c->expires,
347                         (int)(_c->expires - time(NULL)),
348                         _c->received_host.len, _c->received_host.s,
349                         _c->received_port,
350                         _c->path.len, _c->path.s,
351                         _c->received_proto,
352                         _c->aorhash,
353                         _c->sl);
354
355         get_act_time();
356         
357         
358         if ((_c->expires - act_time) + expires_grace <= 0) {//we've allowed some grace time TODO: add as parameter
359         //if ((_c->expires - act_time) <= -10) {//we've allowed some grace time TODO: add as parameter
360                 LM_DBG("pcscf contact <%.*s> has expired and will be removed\n", _c->aor.len, _c->aor.s);
361                 if (exists_ulcb_type(PCSCF_CONTACT_EXPIRE)) {
362                         run_ul_callbacks(PCSCF_CONTACT_EXPIRE, _c);
363                 }
364
365                 if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) {
366                         LM_ERR("Error deleting ims_usrloc_pcscf record in DB");
367                 }
368
369                 update_stat(_c->slot->d->expired, 1);
370                 mem_delete_pcontact(_c->slot->d, _c);
371                 return;
372         }
373
374         //TODO: this is just for tmp debugging
375 //      p = _c->head;
376 //      while (p) {
377 //              if (p->is_default)
378 //                      LM_DBG("public identity %i (default): <%.*s>\n", i, p->public_identity.len, p->public_identity.s);
379 //              else
380 //                      LM_DBG("public identity %i: <%.*s>\n", i, p->public_identity.len, p->public_identity.s);
381 //              i++;
382 //              p=p->next;
383 //      }
384 //
385 //      LM_DBG("There are %i service routes as follows:\n", _c->num_service_routes);
386 //      for (i=0; i<_c->num_service_routes; i++) {
387 //              LM_DBG("service route %i: <%.*s>\n", i+1, _c->service_routes[i].len, _c->service_routes[i].s);
388 //      }
389 }
390
391 void timer_pcontact(pcontact_t* _r)
392 {
393         nodb_timer(_r);
394 }
395
396 void print_pcontact(FILE* _f, pcontact_t* _r)
397 {
398
399 }