pkg/kamailio/(centos|fedora): Updated .spec and .appl files to build RPM for cdp...
[sip-router] / data_lump.c
1 /* $Id$
2  *
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of SIP-router, a free SIP server.
7  *
8  * SIP-router 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  * SIP-router is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * History:
23  * --------
24  *  2003-01-19  support for duplication lump lists added (jiri)
25  *  2003-03-31  added subst lumps --they expand in ip addr, port a.s.o (andrei)
26  *  2003-04-01  added conditional lump support functions (andrei)
27  *  2003-10-20  anchor_lump & del_lump will automatically choose the lump list
28  *              based on  msg->eoh comparisons (andrei)
29  *  2003-10-28  added extra checks (paranoia) for {anchor,del}_lump (andrei)
30  *  2005-03-24  the type of type attribute changed to enum _hdr_types_t (janakj)
31  */
32 /*!
33  * \file
34  * \brief SIP-router core :: 
35  * \ingroup core
36  * Module: \ref core
37  */
38
39
40
41 #include "data_lump.h"
42 #include "dprint.h"
43 #include "mem/mem.h"
44 #include "globals.h"
45 #include "error.h"
46
47 #include <stdlib.h>
48 #include <string.h>
49
50 #ifdef DEBUG_DMALLOC
51 #include <dmalloc.h>
52 #endif
53
54 /* WARNING: all lump add/insert operations expect a pkg_malloc'ed char* 
55  * pointer the will be DEALLOCATED when the sip_msg is destroyed! */
56
57 enum lump_dir { LD_NEXT, LD_BEFORE, LD_AFTER };
58
59 /* adds a header to the end
60  * returns  pointer on success, 0 on error */
61 struct lump* append_new_lump(struct lump** list, char* new_hdr,
62                                                          int len, enum _hdr_types_t type)
63 {
64         struct lump** t;
65         struct lump* tmp;
66         
67         for (t=list;*t;t=&((*t)->next));
68
69         tmp=pkg_malloc(sizeof(struct lump));
70         if (tmp==0){
71                 LOG(L_ERR, "ERROR: append_new_lump: out of memory\n");
72                 return 0;
73         }
74                 
75         memset(tmp,0,sizeof(struct lump));
76         tmp->type=type;
77         tmp->op=LUMP_ADD;
78         tmp->u.value=new_hdr;
79         tmp->len=len;
80         *t=tmp;
81         return tmp;
82 }
83
84 /* adds a header right after an anchor point if exists
85  * returns  pointer on success, 0 on error */
86 struct lump* add_new_lump(struct lump** list, char* new_hdr,
87                                                          int len, enum _hdr_types_t type)
88 {
89         struct lump** t;
90         struct lump* tmp;
91         
92
93         t = (*list) ? &((*list)->next) : list;
94
95         tmp=pkg_malloc(sizeof(struct lump));
96         if (tmp==0){
97                 LOG(L_ERR, "ERROR: add_new_lump: out of memory\n");
98                 return 0;
99         }
100                 
101         memset(tmp,0,sizeof(struct lump));
102         tmp->type=type;
103         tmp->op=LUMP_ADD;
104         tmp->u.value=new_hdr;
105         tmp->len=len;
106         tmp->next=*t;
107         *t=tmp;
108         return tmp;
109 }
110
111
112
113 /* inserts a header to the beginning 
114  * returns pointer if success, 0 on error */
115 struct lump* insert_new_lump(struct lump** list, char* new_hdr,
116                                                                 int len, enum _hdr_types_t type)
117 {
118         struct lump* tmp;
119
120         tmp=pkg_malloc(sizeof(struct lump));
121         if (tmp==0){
122                 LOG(L_ERR, "ERROR: insert_new_lump: out of memory\n");
123                 return 0;
124         }
125         memset(tmp,0,sizeof(struct lump));
126         tmp->next=*list;
127         tmp->type=type;
128         tmp->op=LUMP_ADD;
129         tmp->u.value=new_hdr;
130         tmp->len=len;
131         *list=tmp;
132         return tmp;
133 }
134
135
136
137 /* inserts a  header/data lump immediately after hdr 
138  * returns pointer on success, 0 on error */
139 struct lump* insert_new_lump_after( struct lump* after, char* new_hdr,
140                                                         int len, enum _hdr_types_t type)
141 {
142         struct lump* tmp;
143
144         tmp=pkg_malloc(sizeof(struct lump));
145         if (tmp==0){
146                 ser_error=E_OUT_OF_MEM;
147                 LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
148                 return 0;
149         }
150         memset(tmp,0,sizeof(struct lump));
151         tmp->after=after->after;
152         tmp->type=type;
153         tmp->op=LUMP_ADD;
154         tmp->u.value=new_hdr;
155         tmp->len=len;
156         after->after=tmp;
157         return tmp;
158 }
159
160
161
162 /* inserts a  header/data lump immediately before "before" 
163  * returns pointer on success, 0 on error */
164 struct lump* insert_new_lump_before( struct lump* before, char* new_hdr,
165                                                         int len, enum _hdr_types_t type)
166 {
167         struct lump* tmp;
168
169         tmp=pkg_malloc(sizeof(struct lump));
170         if (tmp==0){
171                 ser_error=E_OUT_OF_MEM;
172                 LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
173                 return 0;
174         }
175         memset(tmp,0,sizeof(struct lump));
176         tmp->before=before->before;
177         tmp->type=type;
178         tmp->op=LUMP_ADD;
179         tmp->u.value=new_hdr;
180         tmp->len=len;
181         before->before=tmp;
182         return tmp;
183 }
184
185
186
187 /* inserts a  subst lump immediately after hdr 
188  * returns pointer on success, 0 on error */
189 struct lump* insert_subst_lump_after( struct lump* after, enum lump_subst subst,
190                                                                                 enum _hdr_types_t type)
191 {
192         struct lump* tmp;
193         
194         tmp=pkg_malloc(sizeof(struct lump));
195         if (tmp==0){
196                 ser_error=E_OUT_OF_MEM;
197                 LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
198                 return 0;
199         }
200         memset(tmp,0,sizeof(struct lump));
201         tmp->after=after->after;
202         tmp->type=type;
203         tmp->op=LUMP_ADD_SUBST;
204         tmp->u.subst=subst;
205         tmp->len=0;
206         after->after=tmp;
207         return tmp;
208 }
209
210
211
212 /* inserts a  subst lump immediately before "before" 
213  * returns pointer on success, 0 on error */
214 struct lump* insert_subst_lump_before(  struct lump* before, 
215                                                                                 enum lump_subst subst,
216                                                                                 enum _hdr_types_t type)
217 {
218         struct lump* tmp;
219         
220         tmp=pkg_malloc(sizeof(struct lump));
221         if (tmp==0){
222                 ser_error=E_OUT_OF_MEM;
223                 LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
224                 return 0;
225         }
226         memset(tmp,0,sizeof(struct lump));
227         tmp->before=before->before;
228         tmp->type=type;
229         tmp->op=LUMP_ADD_SUBST;
230         tmp->u.subst=subst;
231         tmp->len=0;
232         before->before=tmp;
233         return tmp;
234 }
235
236
237
238 /* inserts a  cond lump immediately after hdr 
239  * returns pointer on success, 0 on error */
240 struct lump* insert_cond_lump_after( struct lump* after, enum lump_conditions c,
241                                                                                 enum _hdr_types_t type)
242 {
243         struct lump* tmp;
244         
245         tmp=pkg_malloc(sizeof(struct lump));
246         if (tmp==0){
247                 ser_error=E_OUT_OF_MEM;
248                 LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
249                 return 0;
250         }
251         memset(tmp,0,sizeof(struct lump));
252         tmp->after=after->after;
253         tmp->type=type;
254         tmp->op=LUMP_ADD_OPT;
255         tmp->u.cond=c;
256         tmp->len=0;
257         after->after=tmp;
258         return tmp;
259 }
260
261
262
263 /* inserts a  conditional lump immediately before "before" 
264  * returns pointer on success, 0 on error */
265 struct lump* insert_cond_lump_before(   struct lump* before, 
266                                                                                 enum lump_conditions c,
267                                                                                 enum _hdr_types_t type)
268 {
269         struct lump* tmp;
270         
271         tmp=pkg_malloc(sizeof(struct lump));
272         if (tmp==0){
273                 ser_error=E_OUT_OF_MEM;
274                 LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
275                 return 0;
276         }
277         memset(tmp,0,sizeof(struct lump));
278         tmp->before=before->before;
279         tmp->type=type;
280         tmp->op=LUMP_ADD_OPT;
281         tmp->u.cond=c;
282         tmp->len=0;
283         before->before=tmp;
284         return tmp;
285 }
286
287
288
289 /* removes an already existing header/data lump */
290 /* WARNING: this function adds the lump either to the msg->add_rm or
291  * msg->body_lumps list, depending on the offset being greater than msg->eoh,
292  * so msg->eoh must be parsed (parse with HDR_EOH) if you think your lump
293  *  might affect the body!! */
294 struct lump* del_lump(struct sip_msg* msg, int offset, int len, enum _hdr_types_t type)
295 {
296         struct lump* tmp;
297         struct lump* prev, *t;
298         struct lump** list;
299
300         /* extra checks */
301         if (offset>msg->len){
302                 LOG(L_CRIT, "BUG: del_lump: offset exceeds message size (%d > %d)"
303                                         " aborting...\n", offset, msg->len);
304                 abort();
305         }
306         if (offset+len>msg->len){
307                 LOG(L_CRIT, " BUG: del_lump: offset + len exceeds message"
308                                 " size (%d + %d > %d)\n", offset, len,  msg->len);
309                 abort();
310         }
311         if (len==0){
312                 LOG(L_WARN, "WARNING: del_lump: called with 0 len (offset =%d)\n",
313                                 offset);
314         }
315         
316         tmp=pkg_malloc(sizeof(struct lump));
317         if (tmp==0){
318                 LOG(L_ERR, "ERROR: del_lump: out of memory\n");
319                 return 0;
320         }
321         memset(tmp,0,sizeof(struct lump));
322         tmp->op=LUMP_DEL;
323         tmp->type=type;
324         tmp->u.offset=offset;
325         tmp->len=len;
326         prev=0;
327         /* check to see whether this might be a body lump */
328         if ((msg->eoh) && (offset> (int)(msg->eoh-msg->buf)))
329                 list=&msg->body_lumps;
330         else
331                 list=&msg->add_rm;
332         for (t=*list;t; prev=t, t=t->next){
333                 /* insert it sorted after offset */
334                 if (((t->op==LUMP_DEL)||(t->op==LUMP_NOP))&&(t->u.offset>offset))
335                         break;
336         }
337         tmp->next=t;
338         if (prev) prev->next=tmp;
339         else *list=tmp;
340         return tmp;
341 }
342
343
344
345 /* add an anchor
346  * WARNING: this function adds the lump either to the msg->add_rm or
347  * msg->body_lumps list, depending on the offset being greater than msg->eoh,
348  * so msg->eoh must be parsed (parse with HDR_EOH) if you think your lump
349  *  might affect the body!! */
350 struct lump* anchor_lump(struct sip_msg* msg, int offset, int len, enum _hdr_types_t type)
351 {
352         struct lump* tmp;
353         struct lump* prev, *t;
354         struct lump** list;
355
356         
357         /* extra checks */
358         if (offset>msg->len){
359                 LOG(L_CRIT, "BUG: anchor_lump: offset exceeds message size (%d > %d)"
360                                         " aborting...\n", offset, msg->len);
361                 abort();
362         }
363         if (len){
364                 LOG(L_WARN, "WARNING: anchor_lump: called with len !=0 (%d)\n", len);
365                 if (offset+len>msg->len)
366                         LOG(L_WARN, "WARNING: anchor_lump: offset + len exceeds message"
367                                         " size (%d + %d > %d)\n", offset, len,  msg->len);
368         }
369         
370         tmp=pkg_malloc(sizeof(struct lump));
371         if (tmp==0){
372                 ser_error=E_OUT_OF_MEM;
373                 LOG(L_ERR, "ERROR: anchor_lump: out of memory\n");
374                 return 0;
375         }
376         memset(tmp,0,sizeof(struct lump));
377         tmp->op=LUMP_NOP;
378         tmp->type=type;
379         tmp->u.offset=offset;
380         tmp->len=len;
381         prev=0;
382         /* check to see whether this might be a body lump */
383         if ((msg->eoh) && (offset> (int)(msg->eoh-msg->buf)))
384                 list=&msg->body_lumps;
385         else
386                 list=&msg->add_rm;
387                 
388         for (t=*list;t; prev=t, t=t->next){
389                 /* insert it sorted after offset */
390                 if (((t->op==LUMP_DEL)||(t->op==LUMP_NOP))&&(t->u.offset>offset))
391                         break;
392         }
393         tmp->next=t;
394         
395         if (prev) prev->next=tmp;
396         else *list=tmp;
397         return tmp;
398 }
399
400 /* add an anchor
401  * Similar to anchor_lump() but this function checks whether or not a lump
402  * has already been added to the same position. If an existing lump is found
403  * then it is returned without adding a new one and is_ref is set to 1.
404  *
405  * WARNING: this function adds the lump either to the msg->add_rm or
406  * msg->body_lumps list, depending on the offset being greater than msg->eoh,
407  * so msg->eoh must be parsed (parse with HDR_EOH) if you think your lump
408  *  might affect the body!! */
409 struct lump* anchor_lump2(struct sip_msg* msg, int offset, int len, enum _hdr_types_t type,
410                 int *is_ref)
411 {
412         struct lump* tmp;
413         struct lump* prev, *t;
414         struct lump** list;
415
416         
417         /* extra checks */
418         if (offset>msg->len){
419                 LOG(L_CRIT, "BUG: anchor_lump2: offset exceeds message size (%d > %d)"
420                                         " aborting...\n", offset, msg->len);
421                 abort();
422         }
423         if (len){
424                 LOG(L_WARN, "WARNING: anchor_lump2: called with len !=0 (%d)\n", len);
425                 if (offset+len>msg->len)
426                         LOG(L_WARN, "WARNING: anchor_lump2: offset + len exceeds message"
427                                         " size (%d + %d > %d)\n", offset, len,  msg->len);
428         }
429         
430         prev=0;
431         /* check to see whether this might be a body lump */
432         if ((msg->eoh) && (offset> (int)(msg->eoh-msg->buf)))
433                 list=&msg->body_lumps;
434         else
435                 list=&msg->add_rm;
436                 
437         for (t=*list;t; prev=t, t=t->next){
438                 /* insert it sorted after offset */
439                 if (((t->op==LUMP_DEL)||(t->op==LUMP_NOP))&&(t->u.offset>=offset))
440                         break;
441         }
442         if (t && (t->u.offset==offset)) {
443                 /* A lump with the same offset is found */
444                 *is_ref=1;
445                 return t;
446         }
447
448         tmp=pkg_malloc(sizeof(struct lump));
449         if (tmp==0){
450                 ser_error=E_OUT_OF_MEM;
451                 LOG(L_ERR, "ERROR: anchor_lump2: out of memory\n");
452                 return 0;
453         }
454         memset(tmp,0,sizeof(struct lump));
455         tmp->op=LUMP_NOP;
456         tmp->type=type;
457         tmp->u.offset=offset;
458         tmp->len=len;
459
460         tmp->next=t;
461         
462         if (prev) prev->next=tmp;
463         else *list=tmp;
464
465         *is_ref=0;
466         return tmp;
467 }
468
469
470 void free_lump(struct lump* lmp)
471 {
472         if (lmp && (lmp->op==LUMP_ADD)){
473                 if (lmp->u.value){
474                         if (lmp->flags &(LUMPFLAG_DUPED|LUMPFLAG_SHMEM)){
475                                 LOG(L_CRIT, "BUG: free_lump: called on a not free-able lump:"
476                                                 "%p flags=%x\n", lmp, lmp->flags);
477                                 abort();
478                         }else{
479                                 pkg_free(lmp->u.value);
480                                 lmp->u.value=0;
481                                 lmp->len=0;
482                         }
483                 }
484         }
485 }
486
487
488
489 void free_lump_list(struct lump* l)
490 {
491         struct lump* t, *r, *foo,*crt;
492         t=l;
493         while(t){
494                 crt=t;
495                 t=t->next;
496         /*
497                  dangerous recursive clean
498                 if (crt->before) free_lump_list(crt->before);
499                 if (crt->after)  free_lump_list(crt->after);
500         */
501                 /* no more recursion, clean after and before and that's it */
502                 r=crt->before;
503                 while(r){
504                         foo=r; r=r->before;
505                         free_lump(foo);
506                         pkg_free(foo);
507                 }
508                 r=crt->after;
509                 while(r){
510                         foo=r; r=r->after;
511                         free_lump(foo);
512                         pkg_free(foo);
513                 }
514                 
515                 /*clean current elem*/
516                 free_lump(crt);
517                 pkg_free(crt);
518         }
519 }
520
521 /* free (shallow-ly) a lump and its after/before lists */
522 static void free_shallow_lump( struct lump *l )
523 {
524         struct lump *r, *foo;
525
526         r=l->before;
527         while(r){
528                 foo=r; r=r->before;
529                 pkg_free(foo);
530         }
531         r=l->after;
532         while(r){
533                 foo=r; r=r->after;
534                 pkg_free(foo);
535         }
536         pkg_free(l);
537 }
538
539 /* duplicate (shallow-ly) a lump list into pkg memory */
540 static struct lump *dup_lump_list_r( struct lump *l, 
541                                 enum lump_dir dir, int *error)
542 {
543         int deep_error;
544         struct lump *new_lump;
545
546         deep_error=0; /* optimist: assume success in recursion */
547         /* if at list end, terminate recursion successfully */
548         if (!l) { *error=0; return 0; }
549         /* otherwise duplicate current element */
550         new_lump=pkg_malloc(sizeof(struct lump));
551         if (!new_lump) { *error=1; return 0; }
552
553         memcpy(new_lump, l, sizeof(struct lump));
554         new_lump->flags=LUMPFLAG_DUPED;
555         new_lump->next=new_lump->before=new_lump->after=0;
556
557         switch(dir) {
558                 case LD_NEXT:   
559                                 new_lump->before=dup_lump_list_r(l->before, 
560                                                                 LD_BEFORE, &deep_error);
561                                 if (deep_error) goto deeperror;
562                                 new_lump->after=dup_lump_list_r(l->after, 
563                                                                 LD_AFTER, &deep_error);
564                                 if (deep_error) goto deeperror;
565                                 new_lump->next=dup_lump_list_r(l->next, 
566                                                                 LD_NEXT, &deep_error);
567                                 break;
568                 case LD_BEFORE:
569                                 new_lump->before=dup_lump_list_r(l->before, 
570                                                                 LD_BEFORE, &deep_error);
571                                 break;
572                 case LD_AFTER:
573                                 new_lump->after=dup_lump_list_r(l->after, 
574                                                                 LD_AFTER, &deep_error);
575                                 break;
576                 default:
577                                 LOG(L_CRIT, "BUG: dup_limp_list_r: unknown dir: "
578                                                 "%d\n", dir );
579                                 deep_error=1;
580         }
581         if (deep_error) goto deeperror;
582
583         *error=0;
584         return new_lump;
585
586 deeperror:
587         LOG(L_ERR, "ERROR: dup_lump_list_r: out of mem\n");
588         free_shallow_lump(new_lump);
589         *error=1;
590         return 0;
591 }
592
593
594
595 /* shallow pkg copy of a lump list
596  *
597  * if either original list empty or error occur returns, 0
598  * is returned, pointer to the copy otherwise
599  */
600 struct lump* dup_lump_list( struct lump *l )
601 {
602         int deep_error;
603
604         deep_error=0;
605         return dup_lump_list_r(l, LD_NEXT, &deep_error);
606 }
607
608
609
610 void free_duped_lump_list(struct lump* l)
611 {
612         struct lump *r, *foo,*crt;
613         while(l){
614                 crt=l;
615                 l=l->next;
616
617                 r=crt->before;
618                 while(r){
619                         foo=r; r=r->before;
620                         /* (+): if a new item was introduced to the shallow-ly
621                          * duped list, remove it completely, preserve it
622                          * otherwise (it is still referred by original list)
623                          */
624                         if (foo->flags!=LUMPFLAG_DUPED) 
625                                         free_lump(foo);
626                         pkg_free(foo);
627                 }
628                 r=crt->after;
629                 while(r){
630                         foo=r; r=r->after;
631                         if (foo->flags!=LUMPFLAG_DUPED) /* (+) ... see above */
632                                 free_lump(foo);
633                         pkg_free(foo);
634                 }
635                 
636                 /*clean current elem*/
637                 if (crt->flags!=LUMPFLAG_DUPED) /* (+) ... see above */
638                         free_lump(crt);
639                 pkg_free(crt);
640         }
641 }
642
643
644
645 void del_nonshm_lump( struct lump** lump_list )
646 {
647         struct lump *r, *foo, *crt, **prev, *prev_r;
648
649         prev = lump_list;
650         crt = *lump_list;
651
652         while (crt) {
653                 if (!(crt->flags&LUMPFLAG_SHMEM)) {
654                         /* unlink it */
655                         foo = crt;
656                         crt = crt->next;
657                         foo->next = 0;
658                         /* update the 'next' link of the previous lump */
659                         *prev = crt;
660                         /* entire before/after list must be removed */
661                         free_lump_list( foo );
662                 } else {
663                         /* check on before and prev list for non-shmem lumps */
664                         r = crt->after;
665                         prev_r = crt;
666                         while(r){
667                                 foo=r; r=r->after;
668                                 if (!(foo->flags&LUMPFLAG_SHMEM)) {
669                                         prev_r->after = r;
670                                         free_lump(foo);
671                                         pkg_free(foo);
672                                 } else {
673                                         prev_r = foo;
674                                 }
675                         }
676                         /* before */
677                         r = crt->before;
678                         prev_r = crt;
679                         while(r){
680                                 foo=r; r=r->before;
681                                 if (!(foo->flags&LUMPFLAG_SHMEM)) {
682                                         prev_r->before = r;
683                                         free_lump(foo);
684                                         pkg_free(foo);
685                                 } else {
686                                         prev_r = foo;
687                                 }
688                         }
689                         /* go to next lump */
690                         prev = &(crt->next);
691                         crt = crt->next;
692                 }
693         }
694 }
695
696 unsigned int count_applied_lumps(struct lump *ll, int type)
697 {
698         unsigned int n = 0;
699         struct lump *l = 0;
700
701         for(l=ll; l; l=l->next) {
702                 if (l->op==LUMP_NOP && l->type==type) {
703                         if (l->after && l->after->op==LUMP_ADD_OPT) {
704                                 if (LUMP_IS_COND_TRUE(l->after)) {
705                                         n++;
706                                 }
707                         } else {
708                                 n++;
709                         }
710                 }
711         }
712         return n;
713 }
714