Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b
Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/mod/dl.c b/src/mod/dl.c
new file mode 100644
index 0000000..a449927
--- /dev/null
+++ b/src/mod/dl.c
@@ -0,0 +1,89 @@
+/**
+ * @file dl.c Interface to dynamic linking loader
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <dlfcn.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include "mod_internal.h"
+
+
+#define DEBUG_MODULE "dl"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+static const int dl_flag = RTLD_NOW | RTLD_LOCAL;
+
+
+/**
+ * Load a dynamic library file
+ *
+ * @param name Name of library to load
+ *
+ * @return Opaque library handle, NULL if not loaded
+ */
+void *_mod_open(const char *name)
+{
+ void *h;
+
+ if (!name)
+ return NULL;
+
+ h = dlopen(name, dl_flag);
+ if (!h) {
+ DEBUG_WARNING("mod: %s (%s)\n", name, dlerror());
+ return NULL;
+ }
+
+ return h;
+}
+
+
+/**
+ * Resolve address of symbol in dynamic library
+ *
+ * @param h Library handle
+ * @param symbol Name of symbol to resolve
+ *
+ * @return Address, NULL if failure
+ */
+void *_mod_sym(void *h, const char *symbol)
+{
+ void *sym;
+ const char *err;
+
+ if (!h || !symbol)
+ return NULL;
+
+ (void)dlerror(); /* Clear any existing error */
+
+ sym = dlsym(h, symbol);
+ err = dlerror();
+ if (err) {
+ DEBUG_WARNING("dlsym: %s\n", err);
+ return NULL;
+ }
+
+ return sym;
+}
+
+
+/**
+ * Unload a dynamic library
+ *
+ * @param h Library handle
+ */
+void _mod_close(void *h)
+{
+ int err;
+
+ if (!h)
+ return;
+
+ err = dlclose(h);
+ if (0 != err) {
+ DEBUG_WARNING("dlclose: %d\n", err);
+ }
+}
diff --git a/src/mod/mod.c b/src/mod/mod.c
new file mode 100644
index 0000000..6fc0aa1
--- /dev/null
+++ b/src/mod/mod.c
@@ -0,0 +1,245 @@
+/**
+ * @file mod.c Loadable modules
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_list.h>
+#include <re_mod.h>
+#include "mod_internal.h"
+
+
+#define DEBUG_MODULE "mod"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/** Defines a loadable module */
+struct mod {
+ struct le le; /**< Linked list element */
+ void *h; /**< Module handler */
+ const struct mod_export *me; /**< Module exports */
+};
+
+
+static struct list modl; /* struct mod */
+
+
+/**
+ * Initialise module loading
+ */
+void mod_init(void)
+{
+ list_init(&modl);
+}
+
+
+/**
+ * Unload all modules
+ */
+void mod_close(void)
+{
+ list_flush(&modl);
+}
+
+
+static void mod_destructor(void *data)
+{
+ struct mod *m = data;
+ const struct mod_export *me = m->me;
+ int err;
+
+ if (me && me->close && (err = me->close())) {
+ DEBUG_NOTICE("close: error (%m)\n", err);
+ }
+
+ list_unlink(&m->le);
+
+ _mod_close(m->h);
+}
+
+
+/**
+ * Find a module by name in the list of loaded modules
+ *
+ * @param name Name of module to find
+ *
+ * @return Module if found, NULL if not found
+ */
+struct mod *mod_find(const char *name)
+{
+ struct le *le;
+ struct pl x;
+
+ if (!name)
+ return NULL;
+
+ if (re_regex(name, strlen(name), "[/]*[^./]+" MOD_EXT, NULL, &x))
+ return NULL;
+
+ for (le = modl.head; le; le = le->next) {
+ struct mod *m = le->data;
+
+ if (0 == pl_strcasecmp(&x, m->me->name))
+ return m;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Load and initialise a loadable module by name
+ *
+ * @param mp Pointer to allocated module object
+ * @param name Name of loadable module
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mod_load(struct mod **mp, const char *name)
+{
+ struct mod *m;
+ int err = 0;
+
+ if (!mp || !name)
+ return EINVAL;
+
+ /* check if already loaded */
+ m = mod_find(name);
+ if (m) {
+ DEBUG_NOTICE("module already loaded: %s\n", name);
+ return EALREADY;
+ }
+
+ m = mem_zalloc(sizeof(*m), mod_destructor);
+ if (!m)
+ return ENOMEM;
+
+ list_append(&modl, &m->le, m);
+
+ m->h = _mod_open(name);
+ if (!m->h) {
+ err = ENOENT;
+ goto out;
+ }
+
+ m->me = _mod_sym(m->h, "exports");
+ if (!m->me) {
+ err = ELIBBAD;
+ goto out;
+ }
+
+ if (m->me->init && (err = m->me->init()))
+ goto out;
+
+ out:
+ if (err)
+ mem_deref(m);
+ else
+ *mp = m;
+
+ return err;
+}
+
+
+/**
+ * Add and initialise an external module with exports
+ *
+ * @param mp Pointer to allocated module object
+ * @param me Module exports
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mod_add(struct mod **mp, const struct mod_export *me)
+{
+ struct mod *m;
+ int err = 0;
+
+ if (!mp || !me)
+ return EINVAL;
+
+ /* check if already loaded */
+ m = mod_find(me->name);
+ if (m) {
+ DEBUG_NOTICE("module already loaded: %s\n", me->name);
+ return EALREADY;
+ }
+
+ m = mem_zalloc(sizeof(*m), mod_destructor);
+ if (!m)
+ return ENOMEM;
+
+ list_append(&modl, &m->le, m);
+
+ m->me = me;
+
+ if (m->me->init)
+ err = m->me->init();
+
+ if (err)
+ mem_deref(m);
+ else
+ *mp = m;
+
+ return err;
+}
+
+
+/**
+ * Get module export from a loadable module
+ *
+ * @param m Loadable module
+ *
+ * @return Module export
+ */
+const struct mod_export *mod_export(const struct mod *m)
+{
+ return m ? m->me : NULL;
+}
+
+
+/**
+ * Get the list of loaded modules
+ *
+ * @return Module list
+ */
+struct list *mod_list(void)
+{
+ return &modl;
+}
+
+
+/**
+ * Debug loadable modules
+ *
+ * @param pf Print handler for debug output
+ * @param unused Unused parameter
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mod_debug(struct re_printf *pf, void *unused)
+{
+ struct le *le;
+ int err;
+
+ (void)unused;
+
+ err = re_hprintf(pf, "\n--- Modules (%u) ---\n", list_count(&modl));
+
+ for (le = modl.head; le && !err; le = le->next) {
+ const struct mod *m = le->data;
+ const struct mod_export *me = m->me;
+
+ err = re_hprintf(pf, " %16s type=%-12s ref=%u\n",
+ me->name, me->type, mem_nrefs(m));
+ }
+
+ err |= re_hprintf(pf, "\n");
+
+ return err;
+}
diff --git a/src/mod/mod.mk b/src/mod/mod.mk
new file mode 100644
index 0000000..f9e50a5
--- /dev/null
+++ b/src/mod/mod.mk
@@ -0,0 +1,16 @@
+#
+# mod.mk
+#
+# Copyright (C) 2010 Creytiv.com
+#
+
+SRCS += mod/mod.c
+
+# Unix dlopen
+ifdef HAVE_DLFCN_H
+SRCS += mod/dl.c
+endif
+
+ifeq ($(OS),win32)
+SRCS += mod/win32/dll.c
+endif
diff --git a/src/mod/mod_internal.h b/src/mod/mod_internal.h
new file mode 100644
index 0000000..b764a93
--- /dev/null
+++ b/src/mod/mod_internal.h
@@ -0,0 +1,20 @@
+/**
+ * @file mod_internal.h Internal interface to loadable module
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void *_mod_open(const char *name);
+void *_mod_sym(void *h, const char *symbol);
+void _mod_close(void *h);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/mod/win32/dll.c b/src/mod/win32/dll.c
new file mode 100644
index 0000000..44b4957
--- /dev/null
+++ b/src/mod/win32/dll.c
@@ -0,0 +1,85 @@
+/**
+ * @file dll.c Dynamic library loading for Windows
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <windows.h>
+#include <re_types.h>
+#include "../mod_internal.h"
+
+
+#define DEBUG_MODULE "dll"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/**
+ * Open a DLL file
+ *
+ * @param name Name of DLL to open
+ *
+ * @return Handle (NULL if failed)
+ */
+void *_mod_open(const char *name)
+{
+ HINSTANCE DllHandle = 0;
+
+ DEBUG_INFO("loading %s\n", name);
+
+ DllHandle = LoadLibraryA(name);
+ if (!DllHandle) {
+ DEBUG_WARNING("open: %s LoadLibraryA() failed\n", name);
+ return NULL;
+ }
+
+ return DllHandle;
+}
+
+
+/**
+ * Resolve a symbol address in a DLL
+ *
+ * @param h DLL Handle
+ * @param symbol Symbol to resolve
+ *
+ * @return Address of symbol
+ */
+void *_mod_sym(void *h, const char *symbol)
+{
+ HINSTANCE DllHandle = (HINSTANCE)h;
+ union {
+ FARPROC sym;
+ void *ptr;
+ } u;
+
+ if (!DllHandle)
+ return NULL;
+
+ DEBUG_INFO("get symbol: %s\n", symbol);
+
+ u.sym = GetProcAddress(DllHandle, symbol);
+ if (!u.sym) {
+ DEBUG_WARNING("GetProcAddress: no symbol %s\n", symbol);
+ return NULL;
+ }
+
+ return u.ptr;
+}
+
+
+/**
+ * Close a DLL
+ *
+ * @param h DLL Handle
+ */
+void _mod_close(void *h)
+{
+ HINSTANCE DllHandle = (HINSTANCE)h;
+
+ DEBUG_INFO("unloading %p\n", h);
+
+ if (!DllHandle)
+ return;
+
+ FreeLibrary(DllHandle);
+}