tm: Reason header generation for local CANCELs
[sip-router] / modules / tm / t_msgbuilder.c
1 /*
2  * $Id$
3  *
4  * message printing
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  *
29  *
30  * History:
31  * ----------
32  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
33  * 2003-02-13  build_uac_request uses proto (andrei)
34  * 2003-02-28  scratchpad compatibility abandoned (jiri)
35  * 2003-04-14  build_local no longer checks reply status as it
36  *             is now called before reply status is updated to
37  *             avoid late ACK sending (jiri)
38  * 2003-10-02  added via_builder set host/port support (andrei)
39  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
40  * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan)
41  * 2006-04-21  build_uac_req, assemble_via use struct dest_info now;
42  *              uri2sock replaced with uri2dst (andrei)
43  * 2006-08-11  build_dlg_ack: use the first dns ip for which a send_sock
44  *              is found (andrei)
45  * 2007-03-15  build_dls_ack: removed next_hop and replaced by dst to avoid
46  *               resolving nexthop twice (andrei)
47  * 2007-05-28: build_local_reparse() is introdued: it uses the outgoing
48  *             INVITE as a source to construct a CANCEL or ACK (Miklos)
49  * 2010-02-26  cancel reason (rfc3326) basic support (andrei)
50  */
51
52 #include "defs.h"
53
54 #ifdef EXTRA_DEBUG
55 #include <assert.h>
56 #endif
57 #include "../../comp_defs.h"
58 #include "../../hash_func.h"
59 #include "../../globals.h"
60 #include "t_funcs.h"
61 #include "../../dprint.h"
62 #include "../../config.h"
63 #include "../../parser/parser_f.h"
64 #include "../../parser/parse_to.h"
65 #include "../../ut.h"
66 #include "../../parser/msg_parser.h"
67 #include "../../parser/contact/parse_contact.h"
68 #include "lw_parser.h"
69 #include "t_msgbuilder.h"
70 #include "uac.h"
71 #ifdef USE_DNS_FAILOVER
72 #include "../../dns_cache.h"
73 #include "../../cfg_core.h" /* cfg_get(core, core_cfg, use_dns_failover) */
74 #endif
75
76
77 /* reason building blocks (see rfc3326) */
78 #define REASON_PREFIX "Reason: SIP;cause="
79 #define REASON_PREFIX_LEN (sizeof(REASON_PREFIX)-1)
80 #define REASON_TEXT ";text="
81 #define REASON_TEXT_LEN (sizeof(REASON_TEXT)-1)
82
83 /* convenience macros */
84 #define memapp(_d,_s,_len) \
85         do{\
86                 memcpy((_d),(_s),(_len));\
87                 (_d) += (_len);\
88         }while(0)
89
90
91 /* Build a local request based on a previous request; main
92    customers of this function are local ACK and local CANCEL
93  */
94 char *build_local(struct cell *Trans,unsigned int branch,
95         unsigned int *len, char *method, int method_len, str *to,
96         struct cancel_reason* reason)
97 {
98         char                *cancel_buf, *p, *via;
99         unsigned int         via_len;
100         struct hdr_field    *hdr;
101         char branch_buf[MAX_BRANCH_PARAM_LEN];
102         int branch_len;
103         str branch_str;
104         str via_id;
105         struct hostport hp;
106         int reason_len, code_len;
107
108         /* init */
109         via_id.s=0;
110         via_id.len=0;
111
112         /* method, separators, version: "CANCEL sip:p2@iptel.org SIP/2.0" */
113         *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN;
114         *len+=Trans->uac[branch].uri.len;
115
116         /*via*/
117         if (!t_calc_branch(Trans,  branch, 
118                 branch_buf, &branch_len ))
119                 goto error;
120         branch_str.s=branch_buf;
121         branch_str.len=branch_len;
122         set_hostport(&hp, (is_local(Trans))?0:(Trans->uas.request));
123 #ifdef USE_TCP
124         if (!is_local(Trans) && ((Trans->uas.request->rcv.proto==PROTO_TCP)
125 #ifdef USE_TLS
126                                 || (Trans->uas.request->rcv.proto==PROTO_TLS)
127 #endif /* USE_TLS */
128                 )){
129                 if ((via_id.s=id_builder(Trans->uas.request,
130                                                                         (unsigned int*)&via_id.len))==0){
131                         LOG(L_ERR, "ERROR: build_local: id builder failed\n");
132                         /* try to continue without id */
133                 }
134         }
135 #endif /* USE_TCP */
136         via=via_builder(&via_len, &Trans->uac[branch].request.dst,
137                 &branch_str, via_id.s?&via_id:0 , &hp );
138         
139         /* via_id.s not needed anylonger => free it */
140         if (via_id.s){
141                 pkg_free(via_id.s);
142                 via_id.s=0;
143                 via_id.len=0;
144         }
145         
146         if (!via)
147         {
148                 LOG(L_ERR, "ERROR: build_local: "
149                         "no via header got from builder\n");
150                 goto error;
151         }
152         *len+= via_len;
153         /*headers*/
154         *len+=Trans->from.len+Trans->callid.len+to->len+
155                 +Trans->cseq_n.len+1+method_len+CRLF_LEN; 
156
157
158         /* copy'n'paste Route headers */
159         if (!is_local(Trans)) {
160                 for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
161                          if (hdr->type==HDR_ROUTE_T)
162                                 *len+=hdr->len;
163         }
164
165         /* User Agent */
166         if (server_signature) {
167                 *len += user_agent_hdr.len + CRLF_LEN;
168         }
169         /* Content Length, EoM */
170         *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
171         reason_len = 0;
172         /* compute reason size */
173         if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
174                 if (likely(reason->cause > 0)){
175                         /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
176                         reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
177                                 (reason->u.text.s?
178                                         REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
179                                 CRLF_LEN;
180                 } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
181                                         reason->u.e2e_cancel) {
182                         /* FIXME: TODO */
183                 } else if (unlikely(reason->cause != -1))
184                         BUG("unhandled reason cause %d\n", reason->cause);
185         }
186         *len+= reason_len;
187         *len+= CRLF_LEN; /* end of msg. */
188
189         cancel_buf=shm_malloc( *len+1 );
190         if (!cancel_buf)
191         {
192                 LOG(L_ERR, "ERROR: build_local: cannot allocate memory\n");
193                 goto error01;
194         }
195         p = cancel_buf;
196
197         append_str( p, method, method_len );
198         append_str( p, " ", 1 );
199         append_str( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len);
200         append_str( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
201
202         /* insert our via */
203         append_str(p,via,via_len);
204
205         /*other headers*/
206         append_str( p, Trans->from.s, Trans->from.len );
207         append_str( p, Trans->callid.s, Trans->callid.len );
208         append_str( p, to->s, to->len );
209
210         append_str( p, Trans->cseq_n.s, Trans->cseq_n.len );
211         append_str( p, " ", 1 );
212         append_str( p, method, method_len );
213         append_str( p, CRLF, CRLF_LEN );
214
215         if (!is_local(Trans))  {
216                 for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
217                         if(hdr->type==HDR_ROUTE_T) {
218                                 append_str(p, hdr->name.s, hdr->len );
219                         }
220         }
221
222         /* User Agent header */
223         if (server_signature) {
224                 append_str(p, user_agent_hdr.s, user_agent_hdr.len );
225                 append_str(p, CRLF, CRLF_LEN );
226         }
227         /* Content Length */
228         append_str(p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN);
229         /* add reason if needed */
230         if (reason_len) {
231                 if (likely(reason->cause > 0)) {
232                         append_str(p, REASON_PREFIX, REASON_PREFIX_LEN);
233                         code_len=ushort2sbuf(reason->cause, p,
234                                                                         *len-(int)(p-cancel_buf));
235                         if (unlikely(code_len==0))
236                                 BUG("not enough space to write reason code");
237                         p+=code_len;
238                         if (reason->u.text.s){
239                                 append_str(p, REASON_TEXT, REASON_TEXT_LEN);
240                                 *p='"'; p++;
241                                 append_str(p, reason->u.text.s, reason->u.text.len);
242                                 *p='"'; p++;
243                         }
244                         append_str(p, CRLF, CRLF_LEN);
245                 } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
246                         /* FIXME: handle cancel */
247                 }
248         }
249         append_str(p, CRLF, CRLF_LEN); /* msg. end */
250         *p=0;
251
252         pkg_free(via);
253         return cancel_buf;
254 error01:
255         pkg_free(via);
256 error:
257         return NULL;
258 }
259
260 /* Re-parsing version of build_local() function:
261  * it builds a local CANCEL or ACK (for non-200 response) request based on
262  * the previous INVITE which was sent out.
263  *
264  * Can not be used to build other type of requests!
265  */
266 char *build_local_reparse(struct cell *Trans,unsigned int branch,
267         unsigned int *len, char *method, int method_len, str *to,
268         struct cancel_reason *reason)
269 {
270         char    *invite_buf, *invite_buf_end;
271         char    *cancel_buf;
272         char    *s, *s1, *d;    /* source and destination buffers */
273         short   invite_len;
274         enum _hdr_types_t       hf_type;
275         int     first_via, to_len;
276         int cancel_buf_len, reason_len, code_len;
277
278         invite_buf = Trans->uac[branch].request.buffer;
279         invite_len = Trans->uac[branch].request.buffer_len;
280
281         if (!invite_buf || !invite_len) {
282                 LOG(L_ERR, "ERROR: build_local_reparse: INVITE is missing\n");
283                 goto error;
284         }
285         if ((*invite_buf != 'I') && (*invite_buf != 'i')) {
286                 LOG(L_ERR, "ERROR: trying to call build_local_reparse()"
287                                         " for a non-INVITE request?\n");
288                 goto error;
289         }
290         
291         reason_len = 0;
292         /* compute reason size */
293         if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
294                 if (likely(reason->cause > 0)){
295                         /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
296                         reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
297                                 (reason->u.text.s?
298                                         REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
299                                 CRLF_LEN;
300                 } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
301                                         reason->u.e2e_cancel) {
302                         /* FIXME: TODO */
303                 } else if (unlikely(reason->cause != -1))
304                         BUG("unhandled reason cause %d\n", reason->cause);
305         }
306
307         invite_buf_end = invite_buf + invite_len;
308         s = invite_buf;
309
310         /* Allocate memory for the new message.
311         The new request will be smaller than the INVITE, so the same size is enough.
312         I just extend it with the length of new To HF to be sure.
313         Ugly, but we avoid lots of checks and memory allocations this way */
314         to_len = to ? to->len : 0;
315         cancel_buf_len = invite_len + to_len + reason_len;
316         cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len);
317         if (!cancel_buf)
318         {
319                 LOG(L_ERR, "ERROR: cannot allocate shared memory\n");
320                 goto error;
321         }
322         d = cancel_buf;
323
324         /* method name + space */
325         append_str(d, method, method_len);
326         *d = ' ';
327         d++;
328         /* skip "INVITE " and copy the rest of the line including CRLF */
329         s += 7;
330         s1 = s;
331         s = eat_line(s, invite_buf_end - s);
332         append_str(d, s1, s - s1);
333
334         /* check every header field name,
335         we must exclude and modify some of the headers */
336         first_via = 1;
337         while (s < invite_buf_end) {
338                 s1 = s;
339                 if ((*s == '\n') || (*s == '\r')) {
340                         /* end of SIP msg */
341                         hf_type = HDR_EOH_T;
342                 } else {
343                         /* parse HF name */
344                         s = lw_get_hf_name(s, invite_buf_end,
345                                                 &hf_type);
346                 }
347
348                 switch(hf_type) {
349                         case HDR_CSEQ_T:
350                                 /* find the method name and replace it */
351                                 while ((s < invite_buf_end)
352                                         && ((*s == ':') || (*s == ' ') || (*s == '\t') ||
353                                                 ((*s >= '0') && (*s <= '9')))
354                                         ) s++;
355                                 append_str(d, s1, s - s1);
356                                 append_str(d, method, method_len);
357                                 append_str(d, CRLF, CRLF_LEN);
358                                 s = lw_next_line(s, invite_buf_end);
359                                 break;
360
361                         case HDR_VIA_T:
362                                 s = lw_next_line(s, invite_buf_end);
363                                 if (first_via) {
364                                         /* copy hf */
365                                         append_str(d, s1, s - s1);
366                                         first_via = 0;
367                                 } /* else skip this line, we need olny the first via */
368                                 break;
369
370                         case HDR_TO_T:
371                                 if (to_len == 0) {
372                                         /* there is no To tag required, just copy paste
373                                            the header */
374                                         s = lw_next_line(s, invite_buf_end);
375                                         append_str(d, s1, s - s1);
376                                 } else {
377                                         /* use the given To HF instead of the original one */
378                                         append_str(d, to->s, to->len);
379                                         /* move the pointer to the next line */
380                                         s = lw_next_line(s, invite_buf_end);
381                                 }
382                                 break;
383
384                         case HDR_FROM_T:
385                         case HDR_CALLID_T:
386                         case HDR_ROUTE_T:
387                         case HDR_MAXFORWARDS_T:
388                                 /* copy hf */
389                                 s = lw_next_line(s, invite_buf_end);
390                                 append_str(d, s1, s - s1);
391                                 break;
392
393                         case HDR_REQUIRE_T:
394                         case HDR_PROXYREQUIRE_T:
395                                 /* skip this line */
396                                 s = lw_next_line(s, invite_buf_end);
397                                 break;
398
399                         case HDR_CONTENTLENGTH_T:
400                                 /* copy hf name with 0 value */
401                                 append_str(d, s1, s - s1);
402                                 append_str(d, ": 0" CRLF, 3 + CRLF_LEN);
403                                 /* move the pointer to the next line */
404                                 s = lw_next_line(s, invite_buf_end);
405                                 break;
406
407                         case HDR_EOH_T:
408                                 /* end of SIP message found */
409                                 /* add reason if needed */
410                                 if (reason_len) {
411                                         if (likely(reason->cause > 0)) {
412                                                 append_str(d, REASON_PREFIX, REASON_PREFIX_LEN);
413                                                 code_len=ushort2sbuf(reason->cause, d,
414                                                                                 cancel_buf_len-(int)(d-cancel_buf));
415                                                 if (unlikely(code_len==0))
416                                                         BUG("not enough space to write reason code");
417                                                 d+=code_len;
418                                                 if (reason->u.text.s){
419                                                         append_str(d, REASON_TEXT, REASON_TEXT_LEN);
420                                                         *d='"'; d++;
421                                                         append_str(d, reason->u.text.s,
422                                                                                         reason->u.text.len);
423                                                         *d='"'; d++;
424                                                 }
425                                                 append_str(d, CRLF, CRLF_LEN);
426                                         } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
427                                                 /* FIXME: handle cancel */
428                                         }
429                                 }
430                                 append_str(d, CRLF, CRLF_LEN);
431                                 *len = d - cancel_buf;
432                                 /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */
433                                 return cancel_buf;
434
435                         default:
436                                 s = lw_next_line(s, invite_buf_end);
437
438                                 if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len
439                                 && (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end)
440                                 && (strncasecmp(s1,
441                                                 cfg_get(tm, tm_cfg, ac_extra_hdrs).s,
442                                                 cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)
443                                 ) {
444                                         append_str(d, s1, s - s1);
445                                 } /* else skip this line */
446                                 break;
447                 }
448         }
449
450         /* HDR_EOH_T was not found in the buffer, the message is corrupt */
451         LOG(L_ERR, "ERROR: build_local_reparse: HDR_EOH_T was not found\n");
452
453         shm_free(cancel_buf);
454 error:
455         LOG(L_ERR, "ERROR: build_local_reparse: cannot build %.*s request\n", method_len, method);
456         return NULL;
457
458 }
459
460
461 typedef struct rte {
462         rr_t* ptr;
463         /* 'ptr' above doesn't point to a mem chunk linked to a sip_msg, so it
464          * won't be free'd along with it => it must be free'd "manually" */
465         int free_rr;
466         struct rte* next;
467 } rte_t;
468
469          
470 static inline void free_rte_list(struct rte* list)
471 {
472         struct rte* ptr;
473         
474         while(list) {
475                 ptr = list;
476                 list = list->next;
477                 if (ptr->free_rr)
478                         free_rr(&ptr->ptr);
479                 pkg_free(ptr);
480         }
481 }
482
483
484 static inline int calc_routeset_len(struct rte* list, str* contact)
485 {
486         struct rte* ptr;
487         int ret;
488         
489         if (list || contact) {
490                 ret = ROUTE_PREFIX_LEN + CRLF_LEN;
491         } else {
492                 return 0;
493         }
494         
495         ptr = list;
496         while(ptr) {
497                 if (ptr != list) {
498                         ret += ROUTE_SEPARATOR_LEN;
499                 }
500                 ret += ptr->ptr->len;
501                 ptr = ptr->next;
502         }
503         
504         if (contact) {
505                 if (list) ret += ROUTE_SEPARATOR_LEN;
506                 ret += 2 + contact->len;
507         }
508         
509         return ret;
510 }
511
512
513      /*
514       * Print the route set
515       */
516 static inline char* print_rs(char* p, struct rte* list, str* contact)
517 {
518         struct rte* ptr;
519         
520         if (list || contact) {
521                 memapp(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
522         } else {
523                 return p;
524         }
525         
526         ptr = list;
527         while(ptr) {
528                 if (ptr != list) {
529                         memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
530                 }
531                 
532                 memapp(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len);
533                 ptr = ptr->next;
534         }
535         
536         if (contact) {
537                 if (list) memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
538                 *p++ = '<';
539                 append_str(p, contact->s, contact->len);
540                 *p++ = '>';
541         }
542         
543         memapp(p, CRLF, CRLF_LEN);
544         return p;
545 }
546
547
548      /*
549       * Parse Contact header field body and extract URI
550       * Does not parse headers !
551       */
552 static inline int get_contact_uri(struct sip_msg* msg, str* uri)
553 {
554         contact_t* c;
555         
556         uri->len = 0;
557         if (!msg->contact) return 1;
558         
559         if (parse_contact(msg->contact) < 0) {
560                 LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");
561                 return -1;
562         }
563         
564         c = ((contact_body_t*)msg->contact->parsed)->contacts;
565         
566         if (!c) {
567                 LOG(L_ERR, "get_contact_uri: Empty body or * contact\n");
568                 return -2;
569         }
570         
571         *uri = c->uri;
572         return 0;
573 }
574
575 /**
576  * Extract route set from the message (out of Record-Route, if reply, OR
577  * Route, if request).
578  * The route set is returned into the "UAC-format" (keep order for Rs, reverse
579  * RRs).
580  */
581 static inline int get_uac_rs(sip_msg_t *msg, int is_req, struct rte **rtset)
582 {
583         struct hdr_field* ptr;
584         rr_t *p, *new_p;
585         struct rte *t, *head, *old_head;
586
587         head = 0;
588         for (ptr = is_req ? msg->route : msg->record_route; ptr; ptr = ptr->next) {
589                 switch (ptr->type) {
590                         case HDR_RECORDROUTE_T:
591                                 if (is_req)
592                                         continue;
593                                 break;
594                         case HDR_ROUTE_T:
595                                 if (! is_req)
596                                         continue;
597                                 break;
598                         default:
599                                 continue;
600                 }
601                 if (parse_rr(ptr) < 0) {
602                         ERR("failed to parse Record-/Route HF (%d).\n", ptr->type);
603                         goto err;
604                 }
605                         
606                 p = (rr_t*)ptr->parsed;
607                 while(p) {
608                         if (! (t = pkg_malloc(sizeof(struct rte)))) {
609                                 ERR("out of pkg mem (asked for: %d).\n",
610                                                 (int)sizeof(struct rte));
611                                 goto err;
612                         }
613                         if (is_req) {
614                                 /* in case of requests, the sip_msg structure is free'd before
615                                  * rte list is evaluated => must do a copy of it */
616                                 if (duplicate_rr(&new_p, p) < 0) {
617                                         pkg_free(t);
618                                         ERR("failed to duplicate RR");
619                                         goto err;
620                                 }
621                                 t->ptr = new_p;
622                         } else {
623                                 t->ptr = p;
624                         }
625                         t->free_rr = is_req;
626                         t->next = head;
627                         head = t;
628                         p = p->next;
629                 }
630         }
631
632         if (is_req) {
633                 /* harvesting the R/RR HF above inserts at head, which suites RRs (as
634                  * they must be reversed, anyway), but not Rs => reverse once more */
635                 old_head = head;
636                 head = 0;
637                 while (old_head) {
638                         t = old_head;
639                         old_head = old_head->next;
640                         t->next = head;
641                         head = t;
642                 }
643         }
644
645         *rtset = head;
646         return 0;
647 err:
648         free_rte_list(head);
649         return -1;
650 }
651
652
653 static inline unsigned short uri2port(const struct sip_uri *puri)
654 {
655         if (puri->port.s) {
656                 return puri->port_no;
657         } else switch (puri->type) {
658                 case SIP_URI_T:
659                 case TEL_URI_T:
660                         if (puri->transport_val.len == sizeof("TLS") - 1) {
661                                 unsigned trans;
662                                 trans = puri->transport_val.s[0] | 0x20; trans <<= 8;
663                                 trans |= puri->transport_val.s[1] | 0x20; trans <<= 8;
664                                 trans |= puri->transport_val.s[2] | 0x20;
665                                 if (trans == 0x746C73) /* t l s */
666                                         return SIPS_PORT;
667                         }
668                         return SIP_PORT;
669                 case SIPS_URI_T:
670                 case TELS_URI_T:
671                         return SIPS_PORT;
672                 default:
673                         BUG("unexpected URI type %d.\n", puri->type);
674         }
675         return 0;
676 }
677
678 /**
679  * Evaluate if next hop is a strict or loose router, by looking at the
680  * retr. buffer of the original INVITE.
681  * Assumes:
682  *      orig_inv is a parsed SIP message;
683  *      rtset is not NULL.
684  * @return:
685  *      F_RB_NH_LOOSE : next hop was loose router;
686  *      F_RB_NH_STRICT: nh is strict;
687  *      0 on error.
688  */
689 static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset,
690                 const struct dest_info *dst_inv, str *contact)
691 {
692         struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri;
693         struct ip_addr *uri_ia;
694         union sockaddr_union uri_sau;
695         unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port;
696         rte_t *last_r;
697 #ifdef TM_LOC_ACK_DO_REV_DNS
698         struct ip_addr ia;
699         struct hostent *he;
700         char **alias;
701 #endif
702
703 #define PARSE_URI(_str_, _uri_) \
704         do { \
705                 /* parse_uri() 0z the puri */ \
706                 if (parse_uri((_str_)->s, \
707                                 (_str_)->len, _uri_) < 0) { \
708                         ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \
709                         return 0; \
710                 } \
711         } while (0)
712
713 #define HAS_LR(_rte_) \
714         ({ \
715                 PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \
716                 puri.lr.s; \
717         })
718
719 #define URI_PORT(_puri_, _port) \
720         do { \
721                 if (! (_port = uri2port(_puri_))) \
722                         return 0; \
723         } while (0)
724
725         /* examine the easy/fast & positive cases foremost */
726
727         /* [1] check if 1st route lacks ;lr */
728         DEBUG("checking lack of ';lr' in 1st route.\n");
729         if (! HAS_LR(rtset))
730                 return F_RB_NH_STRICT;
731         topr_uri = puri; /* save 1st route's URI */
732
733         /* [2] check if last route shows ;lr */
734         DEBUG("checking presence of ';lr' in last route.\n");
735         for (last_r = rtset; last_r->next; last_r = last_r->next)
736                 /* scroll down to last route */
737                 ;
738         if (HAS_LR(last_r))
739                 return F_RB_NH_LOOSE;
740
741         /* [3] 1st route has ;lr -> check if the destination of original INV
742          * equals the address provided by this route; if does -> loose */
743         DEBUG("checking INVITE's destination against its first route.\n");
744         URI_PORT(&topr_uri, uri_port);
745         if (! (dst_port = su_getport((void *)&dst_inv->to)))
746                 return 0; /* not really expected */
747         if (dst_port != uri_port)
748                 return F_RB_NH_STRICT;
749         /* if 1st route contains an IP address, comparing it against .dst */
750         if ((uri_ia = str2ip(&topr_uri.host))
751 #ifdef USE_IPV6
752                         || (uri_ia = str2ip6(&topr_uri.host))
753 #endif
754                         ) {
755                 /* we have an IP address in route -> comparison can go swiftly */
756                 if (init_su(&uri_sau, uri_ia, uri_port) < 0)
757                         return 0; /* not really expected */
758                 if (su_cmp(&uri_sau, (void *)&dst_inv->to))
759                         /* ;lr and sent there */
760                         return F_RB_NH_LOOSE;
761                 else
762                         /* ;lr and NOT sent there (probably sent to RURI address) */
763                         return F_RB_NH_STRICT;
764         } else {
765                 /*if 1st route contains a name, rev resolve the .dst and compare*/
766                 INFO("Failed to decode string '%.*s' in route set element as IP "
767                                 "address. Trying name resolution.\n",STR_FMT(&topr_uri.host));
768
769         /* TODO: alternatively, rev name and compare against dest. IP.  */
770 #ifdef TM_LOC_ACK_DO_REV_DNS
771                 ia.af = 0;
772                 su2ip_addr(&ia, (void *)&dst_inv->to);
773                 if (! ia.af)
774                         return 0; /* not really expected */
775                 if ((he = rev_resolvehost(&ia))) {
776                         if ((strlen(he->h_name) == topr_uri.host.len) &&
777                                         (memcmp(he->h_name, topr_uri.host.s, 
778                                                         topr_uri.host.len) == 0))
779                                 return F_RB_NH_LOOSE;
780                         for (alias = he->h_aliases; *alias; alias ++)
781                                 if ((strlen(*alias) == topr_uri.host.len) &&
782                                                 (memcmp(*alias, topr_uri.host.s, 
783                                                                 topr_uri.host.len) == 0))
784                                         return F_RB_NH_LOOSE;
785                         return F_RB_NH_STRICT;
786                 } else {
787                         INFO("failed to resolve address '%s' to a name.\n", 
788                                         ip_addr2a(&ia));
789                 }
790 #endif
791         }
792
793         WARN("failed to establish with certainty the type of next hop; trying an"
794                         " educated guess.\n");
795
796         /* [4] compare (possibly updated) remote target to original RURI; if
797          * equal, a strict router's address wasn't filled in as RURI -> loose */
798         DEBUG("checking remote target against INVITE's RURI.\n");
799         PARSE_URI(contact, &cont_uri);
800         PARSE_URI(GET_RURI(orig_inv), &inv_ruri);
801         URI_PORT(&cont_uri, cont_port);
802         URI_PORT(&inv_ruri, inv_port);
803         if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) &&
804                         (memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0))
805                 return F_RB_NH_LOOSE;
806
807         /* [5] compare (possibly updated) remote target to last route; if equal, 
808          * strict router's address might have been filled as RURI and remote
809          * target appended to route set -> strict */
810         DEBUG("checking remote target against INVITE's last route.\n");
811         PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri);
812         URI_PORT(&lastr_uri, lastr_port);
813         if ((cont_port == lastr_port) && 
814                         (cont_uri.host.len == lastr_uri.host.len) &&
815                         (memcmp(cont_uri.host.s, lastr_uri.host.s, 
816                                         lastr_uri.host.len) == 0))
817                 return F_RB_NH_STRICT;
818
819         WARN("failed to establish the type of next hop; assuming loose router.\n");
820         return F_RB_NH_LOOSE;
821
822 #undef PARSE_URI
823 #undef HAS_LR
824 #undef URI_PORT
825 }
826
827 /**
828  * Evaluates the routing elements in locally originated request or reply to
829  * locally originated request.
830  * If original INVITE was in-dialog (had to-tag), it uses the
831  * routes present there (b/c the 2xx for it does not have a RR set, normally).
832  * Otherwise, use the reply (b/c the INVITE does not have yet the complete 
833  * route set).
834  *
835  * @return: negative for failure; out params:
836  *  - list: route set;
837  *  - ruri: RURI to be used in ACK;
838  *  - nexthop: where to first send the ACK.
839  *
840  *  NOTE: assumes rpl's parsed to EOF!
841  *
842  */
843 static int eval_uac_routing(sip_msg_t *rpl, const struct retr_buf *inv_rb, 
844                 str* contact, struct rte **list, str *ruri, str *next_hop)
845 {
846         sip_msg_t orig_inv, *sipmsg; /* reparse original INVITE */
847         rte_t *t, *prev_t, *rtset = NULL;
848         int is_req;
849         struct sip_uri puri;
850         static size_t chklen;
851         int ret = -1;
852         
853         /* parse the retr. buffer */
854         memset(&orig_inv, 0, sizeof(struct sip_msg));
855         orig_inv.buf = inv_rb->buffer;
856         orig_inv.len = inv_rb->buffer_len;
857         DEBUG("reparsing retransmission buffer of original INVITE:\n%.*s\n",
858                         (int)orig_inv.len, orig_inv.buf);
859         if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) != 0) {
860                 ERR("failed to parse retr buffer (weird!): \n%.*s\n",
861                                 (int)orig_inv.len, orig_inv.buf);
862                 return -1;
863         }
864
865         /* check if we need to look at request or reply */
866         if ((parse_headers(&orig_inv, HDR_TO_F, 0) < 0) || (! orig_inv.to)) {
867                 /* the bug is at message assembly */
868                 BUG("failed to parse INVITE retr. buffer and/or extract 'To' HF:"
869                                 "\n%.*s\n", (int)orig_inv.len, orig_inv.buf);
870                 goto end;
871         }
872         if (((struct to_body *)orig_inv.to->parsed)->tag_value.len) {
873                 DEBUG("building ACK for in-dialog INVITE (using RS in orig. INV.)\n");
874                 if (parse_headers(&orig_inv, HDR_EOH_F, 0) < 0) {
875                         BUG("failed to parse INVITE retr. buffer to EOH:"
876                                         "\n%.*s\n", (int)orig_inv.len, orig_inv.buf);
877                         goto end;
878                 }
879                 sipmsg = &orig_inv;
880                 is_req = 1;
881         } else {
882                 DEBUG("building ACK for out-of-dialog INVITE (using RS in RR set).\n");
883                 sipmsg = rpl;
884                 is_req = 0;
885         }
886
887         /* extract the route set */
888         if (get_uac_rs(sipmsg, is_req, &rtset) < 0) {
889                 ERR("failed to extract route set.\n");
890                 goto end;
891         }
892
893         if (! rtset) { /* No routes */
894                 *ruri = *contact;
895                 *next_hop = *contact;
896         } else if (! is_req) { /* out of dialog req. */
897                 if (parse_uri(rtset->ptr->nameaddr.uri.s, rtset->ptr->nameaddr.uri.len,
898                                 &puri) < 0) {
899                         ERR("failed to parse first route in set.\n");
900                         goto end;
901                 }
902                 
903                 if (puri.lr.s) { /* Next hop is loose router */
904                         *ruri = *contact;
905                         *next_hop = rtset->ptr->nameaddr.uri;
906                 } else { /* Next hop is strict router */
907                         *ruri = rtset->ptr->nameaddr.uri;
908                         *next_hop = *ruri;
909                         /* consume first route, b/c it will be put in RURI */
910                         t = rtset;
911                         rtset = rtset->next;
912                         pkg_free(t);
913                 }
914         } else {
915                 unsigned long route_flags = inv_rb->flags;
916                 DEBUG("UAC rb flags: 0x%x.\n", (unsigned int)route_flags);
917 eval_flags:
918                 switch (route_flags & (F_RB_NH_LOOSE|F_RB_NH_STRICT)) {
919                 case 0:
920                         WARN("calculate_hooks() not called when built the local UAC of "
921                                         "in-dialog request, or called with empty route set.\n");
922                         /* try to figure out what kind of hop is the next one
923                          * (strict/loose) by reading the original invite */
924                         if ((route_flags = nhop_type(&orig_inv, rtset, &inv_rb->dst, 
925                                         contact))) {
926                                 DEBUG("original request's next hop type evaluated to: 0x%x.\n",
927                                                 (unsigned int)route_flags);
928                                 goto eval_flags;
929                         } else {
930                                 ERR("failed to establish what kind of router the next "
931                                                 "hop is.\n");
932                                 goto end;
933                         }
934                         break;
935                 case F_RB_NH_LOOSE:
936                         *ruri = *contact;
937                         *next_hop = rtset->ptr->nameaddr.uri;
938                         break;
939                 case F_RB_NH_STRICT:
940                         /* find ptr to last route body that contains the (possibly) old 
941                          * remote target 
942                          */
943                         for (t = rtset, prev_t = t; t->next; prev_t = t, t = t->next)
944                                 ;
945                         if ((t->ptr->len == contact->len) && 
946                                         (memcmp(t->ptr->nameaddr.name.s, contact->s, 
947                                                         contact->len) == 0)){
948                                 /* the remote target didn't update -> keep the whole route set,
949                                  * including the last entry */
950                                 /* do nothing */
951                         } else {
952                                 /* trash last entry and replace with new remote target */
953                                 free_rte_list(t);
954                                 /* compact the rr_t struct along with rte. this way, free'ing
955                                  * it can be done along with rte chunk, independent of Route
956                                  * header parser's allocator (using pkg/shm) */
957                                 chklen = sizeof(struct rte) + sizeof(rr_t);
958                                 if (! (t = pkg_malloc(chklen))) {
959                                         ERR("out of pkg memory (%d required)\n", (int)chklen);
960                                         goto end;
961                                 }
962                                 /* this way, .free_rr is also set to 0 (!!!) */
963                                 memset(t, 0, chklen); 
964                                 ((rr_t *)&t[1])->nameaddr.name = *contact;
965                                 ((rr_t *)&t[1])->len = contact->len;
966                                 /* chain the new route elem in set */
967                                 if (prev_t == rtset)
968                                         /*there is only one elem in route set: the remote target*/
969                                         rtset = t;
970                                 else
971                                         prev_t->next = t;
972                         }
973
974                         *ruri = *GET_RURI(&orig_inv); /* reuse original RURI */
975                         *next_hop = *ruri;
976                         break;
977                 default:
978                         /* probably a mem corruption */
979                         BUG("next hop of original request marked as both loose and strict"
980                                         " router (buffer: %.*s).\n", inv_rb->buffer_len, 
981                                         inv_rb->buffer);
982 #ifdef EXTRA_DEBUG
983                         abort();
984 #else
985                         goto end;
986 #endif
987                 }
988         }
989
990         *list = rtset;
991         /* all went well */
992         ret = 0;
993 end:
994         free_sip_msg(&orig_inv);
995         if (ret < 0)
996                 free_rte_list(rtset);
997         return ret;
998 }
999
1000      /*
1001       * The function creates an ACK to 200 OK. Route set will be created
1002       * and parsed and the dst parameter will contain the destination to which 
1003           * the request should be send. The function is used by tm when it 
1004           * generates local ACK to 200 OK (on behalf of applications using uac)
1005       */
1006 char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, 
1007                                         unsigned int branch, str *hdrs, str *body,
1008                                         unsigned int *len, struct dest_info* dst)
1009 {
1010         char *req_buf, *p, *via;
1011         unsigned int via_len;
1012         char branch_buf[MAX_BRANCH_PARAM_LEN];
1013         int branch_len;
1014         str branch_str;
1015         struct hostport hp;
1016         struct rte* list;
1017         str contact, ruri, *cont;
1018         str next_hop;
1019         str body_len;
1020         str _to, *to = &_to;
1021 #ifdef USE_DNS_FAILOVER
1022         struct dns_srv_handle dns_h;
1023 #endif
1024 #ifdef WITH_AS_SUPPORT
1025         /* With AS support, TM allows for external modules to generate building of
1026          * the ACK; in this case, the ACK's retransmission buffer is built once
1027          * and kept in memory (to help when retransmitted 2xx are received and ACK
1028          * must be resent).
1029          * Allocation of the string raw buffer that holds the ACK is piggy-backed
1030          * with allocation of the retransmission buffer (since both have the same
1031          * life-cycle): both the string buffer and retransm. buffer are placed 
1032          * into the same allocated chunk of memory (retr. buffer first, string 
1033          * buffer follows).In this case, the 'len' param is used as in-out 
1034          * parameter: 'in' to give the extra space needed by the retr. buffer,
1035          * 'out' to return the lenght of the allocated string buffer.
1036          */
1037         unsigned offset = *len;
1038 #endif
1039         
1040         if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) {
1041                 ERR("Error while parsing headers.\n");
1042                 return 0;
1043         } else {
1044                 _to.s = rpl->to->name.s;
1045                 _to.len = rpl->to->len;
1046         }
1047         
1048         if (get_contact_uri(rpl, &contact) < 0) {
1049                 return 0;
1050         }
1051         
1052         if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact, 
1053                         &list, &ruri, &next_hop) < 0) {
1054                 ERR("failed to evaluate routing elements.\n");
1055                 return 0;
1056         }
1057         DEBUG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri), 
1058                         STR_FMT(&next_hop));
1059
1060         if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
1061                      /* contact != ruri means that the next
1062                       * hop is a strict router, cont will be non-zero
1063                       * and print_routeset will append it at the end
1064                       * of the route set
1065                       */
1066                 cont = &contact;
1067         } else {
1068                      /* Next hop is a loose router, nothing to append */
1069                 cont = 0;
1070         }
1071         
1072              /* method, separators, version: "ACK sip:p2@iptel.org SIP/2.0" */
1073         *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
1074         *len += ruri.len;
1075         
1076         /* dst */
1077         switch(cfg_get(tm, tm_cfg, local_ack_mode)){
1078                 case 1:
1079                         /* send the local 200 ack to the same dst as the corresp. invite*/
1080                         *dst=Trans->uac[branch].request.dst;
1081                         break;
1082                 case 2: 
1083                         /* send the local 200 ack to the same dst as the 200 reply source*/
1084                         init_dst_from_rcv(dst, &rpl->rcv);
1085                         dst->send_flags=rpl->fwd_send_flags;
1086                         break;
1087                 case 0:
1088                 default:
1089                         /* rfc conformant behaviour: use the next_hop determined from the
1090                            contact and the route set */
1091 #ifdef USE_DNS_FAILOVER
1092                 if (cfg_get(core, core_cfg, use_dns_failover)){
1093                         dns_srv_handle_init(&dns_h);
1094                         if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
1095                                         (dst->send_sock==0)){
1096                                 dns_srv_handle_put(&dns_h);
1097                                 LOG(L_ERR, "build_dlg_ack: no socket found\n");
1098                                 goto error;
1099                         }
1100                         dns_srv_handle_put(&dns_h); /* not needed any more */
1101                 }else{
1102                         if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
1103                                         (dst->send_sock==0)){
1104                                 LOG(L_ERR, "build_dlg_ack: no socket found\n");
1105                                 goto error;
1106                         }
1107                 }
1108 #else /* USE_DNS_FAILOVER */
1109                 if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
1110                                 (dst->send_sock==0)){
1111                                 LOG(L_ERR, "build_dlg_ack: no socket found\n");
1112                         goto error;
1113                 }
1114 #endif /* USE_DNS_FAILOVER */
1115                 break;
1116         }
1117         
1118          /* via */
1119         if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
1120         branch_str.s = branch_buf;
1121         branch_str.len = branch_len;
1122         set_hostport(&hp, 0);
1123         via = via_builder(&via_len, dst, &branch_str, 0, &hp);
1124         if (!via) {
1125                 LOG(L_ERR, "build_dlg_ack: No via header got from builder\n");
1126                 goto error;
1127         }
1128         *len+= via_len;
1129         
1130              /*headers*/
1131         *len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;
1132         
1133              /* copy'n'paste Route headers */
1134         
1135         *len += calc_routeset_len(list, cont);
1136         
1137              /* User Agent */
1138         if (server_signature) *len += user_agent_hdr.len + CRLF_LEN;
1139                 /* extra headers */
1140         if (hdrs)
1141                 *len += hdrs->len;
1142                 /* body */
1143         if (body) {
1144                 body_len.s = int2str(body->len, &body_len.len);
1145                 *len += body->len;
1146         } else {
1147                 body_len.len = 0;
1148                 body_len.s = NULL; /*4gcc*/
1149                 *len += 1; /* for the (Cont-Len:) `0' */
1150         }
1151              /* Content Length, EoM */
1152         *len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN;
1153
1154 #if WITH_AS_SUPPORT
1155         req_buf = shm_malloc(offset + *len + 1);
1156         req_buf += offset;
1157 #else
1158         req_buf = shm_malloc(*len + 1);
1159 #endif
1160         if (!req_buf) {
1161                 ERR("Cannot allocate memory (%u+1)\n", *len);
1162                 goto error01;
1163         }
1164         p = req_buf;
1165         
1166         append_str( p, ACK, ACK_LEN );
1167         append_str( p, " ", 1 );
1168         append_str(p, ruri.s, ruri.len);
1169         append_str( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
1170          
1171              /* insert our via */
1172         append_str(p, via, via_len);
1173         
1174              /*other headers*/
1175         append_str(p, Trans->from.s, Trans->from.len);
1176         append_str(p, Trans->callid.s, Trans->callid.len);
1177         append_str(p, to->s, to->len);
1178         
1179         append_str(p, Trans->cseq_n.s, Trans->cseq_n.len);
1180         append_str( p, " ", 1 );
1181         append_str( p, ACK, ACK_LEN);
1182         append_str(p, CRLF, CRLF_LEN);
1183         
1184              /* Routeset */
1185         p = print_rs(p, list, cont);
1186         
1187              /* User Agent header */
1188         if (server_signature) {
1189                 append_str(p, user_agent_hdr.s, user_agent_hdr.len);
1190                 append_str(p, CRLF, CRLF_LEN);
1191         }
1192         
1193         /* extra headers */
1194         if (hdrs)
1195                 append_str(p, hdrs->s, hdrs->len);
1196         
1197              /* Content Length, EoH, (body) */
1198         if (body) {
1199                 append_str(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
1200                 append_str(p, body_len.s, body_len.len);
1201                 append_str(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN + 
1202                                 CRLF_LEN);
1203                 append_str(p, body->s, body->len);
1204         } else {
1205                 append_str(p, CONTENT_LENGTH "0" CRLF CRLF, 
1206                                 CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
1207         }
1208
1209         /* EoM */
1210         *p = 0;
1211         
1212         pkg_free(via);
1213         free_rte_list(list);
1214         return req_buf;
1215         
1216  error01:
1217         pkg_free(via);
1218  error:
1219         free_rte_list(list);
1220         return 0;
1221 }
1222
1223
1224 /*
1225  * Convert length of body into asciiz
1226  */
1227 static inline int print_content_length(str* dest, str* body)
1228 {
1229         static char content_length[10];
1230         int len;
1231         int b_len;
1232         char* tmp;
1233
1234              /* Print Content-Length */
1235         b_len=body?body->len:0;
1236         tmp = int2str(b_len, &len);
1237         if (len >= sizeof(content_length)) {
1238                 LOG(L_ERR, "ERROR: print_content_length: content_len too big\n");
1239                 dest->s = 0;
1240                 dest->len = 0;
1241                 return -1;
1242         }
1243         memcpy(content_length, tmp, len); 
1244         dest->s = content_length;
1245         dest->len = len;
1246         return 0;
1247 }
1248
1249
1250 /*
1251  * Convert CSeq number into asciiz
1252  */
1253 static inline int print_cseq_num(str* _s, dlg_t* _d)
1254 {
1255         static char cseq[INT2STR_MAX_LEN];
1256         char* tmp;
1257         int len;
1258
1259         tmp = int2str(_d->loc_seq.value, &len);
1260         if (len > sizeof(cseq)) {
1261                 LOG(L_ERR, "print_cseq_num: cseq too big\n");
1262                 return -1;
1263         }
1264         
1265         memcpy(cseq, tmp, len);
1266         _s->s = cseq;
1267         _s->len = len;
1268         return 0;
1269 }
1270
1271
1272 /*
1273  * Create Via header
1274  */
1275 static inline int assemble_via(str* dest, struct cell* t, 
1276                                                                 struct dest_info* dst, int branch)
1277 {
1278         static char branch_buf[MAX_BRANCH_PARAM_LEN];
1279         char* via;
1280         int len;
1281         unsigned int via_len;
1282         str branch_str;
1283         struct hostport hp;
1284
1285         if (!t_calc_branch(t, branch, branch_buf, &len)) {
1286                 LOG(L_ERR, "ERROR: assemble_via: branch calculation failed\n");
1287                 return -1;
1288         }
1289         
1290         branch_str.s = branch_buf;
1291         branch_str.len = len;
1292
1293 #ifdef XL_DEBUG
1294         printf("!!!proto: %d\n", sock->proto);
1295 #endif
1296
1297         set_hostport(&hp, 0);
1298         via = via_builder(&via_len, dst, &branch_str, 0, &hp);
1299         if (!via) {
1300                 LOG(L_ERR, "assemble_via: via building failed\n");
1301                 return -2;
1302         }
1303         
1304         dest->s = via;
1305         dest->len = via_len;
1306         return 0;
1307 }
1308
1309
1310 /*
1311  * Print Request-URI
1312  */
1313 static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struct cell* t, int branch)
1314 {
1315         memapp(w, method->s, method->len); 
1316         memapp(w, " ", 1); 
1317
1318         t->uac[branch].uri.s = w; 
1319         t->uac[branch].uri.len = dialog->hooks.request_uri->len;
1320
1321         memapp(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len); 
1322         memapp(w, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
1323
1324         return w;
1325 }
1326
1327
1328 /*
1329  * Print To header field
1330  */
1331 static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
1332 {
1333         t->to.s = w;
1334         t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN;
1335
1336         memapp(w, TO, TO_LEN);
1337         memapp(w, dialog->rem_uri.s, dialog->rem_uri.len);
1338
1339         if (dialog->id.rem_tag.len) {
1340                 t->to.len += TOTAG_LEN + dialog->id.rem_tag.len ;
1341                 memapp(w, TOTAG, TOTAG_LEN);
1342                 memapp(w, dialog->id.rem_tag.s, dialog->id.rem_tag.len);
1343         }
1344
1345         memapp(w, CRLF, CRLF_LEN);
1346         return w;
1347 }
1348
1349
1350 /*
1351  * Print From header field
1352  */
1353 static inline char* print_from(char* w, dlg_t* dialog, struct cell* t)
1354 {
1355         t->from.s = w;
1356         t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN;
1357
1358         memapp(w, FROM, FROM_LEN);
1359         memapp(w, dialog->loc_uri.s, dialog->loc_uri.len);
1360
1361         if (dialog->id.loc_tag.len) {
1362                 t->from.len += FROMTAG_LEN + dialog->id.loc_tag.len;
1363                 memapp(w, FROMTAG, FROMTAG_LEN);
1364                 memapp(w, dialog->id.loc_tag.s, dialog->id.loc_tag.len);
1365         }
1366
1367         memapp(w, CRLF, CRLF_LEN);
1368         return w;
1369 }
1370
1371
1372 /*
1373  * Print CSeq header field
1374  */
1375 char* print_cseq_mini(char* target, str* cseq, str* method) {
1376         memapp(target, CSEQ, CSEQ_LEN);
1377         memapp(target, cseq->s, cseq->len);
1378         memapp(target, " ", 1);
1379         memapp(target, method->s, method->len);
1380         return target;
1381 }
1382
1383 static inline char* print_cseq(char* w, str* cseq, str* method, struct cell* t)
1384 {
1385         t->cseq_n.s = w; 
1386         /* don't include method name and CRLF -- subsequent
1387          * local requests ACK/CANCEL will add their own */
1388         t->cseq_n.len = CSEQ_LEN + cseq->len; 
1389         w = print_cseq_mini(w, cseq, method);
1390         return w;
1391 }
1392
1393 /*
1394  * Print Call-ID header field
1395  * created an extra function for pure header field creation, that is used by t_cancel for 
1396  * t_uac_cancel FIFO function.
1397  */
1398 char* print_callid_mini(char* target, str callid) {
1399         memapp(target, CALLID, CALLID_LEN);
1400         memapp(target, callid.s, callid.len);
1401         memapp(target, CRLF, CRLF_LEN);
1402         return target;
1403 }
1404
1405 static inline char* print_callid(char* w, dlg_t* dialog, struct cell* t)
1406 {
1407         /* begins with CRLF, not included in t->callid, don`t know why...?!? */
1408         memapp(w, CRLF, CRLF_LEN);
1409         t->callid.s = w;
1410         t->callid.len = CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;
1411
1412         w = print_callid_mini(w, dialog->id.call_id);
1413         return w;
1414 }
1415
1416
1417 /*
1418  * Create a request
1419  */
1420 char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int branch, 
1421                         struct cell *t, int* len, struct dest_info* dst)
1422 {
1423         char* buf, *w;
1424         str content_length, cseq, via;
1425
1426         if (!method || !dialog) {
1427                 LOG(L_ERR, "build_uac_req(): Invalid parameter value\n");
1428                 return 0;
1429         }
1430         if (print_content_length(&content_length, body) < 0) {
1431                 LOG(L_ERR, "build_uac_req(): Error while printing content-length\n");
1432                 return 0;
1433         }
1434         if (print_cseq_num(&cseq, dialog) < 0) {
1435                 LOG(L_ERR, "build_uac_req(): Error while printing CSeq number\n");
1436                 return 0;
1437         }
1438         *len = method->len + 1 + dialog->hooks.request_uri->len + 1 + SIP_VERSION_LEN + CRLF_LEN;
1439
1440         if (assemble_via(&via, t, dst, branch) < 0) {
1441                 LOG(L_ERR, "build_uac_req(): Error while assembling Via\n");
1442                 return 0;
1443         }
1444         *len += via.len;
1445
1446         *len += TO_LEN + dialog->rem_uri.len
1447                 + (dialog->id.rem_tag.len ? (TOTAG_LEN + dialog->id.rem_tag.len) : 0) + CRLF_LEN;    /* To */
1448         *len += FROM_LEN + dialog->loc_uri.len
1449                 + (dialog->id.loc_tag.len ? (FROMTAG_LEN + dialog->id.loc_tag.len) : 0) + CRLF_LEN;  /* From */
1450         *len += CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;                                      /* Call-ID */
1451         *len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN;                                    /* CSeq */
1452         *len += calculate_routeset_length(dialog);                                                   /* Route set */
1453         *len += CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN; /* Content-
1454                                                                                                                                          Length */
1455         *len += (server_signature ? (user_agent_hdr.len + CRLF_LEN) : 0);                                /* Signature */
1456         *len += (headers ? headers->len : 0);                                                        /* Additional headers */
1457         *len += (body ? body->len : 0);                                                              /* Message body */
1458         *len += CRLF_LEN;                                                                            /* End of Header */
1459
1460         buf = shm_malloc(*len + 1);
1461         if (!buf) {
1462                 LOG(L_ERR, "build_uac_req(): no shmem\n");
1463                 goto error;
1464         }
1465         
1466         w = buf;
1467
1468         w = print_request_uri(w, method, dialog, t, branch);  /* Request-URI */
1469         memapp(w, via.s, via.len);                            /* Top-most Via */
1470         w = print_to(w, dialog, t);                           /* To */
1471         w = print_from(w, dialog, t);                         /* From */
1472         w = print_cseq(w, &cseq, method, t);                  /* CSeq */
1473         w = print_callid(w, dialog, t);                       /* Call-ID */
1474         w = print_routeset(w, dialog);                        /* Route set */
1475
1476      /* Content-Length */
1477         memapp(w, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
1478         memapp(w, content_length.s, content_length.len);
1479         memapp(w, CRLF, CRLF_LEN);
1480         
1481              /* Server signature */
1482         if (server_signature) {
1483                 memapp(w, user_agent_hdr.s, user_agent_hdr.len);
1484                 memapp(w, CRLF, CRLF_LEN);
1485         }
1486         if (headers) memapp(w, headers->s, headers->len);
1487         memapp(w, CRLF, CRLF_LEN);
1488         if (body) memapp(w, body->s, body->len);
1489
1490 #ifdef EXTRA_DEBUG
1491         assert(w-buf == *len);
1492 #endif
1493
1494         pkg_free(via.s);
1495         return buf;
1496
1497  error:
1498         pkg_free(via.s);
1499         return 0;
1500 }
1501
1502
1503 int t_calc_branch(struct cell *t, 
1504         int b, char *branch, int *branch_len)
1505 {
1506         return syn_branch ?
1507                 branch_builder( t->hash_index,
1508                         t->label, 0,
1509                         b, branch, branch_len )
1510                 : branch_builder( t->hash_index,
1511                         0, t->md5,
1512                         b, branch, branch_len );
1513 }
1514