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