t_msgbuilder.c

Go to the documentation of this file.
00001 /*
00002  * $Id: t_msgbuilder.c 5133 2008-10-24 13:35:00Z miconda $
00003  *
00004  * message printing
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio 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  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  *
00025  * History:
00026  * ----------
00027  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
00028  * 2003-02-13  build_uac_request uses proto (andrei)
00029  * 2003-02-28  scratchpad compatibility abandoned (jiri)
00030  * 2003-04-14  build_local no longer checks reply status as it
00031  *             is now called before reply status is updated to
00032  *             avoid late ACK sending (jiri)
00033  * 2003-10-02  added via_builder set host/port support (andrei)
00034  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
00035  * 2004-02-13  t->is_invite and t->local replaced with flags (bogdan)
00036  * 2008-04-04 added support for local and remote dispaly name in TM dialogs
00037  *            (by Andrei Pisau <andrei.pisau at voice-system dot ro> )
00038  */
00039 
00040 /*! \file
00041  * \brief TM :: Message printing
00042  *
00043  * \ingroup tm
00044  * - Module: \ref tm
00045  */
00046 
00047 #include "../../hash_func.h"
00048 #include "../../dprint.h"
00049 #include "../../parser/parser_f.h"
00050 #include "../../ut.h"
00051 #include "../../parser/msg_parser.h"
00052 #include "../../parser/contact/parse_contact.h"
00053 #include "t_funcs.h"
00054 #include "t_msgbuilder.h"
00055 #include "uac.h"
00056 
00057 
00058 #define ROUTE_PREFIX "Route: "
00059 #define ROUTE_PREFIX_LEN (sizeof(ROUTE_PREFIX) - 1)
00060 
00061 #define ROUTE_SEPARATOR ", "
00062 #define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)
00063 
00064 #define LOCAL_MAXFWD_HEADER "Max-Forwards: " LOCAL_MAXFWD_VALUE CRLF
00065 #define LOCAL_MAXFWD_HEADER_LEN (sizeof(LOCAL_MAXFWD_HEADER) - 1)
00066 
00067 /* convenience macros */
00068 #define LC(_cp) ((*(_cp))|0x20)
00069 #define SET_FOUND(_new_state) \
00070    do{\
00071       fill->s=b;fill->len=p-b;\
00072       LM_DBG("hdr %d extracted as <%.*s>\n",\
00073          flag,fill->len,fill->s);\
00074       flags&=~(flag);\
00075       if (flags) {state=_new_state;}\
00076       else {goto done;}\
00077    }while(0)
00078 #define GET_CSEQ() \
00079    do{\
00080       for(p++;p<end&&isspace((int)*p);p++);\
00081       for(fill->s=b;p<end&&isdigit((int)*p);p++);\
00082       fill->len=p-fill->s;\
00083       if ( (flags&=~(flag))==0) goto done;\
00084       state=1;\
00085    }while(0)
00086 static int extract_hdrs( char *buf, int len, str *from, str *to, str *cseq)
00087 {
00088    char *end, *p;
00089    char *b;
00090    str  *fill;
00091    int state;
00092    int flags;
00093    int flag;
00094 
00095    p = buf;
00096    end = buf+len;
00097    state = 1;
00098    b = 0;
00099    flags = ((from!=0)?0x1:0) | ((to!=0)?0x2:0) | ((cseq!=0)?0x4:0);
00100    flag = 0;
00101    fill = 0;
00102 
00103    while(p<end) {
00104       switch (*p) {
00105          case '\n':
00106          case '\r':
00107             switch (state) {
00108                case 4: state=5;break;
00109                case 5: case 6: state=6;break;
00110                default : state=2;break;
00111             }
00112             break;
00113          case ' ':
00114          case '\t':
00115             switch (state) {
00116                case 4: case 6: state=5; break;
00117                case 2: state=1; break;/*folded line*/
00118             }
00119             break;
00120          case ':':
00121             switch (state) {
00122                case 4:case 5: state=5;if(flag==0x04)GET_CSEQ();break;
00123                case 6: SET_FOUND(1);break;/*found*/
00124                case 2: state=1;break;
00125             }
00126             break;
00127          case 'f':
00128          case 'F':
00129             if (state==5) break;
00130             if (state==6) SET_FOUND(2);/*found*/;
00131             if (state!=2) {state = 1;break;}
00132             /* hdr starting with 'f' */
00133             if (from==0) break;
00134             b = p;
00135             if (p+3<end && LC(p+1)=='r' && LC(p+2)=='o' && LC(p+3)=='m')
00136                p+=3;
00137             state = 4; /* "f" or "from" found */
00138             fill = from;
00139             flag = 0x1;
00140             break;
00141          case 't':
00142          case 'T':
00143             if (state==5) break;
00144             if (state==6) SET_FOUND(2);/*found*/;
00145             if (state!=2) {state = 1;break;}
00146             /* hdr starting with 't' */
00147             if (to==0) break;
00148             b = p;
00149             if (p+1<end && LC(p+1)=='o')
00150                p+=1;
00151             state = 4; /* "t" or "to" found */
00152             fill = to;
00153             flag = 0x2;
00154             break;
00155          case 'c':
00156          case 'C':
00157             if (state==5) break;
00158             if (state==6) SET_FOUND(2);/*found*/;
00159             if (state!=2) {state = 1;break;}
00160             /* hdr starting with 'c' */
00161             if (cseq==0) break;
00162             if (p+3<end && LC(p+1)=='s' && LC(p+2)=='e' && LC(p+3)=='q') {
00163                b = p;
00164                p+=3;
00165                state = 4; /* "cseq" found */
00166                fill = cseq;
00167                flag = 0x4;
00168             }
00169             break;
00170          default:
00171             switch (state) {
00172                case 2:case 4: state=1; break;
00173                case 6: SET_FOUND(1);break;/*found*/;
00174             }
00175       }
00176       p++;
00177    }
00178 
00179    LM_CRIT("no hdrs found in outgoing buffer\n");
00180    return -1;
00181 done:
00182    return 0;
00183 }
00184 
00185 
00186 static inline struct hdr_field* extract_parsed_hdrs( char *buf, int len)
00187 {
00188    char *p;
00189    static struct sip_msg msg;
00190    struct hdr_field  *hdr;
00191 
00192    LM_DBG("----parsing the buf req - first line\n");
00193    /* skip the first line - not interesting */
00194    p = eat_line( buf, len);
00195    if (p>=buf+len)
00196       return 0;
00197 
00198    memset( &msg, 0, sizeof(struct sip_msg) );
00199    msg.buf = buf;
00200    msg.len = len;
00201    msg.unparsed = p;
00202 
00203    /* as we need all Route headers, we need to parse all headers */
00204    if (parse_headers( &msg, HDR_EOH_F, 0)==-1)
00205       goto error;
00206 
00207    hdr = msg.headers;
00208    msg.headers = 0;
00209 
00210    free_sip_msg( &msg );
00211    return hdr;
00212 error:
00213    free_sip_msg( &msg );
00214    return 0;
00215 }
00216 
00217 
00218 /* Build a local request based on a previous request; the only
00219    customers of this function are local ACK and local CANCEL
00220  */
00221 char *build_local(struct cell *Trans,unsigned int branch,
00222    unsigned int *len, char *method, int method_len, str *uas_to)
00223 {
00224    char                *cancel_buf, *p, *via;
00225    unsigned int         via_len;
00226    struct hdr_field    *buf_hdrs;
00227    struct hdr_field    *hdr;
00228    struct sip_msg      *req;
00229    char branch_buf[MAX_BRANCH_PARAM_LEN];
00230    str branch_str;
00231    struct hostport hp;
00232    str from;
00233    str to;
00234    str cseq_n;
00235 
00236    req = Trans->uas.request;
00237    from = Trans->from;
00238    cseq_n = Trans->cseq_n;
00239    to = *uas_to;
00240    buf_hdrs = 0;
00241 
00242    if (req 
00243       && ( req->msg_flags&(FL_USE_UAC_FROM|FL_USE_UAC_CSEQ)
00244          || (method_len!=ACK_LEN && (req->msg_flags&FL_USE_UAC_TO)) )
00245       )
00246    {
00247       if ( extract_hdrs( Trans->uac[branch].request.buffer.s,
00248       Trans->uac[branch].request.buffer.len,
00249       (req->msg_flags&FL_USE_UAC_FROM)?&from:0 ,
00250       (req->msg_flags&FL_USE_UAC_TO && method_len!=ACK_LEN)?&to:0 ,
00251       (req->msg_flags&FL_USE_UAC_CSEQ)?&cseq_n:0 )!=0 ) {
00252          LM_ERR("build_local: failed to extract UAC hdrs\n");
00253          goto error;
00254       }
00255    }
00256    LM_DBG("using FROM=<%.*s>, TO=<%.*s>, CSEQ_N=<%.*s>\n",
00257       from.len,from.s , to.len,to.s , cseq_n.len,cseq_n.s);
00258 
00259    /* method, separators, version  */
00260    *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN;
00261    *len+=Trans->uac[branch].uri.len;
00262 
00263    /*via*/
00264    branch_str.s=branch_buf;
00265    if (!t_calc_branch(Trans,  branch, branch_str.s, &branch_str.len ))
00266       goto error;
00267    set_hostport(&hp, (is_local(Trans))?0:req);
00268    via=via_builder(&via_len, Trans->uac[branch].request.dst.send_sock,
00269       &branch_str, 0, Trans->uac[branch].request.dst.proto, &hp );
00270    if (!via){
00271       LM_ERR("no via header got from builder\n");
00272       goto error;
00273    }
00274    *len+= via_len;
00275    /*headers*/
00276    *len+=from.len+Trans->callid.len+to.len+cseq_n.len+1+method_len+CRLF_LEN;
00277 
00278    /* copy'n'paste Route headers that were sent out */
00279    /* dcm: todo - investigate why not applies to local requests?!? */
00280    if (!is_local(Trans)) {
00281       buf_hdrs = extract_parsed_hdrs(Trans->uac[branch].request.buffer.s,
00282          Trans->uac[branch].request.buffer.len );
00283       if (buf_hdrs==NULL) {
00284          LM_ERR("failed to reparse the request buffer\n");
00285          goto error01;
00286       }
00287       for ( hdr=buf_hdrs ; hdr ; hdr=hdr->next )
00288          if (hdr->type==HDR_ROUTE_T)
00289             *len+=hdr->len;
00290    }
00291 
00292    /* User Agent */
00293    if (server_signature) {
00294       *len += user_agent_header.len + CRLF_LEN;
00295    }
00296    /* Content Length, MaxFwd, EoM */
00297    *len+=LOCAL_MAXFWD_HEADER_LEN + CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN;
00298 
00299    cancel_buf=shm_malloc( *len+1 );
00300    if (!cancel_buf)
00301    {
00302       LM_ERR("no more share memory\n");
00303       goto error02;
00304    }
00305    p = cancel_buf;
00306 
00307    append_str( p, method, method_len );
00308    *(p++) = ' ';
00309    append_str( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len);
00310    append_str( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
00311 
00312    /* insert our via */
00313    append_str(p,via,via_len);
00314 
00315    /*other headers*/
00316    append_str( p, from.s, from.len );
00317    append_str( p, Trans->callid.s, Trans->callid.len );
00318    append_str( p, to.s, to.len );
00319 
00320    append_str( p, cseq_n.s, cseq_n.len );
00321    *(p++) = ' ';
00322    append_str( p, method, method_len );
00323    append_str( p, CRLF LOCAL_MAXFWD_HEADER,
00324       CRLF_LEN+LOCAL_MAXFWD_HEADER_LEN );
00325 
00326    /* add Route hdrs (if any) */
00327    for ( hdr=buf_hdrs ; hdr ; hdr=hdr->next )
00328       if(hdr->type==HDR_ROUTE_T) {
00329          append_str(p, hdr->name.s, hdr->len );
00330       }
00331 
00332    /* User Agent header, Content Length, EoM */
00333    if (server_signature) {
00334       append_str(p, user_agent_header.s, user_agent_header.len);
00335       append_str(p, CRLF CONTENT_LENGTH "0" CRLF CRLF ,
00336          CRLF_LEN+CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
00337    } else {
00338       append_str(p, CONTENT_LENGTH "0" CRLF CRLF ,
00339          CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
00340    }
00341    *p=0;
00342 
00343    pkg_free(via);
00344    free_hdr_field_lst(buf_hdrs);
00345    return cancel_buf;
00346 error02:
00347    free_hdr_field_lst(buf_hdrs);
00348 error01:
00349    pkg_free(via);
00350 error:
00351    return NULL;
00352 }
00353 
00354 
00355 struct rte {
00356    rr_t* ptr;
00357    struct rte* next;
00358 };
00359 
00360 
00361 static inline void free_rte_list(struct rte* list)
00362 {
00363    struct rte* ptr;
00364    
00365    while(list) {
00366       ptr = list;
00367       list = list->next;
00368       pkg_free(ptr);
00369    }
00370 }
00371 
00372 
00373 static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte** list, str* ruri, str* next_hop)
00374 {
00375    struct hdr_field* ptr;
00376    rr_t* p;
00377    struct rte* t, *head;
00378    struct sip_uri puri;
00379    
00380    ptr = msg->record_route;
00381    head = 0;
00382    while(ptr) {
00383       if (ptr->type == HDR_RECORDROUTE_T) {
00384          if (parse_rr(ptr) < 0) {
00385             LM_ERR("failed to parse Record-Route header\n");
00386             return -1;
00387          }
00388          
00389          p = (rr_t*)ptr->parsed;
00390          while(p) {
00391             t = (struct rte*)pkg_malloc(sizeof(struct rte));
00392             if (!t) {
00393                LM_ERR("no more pkg memory\n");
00394                free_rte_list(head);
00395                return -1;
00396             }
00397             t->ptr = p;
00398             t->next = head;
00399             head = t;
00400             p = p->next;
00401          }
00402       }
00403       ptr = ptr->next;
00404    }
00405    
00406    if (head) {
00407       if (parse_uri(head->ptr->nameaddr.uri.s, head->ptr->nameaddr.uri.len, &puri) < 0) {
00408          LM_ERR("failed to parse URI\n");
00409          free_rte_list(head);
00410          return -1;
00411       }
00412       
00413       if (puri.lr.s) {
00414               /* Next hop is loose router */
00415          *ruri = *contact;
00416          *next_hop = head->ptr->nameaddr.uri;
00417       } else {
00418               /* Next hop is strict router */
00419          *ruri = head->ptr->nameaddr.uri;
00420          *next_hop = *ruri;
00421          t = head;
00422          head = head->next;
00423          pkg_free(t);
00424       }
00425    } else {
00426            /* No routes */
00427       *ruri = *contact;
00428       *next_hop = *contact;
00429    }
00430    
00431    *list = head;
00432    return 0;
00433 }
00434 
00435 
00436 static inline int calc_routeset_len(struct rte* list, str* contact)
00437 {
00438    struct rte* ptr;
00439    int ret;
00440    
00441    if (list || contact) {
00442       ret = ROUTE_PREFIX_LEN + CRLF_LEN;
00443    } else {
00444       return 0;
00445    }
00446    
00447    ptr = list;
00448    while(ptr) {
00449       if (ptr != list) {
00450          ret += ROUTE_SEPARATOR_LEN;
00451       }
00452       ret += ptr->ptr->len;
00453       ptr = ptr->next;
00454    }
00455    
00456    if (contact) {
00457       if (list) ret += ROUTE_SEPARATOR_LEN;
00458       ret += 2 + contact->len;
00459    }
00460    
00461    return ret;
00462 }
00463 
00464 
00465 /*
00466  * Print the route set
00467  */
00468 static inline char* print_rs(char* p, struct rte* list, str* contact)
00469 {
00470    struct rte* ptr;
00471    
00472    if (list || contact) {
00473       append_str(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
00474    } else {
00475       return p;
00476    }
00477    
00478    ptr = list;
00479    while(ptr) {
00480       if (ptr != list) {
00481          append_str(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
00482       }
00483       
00484       append_str(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len);
00485       ptr = ptr->next;
00486    }
00487    
00488    if (contact) {
00489       if (list) append_str(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
00490       *p++ = '<';
00491       append_str(p, contact->s, contact->len);
00492       *p++ = '>';
00493    }
00494    
00495    append_str(p, CRLF, CRLF_LEN);
00496    return p;
00497 }
00498 
00499 
00500 /*
00501  * Parse Contact header field body and extract URI
00502  * Does not parse headers !
00503  */
00504 static inline int get_contact_uri(struct sip_msg* msg, str* uri)
00505 {
00506    contact_t* c;
00507    
00508    uri->len = 0;
00509    if (!msg->contact) return 1;
00510    
00511    if (parse_contact(msg->contact) < 0) {
00512       LM_ERR("failed to parse Contact body\n");
00513       return -1;
00514    }
00515    
00516    c = ((contact_body_t*)msg->contact->parsed)->contacts;
00517    
00518    if (!c) {
00519       LM_ERR("body or * contact\n");
00520       return -2;
00521    }
00522    
00523    *uri = c->uri;
00524    return 0;
00525 }
00526 
00527 
00528 
00529 /*
00530  * The function creates an ACK for a local INVITE. If 200 OK, route set 
00531  * will be created and parsed
00532  */
00533 char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans,
00534                      unsigned int branch, str* to, unsigned int *len)
00535 {
00536    char *req_buf, *p, *via;
00537    unsigned int via_len;
00538    char branch_buf[MAX_BRANCH_PARAM_LEN];
00539    int branch_len;
00540    str branch_str;
00541    struct hostport hp;
00542    struct rte* list;
00543    str contact, ruri, *cont;
00544    struct socket_info* send_sock;
00545    str next_hop;
00546 
00547 
00548    if (rpl->first_line.u.reply.statuscode < 300 ) {
00549       /* build e2e ack for 2xx reply -> we need the route set */
00550       if (get_contact_uri(rpl, &contact) < 0) {
00551          return 0;
00552       }
00553 
00554       if (process_routeset(rpl, &contact, &list, &ruri, &next_hop) < 0) {
00555          return 0;
00556       }
00557 
00558       if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
00559          /* contact != ruri means that the next
00560           * hop is a strict router, cont will be non-zero
00561           * and print_routeset will append it at the end
00562           * of the route set
00563           */
00564          cont = &contact;
00565       } else {
00566          /* Next hop is a loose router, nothing to append */
00567          cont = 0;
00568       }
00569    } else {
00570       /* build hop-by-hop ack for negative reply ->
00571        * ruri is the same as in INVITE; no route set */
00572       ruri = Trans->uac[branch].uri;
00573       cont = 0;
00574       list = 0;
00575    }
00576 
00577    /* method, separators, version: "ACK sip:user@domain.org SIP/2.0" */
00578    *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
00579    *len += ruri.len;
00580 
00581    /* use same socket as for INVITE -bogdan */
00582    send_sock = Trans->uac[branch].request.dst.send_sock;
00583 
00584    if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
00585    branch_str.s = branch_buf;
00586    branch_str.len = branch_len;
00587    set_hostport(&hp, 0);
00588 
00589    /* build via */
00590    via = via_builder(&via_len, send_sock, &branch_str, 0, 
00591          send_sock->proto, &hp);
00592    if (!via) {
00593       LM_ERR("no via header got from builder\n");
00594       goto error;
00595    }
00596    *len+= via_len;
00597 
00598    /*headers*/
00599    *len += Trans->from.len + Trans->callid.len + to->len +
00600       Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;
00601 
00602    /* copy'n'paste Route headers */
00603    *len += calc_routeset_len(list, cont);
00604 
00605    /* User Agent */
00606    if (server_signature)
00607       *len += user_agent_header.len + CRLF_LEN;
00608 
00609    /* Content Length, EoM */
00610    *len += CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN;
00611 
00612    req_buf = shm_malloc(*len + 1);
00613    if (!req_buf) {
00614       LM_ERR("no more share memory\n");
00615       goto error01;
00616    }
00617    p = req_buf;
00618 
00619    append_str( p, ACK " ", ACK_LEN+1 );
00620    append_str(p, ruri.s, ruri.len );
00621    append_str( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
00622 
00623    /* insert our via */
00624    append_str(p, via, via_len);
00625 
00626    /*other headers*/
00627    append_str(p, Trans->from.s, Trans->from.len);
00628    append_str(p, Trans->callid.s, Trans->callid.len);
00629    append_str(p, to->s, to->len);
00630 
00631    append_str(p, Trans->cseq_n.s, Trans->cseq_n.len);
00632    *(p++) = ' ';
00633    append_str(p, ACK CRLF, ACK_LEN+CRLF_LEN);
00634 
00635    /* Routeset */
00636    p = print_rs(p, list, cont);
00637 
00638    /* User Agent header, Content Length, EoM */
00639    if (server_signature) {
00640       append_str(p, user_agent_header.s, user_agent_header.len);
00641       append_str(p, CRLF CONTENT_LENGTH "0" CRLF CRLF,
00642          CRLF_LEN+CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
00643    } else {
00644       append_str(p, CONTENT_LENGTH "0" CRLF CRLF,
00645          CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
00646    }
00647    *p = 0;
00648 
00649    pkg_free(via);
00650    free_rte_list(list);
00651    return req_buf;
00652 error01:
00653    pkg_free(via);
00654 error:
00655    free_rte_list(list);
00656    return 0;
00657 }
00658 
00659 
00660 /*
00661  * Convert length of body into asciiz
00662  */
00663 static inline int print_content_length(str* dest, str* body)
00664 {
00665    static char content_length[INT2STR_MAX_LEN];
00666    int len;
00667 
00668    /* Print Content-Length */
00669    if (body && body->len) {
00670       dest->s = int2bstr(body->len, content_length, &len);
00671       dest->len = len;
00672    } else {
00673       dest->s = "0";
00674       dest->len = 1;
00675    }
00676    return 0;
00677 }
00678 
00679 
00680 /*
00681  * Convert CSeq number into asciiz
00682  */
00683 static inline int print_cseq_num(str* _s, dlg_t* _d)
00684 {
00685    static char cseq[INT2STR_MAX_LEN];
00686    int len;
00687 
00688    _s->s = int2bstr(_d->loc_seq.value, cseq, &len);
00689    _s->len = len;
00690    return 0;
00691 }
00692 
00693 
00694 /*
00695  * Create Via header
00696  */
00697 static inline int assemble_via(str* dest, struct cell* t, struct socket_info* sock, int branch)
00698 {
00699    static char branch_buf[MAX_BRANCH_PARAM_LEN];
00700    char* via;
00701    int len;
00702    unsigned int via_len;
00703    str branch_str;
00704    struct hostport hp;
00705 
00706    if (!t_calc_branch(t, branch, branch_buf, &len)) {
00707       LM_ERR("branch calculation failed\n");
00708       return -1;
00709    }
00710    
00711    branch_str.s = branch_buf;
00712    branch_str.len = len;
00713 
00714 #ifdef XL_DEBUG
00715    printf("!!!proto: %d\n", sock->proto);
00716 #endif
00717 
00718    set_hostport(&hp, 0);
00719    via = via_builder(&via_len, sock, &branch_str, 0, sock->proto, &hp);
00720    if (!via) {
00721       LM_ERR("via building failed\n");
00722       return -2;
00723    }
00724    
00725    dest->s = via;
00726    dest->len = via_len;
00727    return 0;
00728 }
00729 
00730 
00731 /*
00732  * Print Request-URI
00733  */
00734 static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struct cell* t, int branch)
00735 {
00736    append_str(w, method->s, method->len); 
00737    append_str(w, " ", 1); 
00738 
00739    t->uac[branch].uri.s = w; 
00740    t->uac[branch].uri.len = dialog->hooks.request_uri->len;
00741 
00742    append_str(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len); 
00743    append_str(w, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
00744    LM_DBG("%.*s\n",dialog->hooks.request_uri->len, dialog->hooks.request_uri->s );
00745    return w;
00746 }
00747 
00748 
00749 /*
00750  * Print To header field
00751  */
00752 static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
00753 {
00754    t->to.s = w;
00755    t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN;
00756 
00757    append_str(w, TO, TO_LEN);
00758    
00759    if(dialog->rem_dname.len) {
00760       t->to.len += dialog->rem_dname.len + 1;
00761       append_str(w, dialog->rem_dname.s, dialog->rem_dname.len);
00762       append_str(w, "<", 1);
00763    }
00764 
00765    append_str(w, dialog->rem_uri.s, dialog->rem_uri.len);
00766 
00767    if(dialog->rem_dname.len) {
00768       t->to.len += 1;
00769       append_str(w, ">", 1);
00770    }
00771 
00772    if (dialog->id.rem_tag.len) {
00773       t->to.len += TOTAG_LEN + dialog->id.rem_tag.len ;
00774       append_str(w, TOTAG, TOTAG_LEN);
00775       append_str(w, dialog->id.rem_tag.s, dialog->id.rem_tag.len);
00776    }
00777 
00778    append_str(w, CRLF, CRLF_LEN);
00779    return w;
00780 }
00781 
00782 
00783 /*
00784  * Print From header field
00785  */
00786 static inline char* print_from(char* w, dlg_t* dialog, struct cell* t)
00787 {
00788    t->from.s = w;
00789    t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN;
00790 
00791    append_str(w, FROM, FROM_LEN);
00792 
00793    if(dialog->loc_dname.len) {
00794       t->from.len += dialog->loc_dname.len + 1;
00795       append_str(w, dialog->loc_dname.s, dialog->loc_dname.len);
00796       append_str(w, "<", 1);
00797    }
00798    
00799    append_str(w, dialog->loc_uri.s, dialog->loc_uri.len);
00800 
00801    if(dialog->loc_dname.len) {
00802       t->from.len += 1;
00803       append_str(w, ">", 1);
00804    }
00805 
00806    if (dialog->id.loc_tag.len) {
00807       t->from.len += FROMTAG_LEN + dialog->id.loc_tag.len;
00808       append_str(w, FROMTAG, FROMTAG_LEN);
00809       append_str(w, dialog->id.loc_tag.s, dialog->id.loc_tag.len);
00810    }
00811 
00812    append_str(w, CRLF, CRLF_LEN);
00813    return w;
00814 }
00815 
00816 
00817 /*
00818  * Print CSeq header field
00819  */
00820 char* print_cseq_mini(char* target, str* cseq, str* method) {
00821    append_str(target, CSEQ, CSEQ_LEN);
00822    append_str(target, cseq->s, cseq->len);
00823    append_str(target, " ", 1);
00824    append_str(target, method->s, method->len);
00825    return target;
00826 }
00827 
00828 static inline char* print_cseq(char* w, str* cseq, str* method, struct cell* t)
00829 {
00830    t->cseq_n.s = w; 
00831    /* don't include method name and CRLF -- subsequent
00832     * local requests ACK/CANCEL will add their own */
00833    t->cseq_n.len = CSEQ_LEN + cseq->len; 
00834    w = print_cseq_mini(w, cseq, method);
00835    return w;
00836 }
00837 
00838 /*
00839  * Print Call-ID header field
00840  * created an extra function for pure header field creation, that is used by t_cancel for 
00841  * t_uac_cancel FIFO function.
00842  */
00843 char* print_callid_mini(char* target, str callid) {
00844    append_str(target, CALLID, CALLID_LEN);
00845    append_str(target, callid.s, callid.len);
00846    append_str(target, CRLF, CRLF_LEN);
00847    return target;
00848 }
00849 
00850 static inline char* print_callid(char* w, dlg_t* dialog, struct cell* t)
00851 {
00852    /* begins with CRLF, not included in t->callid, don`t know why...?!? */
00853    append_str(w, CRLF, CRLF_LEN);
00854    t->callid.s = w;
00855    t->callid.len = CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;
00856 
00857    w = print_callid_mini(w, dialog->id.call_id);
00858    return w;
00859 }
00860 
00861 
00862 /*
00863  * Create a request
00864  */
00865 char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, 
00866                               int branch, struct cell *t, int* len)
00867 {
00868    char* buf, *w;
00869    str content_length, cseq, via;
00870 
00871    if (!method || !dialog) {
00872       LM_ERR("inalid parameter value\n");
00873       return 0;
00874    }
00875    if (print_content_length(&content_length, body) < 0) {
00876       LM_ERR("failed to print content-length\n");
00877       return 0;
00878    }
00879    if (print_cseq_num(&cseq, dialog) < 0) {
00880       LM_ERR("failed to print CSeq number\n");
00881       return 0;
00882    }
00883    *len = method->len + 1 + dialog->hooks.request_uri->len + 1 + 
00884       SIP_VERSION_LEN + CRLF_LEN;
00885 
00886    if (assemble_via(&via, t, dialog->send_sock, branch) < 0) {
00887       LM_ERR("failed to assemble Via\n");
00888       return 0;
00889    }
00890    *len += via.len;
00891 
00892    /* To */
00893    *len += TO_LEN 
00894       + (dialog->rem_dname.len ? (2 + dialog->rem_dname.len) : 0)
00895       + dialog->rem_uri.len
00896       + (dialog->id.rem_tag.len ? (TOTAG_LEN + dialog->id.rem_tag.len) : 0)
00897       + CRLF_LEN;
00898    /* From */
00899    *len += FROM_LEN 
00900       + (dialog->loc_dname.len ? (2 + dialog->loc_dname.len) : 0)
00901       + dialog->loc_uri.len
00902       + (dialog->id.loc_tag.len ? (FROMTAG_LEN + dialog->id.loc_tag.len):0)
00903       + CRLF_LEN;
00904    /* Call-ID */
00905    *len += CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;
00906    /* CSeq */
00907    *len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN;
00908    /* Route set */
00909    *len += calculate_routeset_length(dialog);
00910    /* Content-Length */
00911    *len += CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN;
00912    /* Signature */
00913    *len += (server_signature ? (user_agent_header.len + CRLF_LEN) : 0);
00914    /* Additional headers */
00915    *len += (headers ? headers->len : 0);
00916    /* Message body */
00917    *len += (body ? body->len : 0);
00918    /* End of Header */
00919    *len += CRLF_LEN;
00920 
00921    buf = shm_malloc(*len + 1);
00922    if (!buf) {
00923       LM_ERR("no more share memory\n");
00924       goto error;
00925    }
00926    
00927    w = buf;
00928 
00929    w = print_request_uri(w, method, dialog, t, branch);  /* Request-URI */
00930    append_str(w, via.s, via.len);                     /* Top-most Via */
00931    w = print_to(w, dialog, t);                           /* To */
00932    w = print_from(w, dialog, t);                         /* From */
00933    w = print_cseq(w, &cseq, method, t);                  /* CSeq */
00934    w = print_callid(w, dialog, t);                       /* Call-ID */
00935    w = print_routeset(w, dialog);                        /* Route set */
00936 
00937    /* Content-Length */
00938    append_str(w, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
00939    append_str(w, content_length.s, content_length.len);
00940    append_str(w, CRLF, CRLF_LEN);
00941 
00942    /* Server signature */
00943    if (server_signature) {
00944       append_str(w, user_agent_header.s, user_agent_header.len);
00945       append_str(w, CRLF, CRLF_LEN);
00946    }
00947    if (headers)
00948       append_str(w, headers->s, headers->len);
00949    append_str(w, CRLF, CRLF_LEN);
00950    if (body)
00951       append_str(w, body->s, body->len);
00952 
00953 #ifdef EXTRA_DEBUG
00954    if (w-buf != *len ) abort();
00955 #endif
00956 
00957    pkg_free(via.s);
00958    return buf;
00959 
00960  error:
00961    pkg_free(via.s);
00962    return 0;
00963 }
00964 
00965 
00966 int t_calc_branch(struct cell *t, 
00967    int b, char *branch, int *branch_len)
00968 {
00969    return syn_branch ?
00970       branch_builder( t->hash_index,
00971          t->label, 0,
00972          b, branch, branch_len )
00973       : branch_builder( t->hash_index,
00974          0, t->md5,
00975          b, branch, branch_len );
00976 }
00977 
00978 char *build_uac_cancel(str *headers,str *body,struct cell *cancelledT,
00979                               unsigned int branch, unsigned int *len)
00980 {
00981    char *cancel_buf, *p, *via;
00982    unsigned int via_len;
00983    char branch_buf[MAX_BRANCH_PARAM_LEN];
00984    str branch_str;
00985    struct hostport hp;
00986    str content_length;
00987 
00988    LM_DBG("sing FROM=<%.*s>, TO=<%.*s>, CSEQ_N=<%.*s>\n",
00989       cancelledT->from.len, cancelledT->from.s, cancelledT->to.len,
00990       cancelledT->to.s, cancelledT->cseq_n.len, cancelledT->cseq_n.s);
00991 
00992    branch_str.s=branch_buf;
00993    if (!t_calc_branch(cancelledT,  branch, branch_str.s, &branch_str.len )){
00994       LM_ERR("failed to create branch !\n");
00995       goto error;
00996    }
00997    set_hostport(&hp,0);
00998    via=via_builder(&via_len, cancelledT->uac[branch].request.dst.send_sock,
00999          &branch_str, 0, cancelledT->uac[branch].request.dst.proto, &hp );
01000    if (!via){
01001       LM_ERR("no via header got from builder\n");
01002       goto error;
01003    }
01004 
01005    /* method, separators, version  */
01006    *len=CANCEL_LEN + 2 /* spaces */ +SIP_VERSION_LEN + CRLF_LEN;
01007    *len+=cancelledT->uac[branch].uri.len;
01008    /*via*/
01009    *len+= via_len;
01010    /*From*/
01011    *len+=cancelledT->from.len;
01012    /*To*/
01013    *len+=cancelledT->to.len;
01014    /*CallId*/
01015    *len+=cancelledT->callid.len;
01016    /*CSeq*/
01017    *len+=cancelledT->cseq_n.len+1+CANCEL_LEN+CRLF_LEN;
01018    /* User Agent */
01019    if (server_signature) {
01020       *len += USER_AGENT_LEN + CRLF_LEN;
01021    }
01022    /* Content Length  */
01023    if (print_content_length(&content_length, body) < 0) {
01024       LM_ERR("failed to print content-length\n");
01025       return 0;
01026    }
01027    /* Content-Length */
01028    *len += (body ? (CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN) : 0);
01029    /*Additional headers*/
01030    *len += (headers ? headers->len : 0);
01031    /*EoM*/
01032    *len+= CRLF_LEN;
01033    /* Message body */
01034    *len += (body ? body->len : 0);
01035 
01036    cancel_buf=shm_malloc( *len+1 );
01037    if (!cancel_buf)
01038    {
01039       LM_ERR("no more share memory\n");
01040       goto error01;
01041    }
01042    p = cancel_buf;
01043 
01044    append_str( p, CANCEL, CANCEL_LEN );
01045    *(p++) = ' ';
01046    append_str( p, cancelledT->uac[branch].uri.s,
01047       cancelledT->uac[branch].uri.len);
01048    append_str( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
01049 
01050    /* insert our via */
01051    append_str(p,via,via_len);
01052 
01053    /*other headers*/
01054    append_str( p, cancelledT->from.s, cancelledT->from.len );
01055    append_str( p, cancelledT->callid.s, cancelledT->callid.len );
01056    append_str( p, cancelledT->to.s, cancelledT->to.len );
01057 
01058    append_str( p, cancelledT->cseq_n.s, cancelledT->cseq_n.len );
01059    *(p++) = ' ';
01060    append_str( p, CANCEL, CANCEL_LEN );
01061    append_str( p, CRLF, CRLF_LEN );
01062 
01063    /* User Agent header */
01064    if (server_signature) {
01065       append_str(p,USER_AGENT CRLF, USER_AGENT_LEN+CRLF_LEN );
01066    }
01067    /* Content Length*/
01068    if (body) {
01069       append_str(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
01070       append_str(p, content_length.s, content_length.len);
01071       append_str(p, CRLF, CRLF_LEN);
01072    }
01073    if(headers && headers->len){
01074       append_str(p,headers->s,headers->len);
01075    }
01076    /*EoM*/
01077    append_str(p,CRLF,CRLF_LEN);
01078    if(body && body->len){
01079       append_str(p,body->s,body->len);
01080    }
01081    *p=0;
01082    pkg_free(via);
01083    return cancel_buf;
01084 error01:
01085    pkg_free(via);
01086 error:
01087    return NULL;
01088 }
01089 
01090 /*!
01091  * \brief Check if From/To/CSeq were altered and set approriate flags
01092  */
01093 void check_hdrs_changes(struct sip_msg *msg)
01094 {
01095    struct lump *t;
01096    unsigned int flags;
01097    char *pos;
01098 
01099    flags = FL_USE_UAC_FROM|FL_USE_UAC_TO|FL_USE_UAC_CSEQ;
01100 
01101    /* if internal flags already set, then return */
01102    if((msg->msg_flags&flags) == flags)
01103       return;
01104 
01105    for (t=msg->add_rm;t;t=t->next) {
01106       if ((t->op==LUMP_DEL)||(t->op==LUMP_NOP))
01107       {
01108          pos = msg->buf + t->u.offset;
01109          /* From */
01110          if( ((msg->msg_flags&FL_USE_UAC_FROM)==0)
01111                && (msg->from!=NULL)
01112                && (( pos < msg->from->name.s 
01113                      && pos + t->len > msg->from->name.s )
01114                   || (pos >= msg->from->name.s
01115                      && pos <= msg->from->name.s+msg->from->len)
01116                   )
01117                )
01118             msg->msg_flags |= FL_USE_UAC_FROM;
01119          /* To */
01120          if( ((msg->msg_flags&FL_USE_UAC_TO)==0)
01121                && (msg->to!=NULL)
01122                && (( pos < msg->to->name.s 
01123                      && pos + t->len > msg->to->name.s )
01124                   || (pos >= msg->to->name.s
01125                      && pos <= msg->to->name.s+msg->to->len)
01126                   )
01127                )
01128             msg->msg_flags |= FL_USE_UAC_TO;
01129          /* CSeq */
01130          if( ((msg->msg_flags&FL_USE_UAC_CSEQ)==0)
01131                && (msg->cseq!=NULL)
01132                && (( pos < msg->cseq->name.s 
01133                      && pos + t->len > msg->cseq->name.s )
01134                   || (pos >= msg->cseq->name.s
01135                      && pos <= msg->cseq->name.s+msg->cseq->len)
01136                   )
01137                )
01138             msg->msg_flags |= FL_USE_UAC_CSEQ;
01139 
01140          /* if done, then return */
01141          if((msg->msg_flags&flags) == flags)
01142             return;
01143       }
01144    }
01145 }
01146 

Generated on Thu May 24 20:00:32 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6