a4972662e02a548ead4d6f886184c0abce7b4745
[sip-router] / src / modules / uac / uac_reg.c
1 /**
2  * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 /*!
22  * \file
23  * \brief Kamailio uac :: The SIP UA registration client module
24  * \ingroup uac
25  * Module: \ref uac
26  */
27
28 #include <time.h>
29
30 #include "../../core/dprint.h"
31 #include "../../core/timer.h"
32
33 #include "../../core/mem/shm_mem.h"
34 #include "../../lib/srdb1/db.h"
35 #include "../../core/ut.h"
36 #include "../../core/trim.h"
37 #include "../../core/hashes.h"
38 #include "../../core/locking.h"
39 #include "../../core/parser/parse_uri.h"
40 #include "../../core/parser/parse_from.h"
41 #include "../../core/parser/parse_to.h"
42 #include "../../core/parser/parse_expires.h"
43 #include "../../core/parser/contact/parse_contact.h"
44 #include "../../core/rpc.h"
45 #include "../../core/rpc_lookup.h"
46 #include "../../core/rand/kam_rand.h"
47
48 #include "../../modules/tm/tm_load.h"
49
50 #include "auth.h"
51 #include "auth_hdr.h"
52 #include "uac_reg.h"
53
54 #define UAC_REG_DISABLED        (1<<0) /* registration disabled */
55 #define UAC_REG_ONGOING         (1<<1) /* registration on progress */
56 #define UAC_REG_ONLINE          (1<<2) /* registered */
57 #define UAC_REG_AUTHSENT        (1<<3) /* registration with auth in progress */
58 #define UAC_REG_INIT            (1<<4) /* registration initialized */
59
60 #define MAX_UACH_SIZE 2048
61 #define UAC_REG_TM_CALLID_SIZE 90
62
63 int _uac_reg_gc_interval = 150;
64
65 typedef struct _reg_uac
66 {
67         unsigned int h_uuid;
68         unsigned int h_user;
69         str   l_uuid;
70         str   l_username;
71         str   l_domain;
72         str   r_username;
73         str   r_domain;
74         str   realm;
75         str   auth_proxy;
76         str   auth_username;
77         str   auth_password;
78         str   callid;
79         str   socket;
80         unsigned int cseq;
81         unsigned int flags;
82         unsigned int expires;
83         time_t timer_expires;
84         unsigned int reg_delay;
85         time_t reg_init;
86         gen_lock_t *lock;
87 } reg_uac_t;
88
89 typedef struct _reg_item
90 {
91         reg_uac_t *r;
92         struct _reg_item *next;
93 } reg_item_t;
94
95
96 typedef struct _reg_entry
97 {
98         unsigned int isize;
99         unsigned int usize;
100         reg_item_t *byuser;
101         reg_item_t *byuuid;
102         gen_lock_t lock;
103 } reg_entry_t;
104
105 typedef struct _reg_ht
106 {
107         unsigned int htsize;
108         time_t stime;
109         reg_entry_t *entries;
110 } reg_ht_t;
111
112 static reg_ht_t *_reg_htable = NULL;
113 static reg_ht_t *_reg_htable_gc = NULL;
114 static gen_lock_t *_reg_htable_gc_lock = NULL;
115
116 int reg_use_domain = 0;
117 int reg_timer_interval = 90;
118 int reg_retry_interval = 0;
119 int reg_htable_size = 4;
120 int reg_fetch_rows = 1000;
121 int reg_keep_callid = 0;
122 int reg_random_delay = 0;
123 int *reg_active = NULL;
124 str reg_contact_addr = STR_NULL;
125 str reg_db_url = STR_NULL;
126 str reg_db_table = str_init("uacreg");
127
128 str l_uuid_column = str_init("l_uuid");
129 str l_username_column = str_init("l_username");
130 str l_domain_column = str_init("l_domain");
131 str r_username_column = str_init("r_username");
132 str r_domain_column = str_init("r_domain");
133 str realm_column = str_init("realm");
134 str auth_username_column = str_init("auth_username");
135 str auth_password_column = str_init("auth_password");
136 str auth_proxy_column = str_init("auth_proxy");
137 str expires_column = str_init("expires");
138 str flags_column = str_init("flags");
139 str reg_delay_column = str_init("reg_delay");
140 str socket_column = str_init("socket");
141
142 str str_empty = str_init("");
143
144
145 extern struct tm_binds uac_tmb;
146 extern pv_spec_t auth_username_spec;
147 extern pv_spec_t auth_realm_spec;
148 extern pv_spec_t auth_password_spec;
149
150 counter_handle_t regtotal;         /* Total number of registrations in memory */
151 counter_handle_t regactive;        /* Active registrations - 200 OK */
152 counter_handle_t regdisabled;      /* Disabled registrations */
153
154 /* Init reg active mode */
155 int reg_active_init(int mode)
156 {
157         if(reg_active!=NULL) {
158                 /* already allocated */
159                 *reg_active = mode;
160                 return 0;
161         }
162         reg_active = (int*)shm_malloc(sizeof(int));
163         if(reg_active==NULL) {
164                 LM_ERR("not enough shared memory\n");
165                 return -1;
166         }
167         *reg_active = mode;
168         return 0;
169 }
170
171 /* Init counters */
172 static void uac_reg_counter_init()
173 {
174         LM_DBG("*** Initializing UAC reg counters\n");
175         counter_register(&regtotal, "uac", "regtotal", 0, 0, 0, "Total number of registration accounts in memory", 0);
176         counter_register(&regactive, "uac", "regactive", 0, 0, 0, "Number of successfully registered accounts (200 OK)", 0);
177         counter_register(&regdisabled, "uac", "regdisabled", 0, 0, 0, "Counter of failed registrations (not 200 OK)", 0);
178 }
179
180
181 /**
182  * Init the in-memory registration database in hash table
183  */
184 int uac_reg_init_ht(unsigned int sz)
185 {
186         int i;
187
188         _reg_htable_gc_lock = (gen_lock_t*)shm_malloc(sizeof(gen_lock_t));
189         if(_reg_htable_gc_lock == NULL)
190         {
191                 LM_ERR("no more shm for lock\n");
192                 return -1;
193         }
194         if(lock_init(_reg_htable_gc_lock)==0)
195         {
196                 LM_ERR("cannot init global lock\n");
197                 shm_free((void*)_reg_htable_gc_lock);
198                 return -1;
199         }
200         _reg_htable_gc = (reg_ht_t*)shm_malloc(sizeof(reg_ht_t));
201         if(_reg_htable_gc==NULL)
202         {
203                 LM_ERR("no more shm\n");
204                 lock_destroy(_reg_htable_gc_lock);
205                 shm_free((void*)_reg_htable_gc_lock);
206                 return -1;
207         }
208         memset(_reg_htable_gc, 0, sizeof(reg_ht_t));
209         _reg_htable_gc->htsize = sz;
210
211         _reg_htable_gc->entries =
212                 (reg_entry_t*)shm_malloc(_reg_htable_gc->htsize*sizeof(reg_entry_t));
213         if(_reg_htable_gc->entries==NULL)
214         {
215                 LM_ERR("no more shm.\n");
216                 shm_free(_reg_htable_gc);
217                 lock_destroy(_reg_htable_gc_lock);
218                 shm_free((void*)_reg_htable_gc_lock);
219                 return -1;
220         }
221         memset(_reg_htable_gc->entries, 0, _reg_htable_gc->htsize*sizeof(reg_entry_t));
222
223
224         _reg_htable = (reg_ht_t*)shm_malloc(sizeof(reg_ht_t));
225         if(_reg_htable==NULL)
226         {
227                 LM_ERR("no more shm\n");
228                 shm_free(_reg_htable_gc->entries);
229                 shm_free(_reg_htable_gc);
230                 lock_destroy(_reg_htable_gc_lock);
231                 shm_free((void*)_reg_htable_gc_lock);
232                 return -1;
233         }
234         memset(_reg_htable, 0, sizeof(reg_ht_t));
235         _reg_htable->htsize = sz;
236
237         _reg_htable->entries =
238                 (reg_entry_t*)shm_malloc(_reg_htable->htsize*sizeof(reg_entry_t));
239         if(_reg_htable->entries==NULL)
240         {
241                 LM_ERR("no more shm.\n");
242                 shm_free(_reg_htable_gc->entries);
243                 shm_free(_reg_htable_gc);
244                 shm_free(_reg_htable);
245                 lock_destroy(_reg_htable_gc_lock);
246                 shm_free((void*)_reg_htable_gc_lock);
247                 return -1;
248         }
249         memset(_reg_htable->entries, 0, _reg_htable->htsize*sizeof(reg_entry_t));
250         for(i=0; i<_reg_htable->htsize; i++)
251         {
252                 if(lock_init(&_reg_htable->entries[i].lock)==0)
253                 {
254                         LM_ERR("cannot initialize lock[%d] n", i);
255                         i--;
256                         while(i>=0)
257                         {
258                                 lock_destroy(&_reg_htable->entries[i].lock);
259                                 i--;
260                         }
261                         shm_free(_reg_htable->entries);
262                         shm_free(_reg_htable);
263                         shm_free(_reg_htable_gc->entries);
264                         shm_free(_reg_htable_gc);
265                         lock_destroy(_reg_htable_gc_lock);
266                         shm_free((void*)_reg_htable_gc_lock);
267                         return -1;
268                 }
269         }
270
271         /* Initialize uac reg counters */
272         uac_reg_counter_init();
273
274         return 0;
275 }
276
277 /**
278  *
279  */
280 int uac_reg_free_ht(void)
281 {
282         int i;
283         reg_item_t *it = NULL;
284         reg_item_t *it0 = NULL;
285
286         if(_reg_htable_gc_lock != NULL)
287         {
288                 lock_destroy(_reg_htable_gc_lock);
289                 shm_free((void*)_reg_htable_gc_lock);
290                 _reg_htable_gc_lock = NULL;
291         }
292         if(_reg_htable_gc!=NULL)
293         {
294                 for(i=0; i<_reg_htable_gc->htsize; i++)
295                 {
296                         it = _reg_htable_gc->entries[i].byuuid;
297                         while(it)
298                         {
299                                 it0 = it;
300                                 it = it->next;
301                                 shm_free(it0);
302                         }
303                         it = _reg_htable_gc->entries[i].byuser;
304                         while(it)
305                         {
306                                 it0 = it;
307                                 it = it->next;
308                                 shm_free(it0->r);
309                                 shm_free(it0);
310                         }
311                 }
312                 shm_free(_reg_htable_gc->entries);
313                 shm_free(_reg_htable_gc);
314                 _reg_htable_gc = NULL;
315         }
316
317         if(_reg_htable==NULL)
318         {
319                 LM_DBG("no hash table\n");
320                 return -1;
321         }
322         for(i=0; i<_reg_htable->htsize; i++)
323         {
324                 lock_get(&_reg_htable->entries[i].lock);
325                 /* free entries */
326                 it = _reg_htable->entries[i].byuuid;
327                 while(it)
328                 {
329                         it0 = it;
330                         it = it->next;
331                         shm_free(it0);
332                 }
333                 it = _reg_htable->entries[i].byuser;
334                 while(it)
335                 {
336                         it0 = it;
337                         it = it->next;
338                         shm_free(it0->r);
339                         shm_free(it0);
340                 }
341                 lock_destroy(&_reg_htable->entries[i].lock);
342         }
343         shm_free(_reg_htable->entries);
344         shm_free(_reg_htable);
345         _reg_htable = NULL;
346         return 0;
347 }
348
349 /**
350  *
351  */
352 int uac_reg_reset_ht_gc(void)
353 {
354         int i;
355         reg_item_t *it = NULL;
356         reg_item_t *it0 = NULL;
357
358         if(_reg_htable_gc==NULL)
359         {
360                 LM_DBG("no hash table\n");
361                 return -1;
362         }
363         for(i=0; i<_reg_htable_gc->htsize; i++)
364         {
365                 /* free entries */
366                 it = _reg_htable_gc->entries[i].byuuid;
367                 while(it)
368                 {
369                         it0 = it;
370                         it = it->next;
371                         shm_free(it0);
372                 }
373                 _reg_htable_gc->entries[i].byuuid = NULL;
374                 _reg_htable_gc->entries[i].isize=0;
375                 it = _reg_htable_gc->entries[i].byuser;
376                 while(it)
377                 {
378                         it0 = it;
379                         it = it->next;
380                         shm_free(it0->r);
381                         shm_free(it0);
382                 }
383                 _reg_htable_gc->entries[i].byuser = NULL;
384                 _reg_htable_gc->entries[i].usize = 0;
385         }
386         /* Reset all counters */
387         counter_reset(regtotal);
388         counter_reset(regactive);
389         counter_reset(regdisabled);
390         return 0;
391 }
392
393 /**
394  *
395  */
396 int uac_reg_ht_shift(void)
397 {
398         time_t tn;
399         int i;
400
401         if(_reg_htable==NULL || _reg_htable_gc==NULL)
402         {
403                 LM_ERR("data struct invalid\n");
404                 return -1;
405         }
406         tn = time(NULL);
407
408         lock_get(_reg_htable_gc_lock);
409         if(_reg_htable_gc->stime > tn - _uac_reg_gc_interval) {
410                 lock_release(_reg_htable_gc_lock);
411                 LM_ERR("shifting in-memory table is not possible in less than %d secs\n",
412                                 _uac_reg_gc_interval);
413                 return -1;
414         }
415         uac_reg_reset_ht_gc();
416         for(i=0; i<_reg_htable->htsize; i++)
417         {
418                 /* shift entries */
419                 _reg_htable_gc->entries[i].byuuid = _reg_htable->entries[i].byuuid;
420                 _reg_htable_gc->entries[i].byuser = _reg_htable->entries[i].byuser;
421                 _reg_htable_gc->stime = time(NULL);
422
423                 /* reset active table entries */
424                 _reg_htable->entries[i].byuuid = NULL;
425                 _reg_htable->entries[i].isize=0;
426                 _reg_htable->entries[i].byuser = NULL;
427                 _reg_htable->entries[i].usize = 0;
428         }
429         lock_release(_reg_htable_gc_lock);
430         return 0;
431 }
432
433 #define reg_compute_hash(_s)            get_hash1_raw((_s)->s,(_s)->len)
434 #define reg_get_entry(_h,_size)         ((_h)&((_size)-1))
435
436 /**
437  *
438  */
439 int reg_ht_add_byuuid(reg_uac_t *reg)
440 {
441         unsigned int slot;
442         reg_item_t *ri = NULL;
443
444         if(_reg_htable==NULL)
445         {
446                 LM_ERR("reg hash table not initialized\n");
447                 return -1;
448         }
449
450         ri = (reg_item_t*)shm_malloc(sizeof(reg_item_t));
451         if(ri==NULL)
452         {
453                 LM_ERR("no more shm\n");
454                 return -1;
455         }
456         memset(ri, 0, sizeof(reg_item_t));
457         slot = reg_get_entry(reg->h_uuid, _reg_htable->htsize);
458         ri->r = reg;
459         lock_get(&_reg_htable->entries[slot].lock);
460         ri->next = _reg_htable->entries[slot].byuuid;
461         _reg_htable->entries[slot].byuuid = ri;
462         _reg_htable->entries[slot].isize++;
463         lock_release(&_reg_htable->entries[slot].lock);
464         return 0;
465 }
466
467 /**
468  *
469  */
470 int reg_ht_add_byuser(reg_uac_t *reg)
471 {
472         unsigned int slot;
473         reg_item_t *ri = NULL;
474
475         if(_reg_htable==NULL)
476         {
477                 LM_ERR("reg hash table not initialized\n");
478                 return -1;
479         }
480
481         ri = (reg_item_t*)shm_malloc(sizeof(reg_item_t));
482         if(ri==NULL)
483         {
484                 LM_ERR("no more shm\n");
485                 return -1;
486         }
487         memset(ri, 0, sizeof(reg_item_t));
488         slot = reg_get_entry(reg->h_user, _reg_htable->htsize);
489         ri->r = reg;
490         lock_get(&_reg_htable->entries[slot].lock);
491         ri->next = _reg_htable->entries[slot].byuser;
492         _reg_htable->entries[slot].byuser = ri;
493         _reg_htable->entries[slot].usize++;
494         lock_release(&_reg_htable->entries[slot].lock);
495         return 0;
496 }
497
498 #define reg_copy_shm(dst, src, bsize) do { \
499                 if((src)->s!=NULL) { \
500                         (dst)->s = p; \
501                         strncpy((dst)->s, (src)->s, (src)->len); \
502                         (dst)->len = (src)->len; \
503                         (dst)->s[(dst)->len] = '\0'; \
504                         p = p + ((bsize)!=0?(bsize):(dst)->len) + 1; \
505                 } \
506         } while(0);
507
508 /**
509  *
510  */
511 int reg_ht_add(reg_uac_t *reg)
512 {
513         int len;
514         reg_uac_t *nr = NULL;
515         char *p;
516
517         if(reg==NULL || _reg_htable==NULL)
518         {
519                 LM_ERR("bad parameters: %p/%p\n", reg, _reg_htable);
520                 return -1;
521         }
522         len = reg->l_uuid.len + 1
523                 + reg->l_username.len + 1
524                 + reg->l_domain.len + 1
525                 + reg->r_username.len + 1
526                 + reg->r_domain.len + 1
527                 + reg->realm.len + 1
528                 + reg->auth_proxy.len + 1
529                 + reg->auth_username.len + 1
530                 + reg->auth_password.len + 1
531                 + reg->socket.len + 1
532                 + (reg_keep_callid ? UAC_REG_TM_CALLID_SIZE : 0) + 1;
533         nr = (reg_uac_t*)shm_malloc(sizeof(reg_uac_t) + len);
534         if(nr==NULL)
535         {
536                 LM_ERR("no more shm\n");
537                 return -1;
538         }
539         memset(nr, 0, sizeof(reg_uac_t) + len);
540         nr->expires = reg->expires;
541         nr->flags   = reg->flags;
542         if (reg->reg_delay)
543                 nr->reg_delay = reg->reg_delay;
544         else if (reg_random_delay>0)
545                 nr->reg_delay = kam_rand() % reg_random_delay;
546         nr->reg_init  = time(NULL);
547         nr->h_uuid = reg_compute_hash(&reg->l_uuid);
548         nr->h_user = reg_compute_hash(&reg->l_username);
549
550         p = (char*)nr + sizeof(reg_uac_t);
551
552         reg_copy_shm(&nr->l_uuid, &reg->l_uuid, 0);
553         reg_copy_shm(&nr->l_username, &reg->l_username, 0);
554         reg_copy_shm(&nr->l_domain, &reg->l_domain, 0);
555         reg_copy_shm(&nr->r_username, &reg->r_username, 0);
556         reg_copy_shm(&nr->r_domain, &reg->r_domain, 0);
557         reg_copy_shm(&nr->realm, &reg->realm, 0);
558         reg_copy_shm(&nr->auth_proxy, &reg->auth_proxy, 0);
559         reg_copy_shm(&nr->auth_username, &reg->auth_username, 0);
560         reg_copy_shm(&nr->auth_password, &reg->auth_password, 0);
561         reg_copy_shm(&nr->socket, &reg->socket, 0);
562         reg_copy_shm(&nr->callid, &str_empty, reg_keep_callid ? UAC_REG_TM_CALLID_SIZE : 0);
563
564         reg_ht_add_byuser(nr);
565         reg_ht_add_byuuid(nr);
566         counter_inc(regtotal);
567
568         LM_DBG("added uuid: %.*s - l_user: %.*s\n", nr->l_uuid.len, nr->l_uuid.s,
569                         nr->l_username.len, nr->l_username.s);
570         return 0;
571 }
572
573
574  /**
575   *
576   */
577 int reg_ht_rm(reg_uac_t *reg)
578 {
579         unsigned int slot1, slot2;
580         reg_item_t *it = NULL;
581         reg_item_t *prev = NULL;
582         int found = 0;
583
584         if (reg == NULL)
585         {
586                 LM_ERR("bad parameter\n");
587                 return -1;
588         }
589
590         /* by uuid */
591         slot1 = reg_get_entry(reg->h_uuid, _reg_htable->htsize);
592         it = _reg_htable->entries[slot1].byuuid;
593         while (it)
594         {
595                 if (it->r == reg)
596                 {
597                         if (prev)
598                                 prev->next=it->next;
599                         else
600                                 _reg_htable->entries[slot1].byuuid = it->next;
601                         _reg_htable->entries[slot1].isize--;
602                         shm_free(it);
603                         found = 1;
604                         break;
605                 }
606                 prev = it;
607                 it = it->next;
608         }
609
610         /* by user */
611         prev = NULL;
612         slot2 = reg_get_entry(reg->h_user, _reg_htable->htsize);
613         if (slot2 != slot1) {
614                 lock_get(&_reg_htable->entries[slot2].lock);
615         }
616         it = _reg_htable->entries[slot2].byuser;
617         while (it)
618         {
619                 if (it->r == reg)
620                 {
621                         if (prev)
622                                 prev->next=it->next;
623                         else
624                                 _reg_htable->entries[slot2].byuser = it->next;
625                         _reg_htable->entries[slot2].usize--;
626                         shm_free(it);
627                         break;
628                 }
629                 prev = it;
630                 it = it->next;
631         }
632
633         shm_free(reg);
634         if (slot2 != slot1) {
635                 lock_release(&_reg_htable->entries[slot2].lock);
636         }
637         lock_release(&_reg_htable->entries[slot1].lock);
638
639         if (found) {
640                 counter_add(regtotal, -1);
641                 if(reg->flags & UAC_REG_ONLINE)
642                         counter_add(regactive, -1);
643                 if(reg->flags & UAC_REG_DISABLED)
644                         counter_add(regdisabled, -1);
645         }
646         return 0;
647 }
648
649
650 reg_uac_t *reg_ht_get_byuuid(str *uuid)
651 {
652         unsigned int hash;
653         unsigned int slot;
654         reg_item_t *it = NULL;
655
656         if(_reg_htable==NULL)
657         {
658                 LM_ERR("reg hash table not initialized\n");
659                 return NULL;
660         }
661
662         hash = reg_compute_hash(uuid);
663         slot = reg_get_entry(hash, _reg_htable->htsize);
664         lock_get(&_reg_htable->entries[slot].lock);
665         it = _reg_htable->entries[slot].byuuid;
666         while(it)
667         {
668                 if((it->r->h_uuid==hash) && (it->r->l_uuid.len==uuid->len)
669                                 && (strncmp(it->r->l_uuid.s, uuid->s, uuid->len)==0))
670                 {
671                         it->r->lock = &_reg_htable->entries[slot].lock;
672                         return it->r;
673                 }
674                 it = it->next;
675         }
676         lock_release(&_reg_htable->entries[slot].lock);
677         return NULL;
678 }
679
680 /**
681  *
682  */
683 reg_uac_t *reg_ht_get_byuser(str *user, str *domain)
684 {
685         unsigned int hash;
686         unsigned int slot;
687         reg_item_t *it = NULL;
688
689         if(_reg_htable==NULL)
690         {
691                 LM_ERR("reg hash table not initialized\n");
692                 return NULL;
693         }
694
695         hash = reg_compute_hash(user);
696         slot = reg_get_entry(hash, _reg_htable->htsize);
697         lock_get(&_reg_htable->entries[slot].lock);
698         it = _reg_htable->entries[slot].byuser;
699         while(it)
700         {
701                 if((it->r->h_user==hash) && (it->r->l_username.len==user->len)
702                                 && (strncmp(it->r->l_username.s, user->s, user->len)==0))
703                 {
704                         if(domain!=NULL && domain->s!=NULL)
705                         {
706                                 if((it->r->l_domain.len==domain->len)
707                                                 && (strncmp(it->r->l_domain.s, domain->s, domain->len)==0))
708                                 {
709                                         it->r->lock = &_reg_htable->entries[slot].lock;
710                                         return it->r;
711                                 }
712                         } else {
713                                 it->r->lock = &_reg_htable->entries[slot].lock;
714                                 return it->r;
715                         }
716                 }
717                 it = it->next;
718         }
719         lock_release(&_reg_htable->entries[slot].lock);
720         return NULL;
721 }
722
723 int reg_ht_get_byfilter(reg_uac_t **reg, str *attr, str *val)
724 {
725         int i;
726         str *rval;
727         reg_item_t *it;
728
729         /* try to use the hash table indices */
730         if(attr->len==6 && strncmp(attr->s, "l_uuid", 6)==0) {
731                 *reg = reg_ht_get_byuuid(val);
732                 return *reg != NULL;
733         }
734         if(attr->len==10 && strncmp(attr->s, "l_username", 10)==0) {
735                 *reg = reg_ht_get_byuser(val, NULL);
736                 return *reg != NULL;
737         }
738
739         /* check _all_ records */
740         for(i=0; i<_reg_htable->htsize; i++)
741         {
742                 lock_get(&_reg_htable->entries[i].lock);
743                 /* walk through entries */
744                 it = _reg_htable->entries[i].byuuid;
745                 while(it)
746                 {
747                         if(attr->len==10 && strncmp(attr->s, "r_username", 10)==0) {
748                                 rval = &it->r->r_username;
749                         } else if(attr->len==13 && strncmp(attr->s, "auth_username", 13)==0) {
750                                 rval = &it->r->auth_username;
751                         } else {
752                                 lock_release(&_reg_htable->entries[i].lock);
753                                 LM_ERR("unsupported filter attribute %.*s\n", attr->len, attr->s);
754                                 return -1;
755                         }
756
757                         if(rval->len==val->len && strncmp(val->s, rval->s, val->len)==0) {
758                                 /* found */
759                                 *reg = it->r;
760                                 (*reg)->lock = &_reg_htable->entries[i].lock;
761                                 return 1;
762                         }
763                         it = it->next;
764                 }
765                 lock_release(&_reg_htable->entries[i].lock);
766         }
767         *reg = NULL;
768         return 0;
769 }
770
771 int uac_reg_tmdlg(dlg_t *tmdlg, sip_msg_t *rpl)
772 {
773         if(tmdlg==NULL || rpl==NULL)
774                 return -1;
775
776         if (parse_headers(rpl, HDR_EOH_F, 0) < 0) {
777                 LM_ERR("error while parsing all headers in the reply\n");
778                 return -1;
779         }
780         if(parse_to_header(rpl)<0 || parse_from_header(rpl)<0) {
781                 LM_ERR("error while parsing From/To headers in the reply\n");
782                 return -1;
783         }
784         memset(tmdlg, 0, sizeof(dlg_t));
785
786         str2int(&(get_cseq(rpl)->number), &tmdlg->loc_seq.value);
787         tmdlg->loc_seq.is_set = 1;
788
789         tmdlg->id.call_id = rpl->callid->body;
790         trim(&tmdlg->id.call_id);
791
792         if (get_from(rpl)->tag_value.len) {
793                 tmdlg->id.loc_tag = get_from(rpl)->tag_value;
794         }
795         tmdlg->loc_uri = get_from(rpl)->uri;
796         tmdlg->rem_uri = get_to(rpl)->uri;
797         tmdlg->state= DLG_CONFIRMED;
798         return 0;
799 }
800
801 void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
802 {
803         char *uuid;
804         str suuid;
805         reg_uac_t *ri = NULL;
806         contact_t* c;
807         int expires;
808         struct sip_uri puri;
809         struct hdr_field *hdr;
810         HASHHEX response;
811         str *new_auth_hdr = NULL;
812         static struct authenticate_body auth;
813         struct uac_credential cred;
814         char  b_ruri[MAX_URI_SIZE];
815         str   s_ruri;
816         char  b_hdrs[MAX_UACH_SIZE];
817         str   s_hdrs;
818         uac_req_t uac_r;
819         str method = {"REGISTER", 8};
820         int ret;
821         dlg_t tmdlg;
822
823         if(ps->param==NULL || *ps->param==0)
824         {
825                 LM_DBG("uuid not received\n");
826                 return;
827         }
828         uuid = *((char**)ps->param);
829         LM_DBG("completed with status %d [uuid: %s]\n",
830                         ps->code, uuid);
831         suuid.s = uuid;
832         suuid.len = strlen(suuid.s);
833         ri = reg_ht_get_byuuid(&suuid);
834
835         if(ri==NULL)
836         {
837                 LM_DBG("no user with uuid %s\n", uuid);
838                 goto done;
839         }
840
841         if(ps->code == 200)
842         {
843                 if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1)
844                 {
845                         LM_ERR("failed to parse headers\n");
846                         goto error;
847                 }
848                 if (ps->rpl->contact==NULL)
849                 {
850                         LM_ERR("no Contact found\n");
851                         goto error;
852                 }
853                 if (parse_contact(ps->rpl->contact) < 0)
854                 {
855                         LM_ERR("failed to parse Contact HF\n");
856                         goto error;
857                 }
858                 if (((contact_body_t*)ps->rpl->contact->parsed)->star)
859                 {
860                         LM_DBG("* Contact found\n");
861                         goto done;
862                 }
863
864                 if (contact_iterator(&c, ps->rpl, 0) < 0)
865                         goto done;
866                 while(c)
867                 {
868                         if(parse_uri(c->uri.s, c->uri.len, &puri)!=0)
869                         {
870                                 LM_ERR("failed to parse c-uri\n");
871                                 goto error;
872                         }
873                         if(suuid.len==puri.user.len
874                                         && (strncmp(puri.user.s, suuid.s, suuid.len)==0))
875                         {
876                                 /* calculate expires */
877                                 expires=0;
878                                 if(c->expires==NULL || c->expires->body.len<=0)
879                                 {
880                                         if(ps->rpl->expires!=NULL && parse_expires(ps->rpl->expires)==0)
881                                                 expires = ((exp_body_t *)ps->rpl->expires->parsed)->val;
882                                 } else {
883                                         str2int(&c->expires->body, (unsigned int*)(&expires));
884                                 }
885                                 ri->timer_expires = ri->timer_expires + expires;
886                                 ri->flags |= UAC_REG_ONLINE;
887                                 if (reg_keep_callid && ps->rpl->callid->body.len < UAC_REG_TM_CALLID_SIZE) {
888                                         ri->callid.len = ps->rpl->callid->body.len;
889                                         memcpy(ri->callid.s, ps->rpl->callid->body.s, ri->callid.len);
890                                         str2int(&(get_cseq(ps->rpl)->number), &ri->cseq);
891                                 }
892                                 goto done;
893                         }
894                         if (contact_iterator(&c, ps->rpl, c) < 0)
895                         {
896                                 LM_DBG("local contact not found\n");
897                                 goto done;
898                         }
899                 }
900
901                 LM_DBG("sip response %d while registering [%.*s] with no match\n",
902                                 ps->code, ri->l_uuid.len, ri->l_uuid.s);
903                 goto done;
904         }
905
906         if(ps->code == 401 || ps->code == 407)
907         {
908                 if(ri->flags & UAC_REG_AUTHSENT)
909                 {
910                         LM_ERR("authentication failed for <%.*s>\n",
911                                         ri->l_uuid.len, ri->l_uuid.s);
912                         goto error;
913                 }
914                 hdr = get_autenticate_hdr(ps->rpl, ps->code);
915                 if (hdr==0)
916                 {
917                         LM_ERR("failed to extract authenticate hdr\n");
918                         goto error;
919                 }
920
921                 LM_DBG("auth header body [%.*s]\n",
922                                 hdr->body.len, hdr->body.s);
923
924                 if (parse_authenticate_body(&hdr->body, &auth)<0)
925                 {
926                         LM_ERR("failed to parse auth hdr body\n");
927                         goto error;
928                 }
929                 if (ri->realm.len>0) {
930                         /* only check if realms match if it is non-empty */
931                         if(auth.realm.len!=ri->realm.len
932                                         || strncmp(auth.realm.s, ri->realm.s, ri->realm.len)!=0)
933                         {
934                                 LM_ERR("realms do not match. requested realm: [%.*s]\n",
935                                                 auth.realm.len, auth.realm.s);
936                                 goto error;
937                         }
938                 }
939                 cred.realm = auth.realm;
940                 cred.user = ri->auth_username;
941                 cred.passwd = ri->auth_password;
942                 cred.next = NULL;
943
944                 snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
945                                 ri->r_domain.len, ri->r_domain.s);
946                 s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
947
948                 do_uac_auth(&method, &s_ruri, &cred, &auth, response);
949                 new_auth_hdr=build_authorization_hdr(ps->code, &s_ruri, &cred,
950                                 &auth, response);
951                 if (new_auth_hdr==0)
952                 {
953                         LM_ERR("failed to build authorization hdr\n");
954                         goto error;
955                 }
956
957                 snprintf(b_hdrs, MAX_UACH_SIZE,
958                                 "Contact: <sip:%.*s@%.*s>\r\n"
959                                 "Expires: %d\r\n"
960                                 "%.*s",
961                                 ri->l_uuid.len, ri->l_uuid.s,
962                                 reg_contact_addr.len, reg_contact_addr.s,
963                                 ri->expires,
964                                 new_auth_hdr->len, new_auth_hdr->s);
965                 s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
966                 pkg_free(new_auth_hdr->s);
967
968                 memset(&uac_r, 0, sizeof(uac_r));
969                 if(uac_reg_tmdlg(&tmdlg, ps->rpl)<0)
970                 {
971                         LM_ERR("failed to build tm dialog\n");
972                         goto error;
973                 }
974                 tmdlg.rem_target = s_ruri;
975                 if(ri->auth_proxy.len)
976                         tmdlg.dst_uri = ri->auth_proxy;
977                 uac_r.method = &method;
978                 uac_r.headers = &s_hdrs;
979                 uac_r.dialog = &tmdlg;
980                 uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
981                 /* Callback function */
982                 uac_r.cb  = uac_reg_tm_callback;
983                 /* Callback parameter */
984                 uac_r.cbp = (void*)uuid;
985                 ret = uac_tmb.t_request_within(&uac_r);
986
987                 if(ret<0) {
988                         LM_ERR("failed to send request with authentication for [%.*s]",
989                                         ri->l_uuid.len, ri->l_uuid.s);
990                         goto error;
991                 }
992
993                 ri->flags |= UAC_REG_AUTHSENT;
994                 lock_release(ri->lock);
995                 return;
996         }
997
998         if (ps->code == 423)   /* Interval too brief, retry with longer expiry */
999         {
1000                 if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1) {
1001                         LM_ERR("failed to parse headers\n");
1002                         goto error;
1003                 }
1004                 if(ps->rpl->min_expires!=NULL && parse_expires(ps->rpl->min_expires)==0) {
1005                         ri->expires = ((exp_body_t *)ps->rpl->min_expires->parsed)->val;
1006                 } else {
1007                         ri->expires *= 2;
1008                 }
1009                 LM_DBG("got 423 response while registering [%.*s], set new expires to %d\n",
1010                                 ri->l_uuid.len, ri->l_uuid.s, ri->expires);
1011                 /* Retry will be done on next timer interval */
1012                 goto done;
1013         } else
1014         {
1015                 LM_ERR("got sip response %d while registering [%.*s]\n",
1016                                 ps->code, ri->l_uuid.len, ri->l_uuid.s);
1017                 goto error;
1018         }
1019
1020 error:
1021         if(reg_retry_interval) {
1022                 ri->timer_expires = time(NULL) + reg_retry_interval;
1023         } else {
1024                 ri->flags |= UAC_REG_DISABLED;
1025                 counter_inc(regdisabled);
1026         }
1027         ri->cseq = 0;
1028 done:
1029         if(ri) {
1030                 ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT);
1031                 lock_release(ri->lock);
1032         }
1033         shm_free(uuid);
1034         counter_inc(regactive);
1035 }
1036
1037 int uac_reg_update(reg_uac_t *reg, time_t tn)
1038 {
1039         char *uuid;
1040         uac_req_t uac_r;
1041         str method = {"REGISTER", 8};
1042         int ret;
1043         char  b_ruri[MAX_URI_SIZE];
1044         str   s_ruri;
1045         char  b_turi[MAX_URI_SIZE];
1046         str   s_turi;
1047         char  b_hdrs[MAX_UACH_SIZE];
1048         str   s_hdrs;
1049         dlg_t tmdlg;
1050
1051         if(uac_tmb.t_request==NULL)
1052                 return -1;
1053         if(reg->expires==0)
1054                 return 1;
1055         if(reg->flags&UAC_REG_ONGOING) {
1056                 if (reg->timer_expires > tn - reg_retry_interval)
1057                         return 2;
1058                 LM_DBG("record marked as ongoing registration (%d) - resetting\n",
1059                                 (int)reg->flags);
1060                 reg->flags &= ~(UAC_REG_ONLINE|UAC_REG_AUTHSENT);
1061         }
1062         if(reg_active && *reg_active == 0)
1063                 return 4;
1064         if(reg->flags&UAC_REG_DISABLED)
1065                 return 4;
1066
1067         if(!(reg->flags & UAC_REG_INIT)) {
1068                 if(reg->reg_delay>0) {
1069                         if(tn < reg->reg_init+reg->reg_delay) {
1070                                 return 2;
1071                         }
1072                 }
1073                 reg->flags |= UAC_REG_INIT;
1074         }
1075
1076         if(reg->timer_expires > tn + reg_timer_interval + 3)
1077                 return 3;
1078         uuid = (char*)shm_malloc(reg->l_uuid.len+1);
1079         if(uuid==NULL)
1080         {
1081                 LM_ERR("no more shm\n");
1082                 return -1;
1083         }
1084         reg->timer_expires = tn;
1085         reg->flags |= UAC_REG_ONGOING;
1086         counter_add(regactive, -1);             /* Take it out of the active pool while re-registering */
1087         memcpy(uuid, reg->l_uuid.s, reg->l_uuid.len);
1088         uuid[reg->l_uuid.len] = '\0';
1089
1090         snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
1091                         reg->r_domain.len, reg->r_domain.s);
1092         s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
1093
1094         snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
1095                         reg->r_username.len, reg->r_username.s,
1096                         reg->r_domain.len, reg->r_domain.s);
1097         s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
1098
1099         snprintf(b_hdrs, MAX_UACH_SIZE,
1100                         "Contact: <sip:%.*s@%.*s>\r\n"
1101                         "Expires: %d\r\n",
1102                         reg->l_uuid.len, reg->l_uuid.s,
1103                         reg_contact_addr.len, reg_contact_addr.s,
1104                         reg->expires);
1105         s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
1106
1107         memset(&uac_r, '\0', sizeof(uac_r));
1108         uac_r.method = &method;
1109         uac_r.headers = &s_hdrs;
1110         uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
1111         /* Callback function */
1112         uac_r.cb  = uac_reg_tm_callback;
1113         /* Callback parameter */
1114         uac_r.cbp = (void*)uuid;
1115
1116         if (reg_keep_callid && reg->flags & UAC_REG_ONLINE
1117                                 && reg->cseq > 0 && reg->cseq < 2147483638
1118                                 && reg->callid.len > 0)
1119         {
1120                 /* reregister, reuse callid and cseq */
1121                 memset(&tmdlg, 0, sizeof(dlg_t));
1122                 tmdlg.id.call_id = reg->callid;
1123                 tmdlg.loc_seq.value = reg->cseq;
1124                 tmdlg.loc_seq.is_set = 1;
1125                 tmdlg.rem_target = s_ruri;
1126                 tmdlg.loc_uri = s_turi;
1127                 tmdlg.rem_uri = s_turi;
1128                 tmdlg.state= DLG_CONFIRMED;
1129                 if(reg->auth_proxy.len)
1130                         tmdlg.dst_uri = reg->auth_proxy;
1131                 uac_r.dialog = &tmdlg;
1132
1133                 ret = uac_tmb.t_request_within(&uac_r);
1134         } else {
1135                 /* custom socket */
1136                 if(reg->socket.s != NULL && reg->socket.len > 0) {
1137                         LM_DBG("using custom socket %.*s to send request\n",
1138                                 reg->socket.len, reg->socket.s);
1139                         uac_r.ssock = &reg->socket;
1140                 }
1141                 /* default socket */
1142                 else {
1143                         if(uac_default_socket.s != NULL && uac_default_socket.len > 0) {
1144                                 LM_DBG("using configured default_socket to send request\n");
1145                                 uac_r.ssock = &uac_default_socket;
1146                         }
1147                 }
1148                 ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
1149                                 &s_ruri, /* Request-URI */
1150                                 &s_turi, /* To */
1151                                 &s_turi, /* From */
1152                                 (reg->auth_proxy.len)?&reg->auth_proxy:NULL /* outbound uri */
1153                                 );
1154         }
1155         reg->flags &= ~UAC_REG_ONLINE;
1156
1157         if(ret<0)
1158         {
1159                 LM_ERR("failed to send request for [%.*s]", reg->l_uuid.len, reg->l_uuid.s);
1160                 shm_free(uuid);
1161                 if (reg_retry_interval)
1162                         reg->timer_expires = (tn ? tn : time(NULL)) + reg_retry_interval;
1163                 else {
1164                         reg->flags |= UAC_REG_DISABLED;
1165                         counter_inc(regdisabled);
1166                 }
1167                 reg->flags &= ~UAC_REG_ONGOING;
1168                 return -1;
1169         }
1170         return 0;
1171 }
1172
1173 /**
1174  *
1175  */
1176 void uac_reg_timer(unsigned int ticks)
1177 {
1178         int i;
1179         reg_item_t *it = NULL;
1180         time_t tn;
1181
1182         if(_reg_htable==NULL)
1183                 return;
1184
1185         tn = time(NULL);
1186         for(i=0; i<_reg_htable->htsize; i++)
1187         {
1188                 /* walk through entries */
1189                 lock_get(&_reg_htable->entries[i].lock);
1190                 it = _reg_htable->entries[i].byuuid;
1191                 while(it)
1192                 {
1193                         uac_reg_update(it->r, tn);
1194                         it = it->next;
1195                 }
1196                 lock_release(&_reg_htable->entries[i].lock);
1197         }
1198
1199         if(_reg_htable_gc!=NULL)
1200         {
1201                 lock_get(_reg_htable_gc_lock);
1202                 if(_reg_htable_gc->stime!=0
1203                                 && _reg_htable_gc->stime < tn - _uac_reg_gc_interval)
1204                         uac_reg_reset_ht_gc();
1205                 lock_release(_reg_htable_gc_lock);
1206         }
1207 }
1208
1209 #define reg_db_set_attr(attr, pos) do { \
1210         if(!VAL_NULL(&RES_ROWS(db_res)[i].values[pos])) { \
1211                 reg->attr.s = \
1212                 (char*)(RES_ROWS(db_res)[i].values[pos].val.string_val); \
1213                 reg->attr.len = strlen(reg->attr.s); \
1214                 if(reg->attr.len == 0) { \
1215                         LM_ERR("empty value not allowed for column[%d]='%.*s' - ignoring record\n", \
1216                                         pos, db_cols[pos]->len, db_cols[pos]->s); \
1217                         return -1; \
1218                 } \
1219         } \
1220 } while(0);
1221
1222
1223 static inline int uac_reg_db_to_reg(reg_uac_t *reg, db1_res_t* db_res, int i, db_key_t *db_cols)
1224 {
1225         memset(reg, 0, sizeof(reg_uac_t));;
1226         /* check for NULL values ?!?! */
1227         reg_db_set_attr(l_uuid, 0);
1228         reg_db_set_attr(l_username, 1);
1229         reg_db_set_attr(l_domain, 2);
1230         reg_db_set_attr(r_username, 3);
1231         reg_db_set_attr(r_domain, 4);
1232         /* realm may be empty */
1233         if(!VAL_NULL(&RES_ROWS(db_res)[i].values[5])) {
1234                 reg->realm.s = (char*)(RES_ROWS(db_res)[i].values[5].val.string_val);
1235                 reg->realm.len = strlen(reg->realm.s);
1236         }
1237         reg_db_set_attr(auth_username, 6);
1238         reg_db_set_attr(auth_password, 7);
1239         reg_db_set_attr(auth_proxy, 8);
1240         reg->expires = (unsigned int)RES_ROWS(db_res)[i].values[9].val.int_val;
1241         reg->flags = (unsigned int)RES_ROWS(db_res)[i].values[10].val.int_val;
1242         reg->reg_delay = (unsigned int)RES_ROWS(db_res)[i].values[11].val.int_val;
1243         /* socket may be empty */
1244         if(!VAL_NULL(&RES_ROWS(db_res)[i].values[12])) {
1245                 reg->socket.s = (char*)(RES_ROWS(db_res)[i].values[12].val.string_val);
1246                 reg->socket.len = strlen(reg->socket.s);
1247         }
1248         return 0;
1249 }
1250
1251
1252 /**
1253  *
1254  */
1255 int uac_reg_load_db(void)
1256 {
1257         db1_con_t *reg_db_con = NULL;
1258         db_func_t reg_dbf;
1259         reg_uac_t reg;
1260         db_key_t db_cols[13] = {
1261                 &l_uuid_column,
1262                 &l_username_column,
1263                 &l_domain_column,
1264                 &r_username_column,
1265                 &r_domain_column,
1266                 &realm_column,
1267                 &auth_username_column,
1268                 &auth_password_column,
1269                 &auth_proxy_column,
1270                 &expires_column,
1271                 &flags_column,
1272                 &reg_delay_column,
1273                 &socket_column
1274         };
1275         db1_res_t* db_res = NULL;
1276         int i, ret;
1277
1278         /* binding to db module */
1279         if(reg_db_url.s==NULL)
1280         {
1281                 LM_ERR("no db url\n");
1282                 return -1;
1283         }
1284
1285         if(db_bind_mod(&reg_db_url, &reg_dbf))
1286         {
1287                 LM_ERR("database module not found\n");
1288                 return -1;
1289         }
1290
1291         if (!DB_CAPABILITY(reg_dbf, DB_CAP_ALL))
1292         {
1293                 LM_ERR("database module does not "
1294                                 "implement all functions needed by the module\n");
1295                 return -1;
1296         }
1297
1298         /* open a connection with the database */
1299         reg_db_con = reg_dbf.init(&reg_db_url);
1300         if(reg_db_con==NULL)
1301         {
1302                 LM_ERR("failed to connect to the database\n");
1303                 return -1;
1304         }
1305
1306         if(db_check_table_version(&reg_dbf, reg_db_con, &reg_db_table, UACREG_TABLE_VERSION) < 0) {
1307                 DB_TABLE_VERSION_ERROR(reg_db_table);
1308                 return -1;
1309         }
1310
1311         if (reg_dbf.use_table(reg_db_con, &reg_db_table) < 0)
1312         {
1313                 LM_ERR("failed to use_table\n");
1314                 return -1;
1315         }
1316
1317         if (DB_CAPABILITY(reg_dbf, DB_CAP_FETCH)) {
1318                 if(reg_dbf.query(reg_db_con, 0, 0, 0, db_cols, 0, 13, 0, 0) < 0)
1319                 {
1320                         LM_ERR("Error while querying db\n");
1321                         return -1;
1322                 }
1323                 if(reg_dbf.fetch_result(reg_db_con, &db_res, reg_fetch_rows)<0)
1324                 {
1325                         LM_ERR("Error while fetching result\n");
1326                         if (db_res)
1327                                 reg_dbf.free_result(reg_db_con, db_res);
1328                         goto error;
1329                 } else {
1330                         if(RES_ROW_N(db_res)==0)
1331                         {
1332                                 goto done;
1333                         }
1334                 }
1335         } else {
1336                 if((ret=reg_dbf.query(reg_db_con, NULL, NULL, NULL, db_cols,
1337                                                 0, 13, 0, &db_res))!=0
1338                                 || RES_ROW_N(db_res)<=0 )
1339                 {
1340                         reg_dbf.free_result(reg_db_con, db_res);
1341                         if( ret==0)
1342                         {
1343                                 return 0;
1344                         } else {
1345                                 goto error;
1346                         }
1347                 }
1348         }
1349
1350         do {
1351                 for(i=0; i<RES_ROW_N(db_res); i++)
1352                 {
1353                         if(uac_reg_db_to_reg(&reg, db_res, i, db_cols) < 0)
1354                                 continue;
1355                         if(reg_ht_add(&reg)<0)
1356                         {
1357                                 LM_ERR("Error adding reg to htable\n");
1358                                 goto error;
1359                         }
1360                 }
1361                 if (DB_CAPABILITY(reg_dbf, DB_CAP_FETCH)) {
1362                         if(reg_dbf.fetch_result(reg_db_con, &db_res, reg_fetch_rows)<0) {
1363                                 LM_ERR("Error while fetching!\n");
1364                                 if (db_res)
1365                                         reg_dbf.free_result(reg_db_con, db_res);
1366                                 goto error;
1367                         }
1368                 } else {
1369                         break;
1370                 }
1371         }  while(RES_ROW_N(db_res)>0);
1372         reg_dbf.free_result(reg_db_con, db_res);
1373         reg_dbf.close(reg_db_con);
1374
1375 done:
1376         return 0;
1377
1378 error:
1379         if (reg_db_con) {
1380                 reg_dbf.free_result(reg_db_con, db_res);
1381                 reg_dbf.close(reg_db_con);
1382         }
1383         return -1;
1384 }
1385
1386 /**
1387  *
1388  */
1389 int uac_reg_db_refresh(str *pl_uuid)
1390 {
1391         db1_con_t *reg_db_con = NULL;
1392         db_func_t reg_dbf;
1393         reg_uac_t reg;
1394         reg_uac_t *cur_reg;
1395         db_key_t db_cols[13] = {
1396                 &l_uuid_column,
1397                 &l_username_column,
1398                 &l_domain_column,
1399                 &r_username_column,
1400                 &r_domain_column,
1401                 &realm_column,
1402                 &auth_username_column,
1403                 &auth_password_column,
1404                 &auth_proxy_column,
1405                 &expires_column,
1406                 &flags_column,
1407                 &reg_delay_column,
1408                 &socket_column
1409         };
1410         db_key_t db_keys[1] = {&l_uuid_column};
1411         db_val_t db_vals[1];
1412
1413         db1_res_t* db_res = NULL;
1414         int ret;
1415
1416         /* binding to db module */
1417         if(reg_db_url.s==NULL)
1418         {
1419                 LM_ERR("no db url\n");
1420                 return -1;
1421         }
1422
1423         if(db_bind_mod(&reg_db_url, &reg_dbf))
1424         {
1425                 LM_ERR("database module not found\n");
1426                 return -1;
1427         }
1428
1429         if (!DB_CAPABILITY(reg_dbf, DB_CAP_ALL))
1430         {
1431                 LM_ERR("database module does not "
1432                                 "implement all functions needed by the module\n");
1433                 return -1;
1434         }
1435
1436         /* open a connection with the database */
1437         reg_db_con = reg_dbf.init(&reg_db_url);
1438         if(reg_db_con==NULL)
1439         {
1440                 LM_ERR("failed to connect to the database\n");
1441                 return -1;
1442         }
1443         if (reg_dbf.use_table(reg_db_con, &reg_db_table) < 0)
1444         {
1445                 LM_ERR("failed to use_table\n");
1446                 return -1;
1447         }
1448
1449         db_vals[0].type = DB1_STR;
1450         db_vals[0].nul = 0;
1451         db_vals[0].val.str_val.s = pl_uuid->s;
1452         db_vals[0].val.str_val.len = pl_uuid->len;
1453
1454         if((ret=reg_dbf.query(reg_db_con, db_keys, NULL, db_vals, db_cols,
1455                                         1 /*nr keys*/, 13 /*nr cols*/, 0, &db_res))!=0
1456                         || RES_ROW_N(db_res)<=0 )
1457         {
1458                 reg_dbf.free_result(reg_db_con, db_res);
1459                 if( ret==0)
1460                 {
1461                         return 0;
1462                 } else {
1463                         goto error;
1464                 }
1465         }
1466
1467         if (uac_reg_db_to_reg(&reg, db_res, 0, db_cols)==0)
1468         {
1469                 lock_get(_reg_htable_gc_lock);
1470                 if((cur_reg=reg_ht_get_byuuid(pl_uuid))!=NULL)
1471                 {
1472                         reg.flags |= (cur_reg->flags & (UAC_REG_ONGOING | UAC_REG_AUTHSENT));
1473                         reg_ht_rm(cur_reg);
1474                 }
1475                 if(reg_ht_add(&reg)<0)
1476                 {
1477                         lock_release(_reg_htable_gc_lock);
1478                         LM_ERR("Error adding reg to htable\n");
1479                         goto error;
1480                 }
1481                 lock_release(_reg_htable_gc_lock);
1482         }
1483
1484         reg_dbf.free_result(reg_db_con, db_res);
1485         reg_dbf.close(reg_db_con);
1486
1487         return 1;
1488
1489 error:
1490         if (reg_db_con) {
1491                 reg_dbf.free_result(reg_db_con, db_res);
1492                 reg_dbf.close(reg_db_con);
1493         }
1494         return -1;
1495 }
1496
1497 /**
1498  *
1499  */
1500 int uac_reg_refresh(sip_msg_t *msg, str *l_uuid)
1501 {
1502         int ret;
1503
1504         if(l_uuid==NULL || l_uuid->s==NULL || l_uuid->len<=0) {
1505                 LM_ERR("invalid parameters\n");
1506                 return -1;
1507         }
1508
1509         ret = uac_reg_db_refresh(l_uuid);
1510         if(ret==0) {
1511                 LM_WARN("record not found: %.*s\n", l_uuid->len, l_uuid->s);
1512                 return -1;
1513         } else if(ret<0) {
1514                 LM_WARN("failed to refresh record: %.*s - check log messages\n",
1515                                 l_uuid->len, l_uuid->s);
1516                 return -1;
1517         }
1518
1519         return 1;
1520 }
1521
1522 /**
1523  *
1524  */
1525 int  uac_reg_lookup(struct sip_msg *msg, str *src, pv_spec_t *dst, int mode)
1526 {
1527         char  b_ruri[MAX_URI_SIZE];
1528         str   s_ruri;
1529         struct sip_uri puri;
1530         reg_uac_t *reg = NULL;
1531         pv_value_t val;
1532
1533         if(!pv_is_w(dst))
1534         {
1535                 LM_ERR("dst is not w/\n");
1536                 return -1;
1537         }
1538         if(mode==0)
1539         {
1540                 reg = reg_ht_get_byuuid(src);
1541                 if(reg==NULL)
1542                 {
1543                         LM_DBG("no uuid: %.*s\n", src->len, src->s);
1544                         return -1;
1545                 }
1546                 snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s@%.*s",
1547                                 reg->l_username.len, reg->l_username.s,
1548                                 reg->l_domain.len, reg->l_domain.s);
1549                 s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
1550         } else {
1551                 if(parse_uri(src->s, src->len, &puri)!=0)
1552                 {
1553                         LM_ERR("failed to parse uri\n");
1554                         return -2;
1555                 }
1556                 reg = reg_ht_get_byuser(&puri.user, (reg_use_domain)?&puri.host:NULL);
1557                 if(reg==NULL)
1558                 {
1559                         LM_DBG("no user: %.*s\n", src->len, src->s);
1560                         return -1;
1561                 }
1562                 snprintf(b_ruri, MAX_URI_SIZE, "%.*s",
1563                                 reg->l_uuid.len, reg->l_uuid.s);
1564                 s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
1565         }
1566         lock_release(reg->lock);
1567         memset(&val, 0, sizeof(pv_value_t));
1568         val.flags |= PV_VAL_STR;
1569         val.rs = s_ruri;
1570         if(pv_set_spec_value(msg, dst, 0, &val)!=0)
1571                 return -1;
1572
1573         return 1;
1574 }
1575
1576 /**
1577  *
1578  */
1579 int uac_reg_status(struct sip_msg *msg, str *src, int mode)
1580 {
1581         struct sip_uri puri;
1582         reg_uac_t *reg = NULL;
1583         int ret;
1584
1585         if(mode==0)
1586         {
1587                 reg = reg_ht_get_byuuid(src);
1588                 if(reg==NULL)
1589                 {
1590                         LM_DBG("no uuid: %.*s\n", src->len, src->s);
1591                         return -1;
1592                 }
1593         } else {
1594                 if(parse_uri(src->s, src->len, &puri)!=0)
1595                 {
1596                         LM_ERR("failed to parse uri\n");
1597                         return -1;
1598                 }
1599                 reg = reg_ht_get_byuser(&puri.user, (reg_use_domain)?&puri.host:NULL);
1600                 if(reg==NULL)
1601                 {
1602                         LM_DBG("no user: %.*s\n", src->len, src->s);
1603                         return -1;
1604                 }
1605         }
1606
1607         if ((reg->flags & UAC_REG_ONLINE) && (reg->timer_expires > time(NULL)))
1608                 ret = 1;
1609         else if (reg->flags & UAC_REG_ONGOING)
1610                 ret = -2;
1611         else if (reg->flags & UAC_REG_DISABLED)
1612                 ret = -3;
1613         else
1614                 ret = -99;
1615
1616         lock_release(reg->lock);
1617         return ret;
1618 }
1619
1620 /**
1621  *
1622  */
1623 int uac_reg_request_to(struct sip_msg *msg, str *src, unsigned int mode)
1624 {
1625         char ruri[MAX_URI_SIZE];
1626         struct sip_uri puri;
1627         reg_uac_t *reg = NULL;
1628         pv_value_t val;
1629         struct action act;
1630         struct run_act_ctx ra_ctx;
1631
1632         switch(mode)
1633         {
1634                 case 0:
1635                         reg = reg_ht_get_byuuid(src);
1636                         break;
1637                 case 1:
1638                         if(reg_use_domain)
1639                         {
1640                                 if (parse_uri(src->s, src->len, &puri)!=0)
1641                                 {
1642                                         LM_ERR("failed to parse uri\n");
1643                                         return -2;
1644                                 }
1645                                 reg = reg_ht_get_byuser(&puri.user, &puri.host);
1646                         } else {
1647                                 reg = reg_ht_get_byuser(src, NULL);
1648                         }
1649                         break;
1650                 default:
1651                         LM_ERR("unknown mode: %d\n", mode);
1652                         return -1;
1653         }
1654
1655         if(reg==NULL)
1656         {
1657                 LM_DBG("no user: %.*s\n", src->len, src->s);
1658                 return -1;
1659         }
1660
1661         // Set uri ($ru)
1662         snprintf(ruri, MAX_URI_SIZE, "sip:%.*s@%.*s",
1663                         reg->r_username.len, reg->r_username.s,
1664                         reg->r_domain.len, reg->r_domain.s);
1665         memset(&act, 0, sizeof(act));
1666         act.type = SET_URI_T;
1667         act.val[0].type = STRING_ST;
1668         act.val[0].u.string = ruri;
1669         init_run_actions_ctx(&ra_ctx);
1670         if (do_action(&ra_ctx, &act, msg) < 0) {
1671                 LM_ERR("error while setting request uri\n");
1672                 goto error;
1673         }
1674
1675         // Set auth_proxy ($du)
1676         if (set_dst_uri(msg, &reg->auth_proxy) < 0) {
1677                 LM_ERR("error while setting outbound proxy\n");
1678                 goto error;
1679         }
1680
1681         memset(&val, 0, sizeof(pv_value_t));
1682         val.flags |= PV_VAL_STR;
1683
1684         // Set auth_realm
1685         val.rs = reg->realm;
1686         if(pv_set_spec_value(msg, &auth_realm_spec, 0, &val)!=0) {
1687                 LM_ERR("error while setting auth_realm\n");
1688                 goto error;
1689         }
1690
1691         // Set auth_username
1692         val.rs = reg->auth_username;
1693         if(pv_set_spec_value(msg, &auth_username_spec, 0, &val)!=0) {
1694                 LM_ERR("error while setting auth_username\n");
1695                 goto error;
1696         }
1697
1698         // Set auth_password
1699         val.rs = reg->auth_password;
1700         if(pv_set_spec_value(msg, &auth_password_spec, 0, &val)!=0) {
1701                 LM_ERR("error while setting auth_password\n");
1702                 goto error;
1703         }
1704
1705         lock_release(reg->lock);
1706         return 1;
1707
1708 error:
1709         lock_release(reg->lock);
1710         return -1;
1711 }
1712
1713 /**
1714  *
1715  */
1716 static int uac_reg_update_flag(str *attr, str *val, int mode, int fval)
1717 {
1718         reg_uac_t *reg = NULL;
1719         int ret;
1720
1721         if(_reg_htable==NULL) {
1722                 LM_ERR("uac remote registrations not enabled\n");
1723                 return -1;
1724         }
1725
1726         if(attr->len<=0 || attr->s==NULL || val->len<=0 || val->s==NULL) {
1727                 LM_ERR("bad parameter values\n");
1728                 return -1;
1729         }
1730
1731         ret = reg_ht_get_byfilter(&reg, attr, val);
1732         if (ret == 0) {
1733                 LM_DBG("record not found for %.*s = %.*s\n", attr->len, attr->s,
1734                                 val->len, val->s);
1735                 return -2;
1736         } else if (ret < 0) {
1737                 LM_DBG("unsupported filter attribute %.*s = %.*s\n", attr->len, attr->s,
1738                                 val->len, val->s);
1739                 return -3;
1740         }
1741
1742         if(mode==1) {
1743                 reg->flags |= fval;
1744         } else {
1745                 reg->flags &= ~fval;
1746         }
1747         reg->timer_expires = time(NULL) + 1;
1748
1749         lock_release(reg->lock);
1750         return 1;
1751 }
1752
1753 /**
1754  *
1755  */
1756 int uac_reg_enable(sip_msg_t *msg, str *attr, str *val)
1757 {
1758         counter_add(regdisabled, -1);
1759         return uac_reg_update_flag(attr, val, 0, UAC_REG_DISABLED);
1760 }
1761
1762 /**
1763  *
1764  */
1765 int uac_reg_disable(sip_msg_t *msg, str *attr, str *val)
1766 {
1767         counter_inc(regdisabled);
1768         return uac_reg_update_flag(attr, val, 1, UAC_REG_DISABLED);
1769 }
1770
1771 /**
1772  *
1773  */
1774 static int rpc_uac_reg_add_node_helper(rpc_t* rpc, void* ctx, reg_uac_t *reg, time_t tn)
1775 {
1776         void* th;
1777         str none = {"none", 4};
1778
1779         /* add entry node */
1780         if (rpc->add(ctx, "{", &th) < 0)
1781         {
1782                 rpc->fault(ctx, 500, "Internal error creating rpc");
1783                 return -1;
1784         }
1785         if (rpc->struct_add(th, "SSSSSSSSSddddddS",
1786                                 "l_uuid",        &reg->l_uuid,
1787                                 "l_username",    &reg->l_username,
1788                                 "l_domain",      &reg->l_domain,
1789                                 "r_username",    &reg->r_username,
1790                                 "r_domain",      &reg->r_domain,
1791                                 "realm",         &reg->realm,
1792                                 "auth_username", &reg->auth_username,
1793                                 "auth_password", &reg->auth_password,
1794                                 "auth_proxy",    (reg->auth_proxy.len)?
1795                                 &reg->auth_proxy:&none,
1796                                 "expires",       (int)reg->expires,
1797                                 "flags",         (int)reg->flags,
1798                                 "diff_expires",  (int)(reg->timer_expires - tn),
1799                                 "timer_expires", (int)reg->timer_expires,
1800                                 "reg_init",      (int)reg->reg_init,
1801                                 "reg_delay",     (int)reg->reg_delay,
1802                                 "socket",        &reg->socket
1803                                 )<0) {
1804                 rpc->fault(ctx, 500, "Internal error adding item");
1805                 return -1;
1806         }
1807         return 0;
1808 }
1809
1810 static const char* rpc_uac_reg_dump_doc[2] = {
1811         "Dump the contents of user registrations table.",
1812         0
1813 };
1814
1815 static void rpc_uac_reg_dump(rpc_t* rpc, void* ctx)
1816 {
1817         int i;
1818         reg_item_t *reg = NULL;
1819         time_t tn;
1820
1821         if(_reg_htable==NULL)
1822         {
1823                 rpc->fault(ctx, 500, "Not enabled");
1824                 return;
1825         }
1826
1827         tn = time(NULL);
1828
1829         for(i=0; i<_reg_htable->htsize; i++)
1830         {
1831                 lock_get(&_reg_htable->entries[i].lock);
1832                 /* walk through entries */
1833                 reg = _reg_htable->entries[i].byuuid;
1834                 while(reg)
1835                 {
1836                         if (rpc_uac_reg_add_node_helper(rpc, ctx, reg->r, tn)<0)
1837                         {
1838                                 lock_release(&_reg_htable->entries[i].lock);
1839                                 return;
1840                         }
1841                         reg = reg->next;
1842                 }
1843                 lock_release(&_reg_htable->entries[i].lock);
1844         }
1845 }
1846
1847 static const char* rpc_uac_reg_info_doc[2] = {
1848         "Return the details of registration for a particular record.",
1849         0
1850 };
1851
1852 static void rpc_uac_reg_info(rpc_t* rpc, void* ctx)
1853 {
1854         reg_uac_t *reg = NULL;
1855         str attr = {0};
1856         str val = {0};
1857         int ret;
1858
1859         if(_reg_htable==NULL)
1860         {
1861                 rpc->fault(ctx, 500, "Not enabled");
1862                 return;
1863         }
1864
1865         if(rpc->scan(ctx, "S.S", &attr, &val)<2)
1866         {
1867                 rpc->fault(ctx, 400, "Invalid Parameters");
1868                 return;
1869         }
1870         if(attr.len<=0 || attr.s==NULL || val.len<=0 || val.s==NULL)
1871         {
1872                 LM_ERR("bad parameter values\n");
1873                 rpc->fault(ctx, 400, "Invalid Parameter Values");
1874                 return;
1875         }
1876
1877         ret = reg_ht_get_byfilter(&reg, &attr, &val);
1878         if (ret == 0) {
1879                 rpc->fault(ctx, 404, "Record not found");
1880                 return;
1881         } else if (ret < 0) {
1882                 rpc->fault(ctx, 400, "Unsupported filter attribute");
1883                 return;
1884         }
1885
1886         rpc_uac_reg_add_node_helper(rpc, ctx, reg, time(NULL));
1887         lock_release(reg->lock);
1888         return;
1889 }
1890
1891
1892 static void rpc_uac_reg_update_flag(rpc_t* rpc, void* ctx, int mode, int fval)
1893 {
1894         reg_uac_t *reg = NULL;
1895         str attr = {0};
1896         str val = {0};
1897         int ret;
1898
1899         if(_reg_htable==NULL)
1900         {
1901                 rpc->fault(ctx, 500, "Not enabled");
1902                 return;
1903         }
1904
1905         if(rpc->scan(ctx, "S.S", &attr, &val)<2)
1906         {
1907                 rpc->fault(ctx, 400, "Invalid Parameters");
1908                 return;
1909         }
1910         if(attr.len<=0 || attr.s==NULL || val.len<=0 || val.s==NULL)
1911         {
1912                 LM_ERR("bad parameter values\n");
1913                 rpc->fault(ctx, 400, "Invalid Parameter Values");
1914                 return;
1915         }
1916
1917         ret = reg_ht_get_byfilter(&reg, &attr, &val);
1918         if (ret == 0) {
1919                 rpc->fault(ctx, 404, "Record not found");
1920                 return;
1921         } else if (ret < 0) {
1922                 rpc->fault(ctx, 400, "Unsupported filter attribute");
1923                 return;
1924         }
1925
1926         if(mode==1) {
1927                 reg->flags |= fval;
1928         } else {
1929                 reg->flags &= ~fval;
1930         }
1931         reg->timer_expires = time(NULL) + 1;
1932
1933         lock_release(reg->lock);
1934         return;
1935 }
1936
1937 static const char* rpc_uac_reg_enable_doc[2] = {
1938         "Enable registration for a particular record.",
1939         0
1940 };
1941
1942 static void rpc_uac_reg_enable(rpc_t* rpc, void* ctx)
1943 {
1944         rpc_uac_reg_update_flag(rpc, ctx, 0, UAC_REG_DISABLED);
1945         counter_add(regdisabled, -1);
1946 }
1947
1948 static const char* rpc_uac_reg_disable_doc[2] = {
1949         "Disable registration for a particular record.",
1950         0
1951 };
1952
1953 static void rpc_uac_reg_disable(rpc_t* rpc, void* ctx)
1954 {
1955         rpc_uac_reg_update_flag(rpc, ctx, 1, UAC_REG_DISABLED);
1956         counter_inc(regdisabled);
1957 }
1958
1959 static const char* rpc_uac_reg_reload_doc[2] = {
1960         "Reload records from database.",
1961         0
1962 };
1963
1964 static void rpc_uac_reg_reload(rpc_t* rpc, void* ctx)
1965 {
1966         int ret;
1967         if(uac_reg_ht_shift()<0) {
1968                 rpc->fault(ctx, 500, "Failed to shift records - check log messages");
1969                 return;
1970         }
1971         lock_get(_reg_htable_gc_lock);
1972         ret =  uac_reg_load_db();
1973         lock_release(_reg_htable_gc_lock);
1974         if(ret<0) {
1975                 rpc->fault(ctx, 500, "Failed to reload records - check log messages");
1976                 return;
1977         }
1978 }
1979
1980 static const char* rpc_uac_reg_refresh_doc[2] = {
1981         "Refresh a record from database.",
1982         0
1983 };
1984
1985 static void rpc_uac_reg_refresh(rpc_t* rpc, void* ctx)
1986 {
1987         int ret;
1988         str l_uuid;
1989
1990         if(rpc->scan(ctx, "S", &l_uuid)<1)
1991         {
1992                 rpc->fault(ctx, 400, "Invalid Parameters");
1993                 return;
1994         }
1995
1996         ret =  uac_reg_db_refresh(&l_uuid);
1997         if(ret==0) {
1998                 rpc->fault(ctx, 404, "Record not found");
1999                 return;
2000         } else if(ret<0) {
2001                 rpc->fault(ctx, 500, "Failed to refresh record - check log messages");
2002                 return;
2003         }
2004 }
2005
2006 static const char* rpc_uac_reg_remove_doc[2] = {
2007         "Remove a record from memory.",
2008         0
2009 };
2010
2011 static void rpc_uac_reg_remove(rpc_t* rpc, void* ctx)
2012 {
2013         int ret;
2014         str l_uuid;
2015         reg_uac_t *reg;
2016
2017         if(rpc->scan(ctx, "S", &l_uuid)<1)
2018         {
2019                 rpc->fault(ctx, 400, "Invalid Parameters");
2020                 return;
2021         }
2022         reg = reg_ht_get_byuuid(&l_uuid);
2023         if (!reg) {
2024                 rpc->fault(ctx, 404, "Record not found");
2025                 return;
2026         }
2027
2028         ret = reg_ht_rm(reg);
2029         if(ret<0) {
2030                 rpc->fault(ctx, 500, "Failed to remove record - check log messages");
2031                 return;
2032         }
2033 }
2034
2035 static const char* rpc_uac_reg_add_doc[2] = {
2036         "Add a record to memory.",
2037         0
2038 };
2039
2040 static void rpc_uac_reg_add(rpc_t* rpc, void* ctx)
2041 {
2042         int ret;
2043         reg_uac_t reg;
2044         reg_uac_t *cur_reg;
2045
2046         if(rpc->scan(ctx, "SSSSSSSSSdddS",
2047                                 &reg.l_uuid,
2048                                 &reg.l_username,
2049                                 &reg.l_domain,
2050                                 &reg.r_username,
2051                                 &reg.r_domain,
2052                                 &reg.realm,
2053                                 &reg.auth_username,
2054                                 &reg.auth_password,
2055                                 &reg.auth_proxy,
2056                                 &reg.expires,
2057                                 &reg.flags,
2058                                 &reg.reg_delay,
2059                                 &reg.socket
2060                         )<1)
2061         {
2062                 rpc->fault(ctx, 400, "Invalid Parameters");
2063                 return;
2064         }
2065
2066         cur_reg = reg_ht_get_byuuid(&reg.l_uuid);
2067         if (cur_reg) {
2068                 lock_release(cur_reg->lock);
2069                 rpc->fault(ctx, 409, "uuid already exists");
2070                 return;
2071         }
2072
2073         ret = reg_ht_add(&reg);
2074         if(ret<0) {
2075                 rpc->fault(ctx, 500, "Failed to add record - check log messages");
2076                 return;
2077         }
2078 }
2079
2080
2081 static const char* rpc_uac_reg_active_doc[2] = {
2082         "Set remote registration active or inactive for all records.",
2083         0
2084 };
2085
2086 static void rpc_uac_reg_active(rpc_t* rpc, void* ctx)
2087 {
2088         int omode;
2089         int nmode;
2090         void* th;
2091
2092         if(reg_active==NULL) {
2093                 rpc->fault(ctx, 500, "Not initialized");
2094                 return;
2095         }
2096         if(rpc->scan(ctx, "d", &nmode)<1) {
2097                 LM_ERR("missing parameter");
2098                 rpc->fault(ctx, 500, "Missing parameter");
2099                 return;
2100         }
2101         omode = *reg_active;
2102         *reg_active = (nmode)?1:0;
2103
2104         /* add entry node */
2105         if (rpc->add(ctx, "{", &th) < 0) {
2106                 rpc->fault(ctx, 500, "Internal error creating rpc struct");
2107                 return;
2108         }
2109         if(rpc->struct_add(th, "dd", "omode", omode, "nmode", nmode)<0) {
2110                 rpc->fault(ctx, 500, "Internal error creating response");
2111                 return;
2112         }
2113 }
2114
2115 rpc_export_t uac_reg_rpc[] = {
2116         {"uac.reg_dump", rpc_uac_reg_dump, rpc_uac_reg_dump_doc, RET_ARRAY},
2117         {"uac.reg_info", rpc_uac_reg_info, rpc_uac_reg_info_doc, 0},
2118         {"uac.reg_enable",  rpc_uac_reg_enable,  rpc_uac_reg_enable_doc,  0},
2119         {"uac.reg_disable", rpc_uac_reg_disable, rpc_uac_reg_disable_doc, 0},
2120         {"uac.reg_reload",  rpc_uac_reg_reload,  rpc_uac_reg_reload_doc,  0},
2121         {"uac.reg_refresh", rpc_uac_reg_refresh, rpc_uac_reg_refresh_doc, 0},
2122         {"uac.reg_remove", rpc_uac_reg_remove, rpc_uac_reg_remove_doc, 0},
2123         {"uac.reg_add", rpc_uac_reg_add, rpc_uac_reg_add_doc, 0},
2124         {"uac.reg_active", rpc_uac_reg_active, rpc_uac_reg_active_doc, 0},
2125         {0, 0, 0, 0}
2126 };
2127
2128 int uac_reg_init_rpc(void)
2129 {
2130         if (rpc_register_array(uac_reg_rpc)!=0)
2131         {
2132                 LM_ERR("failed to register RPC commands\n");
2133                 return -1;
2134         }
2135         return 0;
2136 }