Pārlūkot izejas kodu

Adding the sst parser from kamailio core

Jan Janak 16 gadi atpakaļ
vecāks
revīzija
d434e7ed08
2 mainītis faili ar 369 papildinājumiem un 0 dzēšanām
  1. 241 0
      lib/kcore/parse_sst.c
  2. 128 0
      lib/kcore/parse_sst.h

+ 241 - 0
lib/kcore/parse_sst.c

@@ -0,0 +1,241 @@
+/*
+ * $Id$
+ * 
+ * Copyright (c) 2006 SOMA Networks, Inc. <http://www.somanetworks.com/>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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:
+ * --------
+ * 2006-02-17 Initial revision ([email protected])
+ */
+
+/*!
+ * \file
+ * \brief SST parser
+ * \ingroup parser
+ */
+
+#include "parse_sst.h"
+
+#include "../error.h"
+#include "../dprint.h"
+#include "../mem/mem.h"
+
+
+inline int/*bool*/  is_space( char c ) { return (c == ' ' || c == '\t'); }
+inline int/*bool*/  is_num( char c ) { return (c >= '0' && c <= '9'); }
+
+inline unsigned  lower_byte( char b ) { return b | 0x20; }
+inline unsigned  lower_4bytes( unsigned d ) { return d | 0x20202020; }
+inline unsigned  lower_3bytes( unsigned d ) { return d |   0x202020; }
+inline unsigned  read_4bytes( char *val ) {
+	return (*(val + 0) + (*(val + 1) << 8)
+		+ (*(val + 2) << 16) + (*(val + 3) << 24));
+}
+inline unsigned  read_3bytes( char *val ) {
+	return (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16));
+}
+
+/* compile-time constants if called with constants */
+#define  MAKE_4BYTES( a, b, c, d ) \
+	( ((a)&0xFF) | (((b)&0xFF)<<8) | (((c)&0xFF)<<16) | (((d)&0xFF)<<24) )
+#define  MAKE_3BYTES( a, b, c ) \
+	( ((a)&0xFF) | (((b)&0xFF)<<8) | (((c)&0xFF)<<16) )
+
+
+struct session_expires *
+malloc_session_expires( void )
+{
+	struct session_expires *se = (struct session_expires *)
+		pkg_malloc( sizeof(struct session_expires) );
+	if ( se )
+		memset( se, 0, sizeof(struct session_expires) );
+	return se;
+}
+
+
+void
+free_session_expires( struct session_expires *se )
+{
+	if ( se )
+		pkg_free( se );
+}
+
+
+enum parse_sst_result
+parse_session_expires_body( struct hdr_field *hf )
+{
+	register char *p = hf->body.s;
+	int pos = 0;
+	int len = hf->body.len;
+	char *q;
+	struct session_expires se = { 0, sst_refresher_unspecified };
+	unsigned tok;
+
+	if ( !p || len <= 0 ) {
+		LM_ERR(" no body for header field\n" );
+		return parse_sst_header_not_found;
+	}
+
+	/* skip whitespace */
+	for ( ; pos < len && is_space(*p); ++pos, ++p )
+		/*nothing*/;
+
+	/* collect a number */
+	for ( q = p; pos < len && is_num(*q); ++pos, ++q )
+		se.interval = se.interval*10/*radix*/ + (*q - '0');
+
+	if ( q == p ) /*nothing parsed */ {
+		LM_ERR(" no expiry interval\n" );
+		return parse_sst_no_value;
+	}
+	p = q;
+
+	/* continue on with params */
+	while ( pos < len ) {
+
+		if ( *p == ';' ) {
+			++p; ++pos;
+
+			if ( pos + 4 < len ) {
+				switch ( lower_4bytes(read_4bytes(p)) ) {
+					case /*refr*/MAKE_4BYTES('r','e','f','r'):
+						if ( pos + 9 <= len
+							 && lower_4bytes(read_4bytes(p+4))
+								== /*eshe*/MAKE_4BYTES('e','s','h','e')
+							 && lower_byte(*(p+8)) == 'r'
+							 && *(p+9) == '=' ) {
+							tok = lower_3bytes( read_3bytes(p+10) );
+							if ( tok == MAKE_3BYTES('u','a','c') ) {
+								se.refresher = sst_refresher_uac;
+								p += 13; pos += 13;
+							}
+							else if ( tok == MAKE_3BYTES('u','a','s') ) {
+								se.refresher = sst_refresher_uas;
+								p += 13; pos += 13;
+							}
+							else /* unrecognized refresher-param */ {
+								LM_ERR(" unrecognized refresher\n" );
+								return parse_sst_parse_error;
+							}
+						}
+						else /* not "esher=" */ {
+							/* there are no other se-params 
+							   that start with "refr" */
+							for ( ; pos < len && *p != ';'; ++pos, ++p )
+								/*skip to ';'*/;
+						}
+						break;
+					default:
+						/* unrecognized se-param */
+						for ( ; pos < len && *p != ';'; ++pos, ++p )
+							/*skip to ';'*/;
+						break;
+				} /*switch*/
+			} /* exist 4 bytes to check */
+			else /* less than 4 bytes left */ {
+				/* not enough text left for any of the recognized se-params */
+				/* no other recognized se-param */
+				for ( ; pos < len && *p != ';'; ++pos, ++p ) /*skip to ';'*/;
+			}
+		}
+		else /* not ';' */ {
+			LM_ERR("no semicolon separating se-params\n");
+			return parse_sst_parse_error;
+		} /* if ';' */
+	} /* while */
+
+	hf->parsed = malloc_session_expires();
+	if ( !hf->parsed ) {
+		LM_ERR(" out of pkg memory\n" );
+		return parse_sst_out_of_mem;
+	}
+	*((struct session_expires *)hf->parsed) = se;
+
+	return parse_sst_success;
+}
+
+
+enum parse_sst_result
+parse_session_expires( struct sip_msg *msg, struct session_expires *se )
+{
+	enum parse_sst_result result;
+
+	if ( msg->session_expires ) {
+		if ( msg->session_expires->parsed == 0
+			 && (result = parse_session_expires_body(msg->session_expires))
+				!= parse_sst_success ) {
+			return result;
+		}
+		if ( se ) {
+			*se = *((struct session_expires *)msg->session_expires->parsed);
+		}
+		return parse_sst_success;
+	}
+	else {
+		return parse_sst_header_not_found;
+	}
+}
+
+
+enum parse_sst_result
+parse_min_se_body( struct hdr_field *hf )
+{
+	int len = hf->body.len;
+	char *p = hf->body.s;
+	int pos = 0;
+	unsigned int interval = 0;
+
+	/* skip whitespace */
+	for ( ; pos < len && is_space(*p); ++pos, ++p )
+		/*nothing*/;
+	if ( pos == len )
+		return parse_sst_no_value;
+	/* collect a number */
+	for ( ; pos < len && is_num(*p); ++pos, ++p )
+		interval = interval*10/*radix*/ + (*p - '0');
+	/* skip whitespace */
+	for ( ; pos < len && is_space(*p); ++pos, ++p )
+		/*nothing*/;
+	if ( pos != len ) /* shouldn't be any more junk */
+		return parse_sst_parse_error;
+	hf->parsed=(void*)(long)interval;
+	return parse_sst_success;
+}
+
+
+enum parse_sst_result
+parse_min_se( struct sip_msg *msg, unsigned int *min_se )
+{
+	enum parse_sst_result result;
+
+	if ( msg->min_se ) {
+		if ( msg->min_se->parsed == 0
+			 && (result = parse_min_se_body(msg->min_se))
+				!= parse_sst_success ) {
+			return result;
+		}
+		if ( min_se ) {
+			*min_se = (unsigned int)(long)msg->min_se->parsed;
+		}
+		return parse_sst_success;
+	}
+	else {
+		return parse_sst_header_not_found;
+	}
+}

+ 128 - 0
lib/kcore/parse_sst.h

@@ -0,0 +1,128 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2006 SOMA Networks, Inc. <http://www.somanetworks.com/>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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:
+ * --------
+ * 2006-02-17 Initial revision ([email protected])
+ */
+
+/*!
+ * \file
+ * \brief SST parser
+ * \ingroup parser
+ */
+
+#ifndef PARSE_SST_H
+#define PARSE_SST_H 1
+
+
+#include "msg_parser.h"
+#include "hf.h"
+
+
+/*!
+ * Indicate the "refresher=" value of the Session-Expires header.
+ */
+enum sst_refresher {
+	sst_refresher_unspecified,
+	sst_refresher_uac,
+	sst_refresher_uas,
+};
+
+
+/*!
+ * We will treat the 'void* parsed' field of struct hdr_field as
+ * a pointer to a struct session_expires.
+ */
+struct session_expires {
+	unsigned            interval; /* in seconds */
+	enum sst_refresher  refresher;
+};
+
+
+enum parse_sst_result {
+	parse_sst_success,
+	parse_sst_header_not_found,	/* no header */
+	parse_sst_no_value,			/* no interval specified */
+#if NOT_IMPLEMENTED_YET
+	parse_sst_duplicate,		/* multiple s-e / x / min-se headers found */
+#endif
+	parse_sst_out_of_mem,
+	parse_sst_parse_error,		/* something puked */
+};
+
+
+/*!
+ * Allocate a zeroed-out struct session_expires.
+ */
+struct session_expires *
+malloc_session_expires( void );
+
+
+/*!
+ * Deallocates memory previously allocated via malloc_session_expires().
+ */
+void
+free_session_expires( struct session_expires * );
+
+
+/*!
+ * \brief Parses the (should be only one instance) single instance of the
+ * "Session-Expires" or "x" header in the msg. 
+ * \note The header is not automatically parsed in parse_headers()[1]
+ * so you'll have to call this function to get the information.
+ *
+ * Because of time constraints, this function is coded assuming there is
+ * NO WHITESPACE in any of the body -- note that the augBNF for the
+ * Session-Expires body allows sep whitespace between tokens:
+ *   delta-seconds SWS ";" SWS "refresher" SWS "=" SWS ( "uac" / "uas" )
+ *
+ * Note[1]: it looks like only the frequently-used headers are
+ * automatically parsed in parse_headers() (indicated by a parse_<name>
+ * function of the form "char* parse_<name>(char *buf, char *end, foo*)
+ * and a struct foo with a member called "error").
+ *
+ * \param msg the sip message to examine
+ * \param se the place to store session-expires information into, if
+ *         provided; note that result is also available in
+ *         *((struct session_expires *)msg->session_expires->parsed)
+ * \return parse_sst_result
+ */
+enum parse_sst_result
+parse_session_expires( struct sip_msg *msg, struct session_expires *se );
+
+
+/*!
+ * \brief Parses the (should be only one instance) single instance of the
+ * "Min-SE" header in the msg. 
+ * \note The header is not automatically parsed in parse_headers() so you'll have
+ * to call this function to get the information.
+ *
+ * \param msg the sip message to examine
+ * \param min_se the place to store the Min-SE value, if provided; note that
+ *         result is also available in (unsigned)msg->min_se->parsed
+ * \return parse_sst_result
+ */
+enum parse_sst_result
+parse_min_se( struct sip_msg *msg, unsigned *min_se );
+
+
+#endif /* ! PARSE_SST_H */