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