Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

t_msgbuilder.c

Go to the documentation of this file.
00001 /*
00002  * $Id: t_msgbuilder.c,v 1.53 2009/01/05 21:26:44 bpintea Exp $
00003  *
00004  * message printing
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of ser, a free SIP server.
00009  *
00010  * ser is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * For a license to use the ser software under conditions
00016  * other than those described here, or to purchase support for this
00017  * software, please contact iptel.org by e-mail at the following addresses:
00018  *    info@iptel.org
00019  *
00020  * ser is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License 
00026  * along with this program; if not, write to the Free Software 
00027  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028  *
00029  *
00030  * History:
00031  * ----------
00032  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
00033  * 2003-02-13  build_uac_request uses proto (andrei)
00034  * 2003-02-28  scratchpad compatibility abandoned (jiri)
00035  * 2003-04-14  build_local no longer checks reply status as it
00036  *             is now called before reply status is updated to
00037  *             avoid late ACK sending (jiri)
00038  * 2003-10-02  added via_builder set host/port support (andrei)
00039  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
00040  * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan)
00041  * 2006-04-21  build_uac_req, assemble_via use struct dest_info now;
00042  *              uri2sock replaced with uri2dst (andrei)
00043  * 2006-08-11  build_dlg_ack: use the first dns ip for which a send_sock
00044  *              is found (andrei)
00045  * 2007-03-15  build_dls_ack: removed next_hop and replaced by dst to avoid
00046  *               resolving nexthop twice (andrei)
00047  * 2007-05-28: build_local_reparse() is introdued: it uses the outgoing
00048  *             INVITE as a source to construct a CANCEL or ACK (Miklos)
00049  */
00050 
00051 #include "defs.h"
00052 
00053 #ifdef EXTRA_DEBUG
00054 #include <assert.h>
00055 #endif
00056 #include "../../comp_defs.h"
00057 #include "../../hash_func.h"
00058 #include "../../globals.h"
00059 #include "t_funcs.h"
00060 #include "../../dprint.h"
00061 #include "../../config.h"
00062 #include "../../parser/parser_f.h"
00063 #include "../../ut.h"
00064 #include "../../parser/msg_parser.h"
00065 #include "../../parser/contact/parse_contact.h"
00066 #include "lw_parser.h"
00067 #include "t_msgbuilder.h"
00068 #include "uac.h"
00069 #ifdef USE_DNS_FAILOVER
00070 #include "../../dns_cache.h"
00071 #include "../../cfg_core.h" /* cfg_get(core, core_cfg, use_dns_failover) */
00072 #endif
00073 
00074 /* convenience macros */
00075 #define memapp(_d,_s,_len) \
00076         do{\
00077                 memcpy((_d),(_s),(_len));\
00078                 (_d) += (_len);\
00079         }while(0)
00080 
00081 #define  append_mem_block(_d,_s,_len) \
00082                 do{\
00083                         memcpy((_d),(_s),(_len));\
00084                         (_d) += (_len);\
00085                 }while(0)
00086 
00087 #define append_str(_p,_str) \
00088         do{  \
00089                 memcpy((_p), (_str).s, (_str).len); \
00090                 (_p)+=(_str).len;  \
00091         } while(0)
00092 
00093 
00094 /* Build a local request based on a previous request; main
00095    customers of this function are local ACK and local CANCEL
00096  */
00097 char *build_local(struct cell *Trans,unsigned int branch,
00098         unsigned int *len, char *method, int method_len, str *to)
00099 {
00100         char                *cancel_buf, *p, *via;
00101         unsigned int         via_len;
00102         struct hdr_field    *hdr;
00103         char branch_buf[MAX_BRANCH_PARAM_LEN];
00104         int branch_len;
00105         str branch_str;
00106         str via_id;
00107         struct hostport hp;
00108 
00109         /* init */
00110         via_id.s=0;
00111         via_id.len=0;
00112 
00113         /* method, separators, version: "CANCEL sip:p2@iptel.org SIP/2.0" */
00114         *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN;
00115         *len+=Trans->uac[branch].uri.len;
00116 
00117         /*via*/
00118         if (!t_calc_branch(Trans,  branch, 
00119                 branch_buf, &branch_len ))
00120                 goto error;
00121         branch_str.s=branch_buf;
00122         branch_str.len=branch_len;
00123         set_hostport(&hp, (is_local(Trans))?0:(Trans->uas.request));
00124 #ifdef USE_TCP
00125         if (!is_local(Trans) && ((Trans->uas.request->rcv.proto==PROTO_TCP)
00126 #ifdef USE_TLS
00127                                 || (Trans->uas.request->rcv.proto==PROTO_TLS)
00128 #endif /* USE_TLS */
00129                 )){
00130                 if ((via_id.s=id_builder(Trans->uas.request,
00131                                                                         (unsigned int*)&via_id.len))==0){
00132                         LOG(L_ERR, "ERROR: build_local: id builder failed\n");
00133                         /* try to continue without id */
00134                 }
00135         }
00136 #endif /* USE_TCP */
00137         via=via_builder(&via_len, &Trans->uac[branch].request.dst,
00138                 &branch_str, via_id.s?&via_id:0 , &hp );
00139         
00140         /* via_id.s not needed anylonger => free it */
00141         if (via_id.s){
00142                 pkg_free(via_id.s);
00143                 via_id.s=0;
00144                 via_id.len=0;
00145         }
00146         
00147         if (!via)
00148         {
00149                 LOG(L_ERR, "ERROR: build_local: "
00150                         "no via header got from builder\n");
00151                 goto error;
00152         }
00153         *len+= via_len;
00154         /*headers*/
00155         *len+=Trans->from.len+Trans->callid.len+to->len+
00156                 +Trans->cseq_n.len+1+method_len+CRLF_LEN; 
00157 
00158 
00159         /* copy'n'paste Route headers */
00160         if (!is_local(Trans)) {
00161                 for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
00162                          if (hdr->type==HDR_ROUTE_T)
00163                                 *len+=hdr->len;
00164         }
00165 
00166         /* User Agent */
00167         if (server_signature) {
00168                 *len += USER_AGENT_LEN + CRLF_LEN;
00169         }
00170         /* Content Length, EoM */
00171         *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN;
00172 
00173         cancel_buf=shm_malloc( *len+1 );
00174         if (!cancel_buf)
00175         {
00176                 LOG(L_ERR, "ERROR: build_local: cannot allocate memory\n");
00177                 goto error01;
00178         }
00179         p = cancel_buf;
00180 
00181         append_mem_block( p, method, method_len );
00182         append_mem_block( p, " ", 1 );
00183         append_str( p, Trans->uac[branch].uri );
00184         append_mem_block( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
00185 
00186         /* insert our via */
00187         append_mem_block(p,via,via_len);
00188 
00189         /*other headers*/
00190         append_str( p, Trans->from );
00191         append_str( p, Trans->callid );
00192         append_str( p, *to );
00193 
00194         append_str( p, Trans->cseq_n );
00195         append_mem_block( p, " ", 1 );
00196         append_mem_block( p, method, method_len );
00197         append_mem_block( p, CRLF, CRLF_LEN );
00198 
00199         if (!is_local(Trans))  {
00200                 for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
00201                         if(hdr->type==HDR_ROUTE_T) {
00202                                 append_mem_block(p, hdr->name.s, hdr->len );
00203                         }
00204         }
00205 
00206         /* User Agent header */
00207         if (server_signature) {
00208                 append_mem_block(p,USER_AGENT CRLF, USER_AGENT_LEN+CRLF_LEN );
00209         }
00210         /* Content Length, EoM */
00211         append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF ,
00212                 CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
00213         *p=0;
00214 
00215         pkg_free(via);
00216         return cancel_buf;
00217 error01:
00218         pkg_free(via);
00219 error:
00220         return NULL;
00221 }
00222 
00223 /* Re-parsing version of build_local() function:
00224  * it builds a local CANCEL or ACK (for non-200 response) request based on
00225  * the previous INVITE which was sent out.
00226  *
00227  * Can not be used to build other type of requests!
00228  */
00229 char *build_local_reparse(struct cell *Trans,unsigned int branch,
00230         unsigned int *len, char *method, int method_len, str *to)
00231 {
00232         char    *invite_buf, *invite_buf_end;
00233         char    *cancel_buf;
00234         char    *s, *s1, *d;    /* source and destination buffers */
00235         short   invite_len;
00236         enum _hdr_types_t       hf_type;
00237         int     first_via, to_len;
00238 
00239         invite_buf = Trans->uac[branch].request.buffer;
00240         invite_len = Trans->uac[branch].request.buffer_len;
00241 
00242         if (!invite_buf || !invite_len) {
00243                 LOG(L_ERR, "ERROR: build_local_reparse: INVITE is missing\n");
00244                 goto error;
00245         }
00246         if ((*invite_buf != 'I') && (*invite_buf != 'i')) {
00247                 LOG(L_ERR, "ERROR: build_local_reparse: trying to call build_local_reparse() for a non-INVITE request?\n");
00248                 goto error;
00249         }
00250         invite_buf_end = invite_buf + invite_len;
00251         s = invite_buf;
00252 
00253         /* Allocate memory for the new message.
00254         The new request will be smaller than the INVITE, so the same size is enough.
00255         I just extend it with the length of new To HF to be sure.
00256         Ugly, but we avoid lots of checks and memory allocations this way */
00257         to_len = to ? to->len : 0;
00258         cancel_buf = shm_malloc(sizeof(char)*(invite_len + to_len));
00259         if (!cancel_buf)
00260         {
00261                 LOG(L_ERR, "ERROR: build_local_reparse: cannot allocate shared memory\n");
00262                 goto error;
00263         }
00264         d = cancel_buf;
00265 
00266         /* method name + space */
00267         append_mem_block(d, method, method_len);
00268         *d = ' ';
00269         d++;
00270         /* skip "INVITE " and copy the rest of the line including CRLF */
00271         s += 7;
00272         s1 = s;
00273         s = eat_line(s, invite_buf_end - s);
00274         append_mem_block(d, s1, s - s1);
00275 
00276         /* check every header field name,
00277         we must exclude and modify some of the headers */
00278         first_via = 1;
00279         while (s < invite_buf_end) {
00280                 s1 = s;
00281                 if ((*s == '\n') || (*s == '\r')) {
00282                         /* end of SIP msg */
00283                         hf_type = HDR_EOH_T;
00284                 } else {
00285                         /* parse HF name */
00286                         s = lw_get_hf_name(s, invite_buf_end,
00287                                                 &hf_type);
00288                 }
00289 
00290                 switch(hf_type) {
00291                         case HDR_CSEQ_T:
00292                                 /* find the method name and replace it */
00293                                 while ((s < invite_buf_end)
00294                                         && ((*s == ':') || (*s == ' ') || (*s == '\t') || ((*s >= '0') && (*s <= '9')))
00295                                         ) s++;
00296                                 append_mem_block(d, s1, s - s1);
00297                                 append_mem_block(d, method, method_len);
00298                                 append_mem_block(d, CRLF, CRLF_LEN);
00299                                 s = lw_next_line(s, invite_buf_end);
00300                                 break;
00301 
00302                         case HDR_VIA_T:
00303                                 s = lw_next_line(s, invite_buf_end);
00304                                 if (first_via) {
00305                                         /* copy hf */
00306                                         append_mem_block(d, s1, s - s1);
00307                                         first_via = 0;
00308                                 } /* else skip this line, we need olny the first via */
00309                                 break;
00310 
00311                         case HDR_TO_T:
00312                                 if (to_len == 0) {
00313                                         /* there is no To tag required, just copy paste the header */
00314                                         s = lw_next_line(s, invite_buf_end);
00315                                         append_mem_block(d, s1, s - s1);
00316                                 } else {
00317                                         /* use the given To HF instead of the original one */
00318                                         append_mem_block(d, to->s, to->len);
00319                                         /* move the pointer to the next line */
00320                                         s = lw_next_line(s, invite_buf_end);
00321                                 }
00322                                 break;
00323 
00324                         case HDR_FROM_T:
00325                         case HDR_CALLID_T:
00326                         case HDR_ROUTE_T:
00327                         case HDR_MAXFORWARDS_T:
00328                                 /* copy hf */
00329                                 s = lw_next_line(s, invite_buf_end);
00330                                 append_mem_block(d, s1, s - s1);
00331                                 break;
00332 
00333                         case HDR_REQUIRE_T:
00334                         case HDR_PROXYREQUIRE_T:
00335                                 /* skip this line */
00336                                 s = lw_next_line(s, invite_buf_end);
00337                                 break;
00338 
00339                         case HDR_CONTENTLENGTH_T:
00340                                 /* copy hf name with 0 value */
00341                                 append_mem_block(d, s1, s - s1);
00342                                 append_mem_block(d, ": 0" CRLF, 3 + CRLF_LEN);
00343                                 /* move the pointer to the next line */
00344                                 s = lw_next_line(s, invite_buf_end);
00345                                 break;
00346 
00347                         case HDR_EOH_T:
00348                                 /* end of SIP message found */
00349                                 append_mem_block(d, CRLF, CRLF_LEN);
00350                                 *len = d - cancel_buf;
00351                                 /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */
00352                                 return cancel_buf;
00353 
00354                         default:
00355                                 s = lw_next_line(s, invite_buf_end);
00356 
00357                                 if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len
00358                                 && (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end)
00359                                 && (strncasecmp(s1,
00360                                                 cfg_get(tm, tm_cfg, ac_extra_hdrs).s,
00361                                                 cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)
00362                                 ) {
00363                                         append_mem_block(d, s1, s - s1);
00364                                 } /* else skip this line */
00365                                 break;
00366                 }
00367         }
00368 
00369         /* HDR_EOH_T was not found in the buffer, the message is corrupt */
00370         LOG(L_ERR, "ERROR: build_local_reparse: HDR_EOH_T was not found\n");
00371 
00372         shm_free(cancel_buf);
00373 error:
00374         LOG(L_ERR, "ERROR: build_local_reparse: cannot build %.*s request\n", method_len, method);
00375         return NULL;
00376 
00377 }
00378 
00379 
00380 typedef struct rte {
00381         rr_t* ptr;
00382         /* 'ptr' above doesn't point to a mem chunk linked to a sip_msg, so it
00383          * won't be free'd along with it => it must be free'd "manually" */
00384         int free_rr;
00385         struct rte* next;
00386 } rte_t;
00387 
00388          
00389 static inline void free_rte_list(struct rte* list)
00390 {
00391         struct rte* ptr;
00392         
00393         while(list) {
00394                 ptr = list;
00395                 list = list->next;
00396                 if (ptr->free_rr)
00397                         free_rr(&ptr->ptr);
00398                 pkg_free(ptr);
00399         }
00400 }
00401 
00402 
00403 static inline int calc_routeset_len(struct rte* list, str* contact)
00404 {
00405         struct rte* ptr;
00406         int ret;
00407         
00408         if (list || contact) {
00409                 ret = ROUTE_PREFIX_LEN + CRLF_LEN;
00410         } else {
00411                 return 0;
00412         }
00413         
00414         ptr = list;
00415         while(ptr) {
00416                 if (ptr != list) {
00417                         ret += ROUTE_SEPARATOR_LEN;
00418                 }
00419                 ret += ptr->ptr->len;
00420                 ptr = ptr->next;
00421         }
00422         
00423         if (contact) {
00424                 if (list) ret += ROUTE_SEPARATOR_LEN;
00425                 ret += 2 + contact->len;
00426         }
00427         
00428         return ret;
00429 }
00430 
00431 
00432      /*
00433       * Print the route set
00434       */
00435 static inline char* print_rs(char* p, struct rte* list, str* contact)
00436 {
00437         struct rte* ptr;
00438         
00439         if (list || contact) {
00440                 memapp(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
00441         } else {
00442                 return p;
00443         }
00444         
00445         ptr = list;
00446         while(ptr) {
00447                 if (ptr != list) {
00448                         memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
00449                 }
00450                 
00451                 memapp(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len);
00452                 ptr = ptr->next;
00453         }
00454         
00455         if (contact) {
00456                 if (list) memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
00457                 *p++ = '<';
00458                 append_str(p, *contact);
00459                 *p++ = '>';
00460         }
00461         
00462         memapp(p, CRLF, CRLF_LEN);
00463         return p;
00464 }
00465 
00466 
00467      /*
00468       * Parse Contact header field body and extract URI
00469       * Does not parse headers !
00470       */
00471 static inline int get_contact_uri(struct sip_msg* msg, str* uri)
00472 {
00473         contact_t* c;
00474         
00475         uri->len = 0;
00476         if (!msg->contact) return 1;
00477         
00478         if (parse_contact(msg->contact) < 0) {
00479                 LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");
00480                 return -1;
00481         }
00482         
00483         c = ((contact_body_t*)msg->contact->parsed)->contacts;
00484         
00485         if (!c) {
00486                 LOG(L_ERR, "get_contact_uri: Empty body or * contact\n");
00487                 return -2;
00488         }
00489         
00490         *uri = c->uri;
00491         return 0;
00492 }
00493 
00500 static inline int get_uac_rs(sip_msg_t *msg, int is_req, struct rte **rtset)
00501 {
00502         struct hdr_field* ptr;
00503         rr_t *p, *new_p;
00504         struct rte *t, *head, *old_head;
00505 
00506         head = 0;
00507         for (ptr = is_req ? msg->route : msg->record_route; ptr; ptr = ptr->next) {
00508                 switch (ptr->type) {
00509                         case HDR_RECORDROUTE_T:
00510                                 if (is_req)
00511                                         continue;
00512                                 break;
00513                         case HDR_ROUTE_T:
00514                                 if (! is_req)
00515                                         continue;
00516                                 break;
00517                         default:
00518                                 continue;
00519                 }
00520                 if (parse_rr(ptr) < 0) {
00521                         ERR("failed to parse Record-/Route HF (%d).\n", ptr->type);
00522                         goto err;
00523                 }
00524                         
00525                 p = (rr_t*)ptr->parsed;
00526                 while(p) {
00527                         if (! (t = (struct rte*)pkg_malloc(sizeof(struct rte)))) {
00528                                 ERR("out of pkg mem (asked for: %zd).\n", sizeof(struct rte));
00529                                 goto err;
00530                         }
00531                         if (is_req) {
00532                                 /* in case of requests, the sip_msg structure is free'd before
00533                                  * rte list is evaluated => must do a copy of it */
00534                                 if (duplicate_rr(&new_p, p) < 0) {
00535                                         pkg_free(t);
00536                                         ERR("failed to duplicate RR");
00537                                         goto err;
00538                                 }
00539                                 t->ptr = new_p;
00540                         } else {
00541                                 t->ptr = p;
00542                         }
00543                         t->free_rr = is_req;
00544                         t->next = head;
00545                         head = t;
00546                         p = p->next;
00547                 }
00548         }
00549 
00550         if (is_req) {
00551                 /* harvesting the R/RR HF above inserts at head, which suites RRs (as
00552                  * they must be reversed, anyway), but not Rs => reverse once more */
00553                 old_head = head;
00554                 head = 0;
00555                 while (old_head) {
00556                         t = old_head;
00557                         old_head = old_head->next;
00558                         t->next = head;
00559                         head = t;
00560                 }
00561         }
00562 
00563         *rtset = head;
00564         return 0;
00565 err:
00566         free_rte_list(head);
00567         return -1;
00568 }
00569 
00570 
00571 static inline unsigned short uri2port(const struct sip_uri *puri)
00572 {
00573         if (puri->port.s) {
00574                 return puri->port_no;
00575         } else switch (puri->type) {
00576                 case SIP_URI_T:
00577                 case TEL_URI_T:
00578                         if (puri->transport_val.len == sizeof("TLS") - 1) {
00579                                 unsigned trans;
00580                                 trans = puri->transport_val.s[0] | 0x20; trans <<= 8;
00581                                 trans |= puri->transport_val.s[1] | 0x20; trans <<= 8;
00582                                 trans |= puri->transport_val.s[2] | 0x20;
00583                                 if (trans == 0x746C73) /* t l s */
00584                                         return SIPS_PORT;
00585                         }
00586                         return SIP_PORT;
00587                 case SIPS_URI_T:
00588                 case TELS_URI_T:
00589                         return SIPS_PORT;
00590                 default:
00591                         BUG("unexpected URI type %d.\n", puri->type);
00592         }
00593         return 0;
00594 }
00595 
00607 static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset,
00608                 const struct dest_info *dst_inv, str *contact)
00609 {
00610         struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri;
00611         struct ip_addr *uri_ia;
00612         union sockaddr_union uri_sau;
00613         unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port;
00614         rte_t *last_r;
00615 #ifdef TM_LOC_ACK_DO_REV_DNS
00616         struct ip_addr ia;
00617         struct hostent *he;
00618         char **alias;
00619 #endif
00620 
00621 #define PARSE_URI(_str_, _uri_) \
00622         do { \
00623                 /* parse_uri() 0z the puri */ \
00624                 if (parse_uri((_str_)->s, \
00625                                 (_str_)->len, _uri_) < 0) { \
00626                         ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \
00627                         return 0; \
00628                 } \
00629         } while (0)
00630 
00631 #define HAS_LR(_rte_) \
00632         ({ \
00633                 PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \
00634                 puri.lr.s; \
00635         })
00636 
00637 #define URI_PORT(_puri_, _port) \
00638         do { \
00639                 if (! (_port = uri2port(_puri_))) \
00640                         return 0; \
00641         } while (0)
00642 
00643         /* examine the easy/fast & positive cases foremost */
00644 
00645         /* [1] check if 1st route lacks ;lr */
00646         DEBUG("checking lack of ';lr' in 1st route.\n");
00647         if (! HAS_LR(rtset))
00648                 return F_RB_NH_STRICT;
00649         topr_uri = puri; /* save 1st route's URI */
00650 
00651         /* [2] check if last route shows ;lr */
00652         DEBUG("checking presence of ';lr' in last route.\n");
00653         for (last_r = rtset; last_r->next; last_r = last_r->next)
00654                 /* scroll down to last route */
00655                 ;
00656         if (HAS_LR(last_r))
00657                 return F_RB_NH_LOOSE;
00658 
00659         /* [3] 1st route has ;lr -> check if the destination of original INV
00660          * equals the address provided by this route; if does -> loose */
00661         DEBUG("checking INVITE's destination against its first route.\n");
00662         URI_PORT(&topr_uri, uri_port);
00663         if (! (dst_port = su_getport((void *)&dst_inv->to)))
00664                 return 0; /* not really expected */
00665         if (dst_port != uri_port)
00666                 return F_RB_NH_STRICT;
00667         /* if 1st route contains an IP address, comparing it against .dst */
00668         if ((uri_ia = str2ip(&topr_uri.host))
00669 #ifdef USE_IPV6
00670                         || (uri_ia = str2ip6(&topr_uri.host))
00671 #endif
00672                         ) {
00673                 /* we have an IP address in route -> comparison can go swiftly */
00674                 if (init_su(&uri_sau, uri_ia, uri_port) < 0)
00675                         return 0; /* not really expected */
00676                 if (su_cmp(&uri_sau, (void *)&dst_inv->to))
00677                         /* ;lr and sent there */
00678                         return F_RB_NH_LOOSE;
00679                 else
00680                         /* ;lr and NOT sent there (probably sent to RURI address) */
00681                         return F_RB_NH_STRICT;
00682         } else {
00683                 /*if 1st route contains a name, rev resolve the .dst and compare*/
00684                 INFO("Failed to decode string '%.*s' in route set element as IP "
00685                                 "address. Trying name resolution.\n",STR_FMT(&topr_uri.host));
00686 
00687         /* TODO: alternatively, rev name and compare against dest. IP.  */
00688 #ifdef TM_LOC_ACK_DO_REV_DNS
00689                 ia.af = 0;
00690                 su2ip_addr(&ia, (void *)&dst_inv->to);
00691                 if (! ia.af)
00692                         return 0; /* not really expected */
00693                 if ((he = rev_resolvehost(&ia))) {
00694                         if ((strlen(he->h_name) == topr_uri.host.len) &&
00695                                         (memcmp(he->h_name, topr_uri.host.s, 
00696                                                         topr_uri.host.len) == 0))
00697                                 return F_RB_NH_LOOSE;
00698                         for (alias = he->h_aliases; *alias; alias ++)
00699                                 if ((strlen(*alias) == topr_uri.host.len) &&
00700                                                 (memcmp(*alias, topr_uri.host.s, 
00701                                                                 topr_uri.host.len) == 0))
00702                                         return F_RB_NH_LOOSE;
00703                         return F_RB_NH_STRICT;
00704                 } else {
00705                         INFO("failed to resolve address '%s' to a name.\n", 
00706                                         ip_addr2a(&ia));
00707                 }
00708 #endif
00709         }
00710 
00711         WARN("failed to establish with certainty the type of next hop; trying an"
00712                         " educated guess.\n");
00713 
00714         /* [4] compare (possibly updated) remote target to original RURI; if
00715          * equal, a strict router's address wasn't filled in as RURI -> loose */
00716         DEBUG("checking remote target against INVITE's RURI.\n");
00717         PARSE_URI(contact, &cont_uri);
00718         PARSE_URI(GET_RURI(orig_inv), &inv_ruri);
00719         URI_PORT(&cont_uri, cont_port);
00720         URI_PORT(&inv_ruri, inv_port);
00721         if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) &&
00722                         (memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0))
00723                 return F_RB_NH_LOOSE;
00724 
00725         /* [5] compare (possibly updated) remote target to last route; if equal, 
00726          * strict router's address might have been filled as RURI and remote
00727          * target appended to route set -> strict */
00728         DEBUG("checking remote target against INVITE's last route.\n");
00729         PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri);
00730         URI_PORT(&lastr_uri, lastr_port);
00731         if ((cont_port == lastr_port) && 
00732                         (cont_uri.host.len == lastr_uri.host.len) &&
00733                         (memcmp(cont_uri.host.s, lastr_uri.host.s, 
00734                                         lastr_uri.host.len) == 0))
00735                 return F_RB_NH_STRICT;
00736 
00737         WARN("failed to establish the type of next hop; assuming loose router.\n");
00738         return F_RB_NH_LOOSE;
00739 
00740 #undef PARSE_URI
00741 #undef HAS_LR
00742 #undef URI_PORT
00743 }
00744 
00761 static int eval_uac_routing(sip_msg_t *rpl, const struct retr_buf *inv_rb, 
00762                 str* contact, struct rte **list, str *ruri, str *next_hop)
00763 {
00764         sip_msg_t orig_inv, *sipmsg; /* reparse original INVITE */
00765         rte_t *t, *prev_t, *rtset = NULL;
00766         int is_req;
00767         struct sip_uri puri;
00768         static size_t chklen;
00769         int ret = -1;
00770         
00771         /* parse the retr. buffer */
00772         memset(&orig_inv, 0, sizeof(struct sip_msg));
00773         orig_inv.buf = inv_rb->buffer;
00774         orig_inv.len = inv_rb->buffer_len;
00775         DEBUG("reparsing retransmission buffer of original INVITE:\n%.*s\n",
00776                         orig_inv.len, orig_inv.buf);
00777         if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) != 0) {
00778                 ERR("failed to parse retr buffer (weird!): \n%.*s\n", orig_inv.len,
00779                                 orig_inv.buf);
00780                 return -1;
00781         }
00782 
00783         /* check if we need to look at request or reply */
00784         if ((parse_headers(&orig_inv, HDR_TO_F, 0) < 0) || (! orig_inv.to)) {
00785                 /* the bug is at message assembly */
00786                 BUG("failed to parse INVITE retr. buffer and/or extract 'To' HF:"
00787                                 "\n%.*s\n", orig_inv.len, orig_inv.buf);
00788                 goto end;
00789         }
00790         if (((struct to_body *)orig_inv.to->parsed)->tag_value.len) {
00791                 DEBUG("building ACK for in-dialog INVITE (using RS in orig. INV.)\n");
00792                 if (parse_headers(&orig_inv, HDR_EOH_F, 0) < 0) {
00793                         BUG("failed to parse INVITE retr. buffer to EOH:"
00794                                         "\n%.*s\n", orig_inv.len, orig_inv.buf);
00795                         goto end;
00796                 }
00797                 sipmsg = &orig_inv;
00798                 is_req = 1;
00799         } else {
00800                 DEBUG("building ACK for out-of-dialog INVITE (using RS in RR set).\n");
00801                 sipmsg = rpl;
00802                 is_req = 0;
00803         }
00804 
00805         /* extract the route set */
00806         if (get_uac_rs(sipmsg, is_req, &rtset) < 0) {
00807                 ERR("failed to extract route set.\n");
00808                 goto end;
00809         }
00810 
00811         if (! rtset) { /* No routes */
00812                 *ruri = *contact;
00813                 *next_hop = *contact;
00814         } else if (! is_req) { /* out of dialog req. */
00815                 if (parse_uri(rtset->ptr->nameaddr.uri.s, rtset->ptr->nameaddr.uri.len,
00816                                 &puri) < 0) {
00817                         ERR("failed to parse first route in set.\n");
00818                         goto end;
00819                 }
00820                 
00821                 if (puri.lr.s) { /* Next hop is loose router */
00822                         *ruri = *contact;
00823                         *next_hop = rtset->ptr->nameaddr.uri;
00824                 } else { /* Next hop is strict router */
00825                         *ruri = rtset->ptr->nameaddr.uri;
00826                         *next_hop = *ruri;
00827                         /* consume first route, b/c it will be put in RURI */
00828                         t = rtset;
00829                         rtset = rtset->next;
00830                         pkg_free(t);
00831                 }
00832         } else {
00833                 unsigned long route_flags = inv_rb->flags;
00834                 DEBUG("UAC rb flags: 0x%x.\n", (unsigned int)route_flags);
00835 eval_flags:
00836                 switch (route_flags & (F_RB_NH_LOOSE|F_RB_NH_STRICT)) {
00837                 case 0:
00838                         WARN("calculate_hooks() not called when built the local UAC of "
00839                                         "in-dialog request, or called with empty route set.\n");
00840                         /* try to figure out what kind of hop is the next one
00841                          * (strict/loose) by reading the original invite */
00842                         if ((route_flags = nhop_type(&orig_inv, rtset, &inv_rb->dst, 
00843                                         contact))) {
00844                                 DEBUG("original request's next hop type evaluated to: 0x%x.\n",
00845                                                 (unsigned int)route_flags);
00846                                 goto eval_flags;
00847                         } else {
00848                                 ERR("failed to establish what kind of router the next "
00849                                                 "hop is.\n");
00850                                 goto end;
00851                         }
00852                         break;
00853                 case F_RB_NH_LOOSE:
00854                         *ruri = *contact;
00855                         *next_hop = rtset->ptr->nameaddr.uri;
00856                         break;
00857                 case F_RB_NH_STRICT:
00858                         /* find ptr to last route body that contains the (possibly) old 
00859                          * remote target 
00860                          */
00861                         for (t = rtset, prev_t = t; t->next; prev_t = t, t = t->next)
00862                                 ;
00863                         if ((t->ptr->len == contact->len) && 
00864                                         (memcmp(t->ptr->nameaddr.name.s, contact->s, 
00865                                                         contact->len) == 0)){
00866                                 /* the remote target didn't update -> keep the whole route set,
00867                                  * including the last entry */
00868                                 /* do nothing */
00869                         } else {
00870                                 /* trash last entry and replace with new remote target */
00871                                 free_rte_list(t);
00872                                 /* compact the rr_t struct along with rte. this way, free'ing
00873                                  * it can be done along with rte chunk, independent of Route
00874                                  * header parser's allocator (using pkg/shm) */
00875                                 chklen = sizeof(struct rte) + sizeof(rr_t);
00876                                 if (! (t = (struct rte *)pkg_malloc(chklen))) {
00877                                         ERR("out of pkg memory (%zd required)\n", chklen);
00878                                         goto end;
00879                                 }
00880                                 /* this way, .free_rr is also set to 0 (!!!) */
00881                                 memset(t, 0, chklen); 
00882                                 ((rr_t *)&t[1])->nameaddr.name = *contact;
00883                                 ((rr_t *)&t[1])->len = contact->len;
00884                                 /* chain the new route elem in set */
00885                                 if (prev_t == rtset)
00886                                         /*there is only one elem in route set: the remote target*/
00887                                         rtset = t;
00888                                 else
00889                                         prev_t->next = t;
00890                         }
00891 
00892                         *ruri = *GET_RURI(&orig_inv); /* reuse original RURI */
00893                         *next_hop = *ruri;
00894                         break;
00895                 default:
00896                         /* probably a mem corruption */
00897                         BUG("next hop of original request marked as both loose and strict"
00898                                         " router (buffer: %.*s).\n", inv_rb->buffer_len, 
00899                                         inv_rb->buffer);
00900 #ifdef EXTRA_DEBUG
00901                         abort();
00902 #else
00903                         goto end;
00904 #endif
00905                 }
00906         }
00907 
00908         *list = rtset;
00909         /* all went well */
00910         ret = 0;
00911 end:
00912         free_sip_msg(&orig_inv);
00913         if (ret < 0)
00914                 free_rte_list(rtset);
00915         return ret;
00916 }
00917 
00918      /*
00919       * The function creates an ACK to 200 OK. Route set will be created
00920       * and parsed and the dst parameter will contain the destination to which 
00921           * the request should be send. The function is used by tm when it 
00922           * generates local ACK to 200 OK (on behalf of applications using uac)
00923       */
00924 char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, 
00925                                         unsigned int branch, str *hdrs, str *body,
00926                                         unsigned int *len, struct dest_info* dst)
00927 {
00928         char *req_buf, *p, *via;
00929         unsigned int via_len;
00930         char branch_buf[MAX_BRANCH_PARAM_LEN];
00931         int branch_len;
00932         str branch_str;
00933         struct hostport hp;
00934         struct rte* list;
00935         str contact, ruri, *cont;
00936         str next_hop;
00937         str body_len;
00938         str _to, *to = &_to;
00939 #ifdef USE_DNS_FAILOVER
00940         struct dns_srv_handle dns_h;
00941 #endif
00942 #ifdef WITH_AS_SUPPORT
00943         /* With AS support, TM allows for external modules to generate building of
00944          * the ACK; in this case, the ACK's retransmission buffer is built once
00945          * and kept in memory (to help when retransmitted 2xx are received and ACK
00946          * must be resent).
00947          * Allocation of the string raw buffer that holds the ACK is piggy-backed
00948          * with allocation of the retransmission buffer (since both have the same
00949          * life-cycle): both the string buffer and retransm. buffer are placed 
00950          * into the same allocated chunk of memory (retr. buffer first, string 
00951          * buffer follows).In this case, the 'len' param is used as in-out 
00952          * parameter: 'in' to give the extra space needed by the retr. buffer,
00953          * 'out' to return the lenght of the allocated string buffer.
00954          */
00955         unsigned offset = *len;
00956 #endif
00957         
00958         if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) {
00959                 ERR("Error while parsing headers.\n");
00960                 return 0;
00961         } else {
00962                 _to.s = rpl->to->name.s;
00963                 _to.len = rpl->to->len;
00964         }
00965         
00966         if (get_contact_uri(rpl, &contact) < 0) {
00967                 return 0;
00968         }
00969         
00970         if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact, 
00971                         &list, &ruri, &next_hop) < 0) {
00972                 ERR("failed to evaluate routing elements.\n");
00973                 return 0;
00974         }
00975         DEBUG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri), 
00976                         STR_FMT(&next_hop));
00977 
00978         if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
00979                      /* contact != ruri means that the next
00980                       * hop is a strict router, cont will be non-zero
00981                       * and print_routeset will append it at the end
00982                       * of the route set
00983                       */
00984                 cont = &contact;
00985         } else {
00986                      /* Next hop is a loose router, nothing to append */
00987                 cont = 0;
00988         }
00989         
00990              /* method, separators, version: "ACK sip:p2@iptel.org SIP/2.0" */
00991         *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
00992         *len += ruri.len;
00993         
00994         
00995          /* via */
00996 #ifdef USE_DNS_FAILOVER
00997         if (cfg_get(core, core_cfg, use_dns_failover)){
00998                 dns_srv_handle_init(&dns_h);
00999                 if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
01000                                 (dst->send_sock==0)){
01001                         dns_srv_handle_put(&dns_h);
01002                         LOG(L_ERR, "build_dlg_ack: no socket found\n");
01003                         goto error;
01004                 }
01005                 dns_srv_handle_put(&dns_h); /* not needed any more */
01006         }else{
01007                 if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
01008                                 (dst->send_sock==0)){
01009                         LOG(L_ERR, "build_dlg_ack: no socket found\n");
01010                         goto error;
01011                 }
01012         }
01013 #else
01014         if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
01015                         (dst->send_sock==0)){
01016                         LOG(L_ERR, "build_dlg_ack: no socket found\n");
01017                 goto error;
01018         }
01019 #endif
01020         
01021         if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
01022         branch_str.s = branch_buf;
01023         branch_str.len = branch_len;
01024         set_hostport(&hp, 0);
01025         via = via_builder(&via_len, dst, &branch_str, 0, &hp);
01026         if (!via) {
01027                 LOG(L_ERR, "build_dlg_ack: No via header got from builder\n");
01028                 goto error;
01029         }
01030         *len+= via_len;
01031         
01032              /*headers*/
01033         *len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;
01034         
01035              /* copy'n'paste Route headers */
01036         
01037         *len += calc_routeset_len(list, cont);
01038         
01039              /* User Agent */
01040         if (server_signature) *len += USER_AGENT_LEN + CRLF_LEN;
01041                 /* extra headers */
01042         if (hdrs)
01043                 *len += hdrs->len;
01044                 /* body */
01045         if (body) {
01046                 body_len.s = int2str(body->len, &body_len.len);
01047                 *len += body->len;
01048         } else {
01049                 body_len.len = 0;
01050                 body_len.s = NULL; /*4gcc*/
01051                 *len += 1; /* for the (Cont-Len:) `0' */
01052         }
01053              /* Content Length, EoM */
01054         *len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN;
01055 
01056 #if WITH_AS_SUPPORT
01057         req_buf = shm_malloc(offset + *len + 1);
01058         req_buf += offset;
01059 #else
01060         req_buf = shm_malloc(*len + 1);
01061 #endif
01062         if (!req_buf) {
01063                 ERR("Cannot allocate memory (%u+1)\n", *len);
01064                 goto error01;
01065         }
01066         p = req_buf;
01067         
01068         append_mem_block( p, ACK, ACK_LEN );
01069         append_mem_block( p, " ", 1 );
01070         append_str(p, ruri);
01071         append_mem_block( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
01072          
01073              /* insert our via */
01074         append_mem_block(p, via, via_len);
01075         
01076              /*other headers*/
01077         append_str(p, Trans->from);
01078         append_str(p, Trans->callid);
01079         append_str(p, *to);
01080         
01081         append_str(p, Trans->cseq_n);
01082         append_mem_block( p, " ", 1 );
01083         append_mem_block( p, ACK, ACK_LEN);
01084         append_mem_block(p, CRLF, CRLF_LEN);
01085         
01086              /* Routeset */
01087         p = print_rs(p, list, cont);
01088         
01089              /* User Agent header */
01090         if (server_signature) {
01091                 append_mem_block(p, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
01092         }
01093         
01094         /* extra headers */
01095         if (hdrs)
01096                 append_mem_block(p, hdrs->s, hdrs->len);
01097         
01098              /* Content Length, EoH, (body) */
01099         if (body) {
01100                 append_mem_block(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
01101                 append_mem_block(p, body_len.s, body_len.len);
01102                 append_mem_block(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN + 
01103                                 CRLF_LEN);
01104                 append_mem_block(p, body->s, body->len);
01105         } else {
01106                 append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF, 
01107                                 CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
01108         }
01109 
01110         /* EoM */
01111         *p = 0;
01112         
01113         pkg_free(via);
01114         free_rte_list(list);
01115         return req_buf;
01116         
01117  error01:
01118         pkg_free(via);
01119  error:
01120         free_rte_list(list);
01121         return 0;
01122 }
01123 
01124 
01125 /*
01126  * Convert length of body into asciiz
01127  */
01128 static inline int print_content_length(str* dest, str* body)
01129 {
01130         static char content_length[10];
01131         int len;
01132         int b_len;
01133         char* tmp;
01134 
01135              /* Print Content-Length */
01136         b_len=body?body->len:0;
01137         tmp = int2str(b_len, &len);
01138         if (len >= sizeof(content_length)) {
01139                 LOG(L_ERR, "ERROR: print_content_length: content_len too big\n");
01140                 dest->s = 0;
01141                 dest->len = 0;
01142                 return -1;
01143         }
01144         memcpy(content_length, tmp, len); 
01145         dest->s = content_length;
01146         dest->len = len;
01147         return 0;
01148 }
01149 
01150 
01151 /*
01152  * Convert CSeq number into asciiz
01153  */
01154 static inline int print_cseq_num(str* _s, dlg_t* _d)
01155 {
01156         static char cseq[INT2STR_MAX_LEN];
01157         char* tmp;
01158         int len;
01159 
01160         tmp = int2str(_d->loc_seq.value, &len);
01161         if (len > sizeof(cseq)) {
01162                 LOG(L_ERR, "print_cseq_num: cseq too big\n");
01163                 return -1;
01164         }
01165         
01166         memcpy(cseq, tmp, len);
01167         _s->s = cseq;
01168         _s->len = len;
01169         return 0;
01170 }
01171 
01172 
01173 /*
01174  * Create Via header
01175  */
01176 static inline int assemble_via(str* dest, struct cell* t, 
01177                                                                 struct dest_info* dst, int branch)
01178 {
01179         static char branch_buf[MAX_BRANCH_PARAM_LEN];
01180         char* via;
01181         int len;
01182         unsigned int via_len;
01183         str branch_str;
01184         struct hostport hp;
01185 
01186         if (!t_calc_branch(t, branch, branch_buf, &len)) {
01187                 LOG(L_ERR, "ERROR: assemble_via: branch calculation failed\n");
01188                 return -1;
01189         }
01190         
01191         branch_str.s = branch_buf;
01192         branch_str.len = len;
01193 
01194 #ifdef XL_DEBUG
01195         printf("!!!proto: %d\n", sock->proto);
01196 #endif
01197 
01198         set_hostport(&hp, 0);
01199         via = via_builder(&via_len, dst, &branch_str, 0, &hp);
01200         if (!via) {
01201                 LOG(L_ERR, "assemble_via: via building failed\n");
01202                 return -2;
01203         }
01204         
01205         dest->s = via;
01206         dest->len = via_len;
01207         return 0;
01208 }
01209 
01210 
01211 /*
01212  * Print Request-URI
01213  */
01214 static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struct cell* t, int branch)
01215 {
01216         memapp(w, method->s, method->len); 
01217         memapp(w, " ", 1); 
01218 
01219         t->uac[branch].uri.s = w; 
01220         t->uac[branch].uri.len = dialog->hooks.request_uri->len;
01221 
01222         memapp(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len); 
01223         memapp(w, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
01224 
01225         return w;
01226 }
01227 
01228 
01229 /*
01230  * Print To header field
01231  */
01232 static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
01233 {
01234         t->to.s = w;
01235         t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN;
01236 
01237         memapp(w, TO, TO_LEN);
01238         memapp(w, dialog->rem_uri.s, dialog->rem_uri.len);
01239 
01240         if (dialog->id.rem_tag.len) {
01241                 t->to.len += TOTAG_LEN + dialog->id.rem_tag.len ;
01242                 memapp(w, TOTAG, TOTAG_LEN);
01243                 memapp(w, dialog->id.rem_tag.s, dialog->id.rem_tag.len);
01244         }
01245 
01246         memapp(w, CRLF, CRLF_LEN);
01247         return w;
01248 }
01249 
01250 
01251 /*
01252  * Print From header field
01253  */
01254 static inline char* print_from(char* w, dlg_t* dialog, struct cell* t)
01255 {
01256         t->from.s = w;
01257         t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN;
01258 
01259         memapp(w, FROM, FROM_LEN);
01260         memapp(w, dialog->loc_uri.s, dialog->loc_uri.len);
01261 
01262         if (dialog->id.loc_tag.len) {
01263                 t->from.len += FROMTAG_LEN + dialog->id.loc_tag.len;
01264                 memapp(w, FROMTAG, FROMTAG_LEN);
01265                 memapp(w, dialog->id.loc_tag.s, dialog->id.loc_tag.len);
01266         }
01267 
01268         memapp(w, CRLF, CRLF_LEN);
01269         return w;
01270 }
01271 
01272 
01273 /*
01274  * Print CSeq header field
01275  */
01276 char* print_cseq_mini(char* target, str* cseq, str* method) {
01277         memapp(target, CSEQ, CSEQ_LEN);
01278         memapp(target, cseq->s, cseq->len);
01279         memapp(target, " ", 1);
01280         memapp(target, method->s, method->len);
01281         return target;
01282 }
01283 
01284 static inline char* print_cseq(char* w, str* cseq, str* method, struct cell* t)
01285 {
01286         t->cseq_n.s = w; 
01287         /* don't include method name and CRLF -- subsequent
01288          * local requests ACK/CANCEL will add their own */
01289         t->cseq_n.len = CSEQ_LEN + cseq->len; 
01290         w = print_cseq_mini(w, cseq, method);
01291         return w;
01292 }
01293 
01294 /*
01295  * Print Call-ID header field
01296  * created an extra function for pure header field creation, that is used by t_cancel for 
01297  * t_uac_cancel FIFO function.
01298  */
01299 char* print_callid_mini(char* target, str callid) {
01300         memapp(target, CALLID, CALLID_LEN);
01301         memapp(target, callid.s, callid.len);
01302         memapp(target, CRLF, CRLF_LEN);
01303         return target;
01304 }
01305 
01306 static inline char* print_callid(char* w, dlg_t* dialog, struct cell* t)
01307 {
01308         /* begins with CRLF, not included in t->callid, don`t know why...?!? */
01309         memapp(w, CRLF, CRLF_LEN);
01310         t->callid.s = w;
01311         t->callid.len = CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;
01312 
01313         w = print_callid_mini(w, dialog->id.call_id);
01314         return w;
01315 }
01316 
01317 
01318 /*
01319  * Create a request
01320  */
01321 char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int branch, 
01322                         struct cell *t, int* len, struct dest_info* dst)
01323 {
01324         char* buf, *w;
01325         str content_length, cseq, via;
01326 
01327         if (!method || !dialog) {
01328                 LOG(L_ERR, "build_uac_req(): Invalid parameter value\n");
01329                 return 0;
01330         }
01331         if (print_content_length(&content_length, body) < 0) {
01332                 LOG(L_ERR, "build_uac_req(): Error while printing content-length\n");
01333                 return 0;
01334         }
01335         if (print_cseq_num(&cseq, dialog) < 0) {
01336                 LOG(L_ERR, "build_uac_req(): Error while printing CSeq number\n");
01337                 return 0;
01338         }
01339         *len = method->len + 1 + dialog->hooks.request_uri->len + 1 + SIP_VERSION_LEN + CRLF_LEN;
01340 
01341         if (assemble_via(&via, t, dst, branch) < 0) {
01342                 LOG(L_ERR, "build_uac_req(): Error while assembling Via\n");
01343                 return 0;
01344         }
01345         *len += via.len;
01346 
01347         *len += TO_LEN + dialog->rem_uri.len
01348                 + (dialog->id.rem_tag.len ? (TOTAG_LEN + dialog->id.rem_tag.len) : 0) + CRLF_LEN;    /* To */
01349         *len += FROM_LEN + dialog->loc_uri.len
01350                 + (dialog->id.loc_tag.len ? (FROMTAG_LEN + dialog->id.loc_tag.len) : 0) + CRLF_LEN;  /* From */
01351         *len += CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;                                      /* Call-ID */
01352         *len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN;                                    /* CSeq */
01353         *len += calculate_routeset_length(dialog);                                                   /* Route set */
01354         *len += CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN; /* Content-
01355                                                                                                                                          Length */
01356         *len += (server_signature ? (USER_AGENT_LEN + CRLF_LEN) : 0);                                /* Signature */
01357         *len += (headers ? headers->len : 0);                                                        /* Additional headers */
01358         *len += (body ? body->len : 0);                                                              /* Message body */
01359         *len += CRLF_LEN;                                                                            /* End of Header */
01360 
01361         buf = shm_malloc(*len + 1);
01362         if (!buf) {
01363                 LOG(L_ERR, "build_uac_req(): no shmem\n");
01364                 goto error;
01365         }
01366         
01367         w = buf;
01368 
01369         w = print_request_uri(w, method, dialog, t, branch);  /* Request-URI */
01370         memapp(w, via.s, via.len);                            /* Top-most Via */
01371         w = print_to(w, dialog, t);                           /* To */
01372         w = print_from(w, dialog, t);                         /* From */
01373         w = print_cseq(w, &cseq, method, t);                  /* CSeq */
01374         w = print_callid(w, dialog, t);                       /* Call-ID */
01375         w = print_routeset(w, dialog);                        /* Route set */
01376 
01377      /* Content-Length */
01378         memapp(w, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
01379         memapp(w, content_length.s, content_length.len);
01380         memapp(w, CRLF, CRLF_LEN);
01381         
01382              /* Server signature */
01383         if (server_signature) memapp(w, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
01384         if (headers) memapp(w, headers->s, headers->len);
01385         memapp(w, CRLF, CRLF_LEN);
01386         if (body) memapp(w, body->s, body->len);
01387 
01388 #ifdef EXTRA_DEBUG
01389         assert(w-buf == *len);
01390 #endif
01391 
01392         pkg_free(via.s);
01393         return buf;
01394 
01395  error:
01396         pkg_free(via.s);
01397         return 0;
01398 }
01399 
01400 
01401 int t_calc_branch(struct cell *t, 
01402         int b, char *branch, int *branch_len)
01403 {
01404         return syn_branch ?
01405                 branch_builder( t->hash_index,
01406                         t->label, 0,
01407                         b, branch, branch_len )
01408                 : branch_builder( t->hash_index,
01409                         0, t->md5,
01410                         b, branch, branch_len );
01411 }
01412 

Generated on Thu Sep 9 04:16:00 2010 for SIPExpressRouter by  doxygen 1.3.9.1