diff options
Diffstat (limited to 'src/mod_table.c')
-rw-r--r-- | src/mod_table.c | 865 |
1 files changed, 865 insertions, 0 deletions
diff --git a/src/mod_table.c b/src/mod_table.c new file mode 100644 index 0000000..7c92d84 --- /dev/null +++ b/src/mod_table.c @@ -0,0 +1,865 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef FARF_ERROR +#define FARF_ERROR 1 +#endif + +#include <assert.h> +#include "verify.h" +#include "HAP_farf.h" +#include "HAP_pls.h" +#include "mutex.h" +#include "mod_table.h" +#include "platform_libs.h" +#include "remote64.h" +#include "uthash.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "sbuf_parser.h" + +#include <dlfcn.h> + +#define DLOPEN dlopen +#define DLCLOSE dlclose +#define DLSYM dlsym +#define DLERROR dlerror + +/** + * structure for the mod table + * + * you need to define a rw_mutex type and its read/write lock/unlock api's + * which are under the RW_MUTEX namespace. + * + * this library defines 2 functions for opening modules, open_static and + * open_dynamic. Both return a handle that should be closed via close. + * + * you can also register a const handle, an invoke function for a known handle + * value. since handle keys are allocated, you should pick handle values that are + * not going to be returned by malloc (0, or odd). + */ +struct static_mod_table { + RW_MUTEX_T mut; + struct static_mod* staticModOverrides; + struct static_mod* staticMods; + struct const_mod* constMods; + boolean bInit; +}; + +struct open_mod_table { + RW_MUTEX_T mut; + struct open_mod* openMods; + struct static_mod_table* smt; +}; + +typedef int (*invoke_fn)(uint32, remote_arg*); +typedef int (*handle_invoke_fn)(remote_handle64, uint32, remote_arg*); +struct static_mod { + invoke_fn invoke; + handle_invoke_fn handle_invoke; + UT_hash_handle hh; + char uri[1]; +}; + +struct const_mod { + invoke_fn invoke; + handle_invoke_fn handle_invoke; + uint32 key; + remote_handle64 h64; + UT_hash_handle hh; + char uri[1]; +}; + +struct parsed_uri { + const char *file; + int filelen; + const char *sym; + int symlen; + const char *ver; + int verlen; +}; + +struct open_mod { + void* dlhandle; + invoke_fn invoke; + handle_invoke_fn handle_invoke; + uint64 key; + UT_hash_handle hh; + remote_handle64 h64; + int refs; + struct parsed_uri vals; + char uri[1]; +}; + +static int static_mod_table_ctor(struct static_mod_table* me) { + if(me->bInit == 0) { + RW_MUTEX_CTOR(me->mut); + me->staticMods = 0; + me->staticModOverrides = 0; + me->bInit = 1; + } + return 0; +} + +static void static_mod_table_dtor_imp(struct static_mod_table* me) { + struct static_mod *sm, *stmp; + struct const_mod *dm, *ftmp; + if(me->bInit != 0) { + if( me->staticMods || me->constMods || me->staticModOverrides) { + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ITER(hh, me->staticMods, sm, stmp) { + if(me->staticMods) { + HASH_DEL(me->staticMods,sm); + } + free(sm); + sm = NULL; + } + HASH_ITER(hh, me->staticModOverrides, sm, stmp) { + if(me->staticModOverrides) { + HASH_DEL(me->staticModOverrides,sm); + } + free(sm); + sm = NULL; + } + HASH_ITER(hh, me->constMods, dm, ftmp) { + if(me->constMods) { + HASH_DEL(me->constMods,dm); + } + free(dm); + dm = NULL; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + RW_MUTEX_DTOR(me->mut); + me->staticMods = 0; + me->staticModOverrides = 0; + me->bInit = 0; + } +} + +static int open_mod_table_ctor_imp(void* ctx, void* data) { + struct open_mod_table* me = (struct open_mod_table*)data; + RW_MUTEX_CTOR(me->mut); + me->openMods = 0; + me->smt = (struct static_mod_table*) ctx; + return 0; +} + +static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h); + +static void open_mod_table_dtor_imp(void* data) { + struct open_mod_table* me = (struct open_mod_table*)data; + struct open_mod *dm, *ftmp; + if( me->openMods) { + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ITER(hh, me->openMods, dm, ftmp) { + if(me->openMods) { + HASH_DEL(me->openMods,dm); + } + if(dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + free(dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + RW_MUTEX_DTOR(me->mut); + me->openMods = 0; +} +static int open_mod_table_open_from_static(struct open_mod_table* me, + struct static_mod** tbl, + const char* uri, + remote_handle* handle); + +static int open_mod_table_open_static_override(struct open_mod_table* me, const char* uri, remote_handle* handle) { + FARF(HIGH, "open_mod_table_open_static_override"); + return open_mod_table_open_from_static(me, &me->smt->staticModOverrides, uri, handle); +} + + +static int open_mod_table_open_static(struct open_mod_table* me, const char* uri, remote_handle* handle) { + FARF(HIGH, "open_mod_table_open_static"); + return open_mod_table_open_from_static(me, &me->smt->staticMods, uri, handle); +} + +static int static_mod_add(struct static_mod_table* me, struct static_mod** tbl, const char* uri, + int(*invoke)(uint32 sc, remote_arg* pra), + int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra)) { + int nErr = AEE_SUCCESS; + struct static_mod *sm = 0; + int len = std_strlen(uri) + 1; + VERIFYC(NULL != (sm = ((struct static_mod*)calloc(1, sizeof(struct static_mod) + len))), AEE_ENOMEMORY); + std_strlcpy(sm->uri, uri, len); + sm->invoke = invoke; + sm->handle_invoke = handle_invoke; + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ADD_STR(*tbl, uri, sm); + RW_MUTEX_UNLOCK_WRITE(me->mut); +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: static module addition failed\n", nErr); + if(sm) { + free(sm); + sm = NULL; + } + } + return nErr; +} + +static int static_mod_table_register_static_override(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticModOverrides, uri, pfn, 0); +} +static int static_mod_table_register_static_override1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticModOverrides, uri, 0, pfn); +} +static int static_mod_table_register_static(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticMods, uri, pfn, 0); +} +static int static_mod_table_register_static1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64,uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticMods, uri, 0, pfn); +} + + +static int static_mod_table_register_const_handle(struct static_mod_table* me, remote_handle local, + remote_handle64 remote, const char* uri, + int(*invoke)(uint32 sc, remote_arg* pra), + int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra) + ) { + int nErr = AEE_SUCCESS; + int len = std_strlen(uri) + 1; + struct const_mod *dm = 0, *dmOld; + VERIFYC(NULL != (dm = ((struct const_mod*)calloc(1, sizeof(struct open_mod) + len))), AEE_ENOMEMORY); + dm->key = local; + dm->invoke = invoke; + dm->handle_invoke = handle_invoke; + dm->h64 = remote; + std_strlcpy(dm->uri, uri, len); + + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->constMods, &local, dmOld); + if(dmOld == 0) { + HASH_ADD_INT(me->constMods, key, dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + nErr = dmOld != 0 ? -1 : nErr; +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: failed to register const handle in modtable\n", nErr); + if(dm) { + free(dm); + dm = NULL; + } + } + return nErr; +} + +static int open_mod_handle_open(struct open_mod *mod, const char* name, + remote_handle64 *ph) { + int nErr = AEE_SUCCESS; + remote_arg args[3]; + int32_t len = strlen(name) + 1; + args[0].buf.pv = &len; + args[0].buf.nLen = sizeof(len); + args[1].buf.pv = (void*)name; + args[1].buf.nLen = len; + nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,0,2,0,0,1),args); + if(!nErr) { + *ph = args[2].h64; + } + FARF(HIGH, "allocated %x", *ph); + return nErr; +} + +static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h) { + int nErr; + remote_arg args[1]; + args[0].h64 = h; + FARF(HIGH, "releasing %x", h); + nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,1,0,0,1,0),args); + return nErr; +} + +static int notqmark(struct sbuf *buf) { + return sbuf_notchar(buf, '?'); +} +static int notandoreq(struct sbuf *buf) { + return sbuf_notchars(buf, "&="); +} +static int notand(struct sbuf *buf) { + return sbuf_notchar(buf, '&'); +} + +static int parse_uri(const char *uri, int urilen, struct parsed_uri *out) { +// "file:///librhtest_skel.so?rhtest_skel_handle_invoke&_modver=1.0" + int nErr = 0; + char *name, *value; + int nameLen, valueLen; + struct sbuf buf; + FARF(HIGH, "parse_uri %s %d", uri, urilen); + memset(out, 0, sizeof(*out)); + //initialize + sbuf_parser_init(&buf, uri, urilen); + + //parse until question mark + VERIFYC(sbuf_string(&buf, "file://"), AEE_EINVALIDFORMAT); + + //ignore the starting / + (void)sbuf_string(&buf, "/"); + + out->file = sbuf_cur(&buf); + VERIFY(sbuf_many1(&buf, notqmark)); + out->filelen = sbuf_cur(&buf) - out->file; + FARF(HIGH, "file:%.*s %d", out->filelen, out->file, out->filelen); + VERIFY(sbuf_char(&buf, '?')); + out->sym = sbuf_cur(&buf); + VERIFY(sbuf_many1(&buf, notand)); + out->symlen = sbuf_cur(&buf) - out->sym; + assert(out->sym + out->symlen <= uri + urilen); + FARF(HIGH, "sym:%.*s %d", out->symlen, out->sym, out->symlen); + + if(!sbuf_end(&buf) && sbuf_char(&buf, '&')) { + //parse each query + while(!sbuf_end(&buf)) { + //record where the name starts + name = sbuf_cur(&buf); + + //name is valid until '=' or '&' + VERIFY(sbuf_many1(&buf, notandoreq)); + nameLen = sbuf_cur(&buf) - name; + + value = 0; + valueLen = 0; + //if the next char is a '=' then we also get a value + if(sbuf_char(&buf, '=')) { + value = sbuf_cur(&buf); + + //value is until the next query that starts with '&' + VERIFY(sbuf_many1(&buf, notand)); + valueLen = sbuf_cur(&buf) - value; + } + //expect '&' or end + sbuf_char(&buf, '&'); + if(!std_strncmp(name, "_modver", nameLen)) { + out->ver = value; + out->verlen = valueLen; + } + } + } +bail: + if(out->filelen) { + FARF(HIGH, "parse_uri file: %.*s", out->filelen, out->file); + } + if(out->symlen) { + FARF(HIGH, "parse_uri sym: %.*s", out->symlen, out->sym); + } + if(out->verlen) { + FARF(HIGH, "parse_uri version: %.*s", out->verlen, out->ver); + } + FARF(HIGH, "parse_uri done: %s %d err:%x", uri, urilen, nErr); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: parseuri failed for uri %s, urilen %d\n", nErr, uri, urilen); + } + return nErr; +} + +static int open_mod_table_open_dynamic(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlStr, int dlerrorLen, int* pdlErr) +{ + int nErr = AEE_SUCCESS, dlErr = 0; + struct open_mod *dm = 0, *dmOld; + int len = strlen(uri); + int tmplen = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; + char *tmp = 0; + FARF(HIGH, "open_mod_table_open_dynamic"); + VERIFYC(NULL != (tmp = calloc(1, tmplen)), AEE_ENOMEMORY); + VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(struct open_mod) + len + 1))), AEE_ENOMEMORY); + std_memmove(dm->uri, uri, len + 1); + FARF(HIGH, "calling parse_uri"); + (void)parse_uri(dm->uri, len, &dm->vals); + FARF(HIGH, "done calling parse_uri"); + FARF(HIGH, "vals %d %d %d", dm->vals.filelen, dm->vals.symlen, dm->vals.verlen); + if(dm->vals.filelen) { + int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.filelen, dm->vals.file); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } else { + int rv; + rv = std_snprintf(tmp, tmplen, "lib%s_skel.so", uri); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } + FARF(HIGH, "calling dlopen for %s", tmp); + dm->dlhandle = DLOPEN(tmp,RTLD_NOW); + FARF(HIGH, "got %p for dlopen %s", dm->dlhandle, tmp); + VERIFY(!(nErr = (dlErr = dm->dlhandle == 0 ? -5 : 0))); + + if(dm->vals.symlen) { + int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.symlen, dm->vals.sym); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } else { + int rv = std_snprintf(tmp, tmplen, "%s_skel_invoke", uri); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } + + FARF(HIGH, "calling dlsym for %s", tmp); + if(dm->vals.verlen && 0 == std_strncmp(dm->vals.ver, "1.0", dm->vals.verlen)) { + dm->handle_invoke = (handle_invoke_fn) DLSYM(dm->dlhandle, tmp); + } else { + dm->invoke = (invoke_fn) DLSYM(dm->dlhandle, tmp); + } + FARF(HIGH, "dlsym returned %p %p", dm->invoke, dm->handle_invoke); + VERIFYC(!(dlErr = dm->invoke || dm->handle_invoke ? 0 : AEE_ENOSUCHSYMBOL), AEE_ENOSUCHSYMBOL); + + dm->key = (uint32)(uintptr_t)dm; + dm->refs = 1; + if(dm->handle_invoke) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); + } + RW_MUTEX_LOCK_WRITE(me->mut); + do { + HASH_FIND_INT(me->openMods, &dm->key, dmOld); + if(dmOld) { + dm->key++; + } + } while(dmOld); + RW_MUTEX_LOCK_WRITE(me->smt->mut); + HASH_FIND_INT(me->smt->constMods, &dm->key, dmOld); + RW_MUTEX_UNLOCK_WRITE(me->smt->mut); + if(dmOld == 0) { + HASH_ADD_INT(me->openMods, key, dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + nErr = dmOld != 0 ? -1 : nErr; + if(nErr == 0) { + *handle = dm->key; + } +bail: + if (nErr != AEE_SUCCESS) { + if(dlErr) { + const char* dlerr = DLERROR(); + if(dlerr != 0){ + std_strlcpy(dlStr,dlerr,dlerrorLen); + } + FARF(HIGH, "dlerror:%x:%s", dlErr, dlerr == 0 ? "" : dlerr); + nErr = 0; + } + if(pdlErr) { + *pdlErr = dlErr; + } + if(dm && dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(dm && dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + if(dm) { + free(dm); + dm = NULL; + } + VERIFY_EPRINTF("Error %x: open modtable dynamic failed. dlerr %x\n", nErr, dlErr); + } + FARF(HIGH, "done open_mod_table_open_dynamic for %s rv %x handle: %p %x", uri, nErr, *handle, dlErr); + if(tmp) { + free(tmp); + tmp = NULL; + } + return nErr; +} + +static int open_mod_table_open_from_static(struct open_mod_table* me, + struct static_mod** tbl, + const char* uri, + remote_handle* handle) +{ + int nErr = AEE_SUCCESS; + struct static_mod *sm = 0; + struct open_mod *dm = 0, *dmOld = 0; + int len = std_strlen(uri); + int sz = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; + char *tmp = 0; + VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(*dm) + sz))), AEE_ENOMEMORY); + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_STR(*tbl, uri, sm); + RW_MUTEX_UNLOCK_READ(me->mut); + std_memmove(dm->uri, uri, len); + if(sm == 0) { + VERIFY(AEE_SUCCESS == (nErr = parse_uri(uri, len, &dm->vals))); + FARF(HIGH, "file %.*s %d", dm->vals.filelen, dm->vals.file, dm->vals.filelen); + FARF(HIGH, "sym %.*s %d", dm->vals.symlen, dm->vals.sym, dm->vals.symlen); + FARF(HIGH, "version %.*s %d", dm->vals.verlen, dm->vals.ver, dm->vals.verlen); + if(dm->vals.verlen) { + int rv = std_snprintf(dm->uri, sz, "file:///%.*s?%.*s&_modver=%.*s", + dm->vals.filelen, dm->vals.file, + dm->vals.symlen, dm->vals.sym, + dm->vals.verlen, dm->vals.ver); + VERIFYC(sz >= rv, AEE_EBADSIZE); + } else { + int rv = std_snprintf(dm->uri, sz, "file://%.*s?%.*s", + dm->vals.filelen, dm->vals.file, + dm->vals.symlen, dm->vals.sym); + VERIFYC(sz >= rv, AEE_EBADSIZE); + } + FARF(HIGH, "dm->uri:%s", dm->uri); + + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_STR(*tbl, dm->uri, sm); + RW_MUTEX_UNLOCK_READ(me->mut); + } + VERIFYC(0 != sm, AEE_ENOTINITIALIZED); + assert(sm->handle_invoke || sm->invoke); + dm->handle_invoke = sm->handle_invoke; + dm->invoke = sm->invoke; + dm->key = (uint32)(uintptr_t)dm; + dm->refs = 1; + if(dm->handle_invoke) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); + } + + RW_MUTEX_LOCK_WRITE(me->mut); + do { + HASH_FIND_INT(me->openMods, &dm->key, dmOld); + if(dmOld) { + dm->key++; + } + } while(dmOld); + HASH_ADD_INT(me->openMods, key, dm); + RW_MUTEX_UNLOCK_WRITE(me->mut); + + *handle = dm->key; +bail: + if(tmp) { + free(tmp); + tmp = NULL; + } + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable open from static failed.\n", nErr); + } + if(nErr && dm) { + if(dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + free(dm); + dm = NULL; + } + return nErr; +} + +static int open_mod_table_open(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) +{ + int nErr = AEE_SUCCESS, dlErr = 0; + if(pdlErr) { + *pdlErr = 0; + } + if(0 != open_mod_table_open_static_override(me, uri, handle)) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open_dynamic(me, uri, handle, dlerr, dlerrorLen, &dlErr))); + if(dlErr != 0) { + FARF(HIGH, "dynammic open failed, trying static"); + if(0 != open_mod_table_open_static(me, uri, handle)) { + if(pdlErr) { + *pdlErr = dlErr; + } + } + } + } +bail: + FARF(HIGH, "done open for %s rv %d handle: %p", uri, nErr, *handle); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: open modtable failed\n", nErr); + } + return nErr; +} + +static void open_mod_close(struct open_mod_table *me, struct open_mod* dm) { + RW_MUTEX_LOCK_WRITE(me->mut); + dm->refs--; + if(dm->refs <= 0) { + HASH_DEL(me->openMods,dm); + } else { + dm = 0; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + if(dm) { + if(dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + free(dm); + dm = NULL; + } +} +static int open_mod_table_close(struct open_mod_table* me, remote_handle64 handle, char* errStr, int errStrLen, int* pdlErr) +{ + int nErr = AEE_SUCCESS; + struct open_mod *dm, *del = 0;; + int dlErr = 0; + // First ensure that the handle is valid + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->openMods, &handle, dm); + if(dm) { + dm->refs--; + if(dm->refs <= 0) { + del = dm; + FARF(HIGH, "deleting %s %p", del->uri, del); + HASH_DEL(me->openMods,dm); + } else { + FARF(HIGH, "leaked %s", dm->uri); + dm = 0; + } + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + if(del) { + if(del->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(del->dlhandle) { + dlErr = DLCLOSE(del->dlhandle); + } + FARF(HIGH, "free %s %p", del->uri, del); + free(del); + del = NULL; + } + VERIFY(del); + +bail: + if(dlErr) { + const char* error = DLERROR(); + nErr = dlErr; + if(error != 0){ + std_strlcpy(errStr,error,errStrLen); + } + VERIFY_EPRINTF("Error %x: open modtable close failed. dlerr %s\n", nErr, error); + } + if(pdlErr) { + *pdlErr = dlErr; + } + return nErr; +} + +static struct open_mod* open_mod_table_get_open(struct open_mod_table* me, remote_handle handle) { + struct open_mod* om = 0; + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_INT(me->openMods, &handle, om); + if(0 != om) { + om->refs++; + } + RW_MUTEX_UNLOCK_READ(me->mut); + return om; +} +static struct const_mod* open_mod_table_get_const(struct open_mod_table* me, remote_handle handle) { + struct const_mod* cm = 0; + RW_MUTEX_LOCK_READ(me->smt->mut); + HASH_FIND_INT(me->smt->constMods, &handle, cm); + RW_MUTEX_UNLOCK_READ(me->smt->mut); + return cm; +} + +static int open_mod_table_handle_invoke(struct open_mod_table* me, remote_handle handle, uint32 sc, remote_arg* pra) { + int nErr = AEE_SUCCESS; + struct open_mod* om = 0; + struct const_mod* cm = 0; + remote_handle64 h = 0; + invoke_fn invoke = 0; + handle_invoke_fn handle_invoke = 0; + cm = open_mod_table_get_const(me, handle); + if(cm) { + invoke = cm->invoke; + handle_invoke = cm->handle_invoke; + h = cm->h64; + } else { + VERIFYC(0 != (om = open_mod_table_get_open(me, handle)), AEE_ENOSUCHMOD); + invoke = om->invoke; + handle_invoke = om->handle_invoke; + h = om->h64; + } + if(invoke) { + VERIFY(AEE_SUCCESS == (nErr = invoke(sc, pra))); + } else { + VERIFY(AEE_SUCCESS == (nErr = handle_invoke(h, sc, pra))); + } +bail: + if(om) { + open_mod_close(me, om); + } + FARF(HIGH, "invoke rv %p %x %x", handle, sc, nErr); + return nErr; +} + +struct mod_table { + struct static_mod_table smt; + struct open_mod_table omt; +}; + +// mod_table object +static struct static_mod_table static_mod_table_obj; + + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * overrides will be tried first, then dynamic modules, then regular + * static modules. + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static_override(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static_override(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + +int mod_table_register_static_override1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static_override1(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + +int mod_table_register_static1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static1(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + + +/** + * Open a module and get a handle to it + * + * uri, name of module to open + * handle, Output handle + * dlerr, Error String (if an error occurs) + * dlerrorLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_open(const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod_table* pomt = 0; + FARF(HIGH, "mod_table_open for %s", uri); + VERIFY(AEE_SUCCESS == (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, sizeof(*pomt), open_mod_table_ctor_imp, (void*)&static_mod_table_obj, open_mod_table_dtor_imp, (void**)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open(pomt,uri,handle,dlerr,dlerrorLen,pdlErr))); +bail: + FARF(HIGH, "mod_table_open for %s nErr: %x", uri, nErr); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable open failed\n", nErr); + } + return nErr; +} +/** + * invoke a handle in the mod table + * + * handle, handle to invoke + * sc, scalars, see remote.h for documentation. + * pra, args, see remote.h for documentation. + */ +int mod_table_invoke(remote_handle handle, uint32 sc, remote_arg* pra) { + int nErr = AEE_SUCCESS; + struct open_mod_table* pomt = 0; + VERIFY(AEE_SUCCESS == (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, sizeof(*pomt), open_mod_table_ctor_imp, (void*)&static_mod_table_obj, open_mod_table_dtor_imp, (void**)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_handle_invoke(pomt, handle, sc, pra))); +bail: + return nErr; +} + +/** + * Closes a handle in the mod table + * + * handle, handle to close + * errStr, Error String (if an error occurs) + * errStrLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_close(remote_handle handle, char* errStr, int errStrLen, int* pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod_table* pomt = 0; + VERIFY(AEE_SUCCESS == (nErr = HAP_pls_lookup((uintptr_t)open_mod_table_ctor_imp, 0, (void**)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_close(pomt, handle, errStr,errStrLen,pdlErr))); +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable close failed\n", nErr); + } + return nErr; +} + +/** + * internal use only + */ +int mod_table_register_const_handle(remote_handle remote, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_const_handle(&static_mod_table_obj, remote, 0, uri, pfn, 0); + } + return AEE_EUNKNOWN; +} +int mod_table_register_const_handle1(remote_handle remote, remote_handle64 local, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_const_handle(&static_mod_table_obj, remote, local, uri, 0, pfn); + } + return AEE_EUNKNOWN; +} + +// Constructor and destructor +static int mod_table_ctor(void) { + return static_mod_table_ctor(&static_mod_table_obj); +} +static void mod_table_dtor(void) { + static_mod_table_dtor_imp(&static_mod_table_obj); + return; +} + +PL_DEFINE(mod_table, mod_table_ctor, mod_table_dtor); |