summaryrefslogtreecommitdiffstats
path: root/src/sdp/sdp_parser.yxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/sdp/sdp_parser.yxx')
-rw-r--r--src/sdp/sdp_parser.yxx294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/sdp/sdp_parser.yxx b/src/sdp/sdp_parser.yxx
new file mode 100644
index 0000000..5926f09
--- /dev/null
+++ b/src/sdp/sdp_parser.yxx
@@ -0,0 +1,294 @@
+/*
+ Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com>
+
+ This program 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.
+
+ This program 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
+*/
+
+%{
+#include <algorithm>
+#include <cstdio>
+#include <string>
+#include "sdp_parse_ctrl.h"
+#include "sdp.h"
+#include "util.h"
+#include "audits/memman.h"
+
+using namespace std;
+
+extern int yysdplex(void);
+void yysdperror(const char *s);
+%}
+
+// The %debug option causes a problem with the %destructor options later on.
+// The bison compilor generates undefined symbols:
+//
+// parser.y: In function `void yysymprint(FILE*, int, yystype)':
+// parser.y:0: error: `null' undeclared (first use this function)
+//
+// So if you need to debug, then outcomment the %destructor first. This will
+// do no harm to your debugging, it only will cause memory leaks during
+// error handling.
+//
+// %debug
+
+
+%expect 2
+/* See below for the expected shift/reduce conflicts. */
+
+%union {
+ int yysdpt_int;
+ string *yysdpt_str;
+ t_sdp_ntwk_type yysdpt_ntwk_type;
+ t_sdp_addr_type yysdpt_addr_type;
+ t_sdp_connection *yysdpt_connection;
+ list<t_sdp_attr> *yysdpt_attributes;
+ t_sdp_attr *yysdpt_attribute;
+ t_sdp_media *yysdpt_media;
+ list<string> *yysdpt_token_list;
+}
+
+%token <yysdpt_int> T_NUM
+%token <yysdpt_str> T_TOKEN
+%token <yysdpt_str> T_SAFE
+%token <yysdpt_str> T_LINE
+
+%token T_CRLF
+
+%token T_LINE_VERSION
+%token T_LINE_ORIGIN
+%token T_LINE_SESSION_NAME
+%token T_LINE_CONNECTION
+%token T_LINE_ATTRIBUTE
+%token T_LINE_MEDIA
+%token T_LINE_UNKNOWN
+
+// The token T_NULL is never returned by the scanner.
+%token T_NULL
+
+%destructor { MEMMAN_DELETE($$); delete $$; } T_TOKEN
+%destructor { MEMMAN_DELETE($$); delete $$; } T_SAFE
+%destructor { MEMMAN_DELETE($$); delete $$; } T_LINE
+
+%type <yysdpt_addr_type> address_type
+%type <yysdpt_connection> connection
+%type <yysdpt_ntwk_type> network_type
+%type <yysdpt_attributes> attributes
+%type <yysdpt_attribute> attribute
+%type <yysdpt_attribute> attribute2
+%type <yysdpt_media> media
+%type <yysdpt_str> transport
+%type <yysdpt_token_list> formats
+
+%destructor { MEMMAN_DELETE($$); delete $$; } connection
+%destructor { MEMMAN_DELETE($$); delete $$; } attributes
+%destructor { MEMMAN_DELETE($$); delete $$; } attribute
+%destructor { MEMMAN_DELETE($$); delete $$; } attribute2
+%destructor { MEMMAN_DELETE($$); delete $$; } media
+%destructor { MEMMAN_DELETE($$); delete $$; } transport
+%destructor { MEMMAN_DELETE($$); delete $$; } formats
+
+%%
+
+/* The unknown_lines cause an expected shift/reduce conflict */
+sdp_body: version
+ origin
+ session_name
+ unknown_lines
+ sess_connection
+ unknown_lines
+ sess_attributes
+ media_list {
+ /* Parsing stops here. Remaining text is
+ * not parsed.
+ */
+ YYACCEPT; }
+ | error T_NULL {
+ /* KLUDGE to avoid memory leak in bison.
+ * See the SIP parser for an explanation.
+ */
+ YYABORT;
+ }
+;
+
+version: T_LINE_VERSION { CTX_NUM; } T_NUM { CTX_INITIAL; }
+ T_CRLF {
+ SDP->version = $3; }
+;
+
+origin: T_LINE_ORIGIN { CTX_SAFE; } T_SAFE { CTX_INITIAL; }
+ T_TOKEN T_TOKEN network_type address_type T_TOKEN T_CRLF {
+ SDP->origin.username = *$3;
+ SDP->origin.session_id = *$5;
+ SDP->origin.session_version = *$6;
+ SDP->origin.network_type = $7;
+ SDP->origin.address_type = $8;
+ SDP->origin.address = *$9;
+ MEMMAN_DELETE($3); delete $3;
+ MEMMAN_DELETE($5); delete $5;
+ MEMMAN_DELETE($6); delete $6;
+ MEMMAN_DELETE($9); delete $9; }
+;
+
+network_type: T_TOKEN { try {
+ $$ = str2sdp_ntwk_type(*$1);
+ MEMMAN_DELETE($1); delete $1;
+ }
+ catch (t_sdp_syntax_error) {
+ // Invalid network type.
+ // Set network type to NULL. This way the message
+ // will not be discarded and the error can be
+ // handled on the SIP level (error response or
+ // call tear down).
+ MEMMAN_DELETE($1); delete $1;
+ $$ = SDP_NTWK_NULL;
+ } }
+;
+
+address_type: T_TOKEN { try {
+ $$ = str2sdp_addr_type(*$1);
+ MEMMAN_DELETE($1); delete $1;
+ }
+ catch (t_sdp_syntax_error) {
+ // Invalid address type
+ MEMMAN_DELETE($1); delete $1;
+ $$ = SDP_ADDR_NULL;
+ } }
+;
+
+session_name: T_LINE_SESSION_NAME { CTX_LINE; } T_LINE
+ { CTX_INITIAL; } T_CRLF {
+ SDP->session_name = *$3;
+ MEMMAN_DELETE($3); delete $3; }
+;
+
+sess_connection: connection {
+ SDP->connection = *$1;
+ MEMMAN_DELETE($1); delete $1; }
+;
+
+connection: /* empty */ { $$ = new t_sdp_connection(); MEMMAN_NEW($$); }
+ | T_LINE_CONNECTION network_type address_type T_TOKEN
+ T_CRLF {
+ $$ = new t_sdp_connection();
+ MEMMAN_NEW($$);
+ $$->network_type = $2;
+ $$->address_type = $3;
+ $$->address = *$4;
+ MEMMAN_DELETE($4); delete $4; }
+;
+
+sess_attributes: attributes {
+ SDP->attributes = *$1;
+ MEMMAN_DELETE($1); delete $1; }
+;
+
+attributes: /* emtpy */ { $$ = new list<t_sdp_attr>; MEMMAN_NEW($$); }
+ | attributes attribute {
+ $$->push_back(*$2);
+ MEMMAN_DELETE($2); delete $2; }
+;
+
+attribute: T_LINE_ATTRIBUTE attribute2 T_CRLF {
+ $$ = $2; }
+;
+
+attribute2: T_TOKEN {
+ $$ = new t_sdp_attr(*$1);
+ MEMMAN_NEW($$);
+ MEMMAN_DELETE($1); delete $1; }
+ | T_TOKEN ':' { CTX_LINE; } T_LINE { CTX_INITIAL; } {
+ $$ = new t_sdp_attr(*$1, *$4);
+ MEMMAN_NEW($$);
+ MEMMAN_DELETE($1); delete $1;
+ MEMMAN_DELETE($4); delete $4; }
+;
+
+media_list: /* empty */
+ | media_list media {
+ SDP->media.push_back(*$2);
+ MEMMAN_DELETE($2); delete $2; }
+;
+
+/* The unknown_lines cause an expected shift/reduce conflict */
+media: T_LINE_MEDIA T_TOKEN { CTX_NUM; } T_NUM { CTX_INITIAL; }
+ transport formats T_CRLF unknown_lines connection
+ unknown_lines attributes {
+ $$ = new t_sdp_media();
+ MEMMAN_NEW($$);
+
+ if ($4 > 65535) YYERROR;
+
+ $$->media_type = tolower(*$2);
+ $$->port = $4;
+ $$->transport = *$6;
+
+ /* The format depends on the media type */
+ switch($$->get_media_type()) {
+ case SDP_AUDIO:
+ case SDP_VIDEO:
+ /* Numeric format */
+ for (list<string>::const_iterator it = $7->begin(); it != $7->end(); ++it) {
+ if (is_number(*it)) $$->formats.push_back(atoi(it->c_str()));
+ }
+
+ break;
+ default:
+ /* Alpha numeric format */
+ $$->alpha_num_formats = *$7;
+ }
+
+ $$->connection = *$10;
+ $$->attributes = *$12;
+ MEMMAN_DELETE($2); delete $2;
+ MEMMAN_DELETE($6); delete $6;
+ MEMMAN_DELETE($7); delete $7;
+ MEMMAN_DELETE($10); delete $10;
+ MEMMAN_DELETE($12); delete $12; }
+;
+
+transport: T_TOKEN {
+ $$ = $1; }
+ | T_TOKEN '/' T_TOKEN {
+ $$ = new string(*$1 + '/' + *$3);
+ MEMMAN_NEW($$);
+ MEMMAN_DELETE($1); delete $1;
+ MEMMAN_DELETE($3); delete $3; }
+
+// For RTP/AVP a format is a number. For other transport protocols,
+// non-numerical formats are possible.
+formats: /* empty */ { $$ = new list<string>; MEMMAN_NEW($$); }
+ | formats T_TOKEN {
+ $$->push_back(*$2);
+ MEMMAN_DELETE($2);
+ delete $2; }
+;
+
+/* Skip unknown lines */
+unknown_lines: /* empty */
+ | unknown_lines unknown_line
+;
+
+unknown_line: T_LINE_UNKNOWN { CTX_LINE; } T_LINE { CTX_INITIAL; }
+ T_CRLF {
+ MEMMAN_DELETE($3); delete $3; }
+;
+
+%%
+
+void
+yysdperror (const char *s) /* Called by yysdpparse on error */
+{
+ // printf ("%s\n", s);
+}