ipops: replace return with goto error to release resources
[sip-router] / src / modules / ipops / ipops_pv.c
1 /**
2  * $Id$
3  *
4  * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * This file is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  *
14  * This file is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25
26 #include <assert.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <netdb.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
33
34 #include "../../core/dprint.h"
35 #include "../../core/rand/fastrand.h"
36 #include "../../core/hashes.h"
37 #include "../../core/resolve.h"
38 #include "../../core/pvar.h"
39
40
41 #define PV_DNS_ADDR 64
42 #define PV_DNS_RECS 32
43
44 typedef struct _sr_dns_record {
45         int type;
46         char addr[PV_DNS_ADDR];
47 } sr_dns_record_t;
48
49 typedef struct _sr_dns_item {
50         str name;
51         unsigned int hashid;
52         char hostname[256];
53         int count;
54         int ipv4;
55         int ipv6;
56         sr_dns_record_t r[PV_DNS_RECS];
57         struct _sr_dns_item *next;
58 } sr_dns_item_t;
59
60 #define SR_DNS_PVIDX    1
61
62 typedef struct _dns_pv {
63         sr_dns_item_t *item;
64         int type;
65         int flags;
66         pv_spec_t *pidx;
67         int nidx;
68 } dns_pv_t;
69
70 static sr_dns_item_t *_sr_dns_list = NULL;
71
72 /**
73  *
74  */
75 sr_dns_item_t *sr_dns_get_item(str *name)
76 {
77         sr_dns_item_t *it = NULL;
78         unsigned int hashid = 0;
79
80         hashid =  get_hash1_raw(name->s, name->len);
81
82         it = _sr_dns_list;
83         while(it!=NULL)
84         {
85                 if(it->hashid==hashid && it->name.len == name->len
86                                 && strncmp(it->name.s, name->s, name->len)==0)
87                         return it;
88                 it = it->next;
89         }
90         return NULL;
91 }
92
93 /**
94  *
95  */
96 sr_dns_item_t *sr_dns_add_item(str *name)
97 {
98         sr_dns_item_t *it = NULL;
99         unsigned int hashid = 0;
100
101         hashid =  get_hash1_raw(name->s, name->len);
102
103         it = _sr_dns_list;
104         while(it!=NULL)
105         {
106                 if(it->hashid==hashid && it->name.len == name->len
107                                 && strncmp(it->name.s, name->s, name->len)==0)
108                         return it;
109                 it = it->next;
110         }
111         /* add new */
112         it = (sr_dns_item_t*)pkg_malloc(sizeof(sr_dns_item_t));
113         if(it==NULL)
114         {
115                 LM_ERR("no more pkg\n");
116                 return NULL;
117         }
118         memset(it, 0, sizeof(sr_dns_item_t));
119         it->name.s = (char*)pkg_malloc(name->len+1);
120         if(it->name.s==NULL)
121         {
122                 LM_ERR("no more pkg.\n");
123                 pkg_free(it);
124                 return NULL;
125         }
126         memcpy(it->name.s, name->s, name->len);
127         it->name.s[name->len] = '\0';
128         it->name.len = name->len;
129         it->hashid = hashid;
130         it->next = _sr_dns_list;
131         _sr_dns_list = it;
132         return it;
133 }
134
135 /**
136  *
137  */
138 int pv_parse_dns_name(pv_spec_t *sp, str *in)
139 {
140         dns_pv_t *dpv=NULL;
141         char *p;
142         str pvc;
143         str pvs;
144         str pvi;
145         int sign;
146
147         if(sp==NULL || in==NULL || in->len<=0)
148                 return -1;
149
150         dpv = (dns_pv_t*)pkg_malloc(sizeof(dns_pv_t));
151         if(dpv==NULL)
152                 return -1;
153
154         memset(dpv, 0, sizeof(dns_pv_t));
155
156         p = in->s;
157
158         while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
159                 p++;
160         if(p>in->s+in->len || *p=='\0')
161                 goto error;
162         pvc.s = p;
163         while(p < in->s + in->len)
164         {
165                 if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
166                         break;
167                 p++;
168         }
169         if(p>in->s+in->len || *p=='\0')
170                 goto error;
171         pvc.len = p - pvc.s;
172         if(*p!='=')
173         {
174                 while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
175                         p++;
176                 if(p>in->s+in->len || *p=='\0' || *p!='=')
177                         goto error;
178         }
179         p++;
180         if(*p!='>')
181                 goto error;
182         p++;
183
184         pvs.len = in->len - (int)(p - in->s);
185         pvs.s = p;
186         pvi.s = 0;
187         pvi.len = 0;
188         if(pvs.s[pvs.len-1]==']') {
189                 /* index */
190                 p = memchr(pvs.s, '[', pvs.len-1);
191                 if(p==NULL) {
192                         goto error;
193                 }
194                 pvi.s = p + 1;
195                 pvi.len = pvs.s + pvs.len - pvi.s;
196                 pvs.len = p - pvs.s;
197         }
198         LM_DBG("dns [%.*s] - key [%.*s] index [%.*s]\n", pvc.len, pvc.s,
199                         pvs.len, pvs.s, (pvi.len>0)?pvi.len:0, (pvi.s!=NULL)?pvi.s:0);
200
201         dpv->item = sr_dns_add_item(&pvc);
202         if(dpv->item==NULL)
203                 goto error;
204
205         switch(pvs.len)
206         {
207                 case 4: 
208                         if(strncmp(pvs.s, "addr", 4)==0)
209                                 dpv->type = 0;
210                         else if(strncmp(pvs.s, "type", 4)==0)
211                                 dpv->type = 1;
212                         else if(strncmp(pvs.s, "ipv4", 4)==0)
213                                 dpv->type = 2;
214                         else if(strncmp(pvs.s, "ipv6", 4)==0)
215                                 dpv->type = 3;
216                         else goto error;
217                         break;
218                 case 5: 
219                         if(strncmp(pvs.s, "count", 5)==0)
220                                 dpv->type = 4;
221                         else goto error;
222                         break;
223                 default:
224                         goto error;
225         }
226
227         if(pvi.len>0)
228         {
229                 if(pvi.s[0]==PV_MARKER)
230                 {
231                         dpv->pidx = pv_cache_get(&pvi);
232                         if(dpv->pidx==NULL)
233                                 goto error;
234                         dpv->flags |= SR_DNS_PVIDX;
235                 } else {
236                         sign = 1;
237                         p = pvi.s;
238                         if(*p=='-')
239                         {
240                                 sign = -1;
241                                 p++;
242                         }
243                         dpv->nidx = 0;
244                         while(p<pvi.s+pvi.len && *p>='0' && *p<='9')
245                         {
246                                 dpv->nidx = dpv->nidx * 10 + *p - '0';
247                                 p++;
248                         }
249                         if(p!=pvi.s+pvi.len)
250                         {
251                                 LM_ERR("invalid index [%.*s]\n", in->len, in->s);
252                                 goto error;
253                         }
254                         dpv->nidx *= sign;
255                 }
256         }
257         sp->pvp.pvn.u.dname = (void*)dpv;
258         sp->pvp.pvn.type = PV_NAME_OTHER;
259
260         return 0;
261
262 error:
263         LM_ERR("error at PV dns name: %.*s\n", in->len, in->s);
264         if(dpv) pkg_free(dpv);
265         return -1;
266 }
267
268 /**
269  *
270  */
271 int pv_get_dns(sip_msg_t *msg, pv_param_t *param,
272                 pv_value_t *res)
273 {
274         dns_pv_t *dpv;
275         pv_value_t val;
276
277         if(msg==NULL || param==NULL)
278                 return -1;
279
280         dpv = (dns_pv_t*)param->pvn.u.dname;
281         if(dpv==NULL || dpv->item==NULL)
282                 return -1;
283
284         if(dpv->pidx!=NULL)
285         {
286                 if(pv_get_spec_value(msg, dpv->pidx, &val)<0
287                                 || (!(val.flags&PV_VAL_INT)))
288                 {
289                         LM_ERR("failed to evaluate index variable\n");
290                         return pv_get_null(msg, param, res);
291                 }
292         } else {
293                 val.ri = dpv->nidx;
294         }
295         if(val.ri<0)
296         {
297                 if(dpv->item->count+val.ri<0) {
298                         return pv_get_null(msg, param, res);
299                 }
300                 val.ri = dpv->item->count+val.ri;
301         }
302         if(val.ri>=dpv->item->count) {
303                 return pv_get_null(msg, param, res);
304         }
305         switch(dpv->type)
306         {
307                 case 0: /* address */
308                         return pv_get_strzval(msg, param, res,
309                                         dpv->item->r[val.ri].addr);
310                 case 1: /* type */
311                         return pv_get_sintval(msg, param, res,
312                                         dpv->item->r[val.ri].type);
313                 case 2: /* ipv4 */
314                         return pv_get_sintval(msg, param, res,
315                                         dpv->item->ipv4);
316                 case 3: /* ipv6 */
317                         return pv_get_sintval(msg, param, res,
318                                         dpv->item->ipv6);
319                 case 4: /* count */
320                         return pv_get_sintval(msg, param, res,
321                                         dpv->item->count);
322                 default: /* else */
323                         return pv_get_null(msg, param, res);
324         }
325 }
326
327 /**
328  *
329  */
330 int dns_init_pv(char *path)
331 {
332         return 0;
333 }
334
335 /**
336  *
337  */
338 void dns_destroy_list(void)
339 {
340         return;
341 }
342
343 /**
344  *
345  */
346 void dns_destroy_pv(void)
347 {
348         return;
349 }
350
351 /**
352  *
353  */
354 int dns_update_pv(str *hostname, str *name)
355 {
356         sr_dns_item_t *dr = NULL;
357         struct addrinfo hints, *res, *p;
358         struct sockaddr_in *ipv4;
359         struct sockaddr_in6 *ipv6;
360         void *addr;
361         int status;
362         int i;
363
364         if(hostname->len>255)
365         {
366                 LM_DBG("target hostname too long (max 255): %s\n", hostname->s);
367                 return -2;
368         }
369
370         dr = sr_dns_get_item(name);
371         if(dr==NULL)
372         {
373                 LM_DBG("container not found: %s\n", name->s);
374                 return -3;
375         }
376
377         /* reset the counter */
378         dr->count = 0;
379         dr->ipv4  = 0;
380         dr->ipv6  = 0;
381
382         strncpy(dr->hostname, hostname->s, hostname->len);
383         dr->hostname[hostname->len] = '\0';
384         LM_DBG("attempting to resolve: %s\n", dr->hostname);
385
386         memset(&hints, 0, sizeof(hints));
387         hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
388         // hints.ai_socktype = SOCK_STREAM;
389         hints.ai_socktype = SOCK_DGRAM;
390
391         if ((status = getaddrinfo(dr->hostname, NULL, &hints, &res)) != 0)
392         {
393                 LM_ERR("unable to resolve %s - getaddrinfo: %s\n",
394                                 dr->hostname, gai_strerror(status));
395                 return -4;
396         }
397
398         i=0;
399         for(p=res; p!=NULL; p=p->ai_next)
400         {
401                 if (p->ai_family==AF_INET)
402                 {
403                         dr->ipv4 = 1;
404                         dr->r[i].type = 4;
405                         ipv4 = (struct sockaddr_in *)p->ai_addr;
406                         addr = &(ipv4->sin_addr);
407                 } else {
408                         dr->ipv6 = 1;
409                         dr->r[i].type = 6;
410                         ipv6 = (struct sockaddr_in6 *)p->ai_addr;
411                         addr = &(ipv6->sin6_addr);
412                 }
413                 inet_ntop(p->ai_family, addr, dr->r[i].addr,
414                                 PV_DNS_ADDR);
415                 LM_DBG("#%d - type %d addr: %s (%d)\n", i, dr->r[i].type,
416                                 dr->r[i].addr, p->ai_socktype);
417                 i++;
418                 if(i==PV_DNS_RECS) {
419                         LM_WARN("more than %d addresses for %s - truncating\n",
420                                         PV_DNS_RECS, dr->hostname);
421                         break;
422                 }
423         }
424         freeaddrinfo(res);
425
426         dr->count = i;
427
428         LM_DBG("dns PV updated for: %s (%d)\n", dr->hostname, i);
429
430         return 1;
431 }
432
433 struct _hn_pv_data {
434         str data;
435         str fullname;
436         str hostname;
437         str domain;
438         str ipaddr;
439 };
440
441 static struct _hn_pv_data *_hn_data = NULL;
442
443 /**
444  *
445  */
446 int hn_pv_data_init(void)
447 {
448         char hbuf[512];
449         int hlen;
450         char *d;
451         struct hostent *he;
452         int i;
453
454         if(_hn_data != NULL)
455                 return 0;
456
457         if (gethostname(hbuf, 512)<0) {
458                 LM_WARN("gethostname failed - host pvs will be null\n");
459                 return -1;
460         }
461
462         hlen = strlen(hbuf);
463         if(hlen<=0) {
464                 LM_WARN("empty hostname result - host pvs will be null\n");
465                 return -1;
466         }
467
468         _hn_data = (struct _hn_pv_data*)pkg_malloc(sizeof(struct _hn_pv_data)+46+2*(hlen+1));
469         if(_hn_data==NULL) {
470                 LM_ERR("no more pkg to init hostname data\n");
471                 return -1;
472         }
473         memset(_hn_data, 0, sizeof(struct _hn_pv_data)+46+2*(hlen+1));
474
475         _hn_data->data.len = hlen;
476         _hn_data->data.s = (char*)_hn_data + sizeof(struct _hn_pv_data);
477         _hn_data->fullname.len = hlen;
478         _hn_data->fullname.s = _hn_data->data.s + hlen + 1;
479
480         strcpy(_hn_data->data.s, hbuf);
481         strcpy(_hn_data->fullname.s, hbuf);
482
483         d=strchr(_hn_data->data.s, '.');
484         if (d) {
485                 _hn_data->hostname.len   = d - _hn_data->data.s;
486                 _hn_data->hostname.s     = _hn_data->data.s;
487                 _hn_data->domain.len     = _hn_data->fullname.len
488                         - _hn_data->hostname.len-1;
489                 _hn_data->domain.s       = d+1;
490         } else {
491                 _hn_data->hostname       = _hn_data->fullname;
492         }
493
494         he=resolvehost(_hn_data->fullname.s);
495         if (he) {
496                 if ((strlen(he->h_name)!=_hn_data->fullname.len)
497                                 || strncmp(he->h_name, _hn_data->fullname.s,
498                                         _hn_data->fullname.len)) {
499                         LM_WARN("hostname '%.*s' different than gethostbyname '%s'\n",
500                                         _hn_data->fullname.len, _hn_data->fullname.s, he->h_name);
501                 }
502
503                 if (he->h_addr_list) {
504                         for (i=0; he->h_addr_list[i]; i++) {
505                                 if (inet_ntop(he->h_addrtype, he->h_addr_list[i], hbuf, 46)) {
506                                         if (_hn_data->ipaddr.len==0) {
507                                                 _hn_data->ipaddr.len = strlen(hbuf);
508                                                 _hn_data->ipaddr.s = _hn_data->fullname.s + hlen + 1;
509                                                 strcpy(_hn_data->ipaddr.s, hbuf);
510                                         } else if (strncmp(_hn_data->ipaddr.s, hbuf,
511                                                                 _hn_data->ipaddr.len)!=0) {
512                                                 LM_WARN("many IPs to hostname: %s not used\n", hbuf);
513                                         }
514                                 }
515                         }
516                 } else {
517                         LM_WARN(" can't resolve hostname's address: %s\n",
518                                         _hn_data->fullname.s);
519                 }
520         }
521
522         DBG("Hostname: %.*s\n", _hn_data->hostname.len, ZSW(_hn_data->hostname.s));
523         DBG("Domain:   %.*s\n", _hn_data->domain.len, ZSW(_hn_data->domain.s));
524         DBG("Fullname: %.*s\n", _hn_data->fullname.len, ZSW(_hn_data->fullname.s));
525         DBG("IPaddr:   %.*s\n", _hn_data->ipaddr.len, ZSW(_hn_data->ipaddr.s));
526
527         return 0;
528 }
529
530 /**
531  *
532  */
533 int pv_parse_hn_name(pv_spec_p sp, str *in)
534 {
535         if(sp==NULL || in==NULL || in->len<=0)
536                 return -1;
537
538         switch(in->len)
539         {
540                 case 1: 
541                         if(strncmp(in->s, "n", 1)==0)
542                                 sp->pvp.pvn.u.isname.name.n = 0;
543                         else if(strncmp(in->s, "f", 1)==0)
544                                 sp->pvp.pvn.u.isname.name.n = 1;
545                         else if(strncmp(in->s, "d", 1)==0)
546                                 sp->pvp.pvn.u.isname.name.n = 2;
547                         else if(strncmp(in->s, "i", 1)==0)
548                                 sp->pvp.pvn.u.isname.name.n = 3;
549                         else goto error;
550                         break;
551                 default:
552                         goto error;
553         }
554         sp->pvp.pvn.type = PV_NAME_INTSTR;
555         sp->pvp.pvn.u.isname.type = 0;
556
557         hn_pv_data_init();
558
559         return 0;
560
561 error:
562         LM_ERR("unknown host PV name %.*s\n", in->len, in->s);
563         return -1;
564 }
565
566 /**
567  *
568  */
569 int pv_get_hn(struct sip_msg *msg, pv_param_t *param,
570                 pv_value_t *res)
571 {
572         if(param==NULL)
573                 return -1;
574         if(_hn_data==NULL)
575                 return pv_get_null(msg, param, res);;
576         switch(param->pvn.u.isname.name.n)
577         {
578                 case 1:
579                         if(_hn_data->fullname.len==0)
580                                 return pv_get_null(msg, param, res);;
581                         return pv_get_strval(msg, param, res, &_hn_data->fullname);
582                 case 2:
583                         if(_hn_data->domain.len==0)
584                                 return pv_get_null(msg, param, res);;
585                         return pv_get_strval(msg, param, res, &_hn_data->domain);
586                 case 3:
587                         if(_hn_data->ipaddr.len==0)
588                                 return pv_get_null(msg, param, res);;
589                         return pv_get_strval(msg, param, res, &_hn_data->ipaddr);
590                 default:
591                         if(_hn_data->hostname.len==0)
592                                 return pv_get_null(msg, param, res);;
593                         return pv_get_strval(msg, param, res, &_hn_data->hostname);
594         }
595 }
596
597 /**********
598  * srvquery PV
599  **********/
600
601 static char *srvqrylst []
602 = {"count", "port", "priority", "target", "weight", NULL};
603
604 #define PV_SRV_MAXSTR 64
605 #define PV_SRV_MAXRECS 32
606
607 typedef struct _sr_srv_record {
608         unsigned short priority;
609         unsigned short weight;
610         unsigned short port;
611         char target [PV_SRV_MAXSTR + 1];
612 } sr_srv_record_t;
613
614 typedef struct _sr_srv_item {
615         str pvid;
616         unsigned int hashid;
617         int count;
618         sr_srv_record_t rr [PV_SRV_MAXRECS];
619         struct _sr_srv_item *next;
620 } sr_srv_item_t;
621
622 typedef struct _srv_pv {
623         sr_srv_item_t *item;
624         int type;
625         int flags;
626         pv_spec_t *pidx;
627         int nidx;
628 } srv_pv_t;
629
630 static sr_srv_item_t *_sr_srv_list = NULL;
631
632 /**********
633  * Add srvquery Item
634  *
635  * INPUT:
636  *   Arg (1) = pvid string pointer
637  *   Arg (2) = find flag; <>0=search only
638  * OUTPUT: srv record pointer; NULL=not found
639  **********/
640
641 sr_srv_item_t *sr_srv_add_item (str *pvid, int findflg)
642
643 {
644         sr_srv_item_t *pitem;
645         unsigned int hashid;
646
647         /**********
648          * o get hash
649          * o already exists?
650          **********/
651
652         hashid = get_hash1_raw (pvid->s, pvid->len);
653         for (pitem = _sr_srv_list; pitem; pitem = pitem->next) {
654                 if (pitem->hashid == hashid
655                                 && pitem->pvid.len == pvid->len
656                                 && !strncmp (pitem->pvid.s, pvid->s, pvid->len))
657                         return pitem;
658         }
659         if (findflg)
660                 return NULL;
661
662         /**********
663          * o alloc/init item structure
664          * o link in new item
665          **********/
666
667         pitem = (sr_srv_item_t *) pkg_malloc (sizeof (sr_srv_item_t));
668         if (!pitem) {
669                 LM_ERR ("No more pkg memory!\n");
670                 return NULL;
671         }
672         memset (pitem, 0, sizeof (sr_srv_item_t));
673         pitem->pvid.s = (char *) pkg_malloc (pvid->len + 1);
674         if (!pitem->pvid.s) {
675                 LM_ERR ("No more pkg memory!\n");
676                 pkg_free (pitem);
677                 return NULL;
678         }
679         memcpy (pitem->pvid.s, pvid->s, pvid->len);
680         pitem->pvid.len = pvid->len;
681         pitem->hashid = hashid;
682         pitem->next = _sr_srv_list;
683         _sr_srv_list = pitem;
684         return pitem;
685 }
686
687 /**********
688  * Skip Over
689  *
690  * INPUT:
691  *   Arg (1) = string pointer
692  *   Arg (2) = starting position
693  *   Arg (3) = whitespace flag
694  * OUTPUT: position past skipped
695  **********/
696
697 int skip_over (str *pstr, int pos, int bWS)
698
699 {
700         char *pchar;
701
702         /**********
703          * o string exists?
704          * o skip over
705          **********/
706
707         if (pos >= pstr->len)
708                 return pstr->len;
709         for (pchar = &pstr->s [pos]; pos < pstr->len; pchar++, pos++) {
710                 if (*pchar == ' ' || *pchar == '\t' || *pchar == '\n' || *pchar == '\r') {
711                         if (bWS)
712                                 continue;
713                 }
714                 if ((*pchar>='A' && *pchar<='Z') || (*pchar>='a' && *pchar<='z')
715                                 || (*pchar>='0' && *pchar<='9')) {
716                         if (!bWS)
717                                 continue;
718                 }
719                 break;
720         }
721         return pos;
722 }
723
724 /**********
725  * Sort SRV Records by Weight (RFC 2782)
726  *
727  * INPUT:
728  *   Arg (1) = pointer to array of SRV records
729  *   Arg (2) = first record in range
730  *   Arg (3) = last record in range
731  * OUTPUT: position past skipped
732  **********/
733
734 void sort_weights (struct srv_rdata **plist, int pos1, int pos2)
735
736 {
737         int idx1, idx2, lastfound;
738         struct srv_rdata *wlist [PV_SRV_MAXRECS];
739         unsigned int rand, sum, sums [PV_SRV_MAXRECS];
740
741         /**********
742          * place zero weights in the unordered list and then non-zero
743          **********/
744
745         idx2 = 0;
746         for (idx1 = pos1; idx1 <= pos2; idx1++) {
747                 if (!plist [idx1]->weight) {
748                         wlist [idx2++] = plist [idx1];
749                 }
750         }
751         for (idx1 = pos1; idx1 <= pos2; idx1++) {
752                 if (plist [idx1]->weight) {
753                         wlist [idx2++] = plist [idx1];
754                 }
755         }
756
757         /**********
758          * generate running sum list
759          **********/
760
761         sum = 0;
762         for (idx1 = 0; idx1 < idx2; idx1++) {
763                 sum += wlist [idx1]->weight;
764                 sums [idx1] = sum;
765         }
766
767         /**********
768          * resort randomly
769          **********/
770
771         lastfound = 0;
772         for (idx1 = pos1; idx1 <= pos2; idx1++) {
773                 /**********
774                  * o calculate a random number in range
775                  * o find first unsorted
776                  **********/
777
778                 rand = fastrand_max (sum);
779                 for (idx2 = 0; idx2 <= pos2 - pos1; idx2++) {
780                         if (!wlist [idx2]) {
781                                 continue;
782                         }
783                         if (sums [idx2] >= rand) {
784                                 plist [idx1] = wlist [idx2];
785                                 wlist [idx2] = 0;
786                                 break;
787                         }
788                         lastfound = idx2;
789                 }
790                 if (idx2 > pos2 - pos1) {
791                         plist [idx1] = wlist [lastfound];
792                         wlist [lastfound] = 0;
793                 }
794         }
795         return;
796 }
797
798 /**********
799  * Sort SRV Records by Priority/Weight
800  *
801  * INPUT:
802  *   Arg (1) = pointer to array of SRV records
803  *   Arg (2) = record count
804  * OUTPUT: position past skipped
805  **********/
806
807 void sort_srv (struct srv_rdata **plist, int rcount)
808
809 {
810         int idx1, idx2;
811         struct srv_rdata *pswap;
812
813         /**********
814          * sort by priority
815          **********/
816
817         for (idx1 = 1; idx1 < rcount; idx1++) {
818                 pswap = plist [idx1];
819                 for (idx2 = idx1;
820                                 idx2 && (plist [idx2 - 1]->priority > pswap->priority); --idx2) {
821                         plist [idx2] = plist [idx2 - 1];
822                 }
823                 plist [idx2] = pswap;
824         }
825
826         /**********
827          * check for multiple priority
828          **********/
829
830         idx2 = 0;
831         pswap = plist [0];
832         for (idx1 = 1; idx1 < rcount; idx1++) {
833                 if ((idx1 == rcount) || (pswap->priority != plist [idx1]->priority)) {
834                         /**********
835                          * o range has more than one element?
836                          * o restart range
837                          **********/
838
839                         if (idx1 - idx2 - 1) {
840                                 sort_weights (plist, idx2, idx1 - 1);
841                         }
842                         idx2 = idx1;
843                         pswap = plist [idx2];
844                 }
845         }
846         return;
847 }
848
849 /**********
850  * Parse srvquery Name
851  *
852  * INPUT:
853  *   Arg (1) = pv spec pointer
854  *   Arg (2) = input string pointer
855  * OUTPUT: 0=success
856  **********/
857
858 int pv_parse_srv_name (pv_spec_t *sp, str *in)
859
860 {
861         char *pstr;
862         int i, pos, sign;
863         srv_pv_t *dpv;
864         str pvi = {0}, pvk = {0}, pvn = {0};
865
866         /**********
867          * o alloc/init pvid structure
868          * o extract pvid name
869          * o check separator
870          **********/
871
872         if (!sp || !in || in->len<=0)
873                 return -1;
874         dpv = (srv_pv_t *) pkg_malloc (sizeof (srv_pv_t));
875         if (!dpv) {
876                 LM_ERR ("No more pkg memory!\n");
877                 return -1;
878         }
879         memset (dpv, 0, sizeof (srv_pv_t));
880         pos = skip_over (in, 0, 1);
881         if (pos == in->len)
882                 goto error;
883         pvn.s = &in->s [pos];
884         pvn.len = pos;
885         pos = skip_over (in, pos, 0);
886         pvn.len = pos - pvn.len;
887         if (!pvn.len)
888                 goto error;
889         pos = skip_over (in, pos, 1);
890         if ((pos + 2) > in->len)
891                 goto error;
892         if (strncmp (&in->s [pos], "=>", 2))
893                 goto error;
894
895         /**********
896          * o extract key name
897          * o check key name
898          * o count?
899          **********/
900
901         pos = skip_over (in, pos + 2, 1);
902         pvk.s = &in->s [pos];
903         pvk.len = pos;
904         pos = skip_over (in, pos, 0);
905         pvk.len = pos - pvk.len;
906         if (!pvk.len)
907                 goto error;
908         for (i = 0; srvqrylst [i]; i++) {
909                 if (strlen (srvqrylst [i]) != pvk.len)
910                         continue;
911                 if (!strncmp (pvk.s, srvqrylst [i], pvk.len)) {
912                         dpv->type = i;
913                         break;
914                 }
915         }
916         if (!srvqrylst [i])
917                 goto error;
918         if (!i)
919                 goto noindex;
920
921         /**********
922          * o check for array
923          * o extract array index and check
924          **********/
925
926         pos = skip_over (in, pos, 1);
927         if ((pos + 3) > in->len)
928                 goto error;
929         if (in->s [pos] != '[')
930                 goto error;
931         pos = skip_over (in, pos + 1, 1);
932         if ((pos + 2) > in->len)
933                 goto error;
934         pvi.s = &in->s [pos];
935         pvi.len = pos;
936         if (in->s [pos] == PV_MARKER) {
937                 /**********
938                  * o search from the end back to array close
939                  * o get PV value
940                  **********/
941
942                 for (i = in->len - 1; i != pos; --i) {
943                         if (in->s [i] == ']')
944                                 break;
945                 }
946                 if (i == pos)
947                         goto error;
948                 pvi.len = i - pvi.len;
949                 pos = i + 1;
950                 dpv->pidx = pv_cache_get (&pvi);
951                 if (!dpv->pidx)
952                         goto error;
953                 dpv->flags |= SR_DNS_PVIDX;
954         } else {
955                 /**********
956                  * o get index value
957                  * o check for reverse index
958                  * o convert string to number
959                  **********/
960
961                 pos = skip_over (in, pos, 0);
962                 pvi.len = pos - pvi.len;
963                 sign = 1;
964                 i = 0;
965                 pstr = pvi.s;
966                 if (*pstr == '-') {
967                         sign = -1;
968                         i++;
969                         pstr++;
970                 }
971                 for (dpv->nidx = 0; i < pvi.len; i++) {
972                         if (*pstr >= '0' && *pstr <= '9')
973                                 dpv->nidx = (dpv->nidx * 10) + *pstr++ - '0';
974                 }
975                 if (i != pvi.len)
976                         goto error;
977                 dpv->nidx *= sign;
978                 pos = skip_over (in, pos, 1);
979                 if (pos == in->len)
980                         goto error;
981                 if (in->s [pos++] != ']')
982                         goto error;
983         }
984
985         /**********
986          * o check for trailing whitespace
987          * o add data to PV
988          **********/
989
990 noindex:
991         if (skip_over (in, pos, 1) != in->len)
992                 goto error;
993         LM_DBG ("srvquery (%.*s => %.*s [%.*s])\n",
994                         pvn.len, ZSW(pvn.s), pvk.len, ZSW(pvk.s), pvi.len, ZSW(pvi.s));
995         dpv->item = sr_srv_add_item (&pvn, 0);
996         if (!dpv->item)
997                 goto error;
998         sp->pvp.pvn.u.dname = (void *)dpv;
999         sp->pvp.pvn.type = PV_NAME_OTHER;
1000         return 0;
1001
1002 error:
1003         LM_ERR ("error at PV srvquery: %.*s@%d\n", in->len, in->s, pos);
1004         pkg_free (dpv);
1005         return -1;
1006 }
1007
1008 int srv_update_pv (str *srvcname, str *pvid)
1009
1010 {
1011         int idx1, idx2, rcount;
1012         struct rdata *phead, *psrv;
1013         struct srv_rdata *plist [PV_SRV_MAXRECS];
1014         sr_srv_item_t *pitem;
1015         sr_srv_record_t *prec;
1016
1017         /**********
1018          * o service name missing?
1019          * o find pvid
1020          **********/
1021
1022         if (!srvcname->len) {
1023                 LM_DBG ("service name missing: %.*s\n", srvcname->len, srvcname->s);
1024                 return -2;
1025         }
1026         pitem = sr_srv_add_item (pvid, 1);
1027         if (!pitem) {
1028                 LM_DBG ("pvid not found: %.*s\n", pvid->len, pvid->s);
1029                 return -3;
1030         }
1031
1032         /**********
1033          * o get records
1034          * o sort by priority/weight
1035          * o save to PV
1036          **********/
1037
1038         LM_DBG ("attempting to query: %.*s\n", srvcname->len, srvcname->s);
1039         phead = get_record (srvcname->s, T_SRV, RES_ONLY_TYPE);
1040         rcount = 0;
1041         for (psrv = phead; psrv; psrv = psrv->next) {
1042                 if (rcount < PV_SRV_MAXRECS) {
1043                         plist [rcount++] = (struct srv_rdata *) psrv->rdata;
1044                 } else {
1045                         LM_WARN ("truncating srv_query list to %d records!", PV_SRV_MAXRECS);
1046                         break;
1047                 }
1048         }
1049         pitem->count = rcount;
1050         if (rcount)
1051                 sort_srv (plist, rcount);
1052         for (idx1 = 0; idx1 < rcount; idx1++) {
1053                 prec = &pitem->rr [idx1];
1054                 prec->priority = plist [idx1]->priority;
1055                 prec->weight = plist [idx1]->weight;
1056                 prec->port = plist [idx1]->port;
1057                 idx2 = plist [idx1]->name_len;
1058                 if (idx2 > PV_SRV_MAXSTR) {
1059                         LM_WARN ("truncating srv_query target (%.*s)!", idx2, plist [idx1]->name);
1060                         idx2 = PV_SRV_MAXSTR;
1061                 }
1062                 strncpy (prec->target, plist [idx1]->name, idx2);
1063                 prec->target [idx2] = '\0';
1064         }
1065         if (phead)
1066                 free_rdata_list (phead);
1067         LM_DBG ("srvquery PV updated for: %.*s (%d)\n",
1068                         srvcname->len, srvcname->s, rcount);
1069         return 1;
1070 }
1071
1072 /**********
1073  * Get srvquery Values
1074  *
1075  * INPUT:
1076  *   Arg (1) = SIP message pointer
1077  *   Arg (2) = parameter pointer
1078  *   Arg (3) = PV value pointer
1079  * OUTPUT: 0=success
1080  **********/
1081
1082 int pv_get_srv (sip_msg_t *pmsg, pv_param_t *param, pv_value_t *res)
1083
1084 {
1085         pv_value_t val;
1086         srv_pv_t *dpv;
1087
1088         /**********
1089          * o sipmsg and param exist?
1090          * o PV name exists?
1091          * o count?
1092          **********/
1093
1094         if(!pmsg || !param)
1095                 return -1;
1096         dpv = (srv_pv_t *) param->pvn.u.dname;
1097         if(!dpv || !dpv->item)
1098                 return -1;
1099         if (!dpv->type)
1100                 return pv_get_sintval (pmsg, param, res, dpv->item->count);
1101
1102         /**********
1103          * o get index value
1104          * o reverse index?
1105          * o extract data
1106          **********/
1107
1108         if (!dpv->pidx) {
1109                 val.ri = dpv->nidx;
1110         } else {
1111                 if (pv_get_spec_value (pmsg, dpv->pidx, &val) < 0
1112                                 || !(val.flags & PV_VAL_INT)) {
1113                         LM_ERR ("failed to evaluate index variable!\n");
1114                         return pv_get_null (pmsg, param, res);
1115                 }
1116         }
1117         if (val.ri < 0) {
1118                 if ((dpv->item->count + val.ri) < 0)
1119                         return pv_get_null (pmsg, param, res);
1120                 val.ri = dpv->item->count + val.ri;
1121         }
1122         if (val.ri >= dpv->item->count)
1123                 return pv_get_null(pmsg, param, res);
1124         switch (dpv->type) {
1125                 case 1: /* port */
1126                         return pv_get_sintval (pmsg, param, res, dpv->item->rr [val.ri].port);
1127                 case 2: /* priority */
1128                         return pv_get_sintval (pmsg, param, res, dpv->item->rr [val.ri].priority);
1129                 case 3: /* target */
1130                         return pv_get_strzval (pmsg, param, res, dpv->item->rr [val.ri].target);
1131                 case 4: /* weight */
1132                         return pv_get_sintval (pmsg, param, res, dpv->item->rr [val.ri].weight);
1133         }
1134         return pv_get_null (pmsg, param, res);
1135 }
1136
1137 /**********
1138  * naptrquery PV
1139  **********/
1140
1141 static char *naptrqrylst[] =
1142 {
1143         "count",
1144         "order",
1145         "pref",
1146         "flags",
1147         "services",
1148         "regex",
1149         "replace",
1150         NULL
1151 };
1152
1153 #define PV_NAPTR_MAXSTR 64
1154 #define PV_NAPTR_MAXRECS 32
1155
1156 typedef struct _sr_naptr_record {
1157         unsigned short count;
1158         unsigned short order;
1159         unsigned short pref;
1160         char flags[PV_NAPTR_MAXSTR + 1];
1161         char services[PV_NAPTR_MAXSTR + 1];
1162         char regex[PV_NAPTR_MAXSTR + 1];
1163         char replace[PV_NAPTR_MAXSTR + 1];
1164 } sr_naptr_record_t;
1165
1166 typedef struct _sr_naptr_item {
1167         str pvid;
1168         unsigned int hashid;
1169         int count;
1170         sr_naptr_record_t rr[PV_NAPTR_MAXRECS];
1171         struct _sr_naptr_item *next;
1172 } sr_naptr_item_t;
1173
1174 typedef struct _naptr_pv {
1175         sr_naptr_item_t *item;
1176         int type;
1177         int flags;
1178         pv_spec_t *pidx;
1179         int        nidx;
1180 } naptr_pv_t;
1181
1182 static sr_naptr_item_t *_sr_naptr_list = NULL;
1183
1184 /**********
1185  * Add naptrquery Item
1186  *
1187  * INPUT:
1188  *   Arg (1) = pvid string pointer
1189  *   Arg (2) = find flag; <>0=search only
1190  * OUTPUT: naptr record pointer; NULL=not found
1191  **********/
1192
1193 sr_naptr_item_t *sr_naptr_add_item(str *pvid, int findflg)
1194 {
1195         sr_naptr_item_t *pitem;
1196         unsigned int hashid;
1197
1198         LM_DBG("%s:%d %s - called: pvid => [%.*s] findflg => [%d]\n",
1199                         __FILE__,__LINE__,__PRETTY_FUNCTION__,
1200                         STR_FMT(pvid), findflg);
1201
1202         /**********
1203          * o get hash
1204          * o already exists?
1205          **********/
1206
1207         hashid = get_hash1_raw (pvid->s, pvid->len);
1208         for (pitem = _sr_naptr_list; pitem; pitem = pitem->next) {
1209                 if (pitem->hashid == hashid
1210                                 && pitem->pvid.len == pvid->len
1211                                 && !strncmp(pitem->pvid.s, pvid->s, pvid->len))
1212                         return pitem;
1213         }
1214         if (findflg)
1215                 return NULL;
1216
1217         /**********
1218          * o alloc/init item structure
1219          * o link in new item
1220          **********/
1221
1222         pitem = (sr_naptr_item_t *)pkg_malloc(sizeof (sr_naptr_item_t));
1223         if (!pitem) {
1224                 LM_ERR ("No more pkg memory!\n");
1225                 return NULL;
1226         }
1227         memset(pitem, 0, sizeof(sr_naptr_item_t));
1228
1229         pitem->pvid.s = (char *)pkg_malloc(pvid->len + 1);
1230         if (!pitem->pvid.s) {
1231                 LM_ERR ("No more pkg memory!\n");
1232                 pkg_free(pitem);
1233                 return NULL;
1234         }
1235         memcpy(pitem->pvid.s, pvid->s, pvid->len);
1236         pitem->pvid.len = pvid->len;
1237         pitem->hashid   = hashid;
1238         pitem->next     = _sr_naptr_list;
1239
1240         _sr_naptr_list = pitem;
1241
1242         LM_DBG("New item [%.*s]", STR_FMT(pvid));
1243
1244         return pitem;
1245 }
1246
1247 /**********
1248  * Sort NAPTR Records by Order/Pref
1249  *
1250  * INPUT:
1251  *   Arg (1) = pointer to array of NAPTR records
1252  *   Arg (2) = record count
1253  * OUTPUT: position past skipped
1254  **********/
1255
1256 void sort_naptr(struct naptr_rdata **plist, int rcount)
1257
1258 {
1259         int idx1, idx2;
1260         struct naptr_rdata *pswap;
1261
1262         for (idx1 = 1; idx1 < rcount; idx1++) {
1263                 pswap = plist[idx1];
1264                 for (idx2 = idx1;
1265                                 idx2 &&
1266                                 (
1267                                                 (plist[idx2 - 1]->order > pswap->order)
1268                                                 ||
1269                                                 (plist[idx2 - 1]->order == pswap->order && plist[idx2 - 1]->pref > pswap->pref)
1270                                 );
1271                                 --idx2) {
1272                         plist [idx2] = plist [idx2 - 1];
1273                 }
1274                 plist [idx2] = pswap;
1275         }
1276
1277         return;
1278 }
1279
1280 /**********
1281  * Parse naptrquery Name
1282  *
1283  * INPUT:
1284  *   Arg (1) = pv spec pointer
1285  *   Arg (2) = input string pointer
1286  * OUTPUT: 0=success
1287  **********/
1288 int pv_parse_naptr_name(pv_spec_t *sp, str *in)
1289 {
1290         LM_DBG("%s:%d %s - called: sp => [%p] in => [%.*s]\n",
1291                         __FILE__,__LINE__,__PRETTY_FUNCTION__,
1292                         sp, STR_FMT(in));
1293
1294         char *pstr;
1295         int i, pos, sign;
1296         naptr_pv_t *dpv;
1297         str pvn = {0}, pvk = {0}, pvi = {0};
1298
1299         /**********
1300          * o alloc/init pvid structure
1301          * o extract pvid name
1302          * o check separator
1303          **********/
1304
1305         if (!sp || !in || in->len<=0)
1306                 return -1;
1307
1308         /* alloc/init pvid structure */
1309         dpv = (naptr_pv_t *)pkg_malloc(sizeof(naptr_pv_t));
1310         if (!dpv) {
1311                 LM_ERR ("No more pkg memory!\n");
1312                 return -1;
1313         }
1314         memset(dpv, 0, sizeof(naptr_pv_t));
1315
1316         /* skip blank chars and init pvn.s */
1317         pos = skip_over(in, 0, 1);
1318         if (pos == in->len)
1319                 goto error;
1320         pvn.s = &in->s[pos];
1321         pvn.len = pos;
1322
1323         /* skip [a-zA-Z0-9] and find pvn.len */
1324         pos = skip_over(in, pos, 0);
1325         pvn.len = pos - pvn.len;
1326         if (!pvn.len)
1327                 goto error;
1328
1329         /* skip blank chars */
1330         pos = skip_over(in, pos, 1);
1331         if ((pos + 2) > in->len)
1332                 goto error;
1333
1334         if (strncmp(&in->s[pos], "=>", 2))
1335                 goto error;
1336
1337         /**********
1338          * o extract key name
1339          * o check key name
1340          * o count?
1341          **********/
1342
1343         /* skip blank chars and init pvk.s */
1344         pos = skip_over(in, pos + 2, 1);
1345         pvk.s = &in->s[pos];
1346         pvk.len = pos;
1347
1348         /* skip [a-zA-Z0-9] and find pvk.len */
1349         pos = skip_over(in, pos, 0);
1350         pvk.len = pos - pvk.len;
1351         if (!pvk.len)
1352                 goto error;
1353
1354
1355         for (i = 0; naptrqrylst[i]; i++) {
1356                 if (strlen(naptrqrylst[i]) != pvk.len)
1357                         continue;
1358                 if (!strncmp(pvk.s, naptrqrylst[i], pvk.len)) {
1359                         dpv->type = i;
1360                         break;
1361                 }
1362         }
1363
1364         if (!naptrqrylst[i])
1365                 goto error;
1366
1367         /* "=>count" doesn't have any index */
1368         if (!i)
1369                 goto noindex;
1370
1371         /**********
1372          * o check for array
1373          * o extract array index and check
1374          **********/
1375
1376         /* skip blank between "=>order" and array index "["  */
1377         pos = skip_over (in, pos, 1);
1378         if ((pos + 3) > in->len)
1379                 goto error;
1380
1381         if (in->s [pos] != '[')
1382                 goto error;
1383
1384         /* skip blank between index sign "[" and a numeric value */
1385         pos = skip_over (in, pos + 1, 1);
1386         if ((pos + 2) > in->len)
1387                 goto error;
1388
1389         pvi.s = &in->s[pos];
1390         pvi.len = pos;
1391         if (in->s[pos] == PV_MARKER) {
1392                 /**********
1393                  * o search from the end back to array close
1394                  * o get PV value
1395                  **********/
1396
1397                 for (i = in->len - 1; i != pos; --i) {
1398                         if (in->s[i] == ']')
1399                                 break;
1400                 }
1401                 /* empty idx */
1402                 if (i == pos)
1403                         goto error;
1404
1405                 pvi.len = i - pvi.len;
1406                 pos = i + 1;
1407                 dpv->pidx = pv_cache_get(&pvi);
1408                 if (!dpv->pidx)
1409                         goto error;
1410                 dpv->flags |= SR_DNS_PVIDX;
1411         } else {
1412                 /**********
1413                  * o get index value
1414                  * o check for reverse index
1415                  * o convert string to number
1416                  **********/
1417
1418                 /* find the end of the index and its length */
1419                 pos = skip_over(in, pos, 0);
1420                 pvi.len = pos - pvi.len;
1421                 sign = 1;
1422                 i = 0;
1423                 pstr = pvi.s;
1424                 if (*pstr == '-') {
1425                         sign = -1;
1426                         i++;
1427                         pstr++;
1428                 }
1429                 /* homemade atoi() */
1430                 for (dpv->nidx = 0; i < pvi.len; i++) {
1431                         if (*pstr >= '0' && *pstr <= '9')
1432                                 dpv->nidx = (dpv->nidx * 10) + *pstr++ - '0';
1433                 }
1434                 if (i != pvi.len)
1435                         goto error;
1436                 dpv->nidx *= sign;
1437
1438                 /* skip blanks between index and the final "]" */
1439                 pos = skip_over(in, pos, 1);
1440                 if (pos == in->len)
1441                         goto error;
1442
1443                 /* check the final "]" */
1444                 if (in->s [pos++] != ']')
1445                         goto error;
1446         }
1447
1448         /**********
1449          * o check for trailing whitespace
1450          * o add data to PV
1451          **********/
1452
1453 noindex:
1454
1455         if (skip_over(in, pos, 1) != in->len)
1456                 goto error;
1457
1458         LM_DBG ("naptrquery (%.*s => %.*s [%.*s])\n",
1459                         pvn.len, ZSW(pvn.s), pvk.len, ZSW(pvk.s), pvi.len, ZSW(pvi.s));
1460
1461         dpv->item = sr_naptr_add_item(&pvn, 0);
1462         if (!dpv->item)
1463                 goto error;
1464
1465         sp->pvp.pvn.u.dname = (void *)dpv;
1466         sp->pvp.pvn.type = PV_NAME_OTHER;
1467         return 0;
1468
1469 error:
1470         LM_ERR ("error at PV naptrquery: %.*s@%d\n", in->len, in->s, pos);
1471         pkg_free (dpv);
1472         return -1;
1473 }
1474
1475 int naptr_update_pv(str *naptrname, str *pvid)
1476 {
1477         LM_DBG("%s:%d %s - called: naptrname => [%.*s], pvid => [%.*s]\n", __FILE__,__LINE__,__PRETTY_FUNCTION__,
1478                         STR_FMT(naptrname), STR_FMT(pvid));
1479
1480         int idx1, idx2, rcount;
1481         struct rdata *phead, *pnaptr;
1482         struct naptr_rdata *plist[PV_SRV_MAXRECS];
1483         sr_naptr_item_t *pitem;
1484         sr_naptr_record_t *prec;
1485
1486         /**********
1487          * o service name missing?
1488          * o find pvid
1489          **********/
1490
1491         if (!naptrname->len) {
1492                 LM_DBG ("naptr name missing: %.*s\n", naptrname->len, naptrname->s);
1493                 return -2;
1494         }
1495         pitem = sr_naptr_add_item(pvid, 1);
1496         if (!pitem) {
1497                 LM_DBG ("pvid not found: %.*s\n", pvid->len, pvid->s);
1498                 return -3;
1499         }
1500
1501         /**********
1502          * o get records
1503          * o sort by order/pref
1504          * o save to PV
1505          **********/
1506
1507         LM_DBG ("attempting to query: %.*s\n", naptrname->len, naptrname->s);
1508         phead = get_record(naptrname->s, T_NAPTR, RES_ONLY_TYPE);
1509         rcount = 0;
1510         for (pnaptr = phead; pnaptr; pnaptr = pnaptr->next) {
1511                 if (rcount < PV_NAPTR_MAXRECS) {
1512                         plist[rcount++] = (struct naptr_rdata *)pnaptr->rdata;
1513                 } else {
1514                         LM_WARN ("truncating naptr_query list to %d records!", PV_NAPTR_MAXRECS);
1515                         break;
1516                 }
1517         }
1518         pitem->count = rcount;
1519         if (rcount)
1520                 sort_naptr(plist, rcount);
1521         for (idx1 = 0; idx1 < rcount; idx1++) {
1522                 prec = &pitem->rr[idx1];
1523
1524                 prec->order = plist[idx1]->order;
1525                 prec->pref  = plist[idx1]->pref;
1526
1527                 idx2 = plist[idx1]->flags_len;
1528                 if (idx2 > PV_NAPTR_MAXSTR)
1529                 {
1530                         LM_WARN ("truncating naptr_query flags (%.*s)!", idx2, plist[idx1]->flags);
1531                         idx2 = PV_NAPTR_MAXSTR;
1532                 }
1533                 strncpy(prec->flags, plist[idx1]->flags, idx2);
1534                 prec->flags[idx2] = '\0';
1535
1536                 idx2 = plist[idx1]->services_len;
1537                 if (idx2 > PV_NAPTR_MAXSTR)
1538                 {
1539                         LM_WARN ("truncating naptr query services (%.*s)!", idx2, plist[idx1]->services);
1540                         idx2 = PV_NAPTR_MAXSTR;
1541                 }
1542                 strncpy(prec->services, plist[idx1]->services, idx2);
1543                 prec->services[idx2] = '\0';
1544
1545                 idx2 = plist[idx1]->regexp_len;
1546                 if (idx2 > PV_NAPTR_MAXSTR)
1547                 {
1548                         LM_WARN ("truncating naptr query regexp (%.*s)!", idx2, plist[idx1]->regexp);
1549                         idx2 = PV_NAPTR_MAXSTR;
1550                 }
1551                 strncpy(prec->regex, plist[idx1]->regexp, idx2);
1552                 prec->regex[idx2] = '\0';
1553
1554                 idx2 = plist[idx1]->repl_len;
1555                 if (idx2 > PV_NAPTR_MAXSTR)
1556                 {
1557                         LM_WARN ("truncating naptr query replace (%.*s)!", idx2, plist[idx1]->repl);
1558                         idx2 = PV_NAPTR_MAXSTR;
1559                 }
1560                 strncpy(prec->replace, plist[idx1]->repl, idx2);
1561                 prec->replace[idx2] = '\0';
1562         }
1563         if (phead)
1564                 free_rdata_list (phead);
1565         LM_DBG ("naptrquery PV updated for: %.*s (%d)\n",
1566                         naptrname->len, naptrname->s, rcount);
1567
1568         return 1;
1569 }
1570
1571 /**********
1572  * Get naptrquery Values
1573  *
1574  * INPUT:
1575  *   Arg (1) = SIP message pointer
1576  *   Arg (2) = parameter pointer
1577  *   Arg (3) = PV value pointer
1578  * OUTPUT: 0=success
1579  **********/
1580
1581 int pv_get_naptr(sip_msg_t *pmsg, pv_param_t *param, pv_value_t *res)
1582 {
1583         pv_value_t val;
1584         naptr_pv_t *dpv;
1585
1586         LM_DBG("%s:%d %s - called: param => [%p], res => [%p]\n", __FILE__,__LINE__,__PRETTY_FUNCTION__,
1587                         param, res);
1588
1589         /**********
1590          * o sipmsg and param exist?
1591          * o PV name exists?
1592          * o count?
1593          **********/
1594
1595         if (!pmsg || !param)
1596                 return -1;
1597         dpv = (naptr_pv_t *)param->pvn.u.dname;
1598         if (!dpv || !dpv->item)
1599                 return -1;
1600         if (!dpv->type)
1601                 return pv_get_sintval(pmsg, param, res, dpv->item->count);
1602
1603         /**********
1604          * o get index value
1605          * o reverse index?
1606          * o extract data
1607          **********/
1608
1609         if (!dpv->pidx) {
1610                 val.ri = dpv->nidx;
1611         } else {
1612                 if (pv_get_spec_value(pmsg, dpv->pidx, &val) < 0
1613                                 || !(val.flags & PV_VAL_INT)) {
1614                         LM_ERR ("failed to evaluate index variable!\n");
1615                         return pv_get_null (pmsg, param, res);
1616                 }
1617         }
1618         if (val.ri < 0) {
1619                 if ((dpv->item->count + val.ri) < 0)
1620                         return pv_get_null(pmsg, param, res);
1621                 val.ri = dpv->item->count + val.ri;
1622         }
1623         if (val.ri >= dpv->item->count)
1624                 return pv_get_null(pmsg, param, res);
1625
1626         switch (dpv->type) {
1627                 case 1: /* order */
1628                         return pv_get_sintval(pmsg, param, res, dpv->item->rr[val.ri].order);
1629                 case 2: /* pref */
1630                         return pv_get_sintval(pmsg, param, res, dpv->item->rr[val.ri].pref);
1631                 case 3: /* flags */
1632                         return pv_get_strzval(pmsg, param, res, dpv->item->rr[val.ri].flags);
1633                 case 4: /* services */
1634                         return pv_get_strzval(pmsg, param, res, dpv->item->rr[val.ri].services);
1635                 case 5: /* regex */
1636                         return pv_get_strzval(pmsg, param, res, dpv->item->rr[val.ri].regex);
1637                 case 6: /* replace */
1638                         return pv_get_strzval(pmsg, param, res, dpv->item->rr[val.ri].replace);
1639         }
1640         return pv_get_null (pmsg, param, res);
1641 }