all: updated FSF address in GPL text
[sip-router] / modules / registrar / regpv.c
1 /*
2  * $Id$
3  *
4  * Export vontact attrs as PV
5  *
6  * Copyright (C) 2008 Daniel-Constantin Mierla (asipto.com)
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  */
24
25 /*!
26  * \file
27  * \brief SIP registrar module - export contacts as PV
28  * \ingroup registrar   
29  */  
30
31
32 #include <string.h>
33 #include "../../dprint.h"
34 #include "../../mem/mem.h"
35 #include "../../mod_fix.h"
36 #include "../../route.h"
37 #include "../../action.h"
38 #include "../../lib/kcore/faked_msg.h"
39 #include "../usrloc/usrloc.h"
40 #include "reg_mod.h"
41 #include "common.h"
42 #include "regpv.h"
43
44 typedef struct _regpv_profile {
45         str pname;
46         str domain;
47         str aor;
48         int flags;
49         unsigned int aorhash;
50         int nrc;
51         ucontact_t* contacts;
52         struct _regpv_profile *next;
53 } regpv_profile_t;
54
55 typedef struct _regpv_name {
56         regpv_profile_t *rp;
57         int attr;
58 } regpv_name_t;
59
60 static regpv_profile_t *_regpv_profile_list = NULL;
61
62 static inline regpv_profile_t* regpv_get_profile(str *name)
63 {
64         regpv_profile_t *rp;
65
66         if(name==NULL || name->len<=0)
67         {
68                 LM_ERR("invalid parameters\n");
69                 return NULL;
70         }
71
72         rp = _regpv_profile_list;
73         while(rp)
74         {
75                 if(rp->pname.len == name->len
76                                 && strncmp(rp->pname.s, name->s, name->len)==0)
77                         return rp;
78                 rp = rp->next;
79         }
80
81         rp = (regpv_profile_t*)pkg_malloc(sizeof(regpv_profile_t));
82         if(rp==NULL)
83         {
84                 LM_ERR("no more pkg\n");
85                 return NULL;
86         }
87         memset(rp, 0, sizeof(regpv_profile_t));
88         rp->pname.s = (char*)pkg_malloc((name->len+1)*sizeof(char));
89         if(rp->pname.s==NULL)
90         {
91                 LM_ERR("no more pkg\n");
92                 pkg_free(rp);
93                 return NULL;
94         }
95         memcpy(rp->pname.s, name->s, name->len);
96         rp->pname.s[name->len] = '\0';
97         rp->pname.len = name->len;
98
99         rp->next = _regpv_profile_list;
100         _regpv_profile_list = rp;
101         return rp;
102 }
103
104 static void regpv_free_profile(regpv_profile_t *rpp)
105 {
106         ucontact_t* ptr;
107         ucontact_t* ptr0;
108
109         if(rpp==NULL)
110                 return;
111
112         ptr = rpp->contacts;
113         while(ptr)
114         {
115                 ptr0 = ptr;
116                 ptr = ptr->next;
117                 pkg_free(ptr0);
118         }
119         if(rpp->domain.s!=NULL)
120         {
121                 rpp->domain.s = 0;
122                 rpp->domain.len = 0;
123         }
124         if(rpp->aor.s!=NULL)
125         {
126                 pkg_free(rpp->aor.s);
127                 rpp->aor.s = 0;
128                 rpp->aor.len = 0;
129         }
130
131         rpp->flags = 0;
132         rpp->aorhash = 0;
133         rpp->nrc = 0;
134         rpp->contacts = 0;
135
136 }
137
138 void regpv_free_profiles(void)
139 {
140         regpv_profile_t *rp;
141         regpv_profile_t *rp0;
142
143         rp = _regpv_profile_list;
144
145         while(rp)
146         {
147                 if(rp->pname.s!=NULL)
148                         pkg_free(rp->pname.s);
149                 rp0 = rp;
150                 regpv_free_profile(rp0);
151                 rp = rp->next;
152         }
153         _regpv_profile_list = 0;
154 }
155
156 int pv_get_ulc(struct sip_msg *msg,  pv_param_t *param,
157                 pv_value_t *res)
158 {
159         regpv_name_t *rp;
160         regpv_profile_t *rpp;
161         ucontact_t *c;
162         int idx;
163         int i;
164
165         if(param==NULL)
166         {
167                 LM_ERR("invalid params\n");
168                 return -1;
169         }
170         rp = (regpv_name_t*)param->pvn.u.dname;
171         if(rp==NULL || rp->rp==NULL)
172         {
173                 LM_DBG("no profile in params\n");
174                 return pv_get_null(msg, param, res);
175         }
176         rpp = rp->rp;
177
178         if(rpp->flags==0 || rpp->contacts==NULL)
179         {
180                 LM_DBG("profile not set or no contacts there\n");
181                 return pv_get_null(msg, param, res);
182         }
183         /* get index */
184         if(pv_get_spec_index(msg, param, &idx, &i)!=0)
185         {
186                 LM_ERR("invalid index\n");
187                 return -1;
188         }
189
190         /* work only with positive indexes by now */
191         if(idx<0)
192                 idx = 0;
193
194         /* get contact */
195         i = 0;
196         c = rpp->contacts;
197         while(rpp)
198         {
199                 if(i == idx)
200                         break;
201                 i++;
202                 c = c->next;
203         }
204         if(c==NULL)
205                 return pv_get_null(msg, param, res);
206
207         switch(rp->attr)
208         {
209                 case 0: /* aor */
210                         return  pv_get_strval(msg, param, res, &rpp->aor);
211                 break;
212                 case 1: /* domain */
213                         return  pv_get_strval(msg, param, res, &rpp->domain);
214                 break;
215                 case 2: /* aorhash */
216                         return pv_get_uintval(msg, param, res, rpp->aorhash);
217                 break;
218                 case 3: /* addr */
219                         return  pv_get_strval(msg, param, res, &c->c);
220                 break;
221                 case 4: /* path */
222                         return  pv_get_strval(msg, param, res, &c->path);
223                 break;
224                 case 5: /* received */
225                         return  pv_get_strval(msg, param, res, &c->received);
226                 break;
227                 case 6: /* expires */
228                         return pv_get_uintval(msg, param, res,
229                                         (unsigned int)c->expires);
230                 break;
231                 case 7: /* callid */
232                         return  pv_get_strval(msg, param, res, &c->callid);
233                 break;
234                 case 8: /* q */
235                         return pv_get_sintval(msg, param, res, (int)c->q);
236                 break;
237                 case 9: /* cseq */
238                         return pv_get_sintval(msg, param, res, c->cseq);
239                 break;
240                 case 10: /* flags */
241                         return pv_get_uintval(msg, param, res, c->flags);
242                 break;
243                 case 11: /* cflags */
244                         return pv_get_uintval(msg, param, res, c->cflags);
245                 break;
246                 case 12: /* user agent */
247                         return  pv_get_strval(msg, param, res, &c->user_agent);
248                 break;
249                 case 14: /* socket */
250                         if(c->sock==NULL)
251                                 return pv_get_null(msg, param, res);
252                         return pv_get_strval(msg, param, res, &c->sock->sock_str);
253                 break;
254                 case 15: /* modified */
255                         return pv_get_uintval(msg, param, res,
256                                         (unsigned int)c->last_modified);
257                 break;
258                 case 16: /* methods */
259                         return pv_get_uintval(msg, param, res, c->methods);
260                 break;
261                 case 17: /* count */
262                         return pv_get_sintval(msg, param, res, rpp->nrc);
263                 break;
264                 case 18: /* ruid */
265                         return  pv_get_strval(msg, param, res, &c->ruid);
266                 break;
267                 case 19: /* reg-id */
268                         return pv_get_uintval(msg, param, res, c->reg_id);
269                 break;
270                 case 20: /* instance */
271                         if(c->instance.len>0)
272                                 return  pv_get_strval(msg, param, res, &c->instance);
273                 break;
274         }
275
276         return pv_get_null(msg, param, res);
277 }
278
279 int pv_set_ulc(struct sip_msg* msg, pv_param_t *param,
280                 int op, pv_value_t *val)
281 {
282         return 0;
283 }
284
285 int pv_parse_ulc_name(pv_spec_p sp, str *in)
286 {
287         str pn;
288         str pa;
289         regpv_name_t *rp;
290         regpv_profile_t *rpp;
291
292         if(sp==NULL || in==NULL || in->len<=0)
293                 return -1;
294
295         pa.s = in->s;
296         while(pa.s < in->s + in->len - 2)
297         {
298                 if(*pa.s=='=')
299                         break;
300                 pa.s++;
301         }
302         
303         if(pa.s >= in->s + in->len - 2)
304         {
305                 LM_ERR("invalid contact pv name %.*s\n", in->len, in->s);
306                 return -1;
307         }
308         if(*(pa.s+1) != '>')
309         {
310                 LM_ERR("invalid contact pv name %.*s.\n", in->len, in->s);
311                 return -1;
312         }
313
314         pn.s = in->s;
315         pn.len = pa.s - pn.s;
316
317         LM_DBG("get profile [%.*s]\n", pn.len, pn.s);
318
319         rpp = regpv_get_profile(&pn);
320         if(rpp==NULL)
321         {
322                 LM_ERR("cannot get profile [%.*s]\n", pn.len, pn.s);
323                 return -1;
324         }
325         pa.s += 2;
326         pa.len = in->s + in->len - pa.s;
327         LM_DBG("get attr [%.*s]\n", pa.len, pa.s);
328
329         rp = (regpv_name_t*)pkg_malloc(sizeof(regpv_name_t));
330         if(rp==0)
331         {
332                 LM_ERR("no more pkg\n");
333                 return -1;
334         }
335         memset(rp, 0, sizeof(regpv_name_t));
336         rp->rp = rpp;
337
338         switch(pa.len)
339         {
340                 case 1: 
341                         if(strncmp(pa.s, "q", 1)==0)
342                                 rp->attr = 8;
343                         else goto error;
344                 break;
345                 case 3: 
346                         if(strncmp(pa.s, "aor", 3)==0)
347                                 rp->attr = 0;
348                         else goto error;
349                 break;
350                 case 4: 
351                         if(strncmp(pa.s, "addr", 4)==0)
352                                 rp->attr = 3;
353                         else if(strncmp(pa.s, "path", 4)==0)
354                                 rp->attr = 4;
355                         else if(strncmp(pa.s, "cseq", 4)==0)
356                                 rp->attr = 9;
357                         else if(strncmp(pa.s, "ruid", 4)==0)
358                                 rp->attr = 18;
359                         else goto error;
360                 break;
361                 case 5: 
362                         if(strncmp(pa.s, "flags", 5)==0)
363                                 rp->attr = 10;
364                         else if(strncmp(pa.s, "count", 5)==0)
365                                 rp->attr = 17;
366                         else if(strncmp(pa.s, "regid", 5)==0)
367                                 rp->attr = 19;
368                         else goto error;
369                 break;
370                 case 6: 
371                         if(strncmp(pa.s, "domain", 6)==0)
372                                 rp->attr = 1;
373                         else if(strncmp(pa.s, "callid", 6)==0)
374                                 rp->attr = 7;
375                         else if(strncmp(pa.s, "cflags", 6)==0)
376                                 rp->attr = 11;
377                         else if(strncmp(pa.s, "socket", 6)==0)
378                                 rp->attr = 14;
379                         else goto error;
380                 break;
381                 case 7: 
382                         if(strncmp(pa.s, "aorhash", 7)==0)
383                                 rp->attr = 2;
384                         else if(strncmp(pa.s, "expires", 7)==0)
385                                 rp->attr = 6;
386                         else if(strncmp(pa.s, "methods", 7)==0)
387                                 rp->attr = 16;
388                         else goto error;
389                 break;
390                 case 8: 
391                         if(strncmp(pa.s, "received", 8)==0)
392                                 rp->attr = 5;
393                         else if(strncmp(pa.s, "modified", 8)==0)
394                                 rp->attr = 15;
395                         else if(strncmp(pa.s, "instance", 8)==0)
396                                 rp->attr = 20;
397                         else goto error;
398                 break;
399                 case 10: 
400                         if(strncmp(pa.s, "user_agent", 10)==0)
401                                 rp->attr = 12;
402                         else goto error;
403                 break;
404                 default:
405                         goto error;
406         }
407         sp->pvp.pvn.u.dname = (void*)rp;
408         sp->pvp.pvn.type = PV_NAME_PVAR;
409
410         return 0;
411
412 error:
413         LM_ERR("unknown contact attr name in %.*s\n", in->len, in->s);
414         return -1;
415 }
416
417 int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri,
418                 char* profile)
419 {
420         urecord_t* r;
421         ucontact_t* ptr;
422         ucontact_t* ptr0;
423         ucontact_t* c0;
424         regpv_profile_t *rpp;
425         str aor = {0, 0};
426         str u = {0, 0};
427         int res;
428         int olen;
429         int ilen;
430         int n;
431         char *p;
432
433         rpp = regpv_get_profile((str*)profile);
434         if(rpp==0)
435         {
436                 LM_ERR("invalid parameters\n");
437                 return -1;
438         }
439
440         /* check and free if profile already set */
441         if(rpp->flags)
442                 regpv_free_profile(rpp);
443
444         if(fixup_get_svalue(msg, (gparam_p)uri, &u)!=0 || u.len<=0)
445         {
446                 LM_ERR("invalid uri parameter\n");
447                 return -1;
448         }
449
450         if (extract_aor(&u, &aor, NULL) < 0) {
451                 LM_ERR("failed to extract Address Of Record\n");
452                 return -1;
453         }
454
455         /* copy aor and ul domain */
456         rpp->aor.s = (char*)pkg_malloc(aor.len*sizeof(char));
457         if(rpp->aor.s==NULL)
458         {
459                 LM_ERR("no more pkg\n");
460                 return -1;
461         }
462         memcpy(rpp->aor.s, aor.s, aor.len);
463         rpp->aor.len = aor.len;
464         rpp->domain = *((udomain_head_t*)table)->name;
465         rpp->flags = 1;
466
467         /* copy contacts */
468         ilen = sizeof(ucontact_t);
469         ul.lock_udomain((udomain_t*)table, &aor);
470         res = ul.get_urecord((udomain_t*)table, &aor, &r);
471         if (res > 0) {
472                 LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
473                 ul.unlock_udomain((udomain_t*)table, &aor);
474                 return -1;
475         }
476
477         ptr = r->contacts;
478         ptr0 = NULL;
479         n = 0;
480         while(ptr)
481         {
482                 olen = (ptr->c.len + ptr->received.len + ptr->path.len
483                         + ptr->callid.len + ptr->user_agent.len + ptr->ruid.len
484                         + ptr->instance.len)*sizeof(char) + ilen;
485                 c0 = (ucontact_t*)pkg_malloc(olen);
486                 if(c0==NULL)
487                 {
488                         LM_ERR("no more pkg\n");
489                         ul.release_urecord(r);
490                         ul.unlock_udomain((udomain_t*)table, &aor);
491                         goto error;
492                 }
493                 memcpy(c0, ptr, ilen);
494                 c0->domain = NULL;
495                 c0->aor = NULL;
496                 c0->next = NULL;
497                 c0->prev = NULL;
498
499                 c0->c.s = (char*)c0 + ilen;
500                 memcpy(c0->c.s, ptr->c.s, ptr->c.len);
501                 c0->c.len = ptr->c.len;
502                 p = c0->c.s + c0->c.len;
503                 
504                 if(ptr->received.s!=NULL)
505                 {
506                         c0->received.s = p;
507                         memcpy(c0->received.s, ptr->received.s, ptr->received.len);
508                         c0->received.len = ptr->received.len;
509                         p += c0->received.len;
510                 }
511                 if(ptr->path.s!=NULL)
512                 {
513                         c0->path.s = p;
514                         memcpy(c0->path.s, ptr->path.s, ptr->path.len);
515                         c0->path.len = ptr->path.len;
516                         p += c0->path.len;
517                 }
518                 c0->callid.s = p;
519                 memcpy(c0->callid.s, ptr->callid.s, ptr->callid.len);
520                 c0->callid.len = ptr->callid.len;
521                 p += c0->callid.len;
522                 if(ptr->user_agent.s!=NULL)
523                 {
524                         c0->user_agent.s = p;
525                         memcpy(c0->user_agent.s, ptr->user_agent.s, ptr->user_agent.len);
526                         c0->user_agent.len = ptr->user_agent.len;
527                         p += c0->user_agent.len;
528                 }
529                 if(ptr->ruid.s!=NULL)
530                 {
531                         c0->ruid.s = p;
532                         memcpy(c0->ruid.s, ptr->ruid.s, ptr->ruid.len);
533                         c0->ruid.len = ptr->ruid.len;
534                         p += c0->ruid.len;
535                 }
536                 if(ptr->instance.s!=NULL)
537                 {
538                         c0->instance.s = p;
539                         memcpy(c0->instance.s, ptr->instance.s, ptr->instance.len);
540                         c0->instance.len = ptr->instance.len;
541                         p += c0->instance.len;
542                 }
543
544                 if(ptr0==NULL)
545                 {
546                         rpp->contacts = c0;
547                 } else {
548                         ptr0->next = c0;
549                         c0->prev = ptr0;
550                 }
551                 n++;
552                 ptr0 = c0;
553                 ptr = ptr->next;
554         }
555         ul.release_urecord(r);
556         ul.unlock_udomain((udomain_t*)table, &aor);
557         rpp->nrc = n;
558         LM_DBG("fetched <%d> contacts for <%.*s> in [%.*s]\n",
559                         n, aor.len, aor.s, rpp->pname.len, rpp->pname.s);
560         return 1;
561
562 error:
563         regpv_free_profile(rpp);
564         return -1;
565 }
566 int pv_free_contacts(struct sip_msg* msg, char* profile, char* s2)
567 {
568         regpv_profile_t *rpp;
569
570         rpp = regpv_get_profile((str*)profile);
571         if(rpp==0)
572                 return -1;
573
574         regpv_free_profile(rpp);
575
576         return 1;
577 }
578
579 void reg_ul_expired_contact(ucontact_t* ptr, int type, void* param)
580 {
581         str profile = {"exp", 3};
582         regpv_profile_t *rpp;
583         ucontact_t* c0;
584         int backup_rt;
585         struct run_act_ctx ctx;
586         sip_msg_t *fmsg;
587         int olen;
588         int ilen;
589         char *p;
590
591         if(reg_expire_event_rt<0)
592                 return;
593
594         if (faked_msg_init() < 0)
595         {
596                 LM_ERR("faked_msg_init() failed\n");
597                 return;
598         }
599
600         rpp = regpv_get_profile(&profile);
601         if(rpp==0)
602         {
603                 LM_ERR("error getting profile structure\n");
604                 return;
605         }
606         /* check and free if profile already set */
607         if(rpp->flags)
608                 regpv_free_profile(rpp);
609
610         /* copy aor and ul domain */
611         rpp->aor.s = (char*)pkg_malloc(ptr->aor->len*sizeof(char));
612         if(rpp->aor.s==NULL)
613         {
614                 LM_ERR("no more pkg\n");
615                 return;
616         }
617         memcpy(rpp->aor.s, ptr->aor->s, ptr->aor->len);
618         rpp->aor.len = ptr->aor->len;
619         rpp->domain = *ptr->domain;
620         rpp->flags = 1;
621
622         /* copy contact */
623         ilen = sizeof(ucontact_t);
624
625         olen = (ptr->c.len + ptr->received.len + ptr->path.len
626                         + ptr->callid.len + ptr->user_agent.len + ptr->ruid.len
627                         + ptr->instance.len)*sizeof(char) + ilen;
628         c0 = (ucontact_t*)pkg_malloc(olen);
629         if(c0==NULL)
630         {
631                 LM_ERR("no more pkg\n");
632                 goto error;
633         }
634         memcpy(c0, ptr, ilen);
635         c0->domain = NULL;
636         c0->aor = NULL;
637         c0->next = NULL;
638         c0->prev = NULL;
639
640         c0->c.s = (char*)c0 + ilen;
641         memcpy(c0->c.s, ptr->c.s, ptr->c.len);
642         c0->c.len = ptr->c.len;
643         p = c0->c.s + c0->c.len;
644
645         if(ptr->received.s!=NULL)
646         {
647                 c0->received.s = p;
648                 memcpy(c0->received.s, ptr->received.s, ptr->received.len);
649                 c0->received.len = ptr->received.len;
650                 p += c0->received.len;
651         }
652         if(ptr->path.s!=NULL)
653         {
654                 c0->path.s = p;
655                 memcpy(c0->path.s, ptr->path.s, ptr->path.len);
656                 c0->path.len = ptr->path.len;
657                 p += c0->path.len;
658         }
659         c0->callid.s = p;
660         memcpy(c0->callid.s, ptr->callid.s, ptr->callid.len);
661         c0->callid.len = ptr->callid.len;
662         p += c0->callid.len;
663         if(ptr->user_agent.s!=NULL)
664         {
665                 c0->user_agent.s = p;
666                 memcpy(c0->user_agent.s, ptr->user_agent.s, ptr->user_agent.len);
667                 c0->user_agent.len = ptr->user_agent.len;
668                 p += c0->user_agent.len;
669         }
670         if(ptr->ruid.s!=NULL)
671         {
672                 c0->ruid.s = p;
673                 memcpy(c0->ruid.s, ptr->ruid.s, ptr->ruid.len);
674                 c0->ruid.len = ptr->ruid.len;
675                 p += c0->ruid.len;
676         }
677         if(ptr->instance.s!=NULL)
678         {
679                 c0->instance.s = p;
680                 memcpy(c0->instance.s, ptr->instance.s, ptr->instance.len);
681                 c0->instance.len = ptr->instance.len;
682                 p += c0->instance.len;
683         }
684
685         rpp->contacts = c0;
686         rpp->nrc = 1;
687         LM_DBG("saved contact for <%.*s> in [%.*s]\n",
688                         ptr->aor->len, ptr->aor->s, rpp->pname.len, rpp->pname.s);
689
690         fmsg = faked_msg_next();
691         backup_rt = get_route_type();
692         set_route_type(REQUEST_ROUTE);
693         init_run_actions_ctx(&ctx);
694         run_top_route(event_rt.rlist[reg_expire_event_rt], fmsg, 0);
695         set_route_type(backup_rt);
696
697         return;
698 error:
699         regpv_free_profile(rpp);
700         return;
701 }