source: roaraudio/libroar/roardl.c @ 6076:b81c397aee90

Last change on this file since 6076:b81c397aee90 was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

File size: 34.5 KB
Line 
1//roardl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2015
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38#ifdef ROAR_HAVE_H_DIRENT
39#include <dirent.h>
40#endif
41
42#if defined(ROAR_HAVE_H_DLFCN) && !defined(RTLD_NEXT)
43#define RTLD_NEXT ((void *) -1L)
44#endif
45
46#define RTF_RA_INITED       0x0001
47#define RTF_APPSCHED_INITED 0x0002
48#define RTF_APPSCHED_FREED  0x0004
49
50struct roar_dl_lhandle {
51 size_t refc; // currently unused.
52 int flags;
53 char * libname; // only used for ROAR_DL_FLAG_STATIC.
54 struct roar_dl_librarypara * para;
55 struct roar_dl_libraryinst * lib;
56 struct {
57  struct roar_error_state error_state;
58  void *  global_data;
59  void *  global_data_state;
60  struct roar_notify_core * notifycore;
61  struct roar_vio_calls * stdvios[3];
62 } context;
63 unsigned int runtime_flags;
64#if defined(ROAR_HAVE_H_DLFCN)
65 void * handle;
66#elif defined(ROAR_TARGET_WIN32)
67 HMODULE handle;
68#endif
69};
70
71// TODO: this should be removed on next SONAME change.
72static struct roar_dl_lhandle * __currently_inited    = NULL;
73static int                      __currently_inited_fn = -1;
74
75struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
76                                              const char * appname, const char * abiversion) {
77 struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
78 ssize_t argc;
79 int err;
80
81 if ( ret == NULL )
82  return NULL;
83
84 memset(ret, 0, sizeof(struct roar_dl_librarypara));
85
86 ret->version    = ROAR_DL_LIBPARA_VERSION;
87 ret->len        = sizeof(struct roar_dl_librarypara);
88 ret->refc       = 1;
89 ret->argc       = 0;
90 ret->argv       = NULL;
91 ret->args_store = NULL;
92 ret->binargv    = binargv;
93 ret->appname    = appname;
94 ret->abiversion = abiversion;
95
96 if ( args != NULL ) {
97  ret->args_store = roar_mm_strdup(args);
98  if ( ret->args_store == NULL ) {
99   roar_mm_free_noerror(ret);
100   return NULL;
101  }
102
103  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 1);
104  if ( argc == -1 ) {
105   err = roar_error;
106   roar_mm_free(ret->args_store);
107   roar_mm_free(ret);
108   roar_error = err;
109   return NULL;
110  }
111
112  ret->argc = argc;
113 }
114
115 return ret;
116}
117
118int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
119 if ( para == NULL ) {
120  ROAR_DBG("roar_dl_para_ref(para=%p) = -1 // error=FAULT", para);
121  roar_err_set(ROAR_ERROR_FAULT);
122  return -1;
123 }
124
125 para->refc++;
126
127 ROAR_DBG("roar_dl_para_ref(para=%p) = 0", para);
128 return 0;
129}
130
131int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
132 if ( para == NULL ) {
133  ROAR_DBG("roar_dl_para_unref(para=%p) = -1 // error=FAULT", para);
134  roar_err_set(ROAR_ERROR_FAULT);
135  return -1;
136 }
137
138 para->refc--;
139
140 if ( para->refc ) {
141  ROAR_DBG("roar_dl_para_unref(para=%p) = 0", para);
142  return 0;
143 }
144
145 if ( para->notifycore != NULL )
146  roar_notify_core_unref(para->notifycore);
147
148 if ( para->args_store != NULL ) {
149  roar_mm_free(para->args_store);
150  roar_mm_free(para->argv);
151 }
152
153 roar_mm_free(para);
154
155 ROAR_DBG("roar_dl_para_unref(para=%p) = 0", para);
156 return 0;
157}
158int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
159                                         const char * appname, const char * abiversion) {
160 if ( para == NULL ) {
161  roar_err_set(ROAR_ERROR_FAULT);
162  return -1;
163 }
164
165 // check if both appnames are NULL or non-NULL.
166 if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
167  roar_err_set(ROAR_ERROR_BADHOST);
168  return -1;
169 }
170
171 // check if the appname matches if given.
172 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
173  roar_err_set(ROAR_ERROR_BADHOST);
174  return -1;
175 }
176
177 // check if both ABI versions are NULL or non-NULL.
178 if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
179  roar_err_set(ROAR_ERROR_BADVERSION);
180  return -1;
181 }
182
183 // check if the ABI versions matches if given.
184 if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
185  roar_err_set(ROAR_ERROR_BADVERSION);
186  return -1;
187 }
188
189 return 0;
190}
191
192
193#if defined(ROAR_HAVE_H_DLFCN)
194static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
195 ROAR_DBG("_roardl2ldl(lhandle=%p) = ?", lhandle);
196
197 if ( (void*)lhandle < (void*)128 ) {
198  switch ((int)(void*)lhandle) {
199   case (int)(void*)ROAR_DL_HANDLE_DEFAULT:
200   case (int)(void*)ROAR_DL_HANDLE_LIBROAR:
201   case (int)(void*)ROAR_DL_HANDLE_APPLICATION:
202     ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_DEFAULT);
203     return RTLD_DEFAULT;
204    break;
205   case (int)(void*)ROAR_DL_HANDLE_NEXT:
206     ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_NEXT);
207     return RTLD_NEXT;
208    break;
209  }
210 }
211
212 ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)(lhandle->handle));
213 return lhandle->handle;
214}
215#elif defined(ROAR_TARGET_WIN32)
216static HMODULE _roardl2winhandle(struct roar_dl_lhandle * lhandle) {
217 if ( (void*)lhandle < (void*)128 ) {
218  return NULL;
219 }
220 return lhandle->handle;
221}
222#endif
223
224#ifdef ROAR_HAVE_H_DIRENT
225// pvn = prefix, host vendor, host name
226static struct roar_dl_lhandle * _load_from_path_pvn(const char * name,
227                                                    int flags, int ra_init,
228                                                    struct roar_dl_librarypara * para,
229                                                    const char * prefix,
230                                                    const char * hostvendor,
231                                                    const char * hostname) {
232 struct roar_dl_lhandle * ret = NULL;
233 int i, j;
234 char path[1024];
235 const char * path_format[] = {"%s/%s/%s", "%s/%s/universal", "%s/universal/universal"};
236 DIR * dir;
237 struct dirent * dirent;
238 char file[1024];
239 const char * file_format[] = {"%s/%s/%s", "%s/%s/%s" ROAR_SHARED_SUFFIX, "%s/%s/lib%s" ROAR_SHARED_SUFFIX};
240//  cont->handle[idx] = roar_dl_open(name, ROAR_DL_FLAG_DEFAULTS, 1, para);
241//#vars: $PREFIX_PLUGINS, $hostvendor, $hostname, $name
242//#search order: $PREFIX_PLUGINS/{$hostvendor/{$hostname,universal},universal/universal}/*/{,lib}$name.so
243
244 for (i = 0; i < 3; i++) {
245  snprintf(path, sizeof(path), path_format[i], prefix, hostvendor, hostname);
246  dir = opendir(path);
247  if ( dir == NULL )
248   continue;
249
250  while ((dirent = readdir(dir)) != NULL) {
251   if ( !strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..") )
252    continue;
253
254   for (j = 0; j < 3; j++) {
255    snprintf(file, sizeof(file), file_format[j], path, dirent->d_name, name);
256    ret = roar_dl_open(file, flags, ra_init, para);
257    if ( ret != NULL ) {
258     closedir(dir);
259     return ret;
260    }
261   }
262  }
263
264  closedir(dir);
265 }
266
267 return NULL;
268}
269
270static struct roar_dl_lhandle * _load_from_path(const char * name, int flags, int ra_init,
271                                                struct roar_dl_librarypara * para) {
272 struct roar_dl_lhandle * ret = NULL;
273 char * host = NULL;
274 char * hostvendor_buffer = NULL;
275 char * hostvendor = NULL;
276 char * hostname = NULL;
277 size_t hostvendor_len;
278 char * c, * d;
279
280 if ( para != NULL && para->appname != NULL && para->appname[0] != 0 ) {
281  host = roar_mm_strdup(para->appname);
282
283  // if we are out of memory we will likely not pass the rest, so just return in error.
284  if ( host == NULL )
285   return NULL;
286
287  hostname = host;
288  c = strstr(host, "<");
289  if ( c != NULL ) {
290   while (c[-1] == ' ') c--;
291   *c = 0;
292   c++;
293   while (*c == ' ' || *c == '<') c++;
294   if ( *c ) {
295    d = strstr(c, ">");
296    if ( d != NULL )
297     *d = 0;
298
299    d = strstr(c, "/");
300    if ( d != NULL ) {
301     *d = '-';
302     hostvendor = c;
303    } else {
304     hostvendor_len = roar_mm_strlen(c) + 1 /* tailing \0 */ + 6 /* "unreg-" */;
305     hostvendor_buffer = roar_mm_malloc(hostvendor_len);
306
307     // see above
308     if ( hostvendor_buffer == NULL ) {
309      roar_mm_free(host);
310      return NULL;
311     }
312
313     roar_mm_strlcpy(hostvendor_buffer, "unreg-", hostvendor_len);
314     roar_mm_strlcat(hostvendor_buffer, c, hostvendor_len);
315     hostvendor = hostvendor_buffer;
316    }
317   }
318  }
319 }
320
321 if ( hostvendor == NULL )
322  hostvendor = "universal";
323
324 if ( hostname == NULL )
325  hostname = "universal";
326
327 ret = _load_from_path_pvn(name, flags, ra_init, para, ROAR_PREFIX_PLUGINS, hostvendor, hostname);
328
329 if ( host != NULL )
330  roar_mm_free(host);
331 if ( hostvendor_buffer != NULL )
332  roar_mm_free(hostvendor_buffer);
333 return ret;
334}
335#endif
336
337static struct roar_dl_lhandle * _roar_dl_open_pluginpath(const char * filename, int flags,
338                                      int ra_init, struct roar_dl_librarypara * para) {
339 flags |= ROAR_DL_FLAG_PLUGINPATH;
340 flags -= ROAR_DL_FLAG_PLUGINPATH;
341
342#ifdef ROAR_HAVE_H_DIRENT
343 // do normal open for everything with a path name.
344 if ( strstr(filename, "/") != NULL )
345  return roar_dl_open(filename, flags, ra_init, para);
346
347 return _load_from_path(filename, flags, ra_init, para);
348#else
349 // fall back to system open function.
350 return roar_dl_open(filename, flags, ra_init, para);
351#endif
352}
353
354struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
355                                      int ra_init, struct roar_dl_librarypara * para) {
356 struct roar_dl_lhandle * ret = NULL;
357#if defined(ROAR_HAVE_H_DLFCN)
358#if defined(RTLD_DEEPBIND) && 0
359 // FIXME: This is currently disabled. See #296.
360 int libdl_flags = RTLD_DEEPBIND;
361#else
362 int libdl_flags = 0;
363#endif
364#endif
365 int err;
366
367 switch (flags) {
368  case ROAR_DL_FLAG_DEFAULTS: flags = ROAR_DL_FLAG_NONE;       break;
369  case ROAR_DL_FLAG_PLUGIN:   flags = ROAR_DL_FLAG_PLUGINPATH; break;
370 }
371
372 if ( flags & ROAR_DL_FLAG_PLUGINPATH )
373  return _roar_dl_open_pluginpath(filename, flags, ra_init, para);
374
375#if defined(ROAR_HAVE_H_DLFCN)
376 if ( flags & ROAR_DL_FLAG_LAZY ) {
377  libdl_flags |= RTLD_LAZY;
378 } else {
379  libdl_flags |= RTLD_NOW;
380 }
381#endif
382
383 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
384  return NULL;
385
386 memset(ret, 0, sizeof(struct roar_dl_lhandle));
387
388 roar_err_initstore(&(ret->context.error_state));
389
390 ret->flags = flags;
391 ret->refc  = 1;
392
393 if ( flags & ROAR_DL_FLAG_STATIC ) {
394  if ( filename == NULL ) {
395   ret->libname = NULL;
396  } else {
397   ret->libname = roar_mm_strdup(filename);
398  }
399 } else {
400#if defined(ROAR_HAVE_H_DLFCN)
401  ret->handle = dlopen(filename, libdl_flags);
402
403  if ( ret->handle == NULL ) {
404   ROAR_DBG("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not load library: %s", filename, flags, ra_init, para, roar_dl_errstr(ret));
405   roar_mm_free(ret);
406   return NULL;
407  }
408#elif defined(ROAR_TARGET_WIN32)
409  ret->handle = LoadLibrary(filename);
410
411  if ( ret->handle == NULL ) {
412   roar_mm_free(ret);
413   return NULL;
414  }
415#else
416  roar_mm_free(ret);
417  roar_err_set(ROAR_ERROR_NOSYS);
418  return NULL;
419#endif
420 }
421
422 ret->para = para;
423
424 if ( roar_vio_ref(roar_stdin) == 0 )
425  ret->context.stdvios[0] = roar_stdin;
426 if ( roar_vio_ref(roar_stdout) == 0 )
427  ret->context.stdvios[1] = roar_stdout;
428 if ( roar_vio_ref(roar_stderr) == 0 )
429  ret->context.stdvios[2] = roar_stderr;
430
431 if ( ra_init ) {
432  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
433   err = roar_error;
434   ROAR_WARN("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not init RA lib: %s", filename, flags, ra_init, para, roar_error2str(err));
435#if defined(ROAR_HAVE_H_DLFCN)
436   if ( ret->handle != NULL )
437    dlclose(ret->handle);
438#elif defined(ROAR_TARGET_WIN32)
439   if ( ret->handle != NULL )
440    FreeLibrary(ret->handle);
441#endif
442   roar_vio_unref(ret->context.stdvios[0]);
443   roar_vio_unref(ret->context.stdvios[1]);
444   roar_vio_unref(ret->context.stdvios[2]);
445   roar_mm_free(ret);
446   roar_error = err;
447   return NULL;
448  }
449 }
450
451 if ( para != NULL )
452  roar_dl_para_ref(para);
453
454 return ret;
455}
456
457int                      roar_dl_ref    (struct roar_dl_lhandle * lhandle) {
458 if ( (void*)lhandle < (void*)128 ) {
459  ROAR_DBG("roar_dl_ref(lhandle=%p) = -1 // error=BADFH", lhandle);
460  roar_err_set(ROAR_ERROR_BADFH);
461  return -1;
462 }
463
464 lhandle->refc++;
465
466 ROAR_DBG("roar_dl_ref(lhandle=%p) = 0", lhandle);
467 return 0;
468}
469
470int                      roar_dl_unref  (struct roar_dl_lhandle * lhandle) {
471 int ret = -1;
472
473 if ( (void*)lhandle < (void*)128 ) {
474  ROAR_DBG("roar_dl_unref(lhandle=%p) = -1 // error=BADFH", lhandle);
475  roar_err_set(ROAR_ERROR_BADFH);
476  return -1;
477 }
478
479 lhandle->refc--;
480
481 if ( lhandle->refc ) {
482  ROAR_DBG("roar_dl_unref(lhandle=%p) = 0", lhandle);
483  return 0;
484 }
485
486 roar_dl_unregister_fn(lhandle);
487
488 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
489  roar_dl_context_restore(lhandle);
490  lhandle->lib->unload(lhandle->para, lhandle->lib);
491  roar_dl_context_store(lhandle);
492 }
493
494#if defined(ROAR_HAVE_H_DLFCN)
495 if ( lhandle->handle == NULL ) {
496  ret = 0;
497 } else {
498  ret = dlclose(_roardl2ldl(lhandle));
499 }
500#elif defined(ROAR_TARGET_WIN32)
501 if ( lhandle->handle == NULL ) {
502  ret = 0;
503 } else {
504  if ( FreeLibrary(_roardl2winhandle(lhandle)) ) {
505   ret = 0;
506  } else {
507   ret = -1;
508  }
509 }
510#else
511 ret = -1;
512#endif
513
514 roar_vio_unref(lhandle->context.stdvios[0]);
515 roar_vio_unref(lhandle->context.stdvios[1]);
516 roar_vio_unref(lhandle->context.stdvios[2]);
517
518 if ( lhandle->context.global_data != NULL )
519  roar_mm_free(lhandle->context.global_data);
520
521 if ( lhandle->para != NULL )
522  roar_dl_para_unref(lhandle->para);
523
524 if ( lhandle->libname != NULL )
525  roar_mm_free(lhandle->libname);
526
527 roar_mm_free(lhandle);
528
529 ROAR_DBG("roar_dl_unref(lhandle=%p) = %i", lhandle, ret);
530 return ret;
531}
532
533void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
534#if defined(ROAR_HAVE_H_DLFCN)
535 void * ret = dlsym(_roardl2ldl(lhandle), sym);
536
537 (void)type;
538
539 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i): ret=%p, errno=%s(%i), dlerror()='%s'", lhandle, sym, type, ret, strerror(errno), errno, dlerror());
540 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
541
542 return ret;
543#elif defined(ROAR_TARGET_WIN32)
544 FARPROC ret = GetProcAddress(_roardl2winhandle(lhandle), sym);
545 return (void*)ret;
546#else
547 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = NULL // errno=NOSYS", lhandle, sym, type, ret);
548 roar_err_set(ROAR_ERROR_NOSYS);
549 return NULL;
550#endif
551}
552
553int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
554                                         const char * prefix,
555                                         struct roar_dl_librarypara * para) {
556 struct roar_dl_lhandle * old_init;
557 int old_fn;
558#define _SUFFIX "_roaraudio_library_init"
559 char name[80] = _SUFFIX;
560 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
561 struct roar_dl_libraryinst * lib;
562 struct roar_dl_lhandle     * getsymhandle = lhandle;
563 void * global_data_state = NULL;
564 int i;
565
566 if ( (void*)lhandle < (void*)128 ) {
567  if ( prefix == NULL )
568   return -1;
569 } else {
570  if ( lhandle->runtime_flags & RTF_RA_INITED )
571   return 0;
572
573  if ( prefix == NULL )
574   prefix = lhandle->libname;
575
576  if ( para == NULL )
577   para = lhandle->para;
578
579  if ( lhandle->flags & ROAR_DL_FLAG_STATIC )
580   getsymhandle = ROAR_DL_HANDLE_DEFAULT;
581 }
582
583
584 if ( prefix != NULL ) {
585  roar_mm_strscpy(name, "_");
586  roar_mm_strscat(name, prefix);
587  roar_mm_strscat(name, _SUFFIX);
588 }
589
590 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
591
592 if ( (func = roar_dl_getsym(getsymhandle, name, -1)) == NULL ) {
593  ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s') = -1", lhandle, prefix);
594  return -1;
595 }
596
597 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
598
599 roar_err_set(ROAR_ERROR_BADLIB); // set a default error in case it returns NULL but not set an error code.
600 lib = func(para);
601
602 if ( lib == NULL )
603  return -1;
604
605 if ( lib->version != ROAR_DL_LIBINST_VERSION )
606  return -1;
607
608 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
609  return -1;
610
611 if ( lib->host_appname != NULL || lib->host_abiversion != NULL ) {
612  // check for correct host.
613  if ( para == NULL ) {
614   roar_err_set(ROAR_ERROR_INVAL);
615   return -1;
616  }
617  if ( roar_dl_para_check_version(para, lib->host_appname, lib->host_abiversion) == -1 )
618   return -1;
619 }
620
621 if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) {
622  roar_err_set(ROAR_ERROR_BADLIB);
623  return -1;
624 }
625
626 if ( lib->libdep != NULL && lib->libdep_len ) {
627  // dynamic loader infos are currently not supported.
628  roar_err_set(ROAR_ERROR_NOTSUP);
629  return -1;
630 }
631
632 if ( !((void*)lhandle < (void*)128) ) {
633  lhandle->lib = lib;
634
635  if ( lib->global_data_len ) {
636   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
637   if ( lhandle->context.global_data == NULL )
638    return -1;
639
640   if ( lib->global_data_init == NULL ) {
641    memset(lhandle->context.global_data, 0, lib->global_data_len);
642   } else {
643    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
644   }
645  }
646 }
647
648 if ( lib->global_data_pointer != NULL ) {
649  global_data_state = *(lib->global_data_pointer);
650  if ( (void*)lhandle < (void*)128 ) {
651   *(lib->global_data_pointer) = lib->global_data_init;
652  } else {
653   *(lib->global_data_pointer) = lhandle->context.global_data;
654  }
655 }
656
657 roar_dl_context_restore(lhandle);
658
659 old_init = __currently_inited;
660 old_fn   = __currently_inited_fn;
661 __currently_inited = lhandle;
662 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
663  __currently_inited_fn = i;
664  if ( lib->func[i] != NULL )
665   lib->func[i](para, lib);
666 }
667 __currently_inited_fn = old_fn;
668 __currently_inited = old_init;
669
670 roar_dl_context_store(lhandle);
671
672 if ( lib->global_data_pointer != NULL ) {
673  if ( !((void*)lhandle < (void*)128) ) {
674   *(lib->global_data_pointer) = global_data_state;
675  }
676 }
677
678 if ( !((void*)lhandle < (void*)128) )
679  lhandle->runtime_flags |= RTF_RA_INITED;
680
681 return 0;
682}
683
684const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
685#if defined(ROAR_HAVE_H_DLFCN)
686 (void)lhandle;
687 return dlerror();
688#elif defined(ROAR_TARGET_WIN32)
689 roar_err_from_errno();
690 return roar_error2str(roar_error);
691#else
692 return NULL;
693#endif
694}
695
696struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
697 if ( (void*)lhandle < (void*)128 ) {
698  roar_err_set(ROAR_ERROR_NOTSUP);
699  return NULL;
700 }
701
702 if ( lhandle->para == NULL ) {
703  roar_err_set(ROAR_ERROR_NOENT);
704  return NULL;
705 }
706
707 if ( roar_dl_para_ref(lhandle->para) == -1 )
708  return NULL;
709
710 return lhandle->para;
711}
712
713const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
714 if ( (void*)lhandle < (void*)128 ) {
715  roar_err_set(ROAR_ERROR_NOTSUP);
716  return NULL;
717 }
718
719 if ( lhandle->lib == NULL ) {
720  roar_err_set(ROAR_ERROR_BADLIB);
721  return NULL;
722 }
723
724 if ( lhandle->lib->libname == NULL ) {
725  roar_err_set(ROAR_ERROR_NOENT);
726  return NULL;
727 }
728
729 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
730  roar_err_set(ROAR_ERROR_BADVERSION);
731  return NULL;
732 }
733
734 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
735  roar_err_set(ROAR_ERROR_HOLE);
736  return NULL;
737 }
738
739 return lhandle->lib->libname;
740}
741
742static inline void __swap_stdvios(struct roar_dl_lhandle * lhandle) {
743 struct roar_vio_calls * vio;
744
745 vio = roar_stdin;
746 roar_stdin = lhandle->context.stdvios[0];
747 lhandle->context.stdvios[0] = vio;
748 vio = roar_stdout;
749 roar_stdout = lhandle->context.stdvios[1];
750 lhandle->context.stdvios[1] = vio;
751 vio = roar_stderr;
752 roar_stderr = lhandle->context.stdvios[2];
753 lhandle->context.stdvios[2] = vio;
754}
755
756int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
757 struct roar_error_state error_state;
758
759 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
760
761 if ( (void*)lhandle < (void*)128 ) {
762  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
763  roar_err_set(ROAR_ERROR_NOTSUP);
764  return -1;
765 }
766
767 roar_err_store(&error_state);
768 roar_err_restore(&(lhandle->context.error_state));
769 lhandle->context.error_state = error_state;
770
771 __swap_stdvios(lhandle);
772
773 if ( lhandle->lib->global_data_pointer != NULL ) {
774  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
775           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
776  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
777  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
778 }
779
780 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL )
781  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
782
783 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
784 return 0;
785}
786
787int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
788 struct roar_error_state error_state;
789
790 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
791
792 if ( (void*)lhandle < (void*)128 ) {
793  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
794  roar_err_set(ROAR_ERROR_NOTSUP);
795  return -1;
796 }
797
798 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL ) {
799  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
800  roar_notify_core_unref(lhandle->context.notifycore);
801  lhandle->context.notifycore = NULL;
802 }
803
804 if ( lhandle->lib->global_data_pointer != NULL ) {
805  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
806           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
807  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
808 }
809
810 __swap_stdvios(lhandle);
811
812 roar_err_store(&error_state);
813 roar_err_restore(&(lhandle->context.error_state));
814 lhandle->context.error_state = error_state;
815
816 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
817 return 0;
818}
819
820int                      roar_dl_appsched_trigger__handle_about(struct roar_dl_lhandle * lhandle) {
821 libroar_dl_service_apitype(roar_service_about) api;
822 int ret, err;
823
824 if ( roar_dl_service_get_api(NULL, ROAR_SERVICE_ABOUT_NAME, ROAR_SERVICE_ABOUT_ABI, &api) == -1 )
825  return -1;
826
827 ret = libroar_dl_service_run_func(api, show, int, roar_dl_getlibname(lhandle));
828 err = roar_error;
829
830 libroar_dl_service_free_api(api);
831
832 roar_error = err;
833 return ret;
834}
835
836int                      roar_dl_appsched_trigger__handle_help(struct roar_dl_lhandle * lhandle) {
837 libroar_dl_service_apitype(roar_service_help) api;
838 int ret, err;
839
840 if ( roar_dl_service_get_api(NULL, ROAR_SERVICE_HELP_NAME, ROAR_SERVICE_HELP_ABI, &api) == -1 )
841  return -1;
842
843 ret = libroar_dl_service_run_func(api, show, int, roar_dl_getlibname(lhandle), NULL);
844 err = roar_error;
845
846 libroar_dl_service_free_api(api);
847
848 roar_error = err;
849 return ret;
850}
851
852int                      roar_dl_appsched_trigger__handle_preferences(struct roar_dl_lhandle * lhandle) {
853 roar_err_set(ROAR_ERROR_NOSYS);
854 return -1;
855}
856
857int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
858 int (*func)  (struct roar_dl_librarypara * para) = NULL;
859 int ret;
860
861 if ( (void*)lhandle < (void*)128 ) {
862  roar_err_set(ROAR_ERROR_NOTSUP);
863  return -1;
864 }
865
866 if ( lhandle->lib == NULL ) {
867  roar_err_set(ROAR_ERROR_TYPEMM);
868  return -1;
869 }
870
871 if ( lhandle->lib->appsched == NULL ) {
872  roar_err_set(ROAR_ERROR_NOENT);
873  return -1;
874 }
875
876 switch (trigger) {
877#define _trig(lname,uname) \
878  case ROAR_DL_APPSCHED_ ## uname :             \
879    func = lhandle->lib->appsched->lname;       \
880   break;
881  _trig(init, INIT);
882  _trig(free, FREE);
883  _trig(update, UPDATE);
884  _trig(tick, TICK);
885  _trig(wait, WAIT);
886
887  // not yet supported by struct roar_dl_appsched.
888  case ROAR_DL_APPSCHED_ABOUT:
889  case ROAR_DL_APPSCHED_HELP:
890  case ROAR_DL_APPSCHED_PREFERENCES:
891    func = NULL;
892   break;
893// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
894#ifndef DEBUG
895  default:
896    roar_err_set(ROAR_ERROR_BADRQC);
897    return -1;
898   break;
899#endif
900 }
901
902 if ( func == NULL ) {
903  if ( trigger == ROAR_DL_APPSCHED_INIT ) {
904   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
905   lhandle->runtime_flags -= RTF_APPSCHED_FREED;
906  } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
907   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
908   lhandle->runtime_flags -= RTF_APPSCHED_INITED;
909  }
910  switch (trigger) {
911   case ROAR_DL_APPSCHED_ABOUT:
912     return roar_dl_appsched_trigger__handle_about(lhandle);
913    break;
914   case ROAR_DL_APPSCHED_HELP:
915     return roar_dl_appsched_trigger__handle_help(lhandle);
916    break;
917   case ROAR_DL_APPSCHED_PREFERENCES:
918     return roar_dl_appsched_trigger__handle_preferences(lhandle);
919    break;
920   default:
921     roar_err_set(ROAR_ERROR_NOENT);
922     return -1;
923    break;
924  }
925 }
926
927 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
928  if ( lhandle->runtime_flags & RTF_APPSCHED_INITED ) {
929   roar_err_set(ROAR_ERROR_BUSY);
930   return -1;
931  }
932 } else {
933  if ( !(lhandle->runtime_flags & RTF_APPSCHED_INITED) ) {
934   roar_err_set(ROAR_ERROR_BUSY);
935   return -1;
936  }
937 }
938
939 roar_dl_context_restore(lhandle);
940 ret = func(lhandle->para);
941 roar_dl_context_store(lhandle);
942
943 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
944  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
945  lhandle->runtime_flags -= RTF_APPSCHED_FREED;
946 } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
947  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
948  lhandle->runtime_flags -= RTF_APPSCHED_INITED;
949 }
950
951 return ret;
952}
953
954
955#define __MAX_FNREGS 24
956static struct __fnregs {
957 struct roar_dl_lhandle * lhandle;
958 int subtype;
959 const void * object;
960 size_t objectlen;
961 int version;
962 int options;
963} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
964
965static int  __fnreg_check_trigger(const struct __fnregs * handle) {
966 if ( handle->subtype != ROAR_DL_FNREG_SUBTYPE )
967  return -1;
968 if ( handle->version != ROAR_DL_FNREG_VERSION )
969  return -1;
970 if ( handle->objectlen != ROAR_DL_FNREG_SIZE )
971  return -1;
972
973 return 0;
974}
975
976static void __fnreg_trigger_if_match(const struct roar_dl_fnreg * callback,
977                                     const struct __fnregs * reg,
978                                     int fn,
979                                     enum roar_dl_fnreg_action action) {
980 if ( callback->fn != -1 && callback->fn != fn )
981  return;
982 if ( callback->subtype != -1 && callback->subtype != reg->subtype )
983  return;
984 if ( callback->version != -1 && callback->version != reg->version )
985  return;
986
987 if ( callback->callback == NULL )
988  return;
989
990 callback->callback(action, fn, reg->subtype, reg->object, reg->objectlen, reg->version, reg->options, callback->userdata, reg->lhandle);
991}
992
993static void __fnreg_trigger_by_reg(const struct __fnregs * reg, enum roar_dl_fnreg_action action, int fn) {
994 size_t j;
995
996 for (j = 0; j < __MAX_FNREGS; j++) {
997  if ( __fnrefs[ROAR_DL_FN_REGFN][j].lhandle != NULL ) {
998   if ( __fnreg_check_trigger(&(__fnrefs[ROAR_DL_FN_REGFN][j])) == -1 )
999    continue;
1000   __fnreg_trigger_if_match(__fnrefs[ROAR_DL_FN_REGFN][j].object, reg, fn, action);
1001  }
1002 }
1003}
1004
1005static void __fnreg_trigger_by_handler(const struct __fnregs * handle, enum roar_dl_fnreg_action action) {
1006 size_t i, j;
1007
1008 if ( __fnreg_check_trigger(handle) == -1 )
1009  return;
1010
1011 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
1012  for (j = 0; j < __MAX_FNREGS; j++) {
1013   if ( __fnrefs[i][j].lhandle != NULL ) {
1014    __fnreg_trigger_if_match(handle->object, &(__fnrefs[i][j]), i, action);
1015   }
1016  }
1017 }
1018}
1019
1020int roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
1021 struct __fnregs * c = NULL;
1022 size_t i;
1023
1024 if ( lhandle == NULL )
1025  lhandle = __currently_inited;
1026
1027 if ( fn == -1 )
1028  fn = __currently_inited_fn;
1029
1030 if ( lhandle == NULL ) {
1031  roar_err_set(ROAR_ERROR_FAULT);
1032  return -1;
1033 }
1034
1035 if ( fn < 0 || fn >= ROAR_DL_FN_MAX ) {
1036  roar_err_set(ROAR_ERROR_RANGE);
1037  return -1;
1038 }
1039
1040 if ( object == NULL || objectlen == 0 ) {
1041  roar_err_set(ROAR_ERROR_INVAL);
1042  return -1;
1043 }
1044
1045 for (i = 0; i < __MAX_FNREGS; i++) {
1046  if ( __fnrefs[fn][i].lhandle != NULL )
1047   continue;
1048  c = &(__fnrefs[fn][i]);
1049  break;
1050 }
1051
1052 if ( c == NULL ) {
1053  roar_err_set(ROAR_ERROR_NOSPC);
1054  return -1;
1055 }
1056
1057 c->lhandle   = lhandle;
1058 c->subtype   = subtype;
1059 c->object    = object;
1060 c->objectlen = objectlen;
1061 c->version   = version;
1062
1063 if ( fn == ROAR_DL_FN_REGFN ) {
1064  __fnreg_trigger_by_handler(c, ROAR_DL_FNREG);
1065 } else {
1066  __fnreg_trigger_by_reg(c, ROAR_DL_FNREG, fn);
1067 }
1068
1069 return 0;
1070}
1071
1072int                      roar_dl_unregister_fn2(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
1073 struct __fnregs * c = NULL;
1074 size_t i, j;
1075
1076 if ( lhandle == NULL ) {
1077  roar_err_set(ROAR_ERROR_FAULT);
1078  return -1;
1079 }
1080
1081 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
1082  if ( fn != -1 && fn != i )
1083   continue;
1084
1085  for (j = 0; j < __MAX_FNREGS; j++) {
1086   c = &(__fnrefs[i][j]);
1087
1088   if ( c->lhandle != lhandle )
1089    continue;
1090
1091   if ( subtype != -1 && subtype != c->subtype )
1092    continue;
1093   if ( object != NULL && object != c->object )
1094    continue;
1095   if ( objectlen != (size_t)-1 && objectlen != c->objectlen )
1096    continue;
1097   if ( version != -1 && version != c->version )
1098    continue;
1099   if ( options != -1 && options != c->options )
1100    continue;
1101
1102   if ( i == ROAR_DL_FN_REGFN ) {
1103    __fnreg_trigger_by_handler(&(__fnrefs[i][j]), ROAR_DL_FNUNREG);
1104   } else {
1105    __fnreg_trigger_by_reg(&(__fnrefs[i][j]), ROAR_DL_FNUNREG, i);
1106   }
1107   memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
1108   __fnrefs[i][j].lhandle = NULL;
1109  }
1110 }
1111
1112 return 0;
1113}
1114
1115int roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle) {
1116 return roar_dl_unregister_fn2(lhandle, -1, -1, NULL, (size_t)-1, -1, -1);
1117}
1118
1119
1120int roar_dl_query_fn(struct roar_dl_lhandle ** lhandle, int fn, int subtype, const void ** object, size_t * objectlen, int version, int * options, ssize_t index) {
1121 struct __fnregs * c = NULL;
1122 ssize_t found = 0;
1123 size_t j;
1124
1125 if ( lhandle == NULL || object == NULL || objectlen == NULL || options == NULL ) {
1126  roar_err_set(ROAR_ERROR_FAULT);
1127  return -1;
1128 }
1129
1130 if ( fn <= 0 || fn >= ROAR_DL_FN_MAX || index < 0 || index >= __MAX_FNREGS ) {
1131  roar_err_set(ROAR_ERROR_INVAL);
1132  return -1;
1133 }
1134
1135 for (j = 0; j < __MAX_FNREGS; j++) {
1136  c = &(__fnrefs[fn][j]);
1137
1138  if ( c->lhandle == NULL )
1139   continue;
1140  if ( c->subtype != subtype )
1141   continue;
1142  if ( c->version != version )
1143   continue;
1144
1145  if ( index == found++ ) {
1146   *lhandle   = c->lhandle;
1147   *object    = c->object;
1148   *objectlen = c->objectlen;
1149   *options   = c->options;
1150   return 0;
1151  }
1152 }
1153
1154 roar_err_set(ROAR_ERROR_NOENT);
1155 return -1;
1156}
1157
1158static inline int __load_plugin_any_get_api(struct roar_dl_librarypara * para, const char * appname, const char * appabi, const char * servicename, const char * serviceabi, int universal, struct roar_dl_service_api * api) {
1159 struct roar_dl_lhandle * lhandle = NULL;
1160 struct roar_dl_librarypara * mypara = NULL;
1161 char name[80];
1162 int err;
1163 int ret;
1164
1165 mypara = roar_dl_para_new(NULL, NULL, LIBROAR_DL_APPNAME, LIBROAR_DL_ABIVERSION);
1166 if ( mypara == NULL )
1167  return -1;
1168
1169 if ( serviceabi != NULL ) {
1170  snprintf(name, sizeof(name), "service-%s-%s", servicename, serviceabi);
1171  lhandle = roar_dl_open(name, ROAR_DL_FLAG_PLUGIN, 1, mypara);
1172 }
1173
1174 if ( lhandle == NULL ) {
1175  snprintf(name, sizeof(name), "service-%s", servicename);
1176  lhandle = roar_dl_open(name, ROAR_DL_FLAG_PLUGIN, 1, mypara);
1177 }
1178
1179 err = roar_error;
1180 roar_dl_para_unref(mypara);
1181 roar_error = err;
1182
1183 if ( lhandle == NULL )
1184  return -1;
1185
1186 roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_INIT);
1187
1188 ret = libroar_dl_service_get_api_real(para, appname, appabi, servicename, serviceabi, universal, api, 0);
1189
1190 err = roar_error;
1191 roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_FREE);
1192 roar_dl_unref(lhandle);
1193 roar_error = err;
1194
1195 return ret;
1196}
1197
1198int libroar_dl_service_get_api_real(struct roar_dl_librarypara * para, const char * appname, const char * appabi, const char * servicename, const char * serviceabi, int universal, struct roar_dl_service_api * api, int retry) {
1199 const struct roar_dl_service * s;
1200 struct __fnregs * c = NULL;
1201 size_t i;
1202 int err;
1203
1204 if ( servicename == NULL || serviceabi == NULL || api == NULL ) {
1205  roar_err_set(ROAR_ERROR_FAULT);
1206  return -1;
1207 }
1208
1209 if ( para != NULL ) {
1210  if ( roar_dl_para_ref(para) == -1 )
1211   return -1;
1212 } else {
1213  para = roar_dl_para_new(NULL, NULL, NULL, NULL);
1214  if ( para == NULL )
1215   return -1;
1216 }
1217
1218 memset(api, 0, sizeof(struct roar_dl_service_api));
1219
1220 for (i = 0; i < __MAX_FNREGS; i++) {
1221  c = &(__fnrefs[ROAR_DL_FN_SERVICE][i]);
1222  s = c->object;
1223
1224  if ( c->lhandle == NULL )
1225   continue;
1226
1227  if ( c->subtype != ROAR_DL_SERVICE_SUBTYPE )
1228   continue;
1229  if ( c->objectlen != ROAR_DL_SERVICE_SIZE )
1230   continue;
1231  if ( c->version != ROAR_DL_SERVICE_VERSION )
1232   continue;
1233
1234  if ( !universal && s->appname == NULL )
1235   continue;
1236  if ( universal == 2 && s->appname != NULL )
1237   continue;
1238  if ( s->appname != NULL && !!strcmp(s->appname, appname) )
1239   continue;
1240  if ( (s->appabi == NULL && appabi != NULL) || (s->appabi != NULL && appabi == NULL) ||
1241       (s->appabi != NULL && appabi != NULL && !!strcmp(s->appabi, appabi) ) )
1242   continue;
1243  if ( s->servicename == NULL || !!strcmp(s->servicename, servicename) )
1244   continue;
1245  if ( s->serviceabi == NULL || !!strcmp(s->serviceabi, serviceabi) )
1246   continue;
1247
1248  if ( s->get_api == NULL )
1249   continue;
1250
1251  if ( roar_dl_ref(c->lhandle) != 0 )
1252   continue;
1253
1254  api->service = s;
1255  api->lhandle = c->lhandle;
1256
1257  api->api = s->get_api(s, para);
1258  if ( api->api == NULL ) {
1259   err = roar_error;
1260   roar_dl_unref(c->lhandle);
1261   roar_dl_para_unref(para);
1262   api->lhandle = NULL;
1263   roar_error = err;
1264   return -1;
1265  }
1266
1267  roar_dl_para_unref(para);
1268  return 0;
1269 }
1270
1271 if ( retry ) {
1272  if ( __load_plugin_any_get_api(para, appname, appabi, servicename, serviceabi, universal, api) == 0 ) {
1273   roar_dl_para_unref(para);
1274   return 0;
1275  }
1276 }
1277
1278 roar_dl_para_unref(para);
1279 roar_err_set(ROAR_ERROR_NOENT);
1280 return -1;
1281}
1282
1283int libroar_dl_service_free_api_real(struct roar_dl_service_api * api) {
1284 if ( api == NULL ) {
1285  roar_err_set(ROAR_ERROR_FAULT);
1286  return -1;
1287 }
1288
1289 roar_dl_unref(api->lhandle);
1290
1291 memset(api, 0, sizeof(struct roar_dl_service_api));
1292
1293 return 0;
1294}
1295
1296//ll
Note: See TracBrowser for help on using the repository browser.