The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fd_config.c
Go to the documentation of this file.
1/*
2 * This program is 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 (at
5 * 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: 76316863d827cfb700ca480cfda7bded708e00ca $
19 * @file lib/bio/fd_config.c
20 * @brief BIO abstractions for configuring file descriptors.
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24
25#include <freeradius-devel/server/cf_parse.h>
26#include <freeradius-devel/server/tmpl.h>
27#include <freeradius-devel/util/perm.h>
28
29#include <freeradius-devel/bio/fd_priv.h>
30
32 { L("read-only"), O_RDONLY },
33 { L("read-write"), O_RDWR },
34 { L("ro"), O_RDONLY },
35 { L("rw"), O_RDWR },
36 { L("wo"), O_WRONLY },
37 { L("write-only"), O_WRONLY },
38};
40
41static int mode_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
42{
43 int mode;
44 char const *name = cf_pair_value(cf_item_to_pair(ci));
45
47 if (mode < 0) {
48 cf_log_err(ci, "Invalid mode name \"%s\"", name);
49 return -1;
50 }
51
52 *(int *) out = mode;
53
54 return 0;
55}
56
57/** Parse "transport" and then set the subconfig
58 *
59 */
60static int common_transport_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule, fr_table_ptr_sorted_t const *transport_table, size_t transport_table_len)
61{
62 int socket_type = SOCK_STREAM;
63 conf_parser_t const *rules;
64 char const *name = cf_pair_value(cf_item_to_pair(ci));
66 CONF_SECTION *cs, *subcs;
67
68 rules = fr_table_value_by_str(transport_table, name, NULL);
69 if (!rules) {
70 cf_log_err(ci, "Invalid transport name \"%s\"", name);
71 return -1;
72 }
73
75
76 /*
77 * Find the relevant subsection. Note that we don't do anything with it, as we push a parse
78 * rule in the parent which then points to the subsection.
79 */
80 subcs = cf_section_find(cs, name, NULL);
81 if (!subcs) {
82 cf_log_perr(ci, "Failed finding transport configuration section %s { ... }", name);
83 return -1;
84 }
85
86 /*
87 * Note that these offsets will get interpreted as being offsets from base of the subsection.
88 * i.e. the parent section and the subsection have to be parsed with the same base pointer.
89 */
90 if (cf_section_rules_push(cs, rules) < 0) {
91 cf_log_perr(ci, "Failed updating parse rules");
92 return -1;
93 }
94
95 if (strcmp(name, "udp") == 0) socket_type = SOCK_DGRAM;
96
97 /*
98 * Client sockets are always connected.
99 */
100 fd_config->socket_type = socket_type;
101 *(char const **) out = name;
102
103 return 0;
104}
105
108 { FR_CONF_OFFSET_TYPE_FLAGS("ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, dst_ipaddr) },
109 { FR_CONF_OFFSET_TYPE_FLAGS("ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, dst_ipaddr) },
110
111 { FR_CONF_OFFSET("port", fr_bio_fd_config_t, dst_port) },
112
113 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipaddr", FR_TYPE_COMBO_IP_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
114 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
115 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
116
117 { FR_CONF_OFFSET("src_port", fr_bio_fd_config_t, src_port) },
118 { FR_CONF_OFFSET("src_port_start", fr_bio_fd_config_t, src_port_start) },
119 { FR_CONF_OFFSET("src_port_end", fr_bio_fd_config_t, src_port_end) },
120
121 { FR_CONF_OFFSET("interface", fr_bio_fd_config_t, interface) },
122
123#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
124 { FR_CONF_OFFSET("exceed_mtu", fr_bio_fd_config_t, exceed_mtu), .dflt = "yes" },
125#endif
126
127 { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
128 { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
129
131};
132
134 { FR_CONF_POINTER("udp", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) client_udp_sub_config },
135
137};
138
139
141 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipaddr", FR_TYPE_COMBO_IP_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
142 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
143 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
144
145 { FR_CONF_OFFSET("interface", fr_bio_fd_config_t, interface) },
146
147 { FR_CONF_OFFSET("src_port_start", fr_bio_fd_config_t, src_port_start) },
148 { FR_CONF_OFFSET("src_port_end", fr_bio_fd_config_t, src_port_end) },
149
150#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
151 { FR_CONF_OFFSET("exceed_mtu", fr_bio_fd_config_t, exceed_mtu), .dflt = "yes" },
152#endif
153
154 { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
155 { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
156
158};
159
165
166
169 { FR_CONF_OFFSET_TYPE_FLAGS("ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, dst_ipaddr) },
170 { FR_CONF_OFFSET_TYPE_FLAGS("ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, dst_ipaddr) },
171
172 { FR_CONF_OFFSET("port", fr_bio_fd_config_t, dst_port) },
173
174 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipaddr", FR_TYPE_COMBO_IP_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
175 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
176 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
177
178 { FR_CONF_OFFSET("src_port", fr_bio_fd_config_t, src_port) },
179 { FR_CONF_OFFSET("src_port_start", fr_bio_fd_config_t, src_port_start) },
180 { FR_CONF_OFFSET("src_port_end", fr_bio_fd_config_t, src_port_end) },
181
182 { FR_CONF_OFFSET("interface", fr_bio_fd_config_t, interface) },
183
184 { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
185 { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
186
187 { FR_CONF_OFFSET("delay_tcp_writes", fr_bio_fd_config_t, tcp_delay) },
188
190};
191
193 { FR_CONF_POINTER("tcp", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) client_tcp_sub_config },
194
196};
197
200
201 { FR_CONF_OFFSET("permissions", fr_bio_fd_config_t, perm), .dflt = "0600", .func = cf_parse_permissions },
202
203 { FR_CONF_OFFSET("mode", fr_bio_fd_config_t, flags), .dflt = "read-write", .func = mode_parse },
204
206};
207
209 { FR_CONF_POINTER("file", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) client_file_sub_config },
210
212};
213
219
221 { FR_CONF_POINTER("unix", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) client_unix_sub_config },
222
224};
225
227 { L("file"), client_file_config },
228 { L("tcp"), client_tcp_config },
229 { L("udp"), client_udp_config },
230 { L("unix"), client_unix_config },
231};
233
234/** Parse "transport" and then set the subconfig
235 *
236 */
237static int client_transport_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
238{
240
241 /*
242 * Unconnected UDP sockets can only take src_ipaddr, but not port, and not dst_ipaddr.
243 */
245 char const *name = cf_pair_value(cf_item_to_pair(ci));
247
248 if (strcmp(name, "udp") != 0) {
249 cf_log_err(ci, "Invalid transport for unconnected UDP socket");
250 return -1;
251 }
252
254 cf_log_perr(ci, "Failed updating parse rules");
255 return -1;
256 }
257
258 fd_config->socket_type = SOCK_DGRAM;
259 *(char const **) out = name;
260
261 return 0;
262 }
263
265
266 return common_transport_parse(ctx, out, parent, ci, rule,
268}
269
270/*
271 * Client uses src_ipaddr for our address, and ipaddr for their address.
272 */
274 { FR_CONF_OFFSET("transport", fr_bio_fd_config_t, transport), .func = client_transport_parse },
275
276 { FR_CONF_OFFSET("async", fr_bio_fd_config_t, async), .dflt = "true" },
277
279};
280
281/*
282 * Server configuration
283 *
284 * "ipaddr" is src_ipaddr
285 * There's no "dst_ipaddr" or "src_ipaddr" in the config.
286 *
287 * Files have permissions which can be set.
288 */
289
292 { FR_CONF_OFFSET_TYPE_FLAGS("ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
293 { FR_CONF_OFFSET_TYPE_FLAGS("ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
294
295 { FR_CONF_OFFSET("port", fr_bio_fd_config_t, src_port) },
296
297 { FR_CONF_OFFSET("interface", fr_bio_fd_config_t, interface) },
298
299 { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
300 { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
301
302#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
303 { FR_CONF_OFFSET("exceed_mtu", fr_bio_fd_config_t, exceed_mtu), .dflt = "yes" },
304#endif
305
307};
308
310 { FR_CONF_POINTER("udp", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) server_udp_sub_config },
311
313};
314
317 { FR_CONF_OFFSET_TYPE_FLAGS("ipv4addr", FR_TYPE_IPV4_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
318 { FR_CONF_OFFSET_TYPE_FLAGS("ipv6addr", FR_TYPE_IPV6_ADDR, 0, fr_bio_fd_config_t, src_ipaddr) },
319
320 { FR_CONF_OFFSET("port", fr_bio_fd_config_t, src_port) },
321
322 { FR_CONF_OFFSET("interface", fr_bio_fd_config_t, interface) },
323
324 { FR_CONF_OFFSET_IS_SET("backlog", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, backlog) },
325
326 { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
327 { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
328
329 { FR_CONF_OFFSET("delay_tcp_writes", fr_bio_fd_config_t, tcp_delay) },
330
332};
333
335 { FR_CONF_POINTER("tcp", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) server_tcp_sub_config },
336
338};
339
342
343 { FR_CONF_OFFSET("permissions", fr_bio_fd_config_t, perm), .dflt = "0600", .func = cf_parse_permissions },
344
345 { FR_CONF_OFFSET("mkdir", fr_bio_fd_config_t, mkdir) },
346
348};
349
351 { FR_CONF_POINTER("file", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) server_file_sub_config },
352
354};
355
362
365
366 { FR_CONF_OFFSET("permissions", fr_bio_fd_config_t, perm), .dflt = "0600", .func = cf_parse_permissions },
367
368 { FR_CONF_OFFSET("mode", fr_bio_fd_config_t, flags), .dflt = "read-only", .func = mode_parse },
369
370 { FR_CONF_OFFSET("mkdir", fr_bio_fd_config_t, mkdir) },
371
372 { FR_CONF_POINTER("peercred", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) server_peercred_config },
373
375};
376
378 { FR_CONF_POINTER("unix", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) server_unix_sub_config },
379
381};
382
383/*
384 * @todo - move this to client/server config in the same struct?
385 */
387 { L("file"), server_file_config },
388 { L("tcp"), server_tcp_config },
389 { L("udp"), server_udp_config },
390 { L("unix"), server_unix_config },
391};
393
394/** Parse "transport" and then set the subconfig
395 *
396 */
397static int server_transport_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
398{
399 int rcode;
401
402 fd_config->server = true;
403
404 rcode = common_transport_parse(ctx, out, parent, ci, rule,
406 if (rcode < 0) return rcode;
407
408 /*
409 * Automatically set the BIO type, too.
410 */
411 if (fd_config->socket_type == SOCK_DGRAM) {
413 } else {
415 }
416
417 return 0;
418}
419
420/*
421 * Server uses ipaddr for our address, and doesn't use src_ipaddr.
422 */
424 { FR_CONF_OFFSET("transport", fr_bio_fd_config_t, transport), .func = server_transport_parse },
425
426 { FR_CONF_OFFSET("async", fr_bio_fd_config_t, async), .dflt = "true" },
427
429};
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
int cf_parse_gid(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving GID strings to uid_t values.
Definition cf_parse.c:1703
int cf_parse_permissions(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving permissions to a mode-t.
Definition cf_parse.c:1718
int cf_parse_uid(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving UID strings to uid_t values.
Definition cf_parse.c:1688
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:660
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:614
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:283
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:692
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition cf_parse.h:337
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition cf_parse.h:297
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:271
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:432
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:426
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:241
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:597
Common header for all CONF_* types.
Definition cf_priv.h:49
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:1027
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:683
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1574
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:288
#define cf_parent(_cf)
Definition cf_util.h:101
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:295
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:68
@ FR_BIO_FD_INVALID
not set
Definition fd.h:64
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
Definition fd.h:65
@ FR_BIO_FD_LISTEN
returns new fd in buffer on fr_bio_read() or fr_bio_fd_accept()
Definition fd.h:69
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition fd.h:81
bool server
is this a client or a server?
Definition fd.h:85
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:83
Configuration for sockets.
Definition fd.h:80
const conf_parser_t fr_bio_fd_server_config[]
Definition fd_config.c:423
static conf_parser_t const client_udp_unconnected_config[]
Definition fd_config.c:160
static conf_parser_t const client_file_config[]
Definition fd_config.c:208
static const conf_parser_t server_unix_sub_config[]
Definition fd_config.c:363
static size_t server_transport_names_len
Definition fd_config.c:392
static conf_parser_t const server_unix_config[]
Definition fd_config.c:377
static const conf_parser_t server_udp_sub_config[]
Definition fd_config.c:290
static int mode_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Definition fd_config.c:41
static const conf_parser_t client_udp_sub_config[]
Definition fd_config.c:106
static const conf_parser_t server_file_sub_config[]
Definition fd_config.c:340
static const conf_parser_t client_unix_sub_config[]
Definition fd_config.c:214
static int common_transport_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule, fr_table_ptr_sorted_t const *transport_table, size_t transport_table_len)
Parse "transport" and then set the subconfig.
Definition fd_config.c:60
static const conf_parser_t client_udp_unconnected_sub_config[]
Definition fd_config.c:140
const conf_parser_t fr_bio_fd_client_config[]
Definition fd_config.c:273
static conf_parser_t const client_udp_config[]
Definition fd_config.c:133
static int server_transport_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Parse "transport" and then set the subconfig.
Definition fd_config.c:397
static fr_table_ptr_sorted_t client_transport_names[]
Definition fd_config.c:226
static size_t client_transport_names_len
Definition fd_config.c:232
static const conf_parser_t client_file_sub_config[]
Definition fd_config.c:198
static int client_transport_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Parse "transport" and then set the subconfig.
Definition fd_config.c:237
static conf_parser_t const client_unix_config[]
Definition fd_config.c:220
static const conf_parser_t client_tcp_sub_config[]
Definition fd_config.c:167
static conf_parser_t const server_file_config[]
Definition fd_config.c:350
static conf_parser_t const server_udp_config[]
Definition fd_config.c:309
static const conf_parser_t server_peercred_config[]
Definition fd_config.c:356
static const conf_parser_t server_tcp_sub_config[]
Definition fd_config.c:315
static size_t mode_names_len
Definition fd_config.c:39
static fr_table_num_sorted_t mode_names[]
Definition fd_config.c:31
static conf_parser_t const server_tcp_config[]
Definition fd_config.c:334
static fr_table_ptr_sorted_t server_transport_names[]
Definition fd_config.c:386
static conf_parser_t const client_tcp_config[]
Definition fd_config.c:192
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
static fr_bio_fd_config_t fd_config
static char const * name
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
An element in a lexicographically sorted array of name to ptr mappings.
Definition table.h:65
static fr_slen_t parent
Definition pair.h:858
static size_t char ** out
Definition value.h:1030