4a9d6f53320e6e8473b3f2f2161d4a79dd1e6a73
[sip-router] / src / modules / registrar / registrar.c
1 /*
2  * Registrar module interface
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 /*!
25  * \defgroup registrar Registrar :: SIP Registrar support
26  * The module contains REGISTER processing logic.
27  */
28
29 /*!
30  * \file
31  * \brief SIP registrar module - interface
32  * \ingroup registrar
33  *
34  * - Module: \ref registrar
35  */
36
37 #include <stdio.h>
38 #include "../../core/sr_module.h"
39 #include "../../core/timer.h"
40 #include "../../core/dprint.h"
41 #include "../../core/error.h"
42 #include "../../core/socket_info.h"
43 #include "../../core/pvar.h"
44 #include "../../core/dset.h"
45 #include "../../modules/usrloc/usrloc.h"
46 #include "../../core/counters.h"
47 #include "../../lib/srutils/sruid.h"
48 #include "../../modules/sl/sl.h"
49 #include "../../core/mod_fix.h"
50 #include "../../core/kemi.h"
51
52 #include "save.h"
53 #include "api.h"
54 #include "lookup.h"
55 #include "regpv.h"
56 #include "reply.h"
57 #include "registrar.h"
58 #include "config.h"
59
60 MODULE_VERSION
61
62 usrloc_api_t ul;/*!< Structure containing pointers to usrloc functions*/
63
64 /*! \brief Module init & destroy function */
65 static int  mod_init(void);
66 static int  child_init(int);
67 static void mod_destroy(void);
68 static int w_save2(struct sip_msg* _m, char* _d, char* _cflags);
69 static int w_save3(struct sip_msg* _m, char* _d, char* _cflags, char* _uri);
70 static int w_lookup(struct sip_msg* _m, char* _d, char* _p2);
71 static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _p2);
72 static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2);
73 static int w_registered(struct sip_msg* _m, char* _d, char* _uri);
74 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri);
75 static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid);
76 static int w_registered3(struct sip_msg* _m, char* _d, char* _uri, char* _flags);
77 static int w_registered4(struct sip_msg* _m, char* _d, char* _uri, char* _flags,
78                 char* _actionflags);
79
80 /*! \brief Fixup functions */
81 static int domain_fixup(void** param, int param_no);
82 static int domain_uri_fixup(void** param, int param_no);
83 static int save_fixup(void** param, int param_no);
84 static int unreg_fixup(void** param, int param_no);
85 static int fetchc_fixup(void** param, int param_no);
86 static int registered_fixup(void** param, int param_no);
87 /*! \brief Functions */
88 static int w_add_sock_hdr(struct sip_msg* msg, char *str, char *foo);
89
90 /*!< if the TCP connection should be kept open */
91 int tcp_persistent_flag = -1;
92 /*!< if the looked up contacts should be filtered based on supported methods */
93 int method_filtering = 0;
94 /*!< if the Path HF should be handled */
95 int path_enabled = 0;
96 /*!< if the Path HF should be inserted in the reply.
97         *   - STRICT (2): always insert, error if no support indicated in request
98         *   - LAZY   (1): insert only if support indicated in request
99         *   - OFF    (0): never insert */
100 int path_mode = PATH_MODE_STRICT;
101
102 /*!< if the received- and nat-parameters of last Path uri should be used
103         * to determine if UAC is nat'ed */
104 int path_use_params = 0;
105
106 int path_check_local = 0;
107
108 /* sruid to get internal uid */
109 sruid_t _reg_sruid;
110
111 int reg_gruu_enabled = 1;
112 int reg_outbound_mode = 0;
113 int reg_regid_mode = 0;
114 int reg_flow_timer = 0;
115
116 int contact_max_size = 512; /* max size of contact URIs */
117
118 str match_callid_name = str_init("match_callid");
119 str match_received_name = str_init("match_received");
120 str match_contact_name = str_init("match_contact");
121
122 char* rcv_avp_param = 0;
123 unsigned short rcv_avp_type = 0;
124 int_str rcv_avp_name;
125
126 str reg_xavp_cfg = {0};
127 str reg_xavp_rcd = {0};
128
129 int reg_use_domain = 0;
130
131 int sock_flag = -1;
132 str sock_hdr_name = {0,0};
133
134 /* where to go for event route ("usrloc:contact-expired") */
135 int reg_expire_event_rt = -1; /* default disabled */
136 str reg_event_callback = STR_NULL;
137
138 int reg_lookup_filter_mode = 0;
139
140 sr_kemi_eng_t *keng = NULL;
141
142 #define RCV_NAME "received"
143 str rcv_param = str_init(RCV_NAME);
144
145 stat_var *accepted_registrations;
146 stat_var *rejected_registrations;
147 stat_var *max_expires_stat;
148 stat_var *max_contacts_stat;
149 stat_var *default_expire_stat;
150 stat_var *default_expire_range_stat;
151 stat_var *expire_range_stat;
152 /** SL API structure */
153 sl_api_t slb;
154
155 /*! \brief
156  * Exported PV
157  */
158 static pv_export_t mod_pvs[] = {
159         { {"ulc", sizeof("ulc")-1}, PVT_OTHER, pv_get_ulc, pv_set_ulc,
160                 pv_parse_ulc_name, pv_parse_index, 0, 0 },
161         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
162 };
163
164
165 /*! \brief
166  * Exported functions
167  */
168 static cmd_export_t cmds[] = {
169         {"save",         (cmd_function)w_save2,       1,  save_fixup, 0,
170                         REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
171         {"save",         (cmd_function)w_save2,       2,  save_fixup, 0,
172                         REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
173         {"save",         (cmd_function)w_save3,       3,  save_fixup, 0,
174                         REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
175         {"lookup",       (cmd_function)w_lookup,      1,  domain_uri_fixup, 0,
176                         REQUEST_ROUTE | FAILURE_ROUTE },
177         {"lookup",       (cmd_function)w_lookup,      2,  domain_uri_fixup, 0,
178                         REQUEST_ROUTE | FAILURE_ROUTE },
179         {"lookup_to_dset",  (cmd_function)w_lookup_to_dset,  1,  domain_uri_fixup, 0,
180                         REQUEST_ROUTE | FAILURE_ROUTE },
181         {"lookup_to_dset",  (cmd_function)w_lookup_to_dset,  2,  domain_uri_fixup, 0,
182                         REQUEST_ROUTE | FAILURE_ROUTE },
183         {"registered",   (cmd_function)w_registered,  1,  domain_uri_fixup, 0,
184                         ANY_ROUTE },
185         {"registered",   (cmd_function)w_registered,  2,  domain_uri_fixup, 0,
186                         ANY_ROUTE },
187         {"registered",   (cmd_function)w_registered3, 3,  registered_fixup, 0,
188                         ANY_ROUTE },
189         {"registered",   (cmd_function)w_registered4, 4,  registered_fixup, 0,
190                         ANY_ROUTE },
191         {"add_sock_hdr", (cmd_function)w_add_sock_hdr,  1,  fixup_spve_null, 0,
192                         REQUEST_ROUTE },
193         {"unregister",   (cmd_function)w_unregister,  2,  unreg_fixup, 0,
194                         REQUEST_ROUTE| FAILURE_ROUTE },
195         {"unregister",   (cmd_function)w_unregister2, 3, unreg_fixup, 0,
196                         REQUEST_ROUTE| FAILURE_ROUTE },
197         {"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3,
198                         fetchc_fixup, 0,
199                         REQUEST_ROUTE| FAILURE_ROUTE },
200         {"reg_free_contacts", (cmd_function)pv_free_contacts,   1,
201                         fixup_str_null, 0,
202                         REQUEST_ROUTE| FAILURE_ROUTE },
203         {"lookup_branches",  (cmd_function)w_lookup_branches, 1,  domain_uri_fixup, 0,
204                         REQUEST_ROUTE | FAILURE_ROUTE },
205         {"bind_registrar",  (cmd_function)bind_registrar,  0,
206                 0, 0, 0},
207         {0, 0, 0, 0, 0, 0}
208 };
209
210
211 /*! \brief
212  * Exported parameters
213  */
214 static param_export_t params[] = {
215         {"default_expires",    INT_PARAM, &default_registrar_cfg.default_expires                },
216         {"default_expires_range", INT_PARAM, &default_registrar_cfg.default_expires_range       },
217         {"expires_range",      INT_PARAM, &default_registrar_cfg.expires_range  },
218         {"default_q",          INT_PARAM, &default_registrar_cfg.default_q                      },
219         {"append_branches",    INT_PARAM, &default_registrar_cfg.append_branches                },
220         {"case_sensitive",     INT_PARAM, &default_registrar_cfg.case_sensitive                 },
221         /*      {"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag }, */
222         {"realm_prefix",       PARAM_STR, &default_registrar_cfg.realm_pref                     },
223         {"min_expires",        INT_PARAM, &default_registrar_cfg.min_expires                    },
224         {"max_expires",        INT_PARAM, &default_registrar_cfg.max_expires                    },
225         {"received_param",     PARAM_STR, &rcv_param                                            },
226         {"received_avp",       PARAM_STRING, &rcv_avp_param                                             },
227         {"max_contacts",       INT_PARAM, &default_registrar_cfg.max_contacts                   },
228         {"retry_after",        INT_PARAM, &default_registrar_cfg.retry_after                    },
229         {"sock_flag",          INT_PARAM, &sock_flag                                            },
230         {"sock_hdr_name",      PARAM_STR, &sock_hdr_name                                        },
231         {"method_filtering",   INT_PARAM, &method_filtering                                     },
232         {"use_path",           INT_PARAM, &path_enabled                                         },
233         {"path_mode",          INT_PARAM, &path_mode                                            },
234         {"path_use_received",  INT_PARAM, &path_use_params                                      },
235         {"path_check_local",   INT_PARAM, &path_check_local                     },
236         {"xavp_cfg",           PARAM_STR, &reg_xavp_cfg                                         },
237         {"xavp_rcd",           PARAM_STR, &reg_xavp_rcd                                         },
238         {"gruu_enabled",       INT_PARAM, &reg_gruu_enabled                                     },
239         {"outbound_mode",      INT_PARAM, &reg_outbound_mode                                    },
240         {"regid_mode",         INT_PARAM, &reg_regid_mode                                       },
241         {"flow_timer",         INT_PARAM, &reg_flow_timer                                       },
242         {"contact_max_size",   INT_PARAM, &contact_max_size                                     },
243         {"event_callback",     PARAM_STR, &reg_event_callback                           },
244         {"lookup_filter_mode", INT_PARAM, &reg_lookup_filter_mode                       },
245         {0, 0, 0}
246 };
247
248
249 /*! \brief We expose internal variables via the statistic framework below.*/
250 stat_export_t mod_stats[] = {
251         {"max_expires",       STAT_NO_RESET, &max_expires_stat        },
252         {"max_contacts",      STAT_NO_RESET, &max_contacts_stat       },
253         {"default_expire",    STAT_NO_RESET, &default_expire_stat     },
254         {"default_expires_range", STAT_NO_RESET, &default_expire_range_stat },
255         {"expires_range",     STAT_NO_RESET, &expire_range_stat },
256         {"accepted_regs",                 0, &accepted_registrations  },
257         {"rejected_regs",                 0, &rejected_registrations  },
258         {0, 0, 0}
259 };
260
261
262
263 /*! \brief
264  * Module exports structure
265  */
266 struct module_exports exports = {
267         "registrar", /* module name */
268         DEFAULT_DLFLAGS, /* dlopen flags */
269         cmds,        /* exported functions */
270         params,      /* exported parameters */
271         0,           /* exported rpc functions */
272         mod_pvs,     /* exported pseudo-variables */
273         0,           /* response handling function */
274         mod_init,    /* module initialization function */
275         child_init,  /* per-child init function */
276         mod_destroy  /* destroy function */
277 };
278
279
280 /*! \brief
281  * Initialize parent
282  */
283 static int mod_init(void)
284 {
285         pv_spec_t avp_spec;
286         str s;
287         bind_usrloc_t bind_usrloc;
288         qvalue_t dq;
289
290         if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC) < 0) {
291                 return -1;
292         }
293
294 #ifdef STATISTICS
295         /* register statistics */
296         if (register_module_stats( exports.name, mod_stats)!=0 ) {
297                 LM_ERR("Failed to register core statistics\n");
298                 return -1;
299         }
300 #endif
301
302         /* bind the SL API */
303         if (sl_load_api(&slb)!=0) {
304                 LM_ERR("Cannot bind to SL API. Please load the SL module before"
305                                 " loading this module.\n");
306                 return -1;
307         }
308
309         if(cfg_declare("registrar", registrar_cfg_def, &default_registrar_cfg,
310                                 cfg_sizeof(registrar), &registrar_cfg)){
311                 LM_ERR("Failed to declare the configuration parameters.\n");
312                 return -1;
313         }
314
315         if (rcv_avp_param && *rcv_avp_param) {
316                 s.s = rcv_avp_param; s.len = strlen(s.s);
317                 if (pv_parse_spec(&s, &avp_spec)==0
318                                 || avp_spec.type!=PVT_AVP) {
319                         LM_ERR("malformed or non AVP %s AVP definition\n", rcv_avp_param);
320                         return -1;
321                 }
322
323                 if(pv_get_avp_name(0, &avp_spec.pvp, &rcv_avp_name, &rcv_avp_type)!=0)
324                 {
325                         LM_ERR("[%s]- invalid AVP definition\n", rcv_avp_param);
326                         return -1;
327                 }
328         } else {
329                 rcv_avp_name.n = 0;
330                 rcv_avp_type = 0;
331         }
332
333         bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
334         if (!bind_usrloc) {
335                 LM_ERR("Can't bind to the usrloc module."
336                                 "Please load it before this module.\n");
337                 return -1;
338         }
339
340         /* Normalize default_q parameter */
341         dq = cfg_get(registrar, registrar_cfg, default_q);
342         if ( dq!= Q_UNSPECIFIED) {
343                 if (dq > MAX_Q) {
344                         LM_DBG("default_q = %d, lowering to MAX_Q: %d\n", dq, MAX_Q);
345                         dq = MAX_Q;
346                 } else if (dq < MIN_Q) {
347                         LM_DBG("default_q = %d, raising to MIN_Q: %d\n", dq, MIN_Q);
348                         dq = MIN_Q;
349                 }
350         }
351         cfg_get(registrar, registrar_cfg, default_q) = dq;
352
353         if (bind_usrloc(&ul) < 0) {
354                 return -1;
355         }
356
357         if(ul.register_ulcb != NULL) {
358                 if (reg_event_callback.s==NULL || reg_event_callback.len<=0 ) {
359                         reg_expire_event_rt = route_lookup(&event_rt, "usrloc:contact-expired");
360                         if (reg_expire_event_rt>=0 && event_rt.rlist[reg_expire_event_rt]==0)
361                                 reg_expire_event_rt=-1; /* disable */
362                 } else {
363                         keng = sr_kemi_eng_get();
364                         if(keng==NULL) {
365                                 LM_DBG("event callback (%s) set, but no cfg engine\n",
366                                         reg_event_callback.s);
367                         }
368                 }
369                 if (reg_expire_event_rt>=0 || (reg_event_callback.s!=NULL
370                                         && keng !=NULL)) {
371                         set_child_rpc_sip_mode();
372                         if(ul.register_ulcb(UL_CONTACT_EXPIRE, reg_ul_expired_contact, 0)< 0)
373                         {
374                                 LM_ERR("Can not register callback for expired contacts"
375                                                 " (usrloc module)\n");
376                                 return -1;
377                         }
378                 }
379         }
380         /*
381          * Import use_domain parameter from usrloc
382          */
383         reg_use_domain = ul.use_domain;
384
385         if (sock_hdr_name.s) {
386                 if (sock_hdr_name.len==0 || sock_flag==-1) {
387                         LM_INFO("empty sock_hdr_name or sock_flag not set -> resetting\n");
388                         sock_hdr_name.len = 0;
389                         sock_flag = -1;
390                 }
391         } else if (reg_xavp_cfg.s) {
392                 if (reg_xavp_cfg.len == 0 || sock_flag == -1) {
393                         LM_DBG("empty reg_xavp_cfg or sock_flag not set -> resetting\n");
394                         sock_flag = -1;
395                 }
396         } else if (sock_flag!=-1) {
397                 LM_INFO("sock_flag defined but no sock_hdr_name"
398                                 " or no reg_xavp_cfg -> resetting flag\n");
399                 sock_flag = -1;
400         }
401
402         if (reg_outbound_mode < 0 || reg_outbound_mode > 2) {
403                 LM_ERR("outbound_mode modparam must be 0 (not supported),"
404                                 " 1 (supported), or 2 (supported and required)\n");
405                 return -1;
406         }
407
408         if (reg_regid_mode < 0 || reg_regid_mode > 1) {
409                 LM_ERR("regid_mode modparam must be 0 (use with outbound),"
410                                 " 1 (use always)\n");
411                 return -1;
412         }
413
414         if (reg_flow_timer < 0 || reg_flow_timer > REG_FLOW_TIMER_MAX
415                         || (reg_flow_timer > 0 && reg_outbound_mode == REG_OUTBOUND_NONE)) {
416                 LM_ERR("bad value for flow_timer\n");
417                 return -1;
418         }
419
420         /* fix the flags */
421         sock_flag = (sock_flag!=-1)?(1<<sock_flag):0;
422         tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<<tcp_persistent_flag):0;
423
424         set_aor_case_sensitive(cfg_get(registrar, registrar_cfg, case_sensitive));
425
426         return 0;
427 }
428
429
430 static int child_init(int rank)
431 {
432         if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC)<0)
433                 return -1;
434         if (rank==1) {
435                 /* init stats */
436                 //TODO if parameters are modified via cfg framework do i change them?
437                 update_stat(max_expires_stat, default_registrar_cfg.max_expires);
438                 update_stat(max_contacts_stat, default_registrar_cfg.max_contacts);
439                 update_stat(default_expire_stat, default_registrar_cfg.default_expires);
440         }
441
442         return 0;
443 }
444
445 /*! \brief
446  * Wrapper to save(location)
447  */
448 static int w_save2(struct sip_msg* _m, char* _d, char* _cflags)
449 {
450         return save(_m, (udomain_t*)_d, ((int)(unsigned long)_cflags), NULL);
451 }
452
453 /*! \brief
454  * Wrapper to save(location)
455  */
456 static int w_save3(struct sip_msg* _m, char* _d, char* _cflags, char* _uri)
457 {
458         str uri;
459         if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)
460         {
461                 LM_ERR("invalid uri parameter\n");
462                 return -1;
463         }
464
465         return save(_m, (udomain_t*)_d, ((int)(unsigned long)_cflags), &uri);
466 }
467
468 /*! \brief
469  * Wrapper to lookup(location)
470  */
471 static int w_lookup(struct sip_msg* _m, char* _d, char* _uri)
472 {
473         str uri = {0};
474         if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
475                                 || uri.len<=0))
476         {
477                 LM_ERR("invalid uri parameter\n");
478                 return -1;
479         }
480
481         return lookup(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
482 }
483
484 /*! \brief
485  * Wrapper to lookup_to_dset(location)
486  */
487 static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _uri)
488 {
489         str uri = {0};
490         if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
491                                 || uri.len<=0))
492         {
493                 LM_ERR("invalid uri parameter\n");
494                 return -1;
495         }
496
497         return lookup_to_dset(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
498 }
499
500 /*! \brief
501  * Wrapper to lookup_branches(location)
502  */
503 static int w_lookup_branches(sip_msg_t* _m, char* _d, char* _p2)
504 {
505         return lookup_branches(_m, (udomain_t*)_d);
506 }
507
508
509 static int ki_lookup_branches(sip_msg_t* _m, str* _dtable)
510 {
511         udomain_t* d;
512
513         if(ul.get_udomain(_dtable->s, &d)<0) {
514                 LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
515                 return -1;
516         }
517
518         return lookup_branches(_m, d);
519 }
520
521 static int w_registered(struct sip_msg* _m, char* _d, char* _uri)
522 {
523         str uri = {0};
524         if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
525                                 || uri.len<=0))
526         {
527                 LM_ERR("invalid uri parameter\n");
528                 return -1;
529         }
530         return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
531 }
532
533 static int ki_registered_uri(sip_msg_t* _m, str* _dtable, str* _uri)
534 {
535         udomain_t* d;
536
537         if(ul.get_udomain(_dtable->s, &d)<0) {
538                 LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
539                 return -1;
540         }
541
542         return registered(_m, d, (_uri && _uri->len>0)?_uri:NULL);
543 }
544
545 static int w_registered3(struct sip_msg* _m, char* _d, char* _uri, char* _flags)
546 {
547         str uri = {0};
548         int flags = 0;
549         if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
550                                 || uri.len<=0))
551         {
552                 LM_ERR("invalid uri parameter\n");
553                 return -1;
554         }
555         if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0)
556         {
557                 LM_ERR("invalid flags parameter\n");
558                 return -1;
559         }
560         return registered3(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags);
561 }
562
563 static int ki_registered_flags(sip_msg_t* _m, str* _dtable, str* _uri, int _f)
564 {
565         udomain_t* d;
566
567         if(ul.get_udomain(_dtable->s, &d)<0) {
568                 LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
569                 return -1;
570         }
571
572         return registered3(_m, d, (_uri && _uri->len>0)?_uri:NULL, _f);
573 }
574
575 static int w_registered4(struct sip_msg* _m, char* _d, char* _uri,
576                 char* _flags, char* _actionflags)
577 {
578         str uri = {0};
579         int flags = 0;
580         int actionflags = 0;
581         if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0
582                                 || uri.len<=0))
583         {
584                 LM_ERR("invalid uri parameter\n");
585                 return -1;
586         }
587         if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0)
588         {
589                 LM_ERR("invalid flags parameter\n");
590                 return -1;
591         }
592         if(_actionflags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_actionflags,
593                                         &actionflags)) < 0)
594         {
595                 LM_ERR("invalid action flag parameter\n");
596                 return -1;
597         }
598         return registered4(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags,
599                         actionflags);
600 }
601
602 static int ki_registered_action(sip_msg_t* _m, str* _dtable, str* _uri,
603                 int _f, int _aflags)
604 {
605         udomain_t* d;
606
607         if(ul.get_udomain(_dtable->s, &d)<0) {
608                 LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
609                 return -1;
610         }
611
612         return registered4(_m, d, (_uri && _uri->len>0)?_uri:NULL, _f, _aflags);
613 }
614
615 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri)
616 {
617         str uri = {0};
618         if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)
619         {
620                 LM_ERR("invalid uri parameter\n");
621                 return -1;
622         }
623
624         return unregister(_m, (udomain_t*)_d, &uri, NULL);
625 }
626
627 static int ki_unregister(sip_msg_t* _m, str* _dtable, str* _uri)
628 {
629         udomain_t* d;
630
631         if(_uri==NULL || _uri->len<=0) {
632                 LM_ERR("invalid uri parameter\n");
633                 return -1;
634         }
635         if(ul.get_udomain(_dtable->s, &d)<0) {
636                 LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
637                 return -1;
638         }
639
640         return unregister(_m, d, _uri, NULL);
641 }
642
643 static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid)
644 {
645         str uri = {0, 0};
646         str ruid = {0};
647         if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0)
648         {
649                 LM_ERR("invalid uri parameter\n");
650                 return -1;
651         }
652         if(fixup_get_svalue(_m, (gparam_p)_ruid, &ruid)!=0 || ruid.len<=0)
653         {
654                 LM_ERR("invalid ruid parameter\n");
655                 return -1;
656         }
657
658         return unregister(_m, (udomain_t*)_d, &uri, &ruid);
659 }
660
661 static int ki_unregister_ruid(sip_msg_t* _m, str* _dtable, str* _uri, str *_ruid)
662 {
663         udomain_t* d;
664
665         if(_uri==NULL || _uri->len<=0) {
666                 LM_ERR("invalid uri parameter\n");
667                 return -1;
668         }
669         if(ul.get_udomain(_dtable->s, &d)<0) {
670                 LM_ERR("usrloc domain [%s] not found\n", _dtable->s);
671                 return -1;
672         }
673
674         return unregister(_m, d, _uri, _ruid);
675 }
676
677 /*! \brief
678  * Convert char* parameter to udomain_t* pointer
679  */
680 static int domain_fixup(void** param, int param_no)
681 {
682         udomain_t* d;
683
684         if (param_no == 1) {
685                 if (ul.register_udomain((char*)*param, &d) < 0) {
686                         LM_ERR("failed to register domain\n");
687                         return E_UNSPEC;
688                 }
689
690                 *param = (void*)d;
691         }
692         return 0;
693 }
694
695 /*! \brief
696  * Convert char* parameter to udomain_t* pointer
697  */
698 static int domain_uri_fixup(void** param, int param_no)
699 {
700         if (param_no == 1) {
701                 return domain_fixup(param, 1);
702         } else if (param_no == 2) {
703                 return fixup_spve_null(param, 1);
704         }
705         return 0;
706 }
707
708 static int registered_fixup(void** param, int param_no)
709 {
710         if (param_no == 1) {
711                 return domain_fixup(param, 1);
712         } else if (param_no == 2) {
713                 return fixup_spve_null(param, 1);
714         } else if (param_no == 3) {
715                 return fixup_igp_null(param, 1);
716         } else if (param_no == 4) {
717                 return fixup_igp_null(param, 1);
718         }
719         return 0;
720 }
721
722 /*! \brief
723  * Convert char* parameter to udomain_t* pointer
724  * Convert char* parameter to pv_elem_t* pointer
725  */
726 static int unreg_fixup(void** param, int param_no)
727 {
728         if (param_no == 1) {
729                 return domain_fixup(param, 1);
730         } else if (param_no == 2) {
731                 return fixup_spve_null(param, 1);
732         } else if (param_no == 3) {
733                 return fixup_spve_null(param, 1);
734         }
735         return 0;
736 }
737
738
739
740 /*! \brief
741  * Fixup for "save" function - both domain and flags
742  */
743 static int save_fixup(void** param, int param_no)
744 {
745         unsigned int flags;
746         str s;
747
748         if (param_no == 1) {
749                 return domain_fixup(param,param_no);
750         } else if (param_no == 2) {
751                 s.s = (char*)*param;
752                 s.len = strlen(s.s);
753                 flags = 0;
754                 if ( (strno2int(&s, &flags )<0) || (flags>REG_SAVE_ALL_FL) ) {
755                         LM_ERR("bad flags <%s>\n", (char *)(*param));
756                         return E_CFG;
757                 }
758                 if (ul.db_mode==DB_ONLY && flags&REG_SAVE_MEM_FL) {
759                         LM_ERR("MEM flag set while using the DB_ONLY mode in USRLOC\n");
760                         return E_CFG;
761                 }
762                 pkg_free(*param);
763                 *param = (void*)(unsigned long int)flags;
764         } else if (param_no == 3) {
765                 return fixup_spve_null(param, 1);
766         }
767         return 0;
768 }
769
770 /*! \brief
771  * Convert char* parameter to udomain_t* pointer
772  * Convert char* parameter to pv_elem_t* pointer
773  * Convert char* parameter to str* pointer
774  */
775 static int fetchc_fixup(void** param, int param_no)
776 {
777         if (param_no == 1) {
778                 return domain_fixup(param, 1);
779         } else if (param_no == 2) {
780                 return fixup_spve_null(param, 1);
781         } else if (param_no == 3) {
782                 return fixup_str_null(param, 1);
783         }
784         return 0;
785 }
786
787
788 static void mod_destroy(void)
789 {
790         free_contact_buf();
791 }
792
793
794 #include "../../core/data_lump.h"
795 #include "../../core/ip_addr.h"
796 #include "../../core/ut.h"
797
798 static int ki_add_sock_hdr(sip_msg_t* msg, str *hdr_name)
799 {
800         struct socket_info* si;
801         struct lump* anchor;
802         str hdr;
803         char *p;
804
805         if(hdr_name==NULL || hdr_name->s==NULL || hdr_name->len<=0) {
806                 LM_ERR("invalid header name parameter\n");
807                 return -1;
808         }
809         si = msg->rcv.bind_address;
810
811         if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
812                 LM_ERR("failed to parse message\n");
813                 goto error;
814         }
815
816         anchor = anchor_lump( msg, msg->unparsed-msg->buf, 0, 0);
817         if (anchor==0) {
818                 LM_ERR("can't get anchor\n");
819                 goto error;
820         }
821
822         hdr.len = hdr_name->len + 2 + si->sock_str.len + CRLF_LEN;
823         if ( (hdr.s=(char*)pkg_malloc(hdr.len))==0 ) {
824                 LM_ERR("no more pkg mem\n");
825                 goto error;
826         }
827
828         p = hdr.s;
829         memcpy( p, hdr_name->s, hdr_name->len);
830         p += hdr_name->len;
831         *(p++) = ':';
832         *(p++) = ' ';
833
834         memcpy( p, si->sock_str.s, si->sock_str.len);
835         p += si->sock_str.len;
836
837         memcpy( p, CRLF, CRLF_LEN);
838         p += CRLF_LEN;
839
840         if ( p-hdr.s!=hdr.len ) {
841                 LM_CRIT("buffer overflow (%d!=%d)\n", (int)(long)(p-hdr.s),hdr.len);
842                 goto error1;
843         }
844
845         if (insert_new_lump_before( anchor, hdr.s, hdr.len, 0) == 0) {
846                 LM_ERR("can't insert lump\n");
847                 goto error1;
848         }
849
850         return 1;
851 error1:
852         pkg_free(hdr.s);
853 error:
854         return -1;
855 }
856
857 static int w_add_sock_hdr(struct sip_msg* msg, char *name, char *foo)
858 {
859         str hdr_name;
860         if(fixup_get_svalue(msg, (gparam_t*)name, &hdr_name)<0) {
861                 LM_ERR("cannot get the header name\n");
862                 return -1;
863         }
864         return ki_add_sock_hdr(msg, &hdr_name);
865 }
866
867 void default_expires_stats_update(str* gname, str* name)
868 {
869         update_stat(default_expire_stat, cfg_get(registrar, registrar_cfg,
870                                 default_expires));
871 }
872
873 void max_expires_stats_update(str* gname, str* name)
874 {
875         update_stat(max_expires_stat, cfg_get(registrar, registrar_cfg,
876                                 max_expires));
877 }
878
879 void default_expires_range_update(str* gname, str* name)
880 {
881         update_stat(default_expire_range_stat, cfg_get(registrar, registrar_cfg,
882                                 default_expires_range));
883 }
884
885 void expires_range_update(str* gname, str* name){
886         update_stat(expire_range_stat, cfg_get(registrar, registrar_cfg,
887                                 expires_range));
888 }
889
890 /**
891  *
892  */
893 static sr_kemi_t sr_kemi_registrar_exports[] = {
894         { str_init("registrar"), str_init("save"),
895                 SR_KEMIP_INT, regapi_save,
896                 { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
897                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
898         },
899         { str_init("registrar"), str_init("save_uri"),
900                 SR_KEMIP_INT, regapi_save_uri,
901                 { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_STR,
902                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
903         },
904         { str_init("registrar"), str_init("lookup"),
905                 SR_KEMIP_INT, regapi_lookup,
906                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
907                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
908         },
909         { str_init("registrar"), str_init("lookup_uri"),
910                 SR_KEMIP_INT, regapi_lookup_uri,
911                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
912                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
913         },
914         { str_init("registrar"), str_init("lookup_to_dset"),
915                 SR_KEMIP_INT, regapi_lookup_to_dset,
916                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
917                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
918         },
919         { str_init("registrar"), str_init("lookup_branches"),
920                 SR_KEMIP_INT, ki_lookup_branches,
921                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
922                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
923         },
924         { str_init("registrar"), str_init("registered"),
925                 SR_KEMIP_INT, regapi_registered,
926                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
927                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
928         },
929         { str_init("registrar"), str_init("registered_uri"),
930                 SR_KEMIP_INT, ki_registered_uri,
931                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
932                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
933         },
934         { str_init("registrar"), str_init("registered_flags"),
935                 SR_KEMIP_INT, ki_registered_flags,
936                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
937                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
938         },
939         { str_init("registrar"), str_init("registered_action"),
940                 SR_KEMIP_INT, ki_registered_action,
941                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
942                         SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE }
943         },
944         { str_init("registrar"), str_init("set_q_override"),
945                 SR_KEMIP_INT, regapi_set_q_override,
946                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
947                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
948         },
949         { str_init("registrar"), str_init("add_sock_hdr"),
950                 SR_KEMIP_INT, ki_add_sock_hdr,
951                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
952                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
953         },
954         { str_init("registrar"), str_init("unregister"),
955                 SR_KEMIP_INT, ki_unregister,
956                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
957                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
958         },
959         { str_init("registrar"), str_init("unregister_ruid"),
960                 SR_KEMIP_INT, ki_unregister_ruid,
961                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
962                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
963         },
964         { str_init("registrar"), str_init("reg_fetch_contacts"),
965                 SR_KEMIP_INT, ki_reg_fetch_contacts,
966                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
967                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
968         },
969         { str_init("registrar"), str_init("reg_free_contacts"),
970                 SR_KEMIP_INT, ki_reg_free_contacts,
971                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
972                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
973         },
974         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
975 };
976
977 /**
978  *
979  */
980 int mod_register(char *path, int *dlflags, void *p1, void *p2)
981 {
982         sr_kemi_modules_add(sr_kemi_registrar_exports);
983         return 0;
984 }