📄 t_msgbuilder.c
字号:
/* * $Id: t_msgbuilder.c,v 1.12 2006/05/29 16:55:21 bogdan_iancu Exp $ * * message printing * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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) */#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 "t_msgbuilder.h"#include "uac.h"#define ROUTE_PREFIX "Route: "#define ROUTE_PREFIX_LEN (sizeof(ROUTE_PREFIX) - 1)#define ROUTE_SEPARATOR ", "#define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)/* convenience macros */#define append_string(_d,_s,_len) \ do{\ memcpy((_d),(_s),(_len));\ (_d) += (_len);\ }while(0);#define LC(_cp) ((*(_cp))|0x20)#define SET_FOUND(_new_state) \ do{\ fill->s=b;fill->len=p-b;\ DBG("DEBUG:tm:extract_hdrs: hdr %d extracted as <%.*s>\n",\ flag,fill->len,fill->s);\ flags&=~(flag);\ if (flags) {state=_new_state;}\ else {goto done;}\ }while(0)#define GET_CSEQ() \ do{\ for(p++;p<end&&isspace((int)*p);p++);\ for(fill->s=b;p<end&&isdigit((int)*p);p++);\ fill->len=p-fill->s;\ if ( (flags&=~(flag))==0) goto done;\ state=1;\ }while(0)static int extract_hdrs( char *buf, int len, str *from, str *to, str *cseq){ char *end, *p; char *b; str *fill; int state; int flags; int flag; p = buf; end = buf+len; state = 1; b = 0; flags = ((from!=0)?0x1:0) | ((to!=0)?0x2:0) | ((cseq!=0)?0x4:0); flag = 0; fill = 0; while(p<end) { switch (*p) { case '\n': case '\r': switch (state) { case 4: state=5;break; case 5: case 6: state=6;break; default : state=2;break; } break; case ' ': case '\t': switch (state) { case 4: case 6: state=5; break; case 2: state=1; break;/*folded line*/ } break; case ':': switch (state) { case 4:case 5: state=5;if(flag==0x04)GET_CSEQ();break; case 6: SET_FOUND(1);break;/*found*/ case 2: state=1;break; } break; case 'f': case 'F': if (state==5) break; if (state==6) SET_FOUND(2);/*found*/; if (state!=2) {state = 1;break;} /* hdr starting with 'f' */ if (from==0) break; b = p; if (p+3<end && LC(p+1)=='r' && LC(p+2)=='o' && LC(p+3)=='m') p+=3; state = 4; /* "f" or "from" found */ fill = from; flag = 0x1; break; case 't': case 'T': if (state==5) break; if (state==6) SET_FOUND(2);/*found*/; if (state!=2) {state = 1;break;} /* hdr starting with 't' */ if (to==0) break; b = p; if (p+1<end && LC(p+1)=='o') p+=1; state = 4; /* "t" or "to" found */ fill = to; flag = 0x2; break; case 'c': case 'C': if (state==5) break; if (state==6) SET_FOUND(2);/*found*/; if (state!=2) {state = 1;break;} /* hdr starting with 'c' */ if (cseq==0) break; if (p+3<end && LC(p+1)=='s' && LC(p+2)=='e' && LC(p+3)=='q') { b = p; p+=3; state = 4; /* "cseq" found */ fill = cseq; flag = 0x4; } break; default: switch (state) { case 2:case 4: state=1; break; case 6: SET_FOUND(1);break;/*found*/; } } p++; } LOG(L_CRIT,"BUG:tm:extract_hdrs: no hdrs found in outgoing buffer\n"); return -1;done: return 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 *uas_to){ char *cancel_buf, *p, *via; unsigned int via_len; struct hdr_field *hdr; struct sip_msg *req; char branch_buf[MAX_BRANCH_PARAM_LEN]; str branch_str; struct hostport hp; str from; str to; str cseq_n; req = Trans->uas.request; from = Trans->from; cseq_n = Trans->cseq_n; to = *uas_to; if (req && req->msg_flags&(FL_USE_UAC_FROM|FL_USE_UAC_TO|FL_USE_UAC_CSEQ)) { if ( extract_hdrs( Trans->uac[branch].request.buffer.s, Trans->uac[branch].request.buffer.len, (req->msg_flags&FL_USE_UAC_FROM)?&from:0 , (req->msg_flags&FL_USE_UAC_TO)?&to:0 , (req->msg_flags&FL_USE_UAC_CSEQ)?&cseq_n:0 )!=0 ) { LOG(L_ERR, "ERROR:tm:build_local: " "failed to extract UAC hdrs\n"); goto error; } } DBG("DEBUG:tm:build_local: using FROM=<%.*s>, TO=<%.*s>, CSEQ_N=<%.*s>\n", from.len,from.s , to.len,to.s , cseq_n.len,cseq_n.s); /* method, separators, version */ *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN; *len+=Trans->uac[branch].uri.len; /*via*/ branch_str.s=branch_buf; if (!t_calc_branch(Trans, branch, branch_str.s, &branch_str.len )) goto error; set_hostport(&hp, (is_local(Trans))?0:req); via=via_builder(&via_len, Trans->uac[branch].request.dst.send_sock, &branch_str, 0, Trans->uac[branch].request.dst.proto, &hp ); if (!via) { LOG(L_ERR, "ERROR: build_local: " "no via header got from builder\n"); goto error; } *len+= via_len; /*headers*/ *len+=from.len+Trans->callid.len+to.len+cseq_n.len+1+method_len+CRLF_LEN; /* copy'n'paste Route headers */ if (!is_local(Trans)) { for ( hdr=req->headers ; hdr ; hdr=hdr->next ) if (hdr->type==HDR_ROUTE_T) *len+=hdr->len; } /* User Agent */ if (server_signature) { *len += user_agent_header.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_string( p, method, method_len ); *(p++) = ' '; append_string( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len); append_string( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN ); /* insert our via */ append_string(p,via,via_len); /*other headers*/ append_string( p, from.s, from.len ); append_string( p, Trans->callid.s, Trans->callid.len ); append_string( p, to.s, to.len ); append_string( p, cseq_n.s, cseq_n.len ); *(p++) = ' '; append_string( p, method, method_len ); append_string( p, CRLF, CRLF_LEN ); if (!is_local(Trans)) { for ( hdr=req->headers ; hdr ; hdr=hdr->next ) if(hdr->type==HDR_ROUTE_T) { append_string(p, hdr->name.s, hdr->len ); } } /* User Agent header, Content Length, EoM */ if (server_signature) { append_string(p, user_agent_header.s, user_agent_header.len); append_string(p, CRLF CONTENT_LENGTH "0" CRLF CRLF , CRLF_LEN+CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN); } else { append_string(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;}struct rte { rr_t* ptr; struct rte* next;};static inline void free_rte_list(struct rte* list){ struct rte* ptr; while(list) { ptr = list; list = list->next; pkg_free(ptr); }}static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte** list, str* ruri, str* next_hop){ struct hdr_field* ptr; rr_t* p; struct rte* t, *head; struct sip_uri puri; ptr = msg->record_route; head = 0; while(ptr) { if (ptr->type == HDR_RECORDROUTE_T) { if (parse_rr(ptr) < 0) { LOG(L_ERR, "process_routeset: Error while parsing Record-Route header\n"); return -1; } p = (rr_t*)ptr->parsed; while(p) { t = (struct rte*)pkg_malloc(sizeof(struct rte)); if (!t) { LOG(L_ERR, "process_routeset: No memory left\n"); free_rte_list(head); return -1; } t->ptr = p; t->next = head; head = t; p = p->next; } } ptr = ptr->next; } if (head) { if (parse_uri(head->ptr->nameaddr.uri.s, head->ptr->nameaddr.uri.len, &puri) < 0) { LOG(L_ERR, "process_routeset: Error while parsing URI\n"); free_rte_list(head); return -1; } if (puri.lr.s) { /* Next hop is loose router */ *ruri = *contact; *next_hop = head->ptr->nameaddr.uri; } else { /* Next hop is strict router */ *ruri = head->ptr->nameaddr.uri; *next_hop = *ruri; t = head; head = head->next; pkg_free(t); } } else { /* No routes */ *ruri = *contact; *next_hop = *contact; } *list = head; return 0;}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) { append_string(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN); } else { return p; } ptr = list; while(ptr) { if (ptr != list) { append_string(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN); } append_string(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len); ptr = ptr->next; } if (contact) { if (list) append_string(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN); *p++ = '<'; append_string(p, contact->s, contact->len); *p++ = '>'; } append_string(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -