src/modules/registrar/registrar.c
982b9d7a
 /*
31ccf6a2
  * Registrar module interface
  *
  * Copyright (C) 2001-2003 FhG Fokus
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
31ccf6a2
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
31ccf6a2
  * 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,
31ccf6a2
  * 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.
  *
90350e2a
  * 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
31ccf6a2
  *
  */
 
d847357a
 /*!
35882b72
  * \defgroup registrar Registrar :: SIP Registrar support
d847357a
  * The module contains REGISTER processing logic.
90350e2a
  */
d847357a
 
 /*!
  * \file
  * \brief SIP registrar module - interface
90350e2a
  * \ingroup registrar
35882b72
  *
  * - Module: \ref registrar
90350e2a
  */
d847357a
 
31ccf6a2
 #include <stdio.h>
cf83221d
 #include "../../core/sr_module.h"
 #include "../../core/timer.h"
 #include "../../core/dprint.h"
 #include "../../core/error.h"
 #include "../../core/socket_info.h"
 #include "../../core/pvar.h"
 #include "../../core/dset.h"
63a09d85
 #include "../../modules/usrloc/usrloc.h"
cf83221d
 #include "../../core/counters.h"
b2201096
 #include "../../core/utils/sruid.h"
1a9a0d9b
 #include "../../modules/sl/sl.h"
cf83221d
 #include "../../core/mod_fix.h"
 #include "../../core/kemi.h"
8461dc65
 
31ccf6a2
 #include "save.h"
5befde48
 #include "api.h"
31ccf6a2
 #include "lookup.h"
7a67411c
 #include "regpv.h"
31ccf6a2
 #include "reply.h"
f635a60d
 #include "registrar.h"
0d3a8dc2
 #include "config.h"
31ccf6a2
 
 MODULE_VERSION
 
1828803f
 usrloc_api_t ul;/*!< Structure containing pointers to usrloc functions*/
31ccf6a2
 
d847357a
 /*! \brief Module init & destroy function */
bf3705d3
 static int  mod_init(void);
233c40ed
 static int  child_init(int);
bf3705d3
 static void mod_destroy(void);
3417a42c
 static int w_save2(struct sip_msg* _m, char* _d, char* _cflags);
 static int w_save3(struct sip_msg* _m, char* _d, char* _cflags, char* _uri);
5befde48
 static int w_lookup(struct sip_msg* _m, char* _d, char* _p2);
ccaa53b1
 static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _p2);
2ac602d3
 static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2);
3417a42c
 static int w_registered(struct sip_msg* _m, char* _d, char* _uri);
 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri);
0a919692
 static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid);
3b029441
 static int w_registered3(struct sip_msg* _m, char* _d, char* _uri, char* _flags);
23907981
 static int w_registered4(struct sip_msg* _m, char* _d, char* _uri, char* _flags,
 		char* _actionflags);
3c1c0c59
 static int w_reg_send_reply(sip_msg_t* _m, char* _p1, char* _p2);
5befde48
 
d847357a
 /*! \brief Fixup functions */
bf3705d3
 static int domain_fixup(void** param, int param_no);
3417a42c
 static int domain_uri_fixup(void** param, int param_no);
bf3705d3
 static int save_fixup(void** param, int param_no);
b235af63
 static int unreg_fixup(void** param, int param_no);
7a67411c
 static int fetchc_fixup(void** param, int param_no);
3b029441
 static int registered_fixup(void** param, int param_no);
d847357a
 /*! \brief Functions */
b7baf05b
 static int w_add_sock_hdr(struct sip_msg* msg, char *str, char *foo);
31ccf6a2
 
23907981
 /*!< if the TCP connection should be kept open */
 int tcp_persistent_flag = -1;
 /*!< if the looked up contacts should be filtered based on supported methods */
 int method_filtering = 0;
 /*!< if the Path HF should be handled */
 int path_enabled = 0;
 /*!< if the Path HF should be inserted in the reply.
 	*   - STRICT (2): always insert, error if no support indicated in request
 	*   - LAZY   (1): insert only if support indicated in request
 	*   - OFF    (0): never insert */
 int path_mode = PATH_MODE_STRICT;
 
 /*!< if the received- and nat-parameters of last Path uri should be used
 	* to determine if UAC is nat'ed */
 int path_use_params = 0;
d847357a
 
635f23b1
 int path_check_local = 0;
d847357a
 
fd9fe6e6
 /* sruid to get internal uid */
 sruid_t _reg_sruid;
 
21f1a378
 int reg_gruu_enabled = 1;
c486a935
 int reg_outbound_mode = 0;
50e9baf2
 int reg_regid_mode = 0;
e18905ea
 int reg_flow_timer = 0;
21f1a378
 
62ea33a6
 int contact_max_size = 512; /* max size of contact URIs */
eb6b9c6b
 
7ba770ca
 str match_callid_name = str_init("match_callid");
 str match_received_name = str_init("match_received");
 str match_contact_name = str_init("match_contact");
f0ed82ce
 
8d9d76ed
 char* rcv_avp_param = 0;
 unsigned short rcv_avp_type = 0;
 int_str rcv_avp_name;
31ccf6a2
 
71348e9c
 str reg_xavp_cfg = {0};
2e1a9d55
 str reg_xavp_rcd = {0};
9593e3fe
 int reg_xavp_rcd_mask = 0;
32f46645
 int reg_use_domain = 0;
31ccf6a2
 
 int sock_flag = -1;
 str sock_hdr_name = {0,0};
 
32bf022a
 int reg_sock_mode = 0;
e3ec71b4
 
83410304
 /* where to go for event route ("usrloc:contact-expired") */
 int reg_expire_event_rt = -1; /* default disabled */
98f05b7b
 str reg_event_callback = STR_NULL;
 
97f7d248
 int reg_lookup_filter_mode = 0;
7418625d
 int reg_min_expires_mode = 0;
97f7d248
 
98f05b7b
 sr_kemi_eng_t *keng = NULL;
83410304
 
31ccf6a2
 #define RCV_NAME "received"
bf3705d3
 str rcv_param = str_init(RCV_NAME);
31ccf6a2
 
f56ae82e
 stat_var *accepted_registrations;
 stat_var *rejected_registrations;
 stat_var *max_expires_stat;
 stat_var *max_contacts_stat;
 stat_var *default_expire_stat;
4480f807
 stat_var *default_expire_range_stat;
806e967e
 stat_var *expire_range_stat;
1a9a0d9b
 /** SL API structure */
 sl_api_t slb;
31ccf6a2
 
7a67411c
 /*! \brief
  * Exported PV
  */
 static pv_export_t mod_pvs[] = {
b162288d
 	{ {"ulc", sizeof("ulc")-1}, PVT_OTHER, pv_get_ulc, pv_set_ulc,
7a67411c
 		pv_parse_ulc_name, pv_parse_index, 0, 0 },
 	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
 };
 
31ccf6a2
 
d847357a
 /*! \brief
31ccf6a2
  * Exported functions
  */
 static cmd_export_t cmds[] = {
3417a42c
 	{"save",         (cmd_function)w_save2,       1,  save_fixup, 0,
e2376e34
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
3417a42c
 	{"save",         (cmd_function)w_save2,       2,  save_fixup, 0,
e2376e34
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
3417a42c
 	{"save",         (cmd_function)w_save3,       3,  save_fixup, 0,
e2376e34
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
3417a42c
 	{"lookup",       (cmd_function)w_lookup,      1,  domain_uri_fixup, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"lookup",       (cmd_function)w_lookup,      2,  domain_uri_fixup, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
ccaa53b1
 	{"lookup_to_dset",  (cmd_function)w_lookup_to_dset,  1,  domain_uri_fixup, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
09e1a72b
 	{"lookup_to_dset",  (cmd_function)w_lookup_to_dset,  2,  domain_uri_fixup, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
3417a42c
 	{"registered",   (cmd_function)w_registered,  1,  domain_uri_fixup, 0,
c3755580
 			ANY_ROUTE },
3417a42c
 	{"registered",   (cmd_function)w_registered,  2,  domain_uri_fixup, 0,
c3755580
 			ANY_ROUTE },
7ba770ca
 	{"registered",   (cmd_function)w_registered3, 3,  registered_fixup, 0,
c3755580
 			ANY_ROUTE },
7ba770ca
 	{"registered",   (cmd_function)w_registered4, 4,  registered_fixup, 0,
c3755580
 			ANY_ROUTE },
b7baf05b
 	{"add_sock_hdr", (cmd_function)w_add_sock_hdr,  1,  fixup_spve_null, 0,
0b7b6f4f
 			REQUEST_ROUTE },
3417a42c
 	{"unregister",   (cmd_function)w_unregister,  2,  unreg_fixup, 0,
0cc64de7
 			ANY_ROUTE },
0a919692
 	{"unregister",   (cmd_function)w_unregister2, 3, unreg_fixup, 0,
0cc64de7
 			ANY_ROUTE },
90350e2a
 	{"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3,
7a67411c
 			fetchc_fixup, 0,
 			REQUEST_ROUTE| FAILURE_ROUTE },
 	{"reg_free_contacts", (cmd_function)pv_free_contacts,   1,
 			fixup_str_null, 0,
 			REQUEST_ROUTE| FAILURE_ROUTE },
2ac602d3
 	{"lookup_branches",  (cmd_function)w_lookup_branches, 1,  domain_uri_fixup, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
3c1c0c59
 	{"reg_send_reply",   (cmd_function)w_reg_send_reply,  0, 0, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
5befde48
 	{"bind_registrar",  (cmd_function)bind_registrar,  0,
 		0, 0, 0},
80998a7f
 	{0, 0, 0, 0, 0, 0}
31ccf6a2
 };
 
 
d847357a
 /*! \brief
31ccf6a2
  * Exported parameters
  */
 static param_export_t params[] = {
4480f807
 	{"default_expires",    INT_PARAM, &default_registrar_cfg.default_expires     		},
 	{"default_expires_range", INT_PARAM, &default_registrar_cfg.default_expires_range	},
806e967e
 	{"expires_range",      INT_PARAM, &default_registrar_cfg.expires_range	},
4480f807
 	{"default_q",          INT_PARAM, &default_registrar_cfg.default_q			},
 	{"append_branches",    INT_PARAM, &default_registrar_cfg.append_branches		},
 	{"case_sensitive",     INT_PARAM, &default_registrar_cfg.case_sensitive			},
021e8d57
 	/*	{"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag }, */
a3db4686
 	{"realm_prefix",       PARAM_STR, &default_registrar_cfg.realm_pref          		},
4480f807
 	{"min_expires",        INT_PARAM, &default_registrar_cfg.min_expires			},
 	{"max_expires",        INT_PARAM, &default_registrar_cfg.max_expires			},
e3239f6f
 	{"received_param",     PARAM_STR, &rcv_param           					},
 	{"received_avp",       PARAM_STRING, &rcv_avp_param       					},
4480f807
 	{"max_contacts",       INT_PARAM, &default_registrar_cfg.max_contacts			},
 	{"retry_after",        INT_PARAM, &default_registrar_cfg.retry_after			},
32bf022a
 	{"sock_mode",          PARAM_INT, &reg_sock_mode						},
4480f807
 	{"sock_flag",          INT_PARAM, &sock_flag           					},
e3239f6f
 	{"sock_hdr_name",      PARAM_STR, &sock_hdr_name     					},
4480f807
 	{"method_filtering",   INT_PARAM, &method_filtering    					},
 	{"use_path",           INT_PARAM, &path_enabled        					},
 	{"path_mode",          INT_PARAM, &path_mode           					},
 	{"path_use_received",  INT_PARAM, &path_use_params     					},
23907981
 	{"path_check_local",   INT_PARAM, &path_check_local                     },
e3239f6f
 	{"xavp_cfg",           PARAM_STR, &reg_xavp_cfg     					},
 	{"xavp_rcd",           PARAM_STR, &reg_xavp_rcd     					},
9593e3fe
 	{"xavp_rcd_mask",      INT_PARAM, &reg_xavp_rcd_mask   					},
21f1a378
 	{"gruu_enabled",       INT_PARAM, &reg_gruu_enabled    					},
c486a935
 	{"outbound_mode",      INT_PARAM, &reg_outbound_mode					},
50e9baf2
 	{"regid_mode",         INT_PARAM, &reg_regid_mode					},
e18905ea
 	{"flow_timer",         INT_PARAM, &reg_flow_timer					},
eb6b9c6b
 	{"contact_max_size",   INT_PARAM, &contact_max_size					},
98f05b7b
 	{"event_callback",     PARAM_STR, &reg_event_callback				},
97f7d248
 	{"lookup_filter_mode", INT_PARAM, &reg_lookup_filter_mode			},
7418625d
 	{"min_expires_mode",   PARAM_INT, &reg_min_expires_mode				},
252d18a0
 	{"use_expired_contacts",  INT_PARAM, &default_registrar_cfg.use_expired_contacts	 },
31ccf6a2
 	{0, 0, 0}
 };
 
 
d847357a
 /*! \brief We expose internal variables via the statistic framework below.*/
f56ae82e
 stat_export_t mod_stats[] = {
 	{"max_expires",       STAT_NO_RESET, &max_expires_stat        },
 	{"max_contacts",      STAT_NO_RESET, &max_contacts_stat       },
 	{"default_expire",    STAT_NO_RESET, &default_expire_stat     },
4480f807
 	{"default_expires_range", STAT_NO_RESET, &default_expire_range_stat },
806e967e
 	{"expires_range",     STAT_NO_RESET, &expire_range_stat },
f56ae82e
 	{"accepted_regs",                 0, &accepted_registrations  },
 	{"rejected_regs",                 0, &rejected_registrations  },
 	{0, 0, 0}
 };
 
 
0d3a8dc2
 
d847357a
 /*! \brief
31ccf6a2
  * Module exports structure
  */
 struct module_exports exports = {
8f98b5ac
 	"registrar", /* module name */
51716422
 	DEFAULT_DLFLAGS, /* dlopen flags */
8f98b5ac
 	cmds,        /* exported functions */
 	params,      /* exported parameters */
 	0,           /* exported rpc functions */
7a67411c
 	mod_pvs,     /* exported pseudo-variables */
8f98b5ac
 	0,           /* response handling function */
31ccf6a2
 	mod_init,    /* module initialization function */
8f98b5ac
 	child_init,  /* per-child init function */
 	mod_destroy  /* destroy function */
31ccf6a2
 };
 
 
d847357a
 /*! \brief
31ccf6a2
  * Initialize parent
  */
 static int mod_init(void)
 {
b0a7f212
 	pv_spec_t avp_spec;
 	str s;
31ccf6a2
 	bind_usrloc_t bind_usrloc;
1a8ce8fd
 	qvalue_t dq;
31ccf6a2
 
0a296e5d
 	if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC) < 0) {
fd9fe6e6
 		return -1;
0a296e5d
 	}
fd9fe6e6
 
93154d27
 #ifdef STATISTICS
 	/* register statistics */
 	if (register_module_stats( exports.name, mod_stats)!=0 ) {
0a296e5d
 		LM_ERR("Failed to register core statistics\n");
93154d27
 		return -1;
 	}
 #endif
 
1a9a0d9b
 	/* bind the SL API */
 	if (sl_load_api(&slb)!=0) {
23907981
 		LM_ERR("Cannot bind to SL API. Please load the SL module before"
 				" loading this module.\n");
31ccf6a2
 		return -1;
 	}
90350e2a
 
23907981
 	if(cfg_declare("registrar", registrar_cfg_def, &default_registrar_cfg,
 				cfg_sizeof(registrar), &registrar_cfg)){
0a296e5d
 		LM_ERR("Failed to declare the configuration parameters.\n");
90350e2a
 		return -1;
0d3a8dc2
 	}
8d9d76ed
 
 	if (rcv_avp_param && *rcv_avp_param) {
b0a7f212
 		s.s = rcv_avp_param; s.len = strlen(s.s);
 		if (pv_parse_spec(&s, &avp_spec)==0
 				|| avp_spec.type!=PVT_AVP) {
387847d7
 			LM_ERR("malformed or non AVP %s AVP definition\n", rcv_avp_param);
8d9d76ed
 			return -1;
 		}
 
b0a7f212
 		if(pv_get_avp_name(0, &avp_spec.pvp, &rcv_avp_name, &rcv_avp_type)!=0)
8d9d76ed
 		{
387847d7
 			LM_ERR("[%s]- invalid AVP definition\n", rcv_avp_param);
8d9d76ed
 			return -1;
 		}
 	} else {
 		rcv_avp_name.n = 0;
 		rcv_avp_type = 0;
 	}
31ccf6a2
 
 	bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
 	if (!bind_usrloc) {
23907981
 		LM_ERR("Can't bind to the usrloc module."
 				"Please load it before this module.\n");
31ccf6a2
 		return -1;
 	}
 
30368e16
 	/* Normalize default_q parameter */
1a8ce8fd
 	dq = cfg_get(registrar, registrar_cfg, default_q);
c2b7096e
 	if ( dq!= Q_UNSPECIFIED) {
 		if (dq > MAX_Q) {
 			LM_DBG("default_q = %d, lowering to MAX_Q: %d\n", dq, MAX_Q);
 			dq = MAX_Q;
 		} else if (dq < MIN_Q) {
 			LM_DBG("default_q = %d, raising to MIN_Q: %d\n", dq, MIN_Q);
 			dq = MIN_Q;
31ccf6a2
 		}
 	}
c2b7096e
 	cfg_get(registrar, registrar_cfg, default_q) = dq;
31ccf6a2
 
 	if (bind_usrloc(&ul) < 0) {
 		return -1;
 	}
 
98f05b7b
 	if(ul.register_ulcb != NULL) {
 		if (reg_event_callback.s==NULL || reg_event_callback.len<=0 ) {
 			reg_expire_event_rt = route_lookup(&event_rt, "usrloc:contact-expired");
 			if (reg_expire_event_rt>=0 && event_rt.rlist[reg_expire_event_rt]==0)
 				reg_expire_event_rt=-1; /* disable */
 		} else {
 			keng = sr_kemi_eng_get();
 			if(keng==NULL) {
 				LM_DBG("event callback (%s) set, but no cfg engine\n",
 					reg_event_callback.s);
 			}
 		}
23907981
 		if (reg_expire_event_rt>=0 || (reg_event_callback.s!=NULL
 					&& keng !=NULL)) {
83410304
 			set_child_rpc_sip_mode();
 			if(ul.register_ulcb(UL_CONTACT_EXPIRE, reg_ul_expired_contact, 0)< 0)
 			{
23907981
 				LM_ERR("Can not register callback for expired contacts"
 						" (usrloc module)\n");
83410304
 				return -1;
 			}
 		}
 	}
30368e16
 	/*
bf3705d3
 	 * Import use_domain parameter from usrloc
30368e16
 	 */
32f46645
 	reg_use_domain = ul.use_domain;
31ccf6a2
 
 	if (sock_hdr_name.s) {
 		if (sock_hdr_name.len==0 || sock_flag==-1) {
ceff642b
 			LM_INFO("empty sock_hdr_name or sock_flag not set -> resetting\n");
31ccf6a2
 			sock_hdr_name.len = 0;
 			sock_flag = -1;
 		}
c46a5f27
 	} else if (reg_xavp_cfg.s) {
 		if (reg_xavp_cfg.len == 0 || sock_flag == -1) {
ceff642b
 			LM_DBG("empty reg_xavp_cfg or sock_flag not set -> resetting\n");
c46a5f27
 			sock_flag = -1;
 		}
31ccf6a2
 	} else if (sock_flag!=-1) {
23907981
 		LM_INFO("sock_flag defined but no sock_hdr_name"
 				" or no reg_xavp_cfg -> resetting flag\n");
31ccf6a2
 		sock_flag = -1;
 	}
30368e16
 
c486a935
 	if (reg_outbound_mode < 0 || reg_outbound_mode > 2) {
23907981
 		LM_ERR("outbound_mode modparam must be 0 (not supported),"
 				" 1 (supported), or 2 (supported and required)\n");
c486a935
 		return -1;
 	}
 
50e9baf2
 	if (reg_regid_mode < 0 || reg_regid_mode > 1) {
23907981
 		LM_ERR("regid_mode modparam must be 0 (use with outbound),"
 				" 1 (use always)\n");
50e9baf2
 		return -1;
 	}
 
e18905ea
 	if (reg_flow_timer < 0 || reg_flow_timer > REG_FLOW_TIMER_MAX
2a430028
 			|| (reg_flow_timer > 0 && reg_outbound_mode == REG_OUTBOUND_NONE)) {
e18905ea
 		LM_ERR("bad value for flow_timer\n");
 		return -1;
 	}
 
30368e16
 	/* fix the flags */
8f55b4c0
 	sock_flag = (sock_flag!=-1)?(1<<sock_flag):0;
 	tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<<tcp_persistent_flag):0;
31ccf6a2
 
acf0432c
 	set_aor_case_sensitive(cfg_get(registrar, registrar_cfg, case_sensitive));
 
233c40ed
 	return 0;
 }
 
 
 static int child_init(int rank)
 {
fd9fe6e6
 	if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC)<0)
 		return -1;
233c40ed
 	if (rank==1) {
 		/* init stats */
0d3a8dc2
 		//TODO if parameters are modified via cfg framework do i change them?
23907981
 		update_stat(max_expires_stat, default_registrar_cfg.max_expires);
 		update_stat(max_contacts_stat, default_registrar_cfg.max_contacts);
 		update_stat(default_expire_stat, default_registrar_cfg.default_expires);
233c40ed
 	}
f56ae82e
 
31ccf6a2
 	return 0;
 }
 
5befde48
 /*! \brief
  * Wrapper to save(location)
  */
3417a42c
 static int w_save2(struct sip_msg* _m, char* _d, char* _cflags)
5befde48
 {
3417a42c
 	return save(_m, (udomain_t*)_d, ((int)(unsigned long)_cflags), NULL);
 }
 
 /*! \brief
  * Wrapper to save(location)
  */
 static int w_save3(struct sip_msg* _m, char* _d, char* _cflags, char* _uri)
 {
 	str uri;
 	if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 
 	return save(_m, (udomain_t*)_d, ((int)(unsigned long)_cflags), &uri);
5befde48
 }
 
 /*! \brief
  * Wrapper to lookup(location)
  */
3417a42c
 static int w_lookup(struct sip_msg* _m, char* _d, char* _uri)
 {
 	str uri = {0};
23907981
 	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
 				|| uri.len<=0))
3417a42c
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 
 	return lookup(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
 }
 
ccaa53b1
 /*! \brief
  * Wrapper to lookup_to_dset(location)
  */
 static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _uri)
 {
 	str uri = {0};
23907981
 	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
 				|| uri.len<=0))
ccaa53b1
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 
 	return lookup_to_dset(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
 }
0a296e5d
 
2ac602d3
 /*! \brief
  * Wrapper to lookup_branches(location)
  */
 static int w_lookup_branches(sip_msg_t* _m, char* _d, char* _p2)
 {
 	return lookup_branches(_m, (udomain_t*)_d);
 }
 
 
69353523
 static int ki_lookup_branches(sip_msg_t* _m, str* _dtable)
 {
 	udomain_t* d;
 
 	if(ul.get_udomain(_dtable->s, &d)<0) {
 		LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
 		return -1;
 	}
 
 	return lookup_branches(_m, d);
 }
 
3417a42c
 static int w_registered(struct sip_msg* _m, char* _d, char* _uri)
 {
 	str uri = {0};
23907981
 	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
 				|| uri.len<=0))
3417a42c
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 	return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
 }
 
69353523
 static int ki_registered_uri(sip_msg_t* _m, str* _dtable, str* _uri)
 {
 	udomain_t* d;
 
 	if(ul.get_udomain(_dtable->s, &d)<0) {
 		LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
 		return -1;
 	}
 
 	return registered(_m, d, (_uri && _uri->len>0)?_uri:NULL);
 }
 
7ba770ca
 static int w_registered3(struct sip_msg* _m, char* _d, char* _uri, char* _flags)
 {
 	str uri = {0};
 	int flags = 0;
23907981
 	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
 				|| uri.len<=0))
7ba770ca
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 	if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0)
 	{
 		LM_ERR("invalid flags parameter\n");
 		return -1;
 	}
 	return registered3(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags);
 }
 
69353523
 static int ki_registered_flags(sip_msg_t* _m, str* _dtable, str* _uri, int _f)
 {
 	udomain_t* d;
 
 	if(ul.get_udomain(_dtable->s, &d)<0) {
 		LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
 		return -1;
 	}
 
 	return registered3(_m, d, (_uri && _uri->len>0)?_uri:NULL, _f);
 }
 
23907981
 static int w_registered4(struct sip_msg* _m, char* _d, char* _uri,
 		char* _flags, char* _actionflags)
7ba770ca
 {
 	str uri = {0};
 	int flags = 0;
 	int actionflags = 0;
23907981
 	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
 				|| uri.len<=0))
7ba770ca
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 	if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0)
 	{
 		LM_ERR("invalid flags parameter\n");
 		return -1;
 	}
23907981
 	if(_actionflags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_actionflags,
 					&actionflags)) < 0)
7ba770ca
 	{
 		LM_ERR("invalid action flag parameter\n");
 		return -1;
 	}
23907981
 	return registered4(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags,
 			actionflags);
7ba770ca
 }
 
69353523
 static int ki_registered_action(sip_msg_t* _m, str* _dtable, str* _uri,
 		int _f, int _aflags)
 {
 	udomain_t* d;
 
 	if(ul.get_udomain(_dtable->s, &d)<0) {
 		LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
 		return -1;
 	}
 
 	return registered4(_m, d, (_uri && _uri->len>0)?_uri:NULL, _f, _aflags);
 }
 
3417a42c
 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri)
5befde48
 {
3417a42c
 	str uri = {0};
 	if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)
 	{
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 
0a919692
 	return unregister(_m, (udomain_t*)_d, &uri, NULL);
 }
 
69353523
 static int ki_unregister(sip_msg_t* _m, str* _dtable, str* _uri)
 {
 	udomain_t* d;
 
 	if(_uri==NULL || _uri->len<=0) {
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 	if(ul.get_udomain(_dtable->s, &d)<0) {
 		LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
 		return -1;
 	}
 
 	return unregister(_m, d, _uri, NULL);
 }
 
0a919692
 static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid)
 {
90350e2a
 	str uri = {0, 0};
0a919692
 	str ruid = {0};
6c385398
 	if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0)
0a919692
 	{
90350e2a
 		LM_ERR("invalid uri parameter\n");
0a919692
 		return -1;
 	}
 	if(fixup_get_svalue(_m, (gparam_p)_ruid, &ruid)!=0 || ruid.len<=0)
 	{
 		LM_ERR("invalid ruid parameter\n");
 		return -1;
 	}
 
 	return unregister(_m, (udomain_t*)_d, &uri, &ruid);
5befde48
 }
31ccf6a2
 
69353523
 static int ki_unregister_ruid(sip_msg_t* _m, str* _dtable, str* _uri, str *_ruid)
 {
 	udomain_t* d;
 
 	if(_uri==NULL || _uri->len<=0) {
 		LM_ERR("invalid uri parameter\n");
 		return -1;
 	}
 	if(ul.get_udomain(_dtable->s, &d)<0) {
 		LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
 		return -1;
 	}
 
 	return unregister(_m, d, _uri, _ruid);
 }
 
3c1c0c59
 /*!
  *
  */
 static int ki_reg_send_reply(sip_msg_t* _m)
 {
 	int ret;
 	ret = reg_send_reply(_m);
 	return (ret==0)?1:ret;
 }
 
 /*!
  *
  */
 static int w_reg_send_reply(sip_msg_t* _m, char* _p1, char* _p2)
 {
 	return ki_reg_send_reply(_m);
 }
 
d847357a
 /*! \brief
31ccf6a2
  * Convert char* parameter to udomain_t* pointer
  */
 static int domain_fixup(void** param, int param_no)
 {
 	udomain_t* d;
 
 	if (param_no == 1) {
 		if (ul.register_udomain((char*)*param, &d) < 0) {
387847d7
 			LM_ERR("failed to register domain\n");
31ccf6a2
 			return E_UNSPEC;
 		}
 
 		*param = (void*)d;
 	}
 	return 0;
 }
 
3417a42c
 /*! \brief
  * Convert char* parameter to udomain_t* pointer
  */
 static int domain_uri_fixup(void** param, int param_no)
 {
 	if (param_no == 1) {
 		return domain_fixup(param, 1);
 	} else if (param_no == 2) {
 		return fixup_spve_null(param, 1);
 	}
 	return 0;
 }
 
7ba770ca
 static int registered_fixup(void** param, int param_no)
 {
 	if (param_no == 1) {
 		return domain_fixup(param, 1);
 	} else if (param_no == 2) {
 		return fixup_spve_null(param, 1);
 	} else if (param_no == 3) {
 		return fixup_igp_null(param, 1);
 	} else if (param_no == 4) {
 		return fixup_igp_null(param, 1);
 	}
 	return 0;
 }
3417a42c
 
b235af63
 /*! \brief
  * Convert char* parameter to udomain_t* pointer
  * Convert char* parameter to pv_elem_t* pointer
  */
 static int unreg_fixup(void** param, int param_no)
 {
 	if (param_no == 1) {
7a67411c
 		return domain_fixup(param, 1);
b235af63
 	} else if (param_no == 2) {
 		return fixup_spve_null(param, 1);
0a919692
 	} else if (param_no == 3) {
 		return fixup_spve_null(param, 1);
b235af63
 	}
 	return 0;
 }
 
 
bf3705d3
 
d847357a
 /*! \brief
bf3705d3
  * Fixup for "save" function - both domain and flags
  */
 static int save_fixup(void** param, int param_no)
 {
 	unsigned int flags;
 	str s;
 
 	if (param_no == 1) {
 		return domain_fixup(param,param_no);
3417a42c
 	} else if (param_no == 2) {
bf3705d3
 		s.s = (char*)*param;
 		s.len = strlen(s.s);
00503cf8
 		flags = 0;
bf3705d3
 		if ( (strno2int(&s, &flags )<0) || (flags>REG_SAVE_ALL_FL) ) {
387847d7
 			LM_ERR("bad flags <%s>\n", (char *)(*param));
bf3705d3
 			return E_CFG;
 		}
 		if (ul.db_mode==DB_ONLY && flags&REG_SAVE_MEM_FL) {
387847d7
 			LM_ERR("MEM flag set while using the DB_ONLY mode in USRLOC\n");
bf3705d3
 			return E_CFG;
 		}
 		pkg_free(*param);
 		*param = (void*)(unsigned long int)flags;
3417a42c
 	} else if (param_no == 3) {
 		return fixup_spve_null(param, 1);
bf3705d3
 	}
3417a42c
 	return 0;
bf3705d3
 }
 
7a67411c
 /*! \brief
  * Convert char* parameter to udomain_t* pointer
  * Convert char* parameter to pv_elem_t* pointer
  * Convert char* parameter to str* pointer
  */
 static int fetchc_fixup(void** param, int param_no)
 {
 	if (param_no == 1) {
 		return domain_fixup(param, 1);
 	} else if (param_no == 2) {
 		return fixup_spve_null(param, 1);
 	} else if (param_no == 3) {
 		return fixup_str_null(param, 1);
 	}
 	return 0;
 }
 
bf3705d3
 
31ccf6a2
 static void mod_destroy(void)
 {
 	free_contact_buf();
 }
 
 
cf83221d
 #include "../../core/data_lump.h"
 #include "../../core/ip_addr.h"
 #include "../../core/ut.h"
31ccf6a2
 
b7baf05b
 static int ki_add_sock_hdr(sip_msg_t* msg, str *hdr_name)
31ccf6a2
 {
f88eab5b
 	struct socket_info* si;
31ccf6a2
 	struct lump* anchor;
 	str hdr;
 	char *p;
 
b7baf05b
 	if(hdr_name==NULL || hdr_name->s==NULL || hdr_name->len<=0) {
 		LM_ERR("invalid header name parameter\n");
 		return -1;
 	}
f88eab5b
 	si = msg->rcv.bind_address;
31ccf6a2
 
b68fbcd1
 	if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
387847d7
 		LM_ERR("failed to parse message\n");
31ccf6a2
 		goto error;
 	}
 
 	anchor = anchor_lump( msg, msg->unparsed-msg->buf, 0, 0);
 	if (anchor==0) {
387847d7
 		LM_ERR("can't get anchor\n");
31ccf6a2
 		goto error;
 	}
 
f88eab5b
 	hdr.len = hdr_name->len + 2 + si->sock_str.len + CRLF_LEN;
31ccf6a2
 	if ( (hdr.s=(char*)pkg_malloc(hdr.len))==0 ) {
387847d7
 		LM_ERR("no more pkg mem\n");
31ccf6a2
 		goto error;
 	}
 
 	p = hdr.s;
 	memcpy( p, hdr_name->s, hdr_name->len);
 	p += hdr_name->len;
 	*(p++) = ':';
 	*(p++) = ' ';
3fbb9d7a
 
f88eab5b
 	memcpy( p, si->sock_str.s, si->sock_str.len);
 	p += si->sock_str.len;
3fbb9d7a
 
31ccf6a2
 	memcpy( p, CRLF, CRLF_LEN);
 	p += CRLF_LEN;
 
 	if ( p-hdr.s!=hdr.len ) {
387847d7
 		LM_CRIT("buffer overflow (%d!=%d)\n", (int)(long)(p-hdr.s),hdr.len);
31ccf6a2
 		goto error1;
 	}
 
 	if (insert_new_lump_before( anchor, hdr.s, hdr.len, 0) == 0) {
387847d7
 		LM_ERR("can't insert lump\n");
31ccf6a2
 		goto error1;
 	}
 
 	return 1;
 error1:
 	pkg_free(hdr.s);
 error:
 	return -1;
 }
 
b7baf05b
 static int w_add_sock_hdr(struct sip_msg* msg, char *name, char *foo)
 {
 	str hdr_name;
 	if(fixup_get_svalue(msg, (gparam_t*)name, &hdr_name)<0) {
 		LM_ERR("cannot get the header name\n");
 		return -1;
 	}
 	return ki_add_sock_hdr(msg, &hdr_name);
 }
 
23907981
 void default_expires_stats_update(str* gname, str* name)
 {
 	update_stat(default_expire_stat, cfg_get(registrar, registrar_cfg,
 				default_expires));
c2b7096e
 }
 
23907981
 void max_expires_stats_update(str* gname, str* name)
 {
 	update_stat(max_expires_stat, cfg_get(registrar, registrar_cfg,
 				max_expires));
c2b7096e
 }
4480f807
 
23907981
 void default_expires_range_update(str* gname, str* name)
 {
 	update_stat(default_expire_range_stat, cfg_get(registrar, registrar_cfg,
 				default_expires_range));
4480f807
 }
806e967e
 
 void expires_range_update(str* gname, str* name){
23907981
 	update_stat(expire_range_stat, cfg_get(registrar, registrar_cfg,
 				expires_range));
806e967e
 }
d8f6b975
 
 /**
  *
  */
49903d1c
 /* clang-format off */
d8f6b975
 static sr_kemi_t sr_kemi_registrar_exports[] = {
 	{ str_init("registrar"), str_init("save"),
 		SR_KEMIP_INT, regapi_save,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("save_uri"),
 		SR_KEMIP_INT, regapi_save_uri,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_STR,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("lookup"),
 		SR_KEMIP_INT, regapi_lookup,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("lookup_uri"),
 		SR_KEMIP_INT, regapi_lookup_uri,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("lookup_to_dset"),
 		SR_KEMIP_INT, regapi_lookup_to_dset,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
69353523
 	{ str_init("registrar"), str_init("lookup_branches"),
 		SR_KEMIP_INT, ki_lookup_branches,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
d8f6b975
 	{ str_init("registrar"), str_init("registered"),
 		SR_KEMIP_INT, regapi_registered,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
69353523
 	{ str_init("registrar"), str_init("registered_uri"),
 		SR_KEMIP_INT, ki_registered_uri,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("registered_flags"),
 		SR_KEMIP_INT, ki_registered_flags,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("registered_action"),
 		SR_KEMIP_INT, ki_registered_action,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
 			SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("set_q_override"),
 		SR_KEMIP_INT, regapi_set_q_override,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("add_sock_hdr"),
 		SR_KEMIP_INT, ki_add_sock_hdr,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("unregister"),
 		SR_KEMIP_INT, ki_unregister,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("unregister_ruid"),
 		SR_KEMIP_INT, ki_unregister_ruid,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("reg_fetch_contacts"),
 		SR_KEMIP_INT, ki_reg_fetch_contacts,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
c1677c39
 	{ str_init("registrar"), str_init("reg_free_contacts"),
69353523
 		SR_KEMIP_INT, ki_reg_free_contacts,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
3c1c0c59
 	{ str_init("registrar"), str_init("reg_send_reply"),
 		SR_KEMIP_INT, ki_reg_send_reply,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
69f33615
 	{ str_init("registrar"), str_init("ulc_rget"),
 		SR_KEMIP_XVAL, ki_reg_ulc_rget,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("registrar"), str_init("ulc_cget"),
 		SR_KEMIP_XVAL, ki_reg_ulc_cget,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
d8f6b975
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
49903d1c
 /* clang-format on */
d8f6b975
 
 /**
  *
  */
 int mod_register(char *path, int *dlflags, void *p1, void *p2)
 {
 	sr_kemi_modules_add(sr_kemi_registrar_exports);
 	return 0;
 }