Mercurial > hg > waaad
view waaad/conf-gram.y @ 101:54c7f5120aa5
Support for LocalPort configuration
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Wed, 23 Jul 2008 11:32:40 +0900 |
parents | 50665bb608fd |
children | 9a341105760a |
line wrap: on
line source
/********************************************************************************************************* * Software License Agreement (BSD License) * * Author: Sebastien Decugis <sdecugis@nict.go.jp> * * * * Copyright (c) 2008, WIDE Project and NICT * * All rights reserved. * * * * Redistribution and use of this software in source and binary forms, with or without modification, are * * permitted provided that the following conditions are met: * * * * * Redistributions of source code must retain the above * * copyright notice, this list of conditions and the * * following disclaimer. * * * * * Redistributions in binary form must reproduce the above * * copyright notice, this list of conditions and the * * following disclaimer in the documentation and/or other * * materials provided with the distribution. * * * * * Neither the name of the WIDE Project or NICT nor the * * names of its contributors may be used to endorse or * * promote products derived from this software without * * specific prior written permission of WIDE Project and * * NICT. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *********************************************************************************************************/ /* Yacc configuration parser. * * This file defines the grammar for parsing the configuration file of waaad. * Note that each extension has a separate independant configuration file. * * Note : This module is NOT thread-safe. All processing must be done from one thread only. */ /* For development only : */ %debug %error-verbose /* The parser receives a configuration pointer as parameter */ %parse-param {waaad_conf_t * pconfig} /* Keep track of location */ %locations %pure-parser %{ #include "waaad-internal.h" #include "conf-gram.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */ #include <string.h> #include <sys/stat.h> #include <errno.h> #include <sys/socket.h> #include <netdb.h> /* This function checks a string value can be a DiameterId (== a fqdn) */ static int is_valid_fqdn( char * candidate ) { /* We first search for a '.' */ if (!strchr(candidate, '.')) { log_error("The string '%s' is not a valid fully-qualified domain name (fqdn).\n", candidate); return 0; } /* We may do additional checking here */ /* Ok this candidate is valid */ return 1; } /* This function checks a string value is a valid filename */ static int is_valid_file( char * candidate ) { int ret; struct stat buffer; ret = stat(candidate, &buffer); if (ret != 0) { log_error("Error on file '%s': %s.\n", candidate, strerror(errno)); return 0; } /* Ok this candidate is valid */ return 1; } /* This function checks a string value is a valid network locator */ static int is_valid_locator( char * candidate ) { int ret=0; struct addrinfo *ai = NULL; ret = getaddrinfo(candidate, NULL, NULL, &ai); if (ai) freeaddrinfo(ai); if (ret != 0) { log_error("Error on locator '%s': %s.\n", candidate, gai_strerror(ret)); return 0; } /* Ok this candidate is valid */ return 1; } /* Function to report the errors */ void yyerror (YYLTYPE *ploc, waaad_conf_t * pconfig, char const *s) { if (ploc->first_line != ploc->last_line) log_error("%s:%d.%d-%d.%d : %s\n", pconfig->filepath, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); else if (ploc->first_column != ploc->last_column) log_error("%s:%d.%d-%d : %s\n", pconfig->filepath, ploc->first_line, ploc->first_column, ploc->last_column, s); else log_error("%s:%d.%d : %s\n", pconfig->filepath, ploc->first_line, ploc->first_column, s); } /* Global variable to store temporarily extension information */ static struct _ext_detail { char * fname; char * cname; } ext_detail={NULL, NULL}; /* Global variable to store temporarily peer information */ static struct _peer_detail { char * locator; uint16_t port; char flags; } peer_detail={NULL, 0, 0}; /* Flags values; 0 is default behavior */ #define PEER_NO_SEC 0x1 #define PEER_TCP 0x2 %} /* Values returned by lex for token */ %union { char *string; /* The string is allocated by strdup in lex.*/ uint16_t u16; /* Store small values such as TCP port or timers */ int integer; /* Store integer values */ } /* In case of error in the lexical analysis */ %token LEX_ERROR /* A quoted string */ %token <string> QSTRING /* Strings subtypes */ %type <string> FQDN /* This is a fqdn. We check that the syntax is correct. */ %type <string> FILENAME /* This is a filename. existence of the file is checked. */ /* An integer value */ %token <integer> INTEGER /* In the "general" section */ %token SECTION_GENERAL %token GEN_LOG %type <u16> gen_log_type %token GEN_LOG_CONSOLE %token GEN_LOG_SYSLOG %token GEN_DIAMID %token GEN_PORT %type <u16> gen_port_val %token GEN_TCTIMER %token GEN_DISABLERELAY /* In the "extension" section */ %token SECTION_EXTENSION %token <string> EXT_NAME %token EXT_FILENAME %token EXT_CONFFILE /* In the "peer" section */ %token SECTION_PEER %token PEER_URI %token PEER_SCHEME_SEC %token PEER_SCHEME_NOSEC %token <string> PEER_LOCATOR %token <u16> PEER_PORT %token PEER_TRANS_SCTP %token PEER_TRANS_TCP /* In the "routing" section */ %token SECTION_ROUTING /* -------------------------------------- */ %% /* The grammar definition - Sections blocs. General and Extension are mandatory (but may be empty) */ conffile: other_sections general_section other_sections extensions_section other_sections | other_sections extensions_section other_sections general_section other_sections ; /* Other sections are not mandatory and may appear in any order */ other_sections: /* empty */ | other_sections peers_section | other_sections routing_section ; /* These types are used several times: */ FQDN: QSTRING { /* Verify this is a valid FQDN */ if (!is_valid_fqdn($1)) { yyerror (&yylloc, pconfig, "An error was detected on a fqdn, aborting..."); YYERROR; } $$ = $1; } ; FILENAME: QSTRING { /* Verify this is a valid file */ if (!is_valid_file($1)) { yyerror (&yylloc, pconfig, "An error was detected on a file name, aborting..."); YYERROR; } $$ = $1; } ; /* Define the [general] section grammar */ general_section: SECTION_GENERAL general_content ; general_content: /* empty is allowed */ | general_content gen_log | general_content gen_diamid | general_content gen_port | general_content gen_tctimer | general_content gen_disablerelay ; gen_log: GEN_LOG '=' gen_log_type ';' { /* Save the new log type in the configuration. We'll set it only after conf file is parsed */ pconfig->log_to = (int) $3; } ; gen_log_type: /* Terminals rules */ GEN_LOG_SYSLOG { /* Save the syslog flag */ $$ = LOG_TO_SYSLOG; } | GEN_LOG_CONSOLE { /* Save the console flag */ $$ = LOG_TO_CONSOLE; } /* Recursive rules */ | gen_log_type ',' GEN_LOG_SYSLOG { /* Add the syslog flag */ $$ = $1 | LOG_TO_SYSLOG; } | gen_log_type ',' GEN_LOG_CONSOLE { /* Add the console flag */ $$ = $1 | LOG_TO_CONSOLE; } ; gen_diamid: GEN_DIAMID '=' FQDN ';' { /* Save this string as the peer diameter id */ if (pconfig->pub.diameter_identity) { free(pconfig->pub.diameter_identity); pconfig->pub.diameter_identity = NULL; } pconfig->pub.diameter_identity = $3; } | GEN_DIAMID '=' error ';' { log_error("A Diameter-Id MUST be a fqdn. Exiting...\n"); YYERROR; } ; gen_port: GEN_PORT '=' gen_port_val ';' { pconfig->pub.local_port = $3; } ; gen_port_val: INTEGER { if (( $1 <= 0) || ($1 > 65535)) { log_error("The LocalPort value (%d) is invalid. Exiting...\n", $1); YYERROR; } $$ = (uint16_t) $1 ; } ; gen_tctimer: GEN_TCTIMER '=' INTEGER ';' { pconfig->pub.tctimer = $3; } ; gen_disablerelay: GEN_DISABLERELAY '=' INTEGER ';' { pconfig->pub.disable_relay = $3; } ; /* Define the [extensions] section grammar */ extensions_section: SECTION_EXTENSION extensions_content ; extensions_content: /* empty is allowed */ | extensions_content extension_detail ; extension_detail: { /* Reset the ext_detail global before processing the rule */ if (ext_detail.fname) { free(ext_detail.fname); ext_detail.fname = NULL; } if (ext_detail.cname) { free(ext_detail.cname); ext_detail.cname = NULL; } } QSTRING '=' '{' extension_params '}' ';' { int ret = 0; /* Add this extension */ ret = ext_register( ext_detail.fname, ext_detail.cname ); /* Free the strings */ if (ext_detail.fname) { free(ext_detail.fname); ext_detail.fname = NULL; } if (ext_detail.cname) { free(ext_detail.cname); ext_detail.cname = NULL; } /* Check error */ if (ret != 0) { log_error("Failed to register extension %s: %s\n", $2, strerror(ret)); YYERROR; } } ; extension_params: extension_confname extension_filename extension_confname /* confname appears twice on purpose, to allow any order */ ; extension_filename: EXT_FILENAME '=' FILENAME ';' { if (ext_detail.fname) { free(ext_detail.fname); ext_detail.fname = NULL; } ext_detail.fname = $3; } | EXT_FILENAME '=' error ';' { log_error("You must provide a valid filename for extension.\n"); YYERROR; } ; extension_confname: /* This one is optional */ | EXT_CONFFILE '=' FILENAME ';' { if (ext_detail.cname) { free(ext_detail.cname); ext_detail.cname = NULL; } ext_detail.cname = $3; } | EXT_CONFFILE '=' error ';' { log_error("If you provide a configuration file for the extension, it must be a valid file.\n" " Note that you may remove the 'conffile' directive if your extension has no configuration.\n"); YYERROR; } ; /* Define the [peers] section grammar */ peers_section: SECTION_PEER peers_content ; peers_content: /* empty is allowed */ | peers_content peer_detail ; peer_detail: { /* Initialize the peer details */ if (peer_detail.locator ) { free(peer_detail.locator); peer_detail.locator = NULL; } peer_detail.port = 3868; peer_detail.flags = 0; } FQDN '=' '{' peer_uri '}' ';' { int ret = 0; peer_add_t data; memset(&data, 0, sizeof(peer_add_t)); /* $2 is the expansion of the FQDN rule */ data.peer_id = $2; /* The remaining of information is located in the peer_detail variable, filled during peer_uri rule */ /* Now add the peer with its information */ ret = peer_add(&data); if (ret != 0) { yyerror(&yylloc, pconfig, "An error occurred while adding a peer, aborting..."); YYERROR; } /* Free the strings */ if (data.peer_id) free(data.peer_id); } ; peer_uri: /* May be empty */ | PEER_URI '=' '"' peer_scheme peer_locator peer_port peer_transport '"' ';' { } ; peer_scheme: PEER_SCHEME_SEC | PEER_SCHEME_NOSEC { peer_detail.flags |= PEER_NO_SEC; } ; peer_locator: PEER_LOCATOR { /* Check the locator is valid */ if (!is_valid_locator($1)) { yyerror (&yylloc, pconfig, "An error was detected on a locator, aborting..."); YYERROR; } if (peer_detail.locator) free(peer_detail.locator); peer_detail.locator = $1; } ; peer_port: /* empty */ | PEER_PORT { peer_detail.port = $1; } ; peer_transport: /* empty */ | PEER_TRANS_SCTP | PEER_TRANS_TCP { peer_detail.flags |= PEER_TCP; } ; /* Define the [routing] section grammar */ routing_section: SECTION_ROUTING routing_content ; routing_content: /* empty is allowed */ ;