source: roaraudio/libroar/roardl.c @ 5311:778a3e7b2b66

Last change on this file since 5311:778a3e7b2b66 was 5275:811818eb5b81, checked in by phi, 12 years ago

Improved plugin loader a lot (Closes: #190)

File size: 8.9 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 struct roar_dl_librarypara * para;
44 struct roar_dl_libraryinst * lib;
45#if defined(ROAR_HAVE_LIBDL)
46 void * handle;
47#endif
48};
49
50
51struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
52                                              const char * appname, const char * abiversion) {
53 struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
54 ssize_t argc;
55 int err;
56
57 if ( ret == NULL )
58  return NULL;
59
60 memset(ret, 0, sizeof(struct roar_dl_librarypara));
61
62 ret->version    = ROAR_DL_LIBPARA_VERSION;
63 ret->len        = sizeof(struct roar_dl_librarypara);
64 ret->refc       = 1;
65 ret->argc       = 0;
66 ret->argv       = NULL;
67 ret->args_store = NULL;
68 ret->binargv    = binargv;
69 ret->appname    = appname;
70 ret->abiversion = abiversion;
71
72 if ( args != NULL ) {
73  ret->args_store = roar_mm_strdup(args);
74  if ( ret->args_store == NULL ) {
75   err = roar_error;
76   roar_mm_free(ret);
77   roar_error = err;
78   return NULL;
79  }
80
81  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 0);
82  if ( argc == -1 ) {
83   err = roar_error;
84   roar_mm_free(ret->args_store);
85   roar_mm_free(ret);
86   roar_error = err;
87   return NULL;
88  }
89
90  ret->argc = argc;
91 }
92
93 return ret;
94}
95
96int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
97 if ( para == NULL ) {
98  roar_err_set(ROAR_ERROR_FAULT);
99  return -1;
100 }
101
102 para->refc++;
103
104 return 0;
105}
106
107int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
108 if ( para == NULL ) {
109  roar_err_set(ROAR_ERROR_FAULT);
110  return -1;
111 }
112
113 para->refc--;
114
115 if ( para->refc == 0 ) {
116  if ( para->args_store != NULL ) {
117   roar_mm_free(para->args_store);
118   roar_mm_free(para->argv);
119  }
120  roar_mm_free(para);
121 }
122
123 return 0;
124}
125int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
126                                         const char * appname, const char * abiversion) {
127 if ( para == NULL ) {
128  roar_err_set(ROAR_ERROR_FAULT);
129  return -1;
130 }
131
132 // check if both appnames are NULL or non-NULL.
133 if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
134  roar_err_set(ROAR_ERROR_BADVERSION);
135  return -1;
136 }
137
138 // check if the appname matches if given.
139 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
140  roar_err_set(ROAR_ERROR_BADVERSION);
141  return -1;
142 }
143
144 // check if both ABI versions are NULL or non-NULL.
145 if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
146  roar_err_set(ROAR_ERROR_BADVERSION);
147  return -1;
148 }
149
150 // check if the ABI versions matches if given.
151 if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
152  roar_err_set(ROAR_ERROR_BADVERSION);
153  return -1;
154 }
155
156 return 0;
157}
158
159
160#if defined(ROAR_HAVE_LIBDL)
161static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
162 if ( lhandle == ROAR_DL_HANDLE_DEFAULT )
163  return RTLD_DEFAULT;
164
165 if ( lhandle == ROAR_DL_HANDLE_NEXT )
166  return RTLD_NEXT;
167
168 return lhandle->handle;
169}
170#endif
171
172struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
173                                      int ra_init, struct roar_dl_librarypara * para) {
174 struct roar_dl_lhandle * ret = NULL;
175 int err;
176
177 // early errors just return.
178
179 if ( flags != ROAR_DL_FLAG_DEFAUTS ) {
180  roar_err_set(ROAR_ERROR_NOTSUP);
181  return NULL;
182 }
183
184 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
185  return NULL;
186
187 memset(ret, 0, sizeof(struct roar_dl_lhandle));
188
189#if defined(ROAR_HAVE_LIBDL)
190 flags  = RTLD_NOW;
191
192#ifdef RTLD_DEEPBIND
193 flags |= RTLD_DEEPBIND;
194#endif
195
196 ret->handle = dlopen(filename, flags);
197
198 if ( ret->handle == NULL ) {
199  roar_mm_free(ret);
200  return NULL;
201 }
202#else
203 roar_mm_free(ret);
204 roar_err_set(ROAR_ERROR_NOSYS);
205 return NULL;
206#endif
207
208 ret->para = para;
209
210 if ( ra_init ) {
211  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
212   err = roar_error;
213   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));
214#if defined(ROAR_HAVE_LIBDL)
215   dlclose(ret->handle);
216#endif
217   roar_mm_free(ret);
218   roar_error = err;
219   return NULL;
220  }
221 }
222
223 if ( para != NULL )
224  roar_dl_para_ref(para);
225
226 return ret;
227}
228
229int                      roar_dl_close(struct roar_dl_lhandle * lhandle) {
230 int ret = -1;
231
232 if ( lhandle == ROAR_DL_HANDLE_DEFAULT || lhandle == ROAR_DL_HANDLE_NEXT ) {
233  roar_err_set(ROAR_ERROR_BADFH);
234  return -1;
235 }
236
237 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL )
238  lhandle->lib->unload(lhandle->para, lhandle->lib);
239
240#if defined(ROAR_HAVE_LIBDL)
241 ret = dlclose(_roardl2ldl(lhandle));
242#else
243 ret = -1;
244#endif
245
246 if ( lhandle->para != NULL )
247  roar_dl_para_unref(lhandle->para);
248
249 roar_mm_free(lhandle);
250
251 return ret;
252}
253
254void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
255#if defined(ROAR_HAVE_LIBDL)
256 void * ret = dlsym(_roardl2ldl(lhandle), sym);
257
258 (void)type;
259
260 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
261
262 return ret;
263#else
264 return NULL;
265#endif
266}
267
268int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
269                                         const char * prefix,
270                                         struct roar_dl_librarypara * para) {
271#define _SUFFIX "_roaraudio_library_init"
272 char name[80] = _SUFFIX;
273 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
274 struct roar_dl_libraryinst * lib;
275 int i;
276
277 if ( (void*)lhandle < (void*)128 ) {
278  if ( prefix == NULL )
279   return -1;
280 } else {
281  if ( para == NULL )
282   para = lhandle->para;
283 }
284
285
286 if ( prefix != NULL ) {
287  roar_mm_strscpy(name, "_");
288  roar_mm_strscat(name, prefix);
289  roar_mm_strscat(name, _SUFFIX);
290 }
291
292 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
293
294 if ( (func = roar_dl_getsym(lhandle, name, -1)) == NULL )
295  return -1;
296
297 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
298
299 lib = func(para);
300
301 if ( lib == NULL )
302  return -1;
303
304 if ( lib->version != ROAR_DL_LIBINST_VERSION )
305  return -1;
306
307 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
308  return -1;
309
310 if ( !((void*)lhandle < (void*)128) ) {
311  lhandle->lib = lib;
312 }
313
314 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
315  if ( lib->func[i] != NULL )
316   lib->func[i](para, lib);
317 }
318
319 return 0;
320}
321
322const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
323#if defined(ROAR_HAVE_LIBDL)
324 (void)lhandle;
325 return dlerror();
326#else
327 return NULL;
328#endif
329}
330
331struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
332 if ( (void*)lhandle < (void*)128 ) {
333  roar_err_set(ROAR_ERROR_NOTSUP);
334  return NULL;
335 }
336
337 if ( lhandle->para == NULL ) {
338  roar_err_set(ROAR_ERROR_NOENT);
339  return NULL;
340 }
341
342 if ( roar_dl_para_ref(lhandle->para) == -1 )
343  return NULL;
344
345 return lhandle->para;
346}
347
348const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
349 if ( (void*)lhandle < (void*)128 ) {
350  roar_err_set(ROAR_ERROR_NOTSUP);
351  return NULL;
352 }
353
354 if ( lhandle->lib == NULL ) {
355  roar_err_set(ROAR_ERROR_BADLIB);
356  return NULL;
357 }
358
359 if ( lhandle->lib->libname == NULL ) {
360  roar_err_set(ROAR_ERROR_NOENT);
361  return NULL;
362 }
363
364 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
365  roar_err_set(ROAR_ERROR_BADVERSION);
366  return NULL;
367 }
368
369 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
370  roar_err_set(ROAR_ERROR_HOLE);
371  return NULL;
372 }
373
374 return lhandle->lib->libname;
375}
376
377//ll
Note: See TracBrowser for help on using the repository browser.