Mercurial > hg > freeDiameter
diff libfdcore/core.c @ 658:f198d16fa7f4
Initial commit for 1.1.0:
* Restructuring:
* libfreeDiameter:
- renamed folder & binary into libfdproto
- renamed libfD.h into fdproto-internal.h
- removed signals management (replaced by triggers in libfdcore)
* freeDiameter split into:
- libfdcore (most contents)
- renamed fD.h into fdcore-internal.h
- added core.c for framework init/shutdown.
- new triggers mechanism in events.c.
- freeDiameterd (main, command line parsing, signals management)
* tests:
- now in top-level directory tests.
* other changes:
- fd_dict_new now returns 0 on duplicate identical entries.
- fixes in dict_legacy_xml
- fixes in some dictionaries
- moved FD_DEFAULT_CONF_FILENAME definition to freeDiameter-host.h
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Fri, 14 Jan 2011 15:15:23 +0900 |
parents | |
children | 2e94ef0515d7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfdcore/core.c Fri Jan 14 15:15:23 2011 +0900 @@ -0,0 +1,296 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2009, 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. * +*********************************************************************************************************/ + +#include "fdcore-internal.h" + +#include <gcrypt.h> + +/* The static configuration structure */ +static struct fd_config conf; +struct fd_config * fd_g_config = &conf; + +/* gcrypt functions to support posix threads */ +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +/* Signal extensions when the framework is completly initialized */ +static int is_ready = 0; +static pthread_mutex_t is_ready_mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t is_ready_cnd = PTHREAD_COND_INITIALIZER; + +static int signal_framework_ready(void) +{ + TRACE_ENTRY(""); + CHECK_POSIX( pthread_mutex_lock( &is_ready_mtx ) ); + is_ready = 1; + CHECK_POSIX( pthread_cond_broadcast( &is_ready_cnd ) ); + CHECK_POSIX( pthread_mutex_unlock( &is_ready_mtx ) ); + return 0; +} + +/* Thread that process incoming events on the main queue -- and terminates the framework when requested */ +static pthread_t core_runner = (pthread_t)NULL; + +static void * core_runner_thread(void * arg) +{ + fd_log_threadname("Core Runner"); + + /* Handle events incoming on the main event queue */ + while (1) { + int code; size_t sz; void * data; + CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break ); + switch (code) { + case FDEV_DUMP_DICT: + fd_dict_dump(fd_g_config->cnf_dict); + break; + + case FDEV_DUMP_EXT: + fd_ext_dump(); + break; + + case FDEV_DUMP_SERV: + fd_servers_dump(); + break; + + case FDEV_DUMP_QUEUES: + fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk); + fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk); + fd_fifo_dump(0, "Local messages", fd_g_local, fd_msg_dump_walk); + break; + + case FDEV_DUMP_CONFIG: + fd_conf_dump(); + break; + + case FDEV_DUMP_PEERS: + fd_peer_dump_list(FULL); + break; + + case FDEV_TRIGGER: + { + int tv, *p; + CHECK_PARAMS_DO( sz == sizeof(int), + { + TRACE_DEBUG(NONE, "Internal error: got FDEV_TRIGGER without trigger value!"); + ASSERT(0); + goto end; + } ); + p = data; + tv = *p; + free(p); + CHECK_FCT_DO( fd_event_trig_call_cb(tv), goto end ); + } + break; + + case FDEV_TERMINATE: + goto end; + + default: + TRACE_DEBUG(INFO, "Unexpected event in the main event queue (%d), ignored.\n", code); + } + } + +end: + TRACE_DEBUG(INFO, FD_PROJECT_BINARY " framework is stopping..."); + + /* cleanups */ + CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ ); + CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ ); + CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ ); + CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ ); + + CHECK_FCT_DO( fd_ext_term(), /* Cleanup all extensions */ ); + CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ ); + + GNUTLS_TRACE( gnutls_global_deinit() ); + + CHECK_FCT_DO( fd_conf_deinit(), ); + + CHECK_FCT_DO( fd_event_trig_fini(), ); + + fd_log_debug(FD_PROJECT_BINARY " framework is terminated.\n"); + + fd_libproto_fini(); + + return NULL; +} + +/*********************************/ +/* Public interfaces */ + +/* Return a string describing the version of the library */ +const char *fd_core_version(void) +{ + return _stringize(FD_PROJECT_VERSION_MAJOR) "." _stringize(FD_PROJECT_VERSION_MINOR) "." _stringize(FD_PROJECT_VERSION_REV); +} + +/* Initialize the libfdcore internals. This also initializes libfdproto */ +int fd_core_initialize(void) +{ + int ret; + + memset(fd_g_config, 0, sizeof(struct fd_config)); + + /* Initialize the library -- must come first since it initializes the debug facility */ + ret = fd_libproto_init(); + if (ret != 0) { + fprintf(stderr, "Unable to initialize libfdproto: %s\n", strerror(ret)); + return ret; + } + + TRACE_DEBUG(INFO, "libfdproto initialized."); + + /* Name this thread */ + fd_log_threadname("Main"); + + /* Initialize gcrypt and gnutls */ + GNUTLS_TRACE( (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) ); + GNUTLS_TRACE( (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0) ); + CHECK_GNUTLS_DO( gnutls_global_init(), return EINVAL ); + if ( ! gnutls_check_version(GNUTLS_VERSION) ) { + fprintf(stderr, "The GNUTLS library is too old; found '%s', need '" GNUTLS_VERSION "'\n", gnutls_check_version(NULL)); + return EINVAL; + } else { + TRACE_DEBUG(INFO, "libgnutls '%s', libgcrypt '%s', initialized.", gnutls_check_version(NULL), gcry_check_version(NULL) ); + } + + /* Initialize the config with default values */ + CHECK_FCT( fd_conf_init() ); + + /* Add definitions of the base protocol */ + CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) ); + + /* Initialize some modules */ + CHECK_FCT( fd_queues_init() ); + CHECK_FCT( fd_msg_init() ); + CHECK_FCT( fd_sess_start() ); + CHECK_FCT( fd_p_expi_init() ); + + /* Next thing is to parse the config, leave this for a different function */ + return 0; +} + +/* Parse the freeDiameter.conf configuration file, load the extensions */ +int fd_core_parseconf(char * conffile) +{ + TRACE_ENTRY("%p", conffile); + + /* Conf file */ + if (conffile) + fd_g_config->cnf_file = conffile; /* otherwise, we use the default name */ + + CHECK_FCT( fd_conf_parse() ); + + /* The following module use data from the configuration */ + CHECK_FCT( fd_rtdisp_init() ); + + /* Now, load all dynamic extensions */ + CHECK_FCT( fd_ext_load() ); + + /* Display configuration */ + fd_conf_dump(); + + /* Display registered triggers for FDEV_TRIGGER */ + fd_event_trig_dump(); + + return 0; +} + +/* For threads that would need to wait complete start of the framework (ex: in extensions) */ +int fd_core_waitstartcomplete(void) +{ + TRACE_ENTRY(""); + + CHECK_POSIX( pthread_mutex_lock( &is_ready_mtx ) ); + pthread_cleanup_push( fd_cleanup_mutex, &is_ready_mtx ); + + while (!is_ready) { + CHECK_POSIX( pthread_cond_wait( &is_ready_cnd, &is_ready_mtx ) ); + } + + pthread_cleanup_pop( 0 ); + CHECK_POSIX( pthread_mutex_unlock( &is_ready_mtx ) ); + + return 0; +} + +/* Start the server & client threads */ +int fd_core_start(void) +{ + /* Start server threads */ + CHECK_FCT( fd_servers_start() ); + + /* Start the peer state machines */ + CHECK_FCT( fd_psm_start() ); + + /* Start the core runner thread that handles main events (until shutdown) */ + CHECK_POSIX( pthread_create(&core_runner, NULL, core_runner_thread, NULL) ); + + /* Unlock threads waiting into fd_core_waitstartcomplete */ + CHECK_FCT( signal_framework_ready() ); + + /* Ok, everything is running now... */ + return 0; +} + + +/* Initialize shutdown of the framework. This is not blocking. */ +int fd_core_shutdown(void) +{ + /* Signal the framework to terminate */ + CHECK_FCT( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL) ); + + return 0; +} + + +/* Wait for the shutdown to be complete -- this must always be called after fd_core_shutdown to relaim some resources. */ +int fd_core_wait_shutdown_complete(void) +{ + int ret; + void * th_ret = NULL; + + /* Just wait for core_runner_thread to complete and return gracefully */ + ret = pthread_join(core_runner, &th_ret); + if (ret != 0) { + fprintf(stderr, "Unable to wait for main framework thread termination: %s\n", strerror(ret)); + return ret; + } + + return 0; +} + + + +