/* * $Id$ * * 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: * info@iptel.org * * 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-28 removed scratchpad (jiri) * 2003-02-28 scratchpad compatibility abandoned (jiri) * 2003-03-06 enum_request_method changed to begin with 1; * 0 reserved for invalid values; (jiri) * 2003-03-31 removed sip_msg->repl_add_rm (andrei) * 2003-04-01 2 macros added: GET_NEXT_HOP and GET_RURI (janakj) * 2003-04-04 structure for parsed inbound uri added (jiri) * 2003-04-11 updated the sip_uri structure (lots of fields added) (andrei) * 2003-04-12 added msg_flags to sip_msg (andrei) * 2003-11-02 added diversion header field to sip_msg (jh) * 2004-11-08 added force_send_socket (andrei) * 2005-02-25 uri types added (sip, sips & tel) (andrei) * 2006-04-20 uri comp member (only if USE_COMP is defined) (andrei) * 2006-11-10 check_transaction_quadruple inlined (andrei) * 2007-01-26 added date, identity, identity_info header fields * to sip_msg (gergo) * 2007-03-14 added SIP_MSG_START(msg) macro */ #ifndef msg_parser_h #define msg_parser_h #include "../comp_defs.h" #include "../str.h" #include "../lump_struct.h" #include "../flags.h" #include "../ip_addr.h" #include "../md5utils.h" #include "../config.h" #include "parse_def.h" #include "parse_cseq.h" #include "parse_to.h" #include "parse_via.h" #include "parse_fline.h" #include "parse_retry_after.h" #include "hf.h" #include "../error.h" /* convenience short-cut macros */ #define REQ_LINE(_msg) ((_msg)->first_line.u.request) #define REQ_METHOD first_line.u.request.method_value #define REPLY_STATUS first_line.u.reply.statuscode #define REPLY_CLASS(_reply) ((_reply)->REPLY_STATUS/100) /* start of "actual" sip msg (start of first line) */ #define SIP_MSG_START(m) ((m)->first_line.u.request.method.s) /* number methods as power of two to allow bitmap matching */ enum request_method { METHOD_UNDEF=0, METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_ACK=4, METHOD_BYE=8, METHOD_INFO=16, METHOD_REGISTER=32, METHOD_SUBSCRIBE=64, METHOD_NOTIFY=128, METHOD_OTHER=256 }; #define FL_FORCE_RPORT 1 /* force rport */ #define FL_FORCE_ACTIVE 2 /* force active SDP */ #define FL_SDP_IP_AFS 4 /* SDP IP rewritten */ #define FL_SDP_PORT_AFS 8 /* SDP port rewritten */ #define FL_SHM_CLONE 16 /* msg cloned in SHM as a single chunk */ #define FL_TIMEOUT 32 /* message belongs to an "expired" branch (for failure route use) */ #define FL_REPLIED 64 /* message branch received at least one reply (for failure route use) */ #define FL_HASH_INDEX 128 /* msg->hash_index contains a valid value (tm use)*/ #define FL_MTU_TCP_FB 256 #define FL_MTU_TLS_FB 512 #define FL_MTU_SCTP_FB 1024 #define FL_MTU_FB_MASK (FL_MTU_TCP_FB|FL_MTU_TLS_FB|FL_MTU_SCTP_FB) #define IFISMETHOD(methodname,firstchar) \ if ( (*tmp==(firstchar) || *tmp==((firstchar) | 32)) && \ strncasecmp( tmp+1, #methodname +1, methodname##_LEN-1)==0 && \ *(tmp+methodname##_LEN)==' ') { \ fl->type=SIP_REQUEST; \ fl->u.request.method.len=methodname##_LEN; \ fl->u.request.method_value=METHOD_##methodname; \ tmp=buffer+methodname##_LEN; \ } #define IS_HTTP(req) \ ((req)->first_line.u.request.version.len >= HTTP_VERSION_LEN && \ !strncasecmp((req)->first_line.u.request.version.s, \ HTTP_VERSION, HTTP_VERSION_LEN)) #define IS_SIP(req) \ ((req)->first_line.u.request.version.len >= SIP_VERSION_LEN && \ !strncasecmp((req)->first_line.u.request.version.s, \ SIP_VERSION, SIP_VERSION_LEN)) /* * Return a URI to which the message should be really sent (not what should * be in the Request URI. The following fields are tried in this order: * 1) dst_uri * 2) new_uri * 3) first_line.u.request.uri */ #define GET_NEXT_HOP(m) \ (((m)->dst_uri.s && (m)->dst_uri.len) ? (&(m)->dst_uri) : \ (((m)->new_uri.s && (m)->new_uri.len) ? (&(m)->new_uri) : (&(m)->first_line.u.request.uri))) /* * Return the Reqeust URI of a message. * The following fields are tried in this order: * 1) new_uri * 2) first_line.u.request.uri */ #define GET_RURI(m) \ (((m)->new_uri.s && (m)->new_uri.len) ? (&(m)->new_uri) : (&(m)->first_line.u.request.uri)) #if 0 /* old version */ struct sip_uri { str user; /* Username */ str passwd; /* Password */ str host; /* Host name */ str port; /* Port number */ str params; /* Parameters */ str headers; unsigned short port_no; }; #endif enum _uri_type{ERROR_URI_T=0, SIP_URI_T, SIPS_URI_T, TEL_URI_T, TELS_URI_T}; typedef enum _uri_type uri_type; enum _uri_flags{ URI_USER_NORMALIZE=1, URI_SIP_USER_PHONE=2 }; /* bit fields */ typedef enum _uri_flags uri_flags; struct sip_uri { str user; /* Username */ str passwd; /* Password */ str host; /* Host name */ str port; /* Port number */ str params; /* Parameters */ str headers; unsigned short port_no; unsigned short proto; /* from transport */ uri_type type; /* uri scheme */ uri_flags flags; /* parameters */ str transport; str ttl; str user_param; str maddr; str method; str lr; str r2; /* ser specific rr parameter */ /* values */ str transport_val; str ttl_val; str user_param_val; str maddr_val; str method_val; str lr_val; /* lr value placeholder for lr=on a.s.o*/ str r2_val; #ifdef USE_COMP unsigned short comp; #endif }; typedef struct sip_msg { unsigned int id; /* message id, unique/process*/ struct msg_start first_line; /* Message first line */ struct via_body* via1; /* The first via */ struct via_body* via2; /* The second via */ struct hdr_field* headers; /* All the parsed headers*/ struct hdr_field* last_header; /* Pointer to the last parsed header*/ hdr_flags_t parsed_flag; /* Already parsed header field types */ /* Via, To, CSeq, Call-Id, From, end of header*/ /* pointers to the first occurrences of these headers; * everything is also saved in 'headers' * (WARNING: do not deallocate them twice!)*/ struct hdr_field* h_via1; struct hdr_field* h_via2; struct hdr_field* callid; struct hdr_field* to; struct hdr_field* cseq; struct hdr_field* from; struct hdr_field* contact; struct hdr_field* maxforwards; struct hdr_field* route; struct hdr_field* record_route; struct hdr_field* content_type; struct hdr_field* content_length; struct hdr_field* authorization; struct hdr_field* expires; struct hdr_field* proxy_auth; struct hdr_field* supported; struct hdr_field* require; struct hdr_field* proxy_require; struct hdr_field* unsupported; struct hdr_field* allow; struct hdr_field* event; struct hdr_field* accept; struct hdr_field* accept_language; struct hdr_field* organization; struct hdr_field* priority; struct hdr_field* subject; struct hdr_field* user_agent; struct hdr_field* server; struct hdr_field* content_disposition; struct hdr_field* accept_disposition; struct hdr_field* diversion; struct hdr_field* rpid; struct hdr_field* refer_to; struct hdr_field* session_expires; struct hdr_field* min_se; struct hdr_field* sipifmatch; struct hdr_field* subscription_state; struct hdr_field* date; struct hdr_field* identity; struct hdr_field* identity_info; char* eoh; /* pointer to the end of header (if found) or null */ char* unparsed; /* here we stopped parsing*/ struct receive_info rcv; /* source & dest ip, ports, proto a.s.o*/ char* buf; /* scratch pad, holds a modified message, * via, etc. point into it */ unsigned int len; /* message len (orig) */ /* modifications */ str new_uri; /* changed first line uri, when you change this don't forget to set parsed_uri_ok to 0*/ str dst_uri; /* Destination URI, must be forwarded to this URI if len != 0 */ /* current uri */ int parsed_uri_ok; /* 1 if parsed_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)*/ struct sip_uri parsed_uri; /* speed-up > keep here the parsed uri*/ /* the same for original uri */ int parsed_orig_ruri_ok; struct sip_uri parsed_orig_ruri; struct lump* add_rm; /* used for all the forwarded requests/replies */ struct lump* body_lumps; /* Lumps that update Content-Length */ struct lump_rpl *reply_lump; /* only for localy generated replies !!!*/ /* str add_to_branch; whatever whoever want to append to branch comes here */ char add_to_branch_s[MAX_BRANCH_PARAM_LEN]; int add_to_branch_len; /* index to TM hash table; stored in core to avoid unnecessary calculations */ unsigned int hash_index; unsigned int msg_flags; /* flags used by core */ /* allows to set various flags on the message; may be used for * simple inter-module communication or remembering processing state * reached */ flag_t flags; str set_global_address; str set_global_port; struct socket_info* force_send_socket; /* force sending on this socket, if ser */ } sip_msg_t; /* pointer to a fakes message which was never received ; (when this message is "relayed", it is generated out of the original request) */ #define FAKED_REPLY ((struct sip_msg *) -1) extern int via_cnt; int parse_msg(char* buf, unsigned int len, struct sip_msg* msg); int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next); char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr); void free_sip_msg(struct sip_msg* msg); /* make sure all HFs needed for transaction identification have been parsed; return 0 if those HFs can't be found */ /* make sure all HFs needed for transaction identification have been parsed; return 0 if those HFs can't be found */ inline static int check_transaction_quadruple( struct sip_msg* msg ) { if ( parse_headers(msg, HDR_FROM_F|HDR_TO_F|HDR_CALLID_F|HDR_CSEQ_F,0)!=-1 && msg->from && msg->to && msg->callid && msg->cseq ) { return 1; } else { ser_error=E_BAD_TUPEL; return 0; } } /* calculate characteristic value of a message -- this value is used to identify a transaction during the process of reply matching */ inline static int char_msg_val( struct sip_msg *msg, char *cv ) { str src[8]; if (!check_transaction_quadruple(msg)) { LOG(L_ERR, "ERROR: can't calculate char_value due " "to a parsing error\n"); memset( cv, '0', MD5_LEN ); return 0; } src[0]= msg->from->body; src[1]= msg->to->body; src[2]= msg->callid->body; src[3]= msg->first_line.u.request.uri; src[4]= get_cseq( msg )->number; /* topmost Via is part of transaction key as well ! */ src[5]= msg->via1->host; src[6]= msg->via1->port_str; if (msg->via1->branch) { src[7]= msg->via1->branch->value; MDStringArray ( cv, src, 8 ); } else { MDStringArray( cv, src, 7 ); } return 1; } /* returns a pointer to the begining of the msg's body */ inline static char* get_body(struct sip_msg *msg) { int offset; unsigned int len; if ( parse_headers(msg, HDR_EOH_F, 0)==-1 ) return 0; if (msg->unparsed){ len=(unsigned int)(msg->unparsed-msg->buf); }else return 0; if ((len+2<=msg->len) && (strncmp(CRLF,msg->unparsed,CRLF_LEN)==0) ) offset = CRLF_LEN; else if ( (len+1<=msg->len) && (*(msg->unparsed)=='\n' || *(msg->unparsed)=='\r' ) ) offset = 1; else return 0; return msg->unparsed + offset; } /* * Make a private copy of the string and assign it to dst_uri */ int set_dst_uri(struct sip_msg* msg, str* uri); #endif