topos_redis: a few improvements for debugging output
[sip-router] / src / modules / topos_redis / topos_redis_storage.c
1 /**
2  * Copyright (C) 2017 kamailio.org
3  * Copyright (C) 2017 flowroute.com
4  *
5  * This file is part of Kamailio, a free SIP server.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version
11  *
12  *
13  * This file 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  * \file
25  * \brief Kamailio topos ::
26  * \ingroup topos
27  * Module: \ref topos
28  */
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33
34 #include "../../core/dprint.h"
35 #include "../../core/ut.h"
36
37 #include "../ndb_redis/api.h"
38 #include "../topos/api.h"
39
40 #include "topos_redis_storage.h"
41
42
43 extern str _topos_redis_serverid;
44 extern ndb_redis_api_t _tps_redis_api;
45 extern topos_api_t _tps_api;
46
47 static str _tps_redis_bprefix = str_init("b:x:");
48 static str _tps_redis_dprefix = str_init("d:z:");
49
50 // void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
51
52 #define TPS_REDIS_NR_KEYS       48
53 #define TPS_REDIS_DATA_SIZE     8192
54
55 static char _tps_redis_cbuf[TPS_REDIS_DATA_SIZE];
56
57 /**
58  * storage keys
59  */
60 str td_key_rectime = str_init("rectime");
61 str td_key_a_callid = str_init("a_callid");
62 str td_key_a_uuid = str_init("a_uuid");
63 str td_key_b_uuid = str_init("b_uuid");
64 str td_key_a_contact = str_init("a_contact");
65 str td_key_b_contact = str_init("b_contact");
66 str td_key_as_contact = str_init("as_contact");
67 str td_key_bs_contact = str_init("bs_contact");
68 str td_key_a_tag = str_init("a_tag");
69 str td_key_b_tag = str_init("b_tag");
70 str td_key_a_rr = str_init("a_rr");
71 str td_key_b_rr = str_init("b_rr");
72 str td_key_s_rr = str_init("s_rr");
73 str td_key_iflags = str_init("iflags");
74 str td_key_a_uri = str_init("a_uri");
75 str td_key_b_uri = str_init("b_uri");
76 str td_key_r_uri = str_init("r_uri");
77 str td_key_a_srcaddr = str_init("a_srcaddr");
78 str td_key_b_srcaddr = str_init("b_srcaddr");
79 str td_key_s_method = str_init("s_method");
80 str td_key_s_cseq = str_init("s_cseq");
81
82 str tt_key_rectime = str_init("rectime");
83 str tt_key_a_callid = str_init("a_callid");
84 str tt_key_a_uuid = str_init("a_uuid");
85 str tt_key_b_uuid = str_init("b_uuid");
86 str tt_key_direction = str_init("direction");
87 str tt_key_x_via = str_init("x_via");
88 str tt_key_x_vbranch = str_init("x_vbranch");
89 str tt_key_x_rr = str_init("x_rr");
90 str tt_key_y_rr = str_init("y_rr");
91 str tt_key_s_rr = str_init("s_rr");
92 str tt_key_x_uri = str_init("x_uri");
93 str tt_key_a_contact = str_init("a_contact");
94 str tt_key_b_contact = str_init("b_contact");
95 str tt_key_as_contact = str_init("as_contact");
96 str tt_key_bs_contact = str_init("bs_contact");
97 str tt_key_x_tag = str_init("x_tag");
98 str tt_key_a_tag = str_init("a_tag");
99 str tt_key_b_tag = str_init("b_tag");
100 str tt_key_s_method = str_init("s_method");
101 str tt_key_s_cseq = str_init("s_cseq");
102
103 #define TPS_REDIS_SET_ARGSV(sval, argc, argv, argvlen) \
104         do { \
105                 if((sval)->s!=NULL && (sval)->len>0) { \
106                         argv[argc] = (sval)->s; \
107                         argvlen[argc] = (sval)->len; \
108                         argc++; \
109                 } \
110         } while(0)
111
112 #define TPS_REDIS_SET_ARGS(sval, argc, akey, argv, argvlen) \
113         do { \
114                 if((sval)->s!=NULL && (sval)->len>0) { \
115                         argv[argc] = (akey)->s; \
116                         argvlen[argc] = (akey)->len; \
117                         argc++; \
118                         argv[argc] = (sval)->s; \
119                         argvlen[argc] = (sval)->len; \
120                         argc++; \
121                 } \
122         } while(0)
123
124 #define TPS_REDIS_SET_ARGSX(sval, argc, akey, argv, argvlen) \
125         do { \
126                 if((sval)!=NULL) { \
127                         TPS_REDIS_SET_ARGS(sval, argc, akey, argv, argvlen); \
128                 } \
129         } while(0)
130
131 #define TPS_REDIS_SET_ARGN(nval, rp, sval, argc, akey, argv, argvlen) \
132         do { \
133                 (sval)->s = int2bstr((unsigned long)nval, rp, &(sval)->len); \
134                 rp = (sval)->s + (sval)->len + 1; \
135                 TPS_REDIS_SET_ARGS((sval), argc, akey, argv, argvlen); \
136         } while(0)
137
138 #define TPS_REDIS_SET_ARGNV(nval, rp, sval, argc, argv, argvlen) \
139         do { \
140                 (sval)->s = int2bstr((unsigned long)nval, rp, &(sval)->len); \
141                 rp = (sval)->s + (sval)->len + 1; \
142                 TPS_REDIS_SET_ARGSV((sval), argc, argv, argvlen); \
143         } while(0)
144
145
146 /**
147  *
148  */
149 int tps_redis_insert_dialog(tps_data_t *td)
150 {
151         char* argv[TPS_REDIS_NR_KEYS];
152         size_t argvlen[TPS_REDIS_NR_KEYS];
153         int argc = 0;
154         str rcmd = str_init("HMSET");
155         str rkey = STR_NULL;
156         char *rp;
157         str rval = STR_NULL;
158         redisc_server_t *rsrv = NULL;
159         redisReply *rrpl = NULL;
160         unsigned long lval = 0;
161
162         if(td->a_uuid.len<=0 && td->b_uuid.len<=0) {
163                 LM_INFO("no uuid for this message\n");
164                 return -1;
165         }
166
167         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
168         if(rsrv==NULL) {
169                 LM_ERR("cannot find redis server [%.*s]\n",
170                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
171                 return -1;
172         }
173
174         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
175         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
176         argc = 0;
177
178         rp = _tps_redis_cbuf;
179         memcpy(rp, _tps_redis_dprefix.s, _tps_redis_dprefix.len);
180
181         if(td->a_uuid.len>0) {
182                 memcpy(rp + _tps_redis_dprefix.len,
183                                 td->a_uuid.s, td->a_uuid.len);
184                 if(td->a_uuid.s[0]=='b') {
185                         rp[_tps_redis_dprefix.len] = 'a';
186                 }
187                 rp[_tps_redis_dprefix.len+td->a_uuid.len] = '\0';
188                 rkey.s = rp;
189                 rkey.len = _tps_redis_dprefix.len+td->a_uuid.len;
190                 rp += _tps_redis_dprefix.len+td->a_uuid.len+1;
191         } else {
192                 memcpy(rp + _tps_redis_dprefix.len,
193                                 td->b_uuid.s, td->b_uuid.len);
194                 if(td->b_uuid.s[0]=='b') {
195                         rp[_tps_redis_dprefix.len] = 'a';
196                 }
197                 rp[_tps_redis_dprefix.len+td->b_uuid.len] = '\0';
198                 rkey.s = rp;
199                 rkey.len = _tps_redis_dprefix.len+td->b_uuid.len;
200                 rp += _tps_redis_dprefix.len+td->b_uuid.len+1;
201         }
202
203         argv[argc]    = rcmd.s;
204         argvlen[argc] = rcmd.len;
205         argc++;
206
207         argv[argc]    = rkey.s;
208         argvlen[argc] = rkey.len;
209         argc++;
210
211         lval = (unsigned long)time(NULL);
212         TPS_REDIS_SET_ARGN(lval, rp, &rval, argc, &td_key_rectime,
213                         argv, argvlen);
214         TPS_REDIS_SET_ARGS(&td->a_callid, argc, &td_key_a_callid, argv, argvlen);
215
216         TPS_REDIS_SET_ARGS(&td->a_uuid, argc, &td_key_a_uuid, argv, argvlen);
217         TPS_REDIS_SET_ARGS(&td->b_uuid, argc, &td_key_b_uuid, argv, argvlen);
218
219         TPS_REDIS_SET_ARGS(&td->a_contact, argc, &td_key_a_contact, argv, argvlen);
220         TPS_REDIS_SET_ARGS(&td->b_contact, argc, &td_key_b_contact, argv, argvlen);
221
222         TPS_REDIS_SET_ARGS(&td->as_contact, argc, &td_key_as_contact, argv, argvlen);
223         TPS_REDIS_SET_ARGS(&td->bs_contact, argc, &td_key_bs_contact, argv, argvlen);
224
225         TPS_REDIS_SET_ARGS(&td->a_tag, argc, &td_key_a_tag, argv, argvlen);
226         TPS_REDIS_SET_ARGS(&td->b_tag, argc, &td_key_b_tag, argv, argvlen);
227
228         TPS_REDIS_SET_ARGS(&td->a_rr, argc, &td_key_a_rr, argv, argvlen);
229         TPS_REDIS_SET_ARGS(&td->b_rr, argc, &td_key_b_rr, argv, argvlen);
230         TPS_REDIS_SET_ARGS(&td->s_rr, argc, &td_key_s_rr, argv, argvlen);
231
232         TPS_REDIS_SET_ARGN(td->iflags, rp, &rval, argc, &td_key_iflags,
233                         argv, argvlen);
234
235         TPS_REDIS_SET_ARGS(&td->a_uri, argc, &td_key_a_uri, argv, argvlen);
236         TPS_REDIS_SET_ARGS(&td->b_uri, argc, &td_key_b_uri, argv, argvlen);
237         TPS_REDIS_SET_ARGS(&td->r_uri, argc, &td_key_r_uri, argv, argvlen);
238
239         TPS_REDIS_SET_ARGS(&td->a_srcaddr, argc, &td_key_a_srcaddr, argv, argvlen);
240         TPS_REDIS_SET_ARGS(&td->b_srcaddr, argc, &td_key_b_srcaddr, argv, argvlen);
241
242         TPS_REDIS_SET_ARGS(&td->s_method, argc, &td_key_s_method, argv, argvlen);
243         TPS_REDIS_SET_ARGS(&td->s_cseq, argc, &td_key_s_cseq, argv, argvlen);
244
245         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
246         if(rrpl==NULL) {
247                 LM_ERR("failed to execute redis command\n");
248                 if(rsrv->ctxRedis->err) {
249                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
250                 }
251                 return -1;
252         }
253         LM_DBG("inserted dialog record for [%.*s] with argc %d\n",
254                         rkey.len, rkey.s, argc);
255         freeReplyObject(rrpl);
256
257         /* set expire for the key */
258         argc = 0;
259
260         argv[argc]    = "EXPIRE";
261         argvlen[argc] = 6;
262         argc++;
263
264         argv[argc]    = rkey.s;
265         argvlen[argc] = rkey.len;
266         argc++;
267
268         lval = (unsigned long)_tps_api.get_dialog_expire();
269         if(lval==0) {
270                 return 0;
271         }
272         TPS_REDIS_SET_ARGNV(lval, rp, &rval, argc, argv, argvlen);
273
274         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
275         if(rrpl==NULL) {
276                 LM_ERR("failed to execute expire redis command\n");
277                 if(rsrv->ctxRedis->err) {
278                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
279                 }
280                 return -1;
281         }
282         LM_DBG("expire %lu set on dialog record for [%.*s] with argc %d\n", lval,
283                         rkey.len, rkey.s, argc);
284         freeReplyObject(rrpl);
285
286         return 0;
287 }
288
289 /**
290  *
291  */
292 int tps_redis_clean_dialogs(void)
293 {
294         return 0;
295 }
296
297 /**
298  *
299  */
300 int tps_redis_insert_invite_branch(tps_data_t *td)
301 {
302         char* argv[TPS_REDIS_NR_KEYS];
303         size_t argvlen[TPS_REDIS_NR_KEYS];
304         int argc = 0;
305         str rcmd = str_init("HMSET");
306         str rkey = STR_NULL;
307         char *rp;
308         str rval = STR_NULL;
309         redisc_server_t *rsrv = NULL;
310         redisReply *rrpl = NULL;
311         unsigned long lval = 0;
312
313         if(td->x_vbranch1.len<=0) {
314                 LM_INFO("no via branch for this message\n");
315                 return -1;
316         }
317
318         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
319         if(rsrv==NULL) {
320                 LM_ERR("cannot find redis server [%.*s]\n",
321                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
322                 return -1;
323         }
324
325         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
326         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
327         argc = 0;
328
329         rp = _tps_redis_cbuf;
330         rkey.len = snprintf(rp, TPS_REDIS_DATA_SIZE-128,
331                                         "%.*sINVITE:%.*s:%.*s",
332                                         _tps_redis_bprefix.len, _tps_redis_bprefix.s,
333                                         td->a_callid.len, td->a_callid.s,
334                                         td->b_tag.len, td->b_tag.s);
335         if(rkey.len<0 || rkey.len>=TPS_REDIS_DATA_SIZE-128) {
336                 LM_ERR("error or insufficient buffer size: %d\n", rkey.len);
337                 return -1;
338         }
339         rkey.s = rp;
340         rp += rkey.len+1;
341
342         argv[argc]    = rcmd.s;
343         argvlen[argc] = rcmd.len;
344         argc++;
345
346         argv[argc]    = rkey.s;
347         argvlen[argc] = rkey.len;
348         argc++;
349
350         lval = (unsigned long)time(NULL);
351         TPS_REDIS_SET_ARGN(lval, rp, &rval, argc, &tt_key_rectime,
352                         argv, argvlen);
353         TPS_REDIS_SET_ARGS(&td->x_vbranch1, argc, &tt_key_x_vbranch, argv, argvlen);
354
355         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
356         if(rrpl==NULL) {
357                 LM_ERR("failed to execute redis command\n");
358                 if(rsrv->ctxRedis->err) {
359                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
360                 }
361                 return -1;
362         }
363         LM_DBG("inserting invite branch record for [%.*s] with argc %d\n",
364                         rkey.len, rkey.s, argc);
365
366         freeReplyObject(rrpl);
367
368         /* set expire for the key */
369         argc = 0;
370
371         argv[argc]    = "EXPIRE";
372         argvlen[argc] = 6;
373         argc++;
374
375         argv[argc]    = rkey.s;
376         argvlen[argc] = rkey.len;
377         argc++;
378
379         lval = (unsigned long)_tps_api.get_branch_expire();
380         if(lval==0) {
381                 return 0;
382         }
383         TPS_REDIS_SET_ARGNV(lval, rp, &rval, argc, argv, argvlen);
384
385         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
386         if(rrpl==NULL) {
387                 LM_ERR("failed to execute expire redis command\n");
388                 if(rsrv->ctxRedis->err) {
389                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
390                 }
391                 return -1;
392         }
393         LM_DBG("expire %lu set on branch record for [%.*s] with argc %d\n", lval,
394                         rkey.len, rkey.s, argc);
395         freeReplyObject(rrpl);
396
397         return 0;
398 }
399
400
401 /**
402  *
403  */
404 int tps_redis_insert_branch(tps_data_t *td)
405 {
406         char* argv[TPS_REDIS_NR_KEYS];
407         size_t argvlen[TPS_REDIS_NR_KEYS];
408         int argc = 0;
409         str rcmd = str_init("HMSET");
410         str rkey = STR_NULL;
411         char *rp;
412         str rval = STR_NULL;
413         redisc_server_t *rsrv = NULL;
414         redisReply *rrpl = NULL;
415         unsigned long lval = 0;
416
417         if(td->x_vbranch1.len<=0) {
418                 LM_INFO("no via branch for this message\n");
419                 return -1;
420         }
421
422         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
423         if(rsrv==NULL) {
424                 LM_ERR("cannot find redis server [%.*s]\n",
425                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
426                 return -1;
427         }
428
429         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
430         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
431         argc = 0;
432
433         rp = _tps_redis_cbuf;
434         memcpy(rp, _tps_redis_bprefix.s, _tps_redis_bprefix.len);
435         memcpy(rp + _tps_redis_bprefix.len,
436                         td->x_vbranch1.s, td->x_vbranch1.len);
437         rp[_tps_redis_bprefix.len+td->x_vbranch1.len] = '\0';
438         rkey.s = rp;
439         rkey.len = _tps_redis_bprefix.len+td->x_vbranch1.len;
440         rp += _tps_redis_bprefix.len+td->x_vbranch1.len+1;
441
442         argv[argc]    = rcmd.s;
443         argvlen[argc] = rcmd.len;
444         argc++;
445
446         argv[argc]    = rkey.s;
447         argvlen[argc] = rkey.len;
448         argc++;
449
450         lval = (unsigned long)time(NULL);
451         TPS_REDIS_SET_ARGN(lval, rp, &rval, argc, &tt_key_rectime,
452                         argv, argvlen);
453         TPS_REDIS_SET_ARGS(&td->a_callid, argc, &tt_key_a_callid, argv, argvlen);
454
455         TPS_REDIS_SET_ARGS(&td->a_uuid, argc, &tt_key_a_uuid, argv, argvlen);
456         TPS_REDIS_SET_ARGS(&td->b_uuid, argc, &tt_key_b_uuid, argv, argvlen);
457
458         TPS_REDIS_SET_ARGN(td->direction, rp, &rval, argc, &tt_key_direction,
459                         argv, argvlen);
460
461         TPS_REDIS_SET_ARGS(&td->x_via, argc, &tt_key_x_via, argv, argvlen);
462         TPS_REDIS_SET_ARGS(&td->x_vbranch1, argc, &tt_key_x_vbranch, argv, argvlen);
463
464         TPS_REDIS_SET_ARGS(&td->x_rr, argc, &tt_key_x_rr, argv, argvlen);
465         TPS_REDIS_SET_ARGS(&td->y_rr, argc, &tt_key_y_rr, argv, argvlen);
466         TPS_REDIS_SET_ARGS(&td->s_rr, argc, &tt_key_s_rr, argv, argvlen);
467
468         TPS_REDIS_SET_ARGS(&td->x_uri, argc, &tt_key_x_uri, argv, argvlen);
469
470         TPS_REDIS_SET_ARGS(&td->x_tag, argc, &tt_key_x_tag, argv, argvlen);
471
472         TPS_REDIS_SET_ARGS(&td->s_method, argc, &tt_key_s_method, argv, argvlen);
473         TPS_REDIS_SET_ARGS(&td->s_cseq, argc, &tt_key_s_cseq, argv, argvlen);
474
475         TPS_REDIS_SET_ARGS(&td->a_contact, argc, &tt_key_a_contact, argv, argvlen);
476         TPS_REDIS_SET_ARGS(&td->b_contact, argc, &tt_key_b_contact, argv, argvlen);
477         TPS_REDIS_SET_ARGS(&td->as_contact, argc, &tt_key_as_contact, argv, argvlen);
478         TPS_REDIS_SET_ARGS(&td->bs_contact, argc, &tt_key_bs_contact, argv, argvlen);
479
480         TPS_REDIS_SET_ARGS(&td->a_tag, argc, &tt_key_a_tag, argv, argvlen);
481         TPS_REDIS_SET_ARGS(&td->b_tag, argc, &tt_key_b_tag, argv, argvlen);
482
483         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
484         if(rrpl==NULL) {
485                 LM_ERR("failed to execute redis command\n");
486                 if(rsrv->ctxRedis->err) {
487                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
488                 }
489                 return -1;
490         }
491         LM_DBG("inserting branch record for [%.*s] with argc %d\n",
492                         rkey.len, rkey.s, argc);
493
494         freeReplyObject(rrpl);
495
496         /* set expire for the key */
497         argc = 0;
498
499         argv[argc]    = "EXPIRE";
500         argvlen[argc] = 6;
501         argc++;
502
503         argv[argc]    = rkey.s;
504         argvlen[argc] = rkey.len;
505         argc++;
506
507         lval = (unsigned long)_tps_api.get_branch_expire();
508         if(lval==0) {
509                 return 0;
510         }
511         TPS_REDIS_SET_ARGNV(lval, rp, &rval, argc, argv, argvlen);
512
513         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
514         if(rrpl==NULL) {
515                 LM_ERR("failed to execute expire redis command\n");
516                 if(rsrv->ctxRedis->err) {
517                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
518                 }
519                 return -1;
520         }
521         LM_DBG("expire %lu set on branch record for [%.*s] with argc %d\n", lval,
522                         rkey.len, rkey.s, argc);
523         freeReplyObject(rrpl);
524
525         return 0;
526 }
527
528 /**
529  *
530  */
531 int tps_redis_clean_branches(void)
532 {
533         return 0;
534 }
535
536 #define TPS_REDIS_DATA_APPEND(_sd, _k, _v, _r) \
537         do { \
538                 if((_sd)->cp + (_v)->len >= (_sd)->cbuf + TPS_DATA_SIZE) { \
539                         LM_ERR("not enough space for %.*s\n", (_k)->len, (_k)->s); \
540                         goto error; \
541                 } \
542                 if((_v)->len>0) { \
543                         (_r)->s = (_sd)->cp; \
544                         (_r)->len = (_v)->len; \
545                         memcpy((_sd)->cp, (_v)->s, (_v)->len); \
546                         (_sd)->cp += (_v)->len; \
547                         (_sd)->cp[0] = '\0'; \
548                         (_sd)->cp++; \
549                 } \
550         } while(0)
551
552 /**
553  *
554  */
555 int tps_redis_load_invite_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
556 {
557         char* argv[TPS_REDIS_NR_KEYS];
558         size_t argvlen[TPS_REDIS_NR_KEYS];
559         int argc = 0;
560         str rcmd = str_init("HGETALL");
561         str rkey = STR_NULL;
562         char *rp;
563         int i;
564         redisc_server_t *rsrv = NULL;
565         redisReply *rrpl = NULL;
566         str skey = STR_NULL;
567         str sval = STR_NULL;
568
569         if(msg==NULL || md==NULL || sd==NULL)
570                 return -1;
571
572         if(md->a_callid.len<=0 || md->b_tag.len<=0) {
573                 LM_INFO("no call-id or to-tag for this message\n");
574                 return -1;
575         }
576
577         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
578         if(rsrv==NULL) {
579                 LM_ERR("cannot find redis server [%.*s]\n",
580                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
581                 return -1;
582         }
583
584         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
585         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
586         argc = 0;
587
588         rp = _tps_redis_cbuf;
589
590         rkey.len = snprintf(rp, TPS_REDIS_DATA_SIZE,
591                                         "%.*sINVITE:%.*s:%.*s",
592                                         _tps_redis_bprefix.len, _tps_redis_bprefix.s,
593                                         md->a_callid.len, md->a_callid.s,
594                                         md->b_tag.len, md->b_tag.s);
595         if(rkey.len<0 || rkey.len>=TPS_REDIS_DATA_SIZE) {
596                 LM_ERR("error or insufficient buffer size: %d\n", rkey.len);
597                 return -1;
598         }
599         rkey.s = rp;
600         rp += rkey.len+1;
601
602         argv[argc]    = rcmd.s;
603         argvlen[argc] = rcmd.len;
604         argc++;
605
606         argv[argc]    = rkey.s;
607         argvlen[argc] = rkey.len;
608         argc++;
609
610         LM_DBG("loading invite branch record for [%.*s]\n", rkey.len, rkey.s);
611
612         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
613         if(rrpl==NULL) {
614                 LM_ERR("failed to execute redis command\n");
615                 if(rsrv->ctxRedis->err) {
616                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
617                 }
618                 return -1;
619         }
620
621         if(rrpl->type != REDIS_REPLY_ARRAY) {
622                 LM_WARN("invalid redis result type: %d\n", rrpl->type);
623                 freeReplyObject(rrpl);
624                 return -1;
625         }
626
627         if(rrpl->elements<=0) {
628                 LM_DBG("hmap with key [%.*s] not found\n", rkey.len, rkey.s);
629                 freeReplyObject(rrpl);
630                 return 1;
631         }
632         if(rrpl->elements % 2) {
633                 LM_DBG("hmap with key [%.*s] has invalid result\n", rkey.len, rkey.s);
634                 freeReplyObject(rrpl);
635                 return -1;
636         }
637
638         memset(sd, 0, sizeof(tps_data_t));
639         sd->cp = sd->cbuf;
640
641         for(i=0; i<rrpl->elements; i++) {
642                 if(rrpl->element[i]->type != REDIS_REPLY_STRING) {
643                         LM_ERR("invalid type for hmap[%.*s] key pos[%d]\n",
644                                         rkey.len, rkey.s, i);
645                         freeReplyObject(rrpl);
646                         return -1;
647                 }
648                 skey.s = rrpl->element[i]->str;
649                 skey.len = rrpl->element[i]->len;
650                 i++;
651                 if(rrpl->element[i]==NULL) {
652                         continue;
653                 }
654                 sval.s = NULL;
655                 switch(rrpl->element[i]->type) {
656                         case REDIS_REPLY_STRING:
657                                 LM_DBG("r[%d]: s[%.*s]\n", i, (int)rrpl->element[i]->len,
658                                                 rrpl->element[i]->str);
659                                 sval.s = rrpl->element[i]->str;
660                                 sval.len = rrpl->element[i]->len;
661                                 break;
662                         case REDIS_REPLY_INTEGER:
663                                 LM_DBG("r[%d]: n[%lld]\n", i, rrpl->element[i]->integer);
664                                 break;
665                         default:
666                                 LM_WARN("unexpected type [%d] at pos [%d]\n",
667                                                 rrpl->element[i]->type, i);
668                 }
669                 if(sval.s==NULL) {
670                         continue;
671                 }
672
673                 if(skey.len==tt_key_rectime.len
674                                 && strncmp(skey.s, tt_key_rectime.s, skey.len)==0) {
675                         /* skip - not needed */
676                 } else if(skey.len==tt_key_x_vbranch.len
677                                 && strncmp(skey.s, tt_key_x_vbranch.s, skey.len)==0) {
678                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->x_vbranch1);
679                 } else {
680                         LM_INFO("useless key[%.*s]\n", skey.len, skey.s);
681                 }
682         }
683
684         freeReplyObject(rrpl);
685         return 0;
686
687 error:
688         if(rrpl) freeReplyObject(rrpl);
689         return -1;
690 }
691
692 /**
693  *
694  */
695 int tps_redis_load_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd,
696                 uint32_t mode)
697 {
698         char* argv[TPS_REDIS_NR_KEYS];
699         size_t argvlen[TPS_REDIS_NR_KEYS];
700         int argc = 0;
701         str rcmd = str_init("HGETALL");
702         str rkey = STR_NULL;
703         char *rp;
704         int i;
705         redisc_server_t *rsrv = NULL;
706         redisReply *rrpl = NULL;
707         str skey = STR_NULL;
708         str sval = STR_NULL;
709         str *xvbranch1 = NULL;
710         tps_data_t id;
711
712         if(msg==NULL || md==NULL || sd==NULL)
713                 return -1;
714
715         if(mode==0 && md->x_vbranch1.len<=0) {
716                 LM_INFO("no via branch for this message\n");
717                 return -1;
718         }
719
720         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
721         if(rsrv==NULL) {
722                 LM_ERR("cannot find redis server [%.*s]\n",
723                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
724                 return -1;
725         }
726
727         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
728         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
729         argc = 0;
730
731         if(mode==0) {
732                 /* load same transaction using Via branch */
733                 xvbranch1 = &md->x_vbranch1;
734         } else {
735                 /* load corresponding INVITE transaction using call-id + to-tag */
736                 if(tps_redis_load_invite_branch(msg, md, &id)<0) {
737                         LM_ERR("failed to load the INVITE branch value\n");
738                         return -1;
739                 }
740                 memset(&id, 0, sizeof(tps_data_t));
741                 xvbranch1 = &id.x_vbranch1;
742         }
743         if(xvbranch1->len<=0 || xvbranch1->s==NULL) {
744                 LM_DBG("branch value not found (mode: %u)\n", mode);
745                 return 1;
746         }
747         rp = _tps_redis_cbuf;
748         memcpy(rp, _tps_redis_bprefix.s, _tps_redis_bprefix.len);
749         memcpy(rp + _tps_redis_bprefix.len,
750                         xvbranch1->s, xvbranch1->len);
751         rp[_tps_redis_bprefix.len+xvbranch1->len] = '\0';
752         rkey.s = rp;
753         rkey.len = _tps_redis_bprefix.len+xvbranch1->len;
754         rp += _tps_redis_bprefix.len+xvbranch1->len+1;
755
756         argv[argc]    = rcmd.s;
757         argvlen[argc] = rcmd.len;
758         argc++;
759
760         argv[argc]    = rkey.s;
761         argvlen[argc] = rkey.len;
762         argc++;
763
764         LM_DBG("loading branch record for [%.*s]\n", rkey.len, rkey.s);
765
766         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
767         if(rrpl==NULL) {
768                 LM_ERR("failed to execute redis command\n");
769                 if(rsrv->ctxRedis->err) {
770                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
771                 }
772                 return -1;
773         }
774
775         if(rrpl->type != REDIS_REPLY_ARRAY) {
776                 LM_WARN("invalid redis result type: %d\n", rrpl->type);
777                 freeReplyObject(rrpl);
778                 return -1;
779         }
780
781         if(rrpl->elements<=0) {
782                 LM_DBG("hmap with key [%.*s] not found\n", rkey.len, rkey.s);
783                 freeReplyObject(rrpl);
784                 return 1;
785         }
786         if(rrpl->elements % 2) {
787                 LM_DBG("hmap with key [%.*s] has invalid result\n", rkey.len, rkey.s);
788                 freeReplyObject(rrpl);
789                 return -1;
790         }
791
792         sd->cp = sd->cbuf;
793
794         for(i=0; i<rrpl->elements; i++) {
795                 if(rrpl->element[i]->type != REDIS_REPLY_STRING) {
796                         LM_ERR("invalid type for hmap[%.*s] key pos[%d]\n",
797                                         rkey.len, rkey.s, i);
798                         freeReplyObject(rrpl);
799                         return -1;
800                 }
801                 skey.s = rrpl->element[i]->str;
802                 skey.len = rrpl->element[i]->len;
803                 i++;
804                 if(rrpl->element[i]==NULL) {
805                         continue;
806                 }
807                 sval.s = NULL;
808                 switch(rrpl->element[i]->type) {
809                         case REDIS_REPLY_STRING:
810                                 LM_DBG("r[%d]: s[%.*s]\n", i, (int)rrpl->element[i]->len,
811                                                 rrpl->element[i]->str);
812                                 sval.s = rrpl->element[i]->str;
813                                 sval.len = rrpl->element[i]->len;
814                                 break;
815                         case REDIS_REPLY_INTEGER:
816                                 LM_DBG("r[%d]: n[%lld]\n", i, rrpl->element[i]->integer);
817                                 break;
818                         default:
819                                 LM_WARN("unexpected type [%d] at pos [%d]\n",
820                                                 rrpl->element[i]->type, i);
821                 }
822                 if(sval.s==NULL) {
823                         continue;
824                 }
825
826                 if(skey.len==tt_key_rectime.len
827                                 && strncmp(skey.s, tt_key_rectime.s, skey.len)==0) {
828                         /* skip - not needed */
829                 } else if(skey.len==tt_key_a_callid.len
830                                 && strncmp(skey.s, tt_key_a_callid.s, skey.len)==0) {
831                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_callid);
832                 } else if(skey.len==tt_key_a_uuid.len
833                                 && strncmp(skey.s, tt_key_a_uuid.s, skey.len)==0) {
834                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_uuid);
835                 } else if(skey.len==tt_key_b_uuid.len
836                                 && strncmp(skey.s, tt_key_b_uuid.s, skey.len)==0) {
837                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_uuid);
838                 } else if(skey.len==tt_key_direction.len
839                                 && strncmp(skey.s, tt_key_direction.s, skey.len)==0) {
840                         /* skip - not needed */
841                 } else if(skey.len==tt_key_x_via.len
842                                 && strncmp(skey.s, tt_key_x_via.s, skey.len)==0) {
843                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->x_via);
844                 } else if(skey.len==tt_key_x_vbranch.len
845                                 && strncmp(skey.s, tt_key_x_vbranch.s, skey.len)==0) {
846                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->x_vbranch1);
847                 } else if(skey.len==tt_key_x_rr.len
848                                 && strncmp(skey.s, tt_key_x_rr.s, skey.len)==0) {
849                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->x_rr);
850                 } else if(skey.len==tt_key_y_rr.len
851                                 && strncmp(skey.s, tt_key_y_rr.s, skey.len)==0) {
852                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->y_rr);
853                 } else if(skey.len==tt_key_s_rr.len
854                                 && strncmp(skey.s, tt_key_s_rr.s, skey.len)==0) {
855                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->s_rr);
856                 } else if(skey.len==tt_key_x_uri.len
857                                 && strncmp(skey.s, tt_key_x_uri.s, skey.len)==0) {
858                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->x_uri);
859                 } else if(skey.len==tt_key_x_tag.len
860                                 && strncmp(skey.s, tt_key_x_tag.s, skey.len)==0) {
861                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->x_tag);
862                 } else if(skey.len==tt_key_s_method.len
863                                 && strncmp(skey.s, tt_key_s_method.s, skey.len)==0) {
864                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->s_method);
865                 } else if(skey.len==tt_key_s_cseq.len
866                                 && strncmp(skey.s, tt_key_s_cseq.s, skey.len)==0) {
867                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->s_cseq);
868                 } else if(skey.len==tt_key_a_contact.len
869                                 && strncmp(skey.s, tt_key_a_contact.s, skey.len)==0) {
870                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_contact);
871                 } else if(skey.len==tt_key_b_contact.len
872                                 && strncmp(skey.s, tt_key_b_contact.s, skey.len)==0) {
873                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_contact);
874                 } else if(skey.len==tt_key_as_contact.len
875                                 && strncmp(skey.s, tt_key_as_contact.s, skey.len)==0) {
876                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->as_contact);
877                 } else if(skey.len==tt_key_bs_contact.len
878                                 && strncmp(skey.s, tt_key_bs_contact.s, skey.len)==0) {
879                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->bs_contact);
880                 } else if(skey.len==tt_key_a_tag.len
881                                 && strncmp(skey.s, tt_key_a_tag.s, skey.len)==0) {
882                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_tag);
883                 } else if(skey.len==tt_key_b_tag.len
884                                 && strncmp(skey.s, tt_key_b_tag.s, skey.len)==0) {
885                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_tag);
886                 } else {
887                         LM_WARN("unknown key[%.*s]\n", skey.len, skey.s);
888                 }
889         }
890
891         freeReplyObject(rrpl);
892         return 0;
893
894 error:
895         if(rrpl) freeReplyObject(rrpl);
896         return -1;
897 }
898
899 /**
900  *
901  */
902 int tps_redis_load_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
903 {
904         char* argv[TPS_REDIS_NR_KEYS];
905         size_t argvlen[TPS_REDIS_NR_KEYS];
906         int argc = 0;
907         str rcmd = str_init("HGETALL");
908         str rkey = STR_NULL;
909         char *rp;
910         int i;
911         redisc_server_t *rsrv = NULL;
912         redisReply *rrpl = NULL;
913         str skey = STR_NULL;
914         str sval = STR_NULL;
915
916         if(msg==NULL || md==NULL || sd==NULL)
917                 return -1;
918
919         if(md->a_uuid.len<=0 && md->b_uuid.len<=0) {
920                 LM_DBG("no dlg uuid provided\n");
921                 return -1;
922         }
923         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
924         if(rsrv==NULL) {
925                 LM_ERR("cannot find redis server [%.*s]\n",
926                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
927                 return -1;
928         }
929
930         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
931         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
932         argc = 0;
933
934         rp = _tps_redis_cbuf;
935         memcpy(rp, _tps_redis_dprefix.s, _tps_redis_dprefix.len);
936
937         if(md->a_uuid.len>0) {
938                 memcpy(rp + _tps_redis_dprefix.len,
939                                 md->a_uuid.s, md->a_uuid.len);
940                 if(md->a_uuid.s[0]=='b') {
941                         rp[_tps_redis_dprefix.len] = 'a';
942                 }
943                 rp[_tps_redis_dprefix.len+md->a_uuid.len] = '\0';
944                 rkey.s = rp;
945                 rkey.len = _tps_redis_dprefix.len+md->a_uuid.len;
946                 rp += _tps_redis_dprefix.len+md->a_uuid.len+1;
947         } else {
948                 memcpy(rp + _tps_redis_dprefix.len,
949                                 md->b_uuid.s, md->b_uuid.len);
950                 if(md->b_uuid.s[0]=='b') {
951                         rp[_tps_redis_dprefix.len] = 'a';
952                 }
953                 rp[_tps_redis_dprefix.len+md->b_uuid.len] = '\0';
954                 rkey.s = rp;
955                 rkey.len = _tps_redis_dprefix.len+md->b_uuid.len;
956                 rp += _tps_redis_dprefix.len+md->b_uuid.len+1;
957         }
958
959         argv[argc]    = rcmd.s;
960         argvlen[argc] = rcmd.len;
961         argc++;
962
963         argv[argc]    = rkey.s;
964         argvlen[argc] = rkey.len;
965         argc++;
966
967         LM_DBG("loading dialog record for [%.*s]\n", rkey.len, rkey.s);
968
969         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
970         if(rrpl==NULL) {
971                 LM_ERR("failed to execute redis command\n");
972                 if(rsrv->ctxRedis->err) {
973                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
974                 }
975                 return -1;
976         }
977
978         if(rrpl->type != REDIS_REPLY_ARRAY) {
979                 LM_WARN("invalid redis result type: %d\n", rrpl->type);
980                 freeReplyObject(rrpl);
981                 return -1;
982         }
983
984         if(rrpl->elements<=0) {
985                 LM_DBG("hmap with key [%.*s] not found\n", rkey.len, rkey.s);
986                 freeReplyObject(rrpl);
987                 return 1;
988         }
989         if(rrpl->elements % 2) {
990                 LM_DBG("hmap with key [%.*s] has invalid result\n", rkey.len, rkey.s);
991                 freeReplyObject(rrpl);
992                 return -1;
993         }
994
995         sd->cp = sd->cbuf;
996
997         for(i=0; i<rrpl->elements; i++) {
998                 if(rrpl->element[i]->type != REDIS_REPLY_STRING) {
999                         LM_ERR("invalid type for hmap[%.*s] key pos[%d]\n",
1000                                         rkey.len, rkey.s, i);
1001                         freeReplyObject(rrpl);
1002                         return -1;
1003                 }
1004                 skey.s = rrpl->element[i]->str;
1005                 skey.len = rrpl->element[i]->len;
1006                 i++;
1007                 if(rrpl->element[i]==NULL) {
1008                         continue;
1009                 }
1010                 sval.s = NULL;
1011                 switch(rrpl->element[i]->type) {
1012                         case REDIS_REPLY_STRING:
1013                                 LM_DBG("r[%d]: s[%.*s]\n", i, (int)rrpl->element[i]->len,
1014                                                 rrpl->element[i]->str);
1015                                 sval.s = rrpl->element[i]->str;
1016                                 sval.len = rrpl->element[i]->len;
1017                                 break;
1018                         case REDIS_REPLY_INTEGER:
1019                                 LM_DBG("r[%d]: n[%lld]\n", i, rrpl->element[i]->integer);
1020                                 break;
1021                         default:
1022                                 LM_WARN("unexpected type [%d] at pos [%d]\n",
1023                                                 rrpl->element[i]->type, i);
1024                 }
1025                 if(sval.s==NULL) {
1026                         continue;
1027                 }
1028                 if(skey.len==td_key_rectime.len
1029                                 && strncmp(skey.s, td_key_rectime.s, skey.len)==0) {
1030                         /* skip - not needed */
1031                 } else if(skey.len==td_key_a_callid.len
1032                                 && strncmp(skey.s, td_key_a_callid.s, skey.len)==0) {
1033                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_callid);
1034                 } else if(skey.len==td_key_a_uuid.len
1035                                 && strncmp(skey.s, td_key_a_uuid.s, skey.len)==0) {
1036                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_uuid);
1037                 } else if(skey.len==td_key_b_uuid.len
1038                                 && strncmp(skey.s, td_key_b_uuid.s, skey.len)==0) {
1039                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_uuid);
1040                 } else if(skey.len==td_key_a_contact.len
1041                                 && strncmp(skey.s, td_key_a_contact.s, skey.len)==0) {
1042                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_contact);
1043                 } else if(skey.len==td_key_b_contact.len
1044                                 && strncmp(skey.s, td_key_b_contact.s, skey.len)==0) {
1045                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_contact);
1046                 } else if(skey.len==td_key_as_contact.len
1047                                 && strncmp(skey.s, td_key_as_contact.s, skey.len)==0) {
1048                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->as_contact);
1049                 } else if(skey.len==td_key_bs_contact.len
1050                                 && strncmp(skey.s, td_key_bs_contact.s, skey.len)==0) {
1051                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->bs_contact);
1052                 } else if(skey.len==td_key_a_tag.len
1053                                 && strncmp(skey.s, td_key_a_tag.s, skey.len)==0) {
1054                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_tag);
1055                 } else if(skey.len==td_key_b_tag.len
1056                                 && strncmp(skey.s, td_key_b_tag.s, skey.len)==0) {
1057                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_tag);
1058                 } else if(skey.len==td_key_a_rr.len
1059                                 && strncmp(skey.s, td_key_a_rr.s, skey.len)==0) {
1060                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_rr);
1061                 } else if(skey.len==td_key_b_rr.len
1062                                 && strncmp(skey.s, td_key_b_rr.s, skey.len)==0) {
1063                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_rr);
1064                 } else if(skey.len==td_key_s_rr.len
1065                                 && strncmp(skey.s, td_key_s_rr.s, skey.len)==0) {
1066                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->s_rr);
1067                 } else if(skey.len==td_key_iflags.len
1068                                 && strncmp(skey.s, td_key_iflags.s, skey.len)==0) {
1069                         /* skip - not needed */
1070                 } else if(skey.len==td_key_a_uri.len
1071                                 && strncmp(skey.s, td_key_a_uri.s, skey.len)==0) {
1072                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_uri);
1073                 } else if(skey.len==td_key_b_uri.len
1074                                 && strncmp(skey.s, td_key_b_uri.s, skey.len)==0) {
1075                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_uri);
1076                 } else if(skey.len==td_key_r_uri.len
1077                                 && strncmp(skey.s, td_key_r_uri.s, skey.len)==0) {
1078                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->r_uri);
1079                 } else if(skey.len==td_key_a_srcaddr.len
1080                                 && strncmp(skey.s, td_key_a_srcaddr.s, skey.len)==0) {
1081                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->a_srcaddr);
1082                 } else if(skey.len==td_key_b_srcaddr.len
1083                                 && strncmp(skey.s, td_key_b_srcaddr.s, skey.len)==0) {
1084                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->b_srcaddr);
1085                 } else if(skey.len==td_key_s_method.len
1086                                 && strncmp(skey.s, td_key_s_method.s, skey.len)==0) {
1087                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->s_method);
1088                 } else if(skey.len==td_key_s_cseq.len
1089                                 && strncmp(skey.s, td_key_s_cseq.s, skey.len)==0) {
1090                         TPS_REDIS_DATA_APPEND(sd, &skey, &sval, &sd->s_cseq);
1091                 } else {
1092                         LM_WARN("unknown key[%.*s]\n", skey.len, skey.s);
1093                 }
1094         }
1095
1096         freeReplyObject(rrpl);
1097         return 0;
1098
1099 error:
1100         if(rrpl) freeReplyObject(rrpl);
1101         return -1;
1102 }
1103
1104 /**
1105  *
1106  */
1107 int tps_redis_update_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd,
1108                 uint32_t mode)
1109 {
1110         char* argv[TPS_REDIS_NR_KEYS];
1111         size_t argvlen[TPS_REDIS_NR_KEYS];
1112         int argc = 0;
1113         str rcmd = str_init("HMSET");
1114         str rkey = STR_NULL;
1115         char *rp;
1116         redisc_server_t *rsrv = NULL;
1117         redisReply *rrpl = NULL;
1118
1119         if(sd->a_uuid.len<=0 && sd->b_uuid.len<=0) {
1120                 LM_INFO("no uuid for this message\n");
1121                 return -1;
1122         }
1123
1124         if(md->s_method.len==6 && strncmp(md->s_method.s, "INVITE", 6)==0) {
1125                 if(tps_redis_insert_invite_branch(md)<0) {
1126                         LM_ERR("failed to insert INVITE extra branch data\n");
1127                         return -1;
1128                 }
1129         }
1130         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
1131         if(rsrv==NULL) {
1132                 LM_ERR("cannot find redis server [%.*s]\n",
1133                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
1134                 return -1;
1135         }
1136
1137         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
1138         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
1139         argc = 0;
1140
1141         rp = _tps_redis_cbuf;
1142         memcpy(rp, _tps_redis_bprefix.s, _tps_redis_bprefix.len);
1143
1144         memcpy(rp + _tps_redis_bprefix.len,
1145                         sd->x_vbranch1.s, sd->x_vbranch1.len);
1146         rp[_tps_redis_bprefix.len+sd->x_vbranch1.len] = '\0';
1147         rkey.s = rp;
1148         rkey.len = _tps_redis_bprefix.len+sd->x_vbranch1.len;
1149         rp += _tps_redis_bprefix.len+sd->x_vbranch1.len+1;
1150
1151         argv[argc]    = rcmd.s;
1152         argvlen[argc] = rcmd.len;
1153         argc++;
1154
1155         argv[argc]    = rkey.s;
1156         argvlen[argc] = rkey.len;
1157         argc++;
1158
1159         if(mode & TPS_DBU_CONTACT) {
1160                 TPS_REDIS_SET_ARGS(&md->b_contact, argc, &tt_key_b_contact,
1161                                 argv, argvlen);
1162                 TPS_REDIS_SET_ARGS(&md->b_contact, argc, &tt_key_b_contact,
1163                                 argv, argvlen);
1164         }
1165
1166         if((mode & TPS_DBU_RPLATTRS) && msg->first_line.type==SIP_REPLY) {
1167                 if(sd->b_tag.len<=0
1168                                 && msg->first_line.u.reply.statuscode>=180
1169                                 && msg->first_line.u.reply.statuscode<200) {
1170
1171                         TPS_REDIS_SET_ARGS(&md->b_rr, argc, &tt_key_y_rr, argv, argvlen);
1172
1173                         TPS_REDIS_SET_ARGS(&md->b_tag, argc, &tt_key_b_tag, argv, argvlen);
1174                 }
1175         }
1176
1177         if(argc<=2) {
1178                 return 0;
1179         }
1180
1181         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
1182         if(rrpl==NULL) {
1183                 LM_ERR("failed to execute redis command for branch update\n");
1184                 if(rsrv->ctxRedis->err) {
1185                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
1186                 }
1187                 return -1;
1188         }
1189         LM_DBG("updated branch record for [%.*s] with argc %d\n",
1190                         rkey.len, rkey.s, argc);
1191         freeReplyObject(rrpl);
1192
1193         return 0;
1194 }
1195
1196 /**
1197  *
1198  */
1199 int tps_redis_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd,
1200                 uint32_t mode)
1201 {
1202         char* argv[TPS_REDIS_NR_KEYS];
1203         size_t argvlen[TPS_REDIS_NR_KEYS];
1204         int argc = 0;
1205         str rcmd = str_init("HMSET");
1206         str rkey = STR_NULL;
1207         char *rp;
1208         str rval = STR_NULL;
1209         redisc_server_t *rsrv = NULL;
1210         redisReply *rrpl = NULL;
1211         int32_t liflags;
1212
1213         if(sd->a_uuid.len<=0 && sd->b_uuid.len<=0) {
1214                 LM_INFO("no uuid for this message\n");
1215                 return -1;
1216         }
1217
1218         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
1219         if(rsrv==NULL) {
1220                 LM_ERR("cannot find redis server [%.*s]\n",
1221                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
1222                 return -1;
1223         }
1224
1225         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
1226         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
1227         argc = 0;
1228
1229         rp = _tps_redis_cbuf;
1230         memcpy(rp, _tps_redis_dprefix.s, _tps_redis_dprefix.len);
1231
1232         if(sd->a_uuid.len>0) {
1233                 memcpy(rp + _tps_redis_dprefix.len,
1234                                 sd->a_uuid.s, sd->a_uuid.len);
1235                 if(sd->a_uuid.s[0]=='b') {
1236                         rp[_tps_redis_dprefix.len] = 'a';
1237                 }
1238                 rp[_tps_redis_dprefix.len+sd->a_uuid.len] = '\0';
1239                 rkey.s = rp;
1240                 rkey.len = _tps_redis_dprefix.len+sd->a_uuid.len;
1241                 rp += _tps_redis_dprefix.len+sd->a_uuid.len+1;
1242         } else {
1243                 memcpy(rp + _tps_redis_dprefix.len,
1244                                 sd->b_uuid.s, sd->b_uuid.len);
1245                 if(sd->b_uuid.s[0]=='b') {
1246                         rp[_tps_redis_dprefix.len] = 'a';
1247                 }
1248                 rp[_tps_redis_dprefix.len+sd->b_uuid.len] = '\0';
1249                 rkey.s = rp;
1250                 rkey.len = _tps_redis_dprefix.len+sd->b_uuid.len;
1251                 rp += _tps_redis_dprefix.len+sd->b_uuid.len+1;
1252         }
1253
1254         argv[argc]    = rcmd.s;
1255         argvlen[argc] = rcmd.len;
1256         argc++;
1257
1258         argv[argc]    = rkey.s;
1259         argvlen[argc] = rkey.len;
1260         argc++;
1261
1262         if(mode & TPS_DBU_CONTACT) {
1263                 TPS_REDIS_SET_ARGS(&md->b_contact, argc, &td_key_b_contact,
1264                                 argv, argvlen);
1265                 TPS_REDIS_SET_ARGS(&md->b_contact, argc, &td_key_b_contact,
1266                                 argv, argvlen);
1267         }
1268
1269         if((mode & TPS_DBU_RPLATTRS) && msg->first_line.type==SIP_REPLY) {
1270                 if(sd->b_tag.len<=0
1271                                 && msg->first_line.u.reply.statuscode>=200
1272                                 && msg->first_line.u.reply.statuscode<300) {
1273
1274                         if((sd->iflags&TPS_IFLAG_DLGON) == 0) {
1275                                 TPS_REDIS_SET_ARGS(&md->b_rr, argc, &td_key_b_rr, argv, argvlen);
1276                         }
1277
1278                         TPS_REDIS_SET_ARGS(&md->b_tag, argc, &td_key_b_tag, argv, argvlen);
1279
1280                         liflags = sd->iflags|TPS_IFLAG_DLGON;
1281                         TPS_REDIS_SET_ARGN(liflags, rp, &rval, argc, &td_key_iflags,
1282                                         argv, argvlen);
1283                 }
1284         }
1285
1286         if(argc<=2) {
1287                 return 0;
1288         }
1289
1290         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
1291         if(rrpl==NULL) {
1292                 LM_ERR("failed to execute redis command for dialog update\n");
1293                 if(rsrv->ctxRedis->err) {
1294                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
1295                 }
1296                 return -1;
1297         }
1298         LM_DBG("updated dialog record for [%.*s] with argc %d\n",
1299                         rkey.len, rkey.s, argc);
1300         freeReplyObject(rrpl);
1301
1302         return 0;
1303 }
1304
1305 /**
1306  *
1307  */
1308 int tps_redis_end_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
1309 {
1310         char* argv[TPS_REDIS_NR_KEYS];
1311         size_t argvlen[TPS_REDIS_NR_KEYS];
1312         int argc = 0;
1313         str rcmd = str_init("HMSET");
1314         str rkey = STR_NULL;
1315         char *rp;
1316         str rval = STR_NULL;
1317         redisc_server_t *rsrv = NULL;
1318         redisReply *rrpl = NULL;
1319         int32_t liflags;
1320         unsigned long lval = 0;
1321
1322         if(md->s_method_id != METHOD_BYE) {
1323                 return 0;
1324         }
1325
1326         if(sd->a_uuid.len<=0 && sd->b_uuid.len<=0) {
1327                 LM_INFO("no uuid for this message\n");
1328                 return -1;
1329         }
1330
1331         rsrv = _tps_redis_api.get_server(&_topos_redis_serverid);
1332         if(rsrv==NULL) {
1333                 LM_ERR("cannot find redis server [%.*s]\n",
1334                                 _topos_redis_serverid.len, _topos_redis_serverid.s);
1335                 return -1;
1336         }
1337
1338         memset(argv, 0, TPS_REDIS_NR_KEYS * sizeof(char*));
1339         memset(argvlen, 0, TPS_REDIS_NR_KEYS * sizeof(size_t));
1340         argc = 0;
1341
1342         rp = _tps_redis_cbuf;
1343         memcpy(rp, _tps_redis_dprefix.s, _tps_redis_dprefix.len);
1344
1345         if(sd->a_uuid.len>0) {
1346                 memcpy(rp + _tps_redis_dprefix.len,
1347                                 sd->a_uuid.s, sd->a_uuid.len);
1348                 if(sd->a_uuid.s[0]=='b') {
1349                         rp[_tps_redis_dprefix.len] = 'a';
1350                 }
1351                 rp[_tps_redis_dprefix.len+sd->a_uuid.len] = '\0';
1352                 rkey.s = rp;
1353                 rkey.len = _tps_redis_dprefix.len+sd->a_uuid.len;
1354                 rp += _tps_redis_dprefix.len+sd->a_uuid.len+1;
1355         } else {
1356                 memcpy(rp + _tps_redis_dprefix.len,
1357                                 sd->b_uuid.s, sd->b_uuid.len);
1358                 if(sd->b_uuid.s[0]=='b') {
1359                         rp[_tps_redis_dprefix.len] = 'a';
1360                 }
1361                 rp[_tps_redis_dprefix.len+sd->b_uuid.len] = '\0';
1362                 rkey.s = rp;
1363                 rkey.len = _tps_redis_dprefix.len+sd->b_uuid.len;
1364                 rp += _tps_redis_dprefix.len+sd->b_uuid.len+1;
1365         }
1366
1367         argv[argc]    = rcmd.s;
1368         argvlen[argc] = rcmd.len;
1369         argc++;
1370
1371         argv[argc]    = rkey.s;
1372         argvlen[argc] = rkey.len;
1373         argc++;
1374
1375         lval = (unsigned long)time(NULL);
1376         TPS_REDIS_SET_ARGN(lval, rp, &rval, argc, &td_key_rectime,
1377                         argv, argvlen);
1378         liflags = 0;
1379         TPS_REDIS_SET_ARGN(liflags, rp, &rval, argc, &td_key_iflags,
1380                                         argv, argvlen);
1381
1382         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
1383         if(rrpl==NULL) {
1384                 LM_ERR("failed to execute redis command\n");
1385                 if(rsrv->ctxRedis->err) {
1386                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
1387                 }
1388                 return -1;
1389         }
1390         LM_DBG("updated on end the dialog record for [%.*s] with argc %d\n",
1391                         rkey.len, rkey.s, argc);
1392
1393         freeReplyObject(rrpl);
1394
1395         /* set expire for the key */
1396         argc = 0;
1397
1398         argv[argc]    = "EXPIRE";
1399         argvlen[argc] = 6;
1400         argc++;
1401
1402         argv[argc]    = rkey.s;
1403         argvlen[argc] = rkey.len;
1404         argc++;
1405
1406         /* dialog ended -- keep it for branch lifetime only */
1407         lval = (unsigned long)_tps_api.get_branch_expire();
1408         if(lval==0) {
1409                 return 0;
1410         }
1411         TPS_REDIS_SET_ARGNV(lval, rp, &rval, argc, argv, argvlen);
1412
1413         rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen);
1414         if(rrpl==NULL) {
1415                 LM_ERR("failed to execute expire redis command\n");
1416                 if(rsrv->ctxRedis->err) {
1417                         LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr);
1418                 }
1419                 return -1;
1420         }
1421         LM_DBG("expire %lu set on dialog record for [%.*s] with argc %d\n", lval,
1422                         rkey.len, rkey.s, argc);
1423         freeReplyObject(rrpl);
1424
1425         return 0;
1426 }