76da385c0dca0067fb479cc75928b3d1301dd5c3
[sip-router] / src / modules / debugger / debugger_mod.c
1 /**
2  * Copyright (C) 2010 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 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "../cfgt/cfgt.h"
29 #include "../../core/sr_module.h"
30 #include "../../core/dprint.h"
31 #include "../../core/ut.h"
32 #include "../../core/mod_fix.h"
33 #include "../../core/parser/parse_param.h"
34 #include "../../core/shm_init.h"
35 #include "../../core/script_cb.h"
36 #include "../../core/msg_translator.h"
37 #include "../../core/kemi.h"
38
39 #include "debugger_api.h"
40 #include "debugger_config.h"
41 #include "debugger_json.h"
42
43 MODULE_VERSION
44
45 static int mod_init(void);
46 static int child_init(int rank);
47 static void mod_destroy(void);
48
49 static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2);
50 static int fixup_dbg_breakpoint(void** param, int param_no);
51 static int dbg_mod_level_param(modparam_t type, void *val);
52 static int dbg_mod_facility_param(modparam_t type, void *val);
53
54 static int fixup_dbg_pv_dump(void** param, int param_no);
55 static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level);
56
57 static struct action *dbg_fixup_get_action(void **param, int param_no);
58 static int fixup_dbg_sip_msg(void** param, int param_no);
59 static int w_dbg_sip_msg(struct sip_msg* msg, char *level, char *facility);
60
61 extern char* dump_lump_list(struct lump *list, int s_offset, char *s_buf);
62
63 /* parameters */
64 extern int _dbg_cfgtrace;
65 extern int _dbg_cfgpkgcheck;
66 extern int _dbg_breakpoint;
67 extern int _dbg_cfgtrace_level;
68 extern int _dbg_cfgtrace_facility;
69 extern char *_dbg_cfgtrace_prefix;
70 extern char *_dbg_cfgtrace_lname;
71 extern int _dbg_step_usleep;
72 extern int _dbg_step_loops;
73 extern int _dbg_reset_msgid;
74 extern int _dbg_cfgtest;
75
76 /* cfgt api */
77 extern cfgt_api_t _dbg_cfgt;
78
79 static int _dbg_sip_msg_cline;
80 static char * _dbg_cfgtrace_facility_str = 0;
81 static int _dbg_log_assign = 0;
82
83 static cmd_export_t cmds[]={
84         {"dbg_breakpoint", (cmd_function)w_dbg_breakpoint, 1,
85                 fixup_dbg_breakpoint, 0, ANY_ROUTE},
86         {"dbg_pv_dump", (cmd_function)w_dbg_dump, 0,
87                 fixup_dbg_pv_dump, 0, ANY_ROUTE},
88         {"dbg_pv_dump", (cmd_function)w_dbg_dump, 1,
89                 fixup_dbg_pv_dump, 0, ANY_ROUTE},
90         {"dbg_pv_dump", (cmd_function)w_dbg_dump, 2,
91                 fixup_dbg_pv_dump, 0, ANY_ROUTE},
92         {"dbg_sip_msg", (cmd_function)w_dbg_sip_msg, 0,
93                 fixup_dbg_sip_msg, 0, REQUEST_ROUTE|ONREPLY_ROUTE},
94         {"dbg_sip_msg", (cmd_function)w_dbg_sip_msg, 1,
95                 fixup_dbg_sip_msg, 0, REQUEST_ROUTE|ONREPLY_ROUTE},
96         {"dbg_sip_msg", (cmd_function)w_dbg_sip_msg, 2,
97                 fixup_dbg_sip_msg, 0, REQUEST_ROUTE|ONREPLY_ROUTE},
98         {0, 0, 0, 0, 0, 0}
99 };
100
101 static param_export_t params[]={
102         {"cfgtrace",          INT_PARAM, &_dbg_cfgtrace},
103         {"breakpoint",        INT_PARAM, &_dbg_breakpoint},
104         {"log_level",         INT_PARAM, &_dbg_cfgtrace_level},
105         {"log_facility",      PARAM_STRING, &_dbg_cfgtrace_facility_str},
106         {"log_prefix",        PARAM_STRING, &_dbg_cfgtrace_prefix},
107         {"log_level_name",    PARAM_STRING, &_dbg_cfgtrace_lname},
108         {"log_assign",        INT_PARAM, &_dbg_log_assign},
109         {"step_usleep",       INT_PARAM, &_dbg_step_usleep},
110         {"step_loops",        INT_PARAM, &_dbg_step_loops},
111         {"mod_hash_size",     INT_PARAM, &default_dbg_cfg.mod_hash_size},
112         {"mod_level_mode",    INT_PARAM, &default_dbg_cfg.mod_level_mode},
113         {"mod_level",         PARAM_STRING|USE_FUNC_PARAM, (void*)dbg_mod_level_param},
114         {"mod_facility_mode", INT_PARAM, &default_dbg_cfg.mod_facility_mode},
115         {"mod_facility",      PARAM_STRING|USE_FUNC_PARAM, (void*)dbg_mod_facility_param},
116         {"reset_msgid",       INT_PARAM, &_dbg_reset_msgid},
117         {"cfgpkgcheck",       INT_PARAM, &_dbg_cfgpkgcheck},
118         {"cfgtest",           INT_PARAM, &_dbg_cfgtest},
119         {0, 0, 0}
120 };
121
122 struct module_exports exports = {
123         "debugger",
124         DEFAULT_DLFLAGS, /* dlopen flags */
125         cmds,
126         params,
127         0,
128         0,              /* exported MI functions */
129         0,              /* exported pseudo-variables */
130         0,              /* extra processes */
131         mod_init,       /* module initialization function */
132         0,              /* response function */
133         mod_destroy,    /* destroy function */
134         child_init      /* per child init function */
135 };
136
137
138 /**
139  * init module function
140  */
141 static int mod_init(void)
142 {
143         int fl;
144         bind_cfgt_t bind_cfgt;
145
146         if (_dbg_cfgtrace_facility_str!=NULL)
147         {
148                 fl = str2facility(_dbg_cfgtrace_facility_str);
149                 if (fl != -1)
150                 {
151                         _dbg_cfgtrace_facility = fl;
152                 } else {
153                         LM_ERR("invalid log facility configured");
154                         return -1;
155                 }
156         }
157
158         if(dbg_init_rpc()!=0)
159         {
160                 LM_ERR("failed to register RPC commands\n");
161                 return -1;
162         }
163
164         if(cfg_declare("dbg", dbg_cfg_def, &default_dbg_cfg, cfg_sizeof(dbg), &dbg_cfg))
165         {
166                 LM_ERR("Fail to declare the configuration\n");
167                 return -1;
168         }
169
170         /* anyhow, should fail before */
171         if (!dbg_cfg) {
172                 return -1;
173         }
174
175         LM_DBG("cfg level_mode:%d facility_mode:%d hash_size:%d\n",
176                 cfg_get(dbg, dbg_cfg, mod_level_mode),
177                 cfg_get(dbg, dbg_cfg, mod_facility_mode),
178                 cfg_get(dbg, dbg_cfg, mod_hash_size));
179
180         if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0)
181         {
182                 LM_ERR("failed to init per module log level\n");
183                 return -1;
184         }
185
186         if(_dbg_log_assign>0)
187         {
188                 if(dbg_init_pvcache()!=0)
189                 {
190                         LM_ERR("failed to create pvcache\n");
191                         return -1;
192                 }
193         }
194         if(_dbg_reset_msgid==1)
195         {
196                 unsigned int ALL = REQUEST_CB+FAILURE_CB+ONREPLY_CB
197                   +BRANCH_CB+ONSEND_CB+ERROR_CB+LOCAL_CB+EVENT_CB+BRANCH_FAILURE_CB;
198                 if (register_script_cb(dbg_msgid_filter, PRE_SCRIPT_CB|ALL, 0) != 0) {
199                         LM_ERR("could not insert callback");
200                         return -1;
201                 }
202         }
203         if(_dbg_cfgtest==1)
204         {
205                 bind_cfgt = (bind_cfgt_t)find_export("cfgt_bind_cfgt", 1, 0);
206                 if (!bind_cfgt) {
207                         LM_ERR("can't find cfgt module\n");
208                         return -1;
209                 }
210
211                 if (bind_cfgt(&_dbg_cfgt) < 0) {
212                         return -1;
213                 }
214                 LM_INFO("bind to cfgt module\n");
215         }
216         return dbg_init_bp_list();
217 }
218
219 /**
220  * child init function
221  */
222 static int child_init(int rank)
223 {
224         LM_DBG("rank is (%d)\n", rank);
225         if (rank==PROC_INIT) {
226                 dbg_enable_mod_levels();
227                 dbg_enable_mod_facilities();
228                 dbg_enable_log_assign();
229                 return dbg_init_pid_list();
230         }
231         return dbg_init_mypid();
232 }
233
234 /**
235  * destroy module function
236  */
237 static void mod_destroy(void)
238 {
239         dbg_cfg = NULL;
240         dbg_destroy_mod_levels();
241 }
242
243 /**
244  * cfg wrapper to set breakpoint (not implemented yet)
245  */
246 static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2)
247 {
248         return 1;
249 }
250
251 /**
252  * fixup for cfg dbg_pv_dump
253  */
254 static int fixup_dbg_pv_dump(void** param, int param_no)
255 {
256         unsigned int mask;
257         int level;
258         str s = STR_NULL;
259
260         switch(param_no)
261         {
262                 case 2:
263                         switch(((char*)(*param))[2])
264                         {
265                                 case 'A': level = L_ALERT; break;
266                                 case 'B': level = L_BUG; break;
267                                 case 'C': level = L_CRIT2; break;
268                                 case 'E': level = L_ERR; break;
269                                 case 'W': level = L_WARN; break;
270                                 case 'N': level = L_NOTICE; break;
271                                 case 'I': level = L_INFO; break;
272                                 case 'D': level = L_DBG; break;
273                                 default:
274                                         LM_ERR("unknown log level\n");
275                                         return E_UNSPEC;
276                         }
277                         *param = (void*)(long)level;
278                 break;
279                 case 1:
280                         s.s = *param;
281                         s.len = strlen(s.s);
282                         if(str2int(&s, &mask) == 0) {
283                                 *param = (void*)(long)mask;
284                         }
285                         else return E_UNSPEC;
286                 break;
287         }
288
289         return 0;
290 }
291
292 /**
293  * dump pv_cache contents as json
294  */
295 static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level)
296 {
297         unsigned int umask = DBG_DP_ALL;
298         int ilevel = L_DBG;
299         if(level!=NULL){
300                 ilevel = (int)(long)level;
301         }
302         if(mask!=NULL){
303                 umask = (unsigned int)(unsigned long)mask;
304         }
305         dbg_dump_json(msg, umask, ilevel);
306         return 1;
307 }
308
309 /**
310  * get the pointer to action structure
311  */
312 static struct action *dbg_fixup_get_action(void **param, int param_no)
313 {
314         struct action *ac, ac2;
315         action_u_t *au, au2;
316         /* param points to au->u.string, get pointer to au */
317         au = (void*) ((char *)param - ((char *)&au2.u.string-(char *)&au2));
318         au = au - 1 - param_no;
319         ac = (void*) ((char *)au - ((char *)&ac2.val-(char *)&ac2));
320         return ac;
321 }
322
323
324 /**
325  * fixup for cfg set breakpoint function
326  */
327 static int fixup_dbg_breakpoint(void** param, int param_no)
328 {
329         struct action *a;
330         char *p;
331
332         if(param_no!=1)
333                 return -1;
334         a = dbg_fixup_get_action(param, param_no);
335         p = (char*)(*param);
336
337         return dbg_add_breakpoint(a, (*p=='0')?0:1);
338 }
339
340 static int dbg_mod_level_param(modparam_t type, void *val)
341 {
342         char *p;
343         str s;
344         int l;
345         if(val==NULL)
346                 return -1;
347
348         p = strchr((char*)val, '=');
349         if(p==NULL) {
350                 LM_ERR("invalid parameter value: %s\n", (char*)val);
351                 return -1;
352         }
353         s.s = p + 1;
354         s.len = strlen(s.s);
355
356         if(str2sint(&s, &l)<0) {
357                 LM_ERR("invalid parameter - level value: %s\n", (char*)val);
358                 return -1;
359         }
360         s.s = (char*)val;
361         s.len = p - s.s;
362
363         if (!dbg_cfg) {
364                 return -1;
365         }
366
367         LM_DBG("cfg level_mode:%d hash_size:%d\n",
368                 cfg_get(dbg, dbg_cfg, mod_level_mode),
369                 cfg_get(dbg, dbg_cfg, mod_hash_size));
370
371         if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0)
372         {
373                 LM_ERR("failed to init per module log level\n");
374                 return -1;
375         }
376
377         if(dbg_set_mod_debug_level(s.s, s.len, &l)<0)
378         {
379                 LM_ERR("cannot store parameter: %s\n", (char*)val);
380                 return -1;
381         }
382
383         return 0;
384
385 }
386
387 static int dbg_mod_facility_param(modparam_t type, void *val)
388 {
389         char *p;
390         str s;
391         int fl;
392         if(val==NULL)
393                 return -1;
394
395         p = strchr((char*)val, '=');
396         if(p==NULL) {
397                 LM_ERR("invalid parameter value: %s\n", (char*)val);
398                 return -1;
399         }
400         s.s = p + 1;
401         s.len = strlen(s.s);
402
403         if ((fl = str2facility(s.s)) == -1) {
404                 LM_ERR("invalid parameter - facility value: %s\n", (char*)val);
405                 return -1;
406         }
407
408         s.s = (char*)val;
409         s.len = p - s.s;
410
411         if (!dbg_cfg) {
412                 return -1;
413         }
414
415         LM_DBG("cfg facility_mode:%d hash_size:%d\n",
416                 cfg_get(dbg, dbg_cfg, mod_facility_mode),
417                 cfg_get(dbg, dbg_cfg, mod_hash_size));
418
419         if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0)
420         {
421                 LM_ERR("failed to init per module log level\n");
422                 return -1;
423         }
424
425         if(dbg_set_mod_debug_facility(s.s, s.len, &fl)<0)
426         {
427                 LM_ERR("cannot store parameter: %s\n", (char*)val);
428                 return -1;
429         }
430
431         return 0;
432 }
433
434 static int fixup_dbg_sip_msg(void** param, int param_no)
435 {
436         int facility;
437         int level;
438         struct action *dbg_sip_msg_action;
439
440         LM_DBG("dbg_sip_msg() called with %d params\n", param_no);
441
442         switch(param_no)
443         {
444                 case 2:
445                         facility = str2facility((char*)*(param));
446                         if (facility == -1) {
447                                 LM_ERR("invalid log facility configured");
448                                 return E_UNSPEC;
449                         }
450
451                         *param = (void*)(long)facility;
452                         break;
453
454                 case 1:
455                         switch(((char*)(*param))[2])
456                         {
457                                 /* add L_OFFSET because L_WARN is consdered null pointer */
458                                 case 'A': level = L_ALERT + L_OFFSET; break;
459                                 case 'B': level = L_BUG + L_OFFSET; break;
460                                 case 'C': level = L_CRIT2 + L_OFFSET; break;
461                                 case 'E': level = L_ERR + L_OFFSET; break;
462                                 case 'W': level = L_WARN + L_OFFSET; break;
463                                 case 'N': level = L_NOTICE + L_OFFSET; break;
464                                 case 'I': level = L_INFO + L_OFFSET; break;
465                                 case 'D': level = L_DBG + L_OFFSET; break;
466                                 default:
467                                         LM_ERR("unknown log level\n");
468                                         return E_UNSPEC;
469                         }
470
471                         *param = (void*)(long)level;
472                         break;
473
474                 case 0:
475                         _dbg_sip_msg_cline = -1;
476                         return 0;
477
478                 default:
479                         // should not reach here
480                         _dbg_sip_msg_cline = -1;
481                         return -1;
482         }
483
484         /* save the config line where this config function was called */
485         dbg_sip_msg_action = dbg_fixup_get_action(param, param_no);
486         _dbg_sip_msg_cline = dbg_sip_msg_action->cline;
487
488         return 0;
489 }
490
491 /**
492   * dump current SIP message and a diff lump list
493   * part of the code taken from msg_apply_changes_f
494   */
495 static int w_dbg_sip_msg(struct sip_msg* msg, char *level, char *facility)
496 {
497         int ilevel = cfg_get(core, core_cfg, debug);
498         int ifacility= cfg_get(core, core_cfg, log_facility);
499         int flag = FLAG_MSG_LUMPS_ONLY; // copy lumps only, not the whole message
500         unsigned int new_buf_offs=0, orig_offs = 0;
501         char *hdr_lumps = NULL;
502         char *bdy_lumps = NULL;
503         const char *start_txt = "------------------------- START OF SIP message debug --------------------------\n";
504         const char *hdr_txt =   "------------------------------ SIP header diffs -------------------------------\n";
505         const char *bdy_txt =   "------------------------------- SIP body diffs --------------------------------\n";
506         const char *end_txt =   "-------------------------- END OF SIP message debug ---------------------------\n\n";
507         struct dest_info send_info;
508         str obuf;
509
510         if (msg->first_line.type != SIP_REPLY && get_route_type() != REQUEST_ROUTE) {
511                 LM_ERR("invalid usage - not in request route\n");
512                 return -1;
513         }
514
515         if (level != NULL) {
516                 /* substract L_OFFSET previously added */
517                 ilevel = (int)(long)level - L_OFFSET;
518         }
519
520         if (facility != NULL) {
521                 ifacility = (int)(long)facility;
522         }
523
524         /* msg_apply_changes_f code needed to get the current msg */
525         init_dest_info(&send_info);
526         send_info.proto = PROTO_UDP;
527         if(msg->first_line.type == SIP_REPLY) {
528                 obuf.s = generate_res_buf_from_sip_res(msg,
529                                 (unsigned int*)&obuf.len, BUILD_NO_VIA1_UPDATE);
530         } else {
531                 obuf.s = build_req_buf_from_sip_req(msg,
532                                 (unsigned int*)&obuf.len, &send_info,
533                                 BUILD_NO_PATH|BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
534         }
535
536         if(obuf.s == NULL)
537         {
538                 LM_ERR("couldn't update msg buffer content\n");
539                 return -1;
540         }
541
542         if(obuf.len >= BUF_SIZE)
543         {
544                 LM_ERR("new buffer overflow (%d)\n", obuf.len);
545                 pkg_free(obuf.s);
546                 return -1;
547         }
548
549         /* skip original uri */
550         if(msg->first_line.type == SIP_REQUEST) {
551                 if(msg->new_uri.s) {
552                         orig_offs = msg->first_line.u.request.uri.s - msg->buf;
553                         orig_offs += msg->first_line.u.request.uri.len;
554                 }
555         }
556
557         /* alloc private mem and copy lumps */
558         hdr_lumps = pkg_malloc(BUF_SIZE);
559         bdy_lumps = pkg_malloc(BUF_SIZE);
560
561         new_buf_offs = 0;
562         process_lumps(msg, msg->add_rm, hdr_lumps, &new_buf_offs, &orig_offs, &send_info, flag);
563
564         new_buf_offs = 0;
565         process_lumps(msg, msg->body_lumps, bdy_lumps, &new_buf_offs, &orig_offs, &send_info, flag);
566
567         /* do the print */
568         if (_dbg_sip_msg_cline < 0 ) {
569                 LOG_FC(ifacility, ilevel, "CONFIG LINE unknown\n%s%.*s%s%s%s%s%s",
570                         start_txt,
571                         obuf.len, obuf.s,
572                         hdr_txt, hdr_lumps,
573                         bdy_txt, bdy_lumps,
574                         end_txt);
575         } else {
576                 LOG_FC(ifacility, ilevel, "CONFIG LINE %d\n%s%.*s%s%s%s%s%s",
577                         _dbg_sip_msg_cline,
578                         start_txt,
579                         obuf.len, obuf.s,
580                         hdr_txt, hdr_lumps,
581                         bdy_txt, bdy_lumps,
582                         end_txt);
583         }
584
585         /* free lumps */
586         if (hdr_lumps) {
587                 pkg_free(hdr_lumps);
588         }
589
590         if (bdy_lumps) {
591                 pkg_free(bdy_lumps);
592         }
593
594         return 1;
595 }
596
597 /**
598  * dump pv_cache contents as json with default parameters
599  */
600 static int ki_dbg_pv_dump(sip_msg_t* msg)
601 {
602         dbg_dump_json(msg, DBG_DP_ALL, L_DBG);
603         return 1;
604 }
605
606 /**
607  * dump pv_cache contents as json with explicit parameters
608  */
609 static int ki_dbg_pv_dump_ex(sip_msg_t* msg, int mask, int level)
610 {
611         dbg_dump_json(msg, (unsigned int)mask, level);
612         return 1;
613 }
614
615 /**
616  *
617  */
618 /* clang-format off */
619 static sr_kemi_t sr_kemi_debugger_exports[] = {
620         { str_init("debugger"), str_init("dbg_pv_dump"),
621                 SR_KEMIP_INT, ki_dbg_pv_dump,
622                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
623                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
624         },
625         { str_init("debugger"), str_init("dbg_pv_dump_ex"),
626                 SR_KEMIP_INT, ki_dbg_pv_dump_ex,
627                 { SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
628                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
629         },
630
631         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
632 };
633 /* clang-format on */
634
635 /**
636  *
637  */
638 int mod_register(char *path, int *dlflags, void *p1, void *p2)
639 {
640         sr_kemi_modules_add(sr_kemi_debugger_exports);
641         return 0;
642 }