- changed sip_msg (new rcv member containing all the ips, ports, protocol)
[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
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #include "msg_translator.h"
39 #include "globals.h"
40 #include "error.h"
41 #include "mem/mem.h"
42 #include "dprint.h"
43 #include "config.h"
44 #include "md5utils.h"
45 #include "data_lump_rpl.h"
46 #include "ip_addr.h"
47 #include "resolve.h"
48 #include "ut.h"
49 #include "pt.h"
50
51
52 #define append_str(_dest,_src,_len,_msg) \
53         do{\
54                 memcpy( (_dest) , (_src) , (_len) );\
55                 (_dest) += (_len) ;\
56         }while(0);
57
58 #define append_str_trans(_dest,_src,_len,_msg) \
59         do{\
60                 memcpy( (_dest) , (_msg)->orig+((_src)-(_msg)->buf) , (_len) );\
61                 (_dest) += (_len) ;\
62         }while(0);
63
64 extern char version[];
65 extern int version_len;
66
67
68
69 /* checks if ip is in host(name) and ?host(ip)=name?
70  * ip must be in network byte order!
71  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
72  * return 0 if equal */
73 int check_address(struct ip_addr* ip, char *name, int resolver)
74 {
75         struct hostent* he;
76         int i;
77         char* s;
78
79         /* maybe we are lucky and name it's an ip */
80         s=ip_addr2a(ip);
81         if (s){
82                 DBG("check_address(%s, %s, %d)\n", s, name, resolver);
83         #ifdef USE_IPV6
84                 if ((ip->af==AF_INET6) && (strcasecmp(name, s)==0))
85                                 return 0;
86                 else
87         #endif
88                         if (strcmp(name, s)==0)
89                                 return 0;
90         }else{
91                 LOG(L_CRIT, "check_address: BUG: could not convert ip address\n");
92                 return -1;
93         }
94                 
95         if (resolver&DO_DNS){
96                 DBG("check_address: doing dns lookup\n");
97                 /* try all names ips */
98                 he=resolvehost(name);
99                 if (he && ip->af==he->h_addrtype){
100                         for(i=0;he && he->h_addr_list[i];i++){
101                                 if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
102                                         return 0;
103                         }
104                 }
105         }
106         if (resolver&DO_REV_DNS){
107                 DBG("check_address: doing rev. dns lookup\n");
108                 /* try reverse dns */
109                 he=rev_resolvehost(ip);
110                 if (he && (strcmp(he->h_name, name)==0))
111                         return 0;
112                 for (i=0; he && he->h_aliases[i];i++){
113                         if (strcmp(he->h_aliases[i],name)==0)
114                                 return 0;
115                 }
116         }
117         return -1;
118 }
119
120
121 char * warning_builder( struct sip_msg *msg, unsigned int *returned_len)
122 {
123         static char buf[MAX_WARNING_LEN];
124         static unsigned int fix_len=0;
125         str *foo;
126         int print_len;
127
128         if (!fix_len)
129         {
130                 memcpy(buf+fix_len,"Warning: 392 ",13);
131                 fix_len +=13;
132                 memcpy(buf+fix_len, bind_address->name.s,bind_address->name.len);
133                 fix_len += bind_address->name.len;
134                 //*(buf+fix_len++) = ':';
135                 memcpy(buf+fix_len,bind_address->port_no_str.s,
136                         bind_address->port_no_str.len);
137                 fix_len += bind_address->port_no_str.len;
138                 memcpy(buf+fix_len, " \"Noisy feedback tells: ",24);
139                 fix_len += 24;
140         }
141
142         /*adding out_uri*/
143         if (msg->new_uri.s)
144                 foo=&(msg->new_uri);
145         else
146                 foo=&(msg->first_line.u.request.uri);
147         print_len=snprintf(buf+fix_len, MAX_WARNING_LEN-fix_len,
148                 "pid=%d req_src_ip=%s in_uri=%.*s out_uri=%.*s via_cnt%c=%d\"",
149                 my_pid(),
150                 ip_addr2a(&msg->rcv.src_ip),
151                 msg->first_line.u.request.uri.len, msg->first_line.u.request.uri.s,
152                 foo->len, foo->s, 
153                 msg->parsed_flag & HDR_EOH ? '=' : '>', /* should be = */
154                 via_cnt );
155
156         if (print_len==-1) {
157                 *returned_len=0;
158                 return 0;
159         } else {
160                 *returned_len=fix_len+print_len;
161                 return buf;
162         }
163 }
164
165
166
167
168 char* received_builder(struct sip_msg *msg, unsigned int *received_len)
169 {
170         char *buf;
171         int  len;
172         struct ip_addr *source_ip;
173         char *tmp;
174         int  tmp_len;
175         int extra_len;
176
177         extra_len = 0;
178         source_ip=&msg->rcv.src_ip;
179         buf = 0;
180
181         buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
182         if (buf==0){
183                 ser_error=E_OUT_OF_MEM;
184                 LOG(L_ERR, "ERROR: received_builder: out of memory\n");
185                 return 0;
186         }
187         /*
188         received_len=snprintf(buf, MAX_RECEIVED_SIZE,
189                                                         ";received=%s",
190                                                         inet_ntoa(*(struct in_addr *)&source_ip));
191         */
192         memcpy(buf, RECEIVED, RECEIVED_LEN);
193         if ( (tmp=ip_addr2a(source_ip))==0)
194                 return 0; /* error*/
195         tmp_len=strlen(tmp);
196         len=RECEIVED_LEN+tmp_len;
197         if(source_ip->af==AF_INET6){
198                 len+=2;
199                 buf[RECEIVED_LEN]='[';
200                 buf[RECEIVED_LEN+tmp_len+1]=']';
201                 extra_len=1;
202         }
203         
204         memcpy(buf+RECEIVED_LEN+extra_len, tmp, tmp_len);
205         buf[len]=0; /*null terminate it */
206
207         *received_len = len;
208         return buf;
209 }
210
211
212
213 /* computes the "unpacked" len of a lump list,
214    code moved from build_req_from_req */
215 static inline int lumps_len(struct lump* l)
216 {
217         int s_offset;
218         int new_len;
219         struct lump* t;
220         struct lump* r;
221
222         s_offset=0;
223         new_len=0;
224         for(t=l;t;t=t->next){
225                 for(r=t->before;r;r=r->before){
226                         switch(r->op){
227                                 case LUMP_ADD:
228                                         new_len+=r->len;
229                                         break;
230                                 default:
231                                         /* only ADD allowed for before/after */
232                                         LOG(L_CRIT, "BUG: lumps_len: invalid op "
233                                                         "for data lump (%x)\n", r->op);
234                         }
235                 }
236                 switch(t->op){
237                         case LUMP_ADD:
238                                 new_len+=t->len;
239                                 break;
240                         case LUMP_DEL:
241                                 /* fix overlapping deleted zones */
242                                 if (t->u.offset < s_offset){
243                                         /* change len */
244                                         if (t->len>s_offset-t->u.offset)
245                                                         t->len-=s_offset-t->u.offset;
246                                         else t->len=0;
247                                         t->u.offset=s_offset;
248                                 }
249                                 s_offset=t->u.offset+t->len;
250                                 new_len-=t->len;
251                                 break;
252                         case LUMP_NOP:
253                                 /* fix offset if overlapping on a deleted zone */
254                                 if (t->u.offset < s_offset){
255                                         t->u.offset=s_offset;
256                                 }else
257                                         s_offset=t->u.offset;
258                                 /* do nothing */
259                                 break;
260                         default:
261                                 LOG(L_CRIT,"BUG:lumps_len: invalid"
262                                                         " op for data lump (%x)\n", r->op);
263                 }
264                 for (r=t->after;r;r=r->after){
265                         switch(r->op){
266                                 case LUMP_ADD:
267                                         new_len+=r->len;
268                                         break;
269                                 default:
270                                         /* only ADD allowed for before/after */
271                                         LOG(L_CRIT, "BUG:lumps_len: invalid"
272                                                                 " op for data lump (%x)\n", r->op);
273                         }
274                 }
275         }
276         return new_len;
277 }
278
279
280
281 /* another helper functions, adds/Removes the lump,
282         code moved form build_req_from_req  */
283
284 static inline void process_lumps(       struct lump* l, char* new_buf, 
285                                                                         unsigned int* new_buf_offs, char* orig,
286                                                                         unsigned int* orig_offs)
287 {
288         struct lump *t;
289         struct lump *r;
290         int size;
291         int offset;
292         int s_offset;
293         
294         offset=*new_buf_offs;
295         s_offset=*orig_offs;
296         
297         for (t=l;t;t=t->next){
298                 switch(t->op){
299                         case LUMP_ADD:
300                                 /* just add it here! */
301                                 /* process before  */
302                                 for(r=t->before;r;r=r->before){
303                                         switch (r->op){
304                                                 case LUMP_ADD:
305                                                         /*just add it here*/
306                                                         memcpy(new_buf+offset, r->u.value, r->len);
307                                                         offset+=r->len;
308                                                         break;
309                                                 default:
310                                                         /* only ADD allowed for before/after */
311                                                         LOG(L_CRIT, "BUG:process_lumps: "
312                                                                         "invalid op for data lump (%x)\n", r->op);
313                                         }
314                                 }
315                                 /* copy "main" part */
316                                 memcpy(new_buf+offset, t->u.value, t->len);
317                                 offset+=t->len;
318                                 /* process after */
319                                 for(r=t->after;r;r=r->after){
320                                         switch (r->op){
321                                                 case LUMP_ADD:
322                                                         /*just add it here*/
323                                                         memcpy(new_buf+offset, r->u.value, r->len);
324                                                         offset+=r->len;
325                                                         break;
326                                                 default:
327                                                         /* only ADD allowed for before/after */
328                                                         LOG(L_CRIT, "BUG:process_lumps: "
329                                                                         "invalid op for data lump (%x)\n", r->op);
330                                         }
331                                 }
332                                 break;
333                         case LUMP_NOP:
334                         case LUMP_DEL:
335                                 /* copy till offset */
336                                 if (s_offset>t->u.offset){
337                                         DBG("Warning: (%d) overlapped lumps offsets,"
338                                                 " ignoring(%x, %x)\n", t->op, s_offset,t->u.offset);
339                                         /* this should've been fixed above (when computing len) */
340                                         /* just ignore it*/
341                                         break;
342                                 }
343                                 size=t->u.offset-s_offset;
344                                 if (size){
345                                         memcpy(new_buf+offset, orig+s_offset,size);
346                                         offset+=size;
347                                         s_offset+=size;
348                                 }
349                                 /* process before  */
350                                 for(r=t->before;r;r=r->before){
351                                         switch (r->op){
352                                                 case LUMP_ADD:
353                                                         /*just add it here*/
354                                                         memcpy(new_buf+offset, r->u.value, r->len);
355                                                         offset+=r->len;
356                                                         break;
357                                                 default:
358                                                         /* only ADD allowed for before/after */
359                                                         LOG(L_CRIT, "BUG:process_lumps: "
360                                                                         "invalid op for data lump (%x)\n",r->op);
361                                         }
362                                 }
363                                 /* process main (del only) */
364                                 if (t->op==LUMP_DEL){
365                                         /* skip len bytes from orig msg */
366                                         s_offset+=t->len;
367                                 }
368                                 /* process after */
369                                 for(r=t->after;r;r=r->after){
370                                         switch (r->op){
371                                                 case LUMP_ADD:
372                                                         /*just add it here*/
373                                                         memcpy(new_buf+offset, r->u.value, r->len);
374                                                         offset+=r->len;
375                                                         break;
376                                                 default:
377                                                         /* only ADD allowed for before/after */
378                                                         LOG(L_CRIT, "BUG:process_lumps: "
379                                                                         "invalid op for data lump (%x)\n", r->op);
380                                         }
381                                 }
382                                 break;
383                         default:
384                                         LOG(L_CRIT, "BUG: process_lumps: "
385                                                         "unknown op (%x)\n", t->op);
386                 }
387         }
388         *new_buf_offs=offset;
389         *orig_offs=s_offset;
390 }
391
392
393
394 char * build_req_buf_from_sip_req( struct sip_msg* msg,
395                                                                 unsigned int *returned_len,
396                                                                 struct socket_info* send_sock, int proto)
397 {
398         unsigned int len, new_len, received_len, uri_len, via_len;
399         char* line_buf;
400         char* received_buf;
401         char* new_buf;
402         char* orig;
403         char* buf;
404         char  backup;
405         unsigned int offset, s_offset, size;
406         struct lump* anchor;
407         int r;
408
409         uri_len=0;
410         orig=msg->orig;
411         buf=msg->buf;
412         len=msg->len;
413         received_len=0;
414         new_buf=0;
415         received_buf=0;
416
417
418         line_buf = via_builder( &via_len, send_sock, 
419                 msg->add_to_branch_s, msg->add_to_branch_len, proto);
420         if (!line_buf){
421                 LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
422                 goto error00;
423         }
424         /* check if received needs to be added */
425         backup = msg->via1->host.s[msg->via1->host.len];
426         msg->via1->host.s[msg->via1->host.len] = 0;
427         r=check_address(&msg->rcv.src_ip, msg->via1->host.s, received_dns);
428         msg->via1->host.s[msg->via1->host.len] = backup;
429         if (r!=0){
430                 if ((received_buf=received_builder(msg,&received_len))==0)
431                         goto error01;  /* free also line_buf */
432         }
433
434         /* add via header to the list */
435         /* try to add it before msg. 1st via */
436         /* add first via, as an anchor for second via*/
437         anchor=anchor_lump(&(msg->add_rm), msg->via1->hdr.s-buf, 0, HDR_VIA);
438         if (anchor==0) goto error01;
439         if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
440                 goto error01;
441         /* if received needs to be added, add anchor after host and add it */
442         if (received_len){
443                 if (msg->via1->params.s){
444                                 size= msg->via1->params.s-msg->via1->hdr.s-1; /*compensate
445                                                                                                                           for ';' */
446                 }else{
447                                 size= msg->via1->host.s-msg->via1->hdr.s+msg->via1->host.len;
448                                 if (msg->via1->port!=0){
449                                         /*size+=strlen(msg->via1->hdr.s+size+1)+1;*/
450                                         size += msg->via1->port_str.len + 1; /* +1 for ':'*/
451                                 }
452                         #ifdef USE_IPV6
453                                 if(send_sock->address.af==AF_INET6) size+=1; /* +1 for ']'*/
454                         #endif
455                 }
456                 anchor=anchor_lump(&(msg->add_rm),msg->via1->hdr.s-buf+size,0,
457                                 HDR_VIA);
458                 if (anchor==0) goto error02; /* free also line_buf */
459                 if (insert_new_lump_after(anchor, received_buf, received_len, HDR_VIA)
460                                 ==0 ) goto error02; /* free also line_buf */
461         }
462
463         /* compute new msg len and fix overlapping zones*/
464         new_len=len+lumps_len(msg->add_rm);
465
466         if (msg->new_uri.s){
467                 uri_len=msg->new_uri.len;
468                 new_len=new_len-msg->first_line.u.request.uri.len+uri_len;
469         }
470         new_buf=(char*)pkg_malloc(new_len+1);
471         if (new_buf==0){
472                 ser_error=E_OUT_OF_MEM;
473                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
474                 goto error00;
475         }
476
477         offset=s_offset=0;
478         if (msg->new_uri.s){
479                 /* copy message up to uri */
480                 size=msg->first_line.u.request.uri.s-buf;
481                 memcpy(new_buf, orig, size);
482                 offset+=size;
483                 s_offset+=size;
484                 /* add our uri */
485                 memcpy(new_buf+offset, msg->new_uri.s, uri_len);
486                 offset+=uri_len;
487                 s_offset+=msg->first_line.u.request.uri.len; /* skip original uri */
488         }
489         new_buf[new_len]=0;
490         /* copy msg adding/removing lumps */
491         process_lumps(msg->add_rm, new_buf, &offset, orig, &s_offset);
492         /* copy the rest of the message */
493         memcpy(new_buf+offset, orig+s_offset, len-s_offset);
494         new_buf[new_len]=0;
495
496 #ifdef DBG_MSG_QA
497         if (new_buf[new_len-1]==0) {
498                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: 0 in the end\n");
499                 abort();
500         }
501 #endif
502
503         *returned_len=new_len;
504         return new_buf;
505
506 error01:
507         pkg_free(line_buf);
508 error02:
509         if (received_buf) pkg_free(received_buf);
510 error00:
511         *returned_len=0;
512         return 0;
513 }
514
515
516 char * build_res_buf_from_sip_res( struct sip_msg* msg,
517                                 unsigned int *returned_len)
518 {
519         unsigned int new_len, via_len;
520         char* new_buf;
521         unsigned offset, s_offset, via_offset;
522         char* orig;
523         char* buf;
524         unsigned int len;
525
526         orig=msg->orig;
527         buf=msg->buf;
528         len=msg->len;
529         new_buf=0;
530         /* we must remove the first via */
531         via_len=msg->via1->bsize;
532         via_offset=msg->via1->hdr.s-buf;
533         DBG("via len: %d, initial via offset: %d\n", via_len, via_offset);
534         if (msg->via1->next){
535                 /* add hdr size*/
536                 via_offset+=msg->via1->hdr.len+1;
537             DBG(" adjusted via len: %d, initial offset: %d\n",
538                                 via_len, via_offset);
539         }else{
540                 /* add hdr size ("Via:")*/
541                 via_len+=msg->via1->hdr.len+1;
542         }
543         /* remove the first via*/
544         if (del_lump( &(msg->repl_add_rm), via_offset, via_len, HDR_VIA)==0){
545                 LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
546                                         "via\n");
547                 goto error;
548         }
549         new_len=len+lumps_len(msg->repl_add_rm);
550
551         DBG(" old size: %d, new size: %d\n", len, new_len);
552         new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging 
553                                                                                          (\0 to print it )*/
554         if (new_buf==0){
555                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of mem\n");
556                 goto error;
557         }
558         new_buf[new_len]=0; /* debug: print the message */
559         offset=s_offset=0;
560         process_lumps(msg->repl_add_rm, new_buf, &offset, orig, &s_offset);
561         /* copy the rest of the message */
562         memcpy(new_buf+offset,orig+s_offset, len-s_offset);
563          /* send it! */
564         DBG(" copied size: orig:%d, new: %d, rest: %d\n",
565                         s_offset, offset,
566                         len-s_offset );
567
568         *returned_len=new_len;
569         return new_buf;
570 error:
571         *returned_len=0;
572         return 0;
573 }
574
575
576
577
578
579 char * build_res_buf_from_sip_req( unsigned int code, char *text,
580                                         char *new_tag, unsigned int new_tag_len,
581                                         struct sip_msg* msg, unsigned int *returned_len)
582 {
583         char              *buf, *p;
584         unsigned int      len,foo;
585         struct hdr_field  *hdr;
586         struct lump_rpl   *lump;
587         int               i;
588         char              backup;
589         char              *received_buf;
590         unsigned int               received_len;
591         char              *warning;
592         unsigned int      warning_len;
593         int r;
594         str to_tag;
595
596         received_buf=0;
597         received_len=0;
598         buf=0;
599         /* make -Wall happy */
600         warning=0;
601
602         /* force parsing all headers -- we want to return all
603         Via's in the reply and they may be scattered down to the
604         end of header (non-block Vias are a really poor property
605         of SIP :( ) */
606         if (parse_headers( msg, HDR_EOH, 0 )==-1) {
607                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
608                         "alas, parse_headers failed\n");
609                 goto error00;
610         }
611
612         /* check if received needs to be added */
613         backup = msg->via1->host.s[msg->via1->host.len];
614         msg->via1->host.s[msg->via1->host.len] = 0;
615         r=check_address(&msg->rcv.src_ip, msg->via1->host.s, received_dns);
616         msg->via1->host.s[msg->via1->host.len] = backup;
617         if (r!=0) {
618                 if ((received_buf=received_builder(msg,&received_len))==0) {
619                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
620                                 "alas, received_builder failed\n");
621                         goto error00;
622                 }
623         }
624
625         /*computes the lenght of the new response buffer*/
626         len = 0;
627         /* first line */
628         len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
629                 strlen(text) + CRLF_LEN/*new line*/;
630         /*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
631         for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
632                 if (hdr->type==HDR_TO) {
633                         if (new_tag)
634                         {
635                                 to_tag=get_to(msg)->tag_value;
636                                 if (to_tag.s )
637                                         len+=new_tag_len-to_tag.len;
638                                 else
639                                         len+=new_tag_len+TOTAG_TOKEN_LEN/*";tag="*/;
640                         }
641                 } else if (hdr->type==HDR_VIA) {
642                                 if (hdr==msg->h_via1) len += received_len;
643                 } else if (hdr->type==HDR_RECORDROUTE) {
644                                 /* RR only for 1xx and 2xx replies */
645                                 if (code<180 || code>=300) continue;
646                 } else if (!(hdr->type==HDR_FROM 
647                                         || hdr->type==HDR_CALLID
648                                         || hdr->type==HDR_CSEQ)) {
649                         continue;
650                 }
651                 len += ((hdr->body.s+hdr->body.len )-hdr->name.s )+CRLF_LEN;
652         }
653         /*lumps length*/
654         for(lump=msg->reply_lump;lump;lump=lump->next)
655                 len += lump->text.len;
656         if (server_signature) {
657                 /*server header*/
658                 len += SERVER_HDR_LEN + CRLF_LEN;
659                 /*content length header*/
660                 len +=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
661         }
662         if (sip_warning) {
663                 warning = warning_builder(msg,&warning_len);
664                 if (warning==0) {
665                         LOG(L_ERR, "ERROR: warning too big\n");
666                         goto error01;
667                 }
668                 len += warning_len + CRLF_LEN;
669         }
670         /* end of message */
671         len += CRLF_LEN; /*new line*/
672         /*allocating mem*/
673         buf = (char*) pkg_malloc( len+1 );
674         if (!buf)
675         {
676                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: out of memory "
677                         " ; needs %d\n",len);
678                 goto error01;
679         }
680
681         /* filling the buffer*/
682         p=buf;
683         /* first line */
684         memcpy( p , SIP_VERSION , SIP_VERSION_LEN );
685         p += SIP_VERSION_LEN;
686         *(p++) = ' ' ;
687         /*code*/
688         for ( i=2 , foo = code  ;  i>=0  ;  i-- , foo=foo/10 )
689                 *(p+i) = '0' + foo - ( foo/10 )*10;
690         p += 3;
691         *(p++) = ' ' ;
692         memcpy( p , text , strlen(text) );
693         p += strlen(text);
694         memcpy( p, CRLF, CRLF_LEN );
695         p+=CRLF_LEN;
696         /* headers*/
697         for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
698                 switch (hdr->type)
699                 {
700                         case HDR_TO:
701                                 if (new_tag){
702                                         if (to_tag.s ) {
703                                                 append_str_trans( p, hdr->name.s ,
704                                                         to_tag.s-hdr->name.s,msg);
705                                                 append_str( p, new_tag,new_tag_len,msg);
706                                                 append_str_trans( p,to_tag.s+to_tag.len,
707                                                         ((hdr->body.s+hdr->body.len )-
708                                                         (to_tag.s+to_tag.len)),msg);
709                                                 append_str( p, CRLF,CRLF_LEN,msg);
710                                         }else{
711                                                 append_str_trans( p, hdr->name.s ,
712                                                         ((hdr->body.s+hdr->body.len )-hdr->name.s ),
713                                                         msg);
714                                                 append_str( p, TOTAG_TOKEN,TOTAG_TOKEN_LEN,msg);
715                                                 append_str( p, new_tag,new_tag_len,msg);
716                                                 append_str( p, CRLF,CRLF_LEN,msg);
717                                         }
718                                         break;
719                                 }
720                         case HDR_VIA:
721                                 append_str_trans( p, hdr->name.s ,
722                                         ((hdr->body.s+hdr->body.len )-hdr->name.s ),msg);
723                                 if (hdr==msg->h_via1 && received_buf)
724                                         append_str( p, received_buf, received_len, msg);
725                                 append_str( p, CRLF,CRLF_LEN,msg);
726                                 break;
727                         case HDR_RECORDROUTE:
728                                 /* RR only for 1xx and 2xx replies */
729                                 if (code<180 || code>=300) break;
730                         case HDR_FROM:
731                         case HDR_CALLID:
732                         case HDR_CSEQ:
733                                         append_str_trans( p, hdr->name.s ,
734                                                 ((hdr->body.s+hdr->body.len )-hdr->name.s ),msg);
735                                         append_str( p, CRLF,CRLF_LEN,msg);
736                 } /* for switch */
737         /*lumps*/
738         for(lump=msg->reply_lump;lump;lump=lump->next)
739         {
740                 memcpy(p,lump->text.s,lump->text.len);
741                 p += lump->text.len;
742         }
743         if (server_signature) {
744                 /*server header*/
745                 memcpy( p, SERVER_HDR , SERVER_HDR_LEN );
746                 p+=SERVER_HDR_LEN;
747                 memcpy( p, CRLF, CRLF_LEN );
748                 p+=CRLF_LEN;
749                 /* content length header*/
750                 memcpy( p, CONTENT_LENGTH "0" , CONTENT_LENGTH_LEN+1 );
751                 p+=CONTENT_LENGTH_LEN+1;
752                 memcpy( p, CRLF, CRLF_LEN );
753                 p+=CRLF_LEN;
754         }
755         if (sip_warning) {
756                 memcpy( p, warning, warning_len);
757                 p+=warning_len;
758                 memcpy( p, CRLF, CRLF_LEN);
759                 p+=CRLF_LEN;
760         }
761         /*end of message*/
762         memcpy( p, CRLF, CRLF_LEN );
763         p+=CRLF_LEN;
764         *(p) = 0;
765         *returned_len = len;
766         /* in req2reply, received_buf is not introduced to lumps and
767            needs to be deleted here
768         */
769         if (received_buf) pkg_free(received_buf);
770         return buf;
771
772 error01:
773         if (received_buf) pkg_free(received_buf);
774 error00:
775         *returned_len=0;
776         return 0;
777 }
778
779 /* return number of chars printed or 0 if space exceeded;
780    assumes buffer sace of at least MAX_BRANCH_PARAM_LEN
781  */
782
783 int branch_builder( unsigned int hash_index,
784         /* only either parameter useful */
785         unsigned int label, char * char_v,
786         int branch,
787         char *branch_str, int *len )
788 {
789
790         char *begin;
791         int size;
792
793 #ifdef _OBSOLETED
794         /* no hash_id --- whoever called me wants to have
795            very simple branch_id
796         */
797         if (hash_index==0) {
798                 *branch_str='0';
799                 *len=1;
800                 return *len;
801         }
802 #endif
803
804         /* hash id provided ... start with it */
805         size=MAX_BRANCH_PARAM_LEN;
806         begin=branch_str;
807         *len=0;
808
809         memcpy(begin, MCOOKIE, MCOOKIE_LEN );
810         size-=MCOOKIE_LEN;begin+=MCOOKIE_LEN;
811
812         if (int2reverse_hex( &begin, &size, hash_index)==-1)
813                 return 0;
814
815         if (size) {
816                 *begin=BRANCH_SEPARATOR;
817                 begin++; size--;
818         } else return 0;
819
820         /* string with request's characteristic value ... use it ... */
821         if (char_v) {
822                 if (memcpy(begin,char_v,MD5_LEN)) {
823                         begin+=MD5_LEN; size-=MD5_LEN;
824                 } else return 0;
825         } else { /* ... use the "label" value otherwise */
826                 if (int2reverse_hex( &begin, &size, label )==-1)
827                         return 0;
828         }
829
830         if (size) {
831                 *begin=BRANCH_SEPARATOR;
832                 begin++; size--;
833         } else return 0;
834
835         if (int2reverse_hex( &begin, &size, branch)==-1)
836                 return 0;
837
838         *len=MAX_BRANCH_PARAM_LEN-size;
839         return size;
840                 
841 }
842
843
844 char* via_builder( unsigned int *len, 
845         struct socket_info* send_sock,
846         char *branch, int branch_len, int proto )
847 {
848         unsigned int  via_len, extra_len;
849         char               *line_buf;
850         int max_len;
851
852
853         max_len=MY_VIA_LEN+send_sock->address_str.len /* space in MY_VIA */
854                 +2 /* just in case it it a v6 address ... [ ] */
855                 +send_sock->port_no_str.len
856                 +MY_BRANCH_LEN+branch_len+CRLF_LEN+1;
857         line_buf=pkg_malloc( max_len );
858         if (line_buf==0){
859                 ser_error=E_OUT_OF_MEM;
860                 LOG(L_ERR, "ERROR: via_builder: out of memory\n");
861                 return 0;
862         }
863
864         extra_len=0;
865
866         via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
867
868         memcpy(line_buf, MY_VIA, MY_VIA_LEN-4); /* without "UPD " */
869         if (proto==PROTO_UDP)
870                 memcpy(line_buf+MY_VIA_LEN-4, "UDP ", 4);
871         else if (proto==PROTO_TCP)
872                 memcpy(line_buf+MY_VIA_LEN-4, "TCP ", 4);
873         else{
874                 LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", proto);
875                 return 0;
876         }
877 #       ifdef USE_IPV6
878         if (send_sock->address.af==AF_INET6) {
879                 line_buf[MY_VIA_LEN]='[';
880                 line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
881                 extra_len=1;
882                 via_len+=2; /* [ ]*/
883         }
884 #       endif
885         memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
886                 send_sock->address_str.len);
887         if (send_sock->port_no!=SIP_PORT){
888                 memcpy(line_buf+via_len, send_sock->port_no_str.s,
889                          send_sock->port_no_str.len);
890                 via_len+=send_sock->port_no_str.len;
891         }
892
893         /* branch parameter */
894         memcpy(line_buf+via_len, MY_BRANCH, MY_BRANCH_LEN );
895         via_len+=MY_BRANCH_LEN;
896         memcpy(line_buf+via_len, branch, branch_len );
897         via_len+=branch_len;
898         memcpy(line_buf+via_len, CRLF, CRLF_LEN);
899         via_len+=CRLF_LEN;
900         line_buf[via_len]=0; /* null terminate the string*/
901
902         *len = via_len;
903         return line_buf;
904 }