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