Navigation


source: freeDiameter/libfdcore/extensions.c

Last change on this file was 1242:b25ca6134bdc, checked in by Sebastien Decugis <sdecugis@freediameter.net>, 7 years ago

Fix configuration dump when no extension is loaded

File size: 8.9 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
4*                                                                                                        *
5* Copyright (c) 2013, 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
38#include <dlfcn.h>      /* We may use libtool's <ltdl.h> later for better portability.... */
39#include <libgen.h>     /* for "basename" */
40
41/* plugins management */
42
43/* List of extensions to load, from the configuration parsing */
44struct fd_ext_info {
45        struct fd_list  chain;          /* link in the list */
46        char            *filename;      /* extension filename. must be a dynamic library with fd_ext_init symbol. */
47        char            *conffile;      /* optional configuration file name for the extension */
48        void            *handler;       /* object returned by dlopen() */
49        const char      **depends;      /* names of the other extensions this one depends on (if provided) */
50        char            *ext_name;      /* points to the extension name, either inside depends, or basename(filename) */
51        int             free_ext_name;  /* must be freed if it was malloc'd */
52        void            (*fini)(void);  /* optional address of the fd_ext_fini callback */
53};
54
55/* list of extensions */
56static struct fd_list ext_list = FD_LIST_INITIALIZER(ext_list);
57
58/* Add new extension */
59int fd_ext_add( char * filename, char * conffile )
60{
61        struct fd_ext_info * new;
62       
63        TRACE_ENTRY("%p %p", filename, conffile);
64       
65        /* Check the filename is valid */
66        CHECK_PARAMS( filename );
67       
68        /* Create a new object in the list */
69        CHECK_MALLOC(  new = malloc( sizeof(struct fd_ext_info) )  );
70        memset(new, 0, sizeof(struct fd_ext_info));
71        fd_list_init(&new->chain, NULL);
72        new->filename = filename;
73        new->conffile = conffile;
74        fd_list_insert_before( &ext_list, &new->chain );
75        TRACE_DEBUG (FULL, "Extension %s added to the list.", filename);
76        return 0;
77}
78
79/* Dump the list */
80DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump)
81{
82        struct fd_list * li;
83        FD_DUMP_HANDLE_OFFSET();
84       
85        if (FD_IS_LIST_EMPTY(&ext_list)) {
86                CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "-none-"), return NULL);
87        } else {
88                for (li = ext_list.next; li != &ext_list; li = li->next)
89                {
90                        struct fd_ext_info * ext = (struct fd_ext_info *)li;
91                        CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'[%s], %sloaded%s",
92                                                ext->filename, 
93                                                ext->conffile?:"(no config file)", 
94                                                ext->handler ? "" : "not ", (li->next == &ext_list) ? "":"\n"), return NULL);
95                }
96        }
97        return *buf;
98}
99
100/* Check the dependencies. The object must have been dlopened already. */
101static int check_dependencies(struct fd_ext_info * ext) 
102{
103        int i = 1;
104        TRACE_ENTRY( "%p", ext );
105       
106        /* Attempt to resolve the dependency array */
107        ext->depends = dlsym( ext->handler, "fd_ext_depends" );
108        if (!ext->depends) {
109                /* Duplicate the filename */
110                char * tmp = strdup(ext->filename);
111                ext->ext_name = strdup(basename(tmp));
112                free(tmp);
113                ext->free_ext_name = 1;
114                TRACE_DEBUG(FULL, "Old extension's [%s] API: missing dependencies (ignored)", ext->ext_name);
115                return 0;
116        }
117       
118        ext->ext_name = (char *)ext->depends[0];
119       
120        TRACE_DEBUG(FULL, "Checking dependencies for '%s'...", ext->ext_name);
121       
122        while (ext->depends[i]) {
123                struct fd_list * li;
124                for (li = ext_list.next; li != &ext->chain; li = li->next)
125                {
126                        struct fd_ext_info * e = (struct fd_ext_info *)li;
127                        if (!strcasecmp(e->ext_name, ext->depends[i])) {
128                                /* the dependency was already loaded */
129                                break;
130                        }
131                }
132               
133                if (li == &ext->chain) {
134                        /* the dependency was not found */
135                        LOG_F("Error: extension [%s] depends on [%s] which was not loaded first. Please fix your configuration file.",
136                                ext->ext_name, ext->depends[i]);
137                        return ESRCH;
138                }
139               
140                i++;
141        }
142
143        /* All dependencies resolved successfully */
144        return 0;
145}
146
147/* Load all extensions in the list */
148int fd_ext_load()
149{
150        int ret;
151        int (*fd_ext_init)(int, int, char *) = NULL;
152        struct fd_list * li;
153       
154        TRACE_ENTRY();
155       
156        /* Loop on all extensions */
157        for (li = ext_list.next; li != &ext_list; li = li->next)
158        {
159                struct fd_ext_info * ext = (struct fd_ext_info *)li;
160                LOG_D( "Loading : %s", ext->filename);
161               
162                /* Load the extension */
163#ifndef DEBUG
164                ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
165#else /* DEBUG */
166                /* We resolve symbols immediatly so it's easier to find problems in ABI */
167                ext->handler = dlopen(ext->filename, RTLD_NOW | RTLD_GLOBAL);
168#endif /* DEBUG */
169                if (ext->handler == NULL) {
170                        /* An error occured */
171                        LOG_F("Loading of extension %s failed: %s", ext->filename, dlerror());
172                        ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
173                        if (ext->handler) {
174                                if (!check_dependencies(ext)) {
175                                        LOG_F("In addition, not all declared dependencies are satisfied (Internal Error!)");
176                                }
177                        }
178                        return EINVAL;
179                }
180               
181                /* Check if declared dependencies are satisfied. */
182                CHECK_FCT( check_dependencies(ext) );
183               
184                /* Resolve the entry point of the extension */
185                fd_ext_init = ( int (*) (int, int, char *) )dlsym( ext->handler, "fd_ext_init" );
186               
187                if (fd_ext_init == NULL) {
188                        /* An error occured */
189                        TRACE_ERROR("Unable to resolve symbol 'fd_ext_init' for extension %s: %s", ext->filename, dlerror());
190                        return EINVAL;
191                }
192               
193                /* Resolve the exit point of the extension, which is optional for extensions */
194                ext->fini = ( void (*) (void) )dlsym( ext->handler, "fd_ext_fini" );
195               
196                if (ext->fini == NULL) {
197                        /* Not provided */
198                        TRACE_DEBUG (FULL, "Extension [%s] has no fd_ext_fini function.", ext->filename);
199                } else {
200                        /* Provided */
201                        TRACE_DEBUG (FULL, "Extension [%s] fd_ext_fini has been resolved successfully.", ext->filename);
202                }
203               
204                /* Now call the entry point to initialize the extension */
205                ret = (*fd_ext_init)( FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, ext->conffile );
206                if (ret != 0) {
207                        /* The extension was unable to load cleanly */
208                        TRACE_ERROR("Extension %s returned an error during initialization: %s", ext->filename, strerror(ret));
209                        return ret;
210                }
211               
212                /* Proceed to the next extension */
213        }
214
215        LOG_N("All extensions loaded.");
216       
217        /* We have finished. */
218        return 0;
219}
220
221/* Now unload the extensions and free the memory */
222int fd_ext_term( void ) 
223{
224        TRACE_ENTRY();
225       
226        /* Loop on all extensions, in FIFO order */
227        while (!FD_IS_LIST_EMPTY(&ext_list))
228        {
229                struct fd_list * li = ext_list.next;
230                struct fd_ext_info * ext = (struct fd_ext_info *)li;
231       
232                /* Unlink this element from the list */
233                fd_list_unlink(li);
234               
235                /* Call the exit point of the extension, if it was resolved */
236                if (ext->fini != NULL) {
237                        TRACE_DEBUG (FULL, "Calling [%s]->fd_ext_fini function.", ext->ext_name ?: ext->filename);
238                        (*ext->fini)();
239                }
240               
241#ifndef SKIP_DLCLOSE
242                /* Now unload the extension */
243                if (ext->handler) {
244                        TRACE_DEBUG (FULL, "Unloading %s", ext->ext_name ?: ext->filename);
245                        if ( dlclose(ext->handler) != 0 ) {
246                                TRACE_DEBUG (INFO, "Unloading [%s] failed : %s", ext->ext_name ?: ext->filename, dlerror());
247                        }
248                }
249#endif /* SKIP_DLCLOSE */
250               
251                /* Free the object and continue */
252                if (ext->free_ext_name)
253                        free(ext->ext_name);
254                free(ext->filename);
255                free(ext->conffile);
256                free(ext);
257        }
258       
259        /* We always return 0 since we would not handle an error anyway... */
260        return 0;
261}
262
Note: See TracBrowser for help on using the repository browser.