/* * Registrar module interface * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of Kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify * 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 * * Kamailio is distributed in the hope that it will be useful, * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /*! * \defgroup registrar Registrar :: SIP Registrar support * The module contains REGISTER processing logic. */ /*! * \file * \brief SIP registrar module - interface * \ingroup registrar * * - Module: \ref registrar */ #include <stdio.h> #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" #include "../../modules/usrloc/usrloc.h" #include "../../core/counters.h" #include "../../core/utils/sruid.h" #include "../../modules/sl/sl.h" #include "../../core/mod_fix.h" #include "../../core/kemi.h" #include "save.h" #include "api.h" #include "lookup.h" #include "regpv.h" #include "reply.h" #include "registrar.h" #include "config.h" MODULE_VERSION usrloc_api_t ul;/*!< Structure containing pointers to usrloc functions*/ /*! \brief Module init & destroy function */ static int mod_init(void); static int child_init(int); static void mod_destroy(void); 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); static int w_lookup(struct sip_msg* _m, char* _d, char* _p2); static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _p2); static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2); static int w_registered(struct sip_msg* _m, char* _d, char* _uri); static int w_unregister(struct sip_msg* _m, char* _d, char* _uri); static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid); static int w_registered3(struct sip_msg* _m, char* _d, char* _uri, char* _flags); static int w_registered4(struct sip_msg* _m, char* _d, char* _uri, char* _flags, char* _actionflags); static int w_reg_send_reply(sip_msg_t* _m, char* _p1, char* _p2); /*! \brief Fixup functions */ static int domain_fixup(void** param, int param_no); static int domain_uri_fixup(void** param, int param_no); static int save_fixup(void** param, int param_no); static int unreg_fixup(void** param, int param_no); static int fetchc_fixup(void** param, int param_no); static int registered_fixup(void** param, int param_no); /*! \brief Functions */ static int w_add_sock_hdr(struct sip_msg* msg, char *str, char *foo); /*!< 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; int path_check_local = 0; /* sruid to get internal uid */ sruid_t _reg_sruid; int reg_gruu_enabled = 1; int reg_outbound_mode = 0; int reg_regid_mode = 0; int reg_flow_timer = 0; int contact_max_size = 512; /* max size of contact URIs */ str match_callid_name = str_init("match_callid"); str match_received_name = str_init("match_received"); str match_contact_name = str_init("match_contact"); char* rcv_avp_param = 0; unsigned short rcv_avp_type = 0; int_str rcv_avp_name; str reg_xavp_cfg = {0}; str reg_xavp_rcd = {0}; int reg_xavp_rcd_mask = 0; int reg_use_domain = 0; int sock_flag = -1; str sock_hdr_name = {0,0}; int reg_sock_mode = 0; /* where to go for event route ("usrloc:contact-expired") */ int reg_expire_event_rt = -1; /* default disabled */ str reg_event_callback = STR_NULL; int reg_lookup_filter_mode = 0; int reg_min_expires_mode = 0; sr_kemi_eng_t *keng = NULL; #define RCV_NAME "received" str rcv_param = str_init(RCV_NAME); stat_var *accepted_registrations; stat_var *rejected_registrations; stat_var *max_expires_stat; stat_var *max_contacts_stat; stat_var *default_expire_stat; stat_var *default_expire_range_stat; stat_var *expire_range_stat; /** SL API structure */ sl_api_t slb; /*! \brief * Exported PV */ static pv_export_t mod_pvs[] = { { {"ulc", sizeof("ulc")-1}, PVT_OTHER, pv_get_ulc, pv_set_ulc, pv_parse_ulc_name, pv_parse_index, 0, 0 }, { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } }; /*! \brief * Exported functions */ static cmd_export_t cmds[] = { {"save", (cmd_function)w_save2, 1, save_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE }, {"save", (cmd_function)w_save2, 2, save_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE }, {"save", (cmd_function)w_save3, 3, save_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE }, {"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 }, {"lookup_to_dset", (cmd_function)w_lookup_to_dset, 1, domain_uri_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"lookup_to_dset", (cmd_function)w_lookup_to_dset, 2, domain_uri_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"registered", (cmd_function)w_registered, 1, domain_uri_fixup, 0, ANY_ROUTE }, {"registered", (cmd_function)w_registered, 2, domain_uri_fixup, 0, ANY_ROUTE }, {"registered", (cmd_function)w_registered3, 3, registered_fixup, 0, ANY_ROUTE }, {"registered", (cmd_function)w_registered4, 4, registered_fixup, 0, ANY_ROUTE }, {"add_sock_hdr", (cmd_function)w_add_sock_hdr, 1, fixup_spve_null, 0, REQUEST_ROUTE }, {"unregister", (cmd_function)w_unregister, 2, unreg_fixup, 0, ANY_ROUTE }, {"unregister", (cmd_function)w_unregister2, 3, unreg_fixup, 0, ANY_ROUTE }, {"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3, fetchc_fixup, 0, REQUEST_ROUTE| FAILURE_ROUTE }, {"reg_free_contacts", (cmd_function)pv_free_contacts, 1, fixup_str_null, 0, REQUEST_ROUTE| FAILURE_ROUTE }, {"lookup_branches", (cmd_function)w_lookup_branches, 1, domain_uri_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"reg_send_reply", (cmd_function)w_reg_send_reply, 0, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"bind_registrar", (cmd_function)bind_registrar, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }; /*! \brief * Exported parameters */ static param_export_t params[] = { {"default_expires", INT_PARAM, &default_registrar_cfg.default_expires }, {"default_expires_range", INT_PARAM, &default_registrar_cfg.default_expires_range }, {"expires_range", INT_PARAM, &default_registrar_cfg.expires_range }, {"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 }, /* {"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag }, */ {"realm_prefix", PARAM_STR, &default_registrar_cfg.realm_pref }, {"min_expires", INT_PARAM, &default_registrar_cfg.min_expires }, {"max_expires", INT_PARAM, &default_registrar_cfg.max_expires }, {"received_param", PARAM_STR, &rcv_param }, {"received_avp", PARAM_STRING, &rcv_avp_param }, {"max_contacts", INT_PARAM, &default_registrar_cfg.max_contacts }, {"retry_after", INT_PARAM, &default_registrar_cfg.retry_after }, {"sock_mode", PARAM_INT, ®_sock_mode }, {"sock_flag", INT_PARAM, &sock_flag }, {"sock_hdr_name", PARAM_STR, &sock_hdr_name }, {"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 }, {"path_check_local", INT_PARAM, &path_check_local }, {"xavp_cfg", PARAM_STR, ®_xavp_cfg }, {"xavp_rcd", PARAM_STR, ®_xavp_rcd }, {"xavp_rcd_mask", INT_PARAM, ®_xavp_rcd_mask }, {"gruu_enabled", INT_PARAM, ®_gruu_enabled }, {"outbound_mode", INT_PARAM, ®_outbound_mode }, {"regid_mode", INT_PARAM, ®_regid_mode }, {"flow_timer", INT_PARAM, ®_flow_timer }, {"contact_max_size", INT_PARAM, &contact_max_size }, {"event_callback", PARAM_STR, ®_event_callback }, {"lookup_filter_mode", INT_PARAM, ®_lookup_filter_mode }, {"min_expires_mode", PARAM_INT, ®_min_expires_mode }, {"use_expired_contacts", INT_PARAM, &default_registrar_cfg.use_expired_contacts }, {0, 0, 0} }; /*! \brief We expose internal variables via the statistic framework below.*/ 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 }, {"default_expires_range", STAT_NO_RESET, &default_expire_range_stat }, {"expires_range", STAT_NO_RESET, &expire_range_stat }, {"accepted_regs", 0, &accepted_registrations }, {"rejected_regs", 0, &rejected_registrations }, {0, 0, 0} }; /*! \brief * Module exports structure */ struct module_exports exports = { "registrar", /* module name */ DEFAULT_DLFLAGS, /* dlopen flags */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported rpc functions */ mod_pvs, /* exported pseudo-variables */ 0, /* response handling function */ mod_init, /* module initialization function */ child_init, /* per-child init function */ mod_destroy /* destroy function */ }; /*! \brief * Initialize parent */ static int mod_init(void) { pv_spec_t avp_spec; str s; bind_usrloc_t bind_usrloc; qvalue_t dq; if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC) < 0) { return -1; } #ifdef STATISTICS /* register statistics */ if (register_module_stats( exports.name, mod_stats)!=0 ) { LM_ERR("Failed to register core statistics\n"); return -1; } #endif /* bind the SL API */ if (sl_load_api(&slb)!=0) { LM_ERR("Cannot bind to SL API. Please load the SL module before" " loading this module.\n"); return -1; } if(cfg_declare("registrar", registrar_cfg_def, &default_registrar_cfg, cfg_sizeof(registrar), ®istrar_cfg)){ LM_ERR("Failed to declare the configuration parameters.\n"); return -1; } if (rcv_avp_param && *rcv_avp_param) { s.s = rcv_avp_param; s.len = strlen(s.s); if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %s AVP definition\n", rcv_avp_param); return -1; } if(pv_get_avp_name(0, &avp_spec.pvp, &rcv_avp_name, &rcv_avp_type)!=0) { LM_ERR("[%s]- invalid AVP definition\n", rcv_avp_param); return -1; } } else { rcv_avp_name.n = 0; rcv_avp_type = 0; } bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LM_ERR("Can't bind to the usrloc module." "Please load it before this module.\n"); return -1; } /* Normalize default_q parameter */ dq = cfg_get(registrar, registrar_cfg, default_q); 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; } } cfg_get(registrar, registrar_cfg, default_q) = dq; if (bind_usrloc(&ul) < 0) { return -1; } 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); } } if (reg_expire_event_rt>=0 || (reg_event_callback.s!=NULL && keng !=NULL)) { set_child_rpc_sip_mode(); if(ul.register_ulcb(UL_CONTACT_EXPIRE, reg_ul_expired_contact, 0)< 0) { LM_ERR("Can not register callback for expired contacts" " (usrloc module)\n"); return -1; } } } /* * Import use_domain parameter from usrloc */ reg_use_domain = ul.use_domain; if (sock_hdr_name.s) { if (sock_hdr_name.len==0 || sock_flag==-1) { LM_INFO("empty sock_hdr_name or sock_flag not set -> resetting\n"); sock_hdr_name.len = 0; sock_flag = -1; } } else if (reg_xavp_cfg.s) { if (reg_xavp_cfg.len == 0 || sock_flag == -1) { LM_DBG("empty reg_xavp_cfg or sock_flag not set -> resetting\n"); sock_flag = -1; } } else if (sock_flag!=-1) { LM_INFO("sock_flag defined but no sock_hdr_name" " or no reg_xavp_cfg -> resetting flag\n"); sock_flag = -1; } if (reg_outbound_mode < 0 || reg_outbound_mode > 2) { LM_ERR("outbound_mode modparam must be 0 (not supported)," " 1 (supported), or 2 (supported and required)\n"); return -1; } if (reg_regid_mode < 0 || reg_regid_mode > 1) { LM_ERR("regid_mode modparam must be 0 (use with outbound)," " 1 (use always)\n"); return -1; } if (reg_flow_timer < 0 || reg_flow_timer > REG_FLOW_TIMER_MAX || (reg_flow_timer > 0 && reg_outbound_mode == REG_OUTBOUND_NONE)) { LM_ERR("bad value for flow_timer\n"); return -1; } /* fix the flags */ sock_flag = (sock_flag!=-1)?(1<<sock_flag):0; tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<<tcp_persistent_flag):0; set_aor_case_sensitive(cfg_get(registrar, registrar_cfg, case_sensitive)); return 0; } static int child_init(int rank) { if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC)<0) return -1; if (rank==1) { /* init stats */ //TODO if parameters are modified via cfg framework do i change them? 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); } return 0; } /*! \brief * Wrapper to save(location) */ static int w_save2(struct sip_msg* _m, char* _d, char* _cflags) { 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); } /*! \brief * Wrapper to lookup(location) */ static int w_lookup(struct sip_msg* _m, char* _d, char* _uri) { str uri = {0}; if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) { LM_ERR("invalid uri parameter\n"); return -1; } return lookup(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL); } /*! \brief * Wrapper to lookup_to_dset(location) */ static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _uri) { str uri = {0}; if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) { LM_ERR("invalid uri parameter\n"); return -1; } return lookup_to_dset(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL); } /*! \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); } 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); } static int w_registered(struct sip_msg* _m, char* _d, char* _uri) { str uri = {0}; if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) { LM_ERR("invalid uri parameter\n"); return -1; } return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL); } 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); } static int w_registered3(struct sip_msg* _m, char* _d, char* _uri, char* _flags) { str uri = {0}; int flags = 0; if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) { 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); } 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); } static int w_registered4(struct sip_msg* _m, char* _d, char* _uri, char* _flags, char* _actionflags) { str uri = {0}; int flags = 0; int actionflags = 0; if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) { 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; } if(_actionflags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_actionflags, &actionflags)) < 0) { LM_ERR("invalid action flag parameter\n"); return -1; } return registered4(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags, actionflags); } 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); } static int w_unregister(struct sip_msg* _m, char* _d, char* _uri) { str uri = {0}; if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0) { LM_ERR("invalid uri parameter\n"); return -1; } return unregister(_m, (udomain_t*)_d, &uri, NULL); } 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); } static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid) { str uri = {0, 0}; str ruid = {0}; if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0) { LM_ERR("invalid uri parameter\n"); 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); } 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); } /*! * */ 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); } /*! \brief * 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) { LM_ERR("failed to register domain\n"); return E_UNSPEC; } *param = (void*)d; } return 0; } /*! \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; } 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; } /*! \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) { return domain_fixup(param, 1); } else if (param_no == 2) { return fixup_spve_null(param, 1); } else if (param_no == 3) { return fixup_spve_null(param, 1); } return 0; } /*! \brief * 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); } else if (param_no == 2) { s.s = (char*)*param; s.len = strlen(s.s); flags = 0; if ( (strno2int(&s, &flags )<0) || (flags>REG_SAVE_ALL_FL) ) { LM_ERR("bad flags <%s>\n", (char *)(*param)); return E_CFG; } if (ul.db_mode==DB_ONLY && flags®_SAVE_MEM_FL) { LM_ERR("MEM flag set while using the DB_ONLY mode in USRLOC\n"); return E_CFG; } pkg_free(*param); *param = (void*)(unsigned long int)flags; } else if (param_no == 3) { return fixup_spve_null(param, 1); } return 0; } /*! \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; } static void mod_destroy(void) { free_contact_buf(); } #include "../../core/data_lump.h" #include "../../core/ip_addr.h" #include "../../core/ut.h" static int ki_add_sock_hdr(sip_msg_t* msg, str *hdr_name) { struct socket_info* si; struct lump* anchor; str hdr; char *p; if(hdr_name==NULL || hdr_name->s==NULL || hdr_name->len<=0) { LM_ERR("invalid header name parameter\n"); return -1; } si = msg->rcv.bind_address; if (parse_headers( msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse message\n"); goto error; } anchor = anchor_lump( msg, msg->unparsed-msg->buf, 0, 0); if (anchor==0) { LM_ERR("can't get anchor\n"); goto error; } hdr.len = hdr_name->len + 2 + si->sock_str.len + CRLF_LEN; if ( (hdr.s=(char*)pkg_malloc(hdr.len))==0 ) { LM_ERR("no more pkg mem\n"); goto error; } p = hdr.s; memcpy( p, hdr_name->s, hdr_name->len); p += hdr_name->len; *(p++) = ':'; *(p++) = ' '; memcpy( p, si->sock_str.s, si->sock_str.len); p += si->sock_str.len; memcpy( p, CRLF, CRLF_LEN); p += CRLF_LEN; if ( p-hdr.s!=hdr.len ) { LM_CRIT("buffer overflow (%d!=%d)\n", (int)(long)(p-hdr.s),hdr.len); goto error1; } if (insert_new_lump_before( anchor, hdr.s, hdr.len, 0) == 0) { LM_ERR("can't insert lump\n"); goto error1; } return 1; error1: pkg_free(hdr.s); error: return -1; } 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); } void default_expires_stats_update(str* gname, str* name) { update_stat(default_expire_stat, cfg_get(registrar, registrar_cfg, default_expires)); } void max_expires_stats_update(str* gname, str* name) { update_stat(max_expires_stat, cfg_get(registrar, registrar_cfg, max_expires)); } void default_expires_range_update(str* gname, str* name) { update_stat(default_expire_range_stat, cfg_get(registrar, registrar_cfg, default_expires_range)); } void expires_range_update(str* gname, str* name){ update_stat(expire_range_stat, cfg_get(registrar, registrar_cfg, expires_range)); } /** * */ /* clang-format off */ 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 } }, { 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 } }, { 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 } }, { 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 } }, { str_init("registrar"), str_init("reg_free_contacts"), 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 } }, { 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 } }, { 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 } }, { {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_registrar_exports); return 0; }