fixed Content-Lenght bug in build_res_buf_with_body_from_sip_req.
[sip-router] / msg_translator.c
1 /* 
2  * $Id$
3  *
4  *
5  * Copyright (C) 2001-2003 Fhg Fokus
6  *
7  * This file is part of ser, a free SIP server.
8  *
9  * ser is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * For a license to use the ser software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * ser is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License 
25  * along with this program; if not, write to the Free Software 
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  * 
28  *
29  * History:
30  * --------
31  * 2003-03-01  VOICE_MAIL defs removed (jiri)
32  * 2003-02-28  scratchpad compatibility abandoned (jiri)
33  * 2003-01-20  bug_fix: use of return value of snprintf aligned to C99 (jiri)
34  * 2003-01-23  added rport patches, contributed by 
35  *              Maxim Sobolev <sobomax@FreeBSD.org> and heavily modified by me
36  *              (andrei)
37  * 2003-01-24  added i param to via of outgoing requests (used by tcp),
38  *              modified via_builder params (andrei)
39  * 2003-01-27  more rport fixes (make use of new via_param->start)  (andrei)
40  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
41  * 2003-01-29  scratchpad removed (jiri)
42  * 2003-03-18  killed the build_warning snprintf (andrei)
43  *
44  */
45
46
47
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <netdb.h>
51 #include <string.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54
55 #include "comp_defs.h"
56 #include "msg_translator.h"
57 #include "globals.h"
58 #include "error.h"
59 #include "mem/mem.h"
60 #include "dprint.h"
61 #include "config.h"
62 #include "md5utils.h"
63 #include "data_lump_rpl.h"
64 #include "ip_addr.h"
65 #include "resolve.h"
66 #include "ut.h"
67 #include "pt.h"
68
69
70 #define append_str(_dest,_src,_len) \
71         do{\
72                 memcpy( (_dest) , (_src) , (_len) );\
73                 (_dest) += (_len) ;\
74         }while(0);
75
76 #define append_str_trans(_dest,_src,_len,_msg) \
77         append_str( (_dest), (_src), (_len) );
78
79 extern char version[];
80 extern int version_len;
81
82
83
84
85
86 /* checks if ip is in host(name) and ?host(ip)=name?
87  * ip must be in network byte order!
88  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
89  * return 0 if equal */
90 static int check_via_address(struct ip_addr* ip, str *name, 
91                                 unsigned short port, int resolver)
92 {
93         struct hostent* he;
94         int i;
95         char* s;
96
97         /* maybe we are lucky and name it's an ip */
98         s=ip_addr2a(ip);
99         if (s){
100                 DBG("check_address(%s, %.*s, %d)\n", 
101                         s, name->len, name->s, resolver);
102
103         #ifdef USE_IPV6
104                 if ((ip->af==AF_INET6) && (strncasecmp(name->s, s, name->len)==0))
105                         return 0;
106                 else
107         #endif
108
109                         if (strncmp(name->s, s, name->len)==0) 
110                                 return 0;
111         }else{
112                 LOG(L_CRIT, "check_address: BUG: could not convert ip address\n");
113                 return -1;
114         }
115
116         if (port==0) port=SIP_PORT;
117         if (resolver&DO_DNS){
118                 DBG("check_address: doing dns lookup\n");
119                 /* try all names ips */
120                 he=sip_resolvehost(name, &port, 0); /* FIXME proto? */
121                 if (he && ip->af==he->h_addrtype){
122                         for(i=0;he && he->h_addr_list[i];i++){
123                                 if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
124                                         return 0;
125                         }
126                 }
127         }
128         if (resolver&DO_REV_DNS){
129                 DBG("check_address: doing rev. dns lookup\n");
130                 /* try reverse dns */
131                 he=rev_resolvehost(ip);
132                 if (he && (strncmp(he->h_name, name->s, name->len)==0))
133                         return 0;
134                 for (i=0; he && he->h_aliases[i];i++){
135                         if (strncmp(he->h_aliases[i],name->s, name->len)==0)
136                                 return 0;
137                 }
138         }
139         return -1;
140 }
141
142
143 static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len)
144 {
145         static char buf[MAX_WARNING_LEN];
146         static unsigned int fix_len=0;
147         str *foo;
148         int print_len, l;
149         int clen;
150         char* t;
151
152 #define str_pair_print(string, string2, string2_len) \
153                 do{ \
154                         l=strlen((string)); \
155                 if ((clen+(string2_len)+l)>MAX_WARNING_LEN) \
156                         goto error_overflow; \
157                 memcpy(buf+clen, (string), l); \
158                 clen+=l; \
159                 memcpy(buf+clen, (string2), (string2_len)); \
160                 clen+=(string2_len); }while(0)
161                 
162                 
163 #define str_int_print(string, intval)\
164                 do{\
165                         t=int2str((intval), &print_len); \
166                         str_pair_print(string, t, print_len);\
167                 } while(0)
168                 
169 #define str_ipaddr_print(string, ipaddr_val)\
170                 do{\
171                         t=ip_addr2a((ipaddr_val)); \
172                         print_len=strlen(t); \
173                         str_pair_print(string, t, print_len);\
174                 } while(0)
175         
176         if (!fix_len)
177         {
178                 memcpy(buf+fix_len,WARNING, WARNING_LEN);
179                 fix_len +=WARNING_LEN;
180                 memcpy(buf+fix_len, bind_address->name.s,bind_address->name.len);
181                 fix_len += bind_address->name.len;
182                 //*(buf+fix_len++) = ':';
183                 memcpy(buf+fix_len,bind_address->port_no_str.s,
184                         bind_address->port_no_str.len);
185                 fix_len += bind_address->port_no_str.len;
186                 memcpy(buf+fix_len, WARNING_PHRASE,WARNING_PHRASE_LEN);
187                 fix_len += WARNING_PHRASE_LEN;
188         }
189         
190         /*adding out_uri*/
191         if (msg->new_uri.s)
192                 foo=&(msg->new_uri);
193         else
194                 foo=&(msg->first_line.u.request.uri);
195                 clen=fix_len;
196                 
197                 /* pid= */
198                 str_int_print("pid=", my_pid());
199                 /* req_src_ip= */
200                 str_ipaddr_print(" req_src_ip=", &msg->rcv.src_ip);
201                 str_int_print(" req_src_port=", ntohs(msg->rcv.src_port));
202                 str_pair_print(" in_uri=", msg->first_line.u.request.uri.s,
203                                                                         msg->first_line.u.request.uri.len);
204                 str_pair_print(" out_uri=", foo->s, foo->len);
205                 str_pair_print(" via_cnt", msg->parsed_flag & HDR_EOH ? "=" : ">", 1);
206                 str_int_print("=", via_cnt);
207                 if (clen<MAX_WARNING_LEN){ buf[clen]='"'; clen++; }
208                 else goto error_overflow;
209                 
210                 
211                 *returned_len=clen;
212                 return buf;
213 error_overflow:
214                 LOG(L_ERR, "ERROR: warning_builder: buffer size exceeded\n");
215                 *returned_len=0;
216                 return 0;
217 }
218
219
220
221
222 char* received_builder(struct sip_msg *msg, unsigned int *received_len)
223 {
224         char *buf;
225         int  len;
226         struct ip_addr *source_ip;
227         char *tmp;
228         int  tmp_len;
229         int extra_len;
230
231         extra_len = 0;
232         source_ip=&msg->rcv.src_ip;
233
234         buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
235         if (buf==0){
236                 ser_error=E_OUT_OF_MEM;
237                 LOG(L_ERR, "ERROR: received_builder: out of memory\n");
238                 return 0;
239         }
240         memcpy(buf, RECEIVED, RECEIVED_LEN);
241         if ( (tmp=ip_addr2a(source_ip))==0)
242                 return 0; /* error*/
243         tmp_len=strlen(tmp);
244         len=RECEIVED_LEN+tmp_len;
245         if(source_ip->af==AF_INET6){
246                 len+=2;
247                 buf[RECEIVED_LEN]='[';
248                 buf[RECEIVED_LEN+tmp_len+1]=']';
249                 extra_len=1;
250         }
251         
252         memcpy(buf+RECEIVED_LEN+extra_len, tmp, tmp_len);
253         buf[len]=0; /*null terminate it */
254
255         *received_len = len;
256         return buf;
257 }
258
259
260
261 char* rport_builder(struct sip_msg *msg, unsigned int *rport_len)
262 {
263         char* buf;
264         char* tmp;
265         int tmp_len;
266         int len;
267         
268         tmp_len=0;
269         tmp=int2str(ntohs(msg->rcv.src_port), &tmp_len);
270         len=RPORT_LEN+tmp_len;
271         buf=pkg_malloc(sizeof(char)*(len+1));/* space for null term */
272         if (buf==0){
273                 ser_error=E_OUT_OF_MEM;
274                 LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
275                 return 0;
276         }
277         memcpy(buf, RPORT, RPORT_LEN);
278         memcpy(buf+RPORT_LEN, tmp, tmp_len);
279         buf[len]=0; /*null terminate it*/
280         
281         *rport_len=len;
282         return buf;
283 }
284
285
286
287 char* id_builder(struct sip_msg* msg, unsigned int *id_len)
288 {
289         char* buf;
290         int len, value_len;
291         char revhex[sizeof(int)*2];
292         char* p;
293         int size;
294         
295         size=sizeof(int)*2;
296         p=&revhex[0];
297         if (int2reverse_hex(&p, &size, msg->rcv.proto_reserved1)==-1){
298                 LOG(L_CRIT, "BUG: id_builder: not enough space for id\n");
299                 return 0;
300         }
301         value_len=p-&revhex[0];
302         len=ID_PARAM_LEN+value_len; 
303         buf=pkg_malloc(sizeof(char)*(len+1));/* place for ending \0 */
304         if (buf==0){
305                 ser_error=E_OUT_OF_MEM;
306                 LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
307                 return 0;
308         }
309         memcpy(buf, ID_PARAM, ID_PARAM_LEN);
310         memcpy(buf+ID_PARAM_LEN, revhex, value_len);
311         buf[len]=0; /* null terminate it */
312         *id_len=len;
313         return buf;
314 }
315
316
317
318 char* clen_builder(struct sip_msg* msg, unsigned int *clen_len)
319 {
320         char* buf;
321         int len;
322         int value;
323         char* value_s;
324         int value_len;
325         char* body;
326         
327         
328         body=get_body(msg);
329         if (body==0){
330                 ser_error=E_BAD_REQ;
331                 LOG(L_ERR, "ERROR: clen_builder: no message body found"
332                                         " (missing crlf?)");
333                 return 0;
334         }
335         value=msg->len-(int)(body-msg->buf);
336         value_s=int2str(value, &value_len);
337         DBG("clen_builder: content-length: %d (%s)\n", value, value_s);
338                 
339         len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
340         buf=pkg_malloc(sizeof(char)*(len+1));
341         if (buf==0){
342                 ser_error=E_OUT_OF_MEM;
343                 LOG(L_ERR, "ERROR: clen_builder: out of memory\n");
344                 return 0;
345         }
346         memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
347         memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
348         memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
349         buf[len]=0; /* null terminate it */
350         *clen_len=len;
351         return buf;
352 }
353
354
355
356 /* computes the "unpacked" len of a lump list,
357    code moved from build_req_from_req */
358 static inline int lumps_len(struct lump* l)
359 {
360         int s_offset;
361         int new_len;
362         struct lump* t;
363         struct lump* r;
364
365         s_offset=0;
366         new_len=0;
367         for(t=l;t;t=t->next){
368                 for(r=t->before;r;r=r->before){
369                         switch(r->op){
370                                 case LUMP_ADD:
371                                         new_len+=r->len;
372                                         break;
373                                 default:
374                                         /* only ADD allowed for before/after */
375                                         LOG(L_CRIT, "BUG: lumps_len: invalid op "
376                                                         "for data lump (%x)\n", r->op);
377                         }
378                 }
379                 switch(t->op){
380                         case LUMP_ADD:
381                                 new_len+=t->len;
382                                 break;
383                         case LUMP_DEL:
384                                 /* fix overlapping deleted zones */
385                                 if (t->u.offset < s_offset){
386                                         /* change len */
387                                         if (t->len>s_offset-t->u.offset)
388                                                         t->len-=s_offset-t->u.offset;
389                                         else t->len=0;
390                                         t->u.offset=s_offset;
391                                 }
392                                 s_offset=t->u.offset+t->len;
393                                 new_len-=t->len;
394                                 break;
395                         case LUMP_NOP:
396                                 /* fix offset if overlapping on a deleted zone */
397                                 if (t->u.offset < s_offset){
398                                         t->u.offset=s_offset;
399                                 }else
400                                         s_offset=t->u.offset;
401                                 /* do nothing */
402                                 break;
403                         default:
404                                 LOG(L_CRIT,"BUG:lumps_len: invalid"
405                                                         " op for data lump (%x)\n", r->op);
406                 }
407                 for (r=t->after;r;r=r->after){
408                         switch(r->op){
409                                 case LUMP_ADD:
410                                         new_len+=r->len;
411                                         break;
412                                 default:
413                                         /* only ADD allowed for before/after */
414                                         LOG(L_CRIT, "BUG:lumps_len: invalid"
415                                                                 " op for data lump (%x)\n", r->op);
416                         }
417                 }
418         }
419         return new_len;
420 }
421
422
423
424 /* another helper functions, adds/Removes the lump,
425         code moved form build_req_from_req  */
426
427 static inline void process_lumps(       struct lump* l, char* new_buf, 
428                                                                         unsigned int* new_buf_offs, char* orig,
429                                                                         unsigned int* orig_offs)
430 {
431         struct lump *t;
432         struct lump *r;
433         int size;
434         int offset;
435         int s_offset;
436         
437         offset=*new_buf_offs;
438         s_offset=*orig_offs;
439         
440         for (t=l;t;t=t->next){
441                 switch(t->op){
442                         case LUMP_ADD:
443                                 /* just add it here! */
444                                 /* process before  */
445                                 for(r=t->before;r;r=r->before){
446                                         switch (r->op){
447                                                 case LUMP_ADD:
448                                                         /*just add it here*/
449                                                         memcpy(new_buf+offset, r->u.value, r->len);
450                                                         offset+=r->len;
451                                                         break;
452                                                 default:
453                                                         /* only ADD allowed for before/after */
454                                                         LOG(L_CRIT, "BUG:process_lumps: "
455                                                                         "invalid op for data lump (%x)\n", r->op);
456                                         }
457                                 }
458                                 /* copy "main" part */
459                                 memcpy(new_buf+offset, t->u.value, t->len);
460                                 offset+=t->len;
461                                 /* process after */
462                                 for(r=t->after;r;r=r->after){
463                                         switch (r->op){
464                                                 case LUMP_ADD:
465                                                         /*just add it here*/
466                                                         memcpy(new_buf+offset, r->u.value, r->len);
467                                                         offset+=r->len;
468                                                         break;
469                                                 default:
470                                                         /* only ADD allowed for before/after */
471                                                         LOG(L_CRIT, "BUG:process_lumps: "
472                                                                         "invalid op for data lump (%x)\n", r->op);
473                                         }
474                                 }
475                                 break;
476                         case LUMP_NOP:
477                         case LUMP_DEL:
478                                 /* copy till offset */
479                                 if (s_offset>t->u.offset){
480                                         DBG("Warning: (%d) overlapped lumps offsets,"
481                                                 " ignoring(%x, %x)\n", t->op, s_offset,t->u.offset);
482                                         /* this should've been fixed above (when computing len) */
483                                         /* just ignore it*/
484                                         break;
485                                 }
486                                 size=t->u.offset-s_offset;
487                                 if (size){
488                                         memcpy(new_buf+offset, orig+s_offset,size);
489                                         offset+=size;
490                                         s_offset+=size;
491                                 }
492                                 /* process before  */
493                                 for(r=t->before;r;r=r->before){
494                                         switch (r->op){
495                                                 case LUMP_ADD:
496                                                         /*just add it here*/
497                                                         memcpy(new_buf+offset, r->u.value, r->len);
498                                                         offset+=r->len;
499                                                         break;
500                                                 default:
501                                                         /* only ADD allowed for before/after */
502                                                         LOG(L_CRIT, "BUG:process_lumps: "
503                                                                         "invalid op for data lump (%x)\n",r->op);
504                                         }
505                                 }
506                                 /* process main (del only) */
507                                 if (t->op==LUMP_DEL){
508                                         /* skip len bytes from orig msg */
509                                         s_offset+=t->len;
510                                 }
511                                 /* process after */
512                                 for(r=t->after;r;r=r->after){
513                                         switch (r->op){
514                                                 case LUMP_ADD:
515                                                         /*just add it here*/
516                                                         memcpy(new_buf+offset, r->u.value, r->len);
517                                                         offset+=r->len;
518                                                         break;
519                                                 default:
520                                                         /* only ADD allowed for before/after */
521                                                         LOG(L_CRIT, "BUG:process_lumps: "
522                                                                         "invalid op for data lump (%x)\n", r->op);
523                                         }
524                                 }
525                                 break;
526                         default:
527                                         LOG(L_CRIT, "BUG: process_lumps: "
528                                                         "unknown op (%x)\n", t->op);
529                 }
530         }
531         *new_buf_offs=offset;
532         *orig_offs=s_offset;
533 }
534
535
536
537 char * build_req_buf_from_sip_req( struct sip_msg* msg,
538                                                                 unsigned int *returned_len,
539                                                                 struct socket_info* send_sock, int proto)
540 {
541         unsigned int len, new_len, received_len, rport_len, uri_len, via_len;
542         char* line_buf;
543         char* received_buf;
544         char* rport_buf;
545         char* new_buf;
546         char* buf;
547         unsigned int offset, s_offset, size;
548         struct lump* anchor;
549         int r;
550         str branch;
551         str extra_params;
552         
553 #ifdef USE_TCP
554         char* id_buf;
555         unsigned int id_len;
556         char* clen_buf;
557         unsigned int clen_len;
558         
559         
560         id_buf=0;
561         id_len=0;
562         clen_buf=0;
563         clen_len=0;
564 #endif
565         extra_params.len=0;
566         extra_params.s=0;
567         uri_len=0;
568         buf=msg->buf;
569         len=msg->len;
570         received_len=0;
571         rport_len=0;
572         new_buf=0;
573         received_buf=0;
574         rport_buf=0;
575         line_buf=0;
576
577         
578 #ifdef USE_TCP
579         /* add id if tcp */
580         if (msg->rcv.proto==PROTO_TCP){
581                 if  ((id_buf=id_builder(msg, &id_len))==0){
582                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
583                                                         " id_builder failed\n");
584                         goto error01; /* free everything */
585                 }
586                 extra_params.s=id_buf;
587                 extra_params.len=id_len;
588         }
589         /* if sending proto == tcp, check if Content-Length needs to be added*/
590         if (proto==PROTO_TCP){
591                 /* first of all parse content-length */
592                 if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
593                         LOG(L_ERR, "build_req_buf_from_sip_req:"
594                                                         " error parsing content-length\n");
595                         goto skip_clen;
596                 }
597                 if (msg->content_length==0){
598                         /* we need to add it */
599                         if ((clen_buf=clen_builder(msg, &clen_len))==0){
600                                 LOG(L_ERR, "build_req_buf_from_sip_req:" 
601                                                                 " clen_builder failed\n");
602                                 goto skip_clen;
603                         }
604                 }
605         }
606 skip_clen:
607 #endif
608         branch.s=msg->add_to_branch_s;
609         branch.len=msg->add_to_branch_len;
610         line_buf = via_builder( &via_len, send_sock, &branch,
611                                                         extra_params.len?&extra_params:0, proto);
612         if (!line_buf){
613                 LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
614                 goto error00;
615         }
616         /* check if received needs to be added */
617         r=check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
618                 msg->via1->port, received_dns);
619         if (r!=0){
620                 if ((received_buf=received_builder(msg,&received_len))==0){
621                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
622                                                         " received_builder failed\n");
623                         goto error01;  /* free also line_buf */
624                 }
625         }
626         
627         /* check if rport needs to be updated */
628         if (msg->via1->rport && msg->via1->rport->value.s==0){
629                 if ((rport_buf=rport_builder(msg, &rport_len))==0){
630                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
631                                                         " rport_builder failed\n");
632                         goto error01; /* free everything */
633                 }
634         }
635
636         /* add via header to the list */
637         /* try to add it before msg. 1st via */
638         /* add first via, as an anchor for second via*/
639         anchor=anchor_lump(&(msg->add_rm), msg->via1->hdr.s-buf, 0, HDR_VIA);
640         if (anchor==0) goto error01;
641         if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
642                 goto error01;
643         /* if received needs to be added, add anchor after host and add it */
644         if (received_len){
645                 if (msg->via1->params.s){
646                                 size= msg->via1->params.s-msg->via1->hdr.s-1; /*compensate
647                                                                                                                           for ';' */
648                 }else{
649                                 size= msg->via1->host.s-msg->via1->hdr.s+msg->via1->host.len;
650                                 if (msg->via1->port!=0){
651                                         /*size+=strlen(msg->via1->hdr.s+size+1)+1;*/
652                                         size += msg->via1->port_str.len + 1; /* +1 for ':'*/
653                                 }
654                         #ifdef USE_IPV6
655                                 if(send_sock->address.af==AF_INET6) size+=1; /* +1 for ']'*/
656                         #endif
657                 }
658                 anchor=anchor_lump(&(msg->add_rm),msg->via1->hdr.s-buf+size,0,
659                                 HDR_VIA);
660                 if (anchor==0) goto error02; /* free received_buf */
661                 if (insert_new_lump_after(anchor, received_buf, received_len, HDR_VIA)
662                                 ==0 ) goto error02; /* free received_buf */
663         }
664         /* if rport needs to be updated, delete it and add it's value */
665         if (rport_len){
666                 anchor=del_lump(&(msg->add_rm), msg->via1->rport->start-buf-1, /*';'*/
667                                                         msg->via1->rport->size+1 /* ; */, HDR_VIA);
668                 if (anchor==0) goto error03; /* free rport_buf*/
669                 if (insert_new_lump_after(anchor, rport_buf, rport_len, HDR_VIA)==0)
670                         goto error03; /* free rport_buf*/
671         }
672 #ifdef USE_TCP
673         /* if clen needs to be added, add it */
674         if (clen_len){
675                 /* msg->unparsed should point just before the final crlf,
676                  * parse_headers is called from clen_builder */
677                 anchor=anchor_lump(&(msg->add_rm), msg->unparsed-buf, 0,
678                                                          HDR_CONTENTLENGTH);
679                 if (anchor==0) goto error04; /* free clen_buf*/
680                 if (insert_new_lump_after(anchor, clen_buf, clen_len,
681                                         HDR_CONTENTLENGTH)==0)
682                         goto error04; /* free clen_buf*/
683         }
684 #endif
685
686         /* compute new msg len and fix overlapping zones*/
687         new_len=len+lumps_len(msg->add_rm);
688
689         if (msg->new_uri.s){
690                 uri_len=msg->new_uri.len;
691                 new_len=new_len-msg->first_line.u.request.uri.len+uri_len;
692         }
693         new_buf=(char*)pkg_malloc(new_len+1);
694         if (new_buf==0){
695                 ser_error=E_OUT_OF_MEM;
696                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
697                 goto error00;
698         }
699
700         offset=s_offset=0;
701         if (msg->new_uri.s){
702                 /* copy message up to uri */
703                 size=msg->first_line.u.request.uri.s-buf;
704                 memcpy(new_buf, buf, size);
705                 offset+=size;
706                 s_offset+=size;
707                 /* add our uri */
708                 memcpy(new_buf+offset, msg->new_uri.s, uri_len);
709                 offset+=uri_len;
710                 s_offset+=msg->first_line.u.request.uri.len; /* skip original uri */
711         }
712         new_buf[new_len]=0;
713         /* copy msg adding/removing lumps */
714         process_lumps(msg->add_rm, new_buf, &offset, buf, &s_offset);
715         /* copy the rest of the message */
716         memcpy(new_buf+offset, buf+s_offset, len-s_offset);
717         new_buf[new_len]=0;
718
719 #ifdef DBG_MSG_QA
720         if (new_buf[new_len-1]==0) {
721                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: 0 in the end\n");
722                 abort();
723         }
724 #endif
725
726         *returned_len=new_len;
727         return new_buf;
728
729 error01:
730         pkg_free(line_buf);
731 #ifdef USE_TCP
732         if (id_buf) pkg_free(id_buf);
733 #endif
734 error02:
735         if (received_buf) pkg_free(received_buf);
736 error03:
737         if (rport_buf) pkg_free(rport_buf);
738 #ifdef USE_TCP
739 error04:
740         if (clen_buf) pkg_free(clen_buf);
741 #endif
742 error00:
743         *returned_len=0;
744         return 0;
745 }
746
747
748
749 char * build_res_buf_from_sip_res( struct sip_msg* msg,
750                                 unsigned int *returned_len)
751 {
752         unsigned int new_len, via_len;
753         char* new_buf;
754         unsigned offset, s_offset, via_offset;
755         char* buf;
756         unsigned int len;
757 #ifdef USE_TCP
758         struct lump* anchor;
759         char* clen_buf;
760         unsigned int clen_len;
761         
762         clen_buf=0;
763         clen_len=0;
764 #endif
765         buf=msg->buf;
766         len=msg->len;
767         new_buf=0;
768         /* we must remove the first via */
769         if (msg->via1->next) {
770                 via_len=msg->via1->bsize;
771                 via_offset=msg->h_via1->body.s-buf;
772         } else {
773                 via_len=msg->h_via1->len;
774                 via_offset=msg->h_via1->name.s-buf;
775         }
776
777 #ifdef USE_TCP
778
779         /* if sending proto == tcp, check if Content-Length needs to be added*/
780         if (msg->via2 && (msg->via2->proto==PROTO_TCP)){
781                 DBG("build_res_from_sip_res: checking content-length for \n%.*s\n",
782                                 (int)msg->len, msg->buf);
783                 /* first of all parse content-length */
784                 if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
785                         LOG(L_ERR, "build_res_buf_from_sip_res:"
786                                                         " error parsing content-length\n");
787                         goto skip_clen;
788                 }
789                 if (msg->content_length==0){
790                         DBG("build_res_from_sip_res: no content_length hdr found\n");
791                         /* we need to add it */
792                         if ((clen_buf=clen_builder(msg, &clen_len))==0){
793                                 LOG(L_ERR, "build_res_buf_from_sip_res:" 
794                                                                 " clen_builder failed\n");
795                                 goto skip_clen;
796                         }
797                 }
798         }
799 skip_clen:
800 #endif
801         
802         /* remove the first via*/
803         if (del_lump( &(msg->repl_add_rm), via_offset, via_len, HDR_VIA)==0){
804                 LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
805                                         "via\n");
806                 goto error;
807         }
808 #ifdef USE_TCP
809         /* if clen needs to be added, add it */
810         if (clen_len){
811                 /* msg->unparsed should point just before the final crlf,
812                  * parse_headers is called from clen_builder */
813                 anchor=anchor_lump(&(msg->repl_add_rm), msg->unparsed-buf, 0, 
814                                                         HDR_CONTENTLENGTH);
815                 DBG("build_res_from_sip_res: adding content-length: %.*s\n",
816                                 (int)clen_len, clen_buf);
817                 if (anchor==0) goto error_clen; /* free clen_buf*/
818                 if (insert_new_lump_after(anchor, clen_buf, clen_len,
819                                         HDR_CONTENTLENGTH)==0)
820                         goto error_clen; /* free clen_buf*/
821         }
822 #endif
823         new_len=len+lumps_len(msg->repl_add_rm);
824
825         DBG(" old size: %d, new size: %d\n", len, new_len);
826         new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging 
827                                                                                          (\0 to print it )*/
828         if (new_buf==0){
829                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of mem\n");
830                 goto error;
831         }
832         new_buf[new_len]=0; /* debug: print the message */
833         offset=s_offset=0;
834         process_lumps(msg->repl_add_rm, new_buf, &offset, 
835                 buf,
836                 &s_offset);
837         /* copy the rest of the message */
838         memcpy(new_buf+offset,
839                 buf+s_offset, 
840                 len-s_offset);
841          /* send it! */
842         DBG("build_res_from_sip_res: copied size: orig:%d, new: %d, rest: %d"
843                         " msg=\n%s\n", s_offset, offset, len-s_offset, new_buf);
844
845         *returned_len=new_len;
846         return new_buf;
847 #ifdef USE_TCP
848 error_clen:
849         if (clen_buf) pkg_free(clen_buf);
850 #endif
851 error:
852         *returned_len=0;
853         return 0;
854 }
855
856
857
858
859
860 char * build_res_buf_from_sip_req( unsigned int code, char *text,
861                                         char *new_tag, unsigned int new_tag_len,
862                                         struct sip_msg* msg, unsigned int *returned_len,
863                                         struct bookmark *bmark)
864 {
865     return build_res_buf_with_body_from_sip_req(code,text,new_tag,new_tag_len,
866                                                 0,0, /* no body */
867                                                 0,0, /* no content type */
868                                                 msg,returned_len, bmark);
869 }
870
871 char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
872                                              char *new_tag, unsigned int new_tag_len ,
873                                              char *body, unsigned int body_len,
874                                              char *content_type, unsigned int content_type_len,
875                                              struct sip_msg* msg, unsigned int *returned_len,
876                                                  struct bookmark *bmark)
877 {
878         char              *buf, *p;
879         unsigned int      len,foo;
880         struct hdr_field  *hdr;
881         struct lump_rpl   *lump;
882         int               i;
883         char              backup;
884         char              *received_buf;
885         char              *rport_buf;
886         unsigned int      received_len;
887         unsigned int      rport_len;
888         unsigned int      delete_len;
889         char              *warning;
890         unsigned int      warning_len;
891         unsigned int      text_len;
892         int  r;
893         int  content_len_len;
894         char *content_len;
895         char content_len_buf[MAX_CONTENT_LEN_BUF];
896         char *after_body;
897         str  to_tag;
898         char *totags;
899
900         received_buf=0;
901         received_len=0;
902         rport_buf=0;
903         rport_len=0;
904         delete_len=0;
905         buf=0;
906         /* make -Wall happy */
907         warning=0;
908         content_len=0;
909
910         text_len=strlen(text);
911
912         /* force parsing all headers -- we want to return all
913         Via's in the reply and they may be scattered down to the
914         end of header (non-block Vias are a really poor property
915         of SIP :( ) */
916         if (parse_headers( msg, HDR_EOH, 0 )==-1) {
917                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
918                         "alas, parse_headers failed\n");
919                 goto error00;
920         }
921
922         /* check if received needs to be added */
923         backup = msg->via1->host.s[msg->via1->host.len];
924         msg->via1->host.s[msg->via1->host.len] = 0;
925         r=check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
926                 msg->via1->port, received_dns);
927         msg->via1->host.s[msg->via1->host.len] = backup;
928         if (r!=0) {
929                 if ((received_buf=received_builder(msg,&received_len))==0) {
930                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
931                                 "alas, received_builder failed\n");
932                         goto error00;
933                 }
934         }
935         /* check if rport needs to be updated */
936         if (msg->via1->rport && msg->via1->rport->value.s==0){
937                 if ((rport_buf=rport_builder(msg, &rport_len))==0){
938                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req:"
939                                                         " rport_builder failed\n");
940                         goto error01; /* free everything */
941                 }
942                 delete_len=msg->via1->rport->size+1; /* include ';' */
943         }
944
945         /*computes the lenght of the new response buffer*/
946         len = 0;
947         /* first line */
948         len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
949                 text_len + CRLF_LEN/*new line*/;
950         /*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
951         for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
952                 if (hdr->type==HDR_TO) {
953                         if (new_tag)
954                         {
955                                 to_tag=get_to(msg)->tag_value;
956                                 if (to_tag.s )
957                                         len+=new_tag_len-to_tag.len;
958                                 else
959                                         len+=new_tag_len+TOTAG_TOKEN_LEN/*";tag="*/;
960                         }
961                         else {
962                                 len+=hdr->len;
963                                 continue;
964                         }
965                 } else if (hdr->type==HDR_VIA) {
966                                 /* we always add CRLF to via*/
967                                 len+=(hdr->body.s+hdr->body.len)-hdr->name.s+CRLF_LEN;
968                                 if (hdr==msg->h_via1) len += received_len+rport_len;
969                                 continue;
970                 } else if (hdr->type==HDR_RECORDROUTE) {
971                                 /* RR only for 1xx and 2xx replies */
972                                 if (code<180 || code>=300) continue;
973                 } else if (!(hdr->type==HDR_FROM 
974                                         || hdr->type==HDR_CALLID
975                                         || hdr->type==HDR_CSEQ)) {
976                         continue;
977                 }
978                 len += hdr->len; /* we keep the original termination for these 
979                                                         headers*/
980         }
981         len-=delete_len;
982         /*lumps length*/
983         for(lump=msg->reply_lump;lump;lump=lump->next)
984                 len += lump->text.len;
985         if (server_signature) {
986                 /*server header*/
987                 len += SERVER_HDR_LEN + CRLF_LEN;
988         }
989
990         if (body_len) {
991                 content_len=int2str(body_len, &content_len_len);
992                 memcpy(content_len_buf,content_len,content_len_len+1);
993                 content_len = content_len_buf;
994                 len += CONTENT_LENGTH_LEN + content_len_len + CRLF_LEN;
995                 len += body_len;
996         } else {
997                 len +=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
998         }
999         if(content_type_len) {
1000             len += content_type_len + CRLF_LEN;
1001         }
1002
1003         if (sip_warning) {
1004                 warning = warning_builder(msg,&warning_len);
1005                 if (warning) len += warning_len + CRLF_LEN;
1006                 else LOG(L_WARN, "WARNING: warning skipped -- too big\n");
1007         }
1008         /* end of message */
1009         len += CRLF_LEN; /*new line*/
1010
1011         /*allocating mem*/
1012         buf = (char*) pkg_malloc( len+1 );
1013         if (!buf)
1014         {
1015                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: out of memory "
1016                         " ; needs %d\n",len);
1017                 goto error01;
1018         }
1019
1020         /* filling the buffer*/
1021         p=buf;
1022         /* first line */
1023         memcpy( p , SIP_VERSION , SIP_VERSION_LEN );
1024         p += SIP_VERSION_LEN;
1025         *(p++) = ' ' ;
1026         /*code*/
1027         for ( i=2 , foo = code  ;  i>=0  ;  i-- , foo=foo/10 )
1028                 *(p+i) = '0' + foo - ( foo/10 )*10;
1029         p += 3;
1030         *(p++) = ' ' ;
1031         memcpy( p , text , text_len );
1032         p += text_len;
1033         memcpy( p, CRLF, CRLF_LEN );
1034         p+=CRLF_LEN;
1035         /* headers*/
1036         for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
1037                 switch (hdr->type)
1038                 {
1039                         case HDR_VIA:
1040                                 if (hdr==msg->h_via1){
1041                                         if (rport_buf){
1042                                                 /* copy until rport */
1043                                                 append_str_trans( p, hdr->name.s ,
1044                                                         msg->via1->rport->start-hdr->name.s-1,msg);
1045                                                 /* copy new rport */
1046                                                 append_str(p, rport_buf, rport_len);
1047                                                 /* copy the rest of the via */
1048                                                 append_str_trans(p, msg->via1->rport->start+
1049                                                                                         msg->via1->rport->size, 
1050                                                                                         hdr->body.s+hdr->body.len-
1051                                                                                         msg->via1->rport->start-
1052                                                                                         msg->via1->rport->size, msg);
1053                                         }else{
1054                                                 /* normal whole via copy */
1055                                                 append_str_trans( p, hdr->name.s , 
1056                                                                 (hdr->body.s+hdr->body.len)-hdr->name.s, msg);
1057                                         }
1058                                         if (received_buf)
1059                                                 append_str( p, received_buf, received_len);
1060                                 }else{
1061                                         /* normal whole via copy */
1062                                         append_str_trans( p, hdr->name.s,
1063                                                         (hdr->body.s+hdr->body.len)-hdr->name.s, msg);
1064                                 }
1065                                 append_str( p, CRLF,CRLF_LEN);
1066                                 break;
1067                         case HDR_RECORDROUTE:
1068                                 /* RR only for 1xx and 2xx replies */
1069                                 if (code<180 || code>=300) break;
1070                                 append_str(p, hdr->name.s, hdr->len);
1071                                 break;
1072                         case HDR_TO:
1073                                 if (new_tag){
1074                                         if (to_tag.s ) { /* replacement */
1075                                                 /* before to-tag */
1076                                                 append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
1077                                                 /* to tag replacement */
1078                                                 bmark->to_tag_val.s=p;
1079                                                 bmark->to_tag_val.len=new_tag_len;
1080                                                 append_str( p, new_tag,new_tag_len);
1081                                                 /* the rest after to-tag */
1082                                                 append_str( p, to_tag.s+to_tag.len,
1083                                                         hdr->name.s+hdr->len-(to_tag.s+to_tag.len));
1084                                         }else{ /* adding a new to-tag */
1085                                                 after_body=hdr->body.s+hdr->body.len;
1086                                                 append_str( p, hdr->name.s, after_body-hdr->name.s);
1087                                                 append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
1088                                                 bmark->to_tag_val.s=p;
1089                                                 bmark->to_tag_val.len=new_tag_len;
1090                                                 append_str( p, new_tag,new_tag_len);
1091                                                 append_str( p, after_body, 
1092                                                                                 hdr->name.s+hdr->len-after_body);
1093                                         }
1094                                         break;
1095                                 } /* no new to-tag -- proceed to 1:1 copying  */
1096                                 totags=((struct to_body*)(hdr->parsed))->tag_value.s;
1097                                 if (totags) {
1098                                         bmark->to_tag_val.s=p+(totags-hdr->name.s);
1099                                         bmark->to_tag_val.len=
1100                                                         ((struct to_body*)(hdr->parsed))->tag_value.len;
1101                                 };
1102                         case HDR_FROM:
1103                         case HDR_CALLID:
1104                         case HDR_CSEQ:
1105                                         append_str(p, hdr->name.s, hdr->len);
1106                 } /* for switch */
1107         /*lumps*/
1108         for(lump=msg->reply_lump;lump;lump=lump->next)
1109         {
1110                 memcpy(p,lump->text.s,lump->text.len);
1111                 p += lump->text.len;
1112         }
1113         if (server_signature) {
1114                 /*server header*/
1115                 memcpy( p, SERVER_HDR , SERVER_HDR_LEN );
1116                 p+=SERVER_HDR_LEN;
1117                 memcpy( p, CRLF, CRLF_LEN );
1118                 p+=CRLF_LEN;
1119         }
1120         
1121         if (body_len) {
1122                 memcpy(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN );
1123                 p+=CONTENT_LENGTH_LEN;
1124                 memcpy( p, content_len, content_len_len );
1125                 p+=content_len_len;
1126                 memcpy( p, CRLF, CRLF_LEN );
1127                 p+=CRLF_LEN;
1128         } else {
1129                 /* content length header*/
1130                 memcpy( p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN+1+CRLF_LEN );
1131                 p+=CONTENT_LENGTH_LEN+1+CRLF_LEN;
1132         }
1133         if(content_type_len){
1134             memcpy( p, content_type, content_type_len );
1135             p+=content_type_len;
1136             memcpy( p, CRLF, CRLF_LEN );
1137             p+=CRLF_LEN;
1138         }
1139         if (sip_warning && warning) {
1140                 memcpy( p, warning, warning_len);
1141                 p+=warning_len;
1142                 memcpy( p, CRLF, CRLF_LEN);
1143                 p+=CRLF_LEN;
1144         }
1145         /*end of message*/
1146         memcpy( p, CRLF, CRLF_LEN );
1147         p+=CRLF_LEN;
1148         if(body_len){
1149             memcpy ( p, body, body_len );
1150             p+=body_len;
1151         }
1152         *(p) = 0;
1153         *returned_len = len;
1154         DBG("build_*: len=%d, diff=%d\n", len, p-buf);
1155         DBG("build_*: rport_len=%d, delete_len=%d\n", rport_len, delete_len);
1156         DBG("build_*: message=\n%.*s\n", (int)len, buf);
1157         /* in req2reply, received_buf is not introduced to lumps and
1158            needs to be deleted here
1159         */
1160         if (received_buf) pkg_free(received_buf);
1161         if (rport_buf) pkg_free(rport_buf);
1162         return buf;
1163
1164 error01:
1165         if (received_buf) pkg_free(received_buf);
1166         if (rport_buf) pkg_free(rport_buf);
1167 error00:
1168         *returned_len=0;
1169         return 0;
1170 }
1171
1172 /* return number of chars printed or 0 if space exceeded;
1173    assumes buffer sace of at least MAX_BRANCH_PARAM_LEN
1174  */
1175
1176 int branch_builder( unsigned int hash_index,
1177         /* only either parameter useful */
1178         unsigned int label, char * char_v,
1179         int branch,
1180         char *branch_str, int *len )
1181 {
1182
1183         char *begin;
1184         int size;
1185
1186         /* hash id provided ... start with it */
1187         size=MAX_BRANCH_PARAM_LEN;
1188         begin=branch_str;
1189         *len=0;
1190
1191         memcpy(begin, MCOOKIE, MCOOKIE_LEN );
1192         size-=MCOOKIE_LEN;begin+=MCOOKIE_LEN;
1193
1194         if (int2reverse_hex( &begin, &size, hash_index)==-1)
1195                 return 0;
1196
1197         if (size) {
1198                 *begin=BRANCH_SEPARATOR;
1199                 begin++; size--;
1200         } else return 0;
1201
1202         /* string with request's characteristic value ... use it ... */
1203         if (char_v) {
1204                 if (memcpy(begin,char_v,MD5_LEN)) {
1205                         begin+=MD5_LEN; size-=MD5_LEN;
1206                 } else return 0;
1207         } else { /* ... use the "label" value otherwise */
1208                 if (int2reverse_hex( &begin, &size, label )==-1)
1209                         return 0;
1210         }
1211
1212         if (size) {
1213                 *begin=BRANCH_SEPARATOR;
1214                 begin++; size--;
1215         } else return 0;
1216
1217         if (int2reverse_hex( &begin, &size, branch)==-1)
1218                 return 0;
1219
1220         *len=MAX_BRANCH_PARAM_LEN-size;
1221         return size;
1222                 
1223 }
1224
1225
1226 char* via_builder( unsigned int *len, 
1227         struct socket_info* send_sock,
1228         str* branch, str* extra_params, int proto )
1229 {
1230         unsigned int  via_len, extra_len;
1231         char               *line_buf;
1232         int max_len;
1233
1234
1235         max_len=MY_VIA_LEN+send_sock->address_str.len /* space in MY_VIA */
1236                 +2 /* just in case it is a v6 address ... [ ] */
1237                 +send_sock->port_no_str.len
1238                 +(branch?(MY_BRANCH_LEN+branch->len):0)
1239                 +(extra_params?extra_params->len:0)
1240                 +CRLF_LEN+1;
1241         line_buf=pkg_malloc( max_len );
1242         if (line_buf==0){
1243                 ser_error=E_OUT_OF_MEM;
1244                 LOG(L_ERR, "ERROR: via_builder: out of memory\n");
1245                 return 0;
1246         }
1247
1248         extra_len=0;
1249
1250         via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
1251
1252         memcpy(line_buf, MY_VIA, MY_VIA_LEN-4); /* without "UPD " */
1253         if (proto==PROTO_UDP)
1254                 memcpy(line_buf+MY_VIA_LEN-4, "UDP ", 4);
1255         else if (proto==PROTO_TCP)
1256                 memcpy(line_buf+MY_VIA_LEN-4, "TCP ", 4);
1257         else{
1258                 LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", proto);
1259                 return 0;
1260         }
1261 #       ifdef USE_IPV6
1262         if (send_sock->address.af==AF_INET6) {
1263                 line_buf[MY_VIA_LEN]='[';
1264                 line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
1265                 extra_len=1;
1266                 via_len+=2; /* [ ]*/
1267         }
1268 #       endif
1269         memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
1270                 send_sock->address_str.len);
1271         if (send_sock->port_no!=SIP_PORT){
1272                 memcpy(line_buf+via_len, send_sock->port_no_str.s,
1273                          send_sock->port_no_str.len);
1274                 via_len+=send_sock->port_no_str.len;
1275         }
1276
1277         /* branch parameter */
1278         if (branch){
1279                 memcpy(line_buf+via_len, MY_BRANCH, MY_BRANCH_LEN );
1280                 via_len+=MY_BRANCH_LEN;
1281                 memcpy(line_buf+via_len, branch->s, branch->len );
1282                 via_len+=branch->len;
1283         }
1284         /* extra params  */
1285         if (extra_params){
1286                 memcpy(line_buf+via_len, extra_params->s, extra_params->len);
1287                 via_len+=extra_params->len;
1288         }
1289         
1290         memcpy(line_buf+via_len, CRLF, CRLF_LEN);
1291         via_len+=CRLF_LEN;
1292         line_buf[via_len]=0; /* null terminate the string*/
1293
1294         *len = via_len;
1295         return line_buf;
1296 }