12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412 |
- /*
- * $Id$
- *
- * message printing
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * History:
- * ----------
- * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
- * 2003-02-13 build_uac_request uses proto (andrei)
- * 2003-02-28 scratchpad compatibility abandoned (jiri)
- * 2003-04-14 build_local no longer checks reply status as it
- * is now called before reply status is updated to
- * avoid late ACK sending (jiri)
- * 2003-10-02 added via_builder set host/port support (andrei)
- * 2004-02-11 FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
- * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan)
- * 2006-04-21 build_uac_req, assemble_via use struct dest_info now;
- * uri2sock replaced with uri2dst (andrei)
- * 2006-08-11 build_dlg_ack: use the first dns ip for which a send_sock
- * is found (andrei)
- * 2007-03-15 build_dls_ack: removed next_hop and replaced by dst to avoid
- * resolving nexthop twice (andrei)
- * 2007-05-28: build_local_reparse() is introdued: it uses the outgoing
- * INVITE as a source to construct a CANCEL or ACK (Miklos)
- */
- #include "defs.h"
- #ifdef EXTRA_DEBUG
- #include <assert.h>
- #endif
- #include "../../comp_defs.h"
- #include "../../hash_func.h"
- #include "../../globals.h"
- #include "t_funcs.h"
- #include "../../dprint.h"
- #include "../../config.h"
- #include "../../parser/parser_f.h"
- #include "../../ut.h"
- #include "../../parser/msg_parser.h"
- #include "../../parser/contact/parse_contact.h"
- #include "lw_parser.h"
- #include "t_msgbuilder.h"
- #include "uac.h"
- #ifdef USE_DNS_FAILOVER
- #include "../../dns_cache.h"
- #include "../../cfg_core.h" /* cfg_get(core, core_cfg, use_dns_failover) */
- #endif
- /* convenience macros */
- #define memapp(_d,_s,_len) \
- do{\
- memcpy((_d),(_s),(_len));\
- (_d) += (_len);\
- }while(0)
- #define append_mem_block(_d,_s,_len) \
- do{\
- memcpy((_d),(_s),(_len));\
- (_d) += (_len);\
- }while(0)
- #define append_str(_p,_str) \
- do{ \
- memcpy((_p), (_str).s, (_str).len); \
- (_p)+=(_str).len; \
- } while(0)
- /* Build a local request based on a previous request; main
- customers of this function are local ACK and local CANCEL
- */
- char *build_local(struct cell *Trans,unsigned int branch,
- unsigned int *len, char *method, int method_len, str *to)
- {
- char *cancel_buf, *p, *via;
- unsigned int via_len;
- struct hdr_field *hdr;
- char branch_buf[MAX_BRANCH_PARAM_LEN];
- int branch_len;
- str branch_str;
- str via_id;
- struct hostport hp;
- /* init */
- via_id.s=0;
- via_id.len=0;
- /* method, separators, version: "CANCEL sip:[email protected] SIP/2.0" */
- *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN;
- *len+=Trans->uac[branch].uri.len;
- /*via*/
- if (!t_calc_branch(Trans, branch,
- branch_buf, &branch_len ))
- goto error;
- branch_str.s=branch_buf;
- branch_str.len=branch_len;
- set_hostport(&hp, (is_local(Trans))?0:(Trans->uas.request));
- #ifdef USE_TCP
- if (!is_local(Trans) && ((Trans->uas.request->rcv.proto==PROTO_TCP)
- #ifdef USE_TLS
- || (Trans->uas.request->rcv.proto==PROTO_TLS)
- #endif /* USE_TLS */
- )){
- if ((via_id.s=id_builder(Trans->uas.request,
- (unsigned int*)&via_id.len))==0){
- LOG(L_ERR, "ERROR: build_local: id builder failed\n");
- /* try to continue without id */
- }
- }
- #endif /* USE_TCP */
- via=via_builder(&via_len, &Trans->uac[branch].request.dst,
- &branch_str, via_id.s?&via_id:0 , &hp );
-
- /* via_id.s not needed anylonger => free it */
- if (via_id.s){
- pkg_free(via_id.s);
- via_id.s=0;
- via_id.len=0;
- }
-
- if (!via)
- {
- LOG(L_ERR, "ERROR: build_local: "
- "no via header got from builder\n");
- goto error;
- }
- *len+= via_len;
- /*headers*/
- *len+=Trans->from.len+Trans->callid.len+to->len+
- +Trans->cseq_n.len+1+method_len+CRLF_LEN;
- /* copy'n'paste Route headers */
- if (!is_local(Trans)) {
- for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
- if (hdr->type==HDR_ROUTE_T)
- *len+=hdr->len;
- }
- /* User Agent */
- if (server_signature) {
- *len += USER_AGENT_LEN + CRLF_LEN;
- }
- /* Content Length, EoM */
- *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN;
- cancel_buf=shm_malloc( *len+1 );
- if (!cancel_buf)
- {
- LOG(L_ERR, "ERROR: build_local: cannot allocate memory\n");
- goto error01;
- }
- p = cancel_buf;
- append_mem_block( p, method, method_len );
- append_mem_block( p, " ", 1 );
- append_str( p, Trans->uac[branch].uri );
- append_mem_block( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
- /* insert our via */
- append_mem_block(p,via,via_len);
- /*other headers*/
- append_str( p, Trans->from );
- append_str( p, Trans->callid );
- append_str( p, *to );
- append_str( p, Trans->cseq_n );
- append_mem_block( p, " ", 1 );
- append_mem_block( p, method, method_len );
- append_mem_block( p, CRLF, CRLF_LEN );
- if (!is_local(Trans)) {
- for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
- if(hdr->type==HDR_ROUTE_T) {
- append_mem_block(p, hdr->name.s, hdr->len );
- }
- }
- /* User Agent header */
- if (server_signature) {
- append_mem_block(p,USER_AGENT CRLF, USER_AGENT_LEN+CRLF_LEN );
- }
- /* Content Length, EoM */
- append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF ,
- CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
- *p=0;
- pkg_free(via);
- return cancel_buf;
- error01:
- pkg_free(via);
- error:
- return NULL;
- }
- /* Re-parsing version of build_local() function:
- * it builds a local CANCEL or ACK (for non-200 response) request based on
- * the previous INVITE which was sent out.
- *
- * Can not be used to build other type of requests!
- */
- char *build_local_reparse(struct cell *Trans,unsigned int branch,
- unsigned int *len, char *method, int method_len, str *to)
- {
- char *invite_buf, *invite_buf_end;
- char *cancel_buf;
- char *s, *s1, *d; /* source and destination buffers */
- short invite_len;
- enum _hdr_types_t hf_type;
- int first_via, to_len;
- invite_buf = Trans->uac[branch].request.buffer;
- invite_len = Trans->uac[branch].request.buffer_len;
- if (!invite_buf || !invite_len) {
- LOG(L_ERR, "ERROR: build_local_reparse: INVITE is missing\n");
- goto error;
- }
- if ((*invite_buf != 'I') && (*invite_buf != 'i')) {
- LOG(L_ERR, "ERROR: build_local_reparse: trying to call build_local_reparse() for a non-INVITE request?\n");
- goto error;
- }
- invite_buf_end = invite_buf + invite_len;
- s = invite_buf;
- /* Allocate memory for the new message.
- The new request will be smaller than the INVITE, so the same size is enough.
- I just extend it with the length of new To HF to be sure.
- Ugly, but we avoid lots of checks and memory allocations this way */
- to_len = to ? to->len : 0;
- cancel_buf = shm_malloc(sizeof(char)*(invite_len + to_len));
- if (!cancel_buf)
- {
- LOG(L_ERR, "ERROR: build_local_reparse: cannot allocate shared memory\n");
- goto error;
- }
- d = cancel_buf;
- /* method name + space */
- append_mem_block(d, method, method_len);
- *d = ' ';
- d++;
- /* skip "INVITE " and copy the rest of the line including CRLF */
- s += 7;
- s1 = s;
- s = eat_line(s, invite_buf_end - s);
- append_mem_block(d, s1, s - s1);
- /* check every header field name,
- we must exclude and modify some of the headers */
- first_via = 1;
- while (s < invite_buf_end) {
- s1 = s;
- if ((*s == '\n') || (*s == '\r')) {
- /* end of SIP msg */
- hf_type = HDR_EOH_T;
- } else {
- /* parse HF name */
- s = lw_get_hf_name(s, invite_buf_end,
- &hf_type);
- }
- switch(hf_type) {
- case HDR_CSEQ_T:
- /* find the method name and replace it */
- while ((s < invite_buf_end)
- && ((*s == ':') || (*s == ' ') || (*s == '\t') || ((*s >= '0') && (*s <= '9')))
- ) s++;
- append_mem_block(d, s1, s - s1);
- append_mem_block(d, method, method_len);
- append_mem_block(d, CRLF, CRLF_LEN);
- s = lw_next_line(s, invite_buf_end);
- break;
- case HDR_VIA_T:
- s = lw_next_line(s, invite_buf_end);
- if (first_via) {
- /* copy hf */
- append_mem_block(d, s1, s - s1);
- first_via = 0;
- } /* else skip this line, we need olny the first via */
- break;
- case HDR_TO_T:
- if (to_len == 0) {
- /* there is no To tag required, just copy paste the header */
- s = lw_next_line(s, invite_buf_end);
- append_mem_block(d, s1, s - s1);
- } else {
- /* use the given To HF instead of the original one */
- append_mem_block(d, to->s, to->len);
- /* move the pointer to the next line */
- s = lw_next_line(s, invite_buf_end);
- }
- break;
- case HDR_FROM_T:
- case HDR_CALLID_T:
- case HDR_ROUTE_T:
- case HDR_MAXFORWARDS_T:
- /* copy hf */
- s = lw_next_line(s, invite_buf_end);
- append_mem_block(d, s1, s - s1);
- break;
- case HDR_REQUIRE_T:
- case HDR_PROXYREQUIRE_T:
- /* skip this line */
- s = lw_next_line(s, invite_buf_end);
- break;
- case HDR_CONTENTLENGTH_T:
- /* copy hf name with 0 value */
- append_mem_block(d, s1, s - s1);
- append_mem_block(d, ": 0" CRLF, 3 + CRLF_LEN);
- /* move the pointer to the next line */
- s = lw_next_line(s, invite_buf_end);
- break;
- case HDR_EOH_T:
- /* end of SIP message found */
- append_mem_block(d, CRLF, CRLF_LEN);
- *len = d - cancel_buf;
- /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */
- return cancel_buf;
- default:
- s = lw_next_line(s, invite_buf_end);
- if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len
- && (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end)
- && (strncasecmp(s1,
- cfg_get(tm, tm_cfg, ac_extra_hdrs).s,
- cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)
- ) {
- append_mem_block(d, s1, s - s1);
- } /* else skip this line */
- break;
- }
- }
- /* HDR_EOH_T was not found in the buffer, the message is corrupt */
- LOG(L_ERR, "ERROR: build_local_reparse: HDR_EOH_T was not found\n");
- shm_free(cancel_buf);
- error:
- LOG(L_ERR, "ERROR: build_local_reparse: cannot build %.*s request\n", method_len, method);
- return NULL;
- }
- typedef struct rte {
- rr_t* ptr;
- /* 'ptr' above doesn't point to a mem chunk linked to a sip_msg, so it
- * won't be free'd along with it => it must be free'd "manually" */
- int free_rr;
- struct rte* next;
- } rte_t;
-
- static inline void free_rte_list(struct rte* list)
- {
- struct rte* ptr;
-
- while(list) {
- ptr = list;
- list = list->next;
- if (ptr->free_rr)
- free_rr(&ptr->ptr);
- pkg_free(ptr);
- }
- }
- static inline int calc_routeset_len(struct rte* list, str* contact)
- {
- struct rte* ptr;
- int ret;
-
- if (list || contact) {
- ret = ROUTE_PREFIX_LEN + CRLF_LEN;
- } else {
- return 0;
- }
-
- ptr = list;
- while(ptr) {
- if (ptr != list) {
- ret += ROUTE_SEPARATOR_LEN;
- }
- ret += ptr->ptr->len;
- ptr = ptr->next;
- }
-
- if (contact) {
- if (list) ret += ROUTE_SEPARATOR_LEN;
- ret += 2 + contact->len;
- }
-
- return ret;
- }
- /*
- * Print the route set
- */
- static inline char* print_rs(char* p, struct rte* list, str* contact)
- {
- struct rte* ptr;
-
- if (list || contact) {
- memapp(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
- } else {
- return p;
- }
-
- ptr = list;
- while(ptr) {
- if (ptr != list) {
- memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
- }
-
- memapp(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len);
- ptr = ptr->next;
- }
-
- if (contact) {
- if (list) memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
- *p++ = '<';
- append_str(p, *contact);
- *p++ = '>';
- }
-
- memapp(p, CRLF, CRLF_LEN);
- return p;
- }
- /*
- * Parse Contact header field body and extract URI
- * Does not parse headers !
- */
- static inline int get_contact_uri(struct sip_msg* msg, str* uri)
- {
- contact_t* c;
-
- uri->len = 0;
- if (!msg->contact) return 1;
-
- if (parse_contact(msg->contact) < 0) {
- LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");
- return -1;
- }
-
- c = ((contact_body_t*)msg->contact->parsed)->contacts;
-
- if (!c) {
- LOG(L_ERR, "get_contact_uri: Empty body or * contact\n");
- return -2;
- }
-
- *uri = c->uri;
- return 0;
- }
- /**
- * Extract route set from the message (out of Record-Route, if reply, OR
- * Route, if request).
- * The route set is returned into the "UAC-format" (keep order for Rs, reverse
- * RRs).
- */
- static inline int get_uac_rs(sip_msg_t *msg, int is_req, struct rte **rtset)
- {
- struct hdr_field* ptr;
- rr_t *p, *new_p;
- struct rte *t, *head, *old_head;
- head = 0;
- for (ptr = is_req ? msg->route : msg->record_route; ptr; ptr = ptr->next) {
- switch (ptr->type) {
- case HDR_RECORDROUTE_T:
- if (is_req)
- continue;
- break;
- case HDR_ROUTE_T:
- if (! is_req)
- continue;
- break;
- default:
- continue;
- }
- if (parse_rr(ptr) < 0) {
- ERR("failed to parse Record-/Route HF (%d).\n", ptr->type);
- goto err;
- }
-
- p = (rr_t*)ptr->parsed;
- while(p) {
- if (! (t = (struct rte*)pkg_malloc(sizeof(struct rte)))) {
- ERR("out of pkg mem (asked for: %zd).\n", sizeof(struct rte));
- goto err;
- }
- if (is_req) {
- /* in case of requests, the sip_msg structure is free'd before
- * rte list is evaluated => must do a copy of it */
- if (duplicate_rr(&new_p, p) < 0) {
- pkg_free(t);
- ERR("failed to duplicate RR");
- goto err;
- }
- t->ptr = new_p;
- } else {
- t->ptr = p;
- }
- t->free_rr = is_req;
- t->next = head;
- head = t;
- p = p->next;
- }
- }
- if (is_req) {
- /* harvesting the R/RR HF above inserts at head, which suites RRs (as
- * they must be reversed, anyway), but not Rs => reverse once more */
- old_head = head;
- head = 0;
- while (old_head) {
- t = old_head;
- old_head = old_head->next;
- t->next = head;
- head = t;
- }
- }
- *rtset = head;
- return 0;
- err:
- free_rte_list(head);
- return -1;
- }
- static inline unsigned short uri2port(const struct sip_uri *puri)
- {
- if (puri->port.s) {
- return puri->port_no;
- } else switch (puri->type) {
- case SIP_URI_T:
- case TEL_URI_T:
- if (puri->transport_val.len == sizeof("TLS") - 1) {
- unsigned trans;
- trans = puri->transport_val.s[0] | 0x20; trans <<= 8;
- trans |= puri->transport_val.s[1] | 0x20; trans <<= 8;
- trans |= puri->transport_val.s[2] | 0x20;
- if (trans == 0x746C73) /* t l s */
- return SIPS_PORT;
- }
- return SIP_PORT;
- case SIPS_URI_T:
- case TELS_URI_T:
- return SIPS_PORT;
- default:
- BUG("unexpected URI type %d.\n", puri->type);
- }
- return 0;
- }
- /**
- * Evaluate if next hop is a strict or loose router, by looking at the
- * retr. buffer of the original INVITE.
- * Assumes:
- * orig_inv is a parsed SIP message;
- * rtset is not NULL.
- * @return:
- * F_RB_NH_LOOSE : next hop was loose router;
- * F_RB_NH_STRICT: nh is strict;
- * 0 on error.
- */
- static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset,
- const struct dest_info *dst_inv, str *contact)
- {
- struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri;
- struct ip_addr *uri_ia;
- union sockaddr_union uri_sau;
- unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port;
- rte_t *last_r;
- #ifdef TM_LOC_ACK_DO_REV_DNS
- struct ip_addr ia;
- struct hostent *he;
- char **alias;
- #endif
- #define PARSE_URI(_str_, _uri_) \
- do { \
- /* parse_uri() 0z the puri */ \
- if (parse_uri((_str_)->s, \
- (_str_)->len, _uri_) < 0) { \
- ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \
- return 0; \
- } \
- } while (0)
- #define HAS_LR(_rte_) \
- ({ \
- PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \
- puri.lr.s; \
- })
- #define URI_PORT(_puri_, _port) \
- do { \
- if (! (_port = uri2port(_puri_))) \
- return 0; \
- } while (0)
- /* examine the easy/fast & positive cases foremost */
- /* [1] check if 1st route lacks ;lr */
- DEBUG("checking lack of ';lr' in 1st route.\n");
- if (! HAS_LR(rtset))
- return F_RB_NH_STRICT;
- topr_uri = puri; /* save 1st route's URI */
- /* [2] check if last route shows ;lr */
- DEBUG("checking presence of ';lr' in last route.\n");
- for (last_r = rtset; last_r->next; last_r = last_r->next)
- /* scroll down to last route */
- ;
- if (HAS_LR(last_r))
- return F_RB_NH_LOOSE;
- /* [3] 1st route has ;lr -> check if the destination of original INV
- * equals the address provided by this route; if does -> loose */
- DEBUG("checking INVITE's destination against its first route.\n");
- URI_PORT(&topr_uri, uri_port);
- if (! (dst_port = su_getport((void *)&dst_inv->to)))
- return 0; /* not really expected */
- if (dst_port != uri_port)
- return F_RB_NH_STRICT;
- /* if 1st route contains an IP address, comparing it against .dst */
- if ((uri_ia = str2ip(&topr_uri.host))
- #ifdef USE_IPV6
- || (uri_ia = str2ip6(&topr_uri.host))
- #endif
- ) {
- /* we have an IP address in route -> comparison can go swiftly */
- if (init_su(&uri_sau, uri_ia, uri_port) < 0)
- return 0; /* not really expected */
- if (su_cmp(&uri_sau, (void *)&dst_inv->to))
- /* ;lr and sent there */
- return F_RB_NH_LOOSE;
- else
- /* ;lr and NOT sent there (probably sent to RURI address) */
- return F_RB_NH_STRICT;
- } else {
- /*if 1st route contains a name, rev resolve the .dst and compare*/
- INFO("Failed to decode string '%.*s' in route set element as IP "
- "address. Trying name resolution.\n",STR_FMT(&topr_uri.host));
- /* TODO: alternatively, rev name and compare against dest. IP. */
- #ifdef TM_LOC_ACK_DO_REV_DNS
- ia.af = 0;
- su2ip_addr(&ia, (void *)&dst_inv->to);
- if (! ia.af)
- return 0; /* not really expected */
- if ((he = rev_resolvehost(&ia))) {
- if ((strlen(he->h_name) == topr_uri.host.len) &&
- (memcmp(he->h_name, topr_uri.host.s,
- topr_uri.host.len) == 0))
- return F_RB_NH_LOOSE;
- for (alias = he->h_aliases; *alias; alias ++)
- if ((strlen(*alias) == topr_uri.host.len) &&
- (memcmp(*alias, topr_uri.host.s,
- topr_uri.host.len) == 0))
- return F_RB_NH_LOOSE;
- return F_RB_NH_STRICT;
- } else {
- INFO("failed to resolve address '%s' to a name.\n",
- ip_addr2a(&ia));
- }
- #endif
- }
- WARN("failed to establish with certainty the type of next hop; trying an"
- " educated guess.\n");
- /* [4] compare (possibly updated) remote target to original RURI; if
- * equal, a strict router's address wasn't filled in as RURI -> loose */
- DEBUG("checking remote target against INVITE's RURI.\n");
- PARSE_URI(contact, &cont_uri);
- PARSE_URI(GET_RURI(orig_inv), &inv_ruri);
- URI_PORT(&cont_uri, cont_port);
- URI_PORT(&inv_ruri, inv_port);
- if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) &&
- (memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0))
- return F_RB_NH_LOOSE;
- /* [5] compare (possibly updated) remote target to last route; if equal,
- * strict router's address might have been filled as RURI and remote
- * target appended to route set -> strict */
- DEBUG("checking remote target against INVITE's last route.\n");
- PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri);
- URI_PORT(&lastr_uri, lastr_port);
- if ((cont_port == lastr_port) &&
- (cont_uri.host.len == lastr_uri.host.len) &&
- (memcmp(cont_uri.host.s, lastr_uri.host.s,
- lastr_uri.host.len) == 0))
- return F_RB_NH_STRICT;
- WARN("failed to establish the type of next hop; assuming loose router.\n");
- return F_RB_NH_LOOSE;
- #undef PARSE_URI
- #undef HAS_LR
- #undef URI_PORT
- }
- /**
- * Evaluates the routing elements in locally originated request or reply to
- * locally originated request.
- * If original INVITE was in-dialog (had to-tag), it uses the
- * routes present there (b/c the 2xx for it does not have a RR set, normally).
- * Otherwise, use the reply (b/c the INVITE does not have yet the complete
- * route set).
- *
- * @return: negative for failure; out params:
- * - list: route set;
- * - ruri: RURI to be used in ACK;
- * - nexthop: where to first send the ACK.
- *
- * NOTE: assumes rpl's parsed to EOF!
- *
- */
- static int eval_uac_routing(sip_msg_t *rpl, const struct retr_buf *inv_rb,
- str* contact, struct rte **list, str *ruri, str *next_hop)
- {
- sip_msg_t orig_inv, *sipmsg; /* reparse original INVITE */
- rte_t *t, *prev_t, *rtset = NULL;
- int is_req;
- struct sip_uri puri;
- static size_t chklen;
- int ret = -1;
-
- /* parse the retr. buffer */
- memset(&orig_inv, 0, sizeof(struct sip_msg));
- orig_inv.buf = inv_rb->buffer;
- orig_inv.len = inv_rb->buffer_len;
- DEBUG("reparsing retransmission buffer of original INVITE:\n%.*s\n",
- orig_inv.len, orig_inv.buf);
- if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) != 0) {
- ERR("failed to parse retr buffer (weird!): \n%.*s\n", orig_inv.len,
- orig_inv.buf);
- return -1;
- }
- /* check if we need to look at request or reply */
- if ((parse_headers(&orig_inv, HDR_TO_F, 0) < 0) || (! orig_inv.to)) {
- /* the bug is at message assembly */
- BUG("failed to parse INVITE retr. buffer and/or extract 'To' HF:"
- "\n%.*s\n", orig_inv.len, orig_inv.buf);
- goto end;
- }
- if (((struct to_body *)orig_inv.to->parsed)->tag_value.len) {
- DEBUG("building ACK for in-dialog INVITE (using RS in orig. INV.)\n");
- if (parse_headers(&orig_inv, HDR_EOH_F, 0) < 0) {
- BUG("failed to parse INVITE retr. buffer to EOH:"
- "\n%.*s\n", orig_inv.len, orig_inv.buf);
- goto end;
- }
- sipmsg = &orig_inv;
- is_req = 1;
- } else {
- DEBUG("building ACK for out-of-dialog INVITE (using RS in RR set).\n");
- sipmsg = rpl;
- is_req = 0;
- }
- /* extract the route set */
- if (get_uac_rs(sipmsg, is_req, &rtset) < 0) {
- ERR("failed to extract route set.\n");
- goto end;
- }
- if (! rtset) { /* No routes */
- *ruri = *contact;
- *next_hop = *contact;
- } else if (! is_req) { /* out of dialog req. */
- if (parse_uri(rtset->ptr->nameaddr.uri.s, rtset->ptr->nameaddr.uri.len,
- &puri) < 0) {
- ERR("failed to parse first route in set.\n");
- goto end;
- }
-
- if (puri.lr.s) { /* Next hop is loose router */
- *ruri = *contact;
- *next_hop = rtset->ptr->nameaddr.uri;
- } else { /* Next hop is strict router */
- *ruri = rtset->ptr->nameaddr.uri;
- *next_hop = *ruri;
- /* consume first route, b/c it will be put in RURI */
- t = rtset;
- rtset = rtset->next;
- pkg_free(t);
- }
- } else {
- unsigned long route_flags = inv_rb->flags;
- DEBUG("UAC rb flags: 0x%x.\n", (unsigned int)route_flags);
- eval_flags:
- switch (route_flags & (F_RB_NH_LOOSE|F_RB_NH_STRICT)) {
- case 0:
- WARN("calculate_hooks() not called when built the local UAC of "
- "in-dialog request, or called with empty route set.\n");
- /* try to figure out what kind of hop is the next one
- * (strict/loose) by reading the original invite */
- if ((route_flags = nhop_type(&orig_inv, rtset, &inv_rb->dst,
- contact))) {
- DEBUG("original request's next hop type evaluated to: 0x%x.\n",
- (unsigned int)route_flags);
- goto eval_flags;
- } else {
- ERR("failed to establish what kind of router the next "
- "hop is.\n");
- goto end;
- }
- break;
- case F_RB_NH_LOOSE:
- *ruri = *contact;
- *next_hop = rtset->ptr->nameaddr.uri;
- break;
- case F_RB_NH_STRICT:
- /* find ptr to last route body that contains the (possibly) old
- * remote target
- */
- for (t = rtset, prev_t = t; t->next; prev_t = t, t = t->next)
- ;
- if ((t->ptr->len == contact->len) &&
- (memcmp(t->ptr->nameaddr.name.s, contact->s,
- contact->len) == 0)){
- /* the remote target didn't update -> keep the whole route set,
- * including the last entry */
- /* do nothing */
- } else {
- /* trash last entry and replace with new remote target */
- free_rte_list(t);
- /* compact the rr_t struct along with rte. this way, free'ing
- * it can be done along with rte chunk, independent of Route
- * header parser's allocator (using pkg/shm) */
- chklen = sizeof(struct rte) + sizeof(rr_t);
- if (! (t = (struct rte *)pkg_malloc(chklen))) {
- ERR("out of pkg memory (%zd required)\n", chklen);
- goto end;
- }
- /* this way, .free_rr is also set to 0 (!!!) */
- memset(t, 0, chklen);
- ((rr_t *)&t[1])->nameaddr.name = *contact;
- ((rr_t *)&t[1])->len = contact->len;
- /* chain the new route elem in set */
- if (prev_t == rtset)
- /*there is only one elem in route set: the remote target*/
- rtset = t;
- else
- prev_t->next = t;
- }
- *ruri = *GET_RURI(&orig_inv); /* reuse original RURI */
- *next_hop = *ruri;
- break;
- default:
- /* probably a mem corruption */
- BUG("next hop of original request marked as both loose and strict"
- " router (buffer: %.*s).\n", inv_rb->buffer_len,
- inv_rb->buffer);
- #ifdef EXTRA_DEBUG
- abort();
- #else
- goto end;
- #endif
- }
- }
- *list = rtset;
- /* all went well */
- ret = 0;
- end:
- free_sip_msg(&orig_inv);
- if (ret < 0)
- free_rte_list(rtset);
- return ret;
- }
- /*
- * The function creates an ACK to 200 OK. Route set will be created
- * and parsed and the dst parameter will contain the destination to which
- * the request should be send. The function is used by tm when it
- * generates local ACK to 200 OK (on behalf of applications using uac)
- */
- char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans,
- unsigned int branch, str *hdrs, str *body,
- unsigned int *len, struct dest_info* dst)
- {
- char *req_buf, *p, *via;
- unsigned int via_len;
- char branch_buf[MAX_BRANCH_PARAM_LEN];
- int branch_len;
- str branch_str;
- struct hostport hp;
- struct rte* list;
- str contact, ruri, *cont;
- str next_hop;
- str body_len;
- str _to, *to = &_to;
- #ifdef USE_DNS_FAILOVER
- struct dns_srv_handle dns_h;
- #endif
- #ifdef WITH_AS_SUPPORT
- /* With AS support, TM allows for external modules to generate building of
- * the ACK; in this case, the ACK's retransmission buffer is built once
- * and kept in memory (to help when retransmitted 2xx are received and ACK
- * must be resent).
- * Allocation of the string raw buffer that holds the ACK is piggy-backed
- * with allocation of the retransmission buffer (since both have the same
- * life-cycle): both the string buffer and retransm. buffer are placed
- * into the same allocated chunk of memory (retr. buffer first, string
- * buffer follows).In this case, the 'len' param is used as in-out
- * parameter: 'in' to give the extra space needed by the retr. buffer,
- * 'out' to return the lenght of the allocated string buffer.
- */
- unsigned offset = *len;
- #endif
-
- if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) {
- ERR("Error while parsing headers.\n");
- return 0;
- } else {
- _to.s = rpl->to->name.s;
- _to.len = rpl->to->len;
- }
-
- if (get_contact_uri(rpl, &contact) < 0) {
- return 0;
- }
-
- if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact,
- &list, &ruri, &next_hop) < 0) {
- ERR("failed to evaluate routing elements.\n");
- return 0;
- }
- DEBUG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri),
- STR_FMT(&next_hop));
- if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
- /* contact != ruri means that the next
- * hop is a strict router, cont will be non-zero
- * and print_routeset will append it at the end
- * of the route set
- */
- cont = &contact;
- } else {
- /* Next hop is a loose router, nothing to append */
- cont = 0;
- }
-
- /* method, separators, version: "ACK sip:[email protected] SIP/2.0" */
- *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
- *len += ruri.len;
-
-
- /* via */
- #ifdef USE_DNS_FAILOVER
- if (cfg_get(core, core_cfg, use_dns_failover)){
- dns_srv_handle_init(&dns_h);
- if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
- (dst->send_sock==0)){
- dns_srv_handle_put(&dns_h);
- LOG(L_ERR, "build_dlg_ack: no socket found\n");
- goto error;
- }
- dns_srv_handle_put(&dns_h); /* not needed any more */
- }else{
- if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
- (dst->send_sock==0)){
- LOG(L_ERR, "build_dlg_ack: no socket found\n");
- goto error;
- }
- }
- #else
- if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
- (dst->send_sock==0)){
- LOG(L_ERR, "build_dlg_ack: no socket found\n");
- goto error;
- }
- #endif
-
- if (!t_calc_branch(Trans, branch, branch_buf, &branch_len)) goto error;
- branch_str.s = branch_buf;
- branch_str.len = branch_len;
- set_hostport(&hp, 0);
- via = via_builder(&via_len, dst, &branch_str, 0, &hp);
- if (!via) {
- LOG(L_ERR, "build_dlg_ack: No via header got from builder\n");
- goto error;
- }
- *len+= via_len;
-
- /*headers*/
- *len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;
-
- /* copy'n'paste Route headers */
-
- *len += calc_routeset_len(list, cont);
-
- /* User Agent */
- if (server_signature) *len += USER_AGENT_LEN + CRLF_LEN;
- /* extra headers */
- if (hdrs)
- *len += hdrs->len;
- /* body */
- if (body) {
- body_len.s = int2str(body->len, &body_len.len);
- *len += body->len;
- } else {
- body_len.len = 0;
- body_len.s = NULL; /*4gcc*/
- *len += 1; /* for the (Cont-Len:) `0' */
- }
- /* Content Length, EoM */
- *len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN;
- #if WITH_AS_SUPPORT
- req_buf = shm_malloc(offset + *len + 1);
- req_buf += offset;
- #else
- req_buf = shm_malloc(*len + 1);
- #endif
- if (!req_buf) {
- ERR("Cannot allocate memory (%u+1)\n", *len);
- goto error01;
- }
- p = req_buf;
-
- append_mem_block( p, ACK, ACK_LEN );
- append_mem_block( p, " ", 1 );
- append_str(p, ruri);
- append_mem_block( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
-
- /* insert our via */
- append_mem_block(p, via, via_len);
-
- /*other headers*/
- append_str(p, Trans->from);
- append_str(p, Trans->callid);
- append_str(p, *to);
-
- append_str(p, Trans->cseq_n);
- append_mem_block( p, " ", 1 );
- append_mem_block( p, ACK, ACK_LEN);
- append_mem_block(p, CRLF, CRLF_LEN);
-
- /* Routeset */
- p = print_rs(p, list, cont);
-
- /* User Agent header */
- if (server_signature) {
- append_mem_block(p, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
- }
-
- /* extra headers */
- if (hdrs)
- append_mem_block(p, hdrs->s, hdrs->len);
-
- /* Content Length, EoH, (body) */
- if (body) {
- append_mem_block(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
- append_mem_block(p, body_len.s, body_len.len);
- append_mem_block(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN +
- CRLF_LEN);
- append_mem_block(p, body->s, body->len);
- } else {
- append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF,
- CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
- }
- /* EoM */
- *p = 0;
-
- pkg_free(via);
- free_rte_list(list);
- return req_buf;
-
- error01:
- pkg_free(via);
- error:
- free_rte_list(list);
- return 0;
- }
- /*
- * Convert length of body into asciiz
- */
- static inline int print_content_length(str* dest, str* body)
- {
- static char content_length[10];
- int len;
- int b_len;
- char* tmp;
- /* Print Content-Length */
- b_len=body?body->len:0;
- tmp = int2str(b_len, &len);
- if (len >= sizeof(content_length)) {
- LOG(L_ERR, "ERROR: print_content_length: content_len too big\n");
- dest->s = 0;
- dest->len = 0;
- return -1;
- }
- memcpy(content_length, tmp, len);
- dest->s = content_length;
- dest->len = len;
- return 0;
- }
- /*
- * Convert CSeq number into asciiz
- */
- static inline int print_cseq_num(str* _s, dlg_t* _d)
- {
- static char cseq[INT2STR_MAX_LEN];
- char* tmp;
- int len;
- tmp = int2str(_d->loc_seq.value, &len);
- if (len > sizeof(cseq)) {
- LOG(L_ERR, "print_cseq_num: cseq too big\n");
- return -1;
- }
-
- memcpy(cseq, tmp, len);
- _s->s = cseq;
- _s->len = len;
- return 0;
- }
- /*
- * Create Via header
- */
- static inline int assemble_via(str* dest, struct cell* t,
- struct dest_info* dst, int branch)
- {
- static char branch_buf[MAX_BRANCH_PARAM_LEN];
- char* via;
- int len;
- unsigned int via_len;
- str branch_str;
- struct hostport hp;
- if (!t_calc_branch(t, branch, branch_buf, &len)) {
- LOG(L_ERR, "ERROR: assemble_via: branch calculation failed\n");
- return -1;
- }
-
- branch_str.s = branch_buf;
- branch_str.len = len;
- #ifdef XL_DEBUG
- printf("!!!proto: %d\n", sock->proto);
- #endif
- set_hostport(&hp, 0);
- via = via_builder(&via_len, dst, &branch_str, 0, &hp);
- if (!via) {
- LOG(L_ERR, "assemble_via: via building failed\n");
- return -2;
- }
-
- dest->s = via;
- dest->len = via_len;
- return 0;
- }
- /*
- * Print Request-URI
- */
- static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struct cell* t, int branch)
- {
- memapp(w, method->s, method->len);
- memapp(w, " ", 1);
- t->uac[branch].uri.s = w;
- t->uac[branch].uri.len = dialog->hooks.request_uri->len;
- memapp(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len);
- memapp(w, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
- return w;
- }
- /*
- * Print To header field
- */
- static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
- {
- t->to.s = w;
- t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN;
- memapp(w, TO, TO_LEN);
- memapp(w, dialog->rem_uri.s, dialog->rem_uri.len);
- if (dialog->id.rem_tag.len) {
- t->to.len += TOTAG_LEN + dialog->id.rem_tag.len ;
- memapp(w, TOTAG, TOTAG_LEN);
- memapp(w, dialog->id.rem_tag.s, dialog->id.rem_tag.len);
- }
- memapp(w, CRLF, CRLF_LEN);
- return w;
- }
- /*
- * Print From header field
- */
- static inline char* print_from(char* w, dlg_t* dialog, struct cell* t)
- {
- t->from.s = w;
- t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN;
- memapp(w, FROM, FROM_LEN);
- memapp(w, dialog->loc_uri.s, dialog->loc_uri.len);
- if (dialog->id.loc_tag.len) {
- t->from.len += FROMTAG_LEN + dialog->id.loc_tag.len;
- memapp(w, FROMTAG, FROMTAG_LEN);
- memapp(w, dialog->id.loc_tag.s, dialog->id.loc_tag.len);
- }
- memapp(w, CRLF, CRLF_LEN);
- return w;
- }
- /*
- * Print CSeq header field
- */
- char* print_cseq_mini(char* target, str* cseq, str* method) {
- memapp(target, CSEQ, CSEQ_LEN);
- memapp(target, cseq->s, cseq->len);
- memapp(target, " ", 1);
- memapp(target, method->s, method->len);
- return target;
- }
- static inline char* print_cseq(char* w, str* cseq, str* method, struct cell* t)
- {
- t->cseq_n.s = w;
- /* don't include method name and CRLF -- subsequent
- * local requests ACK/CANCEL will add their own */
- t->cseq_n.len = CSEQ_LEN + cseq->len;
- w = print_cseq_mini(w, cseq, method);
- return w;
- }
- /*
- * Print Call-ID header field
- * created an extra function for pure header field creation, that is used by t_cancel for
- * t_uac_cancel FIFO function.
- */
- char* print_callid_mini(char* target, str callid) {
- memapp(target, CALLID, CALLID_LEN);
- memapp(target, callid.s, callid.len);
- memapp(target, CRLF, CRLF_LEN);
- return target;
- }
- static inline char* print_callid(char* w, dlg_t* dialog, struct cell* t)
- {
- /* begins with CRLF, not included in t->callid, don`t know why...?!? */
- memapp(w, CRLF, CRLF_LEN);
- t->callid.s = w;
- t->callid.len = CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;
- w = print_callid_mini(w, dialog->id.call_id);
- return w;
- }
- /*
- * Create a request
- */
- char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int branch,
- struct cell *t, int* len, struct dest_info* dst)
- {
- char* buf, *w;
- str content_length, cseq, via;
- if (!method || !dialog) {
- LOG(L_ERR, "build_uac_req(): Invalid parameter value\n");
- return 0;
- }
- if (print_content_length(&content_length, body) < 0) {
- LOG(L_ERR, "build_uac_req(): Error while printing content-length\n");
- return 0;
- }
- if (print_cseq_num(&cseq, dialog) < 0) {
- LOG(L_ERR, "build_uac_req(): Error while printing CSeq number\n");
- return 0;
- }
- *len = method->len + 1 + dialog->hooks.request_uri->len + 1 + SIP_VERSION_LEN + CRLF_LEN;
- if (assemble_via(&via, t, dst, branch) < 0) {
- LOG(L_ERR, "build_uac_req(): Error while assembling Via\n");
- return 0;
- }
- *len += via.len;
- *len += TO_LEN + dialog->rem_uri.len
- + (dialog->id.rem_tag.len ? (TOTAG_LEN + dialog->id.rem_tag.len) : 0) + CRLF_LEN; /* To */
- *len += FROM_LEN + dialog->loc_uri.len
- + (dialog->id.loc_tag.len ? (FROMTAG_LEN + dialog->id.loc_tag.len) : 0) + CRLF_LEN; /* From */
- *len += CALLID_LEN + dialog->id.call_id.len + CRLF_LEN; /* Call-ID */
- *len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN; /* CSeq */
- *len += calculate_routeset_length(dialog); /* Route set */
- *len += CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN; /* Content-
- Length */
- *len += (server_signature ? (USER_AGENT_LEN + CRLF_LEN) : 0); /* Signature */
- *len += (headers ? headers->len : 0); /* Additional headers */
- *len += (body ? body->len : 0); /* Message body */
- *len += CRLF_LEN; /* End of Header */
- buf = shm_malloc(*len + 1);
- if (!buf) {
- LOG(L_ERR, "build_uac_req(): no shmem\n");
- goto error;
- }
-
- w = buf;
- w = print_request_uri(w, method, dialog, t, branch); /* Request-URI */
- memapp(w, via.s, via.len); /* Top-most Via */
- w = print_to(w, dialog, t); /* To */
- w = print_from(w, dialog, t); /* From */
- w = print_cseq(w, &cseq, method, t); /* CSeq */
- w = print_callid(w, dialog, t); /* Call-ID */
- w = print_routeset(w, dialog); /* Route set */
- /* Content-Length */
- memapp(w, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
- memapp(w, content_length.s, content_length.len);
- memapp(w, CRLF, CRLF_LEN);
-
- /* Server signature */
- if (server_signature) memapp(w, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
- if (headers) memapp(w, headers->s, headers->len);
- memapp(w, CRLF, CRLF_LEN);
- if (body) memapp(w, body->s, body->len);
- #ifdef EXTRA_DEBUG
- assert(w-buf == *len);
- #endif
- pkg_free(via.s);
- return buf;
- error:
- pkg_free(via.s);
- return 0;
- }
- int t_calc_branch(struct cell *t,
- int b, char *branch, int *branch_len)
- {
- return syn_branch ?
- branch_builder( t->hash_index,
- t->label, 0,
- b, branch, branch_len )
- : branch_builder( t->hash_index,
- 0, t->md5,
- b, branch, branch_len );
- }
|