source: roaraudio/libroar/roardl.c @ 5835:62b52f2dc181

Last change on this file since 5835:62b52f2dc181 was 5835:62b52f2dc181, checked in by phi, 11 years ago

typo

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