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