rtjson: regenerated readme
[sip-router] / modules / rls / rls.c
1 /*
2  * rls module - resource list server
3  *
4  * Copyright (C) 2007 Voice Sistem S.R.L.
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 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/ipc.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <time.h>
32
33 #include "../../pt.h"
34 #include "../../lib/srdb1/db.h"
35 #include "../../sr_module.h"
36 #include "../../dprint.h"
37 #include "../../error.h"
38 #include "../../ut.h"
39 #include "../../timer_proc.h"
40 #include "../../hashes.h"
41 #include "../../lib/kmi/mi.h"
42 #include "../../mem/mem.h"
43 #include "../../mem/shm_mem.h"
44 #include "../../modules/tm/tm_load.h"
45 #include "../../modules/sl/sl.h"
46 #include "../presence/bind_presence.h"
47 #include "../presence/hash.h"
48 #include "../pua/pua_bind.h"
49 #include "../pua/pidf.h"
50 #include "../xcap_client/xcap_functions.h"
51 #include "rls.h"
52 #include "notify.h"
53 #include "resource_notify.h"
54 #include "api.h"
55 #include "subscribe.h"
56 #include "../../mod_fix.h"
57
58 MODULE_VERSION
59
60 #define P_TABLE_VERSION 1
61 #define W_TABLE_VERSION 3
62 #define X_TABLE_VERSION 4
63
64 /** database connection */
65 db1_con_t *rls_db = NULL;
66 db_func_t rls_dbf;
67 db1_con_t *rlpres_db = NULL;
68 db_func_t rlpres_dbf;
69 db1_con_t *rls_xcap_db = NULL;
70 db_func_t rls_xcap_dbf;
71
72 /** modules variables */
73 str rls_server_address = {0, 0};
74 int rls_expires_offset=0;
75 int waitn_time = 5;
76 int rls_notifier_poll_rate = 10;
77 int rls_notifier_processes = 1;
78 str rlsubs_table = str_init("rls_watchers");
79 str rlpres_table = str_init("rls_presentity");
80 str rls_xcap_table = str_init("xcap");
81
82 int *rls_notifier_id = NULL;
83
84 str db_url = str_init(DEFAULT_DB_URL);
85 str xcap_db_url = str_init("");
86 str rlpres_db_url = str_init("");
87 int hash_size = 9;
88 shtable_t rls_table;
89 contains_event_t pres_contains_event;
90 search_event_t pres_search_event;
91 get_event_list_t pres_get_ev_list;
92 int clean_period = 100;
93 int rlpres_clean_period = -1;
94
95 /* Lock for rls_update_subs */
96 gen_lock_t *rls_update_subs_lock = NULL;
97
98
99 /* address and port(default: 80):"http://192.168.2.132:8000/xcap-root"*/
100 char* xcap_root;
101 unsigned int xcap_port = 8000;
102 int rls_restore_db_subs(void);
103 int rls_integrated_xcap_server = 0;
104
105 /** libxml api */
106 xmlDocGetNodeByName_t XMLDocGetNodeByName;
107 xmlNodeGetNodeByName_t XMLNodeGetNodeByName;
108 xmlNodeGetNodeContentByName_t XMLNodeGetNodeContentByName;
109 xmlNodeGetAttrContentByName_t XMLNodeGetAttrContentByName;
110
111 /* functions imported from presence to handle subscribe hash table */
112 extern shtable_t rls_new_shtable(int hash_size);
113 extern void rls_destroy_shtable(shtable_t htable, int hash_size);
114 extern int rls_insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs);
115 extern subs_t* rls_search_shtable(shtable_t htable,str callid,str to_tag,
116                 str from_tag,unsigned int hash_code);
117 extern int rls_delete_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs);
118 extern int rls_update_shtable(shtable_t htable,unsigned int hash_code, 
119                 subs_t* subs, int type);
120 extern void rls_update_db_subs_timer(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
121         int htable_size, int no_lock, handle_expired_func_t handle_expired_func);
122
123 new_shtable_t pres_new_shtable;
124 insert_shtable_t pres_insert_shtable;
125 search_shtable_t pres_search_shtable;
126 update_shtable_t pres_update_shtable;
127 delete_shtable_t pres_delete_shtable;
128 destroy_shtable_t pres_destroy_shtable;
129 mem_copy_subs_t  pres_copy_subs;
130 update_db_subs_t pres_update_db_subs_timer;
131 extract_sdialog_info_t pres_extract_sdialog_info;
132 int rls_events= EVENT_PRESENCE;
133 int to_presence_code = 1;
134 int rls_max_expires = 7200;
135 int rls_reload_db_subs = 0;
136 int rls_max_notify_body_len = 0;
137 int dbmode = 0;
138
139 /* functions imported from xcap_client module */
140 xcapGetNewDoc_t xcap_GetNewDoc = 0;
141
142 /* functions imported from pua module*/
143 send_subscribe_t pua_send_subscribe;
144 get_record_id_t pua_get_record_id;
145 get_subs_list_t pua_get_subs_list;
146
147 /* TM bind */
148 struct tm_binds tmb;
149 /** SL API structure */
150 sl_api_t slb;
151
152 str str_rlsubs_did_col = str_init("rlsubs_did");
153 str str_resource_uri_col = str_init("resource_uri");
154 str str_updated_col = str_init("updated");
155 str str_auth_state_col = str_init("auth_state");
156 str str_reason_col = str_init("reason");
157 str str_content_type_col = str_init("content_type");
158 str str_presence_state_col = str_init("presence_state");
159 str str_expires_col = str_init("expires");
160 str str_presentity_uri_col = str_init("presentity_uri");
161 str str_event_col = str_init("event");
162 str str_event_id_col = str_init("event_id");
163 str str_to_user_col = str_init("to_user");
164 str str_to_domain_col = str_init("to_domain");
165 str str_from_user_col = str_init("from_user");
166 str str_from_domain_col = str_init("from_domain");
167 str str_watcher_username_col = str_init("watcher_username");
168 str str_watcher_domain_col = str_init("watcher_domain");
169 str str_callid_col = str_init("callid");
170 str str_to_tag_col = str_init("to_tag");
171 str str_from_tag_col = str_init("from_tag");
172 str str_local_cseq_col = str_init("local_cseq");
173 str str_remote_cseq_col = str_init("remote_cseq");
174 str str_record_route_col = str_init("record_route");
175 str str_socket_info_col = str_init("socket_info");
176 str str_contact_col = str_init("contact");
177 str str_local_contact_col = str_init("local_contact");
178 str str_version_col = str_init("version");
179 str str_status_col = str_init("status");
180 str str_username_col = str_init("username");
181 str str_domain_col = str_init("domain");
182 str str_doc_type_col = str_init("doc_type");
183 str str_etag_col = str_init("etag");
184 str str_doc_col = str_init("doc");
185 str str_doc_uri_col = str_init("doc_uri");
186
187 /* outbound proxy address */
188 str rls_outbound_proxy = {0, 0};
189
190 int rls_fetch_rows = 500;
191
192 int rls_disable_remote_presence = 0;
193 int rls_max_backend_subs = 0;
194
195 /** module functions */
196
197 static int mod_init(void);
198 static int child_init(int);
199 static int mi_child_init(void);
200 static void destroy(void);
201 int rlsubs_table_restore();
202 void rlsubs_table_update(unsigned int ticks,void *param);
203 int add_rls_event(modparam_t type, void* val);
204 int rls_update_subs(struct sip_msg *msg, char *puri, char *pevent);
205 int fixup_update_subs(void** param, int param_no);
206 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param);
207
208 static cmd_export_t cmds[]=
209 {
210         {"rls_handle_subscribe",  (cmd_function)rls_handle_subscribe0,  0,
211                         0, 0, REQUEST_ROUTE},
212         {"rls_handle_subscribe",  (cmd_function)w_rls_handle_subscribe, 1,
213                         fixup_spve_null, 0, REQUEST_ROUTE},
214         {"rls_handle_notify",     (cmd_function)rls_handle_notify,      0,
215                         0, 0, REQUEST_ROUTE},
216         {"rls_update_subs",       (cmd_function)rls_update_subs,        2,
217                         fixup_update_subs, 0, ANY_ROUTE},
218         {"bind_rls",              (cmd_function)bind_rls,               1,
219                         0, 0, 0},
220         {0, 0, 0, 0, 0, 0 }
221 };
222
223 static param_export_t params[]={
224         { "server_address",         PARAM_STR,   &rls_server_address           },
225         { "db_url",                 PARAM_STR,   &db_url                       },
226         { "rlpres_db_url",          PARAM_STR,   &rlpres_db_url          },
227         { "xcap_db_url",            PARAM_STR,   &xcap_db_url                  },
228         { "rlsubs_table",           PARAM_STR,   &rlsubs_table                 },
229         { "rlpres_table",           PARAM_STR,   &rlpres_table                 },
230         { "xcap_table",             PARAM_STR,   &rls_xcap_table               },
231         { "waitn_time",             INT_PARAM,   &waitn_time                     },
232         { "notifier_poll_rate",     INT_PARAM,   &rls_notifier_poll_rate         },
233         { "notifier_processes",     INT_PARAM,   &rls_notifier_processes         },
234         { "clean_period",           INT_PARAM,   &clean_period                   },
235         { "rlpres_clean_period",    INT_PARAM,   &rlpres_clean_period            },
236         { "max_expires",            INT_PARAM,   &rls_max_expires                },
237         { "hash_size",              INT_PARAM,   &hash_size                      },
238         { "integrated_xcap_server", INT_PARAM,   &rls_integrated_xcap_server     },
239         { "to_presence_code",       INT_PARAM,   &to_presence_code               },
240         { "xcap_root",              PARAM_STRING,   &xcap_root                      },
241         { "rls_event",              PARAM_STRING|USE_FUNC_PARAM,(void*)add_rls_event},
242         { "outbound_proxy",         PARAM_STR,   &rls_outbound_proxy           },
243         { "reload_db_subs",         INT_PARAM,   &rls_reload_db_subs             },
244         { "max_notify_body_length", INT_PARAM,   &rls_max_notify_body_len        },
245         { "db_mode",                INT_PARAM,   &dbmode                         },
246         { "expires_offset",         INT_PARAM,   &rls_expires_offset             },
247         { "fetch_rows",             INT_PARAM,   &rls_fetch_rows                 },
248         { "disable_remote_presence",INT_PARAM,   &rls_disable_remote_presence    },
249         { "max_backend_subs",       INT_PARAM,   &rls_max_backend_subs           },
250         {0,                         0,           0                               }
251 };
252
253 static mi_export_t mi_cmds[] = {
254         { "rls_cleanup",        mi_cleanup,             0,  0,  mi_child_init},
255         { 0,                    0,                      0,  0,  0}
256 };
257
258 /** module exports */
259 struct module_exports exports= {
260         "rls",                          /* module name */
261         DEFAULT_DLFLAGS,                /* dlopen flags */
262         cmds,                           /* exported functions */
263         params,                         /* exported parameters */
264         0,                              /* exported statistics */
265         mi_cmds,                        /* exported MI functions */
266         0,                              /* exported pseudo-variables */
267         0,                              /* extra processes */
268         mod_init,                       /* module initialization function */
269         0,                              /* response handling function */
270         (destroy_function) destroy,     /* destroy function */
271         child_init                      /* per-child init function */
272 };
273
274 /**
275  * init module function
276  */
277 static int mod_init(void)
278 {
279         bind_presence_t bind_presence;
280         presence_api_t pres;
281         bind_pua_t bind_pua;
282         pua_api_t pua;
283         bind_libxml_t bind_libxml;
284         libxml_api_t libxml_api;
285         bind_xcap_t bind_xcap;
286         xcap_api_t xcap_api;
287         char* sep;
288
289         LM_DBG("start\n");
290
291         if (register_mi_mod(exports.name, mi_cmds)!=0)
292         {
293                 LM_ERR("failed to register MI commands\n");
294                 return -1;
295         }
296
297         if (dbmode <RLS_DB_DEFAULT || dbmode > RLS_DB_ONLY)
298         {
299                 LM_ERR( "Invalid dbmode-set to default mode\n" );
300                 dbmode = 0;
301         }
302
303         if(!rls_server_address.s || rls_server_address.len<=0)
304         {
305                 LM_ERR("server_address parameter not set in configuration file\n");
306                 return -1;
307         }       
308         
309         if(!rls_integrated_xcap_server && xcap_root== NULL)
310         {
311                 LM_ERR("xcap_root parameter not set\n");
312                 return -1;
313         }
314         /* extract port if any */
315         if(xcap_root)
316         {
317                 sep= strchr(xcap_root, ':');
318                 if(sep)
319                 {
320                         char* sep2= NULL;
321                         sep2= strchr(sep+ 1, ':');
322                         if(sep2)
323                                 sep= sep2;
324
325                         str port_str;
326
327                         port_str.s= sep+ 1;
328                         port_str.len= strlen(xcap_root)- (port_str.s-xcap_root);
329
330                         if(str2int(&port_str, &xcap_port)< 0)
331                         {
332                                 LM_ERR("converting string to int [port]= %.*s\n",
333                                         port_str.len, port_str.s);
334                                 return -1;
335                         }
336                         if(xcap_port< 0 || xcap_port> 65535)
337                         {
338                                 LM_ERR("wrong xcap server port\n");
339                                 return -1;
340                         }
341                         *sep= '\0';
342                 }
343         }
344
345         /* bind the SL API */
346         if (sl_load_api(&slb)!=0) {
347                 LM_ERR("cannot bind to SL API\n");
348                 return -1;
349         }
350
351         /* load all TM stuff */
352         if(load_tm_api(&tmb)==-1)
353         {
354                 LM_ERR("can't load tm functions\n");
355                 return -1;
356         }
357         bind_presence= (bind_presence_t)find_export("bind_presence", 1,0);
358         if (!bind_presence)
359         {
360                 LM_ERR("Can't bind presence\n");
361                 return -1;
362         }
363         if (bind_presence(&pres) < 0)
364         {
365                 LM_ERR("Can't bind presence\n");
366                 return -1;
367         }
368         pres_contains_event = pres.contains_event;
369         pres_search_event   = pres.search_event;
370         pres_get_ev_list    = pres.get_event_list;
371
372         if (rls_expires_offset < 0 ) 
373         {
374                 LM_ERR( "Negative expires_offset, defaulted to zero\n" );
375                 rls_expires_offset = 0; 
376         }
377
378         if (dbmode == RLS_DB_ONLY)
379         {
380                 pres_new_shtable          = rls_new_shtable;
381                 pres_destroy_shtable      = rls_destroy_shtable;
382                 pres_insert_shtable       = rls_insert_shtable;
383                 pres_delete_shtable       = rls_delete_shtable;
384                 pres_update_shtable       = rls_update_shtable;
385                 pres_search_shtable       = rls_search_shtable;
386                 pres_update_db_subs_timer = rls_update_db_subs_timer;
387         }
388         else
389         {
390                 pres_new_shtable          = pres.new_shtable;
391                 pres_destroy_shtable      = pres.destroy_shtable;
392                 pres_insert_shtable       = pres.insert_shtable;
393                 pres_delete_shtable       = pres.delete_shtable;
394                 pres_update_shtable       = pres.update_shtable;
395                 pres_search_shtable       = pres.search_shtable;
396                 pres_update_db_subs_timer = pres.update_db_subs_timer;
397         }
398
399         pres_copy_subs      = pres.mem_copy_subs;
400         pres_extract_sdialog_info= pres.extract_sdialog_info;
401
402         if(!pres_contains_event || !pres_get_ev_list || !pres_new_shtable ||
403                 !pres_destroy_shtable || !pres_insert_shtable || !pres_delete_shtable
404                  || !pres_update_shtable || !pres_search_shtable || !pres_copy_subs
405                  || !pres_extract_sdialog_info)
406         {
407                 LM_ERR("importing functions from presence module\n");
408                 return -1;
409         }
410
411         LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len, db_url.s);
412
413         if(xcap_db_url.len==0)
414         {
415                 xcap_db_url.s = db_url.s;
416                 xcap_db_url.len = db_url.len;
417         }
418
419         LM_DBG("db_url=%s/%d/%p\n", ZSW(xcap_db_url.s), xcap_db_url.len, xcap_db_url.s);
420
421         if(rlpres_db_url.len==0)
422         {
423                 rlpres_db_url.s = db_url.s;
424                 rlpres_db_url.len = db_url.len;
425         }
426
427         LM_DBG("db_url=%s/%d/%p\n", ZSW(rlpres_db_url.s), rlpres_db_url.len, rlpres_db_url.s);
428
429         
430         /* binding to mysql module  */
431
432         if (db_bind_mod(&db_url, &rls_dbf))
433         {
434                 LM_ERR("Database module not found\n");
435                 return -1;
436         }
437
438         if (db_bind_mod(&rlpres_db_url, &rlpres_dbf))
439         {
440                 LM_ERR("Database module not found\n");
441                 return -1;
442         }
443         
444         if (db_bind_mod(&xcap_db_url, &rls_xcap_dbf))
445         {
446                 LM_ERR("Database module not found\n");
447                 return -1;
448         }
449
450         if (!DB_CAPABILITY(rls_dbf, DB_CAP_ALL)) {
451                 LM_ERR("Database module does not implement all functions"
452                                 " needed by the module\n");
453                 return -1;
454         }
455
456         if (!DB_CAPABILITY(rlpres_dbf, DB_CAP_ALL)) {
457                 LM_ERR("Database module does not implement all functions"
458                                 " needed by the module\n");
459                 return -1;
460         }
461
462         if (!DB_CAPABILITY(rls_xcap_dbf, DB_CAP_ALL)) {
463                 LM_ERR("Database module does not implement all functions"
464                                 " needed by the module\n");
465                 return -1;
466         }
467
468         rls_db = rls_dbf.init(&db_url);
469         if (!rls_db)
470         {
471                 LM_ERR("while connecting database\n");
472                 return -1;
473         }
474
475         rlpres_db = rlpres_dbf.init(&rlpres_db_url);
476         if (!rlpres_db)
477         {
478                 LM_ERR("while connecting database\n");
479                 return -1;
480         }
481
482         rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
483         if (!rls_xcap_db)
484         {
485                 LM_ERR("while connecting database\n");
486                 return -1;
487         }
488
489         /* verify table version */
490         if(db_check_table_version(&rls_dbf, rls_db, &rlsubs_table, W_TABLE_VERSION) < 0) {
491                         LM_ERR("error during table version check.\n");
492                         return -1;
493         }
494
495         /* verify table version */
496         if(db_check_table_version(&rlpres_dbf, rlpres_db, &rlpres_table, P_TABLE_VERSION) < 0) {
497                         LM_ERR("error during table version check.\n");
498                         return -1;
499         }
500
501         /* verify table version */
502         if(db_check_table_version(&rls_xcap_dbf, rls_xcap_db, &rls_xcap_table, X_TABLE_VERSION) < 0)
503         {
504                         LM_ERR("error during table version check.\n");
505                         return -1;
506         }
507
508         if (dbmode != RLS_DB_ONLY)
509         {
510                 if(hash_size<=1)
511                         hash_size= 512;
512                 else
513                         hash_size = 1<<hash_size;
514
515                 rls_table= pres_new_shtable(hash_size);
516                 if(rls_table== NULL)
517                 {
518                         LM_ERR("while creating new hash table\n");
519                         return -1;
520                 }
521                 if(rls_reload_db_subs!=0)
522                 {
523                         if(rls_restore_db_subs()< 0)
524                         {
525                                 LM_ERR("while restoring rl watchers table\n");
526                                 return -1;
527                         }
528                 }
529         }
530
531         if(rls_db)
532                 rls_dbf.close(rls_db);
533         rls_db = NULL;
534
535         if(rlpres_db)
536                 rlpres_dbf.close(rlpres_db);
537         rlpres_db = NULL;
538
539         if(rls_xcap_db)
540                 rls_xcap_dbf.close(rls_xcap_db);
541         rls_xcap_db = NULL;
542
543         if(waitn_time<= 0)
544                 waitn_time= 5;
545
546         if(rls_notifier_poll_rate<= 0)
547                 rls_notifier_poll_rate= 10;
548
549         if(rls_notifier_processes<= 0)
550                 rls_notifier_processes= 1;
551
552         /* bind libxml wrapper functions */
553
554         if((bind_libxml=(bind_libxml_t)find_export("bind_libxml_api", 1, 0))== NULL)
555         {
556                 LM_ERR("can't import bind_libxml_api\n");
557                 return -1;
558         }
559         if(bind_libxml(&libxml_api)< 0)
560         {
561                 LM_ERR("can not bind libxml api\n");
562                 return -1;
563         }
564         XMLNodeGetAttrContentByName= libxml_api.xmlNodeGetAttrContentByName;
565         XMLDocGetNodeByName= libxml_api.xmlDocGetNodeByName;
566         XMLNodeGetNodeByName= libxml_api.xmlNodeGetNodeByName;
567         XMLNodeGetNodeContentByName= libxml_api.xmlNodeGetNodeContentByName;
568
569         if(XMLNodeGetAttrContentByName== NULL || XMLDocGetNodeByName== NULL ||
570                         XMLNodeGetNodeByName== NULL || XMLNodeGetNodeContentByName== NULL)
571         {
572                 LM_ERR("libxml wrapper functions could not be bound\n");
573                 return -1;
574         }
575
576         /* bind pua */
577         bind_pua= (bind_pua_t)find_export("bind_pua", 1,0);
578         if (!bind_pua)
579         {
580                 LM_ERR("Can't bind pua\n");
581                 return -1;
582         }
583         
584         if (bind_pua(&pua) < 0)
585         {
586                 LM_ERR("mod_init Can't bind pua\n");
587                 return -1;
588         }
589         if(pua.send_subscribe == NULL)
590         {
591                 LM_ERR("Could not import send_subscribe\n");
592                 return -1;
593         }
594         pua_send_subscribe= pua.send_subscribe;
595         
596         if(pua.get_record_id == NULL)
597         {
598                 LM_ERR("Could not import get_record_id\n");
599                 return -1;
600         }
601         pua_get_record_id= pua.get_record_id;
602
603         if(pua.get_subs_list == NULL)
604         {
605                 LM_ERR("Could not import get_subs_list\n");
606                 return -1;
607         }
608         pua_get_subs_list= pua.get_subs_list;
609
610         if(!rls_integrated_xcap_server)
611         {
612                 /* bind xcap */
613                 bind_xcap= (bind_xcap_t)find_export("bind_xcap", 1, 0);
614                 if (!bind_xcap)
615                 {
616                         LM_ERR("Can't bind xcap_client\n");
617                         return -1;
618                 }
619         
620                 if (bind_xcap(&xcap_api) < 0)
621                 {
622                         LM_ERR("Can't bind xcap\n");
623                         return -1;
624                 }
625                 xcap_GetNewDoc= xcap_api.getNewDoc;
626                 if(xcap_GetNewDoc== NULL)
627                 {
628                         LM_ERR("Can't import xcap_client functions\n");
629                         return -1;
630                 }
631         }
632
633         if (rlpres_clean_period < 0)
634                 rlpres_clean_period = clean_period;
635
636         if (clean_period > 0)           
637                 register_timer(rlsubs_table_update, 0, clean_period);
638         
639         if (rlpres_clean_period > 0)
640                 register_timer(rls_presentity_clean, 0, rlpres_clean_period);
641
642         if(dbmode == RLS_DB_ONLY)
643         {
644                 if ((rls_notifier_id = shm_malloc(sizeof(int) * rls_notifier_processes)) == NULL)
645                 {
646                         LM_ERR("allocating shared memory\n");
647                         return -1;
648                 }
649
650                 register_basic_timers(rls_notifier_processes);
651         }
652         else
653                 register_timer(timer_send_notify, 0, waitn_time);
654
655         if ((rls_update_subs_lock = lock_alloc()) == NULL)
656         {
657                 LM_ERR("Failed to alloc rls_update_subs_lock\n");
658                 return -1;
659         }
660         if (lock_init(rls_update_subs_lock) == NULL)
661         {
662                 LM_ERR("Failed to init rls_updae_subs_lock\n");
663                 return -1;
664         }
665
666         return 0;
667 }
668
669 /**
670  * Initialize children
671  */
672 static int child_init(int rank)
673 {
674         if (rank==PROC_INIT || rank==PROC_TCP_MAIN)
675                 return 0;
676
677         if (rank==PROC_MAIN && dbmode == RLS_DB_ONLY)
678         {
679                 int i;
680
681                 for (i = 0; i < rls_notifier_processes; i++)
682                 {
683                         char tmp[16];
684                         snprintf(tmp, 16, "RLS NOTIFIER %d", i);
685                         rls_notifier_id[i] = i;
686
687                         if (fork_basic_utimer(PROC_TIMER, tmp, 1,
688                                                 timer_send_notify,
689                                                 &rls_notifier_id[i],
690                                                 1000000/rls_notifier_poll_rate) < 0)
691                         {
692                                 LM_ERR("Failed to start RLS NOTIFIER %d\n", i);
693                                 return -1;
694                         }
695                 }
696
697                 return 0;
698         }
699
700         LM_DBG("child [%d]  pid [%d]\n", rank, getpid());
701
702         if (rls_dbf.init==0)
703         {
704                 LM_CRIT("database not bound\n");
705                 return -1;
706         }
707         /* In DB only mode do not pool the connections where possible. */
708         if (dbmode == RLS_DB_ONLY && rls_dbf.init2)
709                 rls_db = rls_dbf.init2(&db_url, DB_POOLING_NONE);
710         else
711                 rls_db = rls_dbf.init(&db_url);
712         if (!rls_db)
713         {
714                 LM_ERR("child %d: Error while connecting database\n",
715                                 rank);
716                 return -1;
717         }
718         else
719         {
720                 if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0)  
721                 {
722                         LM_ERR("child %d: Error in use_table rlsubs_table\n", rank);
723                         return -1;
724                 }
725
726                 LM_DBG("child %d: Database connection opened successfully\n", rank);
727         }
728
729         if (rlpres_dbf.init==0)
730         {
731                 LM_CRIT("database not bound\n");
732                 return -1;
733         }
734         /* In DB only mode do not pool the connections where possible. */
735         if (dbmode == RLS_DB_ONLY && rlpres_dbf.init2)
736                 rlpres_db = rlpres_dbf.init2(&db_url, DB_POOLING_NONE);
737         else
738                 rlpres_db = rlpres_dbf.init(&db_url);
739         if (!rlpres_db)
740         {
741                 LM_ERR("child %d: Error while connecting database\n",
742                                 rank);
743                 return -1;
744         }
745         else
746         {
747                 if (rlpres_dbf.use_table(rlpres_db, &rlpres_table) < 0)  
748                 {
749                         LM_ERR("child %d: Error in use_table rlpres_table\n", rank);
750                         return -1;
751                 }
752
753                 LM_DBG("child %d: Database connection opened successfully\n", rank);
754         }
755
756         if (rls_xcap_dbf.init==0)
757         {
758                 LM_CRIT("database not bound\n");
759                 return -1;
760         }
761         rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
762         if (!rls_xcap_db)
763         {
764                 LM_ERR("child %d: Error while connecting database\n", rank);
765                 return -1;
766         }
767         else
768         {
769                 if (rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)  
770                 {
771                         LM_ERR("child %d: Error in use_table rls_xcap_table\n", rank);
772                         return -1;
773                 }
774
775                 LM_DBG("child %d: Database connection opened successfully\n", rank);
776         }
777
778         return 0;
779 }
780
781 static int mi_child_init(void)
782 {
783         if (rls_dbf.init==0)
784         {
785                 LM_CRIT("database not bound\n");
786                 return -1;
787         }
788         /* In DB only mode do not pool the connections where possible. */
789         if (dbmode == RLS_DB_ONLY && rls_dbf.init2)
790                 rls_db = rls_dbf.init2(&db_url, DB_POOLING_NONE);
791         else
792                 rls_db = rls_dbf.init(&db_url);
793         if (!rls_db)
794         {
795                 LM_ERR("Error while connecting database\n");
796                 return -1;
797         }
798         else
799         {
800                 if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0)  
801                 {
802                         LM_ERR("Error in use_table rlsubs_table\n");
803                         return -1;
804                 }
805
806                 LM_DBG("Database connection opened successfully\n");
807         }
808
809         if (rlpres_dbf.init==0)
810         {
811                 LM_CRIT("database not bound\n");
812                 return -1;
813         }
814         /* In DB only mode do not pool the connections where possible. */
815         if (dbmode == RLS_DB_ONLY && rlpres_dbf.init2)
816                 rlpres_db = rlpres_dbf.init2(&db_url, DB_POOLING_NONE);
817         else
818                 rlpres_db = rlpres_dbf.init(&db_url);
819         if (!rlpres_db)
820         {
821                 LM_ERR("Error while connecting database\n");
822                 return -1;
823         }
824         else
825         {
826                 if (rlpres_dbf.use_table(rlpres_db, &rlpres_table) < 0)  
827                 {
828                         LM_ERR("Error in use_table rlpres_table\n");
829                         return -1;
830                 }
831
832                 LM_DBG("Database connection opened successfully\n");
833         }
834
835         if (rls_xcap_dbf.init==0)
836         {
837                 LM_CRIT("database not bound\n");
838                 return -1;
839         }
840         rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
841         if (!rls_xcap_db)
842         {
843                 LM_ERR("Error while connecting database\n");
844                 return -1;
845         }
846         else
847         {
848                 if (rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)  
849                 {
850                         LM_ERR("Error in use_table rls_xcap_table\n");
851                         return -1;
852                 }
853
854                 LM_DBG("Database connection opened successfully\n");
855         }
856
857         return 0;
858
859 }
860
861 /*
862  * destroy function
863  */
864 static void destroy(void)
865 {
866         LM_DBG("start\n");
867         
868         if(rls_table)
869         {
870                 if(rls_db)
871                         rlsubs_table_update(0, 0);
872                 pres_destroy_shtable(rls_table, hash_size);
873         }
874         if(rls_db && rls_dbf.close)
875                 rls_dbf.close(rls_db);
876         if(rlpres_db && rlpres_dbf.close)
877                 rlpres_dbf.close(rlpres_db);
878         if(rls_xcap_db && rls_xcap_dbf.close)
879                 rls_xcap_dbf.close(rls_xcap_db);
880
881         if (rls_update_subs_lock != NULL)
882         {
883                 lock_destroy(rls_update_subs_lock);
884                 lock_dealloc(rls_update_subs_lock);
885         }
886
887         if (rls_notifier_id != NULL)
888                 shm_free(rls_notifier_id);
889 }
890
891 int handle_expired_record(subs_t* s)
892 {
893         int ret;
894         int tmp;
895         /* send NOTIFY with state terminated - make sure exires value is 0 */
896         tmp = s->expires;
897         s->expires = 0;
898         ret = rls_send_notify(s, NULL, NULL, NULL);
899         s->expires = tmp;
900         if(ret <0)
901         {
902                 LM_ERR("in function send_notify\n");
903                 return -1;
904         }
905         
906         return 0;
907 }
908
909 void rlsubs_table_update(unsigned int ticks,void *param)
910 {
911         int no_lock= 0;
912
913         if (dbmode==RLS_DB_ONLY) { delete_expired_subs_rlsdb(); return; }
914
915         if(ticks== 0 && param == NULL)
916                 no_lock= 1;
917         
918         if(rls_dbf.use_table(rls_db, &rlsubs_table)< 0)
919         {
920                 LM_ERR("sql use table failed\n");
921                 return;
922         }
923         pres_update_db_subs_timer(rls_db, rls_dbf, rls_table, hash_size, 
924                         no_lock, handle_expired_record);
925
926 }
927
928 int rls_restore_db_subs(void)
929 {
930         db_key_t result_cols[24]; 
931         db1_res_t *res= NULL;
932         db_row_t *row = NULL;   
933         db_val_t *row_vals= NULL;
934         int i;
935         int n_result_cols= 0;
936         int pres_uri_col, expires_col, from_user_col, from_domain_col,to_user_col; 
937         int callid_col,totag_col,fromtag_col,to_domain_col,sockinfo_col,reason_col;
938         int event_col,contact_col,record_route_col, event_id_col, status_col;
939         int remote_cseq_col, local_cseq_col, local_contact_col, version_col;
940         int watcher_user_col, watcher_domain_col;
941         subs_t s;
942         str ev_sname;
943         pres_ev_t* event= NULL;
944         event_t parsed_event;
945         unsigned int expires;
946         unsigned int hash_code;
947
948         result_cols[pres_uri_col=n_result_cols++] = &str_presentity_uri_col;
949         result_cols[expires_col=n_result_cols++] = &str_expires_col;
950         result_cols[event_col=n_result_cols++] = &str_event_col;
951         result_cols[event_id_col=n_result_cols++] = &str_event_id_col;
952         result_cols[to_user_col=n_result_cols++] = &str_to_user_col;
953         result_cols[to_domain_col=n_result_cols++] = &str_to_domain_col;
954         result_cols[watcher_user_col=n_result_cols++] = &str_watcher_username_col;
955         result_cols[watcher_domain_col=n_result_cols++] = &str_watcher_domain_col;
956         result_cols[from_user_col=n_result_cols++] = &str_from_user_col;
957         result_cols[from_domain_col=n_result_cols++] = &str_from_domain_col;
958         result_cols[callid_col=n_result_cols++] = &str_callid_col;
959         result_cols[totag_col=n_result_cols++] = &str_to_tag_col;
960         result_cols[fromtag_col=n_result_cols++] = &str_from_tag_col;
961         result_cols[local_cseq_col= n_result_cols++] = &str_local_cseq_col;
962         result_cols[remote_cseq_col= n_result_cols++] = &str_remote_cseq_col;
963         result_cols[record_route_col= n_result_cols++] = &str_record_route_col;
964         result_cols[sockinfo_col= n_result_cols++] = &str_socket_info_col;
965         result_cols[contact_col= n_result_cols++] = &str_contact_col;
966         result_cols[local_contact_col= n_result_cols++] = &str_local_contact_col;
967         result_cols[version_col= n_result_cols++] = &str_version_col;
968         result_cols[status_col= n_result_cols++] = &str_status_col;
969         result_cols[reason_col= n_result_cols++] = &str_reason_col;
970         
971         if(!rls_db)
972         {
973                 LM_ERR("null database connection\n");
974                 return -1;
975         }
976         if(rls_dbf.use_table(rls_db, &rlsubs_table)< 0)
977         {
978                 LM_ERR("in use table\n");
979                 return -1;
980         }
981
982         if(db_fetch_query(&rls_dbf, rls_fetch_rows, rls_db, 0, 0, 0,
983                                 result_cols,0, n_result_cols, 0, &res)< 0)
984         {
985                 LM_ERR("while querrying table\n");
986                 if(res)
987                 {
988                         rls_dbf.free_result(rls_db, res);
989                         res = NULL;
990                 }
991                 return -1;
992         }
993         if(res== NULL)
994                 return -1;
995
996         if(res->n<=0)
997         {
998                 LM_INFO("The query returned no result\n");
999                 rls_dbf.free_result(rls_db, res);
1000                 res = NULL;
1001                 return 0;
1002         }
1003
1004         do {
1005                 LM_DBG("found %d db entries\n", res->n);
1006
1007                 for(i =0 ; i< res->n ; i++)
1008                 {
1009                         row = &res->rows[i];
1010                         row_vals = ROW_VALUES(row);
1011                         memset(&s, 0, sizeof(subs_t));
1012
1013                         expires= row_vals[expires_col].val.int_val;
1014                 
1015                         if(expires< (int)time(NULL))
1016                                 continue;
1017         
1018                         s.pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val;
1019                         s.pres_uri.len= strlen(s.pres_uri.s);
1020                 
1021                         s.to_user.s=(char*)row_vals[to_user_col].val.string_val;
1022                         s.to_user.len= strlen(s.to_user.s);
1023
1024                         s.to_domain.s=(char*)row_vals[to_domain_col].val.string_val;
1025                         s.to_domain.len= strlen(s.to_domain.s);
1026
1027                         s.from_user.s=(char*)row_vals[from_user_col].val.string_val;
1028                         s.from_user.len= strlen(s.from_user.s);
1029                 
1030                         s.from_domain.s=(char*)row_vals[from_domain_col].val.string_val;
1031                         s.from_domain.len= strlen(s.from_domain.s);
1032
1033                         s.watcher_user.s=(char*)row_vals[watcher_user_col].val.string_val;
1034                         s.watcher_user.len= strlen(s.watcher_user.s);
1035                 
1036                         s.watcher_domain.s=(char*)row_vals[watcher_domain_col].val.string_val;
1037                         s.watcher_domain.len= strlen(s.watcher_domain.s);
1038
1039
1040                         s.to_tag.s=(char*)row_vals[totag_col].val.string_val;
1041                         s.to_tag.len= strlen(s.to_tag.s);
1042
1043                         s.from_tag.s=(char*)row_vals[fromtag_col].val.string_val;
1044                         s.from_tag.len= strlen(s.from_tag.s);
1045
1046                         s.callid.s=(char*)row_vals[callid_col].val.string_val;
1047                         s.callid.len= strlen(s.callid.s);
1048
1049                         ev_sname.s= (char*)row_vals[event_col].val.string_val;
1050                         ev_sname.len= strlen(ev_sname.s);
1051                 
1052                         event= pres_contains_event(&ev_sname, &parsed_event);
1053                         if(event== NULL)
1054                         {
1055                                 LM_ERR("event not found in list\n");
1056                                 goto error;
1057                         }
1058                         s.event= event;
1059
1060                         s.event_id.s=(char*)row_vals[event_id_col].val.string_val;
1061                         if(s.event_id.s)
1062                                 s.event_id.len= strlen(s.event_id.s);
1063
1064                         s.remote_cseq= row_vals[remote_cseq_col].val.int_val;
1065                         s.local_cseq= row_vals[local_cseq_col].val.int_val;
1066                         s.version= row_vals[version_col].val.int_val;
1067                 
1068                         s.expires= expires- (int)time(NULL);
1069                         s.status= row_vals[status_col].val.int_val;
1070
1071                         s.reason.s= (char*)row_vals[reason_col].val.string_val;
1072                         if(s.reason.s)
1073                                 s.reason.len= strlen(s.reason.s);
1074
1075                         s.contact.s=(char*)row_vals[contact_col].val.string_val;
1076                         s.contact.len= strlen(s.contact.s);
1077
1078                         s.local_contact.s=(char*)row_vals[local_contact_col].val.string_val;
1079                         s.local_contact.len= strlen(s.local_contact.s);
1080         
1081                         s.record_route.s=(char*)row_vals[record_route_col].val.string_val;
1082                         if(s.record_route.s)
1083                                 s.record_route.len= strlen(s.record_route.s);
1084         
1085                         s.sockinfo_str.s=(char*)row_vals[sockinfo_col].val.string_val;
1086                         s.sockinfo_str.len= strlen(s.sockinfo_str.s);
1087
1088                         hash_code= core_hash(&s.pres_uri, &s.event->name, hash_size);
1089                         if(pres_insert_shtable(rls_table, hash_code, &s)< 0)
1090                         {
1091                                 LM_ERR("adding new record in hash table\n");
1092                                 goto error;
1093                         }
1094                 }
1095         } while((db_fetch_next(&rls_dbf, rls_fetch_rows, rls_db, &res)==1)
1096                         && (RES_ROW_N(res)>0));
1097
1098         rls_dbf.free_result(rls_db, res);
1099
1100         /* delete all records */
1101         if(rls_dbf.delete(rls_db, 0,0,0,0)< 0)
1102         {
1103                 LM_ERR("deleting all records from database table\n");
1104                 return -1;
1105         }
1106
1107         return 0;
1108
1109 error:
1110         if(res)
1111                 rls_dbf.free_result(rls_db, res);
1112         return -1;
1113
1114 }
1115
1116 int add_rls_event(modparam_t type, void* val)
1117 {
1118         char* event= (char*)val;
1119         event_t e;
1120
1121         if(event_parser(event, strlen(event), &e)< 0)
1122         {
1123                 LM_ERR("while parsing event = %s\n", event);
1124                 return -1;
1125         }
1126         if(e.type & EVENT_OTHER)
1127         {
1128                 LM_ERR("wrong event= %s\n", event);
1129                 return -1;
1130         }
1131
1132         rls_events|= e.type;
1133
1134         return 0;
1135
1136 }
1137
1138 int bind_rls(struct rls_binds *pxb)
1139 {
1140                 if (pxb == NULL)
1141                 {
1142                                 LM_WARN("bind_rls: Cannot load rls API into a NULL pointer\n");
1143                                 return -1;
1144                 }
1145
1146                 pxb->rls_handle_subscribe = rls_handle_subscribe;
1147                 pxb->rls_handle_subscribe0 = rls_handle_subscribe0;
1148                 pxb->rls_handle_notify = rls_handle_notify;
1149                 return 0;
1150 }
1151
1152 static struct mi_root* mi_cleanup(struct mi_root* cmd, void *param)
1153 {
1154         LM_DBG("mi_cleanup:start\n");
1155
1156         (void)rlsubs_table_update(0,0);
1157         (void)rls_presentity_clean(0,0);
1158
1159         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
1160 }