1 /*
2 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef FARF_ERROR
30 #define FARF_ERROR 1
31 #endif
32
33 #include <assert.h>
34 #include "verify.h"
35 #include "HAP_farf.h"
36 #include "HAP_pls.h"
37 #include "mutex.h"
38 #include "mod_table.h"
39 #include "platform_libs.h"
40 #include "remote64.h"
41 #include "uthash.h"
42 #include "AEEstd.h"
43 #include "AEEStdErr.h"
44 #include "sbuf_parser.h"
45
46 #include <dlfcn.h>
47
48 #define DLOPEN dlopen
49 #define DLCLOSE dlclose
50 #define DLSYM dlsym
51 #define DLERROR dlerror
52
53 /**
54 * structure for the mod table
55 *
56 * you need to define a rw_mutex type and its read/write lock/unlock api's
57 * which are under the RW_MUTEX namespace.
58 *
59 * this library defines 2 functions for opening modules, open_static and
60 * open_dynamic. Both return a handle that should be closed via close.
61 *
62 * you can also register a const handle, an invoke function for a known handle
63 * value. since handle keys are allocated, you should pick handle values that are
64 * not going to be returned by malloc (0, or odd).
65 */
66 struct static_mod_table {
67 RW_MUTEX_T mut;
68 struct static_mod* staticModOverrides;
69 struct static_mod* staticMods;
70 struct const_mod* constMods;
71 boolean bInit;
72 };
73
74 struct open_mod_table {
75 RW_MUTEX_T mut;
76 struct open_mod* openMods;
77 struct static_mod_table* smt;
78 };
79
80 typedef int (*invoke_fn)(uint32, remote_arg*);
81 typedef int (*handle_invoke_fn)(remote_handle64, uint32, remote_arg*);
82 struct static_mod {
83 invoke_fn invoke;
84 handle_invoke_fn handle_invoke;
85 UT_hash_handle hh;
86 char uri[1];
87 };
88
89 struct const_mod {
90 invoke_fn invoke;
91 handle_invoke_fn handle_invoke;
92 uint32 key;
93 remote_handle64 h64;
94 UT_hash_handle hh;
95 char uri[1];
96 };
97
98 struct parsed_uri {
99 const char *file;
100 int filelen;
101 const char *sym;
102 int symlen;
103 const char *ver;
104 int verlen;
105 };
106
107 struct open_mod {
108 void* dlhandle;
109 invoke_fn invoke;
110 handle_invoke_fn handle_invoke;
111 uint64 key;
112 UT_hash_handle hh;
113 remote_handle64 h64;
114 int refs;
115 struct parsed_uri vals;
116 char uri[1];
117 };
118
static_mod_table_ctor(struct static_mod_table * me)119 static int static_mod_table_ctor(struct static_mod_table* me) {
120 if(me->bInit == 0) {
121 RW_MUTEX_CTOR(me->mut);
122 me->staticMods = 0;
123 me->staticModOverrides = 0;
124 me->bInit = 1;
125 }
126 return 0;
127 }
128
static_mod_table_dtor_imp(struct static_mod_table * me)129 static void static_mod_table_dtor_imp(struct static_mod_table* me) {
130 struct static_mod *sm, *stmp;
131 struct const_mod *dm, *ftmp;
132 if(me->bInit != 0) {
133 if( me->staticMods || me->constMods || me->staticModOverrides) {
134 RW_MUTEX_LOCK_WRITE(me->mut);
135 HASH_ITER(hh, me->staticMods, sm, stmp) {
136 if(me->staticMods) {
137 HASH_DEL(me->staticMods,sm);
138 }
139 free(sm);
140 sm = NULL;
141 }
142 HASH_ITER(hh, me->staticModOverrides, sm, stmp) {
143 if(me->staticModOverrides) {
144 HASH_DEL(me->staticModOverrides,sm);
145 }
146 free(sm);
147 sm = NULL;
148 }
149 HASH_ITER(hh, me->constMods, dm, ftmp) {
150 if(me->constMods) {
151 HASH_DEL(me->constMods,dm);
152 }
153 free(dm);
154 dm = NULL;
155 }
156 RW_MUTEX_UNLOCK_WRITE(me->mut);
157 }
158 RW_MUTEX_DTOR(me->mut);
159 me->staticMods = 0;
160 me->staticModOverrides = 0;
161 me->bInit = 0;
162 }
163 }
164
open_mod_table_ctor_imp(void * ctx,void * data)165 static int open_mod_table_ctor_imp(void* ctx, void* data) {
166 struct open_mod_table* me = (struct open_mod_table*)data;
167 RW_MUTEX_CTOR(me->mut);
168 me->openMods = 0;
169 me->smt = (struct static_mod_table*) ctx;
170 return 0;
171 }
172
173 static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h);
174
open_mod_table_dtor_imp(void * data)175 static void open_mod_table_dtor_imp(void* data) {
176 struct open_mod_table* me = (struct open_mod_table*)data;
177 struct open_mod *dm, *ftmp;
178 if( me->openMods) {
179 RW_MUTEX_LOCK_WRITE(me->mut);
180 HASH_ITER(hh, me->openMods, dm, ftmp) {
181 if(me->openMods) {
182 HASH_DEL(me->openMods,dm);
183 }
184 if(dm->h64) {
185 (void)open_mod_handle_close(dm, dm->h64);
186 }
187 if(dm->dlhandle) {
188 DLCLOSE(dm->dlhandle);
189 }
190 free(dm);
191 }
192 RW_MUTEX_UNLOCK_WRITE(me->mut);
193 }
194 RW_MUTEX_DTOR(me->mut);
195 me->openMods = 0;
196 }
197 static int open_mod_table_open_from_static(struct open_mod_table* me,
198 struct static_mod** tbl,
199 const char* uri,
200 remote_handle* handle);
201
open_mod_table_open_static_override(struct open_mod_table * me,const char * uri,remote_handle * handle)202 static int open_mod_table_open_static_override(struct open_mod_table* me, const char* uri, remote_handle* handle) {
203 FARF(HIGH, "open_mod_table_open_static_override");
204 return open_mod_table_open_from_static(me, &me->smt->staticModOverrides, uri, handle);
205 }
206
207
open_mod_table_open_static(struct open_mod_table * me,const char * uri,remote_handle * handle)208 static int open_mod_table_open_static(struct open_mod_table* me, const char* uri, remote_handle* handle) {
209 FARF(HIGH, "open_mod_table_open_static");
210 return open_mod_table_open_from_static(me, &me->smt->staticMods, uri, handle);
211 }
212
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))213 static int static_mod_add(struct static_mod_table* me, struct static_mod** tbl, const char* uri,
214 int(*invoke)(uint32 sc, remote_arg* pra),
215 int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra)) {
216 int nErr = AEE_SUCCESS;
217 struct static_mod *sm = 0;
218 int len = std_strlen(uri) + 1;
219 VERIFYC(NULL != (sm = ((struct static_mod*)calloc(1, sizeof(struct static_mod) + len))), AEE_ENOMEMORY);
220 std_strlcpy(sm->uri, uri, len);
221 sm->invoke = invoke;
222 sm->handle_invoke = handle_invoke;
223 RW_MUTEX_LOCK_WRITE(me->mut);
224 HASH_ADD_STR(*tbl, uri, sm);
225 RW_MUTEX_UNLOCK_WRITE(me->mut);
226 bail:
227 if(nErr != AEE_SUCCESS) {
228 VERIFY_EPRINTF("Error %x: static module addition failed\n", nErr);
229 if(sm) {
230 free(sm);
231 sm = NULL;
232 }
233 }
234 return nErr;
235 }
236
static_mod_table_register_static_override(struct static_mod_table * me,const char * uri,int (* pfn)(uint32 sc,remote_arg * pra))237 static int static_mod_table_register_static_override(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) {
238 return static_mod_add(me, &me->staticModOverrides, uri, pfn, 0);
239 }
static_mod_table_register_static_override1(struct static_mod_table * me,const char * uri,int (* pfn)(remote_handle64,uint32 sc,remote_arg * pra))240 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)) {
241 return static_mod_add(me, &me->staticModOverrides, uri, 0, pfn);
242 }
static_mod_table_register_static(struct static_mod_table * me,const char * uri,int (* pfn)(uint32 sc,remote_arg * pra))243 static int static_mod_table_register_static(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) {
244 return static_mod_add(me, &me->staticMods, uri, pfn, 0);
245 }
static_mod_table_register_static1(struct static_mod_table * me,const char * uri,int (* pfn)(remote_handle64,uint32 sc,remote_arg * pra))246 static int static_mod_table_register_static1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64,uint32 sc, remote_arg* pra)) {
247 return static_mod_add(me, &me->staticMods, uri, 0, pfn);
248 }
249
250
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))251 static int static_mod_table_register_const_handle(struct static_mod_table* me, remote_handle local,
252 remote_handle64 remote, const char* uri,
253 int(*invoke)(uint32 sc, remote_arg* pra),
254 int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra)
255 ) {
256 int nErr = AEE_SUCCESS;
257 int len = std_strlen(uri) + 1;
258 struct const_mod *dm = 0, *dmOld;
259 VERIFYC(NULL != (dm = ((struct const_mod*)calloc(1, sizeof(struct open_mod) + len))), AEE_ENOMEMORY);
260 dm->key = local;
261 dm->invoke = invoke;
262 dm->handle_invoke = handle_invoke;
263 dm->h64 = remote;
264 std_strlcpy(dm->uri, uri, len);
265
266 RW_MUTEX_LOCK_WRITE(me->mut);
267 HASH_FIND_INT(me->constMods, &local, dmOld);
268 if(dmOld == 0) {
269 HASH_ADD_INT(me->constMods, key, dm);
270 }
271 RW_MUTEX_UNLOCK_WRITE(me->mut);
272 nErr = dmOld != 0 ? -1 : nErr;
273 bail:
274 if(nErr != AEE_SUCCESS) {
275 VERIFY_EPRINTF("Error %x: failed to register const handle in modtable\n", nErr);
276 if(dm) {
277 free(dm);
278 dm = NULL;
279 }
280 }
281 return nErr;
282 }
283
open_mod_handle_open(struct open_mod * mod,const char * name,remote_handle64 * ph)284 static int open_mod_handle_open(struct open_mod *mod, const char* name,
285 remote_handle64 *ph) {
286 int nErr = AEE_SUCCESS;
287 remote_arg args[3];
288 int32_t len = strlen(name) + 1;
289 args[0].buf.pv = &len;
290 args[0].buf.nLen = sizeof(len);
291 args[1].buf.pv = (void*)name;
292 args[1].buf.nLen = len;
293 nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,0,2,0,0,1),args);
294 if(!nErr) {
295 *ph = args[2].h64;
296 }
297 FARF(HIGH, "allocated %x", *ph);
298 return nErr;
299 }
300
open_mod_handle_close(struct open_mod * mod,remote_handle64 h)301 static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h) {
302 int nErr;
303 remote_arg args[1];
304 args[0].h64 = h;
305 FARF(HIGH, "releasing %x", h);
306 nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,1,0,0,1,0),args);
307 return nErr;
308 }
309
notqmark(struct sbuf * buf)310 static int notqmark(struct sbuf *buf) {
311 return sbuf_notchar(buf, '?');
312 }
notandoreq(struct sbuf * buf)313 static int notandoreq(struct sbuf *buf) {
314 return sbuf_notchars(buf, "&=");
315 }
notand(struct sbuf * buf)316 static int notand(struct sbuf *buf) {
317 return sbuf_notchar(buf, '&');
318 }
319
parse_uri(const char * uri,int urilen,struct parsed_uri * out)320 static int parse_uri(const char *uri, int urilen, struct parsed_uri *out) {
321 // "file:///librhtest_skel.so?rhtest_skel_handle_invoke&_modver=1.0"
322 int nErr = 0;
323 char *name, *value;
324 int nameLen, valueLen;
325 struct sbuf buf;
326 FARF(HIGH, "parse_uri %s %d", uri, urilen);
327 memset(out, 0, sizeof(*out));
328 //initialize
329 sbuf_parser_init(&buf, uri, urilen);
330
331 //parse until question mark
332 VERIFYC(sbuf_string(&buf, "file://"), AEE_EINVALIDFORMAT);
333
334 //ignore the starting /
335 (void)sbuf_string(&buf, "/");
336
337 out->file = sbuf_cur(&buf);
338 VERIFY(sbuf_many1(&buf, notqmark));
339 out->filelen = sbuf_cur(&buf) - out->file;
340 FARF(HIGH, "file:%.*s %d", out->filelen, out->file, out->filelen);
341 VERIFY(sbuf_char(&buf, '?'));
342 out->sym = sbuf_cur(&buf);
343 VERIFY(sbuf_many1(&buf, notand));
344 out->symlen = sbuf_cur(&buf) - out->sym;
345 assert(out->sym + out->symlen <= uri + urilen);
346 FARF(HIGH, "sym:%.*s %d", out->symlen, out->sym, out->symlen);
347
348 if(!sbuf_end(&buf) && sbuf_char(&buf, '&')) {
349 //parse each query
350 while(!sbuf_end(&buf)) {
351 //record where the name starts
352 name = sbuf_cur(&buf);
353
354 //name is valid until '=' or '&'
355 VERIFY(sbuf_many1(&buf, notandoreq));
356 nameLen = sbuf_cur(&buf) - name;
357
358 value = 0;
359 valueLen = 0;
360 //if the next char is a '=' then we also get a value
361 if(sbuf_char(&buf, '=')) {
362 value = sbuf_cur(&buf);
363
364 //value is until the next query that starts with '&'
365 VERIFY(sbuf_many1(&buf, notand));
366 valueLen = sbuf_cur(&buf) - value;
367 }
368 //expect '&' or end
369 sbuf_char(&buf, '&');
370 if(!std_strncmp(name, "_modver", nameLen)) {
371 out->ver = value;
372 out->verlen = valueLen;
373 }
374 }
375 }
376 bail:
377 if(out->filelen) {
378 FARF(HIGH, "parse_uri file: %.*s", out->filelen, out->file);
379 }
380 if(out->symlen) {
381 FARF(HIGH, "parse_uri sym: %.*s", out->symlen, out->sym);
382 }
383 if(out->verlen) {
384 FARF(HIGH, "parse_uri version: %.*s", out->verlen, out->ver);
385 }
386 FARF(HIGH, "parse_uri done: %s %d err:%x", uri, urilen, nErr);
387 if(nErr != AEE_SUCCESS) {
388 VERIFY_EPRINTF("Error %x: parseuri failed for uri %s, urilen %d\n", nErr, uri, urilen);
389 }
390 return nErr;
391 }
392
open_mod_table_open_dynamic(struct open_mod_table * me,const char * uri,remote_handle * handle,char * dlStr,int dlerrorLen,int * pdlErr)393 static int open_mod_table_open_dynamic(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlStr, int dlerrorLen, int* pdlErr)
394 {
395 int nErr = AEE_SUCCESS, dlErr = 0;
396 struct open_mod *dm = 0, *dmOld;
397 int len = strlen(uri);
398 int tmplen = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1;
399 char *tmp = 0;
400 FARF(HIGH, "open_mod_table_open_dynamic");
401 VERIFYC(NULL != (tmp = calloc(1, tmplen)), AEE_ENOMEMORY);
402 VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(struct open_mod) + len + 1))), AEE_ENOMEMORY);
403 std_memmove(dm->uri, uri, len + 1);
404 FARF(HIGH, "calling parse_uri");
405 (void)parse_uri(dm->uri, len, &dm->vals);
406 FARF(HIGH, "done calling parse_uri");
407 FARF(HIGH, "vals %d %d %d", dm->vals.filelen, dm->vals.symlen, dm->vals.verlen);
408 if(dm->vals.filelen) {
409 int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.filelen, dm->vals.file);
410 VERIFYC(tmplen >= rv, AEE_EBADSIZE);
411 } else {
412 int rv;
413 rv = std_snprintf(tmp, tmplen, "lib%s_skel.so", uri);
414 VERIFYC(tmplen >= rv, AEE_EBADSIZE);
415 }
416 FARF(HIGH, "calling dlopen for %s", tmp);
417 dm->dlhandle = DLOPEN(tmp,RTLD_NOW);
418 FARF(HIGH, "got %p for dlopen %s", dm->dlhandle, tmp);
419 VERIFY(!(nErr = (dlErr = dm->dlhandle == 0 ? -5 : 0)));
420
421 if(dm->vals.symlen) {
422 int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.symlen, dm->vals.sym);
423 VERIFYC(tmplen >= rv, AEE_EBADSIZE);
424 } else {
425 int rv = std_snprintf(tmp, tmplen, "%s_skel_invoke", uri);
426 VERIFYC(tmplen >= rv, AEE_EBADSIZE);
427 }
428
429 FARF(HIGH, "calling dlsym for %s", tmp);
430 if(dm->vals.verlen && 0 == std_strncmp(dm->vals.ver, "1.0", dm->vals.verlen)) {
431 dm->handle_invoke = (handle_invoke_fn) DLSYM(dm->dlhandle, tmp);
432 } else {
433 dm->invoke = (invoke_fn) DLSYM(dm->dlhandle, tmp);
434 }
435 FARF(HIGH, "dlsym returned %p %p", dm->invoke, dm->handle_invoke);
436 VERIFYC(!(dlErr = dm->invoke || dm->handle_invoke ? 0 : AEE_ENOSUCHSYMBOL), AEE_ENOSUCHSYMBOL);
437
438 dm->key = (uint32)(uintptr_t)dm;
439 dm->refs = 1;
440 if(dm->handle_invoke) {
441 VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64)));
442 }
443 RW_MUTEX_LOCK_WRITE(me->mut);
444 do {
445 HASH_FIND_INT(me->openMods, &dm->key, dmOld);
446 if(dmOld) {
447 dm->key++;
448 }
449 } while(dmOld);
450 RW_MUTEX_LOCK_WRITE(me->smt->mut);
451 HASH_FIND_INT(me->smt->constMods, &dm->key, dmOld);
452 RW_MUTEX_UNLOCK_WRITE(me->smt->mut);
453 if(dmOld == 0) {
454 HASH_ADD_INT(me->openMods, key, dm);
455 }
456 RW_MUTEX_UNLOCK_WRITE(me->mut);
457 nErr = dmOld != 0 ? -1 : nErr;
458 if(nErr == 0) {
459 *handle = dm->key;
460 }
461 bail:
462 if (nErr != AEE_SUCCESS) {
463 if(dlErr) {
464 const char* dlerr = DLERROR();
465 if(dlerr != 0){
466 std_strlcpy(dlStr,dlerr,dlerrorLen);
467 }
468 FARF(HIGH, "dlerror:%x:%s", dlErr, dlerr == 0 ? "" : dlerr);
469 nErr = 0;
470 }
471 if(pdlErr) {
472 *pdlErr = dlErr;
473 }
474 if(dm && dm->h64) {
475 (void)open_mod_handle_close(dm, dm->h64);
476 }
477 if(dm && dm->dlhandle) {
478 DLCLOSE(dm->dlhandle);
479 }
480 if(dm) {
481 free(dm);
482 dm = NULL;
483 }
484 VERIFY_EPRINTF("Error %x: open modtable dynamic failed. dlerr %x\n", nErr, dlErr);
485 }
486 FARF(HIGH, "done open_mod_table_open_dynamic for %s rv %x handle: %p %x", uri, nErr, *handle, dlErr);
487 if(tmp) {
488 free(tmp);
489 tmp = NULL;
490 }
491 return nErr;
492 }
493
open_mod_table_open_from_static(struct open_mod_table * me,struct static_mod ** tbl,const char * uri,remote_handle * handle)494 static int open_mod_table_open_from_static(struct open_mod_table* me,
495 struct static_mod** tbl,
496 const char* uri,
497 remote_handle* handle)
498 {
499 int nErr = AEE_SUCCESS;
500 struct static_mod *sm = 0;
501 struct open_mod *dm = 0, *dmOld = 0;
502 int len = std_strlen(uri);
503 int sz = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1;
504 char *tmp = 0;
505 VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(*dm) + sz))), AEE_ENOMEMORY);
506 RW_MUTEX_LOCK_READ(me->mut);
507 HASH_FIND_STR(*tbl, uri, sm);
508 RW_MUTEX_UNLOCK_READ(me->mut);
509 std_memmove(dm->uri, uri, len);
510 if(sm == 0) {
511 VERIFY(AEE_SUCCESS == (nErr = parse_uri(uri, len, &dm->vals)));
512 FARF(HIGH, "file %.*s %d", dm->vals.filelen, dm->vals.file, dm->vals.filelen);
513 FARF(HIGH, "sym %.*s %d", dm->vals.symlen, dm->vals.sym, dm->vals.symlen);
514 FARF(HIGH, "version %.*s %d", dm->vals.verlen, dm->vals.ver, dm->vals.verlen);
515 if(dm->vals.verlen) {
516 int rv = std_snprintf(dm->uri, sz, "file:///%.*s?%.*s&_modver=%.*s",
517 dm->vals.filelen, dm->vals.file,
518 dm->vals.symlen, dm->vals.sym,
519 dm->vals.verlen, dm->vals.ver);
520 VERIFYC(sz >= rv, AEE_EBADSIZE);
521 } else {
522 int rv = std_snprintf(dm->uri, sz, "file://%.*s?%.*s",
523 dm->vals.filelen, dm->vals.file,
524 dm->vals.symlen, dm->vals.sym);
525 VERIFYC(sz >= rv, AEE_EBADSIZE);
526 }
527 FARF(HIGH, "dm->uri:%s", dm->uri);
528
529 RW_MUTEX_LOCK_READ(me->mut);
530 HASH_FIND_STR(*tbl, dm->uri, sm);
531 RW_MUTEX_UNLOCK_READ(me->mut);
532 }
533 VERIFYC(0 != sm, AEE_ENOTINITIALIZED);
534 assert(sm->handle_invoke || sm->invoke);
535 dm->handle_invoke = sm->handle_invoke;
536 dm->invoke = sm->invoke;
537 dm->key = (uint32)(uintptr_t)dm;
538 dm->refs = 1;
539 if(dm->handle_invoke) {
540 VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64)));
541 }
542
543 RW_MUTEX_LOCK_WRITE(me->mut);
544 do {
545 HASH_FIND_INT(me->openMods, &dm->key, dmOld);
546 if(dmOld) {
547 dm->key++;
548 }
549 } while(dmOld);
550 HASH_ADD_INT(me->openMods, key, dm);
551 RW_MUTEX_UNLOCK_WRITE(me->mut);
552
553 *handle = dm->key;
554 bail:
555 if(tmp) {
556 free(tmp);
557 tmp = NULL;
558 }
559 if(nErr != AEE_SUCCESS) {
560 VERIFY_EPRINTF("Error %x: modtable open from static failed.\n", nErr);
561 }
562 if(nErr && dm) {
563 if(dm->h64) {
564 (void)open_mod_handle_close(dm, dm->h64);
565 }
566 free(dm);
567 dm = NULL;
568 }
569 return nErr;
570 }
571
open_mod_table_open(struct open_mod_table * me,const char * uri,remote_handle * handle,char * dlerr,int dlerrorLen,int * pdlErr)572 static int open_mod_table_open(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr)
573 {
574 int nErr = AEE_SUCCESS, dlErr = 0;
575 if(pdlErr) {
576 *pdlErr = 0;
577 }
578 if(0 != open_mod_table_open_static_override(me, uri, handle)) {
579 VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open_dynamic(me, uri, handle, dlerr, dlerrorLen, &dlErr)));
580 if(dlErr != 0) {
581 FARF(HIGH, "dynammic open failed, trying static");
582 if(0 != open_mod_table_open_static(me, uri, handle)) {
583 if(pdlErr) {
584 *pdlErr = dlErr;
585 }
586 }
587 }
588 }
589 bail:
590 FARF(HIGH, "done open for %s rv %d handle: %p", uri, nErr, *handle);
591 if(nErr != AEE_SUCCESS) {
592 VERIFY_EPRINTF("Error %x: open modtable failed\n", nErr);
593 }
594 return nErr;
595 }
596
open_mod_close(struct open_mod_table * me,struct open_mod * dm)597 static void open_mod_close(struct open_mod_table *me, struct open_mod* dm) {
598 RW_MUTEX_LOCK_WRITE(me->mut);
599 dm->refs--;
600 if(dm->refs <= 0) {
601 HASH_DEL(me->openMods,dm);
602 } else {
603 dm = 0;
604 }
605 RW_MUTEX_UNLOCK_WRITE(me->mut);
606 if(dm) {
607 if(dm->h64) {
608 (void)open_mod_handle_close(dm, dm->h64);
609 }
610 if(dm->dlhandle) {
611 DLCLOSE(dm->dlhandle);
612 }
613 free(dm);
614 dm = NULL;
615 }
616 }
open_mod_table_close(struct open_mod_table * me,remote_handle64 handle,char * errStr,int errStrLen,int * pdlErr)617 static int open_mod_table_close(struct open_mod_table* me, remote_handle64 handle, char* errStr, int errStrLen, int* pdlErr)
618 {
619 int nErr = AEE_SUCCESS;
620 struct open_mod *dm, *del = 0;;
621 int dlErr = 0;
622 // First ensure that the handle is valid
623 RW_MUTEX_LOCK_WRITE(me->mut);
624 HASH_FIND_INT(me->openMods, &handle, dm);
625 if(dm) {
626 dm->refs--;
627 if(dm->refs <= 0) {
628 del = dm;
629 FARF(HIGH, "deleting %s %p", del->uri, del);
630 HASH_DEL(me->openMods,dm);
631 } else {
632 FARF(HIGH, "leaked %s", dm->uri);
633 dm = 0;
634 }
635 }
636 RW_MUTEX_UNLOCK_WRITE(me->mut);
637 if(del) {
638 if(del->h64) {
639 (void)open_mod_handle_close(dm, dm->h64);
640 }
641 if(del->dlhandle) {
642 dlErr = DLCLOSE(del->dlhandle);
643 }
644 FARF(HIGH, "free %s %p", del->uri, del);
645 free(del);
646 del = NULL;
647 }
648 VERIFY(del);
649
650 bail:
651 if(dlErr) {
652 const char* error = DLERROR();
653 nErr = dlErr;
654 if(error != 0){
655 std_strlcpy(errStr,error,errStrLen);
656 }
657 VERIFY_EPRINTF("Error %x: open modtable close failed. dlerr %s\n", nErr, error);
658 }
659 if(pdlErr) {
660 *pdlErr = dlErr;
661 }
662 return nErr;
663 }
664
open_mod_table_get_open(struct open_mod_table * me,remote_handle handle)665 static struct open_mod* open_mod_table_get_open(struct open_mod_table* me, remote_handle handle) {
666 struct open_mod* om = 0;
667 RW_MUTEX_LOCK_READ(me->mut);
668 HASH_FIND_INT(me->openMods, &handle, om);
669 if(0 != om) {
670 om->refs++;
671 }
672 RW_MUTEX_UNLOCK_READ(me->mut);
673 return om;
674 }
open_mod_table_get_const(struct open_mod_table * me,remote_handle handle)675 static struct const_mod* open_mod_table_get_const(struct open_mod_table* me, remote_handle handle) {
676 struct const_mod* cm = 0;
677 RW_MUTEX_LOCK_READ(me->smt->mut);
678 HASH_FIND_INT(me->smt->constMods, &handle, cm);
679 RW_MUTEX_UNLOCK_READ(me->smt->mut);
680 return cm;
681 }
682
open_mod_table_handle_invoke(struct open_mod_table * me,remote_handle handle,uint32 sc,remote_arg * pra)683 static int open_mod_table_handle_invoke(struct open_mod_table* me, remote_handle handle, uint32 sc, remote_arg* pra) {
684 int nErr = AEE_SUCCESS;
685 struct open_mod* om = 0;
686 struct const_mod* cm = 0;
687 remote_handle64 h = 0;
688 invoke_fn invoke = 0;
689 handle_invoke_fn handle_invoke = 0;
690 cm = open_mod_table_get_const(me, handle);
691 if(cm) {
692 invoke = cm->invoke;
693 handle_invoke = cm->handle_invoke;
694 h = cm->h64;
695 } else {
696 VERIFYC(0 != (om = open_mod_table_get_open(me, handle)), AEE_ENOSUCHMOD);
697 invoke = om->invoke;
698 handle_invoke = om->handle_invoke;
699 h = om->h64;
700 }
701 if(invoke) {
702 VERIFY(AEE_SUCCESS == (nErr = invoke(sc, pra)));
703 } else {
704 VERIFY(AEE_SUCCESS == (nErr = handle_invoke(h, sc, pra)));
705 }
706 bail:
707 if(om) {
708 open_mod_close(me, om);
709 }
710 FARF(HIGH, "invoke rv %p %x %x", handle, sc, nErr);
711 return nErr;
712 }
713
714 struct mod_table {
715 struct static_mod_table smt;
716 struct open_mod_table omt;
717 };
718
719 // mod_table object
720 static struct static_mod_table static_mod_table_obj;
721
722
723 /**
724 * register a static component for invocations
725 * this can be called at any time including from a static constructor
726 *
727 * overrides will be tried first, then dynamic modules, then regular
728 * static modules.
729 *
730 * name, name of the interface to register
731 * pfn, function pointer to the skel invoke function
732 *
733 * for example:
734 * __attribute__((constructor)) static void my_module_ctor(void) {
735 * mod_table_register_static("my_module", my_module_skel_invoke);
736 * }
737 *
738 */
mod_table_register_static_override(const char * name,int (* pfn)(uint32 sc,remote_arg * pra))739 int mod_table_register_static_override(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) {
740 if(0 == static_mod_table_ctor(&static_mod_table_obj)) {
741 return static_mod_table_register_static_override(&static_mod_table_obj, name, pfn);
742 }
743 return AEE_EUNKNOWN;
744 }
745
mod_table_register_static_override1(const char * name,int (* pfn)(remote_handle64,uint32 sc,remote_arg * pra))746 int mod_table_register_static_override1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) {
747 if(0 == static_mod_table_ctor(&static_mod_table_obj)) {
748 return static_mod_table_register_static_override1(&static_mod_table_obj, name, pfn);
749 }
750 return AEE_EUNKNOWN;
751 }
752
753
754 /**
755 * register a static component for invocations
756 * this can be called at any time including from a static constructor
757 *
758 * name, name of the interface to register
759 * pfn, function pointer to the skel invoke function
760 *
761 * for example:
762 * __attribute__((constructor)) static void my_module_ctor(void) {
763 * mod_table_register_static("my_module", my_module_skel_invoke);
764 * }
765 *
766 */
mod_table_register_static(const char * name,int (* pfn)(uint32 sc,remote_arg * pra))767 int mod_table_register_static(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) {
768 if(0 == static_mod_table_ctor(&static_mod_table_obj)) {
769 return static_mod_table_register_static(&static_mod_table_obj, name, pfn);
770 }
771 return AEE_EUNKNOWN;
772 }
773
mod_table_register_static1(const char * name,int (* pfn)(remote_handle64,uint32 sc,remote_arg * pra))774 int mod_table_register_static1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) {
775 if(0 == static_mod_table_ctor(&static_mod_table_obj)) {
776 return static_mod_table_register_static1(&static_mod_table_obj, name, pfn);
777 }
778 return AEE_EUNKNOWN;
779 }
780
781
782 /**
783 * Open a module and get a handle to it
784 *
785 * uri, name of module to open
786 * handle, Output handle
787 * dlerr, Error String (if an error occurs)
788 * dlerrorLen, Length of error String (if an error occurs)
789 * pdlErr, Error identifier
790 */
mod_table_open(const char * uri,remote_handle * handle,char * dlerr,int dlerrorLen,int * pdlErr)791 int mod_table_open(const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) {
792 int nErr = AEE_SUCCESS;
793 struct open_mod_table* pomt = 0;
794 FARF(HIGH, "mod_table_open for %s", uri);
795 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)));
796 VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open(pomt,uri,handle,dlerr,dlerrorLen,pdlErr)));
797 bail:
798 FARF(HIGH, "mod_table_open for %s nErr: %x", uri, nErr);
799 if(nErr != AEE_SUCCESS) {
800 VERIFY_EPRINTF("Error %x: modtable open failed\n", nErr);
801 }
802 return nErr;
803 }
804 /**
805 * invoke a handle in the mod table
806 *
807 * handle, handle to invoke
808 * sc, scalars, see remote.h for documentation.
809 * pra, args, see remote.h for documentation.
810 */
mod_table_invoke(remote_handle handle,uint32 sc,remote_arg * pra)811 int mod_table_invoke(remote_handle handle, uint32 sc, remote_arg* pra) {
812 int nErr = AEE_SUCCESS;
813 struct open_mod_table* pomt = 0;
814 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)));
815 VERIFY(AEE_SUCCESS == (nErr = open_mod_table_handle_invoke(pomt, handle, sc, pra)));
816 bail:
817 return nErr;
818 }
819
820 /**
821 * Closes a handle in the mod table
822 *
823 * handle, handle to close
824 * errStr, Error String (if an error occurs)
825 * errStrLen, Length of error String (if an error occurs)
826 * pdlErr, Error identifier
827 */
mod_table_close(remote_handle handle,char * errStr,int errStrLen,int * pdlErr)828 int mod_table_close(remote_handle handle, char* errStr, int errStrLen, int* pdlErr) {
829 int nErr = AEE_SUCCESS;
830 struct open_mod_table* pomt = 0;
831 VERIFY(AEE_SUCCESS == (nErr = HAP_pls_lookup((uintptr_t)open_mod_table_ctor_imp, 0, (void**)&pomt)));
832 VERIFY(AEE_SUCCESS == (nErr = open_mod_table_close(pomt, handle, errStr,errStrLen,pdlErr)));
833 bail:
834 if(nErr != AEE_SUCCESS) {
835 VERIFY_EPRINTF("Error %x: modtable close failed\n", nErr);
836 }
837 return nErr;
838 }
839
840 /**
841 * internal use only
842 */
mod_table_register_const_handle(remote_handle remote,const char * uri,int (* pfn)(uint32 sc,remote_arg * pra))843 int mod_table_register_const_handle(remote_handle remote, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) {
844 if(0 == static_mod_table_ctor(&static_mod_table_obj)) {
845 return static_mod_table_register_const_handle(&static_mod_table_obj, remote, 0, uri, pfn, 0);
846 }
847 return AEE_EUNKNOWN;
848 }
mod_table_register_const_handle1(remote_handle remote,remote_handle64 local,const char * uri,int (* pfn)(remote_handle64,uint32 sc,remote_arg * pra))849 int mod_table_register_const_handle1(remote_handle remote, remote_handle64 local, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) {
850 if(0 == static_mod_table_ctor(&static_mod_table_obj)) {
851 return static_mod_table_register_const_handle(&static_mod_table_obj, remote, local, uri, 0, pfn);
852 }
853 return AEE_EUNKNOWN;
854 }
855
856 // Constructor and destructor
mod_table_ctor(void)857 static int mod_table_ctor(void) {
858 return static_mod_table_ctor(&static_mod_table_obj);
859 }
mod_table_dtor(void)860 static void mod_table_dtor(void) {
861 static_mod_table_dtor_imp(&static_mod_table_obj);
862 return;
863 }
864
865 PL_DEFINE(mod_table, mod_table_ctor, mod_table_dtor);
866