The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
global_lib.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/*
18 * $Id: 1eb22d8b3c1a8ec9520730c37dbd24dbec9fe0d5 $
19 *
20 * @file global_lib.c
21 * @brief Handle global configuration, initialisation and freeing for libraries
22 *
23 * @copyright 2022 The FreeRADIUS server project
24 */
25#include <freeradius-devel/server/global_lib.h>
26#include <freeradius-devel/server/main_config.h>
27#include <freeradius-devel/util/atexit.h>
28
29/*
30 * Terminator for array of global_lib_autoinst_t
31 */
33
34/*
35 * Global list of libraries
36 */
37typedef struct {
40
42
43/** Structure to track use of libraries.
44 *
45 */
46typedef struct {
47 fr_rb_node_t entry; //!< Entry in tree of libraries
48 global_lib_autoinst_t const *autoinit; //!< Autoinit structure used to manage this library
49 uint32_t instance_count; //!< Number of current uses of this library
50 bool initialised; //!< Has the init callback been run for this library
52
53/** Parse the global config section for a library and call its init function
54 *
55 * @param[in] lib to configure and initialise
56 * @return
57 * - 0 on success
58 * - -1 on failure
59 */
61{
62 CONF_SECTION *global_cs, *cs;
63
64 /*
65 * Find relevant config section
66 * If the section does not exist allocate an empty one
67 * so default rules can be evaluated.
68 */
69 global_cs = cf_section_find(cf_root(main_config->root_cs), "global", NULL);
70 if (!global_cs) global_cs = cf_section_alloc(main_config->root_cs, main_config->root_cs, "global", NULL);
71
72 cs = cf_section_find(global_cs, lib->autoinit->name, NULL);
73 if (!cs) cs = cf_section_alloc(global_cs, global_cs, lib->autoinit->name, NULL);
74
75 if ((cf_section_rules_push(cs, lib->autoinit->config)) < 0 ||
76 (cf_section_parse(lib, lib->autoinit->inst, cs) < 0)) {
77 cf_log_err(cs, "Failed evaluating configuration for libldap");
78 return -1;
79 }
80
81 /*
82 * Call the init callback if defined
83 */
84 if (lib->autoinit->init && (lib->autoinit->init()) < 0) return -1;
85
86 lib->initialised = true;
87
88 return 0;
89}
90
91/** Instantiate a list of libraries
92 *
93 * @param to_init Array of autoinit structures detailing libraries to initialise
94 * @return
95 * - 0 on success
96 * - -1 on failure
97 */
98static int lib_auto_instantiate(global_lib_autoinst_t * const *to_init)
99{
100 global_lib_autoinst_t * const *p;
101
102 for (p = to_init; *p != &global_lib_terminator; p++) {
103 global_lib_inst_t *lib = NULL;
104
105 lib = fr_rb_find(&lib_list->libs, &(global_lib_inst_t){ .autoinit = *p });
106
107 /*
108 * If the library is already initialised, just increase the reference count
109 */
110 if ((lib) && (lib->initialised)) {
111 lib->instance_count++;
112 return 0;
113 }
114
115 if (!lib) {
116 MEM(lib = talloc_zero(lib_list, global_lib_inst_t));
117 lib->autoinit = *p;
118 fr_rb_insert(&lib_list->libs, lib);
119 }
120 lib->instance_count++;
121
122 /*
123 * If the main config parsing is not complete we can't initialise the library yet
124 */
125 if (!main_config->root_cs) continue;
126
127 DEBUG2("Instantiating %s", lib->autoinit->name);
128 if (lib_init_call(lib) < 0) return -1;
129 }
130
131 return 0;
132}
133
134/** Callback for creation of "lib" symbols
135 *
136 */
137int global_lib_auto_instantiate(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
138{
139 if (lib_auto_instantiate((global_lib_autoinst_t **)symbol) < 0) return -1;
140
141 return 0;
142}
143
144/** Run free callbacks for external libraries no-longer in use
145 *
146 * @param[in] to_free Array of autoinit structures detailing libraries to free
147 */
148static void lib_autofree(global_lib_autoinst_t * const *to_free)
149{
150 global_lib_autoinst_t * const *p;
151
152 for (p = to_free; *p != &global_lib_terminator; p++) {
153 global_lib_inst_t *lib = NULL;
154
155 lib = fr_rb_find(&lib_list->libs, &(global_lib_inst_t){ .autoinit = *p });
156
157 fr_assert_msg(lib, "Library %s already freed", (*p)->name);
158
159 if (--lib->instance_count > 0) return;
160
161 /*
162 * Only run the free callback if the library was successfully initialised
163 */
164 if (lib->initialised && ((*p)->free)) (*p)->free();
165
166 fr_rb_remove(&lib_list->libs, lib);
167 talloc_free(lib);
168 }
169}
170
171/** Callback for freeing of "lib" symbols
172 *
173 */
174void global_lib_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
175{
177}
178
179/** Compare two fr_lib_t
180 *
181 */
182static int8_t _lib_cmp(void const *one, void const *two)
183{
184 global_lib_inst_t const *a = one;
185 global_lib_inst_t const *b = two;
186
187 return CMP(a->autoinit, b->autoinit);
188}
189
190/** Free global list of libraries
191 *
192 * Called as an atexit function
193 */
194static int _lib_list_free_atexit(UNUSED void *uctx)
195{
196 if (talloc_free(lib_list) < 0) return -1;
197 lib_list = NULL;
198 return 0;
199}
200
201/** Initialise the global list of external libraries
202 *
203 */
205{
206 if (lib_list) return 0;
207
208 MEM(lib_list = talloc_zero(NULL, global_lib_list_t));
210
212 return 0;
213}
214
215/** Walk the tree of libraries and instantiate any which are pending
216 *
217 */
219{
220 /*
221 * Must be called after main config has been parsed
222 */
224
225 DEBUG2("#### Instantiating libraries ####");
227 if (lib->initialised) continue;
228
229 DEBUG2("Instantiating %s", lib->autoinit->name);
230 if (lib_init_call(lib) < 0) return -1;
231
232 }
234 return 0;
235}
#define fr_atexit_global(_func, _uctx)
Add a free function to the global free list.
Definition atexit.h:59
#define endforeach
Definition build.h:493
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define UNUSED
Definition build.h:315
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1124
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:674
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1028
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_root(_cf)
Definition cf_util.h:98
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:140
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:210
#define MEM(x)
Definition debug.h:36
Module handle.
Definition dl.h:58
fr_rb_tree_t libs
Definition global_lib.c:38
fr_rb_node_t entry
Entry in tree of libraries.
Definition global_lib.c:47
static void lib_autofree(global_lib_autoinst_t *const *to_free)
Run free callbacks for external libraries no-longer in use.
Definition global_lib.c:148
int global_lib_init(void)
Initialise the global list of external libraries.
Definition global_lib.c:204
static int _lib_list_free_atexit(UNUSED void *uctx)
Free global list of libraries.
Definition global_lib.c:194
bool initialised
Has the init callback been run for this library.
Definition global_lib.c:50
static int lib_auto_instantiate(global_lib_autoinst_t *const *to_init)
Instantiate a list of libraries.
Definition global_lib.c:98
uint32_t instance_count
Number of current uses of this library.
Definition global_lib.c:49
static global_lib_list_t * lib_list
Definition global_lib.c:41
void global_lib_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback for freeing of "lib" symbols.
Definition global_lib.c:174
int global_lib_auto_instantiate(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback for creation of "lib" symbols.
Definition global_lib.c:137
global_lib_autoinst_t const global_lib_terminator
Definition global_lib.c:32
global_lib_autoinst_t const * autoinit
Autoinit structure used to manage this library.
Definition global_lib.c:48
int global_lib_instantiate(void)
Walk the tree of libraries and instantiate any which are pending.
Definition global_lib.c:218
static int lib_init_call(global_lib_inst_t *lib)
Parse the global config section for a library and call its init function.
Definition global_lib.c:60
static int8_t _lib_cmp(void const *one, void const *two)
Compare two fr_lib_t.
Definition global_lib.c:182
Structure to track use of libraries.
Definition global_lib.c:46
conf_parser_t const * config
Config parser for this library's global options.
Definition global_lib.h:40
char const * name
Name of library and section within global config.
Definition global_lib.h:39
lib_init_t init
Callback to initialise library.
Definition global_lib.h:42
void * inst
Module data to parse global config into.
Definition global_lib.h:41
Structure to define how to initialise libraries with global configuration.
Definition global_lib.h:38
talloc_free(reap)
main_config_t const * main_config
Main server configuration.
Definition main_config.c:69
CONF_SECTION * root_cs
Root of the server config.
Definition main_config.h:55
unsigned int uint32_t
#define fr_assert(_expr)
Definition rad_assert.h:38
#define DEBUG2(fmt,...)
Definition radclient.h:43
void * fr_rb_remove(fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
Definition rb.c:695
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Definition rb.h:180
#define fr_rb_inorder_foreach(_tree, _type, _iter)
Definition rb.h:333
The main red black tree structure.
Definition rb.h:73