866 lines
28 KiB
C
866 lines
28 KiB
C
/*
|
|
* 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);
|