Coverage Report

Created: 2026-09-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/xlog.c
Line
Count
Source
1
/**
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips 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
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 */
20
21
#include <stdio.h>
22
#include <string.h>
23
#include <stdlib.h>
24
#include <sys/types.h>
25
#include <sys/ipc.h>
26
#include <unistd.h>
27
#include <fcntl.h>
28
#include <time.h>
29
#include <ctype.h>
30
31
#include "sr_module.h"
32
#include "dprint.h"
33
#include "error.h"
34
#include "socket_info.h"
35
#include "mem/mem.h"
36
#include "xlog.h"
37
38
#include "pvar.h"
39
#include "trace_api.h"
40
41
0
#define XLOG_TRACE_API_MODULE "proto_hep"
42
#define XLOG_CORRELATION_MAGIC "XLOGCORR"
43
44
45
46
char *log_buf = NULL;
47
48
int xlog_buf_size = 4096;
49
int xlog_force_color = 0;
50
51
/* the log level used when printing xlog messages */
52
int xlog_print_level = L_NOTICE;
53
54
/* the logging level/threshold for filtering the xlog messages for printing */
55
static int xlog_level_default = L_NOTICE;
56
static int xlog_level_local = L_NOTICE;
57
static int *xlog_level_shared = NULL;
58
59
/* current logging level for this process.
60
 * During init it points the 'xlog_level_default' in order to store the
61
 * original configured value
62
 * During runtime it may point to:
63
 *    - xlog_level_shared - the shared xlog level between all procs
64
 *    - &xlog_level_local - for a per-proc changed xlog level
65
 */
66
int *xlog_level = &xlog_level_default;
67
68
/* id with which xlog will be identified by siptrace module
69
 * and will identify an xlog tracing packet */
70
int xlog_proto_id;
71
/* tracing module api */
72
static trace_proto_t tprot;
73
74
/* xlog string identifier */
75
static const char* xlog_id_s="xlog";
76
77
#define is_xlog_printable(_level)  \
78
0
  (((int)(*xlog_level)) >= ((int)(_level)))
79
80
81
void set_shared_xlog_level(int new_level)
82
0
{
83
  /* do not accept setting as time the xlog_level still points to the
84
   * starting/default holder as we will loose the original value */
85
0
  if (xlog_level==&xlog_level_default)
86
0
    return;
87
88
0
  *xlog_level_shared = new_level;
89
0
}
90
91
92
void set_local_xlog_level(int new_level)
93
0
{
94
  /* do not accept setting as time the xlog_level still points to the
95
   * starting/default holder as we will loose the original value */
96
0
  if (xlog_level==&xlog_level_default)
97
0
    return;
98
99
0
  xlog_level_local = new_level;
100
0
  xlog_level = &xlog_level_local;
101
0
}
102
103
104
void reset_xlog_level(void)
105
0
{
106
0
  if (xlog_level==&xlog_level_default)
107
0
    return; /* still init, very unlikely */
108
109
0
  if (xlog_level==&xlog_level_local) {
110
    /* points a local/per-proc xlog level hodler,
111
     * so reset it to the shared value */
112
0
    xlog_level = xlog_level_shared;
113
0
    return;
114
0
  }
115
116
  /* points to the shared holder, so reset the shred value */
117
0
  *xlog_level_shared = xlog_level_default;
118
0
}
119
120
121
static int buf_init(void)
122
0
{
123
0
  LM_DBG("initializing...\n");
124
0
  log_buf = (char*)pkg_malloc((xlog_buf_size+1)*sizeof(char));
125
0
  if(log_buf==NULL)
126
0
  {
127
0
    LM_ERR("no pkg memory left\n");
128
0
    return -1;
129
0
  }
130
0
  return 0;
131
0
}
132
133
134
int init_xlog(void)
135
0
{
136
0
  if (log_buf == NULL) {
137
0
    if (buf_init()) {
138
0
      LM_ERR("Cannot print message!\n");
139
0
      return -1;
140
0
    }
141
0
  }
142
143
0
  xlog_level_shared = (int*)shm_malloc(sizeof(int));
144
0
  if (xlog_level_shared==NULL) {
145
0
    LM_ERR("failed to allocate shared holder for xlog\n");
146
0
    return -1;
147
0
  }
148
0
  xlog_level = xlog_level_shared;
149
0
  *xlog_level = xlog_level_default;
150
151
0
  if (register_trace_type)
152
0
    xlog_proto_id = register_trace_type((char *)xlog_id_s);
153
154
0
  memset(&tprot, 0, sizeof(trace_proto_t));
155
0
  if (global_trace_api) {
156
0
    memcpy(&tprot, global_trace_api, sizeof(trace_proto_t));
157
0
  } else {
158
0
    if (trace_prot_bind(XLOG_TRACE_API_MODULE, &tprot)) {
159
0
      LM_DBG("failed to load trace protocol!\n");
160
0
    }
161
0
  }
162
163
164
0
  return 0;
165
0
}
166
167
168
static inline void add_xlog_data(trace_message message, void* param)
169
0
{
170
0
  str str_level;
171
0
  xl_trace_t* xtrace_param = param;
172
0
  static str sip_str = str_init("sip");
173
174
175
0
  switch (*xlog_level) {
176
0
    case L_ALERT:
177
0
      str_level.s = DP_ALERT_STR;
178
0
      str_level.len = sizeof(DP_ALERT_STR) - 1;
179
0
      break;
180
0
    case L_CRIT:
181
0
      str_level.s = DP_CRIT_STR;
182
0
      str_level.len = sizeof(DP_CRIT_STR) - 1;
183
0
      break;
184
0
    case L_ERR:
185
0
    case 0: /* this is not used, but we have it here just to have
186
             * a continous range and simplify the "default" */
187
0
      str_level.s = DP_ERR_STR;
188
0
      str_level.len = sizeof(DP_ERR_STR) - 1;
189
0
      break;
190
0
    case L_WARN:
191
0
      str_level.s = DP_WARN_STR;
192
0
      str_level.len = sizeof(DP_WARN_STR) - 1;
193
0
      break;
194
0
    case L_NOTICE:
195
0
      str_level.s = DP_NOTICE_STR;
196
0
      str_level.len = sizeof(DP_NOTICE_STR) - 1;
197
0
      break;
198
0
    case L_INFO:
199
0
      str_level.s = DP_INFO_STR;
200
0
      str_level.len = sizeof(DP_INFO_STR) - 1;
201
0
      break;
202
0
    case L_DBG:
203
0
      str_level.s = DP_DBG_STR;
204
0
      str_level.len = sizeof(DP_DBG_STR) - 1;
205
0
      break;
206
0
    default:
207
0
      if (*xlog_level < L_ALERT) {
208
0
        str_level.s = DP_ALERT_STR;
209
0
        str_level.len = sizeof(DP_ALERT_STR) - 1;
210
0
      } else {
211
0
        str_level.s = DP_DBG_STR;
212
0
        str_level.len = sizeof(DP_DBG_STR) - 1;
213
0
      }
214
0
  }
215
216
0
  tprot.add_payload_part( message, "Event", &str_level);
217
218
0
  if ( !xtrace_param )
219
0
    return;
220
221
0
  tprot.add_payload_part( message, "text", &xtrace_param->buf);
222
223
0
  if (xtrace_param->msg && xtrace_param->msg->callid)
224
0
    tprot.add_extra_correlation( message, &sip_str, &xtrace_param->msg->callid->body );
225
0
}
226
227
static inline int trace_xlog(struct sip_msg* msg, char* buf, int len)
228
0
{
229
0
  struct modify_trace mod_p;
230
0
  xl_trace_t xtrace_param;
231
0
  str correlation_str;
232
0
  union sockaddr_union su;
233
234
0
  if (msg == NULL || buf == NULL) {
235
0
    LM_ERR("bad input!\n");
236
0
    return -1;
237
0
  }
238
239
  /* xlog not traced; exit... */
240
0
  if (!check_is_traced || check_is_traced(xlog_proto_id) == 0)
241
0
    return 0;
242
243
0
  mod_p.mod_f = add_xlog_data;
244
0
  xtrace_param.msg = msg;
245
246
0
  xtrace_param.buf.s = buf;
247
0
  xtrace_param.buf.len = len;
248
249
0
  mod_p.param = &xtrace_param;
250
251
0
  if (msg->callid && msg->callid->body.len) {
252
0
    correlation_str = msg->callid->body;
253
0
  } else {
254
0
    correlation_str.s = "<null>";
255
0
    correlation_str.len = 6;
256
0
  }
257
258
0
  if (msg->rcv.bind_address && msg->rcv.bind_address->port_no)
259
    /* coverity[check_return] - CID #211391 */
260
0
    init_su( &su, &msg->rcv.bind_address->address,
261
0
      msg->rcv.bind_address->port_no);
262
0
  else
263
0
    su.s.sa_family = 0;
264
265
0
  if (sip_context_trace(xlog_proto_id,
266
0
  su.s.sa_family ? &su : NULL /*src*/, su.s.sa_family ? &su : NULL /*dst*/,
267
0
  0, IPPROTO_TCP,
268
0
  &correlation_str, &mod_p) < 0) {
269
0
    LM_ERR("failed to trace xlog message!\n");
270
0
    return -1;
271
0
  }
272
273
0
  return 0;
274
0
}
275
276
int xl_print_log(struct sip_msg* msg, pv_elem_p list, int *len)
277
0
{
278
0
  if (pv_printf(msg, list, log_buf, len) < 0)
279
0
    return -1;
280
281
0
  if (trace_xlog(msg, log_buf, *len) < 0) {
282
0
    LM_ERR("failed to trace xlog message!\n");
283
0
    return -2;
284
0
  }
285
286
0
  return 1;
287
0
}
288
289
290
int xlog_2(struct sip_msg* msg, char* lev, char* frm)
291
0
{
292
0
  int log_len, ret;
293
0
  long level;
294
0
  xl_level_p xlp;
295
0
  pv_value_t value;
296
297
0
  xlp = (xl_level_t*)(void*)lev;
298
0
  if(xlp->type==1)
299
0
  {
300
0
    if(pv_get_spec_value(msg, &xlp->v.sp, &value)!=0
301
0
      || value.flags&PV_VAL_NULL || !(value.flags&PV_VAL_INT))
302
0
    {
303
0
      LM_ERR("invalid log level value [%d]\n", value.flags);
304
0
      return -1;
305
0
    }
306
0
    level = (long)value.ri;
307
0
  } else {
308
0
    level = xlp->v.level;
309
0
  }
310
311
0
  if(!is_xlog_printable((int)level))
312
0
    return 1;
313
314
0
  log_len = xlog_buf_size;
315
316
0
  ret = xl_print_log(msg, (pv_elem_t*)(void*)frm, &log_len);
317
0
  if (ret == -1) {
318
0
    LM_ERR("global print buffer too small, increase 'xlog_buf_size'\n");
319
0
    return -1;
320
0
  }
321
322
  /* set the xlog as log level to trick "LM_GEN" */
323
0
  set_proc_log_level( *xlog_level );
324
325
  /* log_buf[log_len] = '\0'; */
326
0
  LM_GEN1((int)level, "%.*s", log_len, log_buf);
327
328
0
  reset_proc_log_level();
329
330
0
  return ret;
331
0
}
332
333
334
int xlog_1(struct sip_msg* msg, char* frm)
335
0
{
336
0
  int log_len, ret;
337
338
0
  if(!is_xlog_printable(xlog_print_level))
339
0
    return 1;
340
341
0
  log_len = xlog_buf_size;
342
343
0
  ret = xl_print_log(msg, (pv_elem_t*)(void*)frm, &log_len);
344
0
  if (ret == -1) {
345
0
    LM_ERR("global print buffer too small, increase 'xlog_buf_size'\n");
346
0
    return -1;
347
0
  }
348
349
  /* set the xlog as log level to trick "LM_GEN" */
350
0
  set_proc_log_level( *xlog_level );
351
352
  /* log_buf[log_len] = '\0'; */
353
0
  LM_GEN1(xlog_print_level, "%.*s", log_len, log_buf);
354
355
0
  reset_proc_log_level();
356
357
0
  return ret;
358
0
}
359
360
/**
361
 */
362
int xdbg(struct sip_msg* msg, char* frm)
363
0
{
364
0
  int log_len, ret;
365
366
0
  if(!is_xlog_printable(L_DBG))
367
0
    return 1;
368
369
0
  log_len = xlog_buf_size;
370
371
0
  ret = xl_print_log(msg, (pv_elem_t*)(void*)frm, &log_len);
372
0
  if (ret == -1) {
373
0
    LM_ERR("global print buffer too small, increase 'xlog_buf_size'\n");
374
0
    return -1;
375
0
  }
376
377
  /* set the xlog as log level to trick "LM_GEN" */
378
0
  set_proc_log_level( *xlog_level );
379
380
  /* log_buf[log_len] = '\0'; */
381
0
  LM_GEN1(L_DBG, "%.*s", log_len, log_buf);
382
383
0
  reset_proc_log_level();
384
385
0
  return ret;
386
0
}
387
388
int pv_parse_color_name(pv_spec_p sp, const str *in)
389
0
{
390
391
0
  if(in==NULL || in->s==NULL || sp==NULL)
392
0
    return -1;
393
394
0
  if(in->len != 2)
395
0
  {
396
0
    LM_ERR("color name must have two chars\n");
397
0
    return -1;
398
0
  }
399
400
  /* foreground */
401
0
  switch(in->s[0])
402
0
  {
403
0
    case 'x':
404
0
    case 's': case 'r': case 'g':
405
0
    case 'y': case 'b': case 'p':
406
0
    case 'c': case 'w': case 'S':
407
0
    case 'R': case 'G': case 'Y':
408
0
    case 'B': case 'P': case 'C':
409
0
    case 'W':
410
0
    break;
411
0
    default:
412
0
      goto error;
413
0
  }
414
415
  /* background */
416
0
  switch(in->s[1])
417
0
  {
418
0
    case 'x':
419
0
    case 's': case 'r': case 'g':
420
0
    case 'y': case 'b': case 'p':
421
0
    case 'c': case 'w':
422
0
    break;
423
0
    default:
424
0
      goto error;
425
0
  }
426
427
0
  sp->pvp.pvn.type = PV_NAME_INTSTR;
428
0
  sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
429
0
  sp->pvp.pvn.u.isname.name.s = *in;
430
431
0
  sp->getf = pv_get_color;
432
433
  /* force the color PV type */
434
0
  sp->type = PVT_COLOR;
435
0
  return 0;
436
0
error:
437
0
  LM_ERR("invalid color name\n");
438
0
  return -1;
439
0
}
440
441
0
#define COL_BUF 10
442
443
#define append_sstring(p, end, s) \
444
0
        do{\
445
0
                if ((p)+(sizeof(s)-1)<=(end)){\
446
0
                        memcpy((p), s, sizeof(s)-1); \
447
0
                        (p)+=sizeof(s)-1; \
448
0
                }else{ \
449
0
                        /* overflow */ \
450
0
                        LM_ERR("append_sstring overflow\n"); \
451
0
                        goto error;\
452
0
                } \
453
0
        } while(0)
454
455
456
int pv_get_color(struct sip_msg *msg, pv_param_t *param,
457
    pv_value_t *res)
458
0
{
459
0
  static char color[COL_BUF];
460
0
  char* p;
461
0
  char* end;
462
0
  str s;
463
464
0
  if(xlog_force_color==0)
465
0
  {
466
0
    s.s = "";
467
0
    s.len = 0;
468
0
    return pv_get_strval(msg, param, res, &s);
469
0
  }
470
471
0
  p = color;
472
0
  end = p + COL_BUF;
473
474
  /* excape sequenz */
475
0
  append_sstring(p, end, "\033[");
476
477
0
  if(param->pvn.u.isname.name.s.s[0]!='_')
478
0
  {
479
0
    if (islower((int)param->pvn.u.isname.name.s.s[0]))
480
0
    {
481
      /* normal font */
482
0
      append_sstring(p, end, "0;");
483
0
    } else {
484
      /* bold font */
485
0
      append_sstring(p, end, "1;");
486
0
      param->pvn.u.isname.name.s.s[0] += 32;
487
0
    }
488
0
  }
489
490
  /* foreground */
491
0
  switch(param->pvn.u.isname.name.s.s[0])
492
0
  {
493
0
    case 'x':
494
0
      append_sstring(p, end, "39;");
495
0
    break;
496
0
    case 's':
497
0
      append_sstring(p, end, "30;");
498
0
    break;
499
0
    case 'r':
500
0
      append_sstring(p, end, "31;");
501
0
    break;
502
0
    case 'g':
503
0
      append_sstring(p, end, "32;");
504
0
    break;
505
0
    case 'y':
506
0
      append_sstring(p, end, "33;");
507
0
    break;
508
0
    case 'b':
509
0
      append_sstring(p, end, "34;");
510
0
    break;
511
0
    case 'p':
512
0
      append_sstring(p, end, "35;");
513
0
    break;
514
0
    case 'c':
515
0
      append_sstring(p, end, "36;");
516
0
    break;
517
0
    case 'w':
518
0
      append_sstring(p, end, "37;");
519
0
    break;
520
0
    default:
521
0
      LM_ERR("invalid foreground\n");
522
0
      return pv_get_null(msg, param, res);
523
0
  }
524
525
  /* background */
526
0
  switch(param->pvn.u.isname.name.s.s[1])
527
0
  {
528
0
    case 'x':
529
0
      append_sstring(p, end, "49");
530
0
    break;
531
0
    case 's':
532
0
      append_sstring(p, end, "40");
533
0
    break;
534
0
    case 'r':
535
0
      append_sstring(p, end, "41");
536
0
    break;
537
0
    case 'g':
538
0
      append_sstring(p, end, "42");
539
0
    break;
540
0
    case 'y':
541
0
      append_sstring(p, end, "43");
542
0
    break;
543
0
    case 'b':
544
0
      append_sstring(p, end, "44");
545
0
    break;
546
0
    case 'p':
547
0
      append_sstring(p, end, "45");
548
0
    break;
549
0
    case 'c':
550
0
      append_sstring(p, end, "46");
551
0
    break;
552
0
    case 'w':
553
0
      append_sstring(p, end, "47");
554
0
    break;
555
0
    default:
556
0
      LM_ERR("invalid background\n");
557
0
      return pv_get_null(msg, param, res);
558
0
  }
559
560
  /* end */
561
0
  append_sstring(p, end, "m");
562
563
0
  s.s = color;
564
0
  s.len = p-color;
565
0
  return pv_get_strval(msg, param, res, &s);
566
567
0
error:
568
0
  return -1;
569
0
}
570