2 * Copyright (c) 2015, Juniper Networks, Inc.
4 * This SOFTWARE is licensed under the LICENSE provided in the
5 * ../Copyright file. By downloading, installing, copying, or otherwise
6 * using the SOFTWARE, you agree to be bound by the terms of that
8 * Phil Shafer, August 2015
12 * libxo includes a number of fixed encoding styles. But other
13 * external encoders are need to deal with new encoders. Rather
14 * than expose a swarm of libxo internals, we create a distinct
15 * API, with a simpler API than we use internally.
21 #include <sys/queue.h>
22 #include <sys/param.h>
25 #include "xo_config.h"
27 #include "xo_encoder.h"
31 #if !defined(HAVE_DLFUNC)
32 #define dlfunc(_p, _n) dlsym(_p, _n)
34 #else /* HAVE_DLFCN_H */
35 #define dlopen(_n, _f) NULL /* Fail */
36 #define dlsym(_p, _n) NULL /* Fail */
37 #define dlfunc(_p, _n) NULL /* Fail */
38 #endif /* HAVE_DLFCN_H */
40 static void xo_encoder_setup (void); /* Forward decl */
43 * Need a simple string collection
45 typedef struct xo_string_node_s {
46 TAILQ_ENTRY(xo_string_node_s) xs_link; /* Next string */
47 char xs_data[0]; /* String data */
50 typedef TAILQ_HEAD(xo_string_list_s, xo_string_node_s) xo_string_list_t;
53 xo_string_list_init (xo_string_list_t *listp)
55 if (listp->tqh_last == NULL)
59 static inline xo_string_node_t *
60 xo_string_add (xo_string_list_t *listp, const char *str)
62 if (listp == NULL || str == NULL)
65 xo_string_list_init(listp);
66 size_t len = strlen(str);
67 xo_string_node_t *xsp;
69 xsp = xo_realloc(NULL, sizeof(*xsp) + len + 1);
71 memcpy(xsp->xs_data, str, len);
72 xsp->xs_data[len] = '\0';
73 TAILQ_INSERT_TAIL(listp, xsp, xs_link);
79 #define XO_STRING_LIST_FOREACH(_xsp, _listp) \
80 xo_string_list_init(_listp); \
81 TAILQ_FOREACH(_xsp, _listp, xs_link)
84 xo_string_list_clean (xo_string_list_t *listp)
86 xo_string_node_t *xsp;
88 xo_string_list_init(listp);
91 xsp = TAILQ_FIRST(listp);
94 TAILQ_REMOVE(listp, xsp, xs_link);
99 static xo_string_list_t xo_encoder_path;
102 xo_encoder_path_add (const char *path)
107 xo_string_add(&xo_encoder_path, path);
110 /* ---------------------------------------------------------------------- */
112 typedef struct xo_encoder_node_s {
113 TAILQ_ENTRY(xo_encoder_node_s) xe_link; /* Next session */
114 char *xe_name; /* Name for this encoder */
115 xo_encoder_func_t xe_handler; /* Callback function */
116 void *xe_dlhandle; /* dlopen handle */
119 typedef TAILQ_HEAD(xo_encoder_list_s, xo_encoder_node_s) xo_encoder_list_t;
121 #define XO_ENCODER_LIST_FOREACH(_xep, _listp) \
122 xo_encoder_list_init(_listp); \
123 TAILQ_FOREACH(_xep, _listp, xe_link)
125 static xo_encoder_list_t xo_encoders;
128 xo_encoder_list_init (xo_encoder_list_t *listp)
130 if (listp->tqh_last == NULL)
134 static xo_encoder_node_t *
135 xo_encoder_list_add (const char *name)
140 xo_encoder_node_t *xep = xo_realloc(NULL, sizeof(*xep));
142 ssize_t len = strlen(name) + 1;
143 xep->xe_name = xo_realloc(NULL, len);
144 if (xep->xe_name == NULL) {
149 memcpy(xep->xe_name, name, len);
151 TAILQ_INSERT_TAIL(&xo_encoders, xep, xe_link);
158 xo_encoders_clean (void)
160 xo_encoder_node_t *xep;
165 xep = TAILQ_FIRST(&xo_encoders);
169 TAILQ_REMOVE(&xo_encoders, xep, xe_link);
171 if (xep->xe_dlhandle)
172 dlclose(xep->xe_dlhandle);
177 xo_string_list_clean(&xo_encoder_path);
181 xo_encoder_setup (void)
187 xo_string_list_init(&xo_encoder_path);
188 xo_encoder_list_init(&xo_encoders);
190 xo_encoder_path_add(XO_ENCODERDIR);
194 static xo_encoder_node_t *
195 xo_encoder_find (const char *name)
197 xo_encoder_node_t *xep;
199 xo_encoder_list_init(&xo_encoders);
201 XO_ENCODER_LIST_FOREACH(xep, &xo_encoders) {
202 if (strcmp(xep->xe_name, name) == 0)
209 static xo_encoder_node_t *
210 xo_encoder_discover (const char *name)
213 char buf[MAXPATHLEN];
214 xo_string_node_t *xsp;
215 xo_encoder_node_t *xep = NULL;
217 XO_STRING_LIST_FOREACH(xsp, &xo_encoder_path) {
218 static const char fmt[] = "%s/%s.enc";
219 char *dir = xsp->xs_data;
220 size_t len = snprintf(buf, sizeof(buf), fmt, dir, name);
222 if (len > sizeof(buf)) /* Should not occur */
225 dlp = dlopen((const char *) buf, RTLD_NOW);
232 * If the library exists, find the initializer function and
235 xo_encoder_init_func_t func;
237 func = (xo_encoder_init_func_t) dlfunc(dlp, XO_ENCODER_INIT_NAME);
239 xo_encoder_init_args_t xei;
241 bzero(&xei, sizeof(xei));
243 xei.xei_version = XO_ENCODER_VERSION;
244 ssize_t rc = func(&xei);
245 if (rc == 0 && xei.xei_handler) {
246 xep = xo_encoder_list_add(name);
248 xep->xe_handler = xei.xei_handler;
249 xep->xe_dlhandle = dlp;
262 xo_encoder_register (const char *name, xo_encoder_func_t func)
266 xo_encoder_node_t *xep = xo_encoder_find(name);
268 if (xep) /* "We alla-ready got one" */
271 xep = xo_encoder_list_add(name);
273 xep->xe_handler = func;
277 xo_encoder_unregister (const char *name)
281 xo_encoder_node_t *xep = xo_encoder_find(name);
283 TAILQ_REMOVE(&xo_encoders, xep, xe_link);
289 xo_encoder_init (xo_handle_t *xop, const char *name)
293 /* Can't have names containing '/' or ':' */
294 if (strchr(name, '/') != NULL || strchr(name, ':') != NULL)
298 * First we look on the list of known (registered) encoders.
299 * If we don't find it, we follow the set of paths to find
300 * the encoding library.
302 xo_encoder_node_t *xep = xo_encoder_find(name);
304 xep = xo_encoder_discover(name);
309 xo_set_encoder(xop, xep->xe_handler);
311 return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL, 0);
315 * A couple of function varieties here, to allow for multiple
316 * use cases. This variant is for when the main program knows
317 * its own encoder needs.
320 xo_encoder_create (const char *name, xo_xof_flags_t flags)
324 xop = xo_create(XO_STYLE_ENCODER, flags);
326 if (xo_encoder_init(xop, name)) {
336 xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
337 const char *name, const char *value, xo_xof_flags_t flags)
339 void *private = xo_get_private(xop);
340 xo_encoder_func_t func = xo_get_encoder(xop);
345 return func(xop, op, name, value, private, flags);
349 xo_encoder_op_name (xo_encoder_op_t op)
351 static const char *names[] = {
354 /* 2 */ "open_container",
355 /* 3 */ "close_container",
357 /* 5 */ "close_list",
358 /* 6 */ "open_leaf_list",
359 /* 7 */ "close_leaf_list",
360 /* 8 */ "open_instance",
361 /* 9 */ "close_instance",
371 if (op > sizeof(names) / sizeof(names[0]))