• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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