all: updated FSF address in GPL text
[sip-router] / modules / dialog / dlg_db_handler.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2007 Voice System SRL
5  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
6  *
7  * This file is part of Kamailio, a free SIP server.
8  *
9  * Kamailio is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * Kamailio is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License 
20  * along with this program; if not, write to the Free Software 
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  * History:
24  * --------
25  * 2007-05-10  initial version (ancuta)
26  * 2007-07-06 additional information saved in the database: cseq, contact, 
27  *                 route set and socket_info for both caller and callee (ancuta)
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/time.h>
33
34 #include "../../dprint.h"
35 #include "../../ut.h"
36 #include "../../timer.h"
37 #include "../../lib/srdb1/db.h"
38 #include "../../str.h"
39 #include "../../socket_info.h"
40 #include "dlg_hash.h"
41 #include "dlg_var.h"
42 #include "dlg_profile.h"
43 #include "dlg_db_handler.h"
44
45
46 str call_id_column                      =       str_init(CALL_ID_COL);
47 str from_uri_column                     =       str_init(FROM_URI_COL);
48 str from_tag_column                     =       str_init(FROM_TAG_COL);
49 str to_uri_column                       =       str_init(TO_URI_COL);
50 str to_tag_column                       =       str_init(TO_TAG_COL);
51 str h_id_column                         =       str_init(HASH_ID_COL);
52 str h_entry_column                      =       str_init(HASH_ENTRY_COL);
53 str state_column                        =       str_init(STATE_COL);
54 str start_time_column           =       str_init(START_TIME_COL);
55 str timeout_column                      =       str_init(TIMEOUT_COL);
56 str to_cseq_column                      =       str_init(TO_CSEQ_COL);
57 str from_cseq_column            =       str_init(FROM_CSEQ_COL);
58 str to_route_column                     =       str_init(TO_ROUTE_COL);
59 str from_route_column           =       str_init(FROM_ROUTE_COL);
60 str to_contact_column           =       str_init(TO_CONTACT_COL);
61 str from_contact_column         =       str_init(FROM_CONTACT_COL);
62 str to_sock_column                      =       str_init(TO_SOCK_COL);
63 str from_sock_column            =       str_init(FROM_SOCK_COL);
64 str sflags_column                       =       str_init(SFLAGS_COL);
65 str iflags_column                       =       str_init(IFLAGS_COL);
66 str toroute_name_column         =       str_init(TOROUTE_NAME_COL);
67 str req_uri_column                      =       str_init(REQ_URI_COL);
68 str xdata_column                        =       str_init(XDATA_COL);
69 str dialog_table_name           =       str_init(DIALOG_TABLE_NAME);
70 int dlg_db_mode                         =       DB_MODE_NONE;
71
72 str vars_h_id_column            =       str_init(VARS_HASH_ID_COL);
73 str vars_h_entry_column         =       str_init(VARS_HASH_ENTRY_COL);
74 str vars_key_column             =       str_init(VARS_KEY_COL);
75 str vars_value_column           =       str_init(VARS_VALUE_COL);
76 str dialog_vars_table_name      =       str_init(DIALOG_VARS_TABLE_NAME);
77
78 static db1_con_t* dialog_db_handle    = 0; /* database connection handle */
79 static db_func_t dialog_dbf;
80
81 extern int dlg_enable_stats;
82 extern int active_dlgs_cnt;
83 extern int early_dlgs_cnt;
84
85
86 #define SET_STR_VALUE(_val, _str)\
87         do{\
88                         VAL_STR((_val)).s               = (_str).s;\
89                         VAL_STR((_val)).len     = (_str).len;\
90         }while(0);
91
92 #define SET_NULL_FLAG(_vals, _i, _max, _flag)\
93         do{\
94                 for((_i) = 0;(_i)<(_max); (_i)++)\
95                         VAL_NULL((_vals)+(_i)) = (_flag);\
96         }while(0);
97
98 #define SET_PROPER_NULL_FLAG(_str, _vals, _index)\
99         do{\
100                 if( (_str).len == 0)\
101                         VAL_NULL( (_vals)+(_index) ) = 1;\
102                 else\
103                         VAL_NULL( (_vals)+(_index) ) = 0;\
104         }while(0);
105
106 #define GET_STR_VALUE(_res, _values, _index, _not_null, _unref)\
107         do{\
108                 if (VAL_NULL((_values)+ (_index))) { \
109                         if (_not_null) {\
110                                 if (_unref) dlg_unref(dlg,1);\
111                                 goto next_dialog; \
112                         } else { \
113                                 (_res).s = 0; \
114                                 (_res).len = 0; \
115                         }\
116                 } else { \
117                         (_res).s = VAL_STR((_values)+ (_index)).s;\
118                         (_res).len = strlen(VAL_STR((_values)+ (_index)).s);\
119                 } \
120         }while(0);
121
122
123 static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows);
124 static int load_dialog_vars_from_db(int fetch_num_rows);
125
126 int dlg_connect_db(const str *db_url)
127 {
128         if (dialog_db_handle) {
129                 LM_CRIT("BUG - db connection found already open\n");
130                 return -1;
131         }
132         if ((dialog_db_handle = dialog_dbf.init(db_url)) == 0)
133                 return -1;
134         return 0;
135 }
136
137
138 int init_dlg_db(const str *db_url, int dlg_hash_size , int db_update_period, int fetch_num_rows)
139 {
140         /* Find a database module */
141         if (db_bind_mod(db_url, &dialog_dbf) < 0){
142                 LM_ERR("Unable to bind to a database driver\n");
143                 return -1;
144         }
145
146         if (dlg_connect_db(db_url)!=0){
147                 LM_ERR("unable to connect to the database\n");
148                 return -1;
149         }
150
151         if(db_check_table_version(&dialog_dbf, dialog_db_handle, &dialog_table_name, DLG_TABLE_VERSION) < 0) {
152                 LM_ERR("error during dialog-table version check.\n");
153                 return -1;
154         }
155
156         if(db_check_table_version(&dialog_dbf, dialog_db_handle, &dialog_vars_table_name, DLG_VARS_TABLE_VERSION) < 0) {
157                 LM_ERR("error during dialog-vars version check.\n");
158                 return -1;
159         }
160
161         if( (dlg_db_mode==DB_MODE_DELAYED) && 
162         (register_timer( dialog_update_db, 0, db_update_period)<0 )) {
163                 LM_ERR("failed to register update db\n");
164                 return -1;
165         }
166
167         if( (load_dialog_info_from_db(dlg_hash_size, fetch_num_rows) ) !=0 ){
168                 LM_ERR("unable to load the dialog data\n");
169                 return -1;
170         }
171         if( (load_dialog_vars_from_db(fetch_num_rows) ) !=0 ){
172                 LM_ERR("unable to load the dialog data\n");
173                 return -1;
174         }
175
176         dialog_dbf.close(dialog_db_handle);
177         dialog_db_handle = 0;
178
179         return 0;
180 }
181
182
183
184 void destroy_dlg_db(void)
185 {
186         /* close the DB connection */
187         if (dialog_db_handle) {
188                 dialog_dbf.close(dialog_db_handle);
189                 dialog_db_handle = 0;
190         }
191 }
192
193
194
195 static int use_dialog_table(void)
196 {
197         if(!dialog_db_handle){
198                 LM_ERR("invalid database handle\n");
199                 return -1;
200         }
201
202         if (dialog_dbf.use_table(dialog_db_handle, &dialog_table_name) < 0) {
203                 LM_ERR("Error in use_table\n");
204                 return -1;
205         }
206
207         return 0;
208 }
209
210 static int use_dialog_vars_table(void)
211 {
212         if(!dialog_db_handle){
213                 LM_ERR("invalid database handle\n");
214                 return -1;
215         }
216
217         if (dialog_dbf.use_table(dialog_db_handle, &dialog_vars_table_name) < 0) {
218                 LM_ERR("Error in use_table\n");
219                 return -1;
220         }
221
222         return 0;
223 }
224
225
226
227 static int select_entire_dialog_table(db1_res_t ** res, int fetch_num_rows)
228 {
229         db_key_t query_cols[DIALOG_TABLE_COL_NO] = {    &h_entry_column,
230                         &h_id_column,           &call_id_column,        &from_uri_column,
231                         &from_tag_column,       &to_uri_column,         &to_tag_column,
232                         &start_time_column,     &state_column,          &timeout_column,
233                         &from_cseq_column,      &to_cseq_column,        &from_route_column,
234                         &to_route_column,       &from_contact_column, &to_contact_column,
235                         &from_sock_column,      &to_sock_column,    &sflags_column,
236                         &toroute_name_column,   &req_uri_column, &xdata_column,
237                         &iflags_column};
238
239         if(use_dialog_table() != 0){
240                 return -1;
241         }
242
243         /* select the whole tabel and all the columns */
244         if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
245                 if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0, 
246                 DIALOG_TABLE_COL_NO, 0, 0) < 0) {
247                         LM_ERR("Error while querying (fetch) database\n");
248                         return -1;
249                 }
250                 if(dialog_dbf.fetch_result(dialog_db_handle, res, fetch_num_rows) < 0) {
251                         LM_ERR("fetching rows failed\n");
252                         return -1;
253                 }
254         } else {
255                 if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0,
256                 DIALOG_TABLE_COL_NO, 0, res) < 0) {
257                         LM_ERR("Error while querying database\n");
258                         return -1;
259                 }
260         }
261
262         return 0;
263 }
264
265
266
267 struct socket_info * create_socket_info(db_val_t * vals, int n){
268
269         struct socket_info * sock;
270         char* p;
271         str host;
272         int port, proto;
273
274         /* socket name */
275         p = (VAL_STR(vals+n)).s;
276
277         if (VAL_NULL(vals+n) || p==0 || p[0]==0){
278                 sock = 0;
279         } else {
280                 if (parse_phostport( p, &host.s, &host.len, 
281                 &port, &proto)!=0) {
282                         LM_ERR("bad socket <%s>\n", p);
283                         return 0;
284                 }
285                 sock = grep_sock_info( &host, (unsigned short)port, proto);
286                 if (sock==0) {
287                         LM_WARN("non-local socket <%s>...ignoring\n", p);
288                         }
289         }
290
291         return sock;
292 }
293
294
295
296 static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
297 {
298         db1_res_t * res;
299         db_val_t * values;
300         db_row_t * rows;
301         int i, nr_rows;
302         struct dlg_cell *dlg;
303         str callid, from_uri, to_uri, from_tag, to_tag, req_uri;
304         str cseq1, cseq2, contact1, contact2, rroute1, rroute2;
305         str toroute_name;
306         str xdata;
307         unsigned int next_id;
308         srjson_doc_t jdoc;
309         
310         res = 0;
311         if((nr_rows = select_entire_dialog_table(&res, fetch_num_rows)) < 0)
312                 goto end;
313
314         nr_rows = RES_ROW_N(res);
315
316         LM_DBG("the database has information about %i dialogs\n", nr_rows);
317
318         rows = RES_ROWS(res);
319
320         do {
321                 /* for every row---dialog */
322                 for(i=0; i<nr_rows; i++){
323
324                         values = ROW_VALUES(rows + i);
325
326                         if (VAL_NULL(values) || VAL_NULL(values+1)) {
327                                 LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
328                                         h_entry_column.len, h_entry_column.s,
329                                         h_id_column.len, h_id_column.s);
330                                 continue;
331                         }
332
333                         if (VAL_NULL(values+7) || VAL_NULL(values+8)) {
334                                 LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
335                                         start_time_column.len, start_time_column.s,
336                                         state_column.len, state_column.s);
337                                 continue;
338                         }
339
340                         /*restore the dialog info*/
341                         GET_STR_VALUE(callid, values, 2, 1, 0);
342                         GET_STR_VALUE(from_uri, values, 3, 1, 0);
343                         GET_STR_VALUE(from_tag, values, 4, 1, 0);
344                         GET_STR_VALUE(to_uri, values, 5, 1, 0);
345                         GET_STR_VALUE(req_uri, values, 20, 1, 0);
346
347                         if((dlg=build_new_dlg(&callid, &from_uri, &to_uri, &from_tag,
348                                                         &req_uri))==0){
349                                 LM_ERR("failed to build new dialog\n");
350                                 goto error;
351                         }
352
353                         if(dlg->h_entry != VAL_INT(values)){
354                                 LM_ERR("inconsistent hash data in the dialog database: "
355                                         "you may have restarted Kamailio using a different "
356                                         "hash_size: please erase %.*s database and restart\n", 
357                                         dialog_table_name.len, dialog_table_name.s);
358                                 shm_free(dlg);
359                                 goto error;
360                         }
361
362                         /*link the dialog*/
363                         link_dlg(dlg, 0);
364
365                         dlg->h_id = VAL_INT(values+1);
366                         next_id = d_table->entries[dlg->h_entry].next_id;
367
368                         d_table->entries[dlg->h_entry].next_id =
369                                 (next_id < dlg->h_id) ? (dlg->h_id+1) : next_id;
370
371                         GET_STR_VALUE(to_tag, values, 6, 1, 1);
372
373                         dlg->start_ts   = VAL_INT(values+7);
374
375                         dlg->state              = VAL_INT(values+8);
376                         if (dlg->state==DLG_STATE_CONFIRMED_NA ||
377                         dlg->state==DLG_STATE_CONFIRMED) {
378                                 active_dlgs_cnt++;
379                         } else if (dlg->state==DLG_STATE_EARLY) {
380                                 early_dlgs_cnt++;
381                         }
382
383                         dlg->tl.timeout = (unsigned int)(VAL_INT(values+9));
384                         LM_DBG("db dialog timeout is %u (%u/%u)\n", dlg->tl.timeout,
385                                         get_ticks(), (unsigned int)time(0));
386                         if (dlg->tl.timeout<=(unsigned int)time(0))
387                                 dlg->tl.timeout = 0;
388                         else
389                                 dlg->tl.timeout -= (unsigned int)time(0);
390                         dlg->lifetime = dlg->tl.timeout;
391
392                         GET_STR_VALUE(cseq1, values, 10 , 1, 1);
393                         GET_STR_VALUE(cseq2, values, 11 , 1, 1);
394                         GET_STR_VALUE(rroute1, values, 12, 0, 0);
395                         GET_STR_VALUE(rroute2, values, 13, 0, 0);
396                         GET_STR_VALUE(contact1, values, 14, 1, 1);
397                         GET_STR_VALUE(contact2, values, 15, 1, 1);
398
399                         if ( (dlg_set_leg_info( dlg, &from_tag, &rroute1, &contact1,
400                         &cseq1, DLG_CALLER_LEG)!=0) ||
401                         (dlg_set_leg_info( dlg, &to_tag, &rroute2, &contact2,
402                         &cseq2, DLG_CALLEE_LEG)!=0) ) {
403                                 LM_ERR("dlg_set_leg_info failed\n");
404                                 dlg_unref(dlg,1);
405                                 continue;
406                         }
407
408                         dlg->bind_addr[DLG_CALLER_LEG] = create_socket_info(values, 16);
409                         dlg->bind_addr[DLG_CALLEE_LEG] = create_socket_info(values, 17);
410
411                         dlg->sflags = (unsigned int)VAL_INT(values+18);
412
413                         GET_STR_VALUE(toroute_name, values, 19, 0, 0);
414                         dlg_set_toroute(dlg, &toroute_name);
415
416                         GET_STR_VALUE(xdata, values, 21, 0, 0);
417                         if(xdata.s!=NULL && dlg->state!=DLG_STATE_DELETED)
418                         {
419                                 srjson_InitDoc(&jdoc, NULL);
420                                 jdoc.buf = xdata;
421                                 dlg_json_to_profiles(dlg, &jdoc);
422                                 srjson_DestroyDoc(&jdoc);
423                         }
424                         dlg->iflags = (unsigned int)VAL_INT(values+22);
425                         /*restore the timer values */
426                         if (0 != insert_dlg_timer( &(dlg->tl), (int)dlg->tl.timeout )) {
427                                 LM_CRIT("Unable to insert dlg %p [%u:%u] "
428                                         "with clid '%.*s' and tags '%.*s' '%.*s'\n",
429                                         dlg, dlg->h_entry, dlg->h_id,
430                                         dlg->callid.len, dlg->callid.s,
431                                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
432                                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
433                                 dlg_unref(dlg,1);
434                                 continue;
435                         }
436                         dlg_ref(dlg,1);
437                         LM_DBG("current dialog timeout is %u (%u)\n", dlg->tl.timeout,
438                                         get_ticks());
439
440                         dlg->dflags = 0;
441                         next_dialog:
442                         ;
443                 }
444
445                 /* any more data to be fetched ?*/
446                 if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
447                         if(dialog_dbf.fetch_result(dialog_db_handle, &res, fetch_num_rows) < 0) {
448                                 LM_ERR("re-fetching rows failed\n");
449                                 goto error;
450                         }
451                         nr_rows = RES_ROW_N(res);
452                         rows = RES_ROWS(res);
453                 } else {
454                         nr_rows = 0;
455                 }
456
457         }while (nr_rows>0);
458
459         if (dlg_db_mode==DB_MODE_SHUTDOWN) {
460                 if (dialog_dbf.delete(dialog_db_handle, 0, 0, 0, 0) < 0) {
461                         LM_ERR("failed to clear dialog table\n");
462                         goto error;
463                 }
464         }
465
466 end:
467         dialog_dbf.free_result(dialog_db_handle, res);
468         return 0;
469 error:
470         dialog_dbf.free_result(dialog_db_handle, res);
471         return -1;
472
473 }
474
475
476
477 static int select_entire_dialog_vars_table(db1_res_t ** res, int fetch_num_rows)
478 {
479         db_key_t query_cols[DIALOG_VARS_TABLE_COL_NO] = {       &vars_h_entry_column,
480                         &vars_h_id_column,      &vars_key_column,       &vars_value_column };
481
482         if(use_dialog_vars_table() != 0){
483                 return -1;
484         }
485
486         /* select the whole tabel and all the columns */
487         if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
488                 if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0, 
489                 DIALOG_VARS_TABLE_COL_NO, 0, 0) < 0) {
490                         LM_ERR("Error while querying (fetch) database\n");
491                         return -1;
492                 }
493                 if(dialog_dbf.fetch_result(dialog_db_handle, res, fetch_num_rows) < 0) {
494                         LM_ERR("fetching rows failed\n");
495                         return -1;
496                 }
497         } else {
498                 if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0,
499                 DIALOG_VARS_TABLE_COL_NO, 0, res) < 0) {
500                         LM_ERR("Error while querying database\n");
501                         return -1;
502                 }
503         }
504
505         return 0;
506 }
507
508 static int load_dialog_vars_from_db(int fetch_num_rows)
509 {
510         db1_res_t * res;
511         db_val_t * values;
512         db_row_t * rows;
513         struct dlg_cell  * dlg; 
514         int i, nr_rows;
515
516         res = 0;
517         if((nr_rows = select_entire_dialog_vars_table(&res, fetch_num_rows)) < 0)
518                 goto end;
519
520         nr_rows = RES_ROW_N(res);
521
522         LM_DBG("the database has information about %i dialog variables\n", nr_rows);
523
524         rows = RES_ROWS(res);
525
526         do {
527                 /* for every row---dialog */
528                 for(i=0; i<nr_rows; i++){
529
530                         values = ROW_VALUES(rows + i);
531
532                         if (VAL_NULL(values) || VAL_NULL(values+1)) {
533                                 LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
534                                         vars_h_entry_column.len, vars_h_entry_column.s,
535                                         vars_h_id_column.len, vars_h_id_column.s);
536                                 continue;
537                         }
538
539                         if (VAL_NULL(values+2) || VAL_NULL(values+3)) {
540                                 LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
541                                         vars_key_column.len, vars_key_column.s,
542                                         vars_value_column.len, vars_value_column.s);
543                                 continue;
544                         }
545                         if (VAL_INT(values) < d_table->size) {
546                                 dlg = (d_table->entries)[VAL_INT(values)].first;
547                                 while (dlg) {
548                                         if (dlg->h_id == VAL_INT(values+1)) {
549                                                 str key = { VAL_STR(values+2).s, strlen(VAL_STRING(values+2)) };
550                                                 str value = { VAL_STR(values+3).s, strlen(VAL_STRING(values+3)) };
551                                                 set_dlg_variable_unsafe(dlg, &key, &value);
552                                                 break;
553                                         }
554                                         dlg = dlg->next;
555                                         if (!dlg) {
556                                                 LM_WARN("insonsistent data: the dialog h_entry/h_id does not exist!\n");
557                                         }
558                                 }
559                         } else {
560                                 LM_WARN("insonsistent data: the h_entry in the DB does not exist!\n");
561                         }
562                 }
563
564                 /* any more data to be fetched ?*/
565                 if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
566                         if(dialog_dbf.fetch_result(dialog_db_handle, &res, fetch_num_rows) < 0) {
567                                 LM_ERR("re-fetching rows failed\n");
568                                 goto error;
569                         }
570                         nr_rows = RES_ROW_N(res);
571                         rows = RES_ROWS(res);
572                 } else {
573                         nr_rows = 0;
574                 }
575
576         }while (nr_rows>0);
577
578         if (dlg_db_mode==DB_MODE_SHUTDOWN) {
579                 if (dialog_dbf.delete(dialog_db_handle, 0, 0, 0, 0) < 0) {
580                         LM_ERR("failed to clear dialog variable table\n");
581                         goto error;
582                 }
583         }
584
585 end:
586         dialog_dbf.free_result(dialog_db_handle, res);
587         return 0;
588 error:
589         dialog_dbf.free_result(dialog_db_handle, res);
590         return -1;
591
592 }
593
594 /*this is only called from destroy_dlg, where the cell's entry lock is acquired*/
595 int remove_dialog_from_db(struct dlg_cell * cell)
596 {
597         db_val_t values[2];
598         db_key_t match_keys[2] = { &h_entry_column, &h_id_column};
599         db_key_t vars_match_keys[2] = { &vars_h_entry_column, &vars_h_id_column};
600
601         /*if the dialog hasn 't been yet inserted in the database*/
602         LM_DBG("trying to remove dialog [%.*s], update_flag is %i\n",
603                         cell->callid.len, cell->callid.s,
604                         cell->dflags);
605         if (cell->dflags & DLG_FLAG_NEW) 
606                 return 0;
607
608         if (use_dialog_table()!=0)
609                 return -1;
610
611         VAL_TYPE(values) = VAL_TYPE(values+1) = DB1_INT;
612         VAL_NULL(values) = VAL_NULL(values+1) = 0;
613
614         VAL_INT(values)         = cell->h_entry;
615         VAL_INT(values+1)       = cell->h_id;
616
617         if(dialog_dbf.delete(dialog_db_handle, match_keys, 0, values, 2) < 0) {
618                 LM_ERR("failed to delete database information\n");
619                 return -1;
620         }
621
622         if (use_dialog_vars_table()!=0)
623                 return -1;
624
625         if(dialog_dbf.delete(dialog_db_handle, vars_match_keys, 0, values, 2) < 0) {
626                 LM_ERR("failed to delete database information\n");
627                 return -1;
628         }
629
630         LM_DBG("callid was %.*s\n", cell->callid.len, cell->callid.s );
631
632         return 0;
633 }
634
635
636 int update_dialog_vars_dbinfo(struct dlg_cell * cell, struct dlg_var * var)
637 {
638         db_val_t values[DIALOG_VARS_TABLE_COL_NO];
639
640         db_key_t insert_keys[DIALOG_VARS_TABLE_COL_NO] = { &vars_h_entry_column,
641                         &vars_h_id_column,      &vars_key_column,       &vars_value_column };
642
643         if(use_dialog_vars_table()!=0)
644                 return -1;
645
646         VAL_TYPE(values) = VAL_TYPE(values+1) = DB1_INT;
647         VAL_TYPE(values+2) = VAL_TYPE(values+3) = DB1_STR;
648         VAL_NULL(values) = VAL_NULL(values+1) = VAL_NULL(values+2) = VAL_NULL(values+3) = 0;
649         SET_STR_VALUE(values+2, var->key);
650
651         VAL_INT(values)                 = cell->h_entry;
652         VAL_INT(values+1)               = cell->h_id;
653         
654         if((var->vflags & DLG_FLAG_DEL) != 0) {
655                 /* delete the current variable */
656                 db_key_t vars_match_keys[3] = { &vars_h_entry_column, &vars_h_id_column, &vars_key_column};
657
658                 if (use_dialog_vars_table()!=0)
659                         return -1;
660
661                 if(dialog_dbf.delete(dialog_db_handle, vars_match_keys, 0, values, 3) < 0) {
662                         LM_ERR("failed to delete database information\n");
663                         return -1;
664                 }
665         } else if((var->vflags & DLG_FLAG_NEW) != 0) {
666                 /* save all the current dialogs information*/
667                 SET_STR_VALUE(values+3, var->value);
668
669                 if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, 
670                                                                 DIALOG_VARS_TABLE_COL_NO)) !=0){
671                         LM_ERR("could not add another dialog-var to db\n");
672                         goto error;
673                 }
674                 var->vflags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED);
675         } else if((var->vflags & DLG_FLAG_CHANGED) != 0) {
676                 /* save only dialog's state and timeout */
677                 SET_STR_VALUE(values+3, var->value);
678
679                 if((dialog_dbf.update(dialog_db_handle, insert_keys, 0, 
680                                                 values, (insert_keys+3), (values+3), 3, 1)) !=0){
681                         LM_ERR("could not update database info\n");
682                         goto error;
683                 }
684                 var->vflags &= ~DLG_FLAG_CHANGED;
685         } else {
686                 return 0;
687         }
688         return 0;
689 error:
690         return -1;
691 }
692
693
694 int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
695 {
696         int i;
697         struct dlg_var *var;
698         srjson_doc_t jdoc;
699
700         db_val_t values[DIALOG_TABLE_COL_NO];
701
702         db_key_t insert_keys[DIALOG_TABLE_COL_NO] = { &h_entry_column,
703                         &h_id_column,        &call_id_column,     &from_uri_column,
704                         &from_tag_column,    &to_uri_column,      &to_tag_column,
705                         &from_sock_column,   &to_sock_column,
706                         &start_time_column,  &state_column,       &timeout_column,
707                         &from_cseq_column,   &to_cseq_column,     &from_route_column,
708                         &to_route_column,    &from_contact_column,&to_contact_column,
709                         &sflags_column,      &toroute_name_column,     &req_uri_column,
710                         &xdata_column, &iflags_column };
711
712         if( (cell->dflags & DLG_FLAG_NEW) != 0 
713         || (cell->dflags & DLG_FLAG_CHANGED_VARS) != 0) {
714                 /* iterate the list */
715                 for(var=cell->vars ; var ; var=var->next) {
716                         if (update_dialog_vars_dbinfo(cell, var) != 0)
717                                 return -1;
718                 }
719                 /* Remove the flag */
720                 cell->dflags &= ~DLG_FLAG_CHANGED_VARS;
721         }
722
723         if(use_dialog_table()!=0)
724                 return -1;
725         
726         srjson_InitDoc(&jdoc, NULL);
727
728         if((cell->dflags & DLG_FLAG_NEW) != 0){
729                 /* save all the current dialogs information*/
730                 VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = 
731                 VAL_TYPE(values+10) = VAL_TYPE(values+11) = DB1_INT;
732
733                 VAL_TYPE(values+2) = VAL_TYPE(values+3) = VAL_TYPE(values+4) = 
734                 VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = 
735                 VAL_TYPE(values+8) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = 
736                 VAL_TYPE(values+14) = VAL_TYPE(values+15) = VAL_TYPE(values+16)=
737                 VAL_TYPE(values+17) = VAL_TYPE(values+20) = DB1_STR;
738
739                 SET_NULL_FLAG(values, i, DIALOG_TABLE_COL_NO-6, 0);
740                 VAL_TYPE(values+18) = DB1_INT;
741                 VAL_TYPE(values+19) = DB1_STR;
742                 VAL_TYPE(values+21) = DB1_STR;
743                 VAL_TYPE(values+22) = DB1_INT;
744
745                 VAL_INT(values)                 = cell->h_entry;
746                 VAL_INT(values+1)               = cell->h_id;
747                 VAL_INT(values+9)               = cell->start_ts;
748                 VAL_INT(values+10)              = cell->state;
749                 VAL_INT(values+11)              = (unsigned int)( (unsigned int)time(0) +
750                                  cell->tl.timeout - get_ticks() );
751
752                 SET_STR_VALUE(values+2, cell->callid);
753                 SET_STR_VALUE(values+3, cell->from_uri);
754                 SET_STR_VALUE(values+4, cell->tag[DLG_CALLER_LEG]);
755                 SET_STR_VALUE(values+5, cell->to_uri);
756                 SET_STR_VALUE(values+6, cell->tag[DLG_CALLEE_LEG]);
757                 SET_PROPER_NULL_FLAG(cell->tag[DLG_CALLEE_LEG], values, 6);
758
759                 LM_DBG("sock_info is %.*s\n", 
760                         cell->bind_addr[DLG_CALLER_LEG]->sock_str.len,
761                         cell->bind_addr[DLG_CALLEE_LEG]->sock_str.s);
762
763                 SET_STR_VALUE(values+7, cell->bind_addr[DLG_CALLER_LEG]->sock_str);
764                 SET_STR_VALUE(values+8, cell->bind_addr[DLG_CALLEE_LEG]->sock_str);
765
766                 SET_STR_VALUE(values+12, cell->cseq[DLG_CALLER_LEG]);
767                 SET_STR_VALUE(values+13, cell->cseq[DLG_CALLEE_LEG]);
768                 SET_STR_VALUE(values+14, cell->route_set[DLG_CALLER_LEG]);
769                 SET_STR_VALUE(values+15, cell->route_set[DLG_CALLEE_LEG]);
770                 SET_STR_VALUE(values+16, cell->contact[DLG_CALLER_LEG]);
771                 SET_STR_VALUE(values+17, cell->contact[DLG_CALLEE_LEG]);
772
773                 SET_PROPER_NULL_FLAG(cell->route_set[DLG_CALLER_LEG],   values, 14);
774                 SET_PROPER_NULL_FLAG(cell->route_set[DLG_CALLEE_LEG],   values, 15);
775                 SET_PROPER_NULL_FLAG(cell->contact[DLG_CALLER_LEG],     values, 16);
776                 SET_PROPER_NULL_FLAG(cell->contact[DLG_CALLEE_LEG],     values, 17);
777
778                 VAL_NULL(values+18) = 0;
779                 VAL_INT(values+18)  = cell->sflags;
780
781                 SET_STR_VALUE(values+19, cell->toroute_name);
782                 SET_PROPER_NULL_FLAG(cell->toroute_name, values, 19);
783                 SET_STR_VALUE(values+20, cell->req_uri);
784                 SET_PROPER_NULL_FLAG(cell->req_uri,     values, 20);
785
786                 dlg_profiles_to_json(cell, &jdoc);
787                 if(jdoc.buf.s!=NULL)
788                 {
789                         SET_STR_VALUE(values+21, jdoc.buf);
790                         SET_PROPER_NULL_FLAG(jdoc.buf, values, 21);
791                 } else {
792                         VAL_NULL(values+21) = 1;
793                 }
794
795                 VAL_NULL(values+22) = 0;
796                 VAL_INT(values+22)  = cell->iflags;
797
798                 if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, 
799                                                                 DIALOG_TABLE_COL_NO)) !=0){
800                         LM_ERR("could not add another dialog to db\n");
801                         goto error;
802                 }
803                 cell->dflags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED);
804                 
805         } else if((cell->dflags & DLG_FLAG_CHANGED) != 0) {
806                 /* save only dialog's state and timeout */
807                 VAL_TYPE(values) = VAL_TYPE(values+1) = 
808                 VAL_TYPE(values+10) = VAL_TYPE(values+11) = DB1_INT;
809
810                 VAL_TYPE(values+12) = VAL_TYPE(values+13) =DB1_STR;
811
812                 VAL_INT(values)                 = cell->h_entry;
813                 VAL_INT(values+1)               = cell->h_id;
814                 VAL_INT(values+10)              = cell->state;
815                 VAL_INT(values+11)              = (unsigned int)( (unsigned int)time(0) +
816                                  cell->tl.timeout - get_ticks() );
817
818                 SET_STR_VALUE(values+12, cell->cseq[DLG_CALLER_LEG]);
819                 SET_STR_VALUE(values+13, cell->cseq[DLG_CALLEE_LEG]);
820
821
822                 VAL_NULL(values) = VAL_NULL(values+1) = 
823                 VAL_NULL(values+10) = VAL_NULL(values+11) = 
824                 VAL_NULL(values+12) = VAL_NULL(values+13) = 0;
825
826                 if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, 
827                                                 (values), (insert_keys+10), (values+10), 2, 4)) !=0){
828                         LM_ERR("could not update database info\n");
829                         goto error;
830                 }
831                 cell->dflags &= ~(DLG_FLAG_CHANGED);
832         } else {
833                 return 0;
834         }
835
836         if(jdoc.buf.s!=NULL) {
837                 jdoc.free_fn(jdoc.buf.s);
838                 jdoc.buf.s = NULL;
839         }
840         srjson_DestroyDoc(&jdoc);
841
842         return 0;
843
844 error:
845         if(jdoc.buf.s!=NULL) {
846                 jdoc.free_fn(jdoc.buf.s);
847                 jdoc.buf.s = NULL;
848         }
849         srjson_DestroyDoc(&jdoc);
850         return -1;
851 }
852
853 int update_dialog_dbinfo(struct dlg_cell * cell)
854 {
855         struct dlg_entry entry;
856         /* lock the entry */
857         entry = (d_table->entries)[cell->h_entry];
858         dlg_lock( d_table, &entry);
859         if (update_dialog_dbinfo_unsafe(cell) != 0) {
860                 dlg_unlock( d_table, &entry);
861                 return -1;
862         } 
863         dlg_unlock( d_table, &entry);
864         return 0;
865 }
866
867 void dialog_update_db(unsigned int ticks, void * param)
868 {
869         int index;
870         struct dlg_entry entry;
871         struct dlg_cell  * cell; 
872
873         LM_DBG("saving current_info \n");
874         
875         for(index = 0; index< d_table->size; index++){
876                 /* lock the whole entry */
877                 entry = (d_table->entries)[index];
878                 dlg_lock( d_table, &entry);
879
880                 for(cell = entry.first; cell != NULL; cell = cell->next){
881                         if (update_dialog_dbinfo_unsafe(cell) != 0) {
882                                 dlg_unlock( d_table, &entry);
883                                 goto error;
884                         }
885                 }
886                 dlg_unlock( d_table, &entry);
887
888         }
889
890         return;
891
892 error:
893         dlg_unlock( d_table, &entry);
894 }