topos: handle return code for parse_headers()
[sip-router] / src / modules / topos / topos_mod.c
1 /**
2  * Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 /*!
23  * \file
24  * \brief Kamailio topos :: Module interface
25  * \ingroup topos
26  * Module: \ref topos
27  */
28
29 /*! \defgroup topoh Kamailio :: Topology stripping
30  *
31  * This module removes the SIP routing headers that show topology details.
32  * The script interpreter gets the SIP messages with full content, so all
33  * existing functionality is preserved.
34  */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40
41 #include "../../core/sr_module.h"
42 #include "../../core/events.h"
43 #include "../../core/dprint.h"
44 #include "../../core/tcp_options.h"
45 #include "../../core/ut.h"
46 #include "../../core/forward.h"
47 #include "../../core/config.h"
48 #include "../../core/parser/msg_parser.h"
49 #include "../../core/parser/parse_uri.h"
50 #include "../../core/parser/parse_to.h"
51 #include "../../core/parser/parse_from.h"
52 #include "../../core/timer_proc.h"
53
54 #include "../../lib/srdb1/db.h"
55 #include "../../lib/srutils/sruid.h"
56
57 #include "../../modules/sanity/api.h"
58
59 #include "tps_storage.h"
60 #include "tps_msg.h"
61 #include "api.h"
62
63 MODULE_VERSION
64
65
66 /* Database connection handle */
67 db1_con_t* _tps_db_handle = NULL;
68 /* DB functions */
69 db_func_t _tpsdbf;
70 /* sruid to get internal uid */
71 sruid_t _tps_sruid;
72
73 /** module parameters */
74 static str _tps_db_url = str_init(DEFAULT_DB_URL);
75 int _tps_param_mask_callid = 0;
76 int _tps_sanity_checks = 0;
77 str _tps_storage = str_init("db");
78
79 extern int _tps_branch_expire;
80 extern int _tps_dialog_expire;
81
82 int _tps_clean_interval = 60;
83
84 sanity_api_t scb;
85
86 int tps_msg_received(sr_event_param_t *evp);
87 int tps_msg_sent(sr_event_param_t *evp);
88
89 /** module functions */
90 /* Module init function prototype */
91 static int mod_init(void);
92 /* Module child-init function prototype */
93 static int child_init(int rank);
94 /* Module destroy function prototype */
95 static void destroy(void);
96
97 int bind_topos(topos_api_t *api);
98
99 static cmd_export_t cmds[]={
100         {"bind_topos",  (cmd_function)bind_topos,  0,
101                 0, 0, 0},
102
103         {0, 0, 0, 0, 0, 0}
104 };
105
106 static param_export_t params[]={
107         {"storage",                     PARAM_STR, &_tps_storage},
108         {"db_url",                      PARAM_STR, &_tps_db_url},
109         {"mask_callid",         PARAM_INT, &_tps_param_mask_callid},
110         {"sanity_checks",       PARAM_INT, &_tps_sanity_checks},
111         {"branch_expire",       PARAM_INT, &_tps_branch_expire},
112         {"dialog_expire",       PARAM_INT, &_tps_dialog_expire},
113         {"clean_interval",      PARAM_INT, &_tps_clean_interval},
114         {0,0,0}
115 };
116
117
118 /** module exports */
119 struct module_exports exports= {
120         "topos",
121         DEFAULT_DLFLAGS, /* dlopen flags */
122         cmds,
123         params,
124         0,          /* exported statistics */
125         0,          /* exported MI functions */
126         0,          /* exported pseudo-variables */
127         0,          /* extra processes */
128         mod_init,   /* module initialization function */
129         0,
130         destroy,    /* destroy function */
131         child_init  /* child initialization function */
132 };
133
134 /**
135  * init module function
136  */
137 static int mod_init(void)
138 {
139         if(_tps_storage.len==2 && strncmp(_tps_storage.s, "db", 2)==0) {
140                 /* Find a database module */
141                 if (db_bind_mod(&_tps_db_url, &_tpsdbf)) {
142                         LM_ERR("unable to bind database module\n");
143                         return -1;
144                 }
145                 if (!DB_CAPABILITY(_tpsdbf, DB_CAP_ALL)) {
146                         LM_CRIT("database modules does not "
147                                 "provide all functions needed\n");
148                         return -1;
149                 }
150         } else {
151                 if(_tps_storage.len!=7 && strncmp(_tps_storage.s, "redis", 5)!=0) {
152                         LM_ERR("unknown storage type: %.*s\n",
153                                         _tps_storage.len, _tps_storage.s);
154                         return -1;
155                 }
156         }
157
158         if(_tps_sanity_checks!=0) {
159                 if(sanity_load_api(&scb)<0) {
160                         LM_ERR("cannot bind to sanity module\n");
161                         goto error;
162                 }
163         }
164         if(tps_storage_lock_set_init()<0) {
165                 LM_ERR("failed to initialize locks set\n");
166                 return -1;
167         }
168
169         if(sruid_init(&_tps_sruid, '-', "tpsh", SRUID_INC)<0)
170                 return -1;
171
172         sr_event_register_cb(SREV_NET_DATA_IN,  tps_msg_received);
173         sr_event_register_cb(SREV_NET_DATA_OUT, tps_msg_sent);
174
175 #ifdef USE_TCP
176         tcp_set_clone_rcvbuf(1);
177 #endif
178
179         if(sr_wtimer_add(tps_storage_clean, NULL, _tps_clean_interval)<0)
180                 return -1;
181
182         return 0;
183 error:
184         return -1;
185 }
186
187 /**
188  *
189  */
190 static int child_init(int rank)
191 {
192         if(sruid_init(&_tps_sruid, '-', "tpsh", SRUID_INC)<0)
193                 return -1;
194
195         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
196                 return 0; /* do nothing for the main process */
197
198         if(_tps_storage.len==2 && strncmp(_tps_storage.s, "db", 2)==0) {
199                 _tps_db_handle = _tpsdbf.init(&_tps_db_url);
200                 if (!_tps_db_handle) {
201                         LM_ERR("unable to connect database\n");
202                         return -1;
203                 }
204         }
205         return 0;
206
207 }
208
209 /**
210  *
211  */
212 static void destroy(void)
213 {
214         if(_tps_storage.len==2 && strncmp(_tps_storage.s, "db", 2)==0) {
215                 if (_tps_db_handle) {
216                         _tpsdbf.close(_tps_db_handle);
217                         _tps_db_handle = 0;
218                 }
219         }
220         tps_storage_lock_set_destroy();
221 }
222
223 /**
224  *
225  */
226 int tps_prepare_msg(sip_msg_t *msg)
227 {
228         if (parse_msg(msg->buf, msg->len, msg)!=0) {
229                 LM_DBG("outbuf buffer parsing failed!");
230                 return 1;
231         }
232
233         if(msg->first_line.type==SIP_REQUEST) {
234                 if(!IS_SIP(msg)) {
235                         LM_DBG("non sip request message\n");
236                         return 1;
237                 }
238         } else if(msg->first_line.type!=SIP_REPLY) {
239                 LM_DBG("non sip message\n");
240                 return 1;
241         }
242
243         if(parse_headers(msg, HDR_VIA2_F, 0)<0) {
244                 LM_DBG("no via2 has been parsed\n");
245         }
246
247         if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL) {
248                 LM_ERR("cannot parse cseq header\n");
249                 return -1;
250         }
251
252         if (parse_headers(msg, HDR_EOH_F, 0)==-1) {
253                 LM_DBG("parsing headers failed [[%.*s]]\n",
254                                 msg->len, msg->buf);
255                 return 2;
256         }
257
258         if(parse_from_header(msg)<0) {
259                 LM_ERR("cannot parse FROM header\n");
260                 return 3;
261         }
262
263         if(parse_to_header(msg)<0 || msg->to==NULL) {
264                 LM_ERR("cannot parse TO header\n");
265                 return 3;
266         }
267
268         if(get_to(msg)==NULL) {
269                 LM_ERR("cannot get TO header\n");
270                 return 3;
271         }
272
273         return 0;
274 }
275
276 /**
277  *
278  */
279 int tps_msg_received(sr_event_param_t *evp)
280 {
281         sip_msg_t msg;
282         str *obuf;
283         char *nbuf = NULL;
284         int dialog;
285         int ret;
286
287         obuf = (str*)evp->data;
288         memset(&msg, 0, sizeof(sip_msg_t));
289         msg.buf = obuf->s;
290         msg.len = obuf->len;
291
292         ret = 0;
293         if(tps_prepare_msg(&msg)!=0) {
294                 goto done;
295         }
296
297         if(tps_skip_msg(&msg)) {
298                 goto done;
299         }
300
301         if(msg.first_line.type==SIP_REQUEST) {
302                 if(_tps_sanity_checks!=0) {
303                         if(scb.check_defaults(&msg)<1) {
304                                 LM_ERR("sanity checks failed\n");
305                                 goto done;
306                         }
307                 }
308                 dialog = (get_to(&msg)->tag_value.len>0)?1:0;
309                 if(dialog) {
310                         /* dialog request */
311                         tps_request_received(&msg, dialog);
312                 }
313         } else {
314                 /* reply */
315                 if(msg.first_line.u.reply.statuscode==100) {
316                         /* nothing to do - it should be absorbed */
317                         goto done;
318                 }
319                 tps_response_received(&msg);
320         }
321
322         nbuf = tps_msg_update(&msg, (unsigned int*)&obuf->len);
323
324         if(nbuf==NULL) {
325                 LM_ERR("not enough pkg memory for new message\n");
326                 ret = -1;
327                 goto done;
328         }
329         if(obuf->len>=BUF_SIZE) {
330                 LM_ERR("new buffer overflow (%d)\n", obuf->len);
331                 ret = -1;
332                 goto done;
333         }
334         memcpy(obuf->s, nbuf, obuf->len);
335         obuf->s[obuf->len] = '\0';
336
337 done:
338         if(nbuf!=NULL)
339                 pkg_free(nbuf);
340         free_sip_msg(&msg);
341         return ret;
342 }
343
344 /**
345  *
346  */
347 int tps_msg_sent(sr_event_param_t *evp)
348 {
349         sip_msg_t msg;
350         str *obuf;
351         int dialog;
352         int local;
353
354         obuf = (str*)evp->data;
355         memset(&msg, 0, sizeof(sip_msg_t));
356         msg.buf = obuf->s;
357         msg.len = obuf->len;
358
359         if(tps_prepare_msg(&msg)!=0) {
360                 goto done;
361         }
362
363         if(tps_skip_msg(&msg)) {
364                 goto done;
365         }
366
367         if(msg.first_line.type==SIP_REQUEST) {
368                 dialog = (get_to(&msg)->tag_value.len>0)?1:0;
369
370                 local = 0;
371                 if(msg.via2==0) {
372                         local = 1;
373                 }
374
375                 tps_request_sent(&msg, dialog, local);
376         } else {
377                 /* reply */
378                 if(msg.first_line.u.reply.statuscode==100) {
379                         /* nothing to do - it should be locally generated */
380                         goto done;
381                 }
382                 tps_response_sent(&msg);
383         }
384
385         obuf->s = tps_msg_update(&msg, (unsigned int*)&obuf->len);
386
387 done:
388         free_sip_msg(&msg);
389         return 0;
390 }
391
392 /**
393  *
394  */
395 int tps_get_dialog_expire(void)
396 {
397         return _tps_dialog_expire;
398 }
399
400 /**
401  *
402  */
403 int tps_get_branch_expire(void)
404 {
405         return _tps_branch_expire;
406 }
407
408 /**
409  *
410  */
411 int bind_topos(topos_api_t *api)
412 {
413         if (!api) {
414                 ERR("Invalid parameter value\n");
415                 return -1;
416         }
417         memset(api, 0, sizeof(topos_api_t));
418         api->set_storage_api = tps_set_storage_api;
419         api->get_dialog_expire = tps_get_dialog_expire;
420         api->get_branch_expire = tps_get_branch_expire;
421
422         return 0;
423 }