src/modules/siptrace/siptrace.c
0e86b73a
 /*
c0c67b7e
  * siptrace module - helper module to trace sip messages
  *
  * Copyright (C) 2006 Voice Sistem S.R.L.
de9ef971
  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
c0c67b7e
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
c0c67b7e
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
c0c67b7e
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
c0c67b7e
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
0e86b73a
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
c0c67b7e
  *
  */
 
eae8e7c1
 /*! \file
  * siptrace module - helper module to trace sip messages
  *
  */
 
c0c67b7e
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
cf83221d
 #include "../../core/sr_module.h"
ca276bb7
 #include "../../core/mod_fix.h"
cf83221d
 #include "../../core/dprint.h"
 #include "../../core/ut.h"
 #include "../../core/ip_addr.h"
 #include "../../core/mem/mem.h"
 #include "../../core/mem/shm_mem.h"
 #include "../../core/rpc.h"
 #include "../../core/rpc_lookup.h"
db0126bc
 #include "../../lib/srdb1/db.h"
cf83221d
 #include "../../core/parser/parse_content.h"
 #include "../../core/parser/parse_from.h"
 #include "../../core/parser/parse_cseq.h"
 #include "../../core/pvar.h"
eb38b3df
 #include "../../modules/tm/tm_load.h"
7a7ee280
 #include "../../modules/sl/sl.h"
fa7eb2ab
 #include "../../modules/dialog/dlg_load.h"
cf83221d
 #include "../../core/str.h"
 #include "../../core/onsend.h"
 #include "../../core/events.h"
5addc451
 #include "../../core/kemi.h"
c0c67b7e
 
0504bf23
 #include "siptrace_data.h"
 #include "siptrace_hep.h"
 #include "siptrace_send.h"
94393b2d
 
c0c67b7e
 MODULE_VERSION
 
1109fcfb
 #define SIPTRACE_MODE_NONE 0
 #define SIPTRACE_MODE_HEP (1)
 #define SIPTRACE_MODE_DB  (1<<1)
 #define SIPTRACE_MODE_URI (1<<2)
 
2ae4d19a
 #define SIPTRACE_ANYADDR "any:255.255.255.255:5060"
 #define SIPTRACE_ANYADDR_LEN (sizeof(SIPTRACE_ANYADDR) - 1)
94393b2d
 
2482f95e
 #define trace_is_off(_msg) \
0edff017
 		(((_msg)->msg_flags & FL_SIPTRACE) == 0)
608145da
 
65778f9e
 #define is_null_pv(_str) \
3619432d
 	(!str_strcmp(&_str, pv_get_null_str()))
65778f9e
 
c0c67b7e
 struct tm_binds tmb;
fa7eb2ab
 struct dlg_binds dlgb;
c0c67b7e
 
7a7ee280
 /** SL API structure */
 sl_api_t slb;
 
c0c67b7e
 /* module function prototypes */
 static int mod_init(void);
9b1c2348
 static int siptrace_init_rpc(void);
c0c67b7e
 static int child_init(int rank);
 static void destroy(void);
fa7eb2ab
 static int sip_trace(sip_msg_t *msg, dest_info_t *, str *, char *);
5addc451
 static int w_sip_trace0(struct sip_msg *, char *p1, char *p2);
e8d76561
 static int w_sip_trace1(struct sip_msg *, char *dest, char *p2);
5addc451
 static int w_sip_trace2(struct sip_msg *, char *dest, char *correlation_id);
fa7eb2ab
 static int w_sip_trace3(struct sip_msg *, char *dest, char *correlation_id, char *trace_type);
0504bf23
 static int fixup_siptrace(void **param, int param_no);
7c98d547
 static int fixup_free_siptrace(void **param, int param_no);
929ff145
 static int w_sip_trace_mode(sip_msg_t *msg, char *pmode, char *p2);
f6396033
 
2482f95e
 static int siptrace_parse_uri(str* duri, dest_info_t* dst);
 static enum siptrace_type_t siptrace_parse_flag(str* sflags);
fa7eb2ab
 
0504bf23
 static int w_hlog1(struct sip_msg *, char *message, char *);
 static int w_hlog2(struct sip_msg *, char *correlationid, char *message);
f6396033
 
f9b98c64
 static int sip_trace_store_db(siptrace_data_t *sto);
c0c67b7e
 
0504bf23
 static void trace_onreq_out(struct cell *t, int type, struct tmcb_params *ps);
e28f4644
 static void trace_cancel_in(struct cell *t, int type, struct tmcb_params *ps);
0504bf23
 static void trace_onreply_in(struct cell *t, int type, struct tmcb_params *ps);
 static void trace_onreply_out(struct cell *t, int type, struct tmcb_params *ps);
1b319682
 static void trace_tm_neg_ack_in(struct cell *t, int type, struct tmcb_params *ps);
7a7ee280
 static void trace_sl_onreply_out(sl_cbp_t *slcb);
 static void trace_sl_ack_in(sl_cbp_t *slcb);
5a2652fd
 
fa7eb2ab
 
796a12d6
 static void trace_transaction(sip_msg_t* msg, siptrace_info_t* info, int dlg_tran);
fa7eb2ab
 static void trace_dialog(struct dlg_cell* dlg, int type, struct dlg_cb_params *params);
 static void trace_dialog_transaction(struct dlg_cell* dlg, int type, struct dlg_cb_params *params);
2482f95e
 static void trace_free_info(void* trace_info);
 static int  trace_add_info_xavp(siptrace_info_t* info);
 static inline int trace_parse_raw_uri(siptrace_info_t* info);
fa7eb2ab
 
fa162f9b
 int siptrace_net_data_recv(sr_event_param_t *evp);
e1570a11
 int siptrace_net_data_sent(sr_event_param_t *evp);
42c7c7a1
 
 #define SIPTRACE_INIT_MODE_ALL 0
 #define SIPTRACE_INIT_MODE_CORECB 1
 #define SIPTRACE_INIT_MODE_SCRIPT 2
 
 static int _siptrace_init_mode = 0;
1771f7e4
 static int _siptrace_mode = 0;
 
72778ab8
 
0504bf23
 static str db_url = str_init(DEFAULT_DB_URL);
 static str siptrace_table = str_init("sip_trace");
 static str date_column = str_init("time_stamp");		 /* 00 */
 static str callid_column = str_init("callid");			 /* 01 */
e2cf6343
 static str traced_user_column = str_init("traced_user"); /* 02 */
0504bf23
 static str msg_column = str_init("msg");				 /* 03 */
 static str method_column = str_init("method");			 /* 04 */
 static str status_column = str_init("status");			 /* 05 */
 static str fromip_column = str_init("fromip");			 /* 06 */
 static str toip_column = str_init("toip");				 /* 07 */
 static str fromtag_column = str_init("fromtag");		 /* 08 */
 static str direction_column = str_init("direction");	 /* 09 */
 static str time_us_column = str_init("time_us");		 /* 10 */
 static str totag_column = str_init("totag");			 /* 11 */
c0c67b7e
 
2482f95e
 #define TRACE_XAVP_INFO_NAME "trace_info"
 static str trace_xavp_info_name_s = str_init(TRACE_XAVP_INFO_NAME);
fa7eb2ab
 
e88c9602
 #define NR_KEYS 12
 #define SIP_TRACE_TABLE_VERSION 4
c0c67b7e
 
be04fb6e
 int trace_flag_param = -1;
83758719
 int trace_flag = 0;
 
0504bf23
 int trace_on = 0;
43207442
 int *trace_on_flag = NULL;
 
f2ce69bf
 int trace_sl_acks = 1;
c0c67b7e
 
0314f73b
 int trace_to_database = 1;
e3a298e3
 int trace_db_delayed = 0;
 int trace_db_mode = 0;
0314f73b
 
2482f95e
 int hep_mode_on = 0;
dd7028a1
 int hep_version = 1;
 int hep_capture_id = 1;
ca276bb7
 int hep_vendor_id = 0;
2482f95e
 str hep_auth_key_str = {0, 0};
dd7028a1
 
8de85574
 int trace_xheaders_write = 0;
 int trace_xheaders_read = 0;
48ebf543
 
2482f95e
 str trace_send_sock_str = {0, 0};
e0109d54
 str trace_send_sock_name_str = {0, 0};
2482f95e
 sip_uri_t *trace_send_sock_uri = 0;
1f524060
 socket_info_t *trace_send_sock_info = 0;
651fd496
 
2482f95e
 str trace_dup_uri_str = {0, 0};
 sip_uri_t *trace_dup_uri = 0;
c0c67b7e
 
f39eca3d
 static str _siptrace_evcb_msg = STR_NULL;
 static int _siptrace_evrt_msg_idx = -1;
 
e2cf6343
 static unsigned short traced_user_avp_type = 0;
90691771
 static int_str traced_user_avp;
e2cf6343
 static str traced_user_avp_str = {NULL, 0};
90691771
 
e2cf6343
 static unsigned short trace_table_avp_type = 0;
90691771
 static int_str trace_table_avp;
e2cf6343
 static str trace_table_avp_str = {NULL, 0};
90691771
 
e2cf6343
 static str trace_local_ip = {NULL, 0};
c0c67b7e
 
2482f95e
 static db1_con_t *db_con = NULL; /*!< database connection */
 static db_func_t db_funcs;		  /*!< Database functions */
c0c67b7e
 
eae8e7c1
 /*! \brief
c0c67b7e
  * Exported functions
  */
43207442
 /* clang-format off */
c0c67b7e
 static cmd_export_t cmds[] = {
5addc451
 	{"sip_trace", (cmd_function)w_sip_trace0, 0, 0, 0,
0504bf23
 		ANY_ROUTE},
5addc451
 	{"sip_trace", (cmd_function)w_sip_trace1, 1, fixup_siptrace, 0,
0504bf23
 		ANY_ROUTE},
7c98d547
 	{"sip_trace", (cmd_function)w_sip_trace2, 2, fixup_siptrace, fixup_free_siptrace,
fa7eb2ab
 		ANY_ROUTE},
7c98d547
 	{"sip_trace", (cmd_function)w_sip_trace3, 3, fixup_siptrace, fixup_free_siptrace,
0504bf23
 		ANY_ROUTE},
 	{"hlog", (cmd_function)w_hlog1, 1, fixup_spve_null, 0,
 		ANY_ROUTE},
 	{"hlog", (cmd_function)w_hlog2, 2, fixup_spve_spve, 0,
 		ANY_ROUTE},
929ff145
 	{"sip_trace_mode", (cmd_function)w_sip_trace_mode, 1, fixup_spve_null,
 		fixup_free_spve_null, ANY_ROUTE},
80998a7f
 	{0, 0, 0, 0, 0, 0}
c0c67b7e
 };
43207442
 /* clang-format on */
c0c67b7e
 
 
eae8e7c1
 /*! \brief
c0c67b7e
  * Exported parameters
  */
43207442
 /* clang-format off */
c0c67b7e
 static param_export_t params[] = {
2482f95e
 	{"auth_key", PARAM_STR, &hep_auth_key_str},
711eeeb1
 	{"db_url", PARAM_STR, &db_url},
 	{"table", PARAM_STR, &siptrace_table},
0504bf23
 	{"date_column", PARAM_STR, &date_column},
 	{"callid_column", PARAM_STR, &callid_column},
 	{"traced_user_column", PARAM_STR, &traced_user_column},
 	{"msg_column", PARAM_STR, &msg_column},
 	{"method_column", PARAM_STR, &method_column},
 	{"status_column", PARAM_STR, &status_column},
 	{"fromip_column", PARAM_STR, &fromip_column},
 	{"toip_column", PARAM_STR, &toip_column},
 	{"fromtag_column", PARAM_STR, &fromtag_column},
 	{"totag_column", PARAM_STR, &totag_column},
 	{"direction_column", PARAM_STR, &direction_column},
be04fb6e
 	{"trace_flag", INT_PARAM, &trace_flag_param},
0504bf23
 	{"trace_on", INT_PARAM, &trace_on},
 	{"traced_user_avp", PARAM_STR, &traced_user_avp_str},
 	{"trace_table_avp", PARAM_STR, &trace_table_avp_str},
2482f95e
 	{"duplicate_uri", PARAM_STR, &trace_dup_uri_str},
0504bf23
 	{"trace_to_database", INT_PARAM, &trace_to_database},
 	{"trace_local_ip", PARAM_STR, &trace_local_ip},
 	{"trace_sl_acks", INT_PARAM, &trace_sl_acks},
8de85574
 	{"xheaders_write", INT_PARAM, &trace_xheaders_write},
 	{"xheaders_read", INT_PARAM, &trace_xheaders_read},
0504bf23
 	{"hep_mode_on", INT_PARAM, &hep_mode_on},
2482f95e
 	{"force_send_sock", PARAM_STR, &trace_send_sock_str},
e0109d54
 	{"send_sock_addr", PARAM_STR, &trace_send_sock_str},
 	{"send_sock_name", PARAM_STR, &trace_send_sock_name_str},
0504bf23
 	{"hep_version", INT_PARAM, &hep_version},
 	{"hep_capture_id", INT_PARAM, &hep_capture_id},
e3a298e3
 	{"trace_delayed", INT_PARAM, &trace_db_delayed},
 	{"trace_db_mode", INT_PARAM, &trace_db_mode},
42c7c7a1
 	{"trace_init_mode", PARAM_INT, &_siptrace_init_mode},
43207442
 	{"trace_mode", PARAM_INT, &_siptrace_mode},
f39eca3d
 	{"evcb_msg", PARAM_STR, &_siptrace_evcb_msg},
43207442
 	{0, 0, 0}
c0c67b7e
 };
43207442
 /* clang-format on */
c0c67b7e
 
 #ifdef STATISTICS
0504bf23
 stat_var *siptrace_req;
 stat_var *siptrace_rpl;
c0c67b7e
 
43207442
 /* clang-format off */
c0c67b7e
 stat_export_t siptrace_stats[] = {
0504bf23
 	{"traced_requests", 0, &siptrace_req},
43207442
 	{"traced_replies", 0, &siptrace_rpl},
 	{0, 0, 0}
c0c67b7e
 };
43207442
 /* clang-format on */
c0c67b7e
 #endif
 
eae8e7c1
 /*! \brief module exports */
43207442
 /* clang-format off */
c0c67b7e
 struct module_exports exports = {
56040f83
 	"siptrace",     /*!< module name */
eae8e7c1
 	DEFAULT_DLFLAGS, /*!< dlopen flags */
56040f83
 	cmds,			/*!< exported functions */
 	params,			/*!< exported parameters */
 	0,				/*!< exported rpc functions */
 	0,				/*!< exported pseudo-variables */
 	0,				/*!< response function */
 	mod_init,		/*!< module initialization function */
 	child_init,		/*!< child initialization function */
 	destroy			/*!< destroy function */
c0c67b7e
 };
43207442
 /* clang-format on */
c0c67b7e
 
 
eae8e7c1
 /*! \brief Initialize siptrace module */
c0c67b7e
 static int mod_init(void)
 {
b0a7f212
 	pv_spec_t avp_spec;
7a7ee280
 	sl_cbelem_t slcb;
e2cf6343
 
51c1fe92
 #ifdef STATISTICS
 	/* register statistics */
0504bf23
 	if(register_module_stats(exports.name, siptrace_stats) != 0) {
51c1fe92
 		LM_ERR("failed to register core statistics\n");
 		return -1;
 	}
 #endif
 
f39eca3d
 	_siptrace_evrt_msg_idx = route_lookup(&event_rt, "siptrace:msg");
 
e3a298e3
 	if(trace_db_delayed!=0) {
 		trace_db_mode = 1;
 	}
 
0504bf23
 	if(siptrace_init_rpc() != 0) {
9b1c2348
 		LM_ERR("failed to register RPC commands\n");
 		return -1;
 	}
e8b35ce3
 
ca276bb7
 	if(hep_version != 1 && hep_version != 2 && hep_version != 3) {
5ac49634
 		LM_ERR("unsupported version of HEP\n");
ddb9171c
 		return -1;
651fd496
 	}
 
0504bf23
 	trace_on_flag = (int *)shm_malloc(sizeof(int));
 	if(trace_on_flag == NULL) {
55e41ddd
 		LM_ERR("no more shm memory left\n");
c0c67b7e
 		return -1;
 	}
 	*trace_on_flag = trace_on;
c5af2356
 
42c7c7a1
 	/* find a database module if needed */
 	if((_siptrace_mode & SIPTRACE_MODE_DB) || (trace_to_database != 0)) {
 		if(db_bind_mod(&db_url, &db_funcs)) {
 			LM_ERR("unable to bind database module\n");
f2ce69bf
 			return -1;
 		}
42c7c7a1
 		if(!DB_CAPABILITY(db_funcs, DB_CAP_INSERT)) {
 			LM_ERR("database modules does not provide all functions needed"
0edff017
 					" by module\n");
42c7c7a1
 			return -1;
68d282e2
 		}
f2ce69bf
 	}
7a7ee280
 
2482f95e
 	if(trace_dup_uri_str.s != 0) {
 		trace_dup_uri = (sip_uri_t*)pkg_malloc(sizeof(sip_uri_t));
 		if(trace_dup_uri == 0) {
55e41ddd
 			LM_ERR("no more pkg memory left\n");
c0c67b7e
 			return -1;
 		}
2482f95e
 		memset(trace_dup_uri, 0, sizeof(sip_uri_t));
 		if(parse_uri(trace_dup_uri_str.s, trace_dup_uri_str.len, trace_dup_uri) < 0) {
9d594b2d
 			LM_ERR("bad duplicate_uri\n");
c0c67b7e
 			return -1;
 		}
2482f95e
 		if(!trace_dup_uri->proto) {
 			trace_dup_uri->proto = PROTO_UDP;
711eeeb1
 		}
2482f95e
 		if(!trace_dup_uri->port_no) {
 			trace_dup_uri->port_no = SIP_PORT;
711eeeb1
 		}
c0c67b7e
 	}
90691771
 
e0109d54
 	if(trace_send_sock_name_str.s != 0) {
 		trace_send_sock_info = ksr_get_socket_by_name(&trace_send_sock_name_str);
 		trace_send_sock_str.s = NULL;
 		trace_send_sock_str.len = 0;
 	} else if(trace_send_sock_str.s != 0) {
2482f95e
 		trace_send_sock_str.len = strlen(trace_send_sock_str.s);
 		trace_send_sock_uri = (sip_uri_t*)pkg_malloc(sizeof(sip_uri_t));
 		if(trace_send_sock_uri == 0) {
ddb9171c
 			LM_ERR("no more pkg memory left\n");
 			return -1;
 		}
2482f95e
 		memset(trace_send_sock_uri, 0, sizeof(sip_uri_t));
 		if(parse_uri(trace_send_sock_str.s, trace_send_sock_str.len,
0edff017
 					trace_send_sock_uri)
0504bf23
 				< 0) {
2482f95e
 			LM_ERR("bad send sock address\n");
ddb9171c
 			return -1;
 		}
2482f95e
 		if(!trace_send_sock_uri->proto) {
 			trace_send_sock_uri->proto = PROTO_UDP;
711eeeb1
 		}
2482f95e
 		if(!trace_send_sock_uri->port_no) {
 			trace_send_sock_uri->port_no = SIP_PORT;
711eeeb1
 		}
1f524060
 		trace_send_sock_info = grep_sock_info(&trace_send_sock_uri->host,
 				trace_send_sock_uri->port_no,
 				trace_send_sock_uri->proto);
651fd496
 	}
 
42c7c7a1
 	if(_siptrace_init_mode==SIPTRACE_INIT_MODE_ALL
 			|| _siptrace_init_mode==SIPTRACE_INIT_MODE_SCRIPT) {
 		if(trace_flag_param!=-1) {
 			if(trace_flag_param < -1 || trace_flag_param > (int)MAX_FLAG) {
 				LM_ERR("invalid trace flag %d\n", trace_flag_param);
 				return -1;
 			}
 			trace_flag = 1 << trace_flag_param;
4392d2e9
 		}
 
42c7c7a1
 		/* register callbacks to TM */
 		if(load_tm_api(&tmb) != 0) {
 			LM_WARN("can't load tm api. Will not install tm callbacks.\n");
90691771
 		}
42c7c7a1
 
 		if (load_dlg_api(&dlgb) < 0) {
 			LM_INFO("can't load dlg api. Will not install dialog callbacks.\n");
 		} else {
 			if (dlgb.register_dlgcb(NULL, DLGCB_CREATED, trace_dialog, NULL, NULL) != 0) {
 				LM_ERR("failed to register dialog callbacks! Tracing dialogs won't be available\n");
 			}
4392d2e9
 		}
 
42c7c7a1
 		/* bind the SL API */
 		if(sl_load_api(&slb) != 0) {
 			LM_WARN("cannot bind to SL API. Will not install sl callbacks.\n");
 		} else {
 			/* register sl callbacks */
 			memset(&slcb, 0, sizeof(sl_cbelem_t));
 
 			slcb.type = SLCB_REPLY_READY;
 			slcb.cbf = trace_sl_onreply_out;
 			if(slb.register_cb(&slcb) != 0) {
 				LM_ERR("can't register for SLCB_REPLY_READY\n");
 				return -1;
 			}
 
 			if(trace_sl_acks) {
 				slcb.type = SLCB_ACK_FILTERED;
 				slcb.cbf = trace_sl_ack_in;
 				if(slb.register_cb(&slcb) != 0) {
 					LM_ERR("can't register for SLCB_ACK_FILTERED\n");
 					return -1;
 				}
 			}
 		}
 		if(traced_user_avp_str.s && traced_user_avp_str.len > 0) {
 			if(pv_parse_spec(&traced_user_avp_str, &avp_spec) == 0
 					|| avp_spec.type != PVT_AVP) {
 				LM_ERR("malformed or non AVP %.*s AVP definition\n",
 						traced_user_avp_str.len, traced_user_avp_str.s);
 				return -1;
 			}
 
 			if(pv_get_avp_name(
0edff017
 						0, &avp_spec.pvp, &traced_user_avp, &traced_user_avp_type)
42c7c7a1
 					!= 0) {
 				LM_ERR("[%.*s] - invalid AVP definition\n", traced_user_avp_str.len,
 						traced_user_avp_str.s);
 				return -1;
 			}
 		} else {
 			traced_user_avp.n = 0;
 			traced_user_avp_type = 0;
 		}
 		if(trace_table_avp_str.s && trace_table_avp_str.len > 0) {
 			if(pv_parse_spec(&trace_table_avp_str, &avp_spec) == 0
 					|| avp_spec.type != PVT_AVP) {
 				LM_ERR("malformed or non AVP %.*s AVP definition\n",
 						trace_table_avp_str.len, trace_table_avp_str.s);
 				return -1;
 			}
 
 			if(pv_get_avp_name(
0edff017
 						0, &avp_spec.pvp, &trace_table_avp, &trace_table_avp_type)
42c7c7a1
 					!= 0) {
 				LM_ERR("[%.*s] - invalid AVP definition\n", trace_table_avp_str.len,
 						trace_table_avp_str.s);
 				return -1;
 			}
 		} else {
 			trace_table_avp.n = 0;
 			trace_table_avp_type = 0;
90691771
 		}
 	}
 
42c7c7a1
 	if(_siptrace_init_mode==SIPTRACE_INIT_MODE_ALL
 			|| _siptrace_init_mode==SIPTRACE_INIT_MODE_CORECB) {
 		if(_siptrace_mode != SIPTRACE_MODE_NONE) {
 			sr_event_register_cb(SREV_NET_DATA_RECV, siptrace_net_data_recv);
e1570a11
 			sr_event_register_cb(SREV_NET_DATA_SENT, siptrace_net_data_sent);
42c7c7a1
 		} else if(_siptrace_init_mode==SIPTRACE_INIT_MODE_CORECB) {
 			LM_ERR("invalid config options for core callbacks tracing\n");
 			return -1;
 		}
1771f7e4
 	}
c0c67b7e
 	return 0;
 }
 
 
 static int child_init(int rank)
 {
0504bf23
 	if(rank == PROC_INIT || rank == PROC_MAIN || rank == PROC_TCP_MAIN)
82a5ef65
 		return 0; /* do nothing for the main process */
 
43207442
 	if((_siptrace_mode & SIPTRACE_MODE_DB) || (trace_to_database != 0)) {
c5af2356
 		db_con = db_funcs.init(&db_url);
0504bf23
 		if(!db_con) {
 			LM_ERR("unable to connect to database. Please check "
0edff017
 					"configuration.\n");
c5af2356
 			return -1;
 		}
4137bebe
 		if(DB_CAPABILITY(db_funcs, DB_CAP_QUERY)) {
 			if(db_check_table_version(
 					&db_funcs, db_con, &siptrace_table, SIP_TRACE_TABLE_VERSION)
 						< 0) {
 				DB_TABLE_VERSION_ERROR(siptrace_table);
 				db_funcs.close(db_con);
 				db_con = 0;
 				return -1;
 			}
e88c9602
 		}
c5af2356
 	}
c0c67b7e
 
 	return 0;
 }
 
 
 static void destroy(void)
 {
c37e0032
 	if(trace_on_flag) {
c5af2356
 		shm_free(trace_on_flag);
c37e0032
 	}
ec04cdae
 }
 
0504bf23
 static inline str *siptrace_get_table(void)
90691771
 {
0504bf23
 	static int_str avp_value;
90691771
 	struct usr_avp *avp;
 
0504bf23
 	if(trace_table_avp.n == 0)
e2cf6343
 		return &siptrace_table;
90691771
 
 	avp = NULL;
0504bf23
 	if(trace_table_avp.n != 0)
 		avp = search_first_avp(
 				trace_table_avp_type, trace_table_avp, &avp_value, 0);
90691771
 
0504bf23
 	if(avp == NULL || !is_avp_str_val(avp) || avp_value.s.len <= 0)
e2cf6343
 		return &siptrace_table;
90691771
 
e2cf6343
 	return &avp_value.s;
90691771
 }
 
f9b98c64
 static int sip_trace_store(siptrace_data_t *sto, dest_info_t *dst,
0504bf23
 		str *correlation_id_str)
c0c67b7e
 {
4e9a7601
 	int ret = 1;
 
0504bf23
 	if(sto == NULL) {
94393b2d
 		LM_DBG("invalid parameter\n");
 		return -1;
 	}
c5af2356
 
4c7048cb
 	gettimeofday(&sto->tv, NULL);
c5af2356
 
0504bf23
 	if(sip_trace_xheaders_read(sto) != 0)
4485f638
 		return -1;
4e9a7601
 
 	ret = sip_trace_store_db(sto);
48ebf543
 
0504bf23
 	if(sip_trace_xheaders_write(sto) != 0)
4485f638
 		return -1;
c5af2356
 
4e9a7601
 	if(hep_mode_on) {
0504bf23
 		trace_send_hep_duplicate(
 				&sto->body, &sto->fromip, &sto->toip, dst, correlation_id_str);
4e9a7601
 	} else {
21338195
 		/* sip_trace_mode() will not set a destination, uses duplicate_uri */
 		if(dst || trace_to_database == 0) {
4e9a7601
 			trace_send_duplicate(sto->body.s, sto->body.len, dst);
 		}
 	}
48ebf543
 
0504bf23
 	if(sip_trace_xheaders_free(sto) != 0)
4485f638
 		return -1;
48ebf543
 
 	return ret;
58947134
 }
 
bb2894a4
 static int sip_trace_insert_db(db_key_t *db_keys, db_val_t *db_vals,
 		int db_nkeys, char *dtext)
 {
 	LM_DBG("storing info - %s\n", dtext);
971b79fe
 	if(trace_db_mode == 2 && db_funcs.insert_async != NULL) {
e3a298e3
 		if(db_funcs.insert_async(db_con, db_keys, db_vals, db_nkeys) < 0) {
 			LM_ERR("error storing trace - async - %s\n", dtext);
 			return -1;
 		}
971b79fe
 	} else if(trace_db_mode == 1 && db_funcs.insert_delayed != NULL) {
bb2894a4
 		if(db_funcs.insert_delayed(db_con, db_keys, db_vals, db_nkeys) < 0) {
e3a298e3
 			LM_ERR("error storing trace - delayed - %s\n", dtext);
bb2894a4
 			return -1;
 		}
 	} else {
 		if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0) {
 			LM_ERR("error storing trace - %s\n", dtext);
 			return -1;
 		}
 	}
 	return 0;
 }
 
f9b98c64
 static int sip_trace_store_db(siptrace_data_t *sto)
58947134
 {
43207442
 	if((trace_to_database == 0) && ((_siptrace_mode & SIPTRACE_MODE_DB) == 0)) {
afd0c929
 		goto done;
43207442
 	}
afd0c929
 
0504bf23
 	if(db_con == NULL) {
740cfa0e
 		LM_DBG("database connection not initialized\n");
 		return -1;
 	}
 
58947134
 	db_key_t db_keys[NR_KEYS];
 	db_val_t db_vals[NR_KEYS];
94393b2d
 
e2cf6343
 	db_keys[0] = &msg_column;
db0126bc
 	db_vals[0].type = DB1_BLOB;
c0c67b7e
 	db_vals[0].nul = 0;
94393b2d
 	db_vals[0].val.blob_val = sto->body;
c5af2356
 
e2cf6343
 	db_keys[1] = &callid_column;
db0126bc
 	db_vals[1].type = DB1_STR;
c0c67b7e
 	db_vals[1].nul = 0;
94393b2d
 	db_vals[1].val.str_val = sto->callid;
c5af2356
 
e2cf6343
 	db_keys[2] = &method_column;
db0126bc
 	db_vals[2].type = DB1_STR;
c0c67b7e
 	db_vals[2].nul = 0;
94393b2d
 	db_vals[2].val.str_val = sto->method;
 
e2cf6343
 	db_keys[3] = &status_column;
db0126bc
 	db_vals[3].type = DB1_STR;
c0c67b7e
 	db_vals[3].nul = 0;
94393b2d
 	db_vals[3].val.str_val = sto->status;
c5af2356
 
e2cf6343
 	db_keys[4] = &fromip_column;
94393b2d
 	db_vals[4].type = DB1_STR;
c0c67b7e
 	db_vals[4].nul = 0;
94393b2d
 	db_vals[4].val.str_val = sto->fromip;
c5af2356
 
e2cf6343
 	db_keys[5] = &toip_column;
94393b2d
 	db_vals[5].type = DB1_STR;
c0c67b7e
 	db_vals[5].nul = 0;
94393b2d
 	db_vals[5].val.str_val = sto->toip;
c5af2356
 
e2cf6343
 	db_keys[6] = &date_column;
db0126bc
 	db_vals[6].type = DB1_DATETIME;
c0c67b7e
 	db_vals[6].nul = 0;
4c7048cb
 	db_vals[6].val.time_val = sto->tv.tv_sec;
c5af2356
 
e2cf6343
 	db_keys[7] = &direction_column;
db0126bc
 	db_vals[7].type = DB1_STRING;
c0c67b7e
 	db_vals[7].nul = 0;
94393b2d
 	db_vals[7].val.string_val = sto->dir;
c5af2356
 
e2cf6343
 	db_keys[8] = &fromtag_column;
db0126bc
 	db_vals[8].type = DB1_STR;
c0c67b7e
 	db_vals[8].nul = 0;
94393b2d
 	db_vals[8].val.str_val = sto->fromtag;
c5af2356
 
e2cf6343
 	db_keys[9] = &traced_user_column;
db0126bc
 	db_vals[9].type = DB1_STR;
c0c67b7e
 	db_vals[9].nul = 0;
c5af2356
 
4c7048cb
 	db_keys[10] = &time_us_column;
 	db_vals[10].type = DB1_INT;
 	db_vals[10].nul = 0;
 	db_vals[10].val.int_val = sto->tv.tv_usec;
c5af2356
 
e88c9602
 	db_keys[11] = &totag_column;
 	db_vals[11].type = DB1_STR;
 	db_vals[11].nul = 0;
 	db_vals[11].val.str_val = sto->totag;
 
4c7048cb
 	db_funcs.use_table(db_con, siptrace_get_table());
c0c67b7e
 
0504bf23
 	if(trace_on_flag != NULL && *trace_on_flag != 0) {
 		db_vals[9].val.str_val.s = "";
c0c67b7e
 		db_vals[9].val.str_val.len = 0;
c5af2356
 
bb2894a4
 		if(sip_trace_insert_db(db_keys, db_vals, NR_KEYS, "no user") < 0) {
 			goto error;
c0c67b7e
 		}
 #ifdef STATISTICS
94393b2d
 		update_stat(sto->stat, 1);
c0c67b7e
 #endif
 	}
c5af2356
 
0504bf23
 	if(sto->avp == NULL)
c0c67b7e
 		goto done;
c5af2356
 
94393b2d
 	db_vals[9].val.str_val = sto->avp_value.s;
c0c67b7e
 
bb2894a4
 	if(sip_trace_insert_db(db_keys, db_vals, NR_KEYS, "first user") < 0) {
 		goto error;
c0c67b7e
 	}
 
94393b2d
 	sto->avp = search_next_avp(&sto->state, &sto->avp_value);
0504bf23
 	while(sto->avp != NULL) {
94393b2d
 		db_vals[9].val.str_val = sto->avp_value.s;
c0c67b7e
 
bb2894a4
 		if(sip_trace_insert_db(db_keys, db_vals, NR_KEYS, "extra user") < 0) {
 			goto error;
c0c67b7e
 		}
94393b2d
 		sto->avp = search_next_avp(&sto->state, &sto->avp_value);
c0c67b7e
 	}
 
 done:
 	return 1;
 error:
 	return -1;
 }
 
2482f95e
 enum siptrace_type_t siptrace_parse_flag(str* sflags)
0504bf23
 {
fa7eb2ab
 	int idx;
 	enum siptrace_type_t trace_type = SIPTRACE_NONE;
32a26c25
 
fa7eb2ab
 	if (sflags == NULL || sflags->s == NULL || sflags->len == 0) {
 		return SIPTRACE_NONE;
32a26c25
 	}
ca276bb7
 
fa7eb2ab
 	for (idx = 0; idx < sflags->len; idx++) {
 		switch(sflags->s[idx]|0x20) { /*|0x20 - to lowercase */
 			case SIPTRACE_MESSAGE:
 			case SIPTRACE_TRANSACTION:
 			case SIPTRACE_DIALOG:
 				if (trace_type != SIPTRACE_NONE) {
 					LM_ERR("only one tracing flag can be used <%.*s>!\n",
 							sflags->len, sflags->s);
 					return SIPTRACE_NONE;
 				}
32a26c25
 
fa7eb2ab
 				trace_type = (sflags->s[idx]|0x20);
 				break;
 			case ' ':
 			case '\t':
 				break;
 			default:
157892f3
 				LM_ERR("Invalid character <%c> in <%.*s> at position <%d>!\n", sflags->s[idx],
 						sflags->len, sflags->s, idx);
fa7eb2ab
 				return SIPTRACE_NONE;
ca276bb7
 		}
fa7eb2ab
 	}
32a26c25
 
fa7eb2ab
 	return trace_type;
 }
ca276bb7
 
fa7eb2ab
 static int fixup_siptrace(void **param, int param_no)
 {
 	str sflags;
 	enum siptrace_type_t trace_type;
ca276bb7
 
fa7eb2ab
 	if(param_no < 1 || param_no > 3) {
 		LM_DBG("params:%s\n", (char *)*param);
 		return 0;
32a26c25
 	}
 
fa7eb2ab
 	if (param_no == 1 || param_no == 2) {
 		/* correlation id */
65778f9e
 		return fixup_spve_all(param, param_no);
fa7eb2ab
 	} else if (param_no == 3) {
 		/* tracing type; string only */
157892f3
 		sflags.s = (char *)*param;
 		sflags.len = strlen(sflags.s);
32a26c25
 
2482f95e
 		trace_type = siptrace_parse_flag(&sflags);
fa7eb2ab
 		if (trace_type == SIPTRACE_NONE) {
 			LM_ERR("Failed to parse trace type!\n");
 			return -1;
 		}
 
 		*param = pkg_malloc(sizeof(trace_type));
7a977615
 		if (*param == NULL) {
 			LM_ERR("no more pkg memory!\n");
 			return -1;
 		}
fa7eb2ab
 		memcpy(*param, &trace_type, sizeof(trace_type));
32a26c25
 	}
 
 	return 0;
 }
 
7c98d547
 static int fixup_free_siptrace(void **param, int param_no)
 {
 	if (param_no == 1 || param_no == 2) {
 		/* correlation id */
 		return fixup_free_spve_all(param, param_no);
 	} if (param_no == 3) {
 		/* tracing type; string only */
 		if (*param) {
 			pkg_free(*param);
 		}
 	}
 
 	return 0;
 }
 
fa7eb2ab
 
5addc451
 /**
fa7eb2ab
  *
2482f95e
  * siptrace_parse_uri (to replace siptrace_fixup and ki_sip_trace_dst_cid beginning)
fa7eb2ab
  * parse_siptrace_type
  *
5addc451
  */
fa7eb2ab
 
2482f95e
 static int siptrace_parse_uri(str* duri, dest_info_t* dst)
ca276bb7
 {
f9b98c64
 	sip_uri_t uri;
 	proxy_l_t *p = NULL;
ca276bb7
 
fa7eb2ab
 	if (dst == NULL) {
 		LM_ERR("bad destination!\n");
 		return -1;
 	}
 
 	if (duri == NULL || duri->len <= 0) {
2482f95e
 		if(trace_dup_uri) {
 			uri = *trace_dup_uri;
0504bf23
 		} else {
ca276bb7
 			LM_ERR("Missing duplicate URI\n");
 			return -1;
 		}
0504bf23
 	} else {
ca276bb7
 		memset(&uri, 0, sizeof(struct sip_uri));
5addc451
 		if(parse_uri(duri->s, duri->len, &uri) < 0) {
ca276bb7
 			LM_ERR("bad dup uri\n");
 			return -1;
 		}
711eeeb1
 		if(!uri.proto) {
 			uri.proto = PROTO_UDP;
 		}
 		if(!uri.port_no) {
 			uri.port_no = SIP_PORT;
 		}
ca276bb7
 	}
 
 	init_dest_info(dst);
 
 	/* create a temporary proxy*/
711eeeb1
 	dst->proto = uri.proto;
 	p = mk_proxy(&uri.host, uri.port_no, dst->proto);
0504bf23
 	if(p == 0) {
ca276bb7
 		LM_ERR("bad host name in uri\n");
 		return -1;
 	}
 
 	hostent2su(&dst->to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);
 
 	/* free temporary proxy*/
0504bf23
 	if(p) {
ca276bb7
 		free_proxy(p); /* frees only p content, not p itself */
 		pkg_free(p);
 	}
 
fa7eb2ab
 	return 0;
 }
 
e8d76561
 /**
  *
  */
 static int sip_trace_helper(sip_msg_t *msg, dest_info_t *dst, str *duri,
 		str *corid, char *dir, enum siptrace_type_t trace_type)
 {
 	siptrace_info_t* info = NULL;
2ad78641
 	struct cell *t_invite, *orig_t;
f0ae3c37
 	char *p = NULL;
2ad78641
 	int canceled;
 	int ret = 0;
e8d76561
 
 	if (trace_type == SIPTRACE_TRANSACTION || trace_type == SIPTRACE_DIALOG) {
796a12d6
 		int alloc_size = sizeof(siptrace_info_t);
 
e8d76561
 		/*
 		 * for each type check that conditions are created
 		 * transaction: it's a request starting a transaction; tm module loaded
 		 * dialog: it's an INVITE; dialog module is loaded
 		 *
 		 * */
 		if (tmb.t_gett == NULL) {
 			LM_WARN("TM module not loaded! Tracing only current message!\n");
 			goto trace_current;
 		}
 
0edff017
 	/* if sip_trace is called over an incoming CANCEL, skip
 	 * capturing it if the cancelled transaction is already being traced
 	 */
2ad78641
 		if (msg->REQ_METHOD==METHOD_CANCEL) {
080c6e07
 			t_invite=tmb.t_lookup_original(msg);
 			if (t_invite!=T_NULL_CELL) {
 				if (t_invite->uas.request->msg_flags & FL_SIPTRACE) {
2ad78641
 					LM_DBG("Transaction is already been traced, skipping.\n");
 					tmb.t_unref(msg);
 					return 1;
080c6e07
 				}
 				tmb.t_unref(msg);
 			}
 		}
0edff017
 
2ad78641
 		/* if sip_trace is called over an incoming ACK, skip
 		 * capturing it if it's an ACK for a negative reply for
 		 * an already traced transaction
 		 */
 		if (msg->REQ_METHOD==METHOD_ACK) {
 			orig_t = tmb.t_gett();
 			if(tmb.t_lookup_request(msg,0,&canceled)) {
 				t_invite = tmb.t_gett();
0c142be9
 				if (t_invite!=T_NULL_CELL) {
 					if (t_invite->uas.request->msg_flags & FL_SIPTRACE) {
 						LM_DBG("Transaction is already been traced, skipping.\n");
 						ret = 1;
 					}
 					tmb.t_release_transaction( t_invite );
 					tmb.t_unref(msg);
2ad78641
 				}
 			}
0c142be9
 			tmb.t_sett(orig_t, T_BR_UNDEFINED);
 			if (ret)
 				return 1;
2ad78641
 		}
 
e8d76561
 		if (trace_type == SIPTRACE_DIALOG && dlgb.get_dlg == NULL) {
 			LM_WARN("DIALOG module not loaded! Tracing only current message!\n");
 			goto trace_current;
 		}
 
 		if (msg->first_line.type != SIP_REQUEST ||
971b79fe
 				(trace_type == SIPTRACE_DIALOG
 				 && msg->first_line.u.request.method_value != METHOD_INVITE)) {
e8d76561
 			LM_WARN("When tracing a %s sip_trace() has to be initiated on the %s\n",
 					trace_type == SIPTRACE_TRANSACTION ? "transaction" : "dialog",
 					trace_type == SIPTRACE_TRANSACTION ? "request message" : "initial invite");
 			return -1;
 		}
 
796a12d6
 		if (corid) {
 			alloc_size += corid->len;
 		}
 
 		if (duri) {
 			alloc_size += duri->len;
 		}
 
 		info = shm_malloc(alloc_size);
e8d76561
 		if (info == NULL) {
 			LM_ERR("No more shm!\n");
 			return -1;
 		}
796a12d6
 		memset(info, 0, alloc_size);
e8d76561
 
f0ae3c37
 		p = (char *)(info + 1);
e8d76561
 		/* could use the dest_info we've already parsed but there's no way to pass
 		 * it to DLGCB_CREATED callback so the only thing to do is keep
 		 * it as uri, serialize in a dlg_var and parse again in DLGCB_CREATED */
 		if(corid) {
f0ae3c37
 			info->correlation_id.s = p;
796a12d6
 			info->correlation_id.len = corid->len;
 			memcpy(info->correlation_id.s, corid->s, corid->len);
e8d76561
 		}
 		if (duri) {
 			info->uriState = STRACE_RAW_URI;
f0ae3c37
 			info->u.dup_uri.s = p + ((info->correlation_id.s)?info->correlation_id.len:0);
796a12d6
 			memcpy(info->u.dup_uri.s, duri->s, duri->len);
 			info->u.dup_uri.len = duri->len;
e8d76561
 		} else {
 			info->uriState = STRACE_UNUSED_URI;
 		}
 
 		if (trace_type == SIPTRACE_TRANSACTION) {
796a12d6
 			trace_transaction(msg, info, 0);
e8d76561
 		} else if (trace_type == SIPTRACE_DIALOG) {
 			if (unlikely(dlgb.set_dlg_var == NULL)) {
 				/* FIXME should we abort tracing here? */
 				LM_WARN("Dialog api not loaded! will trace only current transaction!\n");
 			} else {
 				/* serialize what's in info */
 				/* save correlation id in siptrace_info avp
971b79fe
 				 * we want to have traced user avp value at the moment
 				 * of sip_trace function call */
2482f95e
 				if (trace_add_info_xavp(info) < 0) {
e8d76561
 					LM_ERR("failed to serialize siptrace info! Won't trace dialog!\n");
 					return -1;
 				} else {
 					msg->msg_flags |= FL_SIPTRACE;
 				}
 			}
 
 			/**
2482f95e
 			 * WARNING: don't move trace_transaction before trace_add_info_xavp()
 			 * trace_add_info_xavp() expects the URI in RAW format, unparsed
e8d76561
 			 * trace_transaction() parses the URI if it finds it in raw format;
 			 * a BUG will be thrown if this happens
 			 */
796a12d6
 			trace_transaction(msg, info, 1);
e8d76561
 		}
 	}
 
 	if(trace_type != SIPTRACE_MESSAGE && trace_is_off(msg)) {
 		LM_DBG("trace off...\n");
 		return 1;
 	}
 
 trace_current:
 	return sip_trace(msg, dst, corid, dir);
 }
 
fa7eb2ab
 /**
971b79fe
  * Send sip trace with destination and correlation id
  * and specify what messages to be traced
fa7eb2ab
  */
 static int ki_sip_trace_dst_cid_flag(sip_msg_t *msg, str *duri, str *cid, str* sflag)
 {
 	dest_info_t dst;
 	enum siptrace_type_t trace_type;
 
e8d76561
 	if(duri) {
2482f95e
 		if (siptrace_parse_uri(duri, &dst) < 0) {
e8d76561
 			LM_ERR("failed to parse siptrace uri!\n");
 			return -1;
 		}
fa7eb2ab
 	}
 
 	if (sflag) {
2482f95e
 		trace_type = siptrace_parse_flag(sflag);
fa7eb2ab
 		if (trace_type == SIPTRACE_NONE) {
 			LM_ERR("Invalid flags <%.*s>\n", sflag->len, sflag->s);
 		}
 	} else {
 		trace_type = SIPTRACE_MESSAGE;
 	}
 
e8d76561
 	return sip_trace_helper(msg, (duri)?&dst:NULL, duri, cid, NULL, trace_type);
fa7eb2ab
 }
 
 /**
  * Send sip trace with destination and correlation id
  */
 static int ki_sip_trace_dst_cid(sip_msg_t *msg, str *duri, str *cid)
 {
 	return ki_sip_trace_dst_cid_flag(msg, duri, cid, NULL);
5addc451
 }
 
 /**
  * Send sip trace with destination
  */
 static int ki_sip_trace_dst(sip_msg_t *msg, str *duri)
 {
fa7eb2ab
 	return ki_sip_trace_dst_cid_flag(msg, duri, NULL, NULL);
5addc451
 }
 
 /**
  *
  */
 static int ki_sip_trace(sip_msg_t *msg)
 {
fa7eb2ab
 	return ki_sip_trace_dst_cid_flag(msg, NULL, NULL, NULL);
5addc451
 }
 
 /**
  *
  */
 static int w_sip_trace0(sip_msg_t *msg, char *dest, char *correlation_id)
 {
fa7eb2ab
 	return w_sip_trace3(msg, NULL, NULL, NULL);
5addc451
 }
 
 /**
  *
  */
e8d76561
 static int w_sip_trace1(sip_msg_t *msg, char *dest, char *p2)
5addc451
 {
fa7eb2ab
 	return w_sip_trace3(msg, dest, NULL, NULL);
5addc451
 }
 
 /**
  *
  */
 static int w_sip_trace2(sip_msg_t *msg, char *dest, char *correlation_id)
 {
fa7eb2ab
 	return w_sip_trace3(msg, dest, correlation_id, NULL);
 }
 
 
 static int w_sip_trace3(sip_msg_t *msg, char *dest, char *correlation_id, char *trace_type_p)
 {
65778f9e
 	str dup_uri_param_str = {0, 0};
5addc451
 	str correlation_id_str = {0, 0};
fa7eb2ab
 	dest_info_t dest_info;
 	enum siptrace_type_t trace_type;
5addc451
 
21338195
 	/* to support tracing to database without destination parameter - old mode */
 	if (dest || trace_to_database == 0) {
 		if (dest) {
 			if(fixup_get_svalue(msg, (gparam_t *)dest, &dup_uri_param_str) != 0) {
 				LM_ERR("unable to parse the dest URI string\n");
 				return -1;
 			}
fa7eb2ab
 		}
5addc451
 
4e9a7601
 		if (dup_uri_param_str.s == 0 || (is_null_pv(dup_uri_param_str))) {
2482f95e
 			if (trace_dup_uri_str.s == 0 || trace_dup_uri_str.len == 0) {
4e9a7601
 				LM_ERR("no duplicate_uri modparam nor duplicate uri sip_trace() argument provided!\n");
 				return -1;
 			}
65778f9e
 
2482f95e
 			dup_uri_param_str = trace_dup_uri_str;
4e9a7601
 		}
65778f9e
 
4e9a7601
 		/* if arg dest uri is null  dup_uri_param_str will have length 0 and global dup_uri will be used */
2482f95e
 		if (siptrace_parse_uri(&dup_uri_param_str, &dest_info) < 0) {
4e9a7601
 			LM_ERR("failed to parse uri!\n");
 			return -1;
 		}
 	} else {
 		memset(&dest_info, 0, sizeof(dest_info_t));
ca276bb7
 	}
 
fa7eb2ab
 	if (correlation_id) {
 		if(fixup_get_svalue(msg, (gparam_t *)correlation_id, &correlation_id_str)
 				!= 0) {
 			LM_ERR("unable to parse the correlation id\n");
 			return -1;
 		}
 	}
 
 	if (trace_type_p != NULL) {
 		trace_type = *(enum siptrace_type_t *)(trace_type_p);
 	} else {
40e09d86
 		/* fallback to default - transaction tracking when flag is set,
 		 * otherwise only the current message*/
 		if(msg->flags & trace_flag) {
 			trace_type = SIPTRACE_TRANSACTION;
 		} else {
 			trace_type = SIPTRACE_MESSAGE;
 		}
fa7eb2ab
 	}
 
e8d76561
 	return sip_trace_helper(msg, (dest)?&dest_info:NULL,
 			(dest)?&dup_uri_param_str:NULL,
 			(correlation_id)?&correlation_id_str:NULL, NULL, trace_type);
ca276bb7
 }
 
971b79fe
 /**
  * link call-id, method, from-tag and to-tag
  */
 static int sip_trace_msg_attrs(sip_msg_t *msg, siptrace_data_t *sto)
 {
 	if(sip_trace_prepare(msg) < 0) {
 		return -1;
 	}
 
 	sto->callid = msg->callid->body;
 
 	if(msg->first_line.type == SIP_REQUEST) {
 		sto->method = msg->first_line.u.request.method;
 	} else {
 		sto->method = get_cseq(msg)->method;
 	}
 
 	sto->fromtag = get_from(msg)->tag_value;
 	sto->totag = get_to(msg)->tag_value;
 
 	return 0;
 
 }
 
5addc451
 static int sip_trace(sip_msg_t *msg, dest_info_t *dst,
0504bf23
 		str *correlation_id_str, char *dir)
94393b2d
 {
f9b98c64
 	siptrace_data_t sto;
 	onsend_info_t *snd_inf = NULL;
94393b2d
 
fa7eb2ab
 	if(msg == NULL) {
 		LM_DBG("nothing to trace\n");
 		return -1;
 	}
 
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
94393b2d
 
0504bf23
 	if(traced_user_avp.n != 0)
 		sto.avp = search_first_avp(traced_user_avp_type, traced_user_avp,
94393b2d
 				&sto.avp_value, &sto.state);
 
0504bf23
 	if((sto.avp == NULL) && (trace_on_flag == NULL || *trace_on_flag == 0)) {
94393b2d
 		LM_DBG("trace off...\n");
 		return -1;
 	}
fa7eb2ab
 
971b79fe
 	if(sip_trace_msg_attrs(msg, &sto) < 0) {
94393b2d
 		return -1;
 	}
 
0504bf23
 	if(msg->first_line.type == SIP_REPLY) {
94393b2d
 		sto.status = msg->first_line.u.reply.status;
 	} else {
 		sto.status.s = "";
 		sto.status.len = 0;
 	}
 
0504bf23
 	snd_inf = get_onsend_info();
 	if(snd_inf == NULL) {
9d8df252
 		sto.body.s = msg->buf;
 		sto.body.len = msg->len;
94393b2d
 
0504bf23
 		sto.dir = (dir) ? dir : "in";
93dcc5dc
 
0504bf23
 		if(trace_local_ip.s && trace_local_ip.len > 0
 				&& strncmp(sto.dir, "out", 3) == 0) {
93dcc5dc
 			sto.fromip = trace_local_ip;
 		} else {
788f81af
 			sto.fromip.len = snprintf(sto.fromip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 					siptrace_proto_name(msg->rcv.proto),
 					ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port);
 			if(sto.fromip.len<0 || sto.fromip.len>=SIPTRACE_ADDR_MAX) {
 				LM_ERR("failed to format toip buffer (%d)\n", sto.fromip.len);
 				sto.fromip.s = SIPTRACE_ANYADDR;
 				sto.fromip.len = SIPTRACE_ANYADDR_LEN;
 			} else {
 				sto.fromip.s = sto.fromip_buff;
 			}
93dcc5dc
 		}
 
0504bf23
 		if(trace_local_ip.s && trace_local_ip.len > 0
 				&& strncmp(sto.dir, "in", 2) == 0) {
93dcc5dc
 			sto.toip = trace_local_ip;
 		} else {
788f81af
 			sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 					siptrace_proto_name(msg->rcv.proto), ip_addr2a(&msg->rcv.dst_ip),
 					(int)msg->rcv.dst_port);
 			if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 				LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 				sto.toip.s = SIPTRACE_ANYADDR;
 				sto.toip.len = SIPTRACE_ANYADDR_LEN;
 			} else {
 				sto.toip.s = sto.toip_buff;
 			}
93dcc5dc
 		}
9d8df252
 	} else {
0504bf23
 		sto.body.s = snd_inf->buf;
9d8df252
 		sto.body.len = snd_inf->len;
 
0504bf23
 		if(trace_local_ip.s && trace_local_ip.len > 0) {
93dcc5dc
 			sto.fromip = trace_local_ip;
 		} else {
788f81af
 			if(snd_inf->send_sock->sock_str.len>=SIPTRACE_ADDR_MAX-1) {
 				LM_WARN("local socket address is too large\n");
 				sto.fromip.s = SIPTRACE_ANYADDR;
 				sto.fromip.len = SIPTRACE_ANYADDR_LEN;
 			} else {
 				strncpy(sto.fromip_buff, snd_inf->send_sock->sock_str.s,
 						snd_inf->send_sock->sock_str.len);
 				sto.fromip.s = sto.fromip_buff;
 				sto.fromip.len = snd_inf->send_sock->sock_str.len;
 			}
93dcc5dc
 		}
9d8df252
 
788f81af
 		sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(snd_inf->send_sock->proto),
 				suip2a(snd_inf->to, sizeof(*snd_inf->to)),
 				(int)su_getport(snd_inf->to));
 		if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 			sto.toip.s = SIPTRACE_ANYADDR;
 			sto.toip.len = SIPTRACE_ANYADDR_LEN;
 		} else {
 			sto.toip.s = sto.toip_buff;
 		}
9d8df252
 
 		sto.dir = "out";
 	}
94393b2d
 
 #ifdef STATISTICS
0504bf23
 	if(msg->first_line.type == SIP_REPLY) {
94393b2d
 		sto.stat = siptrace_rpl;
 	} else {
 		sto.stat = siptrace_req;
 	}
 #endif
ca276bb7
 	return sip_trace_store(&sto, dst, correlation_id_str);
94393b2d
 }
 
929ff145
 
 /**
  *
  */
 static int ki_sip_trace_mode(sip_msg_t *msg, str *smode)
 {
 	enum siptrace_type_t trace_type;
 
 	if(smode==NULL || smode->s==NULL || smode->len<=0) {
 		LM_INFO("no tracing mode - trace message\n");
 		trace_type = SIPTRACE_MESSAGE;
 	} else {
 		switch(smode->s[0]) {
 			case 'M':
 			case 'm':
 				trace_type = SIPTRACE_MESSAGE;
 			break;
 			case 'T':
 			case 't':
 				trace_type = SIPTRACE_TRANSACTION;
 			break;
 			case 'D':
 			case 'd':
 				trace_type = SIPTRACE_DIALOG;
 			break;
 			default:
 				trace_type = SIPTRACE_MESSAGE;
 				LM_INFO("unexpected tracing mode [%.*s] - trace message\n",
 						smode->len, smode->s);
 		}
 	}
 
 	return sip_trace_helper(msg, NULL, NULL, NULL, NULL, trace_type);
 }
 
 /**
  *
  */
 static int w_sip_trace_mode(sip_msg_t *msg, char *pmode, char *p2)
 {
 	str smode = STR_NULL;
 	if(fixup_get_svalue(msg, (gparam_t*)pmode, &smode)<0) {
 		LM_ERR("failed to get tracing mode parameter\n");
 		return -1;
 	}
 	return ki_sip_trace_mode(msg, &smode);
 }
 
e28f4644
 static void trace_cancel_in(struct cell *t, int type, struct tmcb_params *ps)
 {
 	siptrace_info_t* info;
 	sip_msg_t *msg;
 
 	if(t == NULL || ps == NULL) {
 		LM_ERR("unexpected parameter values\n");
 		return;
 	}
 
 	if(ps->flags & TMCB_RETR_F) {
 		LM_DBG("retransmission - ignoring\n");
 		return;
 	}
 
 	info = (siptrace_info_t *)(*ps->param);
 	msg = ps->req;
 	if(tmb.register_tmcb(msg, 0, TMCB_RESPONSE_READY, trace_onreply_out, info, 0) <= 0) {
 		LM_ERR("can't register trace_onreply_out\n");
 		return;
 	}
 	msg->msg_flags |= FL_SIPTRACE;
 	sip_trace_helper(msg, NULL, NULL, NULL, NULL, 1);
 }
 
0504bf23
 static void trace_onreq_out(struct cell *t, int type, struct tmcb_params *ps)
c0c67b7e
 {
f9b98c64
 	siptrace_data_t sto;
13378d72
 	siptrace_info_t* info;
94393b2d
 	sip_msg_t *msg;
f9b98c64
 	ip_addr_t to_ip;
 	dest_info_t *dst;
c5af2356
 
0504bf23
 	if(t == NULL || ps == NULL) {
bf3c70e0
 		LM_ERR("unexpected parameter values\n");
94393b2d
 		return;
 	}
de9ef971
 
0504bf23
 	if(ps->flags & TMCB_RETR_F) {
bf3c70e0
 		LM_DBG("retransmission - ignoring\n");
94393b2d
 		return;
 	}
13378d72
 	info = (siptrace_info_t *)(*ps->param);
 
0504bf23
 	msg = ps->req;
 	if(msg == NULL) {
7b2eca49
 		/* check if it is outgoing cancel, t is INVITE
 		 * and send_buf starts with CANCEL */
0504bf23
 		if(is_invite(t) && ps->send_buf.len > 7
 				&& strncmp(ps->send_buf.s, "CANCEL ", 7) == 0) {
7b2eca49
 			msg = t->uas.request;
0504bf23
 			if(msg == NULL) {
7b2eca49
 				LM_DBG("no uas msg for INVITE transaction\n");
 				return;
 			} else {
 				LM_DBG("recording CANCEL based on INVITE transaction\n");
 			}
 		} else {
 			LM_DBG("no uas msg, local transaction\n");
 			return;
 		}
c0c67b7e
 	}
d00be11b
 
971b79fe
 	/* for incoming cancel this is the only place where can get the CANCEL
 	 * transaction and can register a callback for the reply */
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
de9ef971
 
e28f4644
 	if(traced_user_avp.n != 0)
 		sto.avp = search_first_avp(traced_user_avp_type, traced_user_avp,
 				&sto.avp_value, &sto.state);
030d88e7
 
0504bf23
 	if((sto.avp == NULL) && trace_is_off(msg)) {
55e41ddd
 		LM_DBG("trace off...\n");
c0c67b7e
 		return;
 	}
 
971b79fe
 	if(sip_trace_msg_attrs(msg, &sto) < 0) {
0f461ee2
 		return; 
971b79fe
 	}
c0c67b7e
 
e28f4644
 	if(ps->send_buf.len > 0) {
 		sto.body = ps->send_buf;
94393b2d
 	} else {
e28f4644
 		sto.body.s = "No request buffer";
 		sto.body.len = sizeof("No request buffer") - 1;
c0c67b7e
 	}
c5af2356
 
0504bf23
 	if(ps->send_buf.len > 10) {
94393b2d
 		sto.method.s = ps->send_buf.s;
 		sto.method.len = 0;
0504bf23
 		while(sto.method.len < ps->send_buf.len) {
 			if(ps->send_buf.s[sto.method.len] == ' ')
94393b2d
 				break;
 			sto.method.len++;
 		}
0504bf23
 		if(sto.method.len == ps->send_buf.len)
94393b2d
 			sto.method.len = 10;
c0c67b7e
 	} else {
94393b2d
 		sto.method = t->method;
c0c67b7e
 	}
de9ef971
 
94393b2d
 	sto.status.s = "";
 	sto.status.len = 0;
c5af2356
 
7e91c0e7
 	memset(&to_ip, 0, sizeof(struct ip_addr));
13378d72
 	/* destination info from the original message
 	 * used to fetch information to set the from and to for this message
 	 * different from the dest_info in siptrace_info which is the socket
 	 * used to send the message */
94393b2d
 	dst = ps->dst;
7e91c0e7
 
0504bf23
 	if(trace_local_ip.s && trace_local_ip.len > 0) {
94393b2d
 		sto.fromip = trace_local_ip;
eae8e7c1
 	} else {
0504bf23
 		if(dst == 0 || dst->send_sock == 0 || dst->send_sock->sock_str.s == 0) {
219072f0
 			sto.fromip.len = snprintf(sto.fromip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 					siptrace_proto_name(msg->rcv.proto),
 					ip_addr2a(&msg->rcv.dst_ip), (int)msg->rcv.dst_port);
 			if(sto.fromip.len<0 || sto.fromip.len>=SIPTRACE_ADDR_MAX) {
 				LM_ERR("failed to format toip buffer (%d)\n", sto.fromip.len);
 				sto.fromip.s = SIPTRACE_ANYADDR;
 				sto.fromip.len = SIPTRACE_ANYADDR_LEN;
 			} else {
 				sto.fromip.s = sto.fromip_buff;
 			}
7e91c0e7
 		} else {
94393b2d
 			sto.fromip = dst->send_sock->sock_str;
7e91c0e7
 		}
809e05a7
 	}
c5af2356
 
0504bf23
 	if(dst == 0) {
2ae4d19a
 		sto.toip.s = SIPTRACE_ANYADDR;
 		sto.toip.len = SIPTRACE_ANYADDR_LEN;
94393b2d
 	} else {
 		su2ip_addr(&to_ip, &dst->to);
219072f0
 		sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(dst->proto),
 				ip_addr2a(&to_ip), (int)su_getport(&dst->to));
 		if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 			sto.toip.s = SIPTRACE_ANYADDR;
 			sto.toip.len = SIPTRACE_ANYADDR_LEN;
 		} else {
 			sto.toip.s = sto.toip_buff;
 		}
94393b2d
 	}
c5af2356
 
d00be11b
 	/* FIXME the callback is designed for outgoing requests but this along with
 	 * the callback registration at the begining of the function it's for a special
 	 * case - incoming CANCEL transactions; they were not traced before; TMCB_E2ECANCEL_IN
 	 * will throw the incoming request through this function and the callback in the beginning
 	 * will make sure the reply for this cancel is caught */
 	if (unlikely(type == TMCB_E2ECANCEL_IN)) {
 		sto.dir = "in";
 	} else {
 		sto.dir = "out";
 	}
c5af2356
 
c0c67b7e
 #ifdef STATISTICS
94393b2d
 	sto.stat = siptrace_req;
c0c67b7e
 #endif
c5af2356
 
13378d72
 	if (info->uriState == STRACE_RAW_URI) {
 		LM_BUG("uriState must be either UNUSED or PARSED here! must be a bug! Message won't be traced!\n");
 		return;
 	}
 
 	sip_trace_store(&sto, info->uriState == STRACE_PARSED_URI ? &info->u.dest_info : NULL, NULL);
c0c67b7e
 	return;
 }
 
0504bf23
 static void trace_onreply_in(struct cell *t, int type, struct tmcb_params *ps)
c0c67b7e
 {
f9b98c64
 	siptrace_data_t sto;
13378d72
 	siptrace_info_t* info;
94393b2d
 	sip_msg_t *msg;
 	sip_msg_t *req;
95d56e98
 	char statusbuf[INT2STR_MAX_LEN];
e2cf6343
 
0504bf23
 	if(t == NULL || t->uas.request == 0 || ps == NULL) {
55e41ddd
 		LM_DBG("no uas request, local transaction\n");
c0c67b7e
 		return;
 	}
 
f2b1df44
 	req = ps->req;
c0c67b7e
 	msg = ps->rpl;
1b319682
 	if((type != TMCB_ACK_NEG_IN) && (msg == NULL || req == NULL)) {
55e41ddd
 		LM_DBG("no reply\n");
c0c67b7e
 		return;
 	}
13378d72
 	info = (siptrace_info_t *)(*ps->param);
 
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
c5af2356
 
0504bf23
 	if(traced_user_avp.n != 0)
 		sto.avp = search_first_avp(traced_user_avp_type, traced_user_avp,
94393b2d
 				&sto.avp_value, &sto.state);
f2b1df44
 
1b319682
 	if((type != TMCB_ACK_NEG_IN) && ((sto.avp == NULL) && trace_is_off(req))) {
 		LM_DBG("trace off... %d %d\n", sto.avp == NULL, trace_is_off(req));
c0c67b7e
 		return;
 	}
f2b1df44
 
971b79fe
 	if(sip_trace_msg_attrs(msg, &sto) < 0) {
f2b1df44
 		return;
971b79fe
 	}
f2b1df44
 
94393b2d
 	sto.body.s = msg->buf;
 	sto.body.len = msg->len;
f2b1df44
 
95d56e98
 	sto.status.s = int2strbuf(ps->code, statusbuf, INT2STR_MAX_LEN, &sto.status.len);
 	if(sto.status.s == 0) {
 		LM_ERR("failure to get the status string\n");
 		return;
 	}
94393b2d
 
2fc3be57
 	sto.fromip.len = snprintf(sto.fromip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 			siptrace_proto_name(msg->rcv.proto),
 			ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port);
 	if(sto.fromip.len<0 || sto.fromip.len>=SIPTRACE_ADDR_MAX) {
 		LM_ERR("failed to format fromip buffer (%d)\n", sto.fromip.len);
 		sto.fromip.s = SIPTRACE_ANYADDR;
 		sto.fromip.len = SIPTRACE_ANYADDR_LEN;
 	} else {
 		sto.fromip.s = sto.fromip_buff;
 	}
c5af2356
 
eae8e7c1
 	if(trace_local_ip.s && trace_local_ip.len > 0) {
94393b2d
 		sto.toip = trace_local_ip;
eae8e7c1
 	} else {
2fc3be57
 		sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(msg->rcv.proto),
 				ip_addr2a(&msg->rcv.dst_ip), (int)msg->rcv.dst_port);
 		if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 			sto.toip.s = SIPTRACE_ANYADDR;
 			sto.toip.len = SIPTRACE_ANYADDR_LEN;
 		} else {
 			sto.toip.s = sto.toip_buff;
 		}
f2b1df44
 	}
c5af2356
 
94393b2d
 	sto.dir = "in";
c5af2356
 
0cf2a2de
 #ifdef STATISTICS
94393b2d
 	sto.stat = siptrace_rpl;
0cf2a2de
 #endif
c5af2356
 
13378d72
 	if (info->uriState == STRACE_RAW_URI) {
971b79fe
 		LM_BUG("uriState must be either UNUSED or PARSED here - skip tracing!\n");
13378d72
 		return;
 	}
 
971b79fe
 	sip_trace_store(&sto, (info->uriState == STRACE_PARSED_URI)
 			? &info->u.dest_info : NULL, NULL);
f2b1df44
 	return;
c0c67b7e
 }
 
0504bf23
 static void trace_onreply_out(struct cell *t, int type, struct tmcb_params *ps)
c0c67b7e
 {
f9b98c64
 	siptrace_data_t sto;
13378d72
 	siptrace_info_t* info;
c0c67b7e
 	int faked = 0;
ee7496f1
 	int parsed_f = 0;
0504bf23
 	struct sip_msg *msg;
 	struct sip_msg *req;
c0c67b7e
 	struct ip_addr to_ip;
95d56e98
 	char statusbuf[INT2STR_MAX_LEN];
f9b98c64
 	dest_info_t *dst;
c0c67b7e
 
0504bf23
 	if(t == NULL || t->uas.request == 0 || ps == NULL) {
55e41ddd
 		LM_DBG("no uas request, local transaction\n");
c0c67b7e
 		return;
 	}
c5af2356
 
0504bf23
 	if(ps->flags & TMCB_RETR_F) {
94393b2d
 		LM_DBG("retransmission\n");
 		return;
 	}
13378d72
 
 	info = (siptrace_info_t *)(*ps->param);
 
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
030d88e7
 
d00be11b
 	/* can't(don't know) set FL_SIPTRACE flag from trace_onreq_out because
 	 * there no access to CANCEL transaction there */
 	if (likely(type != TMCB_RESPONSE_READY)) {
 		if(traced_user_avp.n != 0)
 			sto.avp = search_first_avp(traced_user_avp_type, traced_user_avp,
 					&sto.avp_value, &sto.state);
 
 		if((sto.avp == NULL) && trace_is_off(t->uas.request)) {
 			LM_DBG("trace off...\n");
 			return;
 		}
c0c67b7e
 	}
c5af2356
 
d1053847
 	req = ps->req;
c0c67b7e
 	msg = ps->rpl;
0504bf23
 	if(msg == NULL || msg == FAKED_REPLY) {
c0c67b7e
 		msg = t->uas.request;
 		faked = 1;
ee7496f1
 		/* check if from header has been already parsed.
 		 * If not we have to parse it in pkg memory and free it at the end.
 		 */
 		if (msg->from && msg->from->parsed == NULL)
 			parsed_f = 1;
c0c67b7e
 	}
 
971b79fe
 	if(sip_trace_msg_attrs(msg, &sto) < 0) {
0f461ee2
 		goto end;
971b79fe
 	}
c0c67b7e
 
0504bf23
 	if(faked == 0) {
 		if(ps->send_buf.len > 0) {
94393b2d
 			sto.body = ps->send_buf;
0504bf23
 		} else if(t->uas.response.buffer != NULL) {
94393b2d
 			sto.body.s = t->uas.response.buffer;
 			sto.body.len = t->uas.response.buffer_len;
0504bf23
 		} else if(msg->len > 0) {
94393b2d
 			sto.body.s = msg->buf;
 			sto.body.len = msg->len;
c0c67b7e
 		} else {
94393b2d
 			sto.body.s = "No reply buffer";
0504bf23
 			sto.body.len = sizeof("No reply buffer") - 1;
c0c67b7e
 		}
 	} else {
0504bf23
 		if(ps->send_buf.len > 0) {
94393b2d
 			sto.body = ps->send_buf;
0504bf23
 		} else if(t->uas.response.buffer != NULL) {
94393b2d
 			sto.body.s = t->uas.response.buffer;
 			sto.body.len = t->uas.response.buffer_len;
c0c67b7e
 		} else {
94393b2d
 			sto.body.s = "No reply buffer";
0504bf23
 			sto.body.len = sizeof("No reply buffer") - 1;
c0c67b7e
 		}
 	}
c5af2356
 
eae8e7c1
 	if(trace_local_ip.s && trace_local_ip.len > 0) {
94393b2d
 		sto.fromip = trace_local_ip;
eae8e7c1
 	} else {
2fc3be57
 		sto.fromip.len = snprintf(sto.fromip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(msg->rcv.proto),
 				ip_addr2a(&req->rcv.dst_ip), (int)req->rcv.dst_port);
 		if(sto.fromip.len<0 || sto.fromip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format fromip buffer (%d)\n", sto.fromip.len);
 			sto.fromip.s = SIPTRACE_ANYADDR;
 			sto.fromip.len = SIPTRACE_ANYADDR_LEN;
 		} else {
 			sto.fromip.s = sto.fromip_buff;
 		}
c0c67b7e
 	}
c5af2356
 
95d56e98
 	sto.status.s = int2strbuf(ps->code, statusbuf, INT2STR_MAX_LEN, &sto.status.len);
 	if(sto.status.s == 0) {
 		LM_ERR("failure to get the status string\n");
0f461ee2
 		goto end;
95d56e98
 	}
c5af2356
 
c0c67b7e
 	memset(&to_ip, 0, sizeof(struct ip_addr));
94393b2d
 	dst = ps->dst;
0504bf23
 	if(dst == 0) {
2ae4d19a
 		sto.toip.s = SIPTRACE_ANYADDR;
 		sto.toip.len = SIPTRACE_ANYADDR_LEN;
c0c67b7e
 	} else {
 		su2ip_addr(&to_ip, &dst->to);
2fc3be57
 		sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(dst->proto),
 				ip_addr2a(&to_ip), (int)su_getport(&dst->to));
 		if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 			sto.toip.s = SIPTRACE_ANYADDR;
 			sto.toip.len = SIPTRACE_ANYADDR_LEN;
 		} else {
 			sto.toip.s = sto.toip_buff;
 		}
c0c67b7e
 	}
c5af2356
 
94393b2d
 	sto.dir = "out";
c5af2356
 
0cf2a2de
 #ifdef STATISTICS
94393b2d
 	sto.stat = siptrace_rpl;
0cf2a2de
 #endif
c0c67b7e
 
13378d72
 	if (info->uriState == STRACE_RAW_URI) {
 		LM_BUG("uriState must be either UNUSED or PARSED here! must be a bug! Message won't be traced!\n");
ee7496f1
 		goto end;
13378d72
 	}
 
 	sip_trace_store(&sto, info->uriState == STRACE_PARSED_URI ? &info->u.dest_info : NULL, NULL);
ee7496f1
 
 end:
 	if (faked && parsed_f) {
 		free_from(msg->from->parsed);
0f461ee2
 		msg->from->parsed = NULL;
ee7496f1
 	}
c0c67b7e
 }
 
1b319682
 static void trace_tm_neg_ack_in(struct cell *t, int type, struct tmcb_params *ps)
 {
13378d72
 	siptrace_info_t* info = (siptrace_info_t *)(*ps->param);
 
1b319682
 	LM_DBG("storing negative ack...\n");
 	/* this condition should not exist but there seems to be a BUG in kamailio
 	 * letting requests other than the ACK inside */
 	if (ps->req->first_line.u.request.method_value != METHOD_ACK) {
 		return;
 	}
 
13378d72
 	if (info->uriState == STRACE_RAW_URI) {
 		LM_BUG("uriState must be either UNUSED or PARSED here! must be a bug! Message won't be traced!\n");
 		return;
 	}
 
83758719
 
e8d76561
 	sip_trace(ps->req, (info->uriState == STRACE_PARSED_URI) ? &info->u.dest_info : NULL,
 			NULL, NULL);
1b319682
 }
 
13378d72
 /**
  * if any param inside info structure is NULL or has 0 length it will not be added
  * if no param set data will have allocated 2 bytes and length 0
  * if at least one param has length > 0
  *
  * data format:
  *
  * | total length | duri_length | duri*   | corr id length | corr id*
  * | 2 bytes      | 2 bytes     | x bytes | 2 bytes        | x bytes
  * params marked with * are optional
  *
  */
2482f95e
 static int trace_add_info_xavp(siptrace_info_t* info)
fa7eb2ab
 {
796a12d6
 	sr_xval_t xval;
13378d72
 
 	if (info == NULL) {
fa7eb2ab
 		LM_ERR("Nothing to serialize!\n");
 		return -1;
 	}
 
13378d72
 	if (info->uriState != STRACE_RAW_URI) {
 		LM_BUG("URI should be in raw format here\n");
fa7eb2ab
 		return -1;
 	}
 
796a12d6
 	memset(&xval, 0, sizeof(sr_xval_t));
 	xval.type = SR_XTYPE_VPTR;
 	xval.v.vptr = (void *)info;
13378d72
 
796a12d6
 	/* save data into avp */
2482f95e
 	if (xavp_add_value(&trace_xavp_info_name_s, &xval, NULL) == NULL) {
796a12d6
 		shm_free(info);
 		LM_ERR("Failed to add xavp!\n");
13378d72
 		return -1;
 	}
 
 	return 0;
 }
 
2482f95e
 static inline int trace_parse_raw_uri(siptrace_info_t* info)
13378d72
 {
 	dest_info_t dest_info;
 
 	if (info == NULL) {
 		LM_ERR("bad function call\n");
 		return -1;
 	}
 
 	if (info->uriState != STRACE_RAW_URI) {
 		LM_ERR("Invalid call! siptrace_info must contain a sip uri string!\n");
 		return -1;
 	}
 
 	/* parse uri and get dest_info structure */
2482f95e
 	if (siptrace_parse_uri(&info->u.dup_uri, &dest_info) < 0) {
13378d72
 		LM_ERR("failed to parse uri!\n");
 		return -1;
 	}
 
 	info->u.dest_info = dest_info;
 	info->uriState = STRACE_PARSED_URI;
 
 	return 0;
 }
 
7a7ee280
 static void trace_sl_ack_in(sl_cbp_t *slcbp)
5a2652fd
 {
7a7ee280
 	sip_msg_t *req;
5a2652fd
 	LM_DBG("storing ack...\n");
7a7ee280
 	req = slcbp->req;
fa7eb2ab
 	sip_trace(req, 0, NULL, NULL);
5a2652fd
 }
 
7a7ee280
 static void trace_sl_onreply_out(sl_cbp_t *slcbp)
c0c67b7e
 {
7a7ee280
 	sip_msg_t *req;
f9b98c64
 	siptrace_data_t sto;
 	sip_msg_t *msg;
 	ip_addr_t to_ip;
95d56e98
 	char statusbuf[INT2STR_MAX_LEN];
c0c67b7e
 
0504bf23
 	if(slcbp == NULL || slcbp->req == NULL) {
55e41ddd
 		LM_ERR("bad parameters\n");
94393b2d
 		return;
c0c67b7e
 	}
7a7ee280
 	req = slcbp->req;
c5af2356
 
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
0504bf23
 	if(traced_user_avp.n != 0)
 		sto.avp = search_first_avp(traced_user_avp_type, traced_user_avp,
94393b2d
 				&sto.avp_value, &sto.state);
030d88e7
 
0504bf23
 	if((sto.avp == NULL) && trace_is_off(req)) {
55e41ddd
 		LM_DBG("trace off...\n");
c0c67b7e
 		return;
 	}
c5af2356
 
c0c67b7e
 	msg = req;
 
971b79fe
 	if(sip_trace_msg_attrs(msg, &sto) < 0) {
c0c67b7e
 		return;
971b79fe
 	}
c5af2356
 
0504bf23
 	sto.body.s = (slcbp->reply) ? slcbp->reply->s : "";
 	sto.body.len = (slcbp->reply) ? slcbp->reply->len : 0;
c5af2356
 
94393b2d
 	if(trace_local_ip.len > 0) {
 		sto.fromip = trace_local_ip;
eae8e7c1
 	} else {
2e460814
 		sto.fromip.len = snprintf(sto.fromip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(req->rcv.proto),
 				ip_addr2a(&req->rcv.dst_ip), req->rcv.dst_port);
 		if(sto.fromip.len<0 || sto.fromip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format toip buffer (%d)\n", sto.fromip.len);
2ae4d19a
 			sto.fromip.s = SIPTRACE_ANYADDR;
 			sto.fromip.len = SIPTRACE_ANYADDR_LEN;
2e460814
 		} else {
 			sto.fromip.s = sto.fromip_buff;
 		}
d1053847
 	}
 
95d56e98
 	sto.status.s = int2strbuf(slcbp->code, statusbuf, INT2STR_MAX_LEN, &sto.status.len);
 	if(sto.status.s == 0) {
 		LM_ERR("failure to get the status string\n");
 		return;
 	}
c5af2356
 
c0c67b7e
 	memset(&to_ip, 0, sizeof(struct ip_addr));
0504bf23
 	if(slcbp->dst == 0) {
2ae4d19a
 		sto.toip.s = SIPTRACE_ANYADDR;
 		sto.toip.len = SIPTRACE_ANYADDR_LEN;
c0c67b7e
 	} else {
7a7ee280
 		su2ip_addr(&to_ip, &slcbp->dst->to);
2e460814
 		sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 				siptrace_proto_name(req->rcv.proto), ip_addr2a(&to_ip),
 				(int)su_getport(&slcbp->dst->to));
 		if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 			LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
2ae4d19a
 			sto.toip.s = SIPTRACE_ANYADDR;
 			sto.toip.len = SIPTRACE_ANYADDR_LEN;
2e460814
 		} else {
 			sto.toip.s = sto.toip_buff;
 		}
c0c67b7e
 	}
c5af2356
 
94393b2d
 	sto.dir = "out";
c5af2356
 
0cf2a2de
 #ifdef STATISTICS
94393b2d
 	sto.stat = siptrace_rpl;
0cf2a2de
 #endif
c5af2356
 
ca276bb7
 	sip_trace_store(&sto, NULL, NULL);
c0c67b7e
 	return;
 }
 
796a12d6
 static void trace_transaction(sip_msg_t* msg, siptrace_info_t* info, int dlg_tran)
fa7eb2ab
 {
313fc935
 	if(msg == NULL) {
 		LM_DBG("nothing to trace\n");
 		return;
 	}
 
fa7eb2ab
 	/* trace current message on out */
 	msg->msg_flags |= FL_SIPTRACE;
13378d72
 	if (info->uriState == STRACE_RAW_URI) {
2482f95e
 		if (trace_parse_raw_uri(info) < 0) {
13378d72
 			LM_ERR("failed to parse trace destination uri!\n");
 			return;
 		}
 	}
fa7eb2ab
 
 	if(tmb.register_tmcb(msg, 0, TMCB_REQUEST_SENT, trace_onreq_out, info, 0) <= 0) {
 		LM_ERR("can't register trace_onreq_out\n");
 		return;
 	}
 
 	/* trace reply on in */
 	if(tmb.register_tmcb(msg, 0, TMCB_RESPONSE_IN, trace_onreply_in, info, 0) <= 0) {
 		LM_ERR("can't register trace_onreply_in\n");
 		return;
 	}
 
 	/* trace reply on out */
796a12d6
 	if(tmb.register_tmcb(msg, 0, TMCB_RESPONSE_SENT, trace_onreply_out, info,
2482f95e
 							dlg_tran ? 0 : trace_free_info)
fa7eb2ab
 			<= 0) {
 		LM_ERR("can't register trace_onreply_out\n");
 		return;
 	}
 
 	/* TODO */
 	/* check the following callbacks: TMCB_REQUEST_PENDING, TMCB_RESPONSE_READY, TMCB_ACK_NEG_IN */
1b319682
 	/* trace reply on in */
 	if(tmb.register_tmcb(msg, 0, TMCB_ACK_NEG_IN, trace_tm_neg_ack_in, info, 0) <= 0) {
 		LM_ERR("can't register trace_onreply_in\n");
 		return;
 	}
d00be11b
 
e28f4644
 	if(tmb.register_tmcb(msg, 0, TMCB_E2ECANCEL_IN, trace_cancel_in, info, 0) <= 0) {
d00be11b
 		LM_ERR("can't register trace_onreply_in\n");
 		return;
 	}
fa7eb2ab
 }
 
 //static void trace_dialog(sip_msg_t* msg, siptrace_info_t* info)
 static void trace_dialog(struct dlg_cell* dlg, int type, struct dlg_cb_params *params)
 {
796a12d6
 	sr_xavp_t* xavp;
fa7eb2ab
 
 	if (!dlgb.get_dlg) {
 		LM_ERR("Dialog API not loaded! Trace off...\n");
 		return;
 	}
 
 	/* request - params->req */
 	if (params == NULL || params->req == NULL) {
 		LM_ERR("Invalid args!\n");
 		return;
 	}
 
 	if (!(params->req->msg_flags & FL_SIPTRACE)) {
26f68412
 		LM_DBG("Trace is off for this request...\n");
fa7eb2ab
 		return;
 	}
 
2482f95e
 	xavp = xavp_get(&trace_xavp_info_name_s, NULL);
796a12d6
 	if (!xavp) {
26f68412
 		/* this actually happens when only the transaction is traced
 		 * FL_SIPTRACE is set from trace_onreq_out
 		 * but xavp is set only for dialogs so this will avoid
 		 * registering dialog callbacks which is the desired behavior */
 		LM_DBG("%.*s xavp not registered! "
2482f95e
 				"Probably incoming E2E CANCEL!\n", trace_xavp_info_name_s.len,
 				trace_xavp_info_name_s.s);
fa7eb2ab
 		return;
 	}
 
 	if(dlgb.register_dlgcb(dlg, DLGCB_REQ_WITHIN,
796a12d6
 				trace_dialog_transaction, xavp->val.v.vptr, 0) != 0) {
6138877f
 		LM_ERR("Failed to register DLGCB_REQ_WITHIN callback!\n");
fa7eb2ab
 		return;
 	}
 
 	if(dlgb.register_dlgcb(dlg, DLGCB_TERMINATED,
2482f95e
 				trace_dialog_transaction, xavp->val.v.vptr, trace_free_info) != 0) {
fa7eb2ab
 		LM_ERR("Failed to register DLGCB_TERMINATED callback!\n");
 		return;
 	}
 
 	return;
 }
 
 
 static void trace_dialog_transaction(struct dlg_cell* dlg, int type, struct dlg_cb_params *params)
 {
13378d72
 	siptrace_info_t* info;
 
c49b50a2
 	/* coverity fix - there shouldn't be a scenario for this to happen */
796a12d6
 	if (params == NULL || params->param == NULL) {
 		LM_ERR("NULL dialog params!\n");
c49b50a2
 		return;
 	}
 
fd17c99e
 	/**
 	 * DUAL BYE - internally generated BYE from kamailio
 	 * set flag to signal request_in callback which will register
 	 * transaction callbacks to catch caller and callee BYEs and their
 	 * responses
 	 */
 	if (params->req == NULL && params->rpl == NULL) {
 		LM_DBG("dual bye!\n");
 		return;
 	}
796a12d6
 	info = (siptrace_info_t *)*params->param;
fd17c99e
 
796a12d6
 	trace_transaction(params->req, info, 1);
fa7eb2ab
 
13378d72
 	sip_trace(params->req, &info->u.dest_info, &info->correlation_id, NULL);
fa7eb2ab
 }
 
2482f95e
 static void trace_free_info(void* trace_info)
fa7eb2ab
 {
 	if (!trace_info) return;
 
 	shm_free(trace_info);
 }
 
f39eca3d
 static int siptrace_exec_evcb_msg(siptrace_data_t *sto)
 {
 	int backup_rt;
 	run_act_ctx_t ctx;
 	run_act_ctx_t *bctx;
 	sr_kemi_eng_t *keng = NULL;
 	str evname = str_init("siptrace:msg");
 	sip_msg_t msg;
 
 	if(_siptrace_evrt_msg_idx < 0 && _siptrace_evcb_msg.len<=0) {
 		return 0;
 	}
 
 	if(sto == NULL || sto->body.s == NULL || sto->body.len <= 0) {
 		return -1;
 	}
 
 	memset(&msg, 0, sizeof(sip_msg_t));
 	msg.buf = sto->body.s;
 	msg.len = sto->body.len;
 	if(parse_msg(msg.buf, msg.len, &msg) != 0) {
 		LM_DBG("parse_msg failed\n");
 		return -1;
 	}
 
 	backup_rt = get_route_type();
 	set_route_type(EVENT_ROUTE);
 	init_run_actions_ctx(&ctx);
 
 	if(_siptrace_evrt_msg_idx>=0) {
ef992449
 		run_top_route(event_rt.rlist[_siptrace_evrt_msg_idx], &msg, &ctx);
f39eca3d
 	} else {
 		keng = sr_kemi_eng_get();
 		if (keng!=NULL) {
 			bctx = sr_kemi_act_ctx_get();
 			sr_kemi_act_ctx_set(&ctx);
 			(void)sr_kemi_route(keng, &msg, EVENT_ROUTE,
 						&_siptrace_evcb_msg, &evname);
 			sr_kemi_act_ctx_set(bctx);
 		}
 	}
 
 	free_sip_msg(&msg);
 	set_route_type(backup_rt);
 	if(ctx.run_flags & DROP_R_F) {
 		return DROP_R_F;
 	}
 	return RETURN_R_F;
 }
 
57e7b28b
 /**
  *
  */
fa162f9b
 int siptrace_net_data_recv(sr_event_param_t *evp)
57e7b28b
 {
 	sr_net_info_t *nd;
f9b98c64
 	siptrace_data_t sto;
1109fcfb
 	sip_msg_t tmsg;
57e7b28b
 
0504bf23
 	if(evp->data == 0)
57e7b28b
 		return -1;
 
6704c511
 	if(trace_on_flag != NULL && *trace_on_flag==0) {
 		return 0;
 	}
 
0504bf23
 	nd = (sr_net_info_t *)evp->data;
1109fcfb
 	if(nd->rcv == NULL || nd->data.s == NULL || nd->data.len <= 0) {
57e7b28b
 		return -1;
1109fcfb
 	}
57e7b28b
 
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
57e7b28b
 
0504bf23
 	sto.body.s = nd->data.s;
57e7b28b
 	sto.body.len = nd->data.len;
 
3430db51
 	sto.fromip.len = snprintf(sto.fromip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 			siptrace_proto_name(nd->rcv->proto),
 			ip_addr2a(&nd->rcv->src_ip), (int)nd->rcv->src_port);
 	if(sto.fromip.len<0 || sto.fromip.len>=SIPTRACE_ADDR_MAX) {
 		LM_ERR("failed to format toip buffer (%d)\n", sto.fromip.len);
 		sto.fromip.s = SIPTRACE_ANYADDR;
 		sto.fromip.len = SIPTRACE_ANYADDR_LEN;
 	} else {
 		sto.fromip.s = sto.fromip_buff;
 	}
 
 	sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
 			siptrace_proto_name(nd->rcv->proto), ip_addr2a(&nd->rcv->dst_ip),
 			(int)nd->rcv->dst_port);
 	if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 		LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 		sto.toip.s = SIPTRACE_ANYADDR;
 		sto.toip.len = SIPTRACE_ANYADDR_LEN;
 	} else {
 		sto.toip.s = sto.toip_buff;
 	}
57e7b28b
 
 	sto.dir = "in";
 
f39eca3d
 	if(siptrace_exec_evcb_msg(&sto) == DROP_R_F) {
 		/* drop() used in event_route - all done */
ff2ff19a
 		LM_DBG("skipping processing message due to drop\n");
f39eca3d
 		return 0;
 	}
 
ff2ff19a
 	LM_DBG("processing message mode %d\n", _siptrace_mode);
 
1109fcfb
 	if(_siptrace_mode & SIPTRACE_MODE_HEP) {
 		trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL, NULL);
 	}
 
 	if(_siptrace_mode & SIPTRACE_MODE_DB) {
 		memset(&tmsg, 0, sizeof(sip_msg_t));
 		tmsg.buf = sto.body.s;
 		tmsg.len = sto.body.len;
 
 		if (parse_msg(tmsg.buf, tmsg.len, &tmsg)!=0) {
5ac49634
 			LM_DBG("msg buffer parsing failed!\n");
1109fcfb
 			goto afterdb;
 		}
 
c840fa6e
 		if(tmsg.first_line.type==SIP_REQUEST) {
 			if(!IS_SIP(&tmsg)) {
 				LM_DBG("non sip request message\n");
 				free_sip_msg(&tmsg);
 				goto afterdb;
 			}
 		} else if(tmsg.first_line.type==SIP_REPLY) {
 			if(!IS_SIP_REPLY(&tmsg)) {
 				LM_DBG("non sip reply message\n");
 				free_sip_msg(&tmsg);
 				goto afterdb;
 			}
 		} else {
 			LM_DBG("unknown sip message type %d\n", tmsg.first_line.type);
 			free_sip_msg(&tmsg);
 			goto afterdb;
 		}
 
971b79fe
 		if(sip_trace_msg_attrs(&tmsg, &sto) < 0) {
1109fcfb
 			free_sip_msg(&tmsg);
 			goto afterdb;
 		}
 
 		if(tmsg.first_line.type == SIP_REPLY) {
 			sto.status = tmsg.first_line.u.reply.status;
 		} else {
 			sto.status.s = "";
 			sto.status.len = 0;
 		}
 
 		gettimeofday(&sto.tv, NULL);
 		sip_trace_store_db(&sto);
 
 		free_sip_msg(&tmsg);
 	}
 
 afterdb:
 	if(_siptrace_mode & SIPTRACE_MODE_URI) {
 		trace_send_duplicate(sto.body.s, sto.body.len, NULL);
 	}
 
57e7b28b
 	return 0;
 }
 
1771f7e4
 /**
  *
  */
e1570a11
 int siptrace_net_data_sent(sr_event_param_t *evp)
1771f7e4
 {
 	sr_net_info_t *nd;
f9b98c64
 	dest_info_t new_dst;
 	siptrace_data_t sto;
1109fcfb
 	sip_msg_t tmsg;
a5f88102
 	int proto;
1771f7e4
 
0504bf23
 	if(evp->data == 0)
1771f7e4
 		return -1;
 
6704c511
 	if(trace_on_flag != NULL && *trace_on_flag==0) {
 		return 0;
 	}
 
0504bf23
 	nd = (sr_net_info_t *)evp->data;
 	if(nd->dst == NULL || nd->data.s == NULL || nd->data.len <= 0)
1771f7e4
 		return -1;
 
0504bf23
 	new_dst = *nd->dst;
929a24f0
 
 	if(new_dst.send_sock == 0) {
 		new_dst.send_sock = get_send_socket(0, &nd->dst->to, nd->dst->proto);
 	}
1771f7e4
 
f9b98c64
 	memset(&sto, 0, sizeof(siptrace_data_t));
1771f7e4
 
0504bf23
 	sto.body.s = nd->data.s;
1771f7e4
 	sto.body.len = nd->data.len;
 
0504bf23
 	if(unlikely(new_dst.send_sock == 0)) {
1771f7e4
 		LM_WARN("no sending socket found\n");
2ae4d19a
 		strcpy(sto.fromip_buff, SIPTRACE_ANYADDR);
 		sto.fromip.len = SIPTRACE_ANYADDR_LEN;
a5f88102
 		proto = PROTO_UDP;
1771f7e4
 	} else {
8f51d6b1
 		if(new_dst.send_sock->sock_str.len>=SIPTRACE_ADDR_MAX-1) {
 			LM_ERR("socket string is too large: %d\n",
 					new_dst.send_sock->sock_str.len);
 			goto error;
 		}
1771f7e4
 		strncpy(sto.fromip_buff, new_dst.send_sock->sock_str.s,
0504bf23
 				new_dst.send_sock->sock_str.len);
8f51d6b1
 		sto.fromip.len = new_dst.send_sock->sock_str.len;
a5f88102
 		proto = new_dst.send_sock->proto;
1771f7e4
 	}
 	sto.fromip.s = sto.fromip_buff;
 
3430db51
 	sto.toip.len = snprintf(sto.toip_buff, SIPTRACE_ADDR_MAX, "%s:%s:%d",
a5f88102
 			siptrace_proto_name(proto),
3430db51
 			suip2a(&new_dst.to, sizeof(new_dst.to)),
8f51d6b1
 			(int)su_getport(&new_dst.to));
3430db51
 	if(sto.toip.len<0 || sto.toip.len>=SIPTRACE_ADDR_MAX) {
 		LM_ERR("failed to format toip buffer (%d)\n", sto.toip.len);
 		sto.toip.s = SIPTRACE_ANYADDR;
 		sto.toip.len = SIPTRACE_ANYADDR_LEN;
 	} else {
 		sto.toip.s = sto.toip_buff;
 	}
1771f7e4
 
 	sto.dir = "out";
 
f39eca3d
 	if(siptrace_exec_evcb_msg(&sto) == DROP_R_F) {
 		/* drop() used in event_route - all done */
ff2ff19a
 		LM_DBG("skipping processing message due to drop\n");
f39eca3d
 		return 0;
 	}
 
ff2ff19a
 	LM_DBG("processing message mode %d\n", _siptrace_mode);
 
1109fcfb
 	if(_siptrace_mode & SIPTRACE_MODE_HEP) {
 		trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL, NULL);
 	}
 
 	if(_siptrace_mode & SIPTRACE_MODE_DB) {
 		memset(&tmsg, 0, sizeof(sip_msg_t));
 		tmsg.buf = sto.body.s;
 		tmsg.len = sto.body.len;
 
 		if (parse_msg(tmsg.buf, tmsg.len, &tmsg)!=0) {
5ac49634
 			LM_DBG("msg buffer parsing failed!\n");
1109fcfb
 			goto afterdb;
 		}
 
c840fa6e
 		if(tmsg.first_line.type==SIP_REQUEST) {
 			if(!IS_SIP(&tmsg)) {
 				LM_DBG("non sip request message\n");
 				free_sip_msg(&tmsg);
 				goto afterdb;
 			}
 		} else if(tmsg.first_line.type==SIP_REPLY) {
 			if(!IS_SIP_REPLY(&tmsg)) {
 				LM_DBG("non sip reply message\n");
 				free_sip_msg(&tmsg);
 				goto afterdb;
 			}
 		} else {
 			LM_DBG("unknown sip message type %d\n", tmsg.first_line.type);
 			free_sip_msg(&tmsg);
 			goto afterdb;
 		}
 
971b79fe
 		if(sip_trace_msg_attrs(&tmsg, &sto) < 0) {
1109fcfb
 			free_sip_msg(&tmsg);
 			goto afterdb;
 		}
 
 		if(tmsg.first_line.type == SIP_REPLY) {
 			sto.status = tmsg.first_line.u.reply.status;
 		} else {
 			sto.status.s = "";
 			sto.status.len = 0;
 		}
 
 		gettimeofday(&sto.tv, NULL);
 		sip_trace_store_db(&sto);
 
 		free_sip_msg(&tmsg);
 	}
 
 afterdb:
 	if(_siptrace_mode & SIPTRACE_MODE_URI) {
 		trace_send_duplicate(sto.body.s, sto.body.len, NULL);
 	}
 
1771f7e4
 	return 0;
8f51d6b1
 
 error:
 	return -1;
1771f7e4
 }
 
5addc451
 /**
  *
  */
0504bf23
 static int w_hlog1(struct sip_msg *msg, char *message, char *_)
 {
 	str smessage;
 	if(fixup_get_svalue(msg, (gparam_t *)message, &smessage) != 0) {
 		LM_ERR("unable to parse the message\n");
 		return -1;
 	}
 	return hlog(msg, NULL, &smessage);
 }
 
5addc451
 /**
  *
  */
 static int ki_hlog(sip_msg_t *msg, str *message)
 {
 	return hlog(msg, NULL, message);
 }
 
 /**
  *
  */
0504bf23
 static int w_hlog2(struct sip_msg *msg, char *correlationid, char *message)
 {
 	str scorrelationid, smessage;
 	if(fixup_get_svalue(msg, (gparam_t *)correlationid, &scorrelationid) != 0) {
 		LM_ERR("unable to parse the correlation id\n");
 		return -1;
 	}
 	if(fixup_get_svalue(msg, (gparam_t *)message, &smessage) != 0) {
 		LM_ERR("unable to parse the message\n");
 		return -1;
 	}
 	return hlog(msg, &scorrelationid, &smessage);
 }
 
5addc451
 /**
  *
  */
 static int ki_hlog_cid(sip_msg_t *msg, str *correlationid, str *message)
 {
 	return hlog(msg, correlationid, message);
 }
 
 /**
  *
  */
0504bf23
 static void siptrace_rpc_status(rpc_t *rpc, void *c)
 {
9b1c2348
 	str status = {0, 0};
 
0504bf23
 	if(rpc->scan(c, "S", &status) < 1) {
9b1c2348
 		rpc->fault(c, 500, "Not enough parameters (on, off or check)");
 		return;
 	}
 
0504bf23
 	if(trace_on_flag == NULL) {
9b1c2348
 		rpc->fault(c, 500, "Internal error");
 		return;
 	}
 
0504bf23
 	if(strncasecmp(status.s, "on", strlen("on")) == 0) {
9b1c2348
 		*trace_on_flag = 1;
13dd700b
 		rpc->rpl_printf(c, "Enabled");
9b1c2348
 		return;
 	}
0504bf23
 	if(strncasecmp(status.s, "off", strlen("off")) == 0) {
9b1c2348
 		*trace_on_flag = 0;
13dd700b
 		rpc->rpl_printf(c, "Disabled");
9b1c2348
 		return;
 	}
0504bf23
 	if(strncasecmp(status.s, "check", strlen("check")) == 0) {
13dd700b
 		rpc->rpl_printf(c, *trace_on_flag ? "Enabled" : "Disabled");
9b1c2348
 		return;
47e8d437
 	}
9b1c2348
 	rpc->fault(c, 500, "Bad parameter (on, off or check)");
 	return;
 }
 
0504bf23
 static const char *siptrace_status_doc[2] = {
ddb9171c
 	"Get status or turn on/off siptrace. Parameters: on, off or check.",
 	0
9b1c2348
 };
 
 rpc_export_t siptrace_rpc[] = {
 	{"siptrace.status", siptrace_rpc_status, siptrace_status_doc, 0},
 	{0, 0, 0, 0}
 };
 
 static int siptrace_init_rpc(void)
 {
0504bf23
 	if(rpc_register_array(siptrace_rpc) != 0) {
9b1c2348
 		LM_ERR("failed to register RPC commands\n");
 		return -1;
 	}
 	return 0;
 }
5addc451
 
 /**
  *
  */
 /* clang-format off */
 static sr_kemi_t sr_kemi_siptrace_exports[] = {
 	{ str_init("siptrace"), str_init("sip_trace"),
 		SR_KEMIP_INT, ki_sip_trace,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("siptrace"), str_init("sip_trace_dst"),
 		SR_KEMIP_INT, ki_sip_trace_dst,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("siptrace"), str_init("sip_trace_dst_cid"),
 		SR_KEMIP_INT, ki_sip_trace_dst_cid,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
fa7eb2ab
 	{ str_init("siptrace"), str_init("sip_trace_dst_cid_type"),
 		SR_KEMIP_INT, ki_sip_trace_dst_cid_flag,
4b1b3502
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
fa7eb2ab
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
5addc451
 	{ str_init("siptrace"), str_init("hlog"),
 		SR_KEMIP_INT, ki_hlog,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("siptrace"), str_init("hlog_cid"),
 		SR_KEMIP_INT, ki_hlog_cid,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
929ff145
 	{ str_init("siptrace"), str_init("sip_trace_mode"),
 		SR_KEMIP_INT, ki_sip_trace_mode,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
5addc451
 
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
 /* clang-format on */
 
 /**
  *
  */
 int mod_register(char *path, int *dlflags, void *p1, void *p2)
 {
 	sr_kemi_modules_add(sr_kemi_siptrace_exports);
 	return 0;
 }