Navigation


source: freeDiameter/libfdcore/core.c

Last change on this file was 1554:566bb46cc73f, checked in by Sebastien Decugis <sdecugis@freediameter.net>, 5 months ago

Updated copyright information

File size: 11.7 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
4*                                                                                                        *
5* Copyright (c) 2019, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38GCC_DIAG_OFF("-Wdeprecated-declarations")
39#include <gcrypt.h>
40GCC_DIAG_ON("-Wdeprecated-declarations")
41
42/* The static configuration structure */
43static struct fd_config g_conf;
44struct fd_config * fd_g_config = NULL;
45
46/* gcrypt functions to support posix threads */
47#ifndef GNUTLS_VERSION_210
48GCRY_THREAD_OPTION_PTHREAD_IMPL;
49#endif /* GNUTLS_VERSION_210 */
50
51/* Thread that process incoming events on the main queue -- and terminates the framework when requested */
52static pthread_t core_runner = (pthread_t)NULL;
53
54/* Signal extensions when the framework is completely initialized (they are waiting in fd_core_waitstartcomplete()) */
55static enum core_state {
56        CORE_NOT_INIT,  /* initial state */
57        CORE_LIBS_INIT, /* fd_core_initialize was called */
58        CORE_CONF_READY,/* Configuration was parsed, extensions are loaded */
59        CORE_RUNNING,   /* Servers and clients are started, core_runner thread is running */
60        CORE_SHUTDOWN,  /* The framework is terminating all objects */
61        CORE_TERM       /* Shutdown complete. */       
62} core_state = CORE_NOT_INIT;
63static pthread_mutex_t core_mtx = PTHREAD_MUTEX_INITIALIZER;
64static pthread_cond_t  core_cnd = PTHREAD_COND_INITIALIZER;
65
66static enum core_state core_state_get(void)
67{
68        enum core_state cur_state;
69        CHECK_POSIX_DO( pthread_mutex_lock( &core_mtx ), );
70        cur_state = core_state;
71        CHECK_POSIX_DO( pthread_mutex_unlock( &core_mtx ), );
72        return cur_state;
73}
74
75static void core_state_set(enum core_state newstate)
76{
77        CHECK_POSIX_DO( pthread_mutex_lock( &core_mtx ), );
78        LOG_D("Core state: %d -> %d", core_state, newstate);
79        core_state = newstate;
80        CHECK_POSIX_DO( pthread_cond_broadcast( &core_cnd ), );
81        CHECK_POSIX_DO( pthread_mutex_unlock( &core_mtx ), );
82}
83
84static int core_state_wait(enum core_state waitstate)
85{
86        int ret = 0;
87        CHECK_POSIX( pthread_mutex_lock( &core_mtx ));
88        pthread_cleanup_push( fd_cleanup_mutex, &core_mtx );
89        while (waitstate > core_state) {
90                CHECK_POSIX_DO(ret = pthread_cond_wait(&core_cnd, &core_mtx), break);
91        }
92        pthread_cleanup_pop( 0 );
93        CHECK_POSIX( pthread_mutex_unlock( &core_mtx ));
94        return ret;
95}
96
97static void core_shutdown(void)
98{
99        LOG_N( FD_PROJECT_BINARY " framework is stopping...");
100        fd_log_threadname("fD Core Shutdown");
101       
102        /* cleanups */
103        CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
104        CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ );
105        CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
106        CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ );
107       
108        CHECK_FCT_DO( fd_ext_term(), /* Cleanup all extensions */ );
109        CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ );
110       
111        GNUTLS_TRACE( gnutls_global_deinit() );
112       
113        CHECK_FCT_DO( fd_conf_deinit(), );
114       
115        CHECK_FCT_DO( fd_event_trig_fini(), );
116       
117        fd_log_debug(FD_PROJECT_BINARY " framework is terminated.");
118       
119        fd_libproto_fini();
120       
121}       
122
123
124static void * core_runner_thread(void * arg) 
125{
126        fd_log_threadname("fD Core Runner");
127       
128        core_state_wait(CORE_RUNNING);
129       
130        /* Handle events incoming on the main event queue */
131        while (1) {
132                int code; size_t sz; void * data;
133                CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
134                switch (code) {
135                        case FDEV_TRIGGER:
136                                {
137                                        int tv, *p;
138                                        CHECK_PARAMS_DO( sz == sizeof(int), 
139                                                {
140                                                        TRACE_DEBUG(NONE, "Internal error: got FDEV_TRIGGER without trigger value!");
141                                                        ASSERT(0);
142                                                        goto end;
143                                                } );
144                                        p = data;
145                                        tv = *p;
146                                        free(p);
147                                        CHECK_FCT_DO( fd_event_trig_call_cb(tv), goto end );
148                                }
149                                break;
150                       
151                        case FDEV_TERMINATE_INT:
152                                goto end;
153                       
154                        default:
155                                TRACE_DEBUG(INFO, "Unexpected event in the main event queue (%d), ignored.", code);
156                }
157        }
158       
159end:
160        core_shutdown();
161       
162        return NULL;
163}
164
165/*********************************/
166/* Public interfaces */
167
168/* Initialize the libfdcore internals. This also initializes libfdproto */
169int fd_core_initialize(void)
170{
171        int ret;
172       
173        if (core_state_get() != CORE_NOT_INIT) {
174                fprintf(stderr, "fd_core_initialize() called more than once!\n");
175                return EINVAL;
176        }
177       
178        /* Initialize the library -- must come first since it initializes the debug facility */
179        ret = fd_libproto_init();
180        if (ret != 0) {
181                fprintf(stderr, "Unable to initialize libfdproto: %s\n", strerror(ret));
182                return ret;
183        }
184       
185        /* Name this thread */
186        fd_log_threadname("Main");
187       
188        LOG_N("libfdproto '%s' initialized.", fd_libproto_version);
189       
190        /* Initialize gcrypt and gnutls */
191        #ifndef GNUTLS_VERSION_210
192        GNUTLS_TRACE( (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) );
193        GNUTLS_TRACE( (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0) );
194        #endif /* GNUTLS_VERSION_210 */
195        CHECK_GNUTLS_DO( gnutls_global_init(), return EINVAL );
196        if ( ! gnutls_check_version(GNUTLS_VERSION) ) {
197                TRACE_ERROR( "The GNUTLS library is too old; found '%s', need '" GNUTLS_VERSION "'", gnutls_check_version(NULL));
198                return EINVAL;
199        } else {
200        #ifdef GNUTLS_VERSION_210
201                TRACE_DEBUG(INFO, "libgnutls '%s' initialized.", gnutls_check_version(NULL) );
202        #else /* GNUTLS_VERSION_210 */
203                TRACE_DEBUG(INFO, "libgnutls '%s', libgcrypt '%s', initialized.", gnutls_check_version(NULL), gcry_check_version(NULL) );
204        #endif /* GNUTLS_VERSION_210 */
205        }
206       
207        /* Initialize the config with default values */
208        memset(&g_conf, 0, sizeof(struct fd_config));
209        fd_g_config = &g_conf;
210        CHECK_FCT( fd_conf_init() );
211       
212        /* Add definitions of the base protocol */
213        CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) );
214       
215        /* Initialize some modules */
216        CHECK_FCT( fd_hooks_init()  );
217        CHECK_FCT( fd_queues_init() );
218        CHECK_FCT( fd_sess_start()  );
219        CHECK_FCT( fd_p_expi_init() );
220       
221        core_state_set(CORE_LIBS_INIT);
222       
223        LOG_N("libfdcore '%s' initialized.", fd_core_version);
224       
225       
226        /* Next thing is to parse the config, leave this for a different function */
227        return 0;
228}
229
230static pthread_mutex_t core_lock = PTHREAD_MUTEX_INITIALIZER;
231
232/* Parse the freeDiameter.conf configuration file, load the extensions */
233static int fd_core_parseconf_int(const char * conffile)
234{
235        char * buf = NULL, *b;
236        size_t len = 0, offset=0;
237       
238       
239        TRACE_ENTRY("%p", conffile);
240       
241        /* Conf file */
242        if (conffile)
243                fd_g_config->cnf_file = conffile; /* otherwise, we use the default name */
244       
245        CHECK_FCT( fd_conf_parse() );
246       
247        /* The following module use data from the configuration */
248        CHECK_FCT( fd_rtdisp_init() );
249       
250        /* Now, load all dynamic extensions */
251        CHECK_FCT(  fd_ext_load()  );
252       
253        /* Display configuration */
254        b = fd_conf_dump(&buf, &len, NULL);
255        LOG_SPLIT(FD_LOG_NOTICE, NULL, b ?: "<Error during configuration dump...>", NULL);
256       
257        /* Display extensions status */
258        b = fd_ext_dump(&buf, &len, NULL);
259        LOG_SPLIT(FD_LOG_NOTICE, "Loaded extensions: ", b?:"<Error during extensions dump...>", NULL);
260       
261        /* Display registered triggers for FDEV_TRIGGER */
262        b = fd_event_trig_dump(&buf, &len, &offset);
263        if (!b || offset) {
264                LOG_N("%s", b ?: "Error during triggers dump...");
265        }
266       
267        free(buf);     
268               
269        /* Since some extensions might have modified the definitions from the dict_base_protocol, we only load the objects now */
270        CHECK_FCT( fd_msg_init()    );
271       
272        /* Ok, ready for next step */
273        core_state_set(CORE_CONF_READY);
274       
275        return 0;
276}
277
278int fd_core_parseconf(const char * conffile)
279{
280        int ret;
281        CHECK_POSIX( pthread_mutex_lock(&core_lock) );
282        ret = fd_core_parseconf_int(conffile);
283        CHECK_POSIX( pthread_mutex_unlock(&core_lock) );
284        return ret;
285}
286
287
288/* For threads that would need to wait complete start of the framework (ex: in extensions) */
289int fd_core_waitstartcomplete(void)
290{
291        TRACE_ENTRY("");
292       
293        return core_state_wait(CORE_RUNNING);
294}
295
296/* Start the server & client threads */
297static int fd_core_start_int(void)
298{
299        /* Start server threads */ 
300        CHECK_FCT( fd_servers_start() );
301       
302        /* Start the peer state machines */
303        CHECK_FCT( fd_psm_start() );
304       
305        /* Start the core runner thread that handles main events (until shutdown) */
306        CHECK_POSIX( pthread_create(&core_runner, NULL, core_runner_thread, NULL) );
307       
308        /* Unlock threads waiting into fd_core_waitstartcomplete */
309        core_state_set(CORE_RUNNING);
310       
311        /* Ok, everything is running now... */
312        return 0;
313}
314
315int fd_core_start(void)
316{
317        int ret;
318        CHECK_FCT( fd_queues_init_after_conf() );
319
320        CHECK_POSIX( pthread_mutex_lock(&core_lock) );
321        ret = fd_core_start_int();
322        CHECK_POSIX( pthread_mutex_unlock(&core_lock) );
323        return ret;
324}
325
326/* Initialize shutdown of the framework. This is not blocking. */
327int fd_core_shutdown(void)
328{
329        enum core_state cur_state = core_state_get();
330       
331        LOG_N("Initiating freeDiameter shutdown sequence (%d)", cur_state);
332               
333        if (cur_state < CORE_RUNNING) {
334                /* Calling application must make sure the initialization is not ongoing in a separate thread... */
335                if (pthread_mutex_lock(&core_lock) != 0) {
336                        /* This function must not be called asynchronously from fd_core_parseconf / fd_core_start ! Please review your main app design */
337                        ASSERT(0);
338                        return EINVAL;
339                }
340                core_shutdown();
341                core_state_set(CORE_TERM);
342                pthread_mutex_unlock(&core_lock);
343        } else if (cur_state == CORE_RUNNING) {
344                core_state_set(CORE_SHUTDOWN);
345                CHECK_FCT( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE_INT, 0, NULL) );
346        }
347       
348        /* Other case, the framework is already shutting down */
349       
350        return 0;
351}
352
353
354/* Wait for the shutdown to be complete -- this must be called after fd_core_shutdown to reclaim some resources. */
355int fd_core_wait_shutdown_complete(void)
356{
357        enum core_state cur_state = core_state_get();
358        void * th_ret = NULL;
359       
360        CHECK_FCT(core_state_wait(CORE_SHUTDOWN));
361       
362        if (cur_state == CORE_TERM)
363                return 0;
364       
365        /* Just wait for core_runner_thread to complete and return gracefully */
366        CHECK_POSIX(pthread_join(core_runner, &th_ret));
367
368        core_state_set(CORE_TERM);
369               
370        return 0;
371}
372
373
374
375
Note: See TracBrowser for help on using the repository browser.