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