source: roaraudio/libroar/roardl.c @ 5317:6b1045321fd6

Last change on this file since 5317:6b1045321fd6 was 5317:6b1045321fd6, checked in by phi, 12 years ago

updated plugin infrastructre

File size: 14.7 KB
Line 
1//roardl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
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#if defined(ROAR_HAVE_LIBDL) && !defined(RTLD_NEXT)
39#define RTLD_NEXT ((void *) -1L)
40#endif
41
42struct roar_dl_lhandle {
43 size_t refc; // currently unused.
44 int flags;
45 char * libname; // only used for ROAR_DL_FLAG_STATIC.
46 struct roar_dl_librarypara * para;
47 struct roar_dl_libraryinst * lib;
48 struct {
49  struct roar_error_state error_state;
50  void *  global_data;
51  void *  global_data_state;
52  struct roar_notify_core * notifycore;
53 } context;
54#if defined(ROAR_HAVE_LIBDL)
55 void * handle;
56#endif
57};
58
59
60struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
61                                              const char * appname, const char * abiversion) {
62 struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
63 ssize_t argc;
64 int err;
65
66 if ( ret == NULL )
67  return NULL;
68
69 memset(ret, 0, sizeof(struct roar_dl_librarypara));
70
71 ret->version    = ROAR_DL_LIBPARA_VERSION;
72 ret->len        = sizeof(struct roar_dl_librarypara);
73 ret->refc       = 1;
74 ret->argc       = 0;
75 ret->argv       = NULL;
76 ret->args_store = NULL;
77 ret->binargv    = binargv;
78 ret->appname    = appname;
79 ret->abiversion = abiversion;
80
81 if ( args != NULL ) {
82  ret->args_store = roar_mm_strdup(args);
83  if ( ret->args_store == NULL ) {
84   err = roar_error;
85   roar_mm_free(ret);
86   roar_error = err;
87   return NULL;
88  }
89
90  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 0);
91  if ( argc == -1 ) {
92   err = roar_error;
93   roar_mm_free(ret->args_store);
94   roar_mm_free(ret);
95   roar_error = err;
96   return NULL;
97  }
98
99  ret->argc = argc;
100 }
101
102 return ret;
103}
104
105int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
106 if ( para == NULL ) {
107  roar_err_set(ROAR_ERROR_FAULT);
108  return -1;
109 }
110
111 para->refc++;
112
113 return 0;
114}
115
116int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
117 if ( para == NULL ) {
118  roar_err_set(ROAR_ERROR_FAULT);
119  return -1;
120 }
121
122 para->refc--;
123
124 if ( para->refc )
125  return 0;
126
127 if ( para->notifycore != NULL )
128  roar_notify_core_unref(para->notifycore);
129
130 if ( para->args_store != NULL ) {
131  roar_mm_free(para->args_store);
132  roar_mm_free(para->argv);
133 }
134
135 roar_mm_free(para);
136
137 return 0;
138}
139int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
140                                         const char * appname, const char * abiversion) {
141 if ( para == NULL ) {
142  roar_err_set(ROAR_ERROR_FAULT);
143  return -1;
144 }
145
146 // check if both appnames are NULL or non-NULL.
147 if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
148  roar_err_set(ROAR_ERROR_BADVERSION);
149  return -1;
150 }
151
152 // check if the appname matches if given.
153 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
154  roar_err_set(ROAR_ERROR_BADVERSION);
155  return -1;
156 }
157
158 // check if both ABI versions are NULL or non-NULL.
159 if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
160  roar_err_set(ROAR_ERROR_BADVERSION);
161  return -1;
162 }
163
164 // check if the ABI versions matches if given.
165 if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
166  roar_err_set(ROAR_ERROR_BADVERSION);
167  return -1;
168 }
169
170 return 0;
171}
172
173
174#if defined(ROAR_HAVE_LIBDL)
175static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
176 ROAR_DBG("_roardl2ldl(lhandle=%p) = ?", lhandle);
177
178 if ( lhandle == ROAR_DL_HANDLE_DEFAULT ) {
179  ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_DEFAULT);
180  return RTLD_DEFAULT;
181 }
182
183 if ( lhandle == ROAR_DL_HANDLE_NEXT ) {
184  ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_NEXT);
185  return RTLD_NEXT;
186 }
187
188 ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)(lhandle->handle));
189 return lhandle->handle;
190}
191#endif
192
193struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
194                                      int ra_init, struct roar_dl_librarypara * para) {
195 struct roar_dl_lhandle * ret = NULL;
196#if defined(ROAR_HAVE_LIBDL)
197#ifdef RTLD_DEEPBIND
198 int libdl_flags = RTLD_NOW|RTLD_DEEPBIND;
199#else
200 int libdl_flags = RTLD_NOW;
201#endif
202#endif
203 int err;
204
205 if ( flags == ROAR_DL_FLAG_DEFAULTS )
206  flags = ROAR_DL_FLAG_NONE;
207
208 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
209  return NULL;
210
211 memset(ret, 0, sizeof(struct roar_dl_lhandle));
212
213 roar_err_initstore(&(ret->context.error_state));
214
215 ret->flags = flags;
216
217 if ( flags & ROAR_DL_FLAG_STATIC ) {
218  if ( filename == NULL ) {
219   ret->libname = NULL;
220  } else {
221   ret->libname = roar_mm_strdup(filename);
222  }
223 } else {
224#if defined(ROAR_HAVE_LIBDL)
225  ret->handle = dlopen(filename, libdl_flags);
226
227  if ( ret->handle == NULL ) {
228   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));
229   roar_mm_free(ret);
230   return NULL;
231  }
232#else
233  roar_mm_free(ret);
234  roar_err_set(ROAR_ERROR_NOSYS);
235  return NULL;
236#endif
237 }
238
239 ret->para = para;
240
241 if ( ra_init ) {
242  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
243   err = roar_error;
244   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));
245#if defined(ROAR_HAVE_LIBDL)
246   if ( ret->handle != NULL )
247    dlclose(ret->handle);
248#endif
249   roar_mm_free(ret);
250   roar_error = err;
251   return NULL;
252  }
253 }
254
255 if ( para != NULL )
256  roar_dl_para_ref(para);
257
258 return ret;
259}
260
261int                      roar_dl_close(struct roar_dl_lhandle * lhandle) {
262 int ret = -1;
263
264 if ( lhandle == ROAR_DL_HANDLE_DEFAULT || lhandle == ROAR_DL_HANDLE_NEXT ) {
265  roar_err_set(ROAR_ERROR_BADFH);
266  return -1;
267 }
268
269 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
270  roar_dl_context_restore(lhandle);
271  lhandle->lib->unload(lhandle->para, lhandle->lib);
272  roar_dl_context_store(lhandle);
273 }
274
275#if defined(ROAR_HAVE_LIBDL)
276 if ( lhandle->handle == NULL ) {
277  ret = 0;
278 } else {
279  ret = dlclose(_roardl2ldl(lhandle));
280 }
281#else
282 ret = -1;
283#endif
284
285 if ( lhandle->context.global_data != NULL )
286  roar_mm_free(lhandle->context.global_data);
287
288 if ( lhandle->para != NULL )
289  roar_dl_para_unref(lhandle->para);
290
291 if ( lhandle->libname != NULL )
292  roar_mm_free(lhandle->libname);
293
294 roar_mm_free(lhandle);
295
296 return ret;
297}
298
299void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
300#if defined(ROAR_HAVE_LIBDL)
301 void * ret = dlsym(_roardl2ldl(lhandle), sym);
302
303 (void)type;
304
305 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i): errno=%s, dlerror()='%s'", lhandle, sym, type, ret, strerror(errno), dlerror());
306 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
307
308 return ret;
309#else
310 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = NULL // errno=NOSYS", lhandle, sym, type, ret);
311 roar_err_set(ROAR_ERROR_NOSYS);
312 return NULL;
313#endif
314}
315
316int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
317                                         const char * prefix,
318                                         struct roar_dl_librarypara * para) {
319#define _SUFFIX "_roaraudio_library_init"
320 char name[80] = _SUFFIX;
321 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
322 struct roar_dl_libraryinst * lib;
323 struct roar_dl_lhandle     * getsymhandle = lhandle;
324 void * global_data_state = NULL;
325 int i;
326
327 if ( (void*)lhandle < (void*)128 ) {
328  if ( prefix == NULL )
329   return -1;
330 } else {
331  if ( prefix == NULL )
332   prefix = lhandle->libname;
333
334  if ( para == NULL )
335   para = lhandle->para;
336
337  if ( lhandle->flags & ROAR_DL_FLAG_STATIC )
338   getsymhandle = ROAR_DL_HANDLE_DEFAULT;
339 }
340
341
342 if ( prefix != NULL ) {
343  roar_mm_strscpy(name, "_");
344  roar_mm_strscat(name, prefix);
345  roar_mm_strscat(name, _SUFFIX);
346 }
347
348 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
349
350 if ( (func = roar_dl_getsym(getsymhandle, name, -1)) == NULL ) {
351  ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s') = -1", lhandle, prefix);
352  return -1;
353 }
354
355 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
356
357 lib = func(para);
358
359 if ( lib == NULL )
360  return -1;
361
362 if ( lib->version != ROAR_DL_LIBINST_VERSION )
363  return -1;
364
365 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
366  return -1;
367
368 if ( !((void*)lhandle < (void*)128) ) {
369  lhandle->lib = lib;
370
371  if ( lib->global_data_len ) {
372   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
373   if ( lhandle->context.global_data == NULL )
374    return -1;
375
376   if ( lib->global_data_init == NULL ) {
377    memset(lhandle->context.global_data, 0, lib->global_data_len);
378   } else {
379    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
380   }
381  }
382 }
383
384 if ( lib->global_data_pointer != NULL ) {
385  global_data_state = *(lib->global_data_pointer);
386  if ( (void*)lhandle < (void*)128 ) {
387   *(lib->global_data_pointer) = lib->global_data_init;
388  } else {
389   *(lib->global_data_pointer) = lhandle->context.global_data;
390  }
391 }
392
393 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
394  if ( lib->func[i] != NULL )
395   lib->func[i](para, lib);
396 }
397
398 if ( lib->global_data_pointer != NULL ) {
399  if ( !((void*)lhandle < (void*)128) ) {
400   *(lib->global_data_pointer) = global_data_state;
401  }
402 }
403
404 return 0;
405}
406
407const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
408#if defined(ROAR_HAVE_LIBDL)
409 (void)lhandle;
410 return dlerror();
411#else
412 return NULL;
413#endif
414}
415
416struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
417 if ( (void*)lhandle < (void*)128 ) {
418  roar_err_set(ROAR_ERROR_NOTSUP);
419  return NULL;
420 }
421
422 if ( lhandle->para == NULL ) {
423  roar_err_set(ROAR_ERROR_NOENT);
424  return NULL;
425 }
426
427 if ( roar_dl_para_ref(lhandle->para) == -1 )
428  return NULL;
429
430 return lhandle->para;
431}
432
433const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
434 if ( (void*)lhandle < (void*)128 ) {
435  roar_err_set(ROAR_ERROR_NOTSUP);
436  return NULL;
437 }
438
439 if ( lhandle->lib == NULL ) {
440  roar_err_set(ROAR_ERROR_BADLIB);
441  return NULL;
442 }
443
444 if ( lhandle->lib->libname == NULL ) {
445  roar_err_set(ROAR_ERROR_NOENT);
446  return NULL;
447 }
448
449 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
450  roar_err_set(ROAR_ERROR_BADVERSION);
451  return NULL;
452 }
453
454 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
455  roar_err_set(ROAR_ERROR_HOLE);
456  return NULL;
457 }
458
459 return lhandle->lib->libname;
460}
461
462int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
463 struct roar_error_state error_state;
464
465 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
466
467 if ( (void*)lhandle < (void*)128 ) {
468  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
469  roar_err_set(ROAR_ERROR_NOTSUP);
470  return -1;
471 }
472
473 roar_err_store(&error_state);
474 roar_err_restore(&(lhandle->context.error_state));
475 lhandle->context.error_state = error_state;
476
477 if ( lhandle->lib->global_data_pointer != NULL ) {
478  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
479           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
480  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
481  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
482 }
483
484 if ( lhandle->para->notifycore != NULL )
485  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
486
487 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
488 return 0;
489}
490
491int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
492 struct roar_error_state error_state;
493
494 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
495
496 if ( (void*)lhandle < (void*)128 ) {
497  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
498  roar_err_set(ROAR_ERROR_NOTSUP);
499  return -1;
500 }
501
502 if ( lhandle->para->notifycore != NULL ) {
503  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
504  roar_notify_core_unref(lhandle->context.notifycore);
505  lhandle->context.notifycore = NULL;
506 }
507
508 if ( lhandle->lib->global_data_pointer != NULL ) {
509  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
510           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
511  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
512 }
513
514 roar_err_store(&error_state);
515 roar_err_restore(&(lhandle->context.error_state));
516 lhandle->context.error_state = error_state;
517
518 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
519 return 0;
520}
521
522int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
523 int ret;
524
525 if ( (void*)lhandle < (void*)128 ) {
526  roar_err_set(ROAR_ERROR_NOTSUP);
527  return -1;
528 }
529
530 if ( lhandle->lib->appsched == NULL ) {
531  roar_err_set(ROAR_ERROR_NOENT);
532  return -1;
533 }
534
535 switch (trigger) {
536#define _trig(lname,uname) \
537  case ROAR_DL_APPSCHED_ ## uname :             \
538    if ( lhandle->lib->appsched->lname == NULL ) {   \
539     roar_err_set(ROAR_ERROR_NOENT);            \
540     return -1;                                 \
541    }                                           \
542    roar_dl_context_restore(lhandle);           \
543    ret = lhandle->lib->appsched->lname(lhandle->para); \
544    roar_dl_context_store(lhandle);             \
545    return ret;                                 \
546   break;
547  _trig(init, INIT);
548  _trig(free, FREE);
549  _trig(update, UPDATE);
550 }
551
552 roar_err_set(ROAR_ERROR_BADRQC);
553 return -1;
554}
555
556//ll
Note: See TracBrowser for help on using the repository browser.