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 */
			;

"Welcome to our mercurial repository"