1 /*
2 * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
3 * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
4 *
5 * The initial version of this code was written by Dragos Vingarzan
6 * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
7 * Fruanhofer Institute. It was and still is maintained in a separate
8 * branch of the original SER. We are therefore migrating it to
9 * Kamailio/SR and look forward to maintaining it from here on out.
10 * 2011/2012 Smile Communications, Pty. Ltd.
11 * ported/maintained/improved by
12 * Jason Penton (jason(dot)penton(at)smilecoms.com and
13 * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
14 * effort to add full IMS support to Kamailio/SR using a new and
15 * improved architecture
16 *
17 * NB: Alot of this code was originally part of OpenIMSCore,
18 * FhG Fokus.
19 * Copyright (C) 2004-2006 FhG Fokus
20 * Thanks for great work! This is an effort to
21 * break apart the various CSCF functions into logically separate
22 * components. We hope this will drive wider use. We also feel
23 * that in this way the architecture is more complete and thereby easier
24 * to manage in the Kamailio/SR environment
25 *
26 * This file is part of Kamailio, a free SIP server.
27 *
28 * Kamailio is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * (at your option) any later version
32 *
33 * Kamailio is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
41 *
42 */
43
44 #include <stdio.h>
45 #include "ims_usrloc_pcscf_mod.h"
46 #include "../../core/sr_module.h"
47 #include "../../core/dprint.h"
48 #include "../../core/rpc_lookup.h"
49 #include "../../core/timer.h" /* register_timer */
50 #include "../../core/globals.h" /* is_main */
51 #include "../../core/ut.h" /* str_init */
52 #include "dlist.h" /* register_udomain */
53 #include "udomain.h" /* {insert,delete,get,release}_urecord */
54 #include "pcontact.h" /* {insert,delete,get}_ucontact */
55 #include "ul_rpc.h"
56 #include "ul_callback.h"
57 #include "usrloc.h"
58 #include "usrloc_db.h"
59
60 MODULE_VERSION
61
62 #define DEFAULT_DBG_FILE "/var/log/usrloc_debug"
63 static FILE *debug_file;
64
65 static int mod_init(void); /*!< Module initialization function */
66 static void destroy(void); /*!< Module destroy function */
67 static void timer(unsigned int ticks, void* param); /*!< Timer handler */
68 static int child_init(int rank); /*!< Per-child init function */
69
70 extern int bind_usrloc(usrloc_api_t* api);
71 extern int ul_locks_no;
72
73
74 int expires_grace = 3600; //default is a grace period of 1 hour - after this contact is removed from P
75
76 /*
77 * Module parameters and their default values
78 */
79 str usrloc_debug_file = str_init(DEFAULT_DBG_FILE);
80 int usrloc_debug = 0;
81 int ul_hash_size = 9;
82 int init_flag = 0;
83 str db_url = str_init(DEFAULT_DB_URL); /*!< Database URL */
84 int timer_interval = 60; /*!< Timer interval in seconds */
85 int db_mode = 0; /*!< Database sync scheme: 0-no db, 1-write through, 2-write back, 3-only db */
86 int ul_fetch_rows = 2000;
87 int match_contact_host_port = 1; /*!< Should we match contact just based on rui host and port*/
88
89 db1_con_t* ul_dbh = 0;
90 db_func_t ul_dbf;
91
92 /*! \brief
93 * Exported functions
94 */
95 static cmd_export_t cmds[] = {
96 {"ul_bind_ims_usrloc_pcscf", (cmd_function)bind_usrloc, 1, 0, 0, 0},
97 {0, 0, 0, 0, 0, 0}
98 };
99
100 /*! \brief
101 * Exported parameters
102 */
103 static param_export_t params[] = {
104 {"hash_size", INT_PARAM, &ul_hash_size },
105 {"timer_interval", INT_PARAM, &timer_interval },
106 {"usrloc_debug_file", PARAM_STR, &usrloc_debug_file },
107 {"enable_debug_file", INT_PARAM, &usrloc_debug},
108
109 {"db_url", PARAM_STR, &db_url },
110 {"timer_interval", INT_PARAM, &timer_interval },
111 {"db_mode", INT_PARAM, &db_mode },
112
113 {"match_contact_host_port", INT_PARAM, &match_contact_host_port },
114 {"expires_grace", INT_PARAM, &expires_grace },
115
116 {0, 0, 0}
117 };
118
119 stat_export_t mod_stats[] = {
120 {"registered_contacts" , STAT_IS_FUNC, (stat_var**)get_number_of_contacts },
121 {"registered_impus" , STAT_IS_FUNC, (stat_var**)get_number_of_impu },
122 {"expired_contacts" , STAT_IS_FUNC, (stat_var**)get_number_of_expired },
123 {0,0,0}
124 };
125
126 struct module_exports exports = {
127 "ims_usrloc_pcscf",
128 DEFAULT_DLFLAGS, /* dlopen flags */
129 cmds, /* exported functions */
130 params, /* export parameters */
131 0, /* exported RPC functions */
132 0, /* exported pseudo-variables */
133 0, /* response·function */
134 mod_init, /* module initialization function */
135 child_init, /* per-child·init·function*/
136 destroy /* destroy function */
137 };
138
139
140 /*! \brief
141 * Module initialization function
142 */
mod_init(void)143 static int mod_init(void) {
144
145 if (usrloc_debug){
146 LM_INFO("Logging usrloc records to %.*s\n", usrloc_debug_file.len, usrloc_debug_file.s);
147 debug_file = fopen(usrloc_debug_file.s, "a");
148 fprintf(debug_file, "starting\n");
149 fflush(debug_file);
150 }
151
152 #ifdef STATISTICS
153 /* register statistics */
154 if (register_module_stats( exports.name, mod_stats)!=0 ) {
155 LM_ERR("failed to register core statistics\n");
156 return -1;
157 }
158 #endif
159
160 if (ul_hash_size <= 1)
161 ul_hash_size = 512;
162 else
163 ul_hash_size = 1 << ul_hash_size;
164 ul_locks_no = ul_hash_size;
165
166 if (ul_init_locks() != 0) {
167 LM_ERR("locks array initialization failed\n");
168 return -1;
169 }
170
171 /* Regsiter RPC */
172 if (rpc_register_array(ul_rpc) != 0) {
173 LM_ERR("failed to register RPC commands\n");
174 return -1;
175 }
176
177 /* Register cache timer */
178 LM_DBG("Registering cache timer");
179 register_timer(timer, 0, timer_interval);
180
181 /* init the callbacks list */
182 if (init_ulcb_list() < 0) {
183 LM_ERR("usrloc/callbacks initialization failed\n");
184 return -1;
185 }
186
187 /* Shall we use database ? */
188 if (db_mode != NO_DB) { /* Yes */
189 if(ul_fetch_rows<=0) {
190 LM_ERR("invalid fetch_rows number '%d'\n", ul_fetch_rows);
191 return -1;
192 }
193
194 if (init_db(&db_url, timer_interval, ul_fetch_rows) != 0) {
195 LM_ERR("Error initializing db connection\n");
196 return -1;
197 }
198 LM_DBG("Running in DB mode %i\n", db_mode);
199 }
200
201 init_flag = 1;
202
203 return 0;
204 }
205
child_init(int _rank)206 static int child_init(int _rank)
207 {
208 dlist_t* ptr;
209
210 /* connecting to DB ? */
211 switch (db_mode) {
212 case NO_DB:
213 return 0;
214 case WRITE_THROUGH:
215 /* connect to db only from SIP workers, TIMER and MAIN processes */
216 if (_rank<=0 && _rank!=PROC_TIMER && _rank!=PROC_MAIN)
217 return 0;
218 break;
219 case WRITE_BACK:
220 /* connect to db only from TIMER (for flush), from MAIN (for
221 * final flush() and from child 1 for preload */
222 if (_rank!=PROC_TIMER && _rank!=PROC_MAIN && _rank!=PROC_SIPINIT)
223 return 0;
224 break;
225 }
226
227 LM_DBG("Connecting to usrloc_pcscf DB for rank %d\n", _rank);
228 if (connect_db(&db_url) != 0) {
229 LM_ERR("child(%d): failed to connect to database\n", _rank);
230 return -1;
231 }
232 /* _rank==PROC_SIPINIT is used even when fork is disabled */
233 if (_rank==PROC_SIPINIT && db_mode!=DB_ONLY) {
234 // if cache is used, populate domains from DB
235 for( ptr=root ; ptr ; ptr=ptr->next) {
236 LM_DBG("Preloading domain %.*s\n", ptr->name.len, ptr->name.s);
237 if (preload_udomain(ul_dbh, ptr->d) < 0) {
238 LM_ERR("child(%d): failed to preload domain '%.*s'\n",
239 _rank, ptr->name.len, ZSW(ptr->name.s));
240 return -1;
241 }
242 }
243 }
244
245 return 0;
246 }
247
248 /*! \brief
249 * Module destroy function
250 */
destroy(void)251 static void destroy(void)
252 {
253 free_all_udomains();
254 ul_destroy_locks();
255
256 /* free callbacks list */
257 destroy_ulcb_list();
258
259 free_service_route_buf();
260 free_impu_buf();
261
262 if (db_mode)
263 destroy_db();
264 }
265
266
267 /*! \brief
268 * Timer handler
269 */
timer(unsigned int ticks,void * param)270 static void timer(unsigned int ticks, void* param) {
271 LM_DBG("Syncing cache\n");
272 if (usrloc_debug) {
273 print_all_udomains(debug_file);
274 fflush(debug_file);
275 }
276
277 if (synchronize_all_udomains() != 0) {
278 LM_ERR("synchronizing cache failed\n");
279 }
280 }
281
282