Login | Register

Documentation

Documentation -> Development Manual 3.6 -> Parsing SIP Messages

This page has been visited 187 times.


Pages for other versions: devel 3.5 3.4 Older versions: 3.3 3.2 3.1


Parsing SIP Messages

The OpenSIPS SIP message parser is a lazy parser, which performs very well in terms of performance. The behavior is the following :

  • when the message is received, only the critical headers are parsed (e.g. topmost Via header)
  • for known header types, when the developer wants to extract the first occurrence of a header, they do not have to parse the entire message, but rather the parser will stop parsing when the first needed header type was identified.


Also, it is important to note that there are two types of parsing:

  • parsing in the sense of identifying header boundaries and separating between the header name and header body (e.g. parsing the 'To : vlad@opensips.org;tag=123\r\n' header, and identifying that first, the header is present, and secondly that the body is 'vlad@opensips.org;tag=123\r\n')
  • in-depth parsing of a specific header type, for identifying header specific information (in our example, extracting the to-tag in the To header, etc.).


All parsing is done in a stateful manner, in the sense that the OpenSIPS parser knows which header was parsed and internally keeps a parsing bitmask. Thus, once the To header was first parsed, any subsequent attempts of parsing the To header will return immediately.
Parser implementations are generally exported in the parser/ folder.

1.  Generic Header Parser

The generic SIP header parser is exposed by parser/msg_parser.h. The function to be used is:

/*
Parameters :
      msg : the SIP message that needs to be parsed – see parser/msg_parser.h for details on the struct sip_msg structure
      flags : bitmask of header types that need to be parsed
      next : specifies whether the parser should explicitly force the parsing of new headers from the provided bitmask, even though those header types were already previously found. Can be useful when trying to find a second occurrence of a header ( in the case that header can appear multiple times in a SIP message – eg. Route )

Returns :
      0 in case of error, -1 in case of error ( either header was not found or some other error occurred ).
*/

int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next);


Example of usage :

if (parse_headers(req, HDR_CALLID_F|HDR_TO_F|HDR_FROM_F, 0) < 0 || !req->callid || !req->to || !req->from) {
      LM_ERR("bad request or missing CALLID/TO/FROM hdr\n");
      return -1;
}

HDR_EOH_F can be used in order to parse all the headers in the current SIP message.

The parse_headers() function will not duplicate SIP headers at all – the hooks in the struct sip_msg structure will be populated with pointers that point directly in the SIP message buffer.


Upon return, if successful, the function will populate the respective hooks in the sip_msg structure for the known headers. The hdr_field* structures are allocated in pkg memory, and will automatically be freed when the SIP message processing has finished.
After successful parsing, the developer can access the header name and body as such:

LM_INFO("The callid header name is %.*s and the callid header body is %.*s\n", req->callid->name.len, req->callid->name.s, req->callid->bodylen.  req->callid->body.s);

2.  Specific Header Parsing

For parsing a specific header type and extracting the header type relevant information, the parser/ directory contains all implementations for known headers. The naming convention is that parser/parse_X.h will expose the parsing for the header named X.
For example, here is the implementation of the parsing of the To header, exposed by parser/parse_to.h :

int parse_to_header( struct sip_msg *msg)
{      
      struct to_body* to_b;

      if ( !msg->to && ( parse_headers(msg,HDR_TO_F,0)==-1 || !msg->to)) {
            LM_ERR("bad msg or missing To header\n");
            goto error;
      }

      /* maybe the header is already parsed! */
      if (msg->to->parsed)
            return 0;

      /* bad luck! :-( - we have to parse it */
      /* first, get some memory */
      to_b = pkg_malloc(sizeof(struct to_body));
      if (to_b == 0) {
            LM_ERR("out of pkg_memory\n");
            goto error;
      }

      /* now parse it!! */
      memset(to_b, 0, sizeof(struct to_body));
      parse_to(msg->to->body.s,msg->to->body.s+msg->to->body.len+1,to_b);
      if (to_b->error == PARSE_ERROR) {
            LM_ERR("bad to header\n");
            pkg_free(to_b);
            goto error;
      }

      msg->to->parsed = to_b;

      return 0;
error:
      return -1;
}


Note that the void *parsed element in the hdr_field structure will contain the header specific parser structure, which will also be allocated into private memory and automatically freed when the SIP message processing has finished.


After parse_to_header() successfully returns, the developer can start accessing the parsed TO header in the following way :

LM_INFO("The To header tag value is %.*s\n", get_to(msg)->tag_value.len, get_to(msg)->tag_value.s);
2.1  Parsing SIP URIs

The OpenSIPS parser also exposes the functionality of parsing individual SIP URI.
parser/parse_uri.h exposes :

/*
Parameters :
      buf - the string which contains our SIP URI
      len - length of the SIP URI buffer
      uri - structure which will be populated by the function in case of success.
      See full struct sip_uri members in parser/msg_parser.h
Returns :
      0 in case of success, negative value in case of error parsing the URI
*/

int parse_uri(char *buf, int len, struct sip_uri* uri);


The parse_uri() function does not allocate any memory, it just populates the sip_uri structure with references to the buf parameter provided as input.
Here is an example of parsing the To header URI:

      /* make sure TO header is parsed before this */
      struct to_body *tb = get_to(msg);
      if (parse_uri(tb->uri.s, tb->uri.len , &tb->parsed_uri)<0) {
            LM_ERR("failed to parse To uri\n");
            return -1;
      }

      LM_INFO(“TO URI user is %.*s and TO URI domain is %.*s\n”,
      tb->parsed_uri.user.len, tb->parsed_uri.user.s,
      tb->parsed_uri.domain.len, tb->parsed_uri.domain.s);

3.  Parsing the SDP Body

OpenSIPS exposes functions for operating on the SIP message body.
parser/msg_parser.h exposes

/*
Parameters :
      msg - the SIP message to fetch the body for
      body - output param, which will hold the body pointer inside the SIP message and the body length, or {NULL,0} in case of no body present
Returns :
      0 in case of success, or -1 in the case of parsing errors ( the function needs to internally parse all the headers in order to detect the body length ).
*/

int get_body(struct sip_msg *msg, str *body)


For parsing the SDP body and extracting various information about the session(s) , parser/sdp/sdp.h exposes

/*
Parameters :
      _m - the SIP message to have it's SDP parsed
Returns :
      0 in case of success, negative in case of error
*/

int parse_sdp(struct sip_msg* _m);


The function will internally populate _m->sdp , see parser/sdp/sdp.h for more details on the sdp_info structure.


Page last modified on December 11, 2019, at 06:40 PM