1 /*
2 Copyright (C) 2001-2005 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include "JackSystemDeps.h"
22 #include "JackDriverLoader.h"
23 #include "JackDriverInfo.h"
24 #include "JackConstants.h"
25 #include "JackError.h"
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <string.h>
30 
31 #ifndef WIN32
32 #include <dirent.h>
33 #endif
34 
35 #ifdef WIN32
36 typedef wchar_t file_char_t;
37 #else
38 typedef char file_char_t;
39 #endif
40 
41 #ifdef WIN32
42 
locate_dll_driver_dir()43 static wchar_t* locate_dll_driver_dir()
44 {
45     HMODULE libjack_handle = NULL;
46     GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
47                        reinterpret_cast<LPCWSTR>(locate_dll_driver_dir), &libjack_handle);
48 
49     // For WIN32 ADDON_DIR is defined in JackConstants.h as relative path
50     wchar_t driver_dir_storage[512];
51     if (3 < GetModuleFileNameW(libjack_handle, driver_dir_storage, 512)) {
52         wchar_t *p = wcsrchr(driver_dir_storage, L'\\');
53         if (p && (p != driver_dir_storage)) {
54             *p = 0;
55         }
56         jack_info("Drivers/internals found in : %S", driver_dir_storage);
57         wcscat(driver_dir_storage, L"\\");
58         wcscat(driver_dir_storage, ADDON_DIRW);
59         return wcsdup(driver_dir_storage);
60     } else {
61         jack_error("Cannot get JACK dll directory : %d", GetLastError());
62         return NULL;
63     }
64 }
65 
locate_driver_dir(HANDLE & file,WIN32_FIND_DATAW & filedata)66 static wchar_t* locate_driver_dir(HANDLE& file, WIN32_FIND_DATAW& filedata)
67 {
68     // Search drivers/internals iin the same folder of "libjackserver.dll"
69     wchar_t* driver_dir = locate_dll_driver_dir();
70     wchar_t dll_filename[512];
71     swprintf(dll_filename, 510, L"%S/*.dll", driver_dir);
72     file = (HANDLE)FindFirstFileW(dll_filename, &filedata);
73 
74     if (file == INVALID_HANDLE_VALUE) {
75         jack_error("Drivers not found in \"%S\": \"%S\"", driver_dir, dll_filename);
76         free(driver_dir);
77         return NULL;
78     } else {
79         return driver_dir;
80     }
81 }
82 
83 #endif
84 
85 jack_driver_desc_t* jackctl_driver_get_desc(jackctl_driver_t * driver);
86 
jack_print_driver_options(jack_driver_desc_t * desc,FILE * file)87 void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file)
88 {
89     unsigned long i;
90     char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
91 
92     for (i = 0; i < desc->nparams; i++) {
93         switch (desc->params[i].type) {
94             case JackDriverParamInt:
95                 sprintf (arg_default, "%" "i", desc->params[i].value.i);
96                 break;
97             case JackDriverParamUInt:
98                 sprintf (arg_default, "%" "u", desc->params[i].value.ui);
99                 break;
100             case JackDriverParamChar:
101                 sprintf (arg_default, "%c", desc->params[i].value.c);
102                 break;
103             case JackDriverParamString:
104                 if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0) {
105                     sprintf (arg_default, "%s", desc->params[i].value.str);
106                 } else {
107                     sprintf (arg_default, "none");
108                 }
109                 break;
110             case JackDriverParamBool:
111                 sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
112                 break;
113         }
114 
115         fprintf(file, "\t-%c, --%s \t%s (default: %s)\n",
116                  desc->params[i].character,
117                  desc->params[i].name,
118                  desc->params[i].long_desc,
119                  arg_default);
120     }
121 }
122 
jack_print_driver_param_usage(jack_driver_desc_t * desc,unsigned long param,FILE * file)123 static void jack_print_driver_param_usage (jack_driver_desc_t* desc, unsigned long param, FILE *file)
124 {
125     fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
126              desc->params[param].name, desc->name);
127     fprintf (file, "%s\n", desc->params[param].long_desc);
128 }
129 
jack_free_driver_params(JSList * driver_params)130 void jack_free_driver_params(JSList * driver_params)
131 {
132     JSList*node_ptr = driver_params;
133     JSList*next_node_ptr;
134 
135     while (node_ptr) {
136         next_node_ptr = node_ptr->next;
137         free(node_ptr->data);
138         free(node_ptr);
139         node_ptr = next_node_ptr;
140     }
141 }
142 
jack_parse_driver_params(jack_driver_desc_t * desc,int argc,char * argv[],JSList ** param_ptr)143 int jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSList** param_ptr)
144 {
145     struct option * long_options;
146     char* options, * options_ptr;
147     unsigned long i;
148     int opt;
149     unsigned int param_index;
150     JSList* params = NULL;
151     jack_driver_param_t * driver_param;
152 
153     if (argc <= 1) {
154         *param_ptr = NULL;
155         return 0;
156     }
157 
158     /* check for help */
159     if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
160         if (argc > 2) {
161             for (i = 0; i < desc->nparams; i++) {
162                 if (strcmp (desc->params[i].name, argv[2]) == 0) {
163                     jack_print_driver_param_usage (desc, i, stdout);
164                     return 1;
165                 }
166             }
167 
168             fprintf (stderr, "Jackd: unknown option '%s' "
169                      "for driver '%s'\n", argv[2],
170                      desc->name);
171         }
172 
173         jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
174         jack_print_driver_options (desc, stdout);
175         return 1;
176     }
177 
178     /* set up the stuff for getopt */
179     options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
180     long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
181 
182     options_ptr = options;
183     for (i = 0; i < desc->nparams; i++) {
184         sprintf (options_ptr, "%c::", desc->params[i].character);
185         options_ptr += 3;
186         long_options[i].name = desc->params[i].name;
187         long_options[i].flag = NULL;
188         long_options[i].val = desc->params[i].character;
189         long_options[i].has_arg = optional_argument;
190     }
191 
192     /* create the params */
193     optind = 0;
194     opterr = 0;
195     while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
196 
197         if (opt == ':' || opt == '?') {
198             if (opt == ':') {
199                 fprintf (stderr, "Missing option to argument '%c'\n", optopt);
200             } else {
201                 fprintf (stderr, "Unknownage with option '%c'\n", optopt);
202             }
203 
204             fprintf (stderr, "Options for driver '%s':\n", desc->name);
205             jack_print_driver_options (desc, stderr);
206             return 1;
207         }
208 
209         for (param_index = 0; param_index < desc->nparams; param_index++) {
210             if (opt == desc->params[param_index].character) {
211                 break;
212             }
213         }
214 
215         driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
216         driver_param->character = desc->params[param_index].character;
217 
218         if (!optarg && optind < argc &&
219                 strlen(argv[optind]) &&
220                 argv[optind][0] != '-') {
221             optarg = argv[optind];
222         }
223 
224         if (optarg) {
225             switch (desc->params[param_index].type) {
226                 case JackDriverParamInt:
227                     driver_param->value.i = atoi(optarg);
228                     break;
229                 case JackDriverParamUInt:
230                     driver_param->value.ui = strtoul(optarg, NULL, 10);
231                     break;
232                 case JackDriverParamChar:
233                     driver_param->value.c = optarg[0];
234                     break;
235                 case JackDriverParamString:
236                     strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
237                     break;
238                 case JackDriverParamBool:
239                     if (strcasecmp("false", optarg) == 0 ||
240                         strcasecmp("off", optarg) == 0 ||
241                         strcasecmp("no", optarg) == 0 ||
242                         strcasecmp("0", optarg) == 0 ||
243                         strcasecmp("(null)", optarg) == 0 ) {
244                         driver_param->value.i = false;
245                     } else {
246                         driver_param->value.i = true;
247                     }
248                     break;
249             }
250         } else {
251             if (desc->params[param_index].type == JackDriverParamBool) {
252                 driver_param->value.i = true;
253             } else {
254                 driver_param->value = desc->params[param_index].value;
255             }
256         }
257 
258         params = jack_slist_append (params, driver_param);
259     }
260 
261     free (options);
262     free (long_options);
263 
264     if (param_ptr) {
265         *param_ptr = params;
266     }
267     return 0;
268 }
269 
jackctl_driver_params_parse(jackctl_driver * driver_ptr,int argc,char * argv[])270 SERVER_EXPORT int jackctl_driver_params_parse(jackctl_driver *driver_ptr, int argc, char* argv[])
271 {
272     struct option* long_options;
273     char* options, * options_ptr;
274     unsigned long i;
275     int opt;
276     JSList* node_ptr;
277     jackctl_parameter_t * param = NULL;
278     union jackctl_parameter_value value;
279 
280     if (argc <= 1) {
281         return 0;
282     }
283 
284     const JSList* driver_params = jackctl_driver_get_parameters(driver_ptr);
285     if (driver_params == NULL) {
286         return 1;
287     }
288 
289     jack_driver_desc_t* desc = jackctl_driver_get_desc(driver_ptr);
290 
291     /* check for help */
292     if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
293         if (argc > 2) {
294             for (i = 0; i < desc->nparams; i++) {
295                 if (strcmp (desc->params[i].name, argv[2]) == 0) {
296                     jack_print_driver_param_usage (desc, i, stdout);
297                     return 1;
298                 }
299             }
300 
301             fprintf (stderr, "Jackd: unknown option '%s' "
302                      "for driver '%s'\n", argv[2],
303                      desc->name);
304         }
305 
306         jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
307         jack_print_driver_options (desc, stdout);
308         return 1;
309     }
310 
311    /* set up the stuff for getopt */
312     options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
313     long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
314 
315     options_ptr = options;
316     for (i = 0; i < desc->nparams; i++) {
317         sprintf(options_ptr, "%c::", desc->params[i].character);
318         options_ptr += 3;
319         long_options[i].name = desc->params[i].name;
320         long_options[i].flag = NULL;
321         long_options[i].val = desc->params[i].character;
322         long_options[i].has_arg = optional_argument;
323     }
324 
325     /* create the params */
326     optind = 0;
327     opterr = 0;
328     while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
329 
330         if (opt == ':' || opt == '?') {
331             if (opt == ':') {
332                 fprintf (stderr, "Missing option to argument '%c'\n", optopt);
333             } else {
334                 fprintf (stderr, "Unknownage with option '%c'\n", optopt);
335             }
336 
337             fprintf (stderr, "Options for driver '%s':\n", desc->name);
338             jack_print_driver_options(desc, stderr);
339             return 1;
340         }
341 
342         node_ptr = (JSList *)driver_params;
343        	while (node_ptr) {
344             param = (jackctl_parameter_t*)node_ptr->data;
345             if (opt == jackctl_parameter_get_id(param)) {
346                 break;
347             }
348             node_ptr = node_ptr->next;
349         }
350 
351         if (!optarg && optind < argc &&
352             strlen(argv[optind]) &&
353             argv[optind][0] != '-') {
354             optarg = argv[optind];
355         }
356 
357         if (optarg) {
358             switch (jackctl_parameter_get_type(param)) {
359                 case JackDriverParamInt:
360                     value.i = atoi(optarg);
361                     jackctl_parameter_set_value(param, &value);
362                     break;
363                 case JackDriverParamUInt:
364                     value.ui = strtoul(optarg, NULL, 10);
365                     jackctl_parameter_set_value(param, &value);
366                     break;
367                 case JackDriverParamChar:
368                     value.c = optarg[0];
369                     jackctl_parameter_set_value(param, &value);
370                     break;
371                 case JackDriverParamString:
372                     strncpy(value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
373                     jackctl_parameter_set_value(param, &value);
374                     break;
375                 case JackDriverParamBool:
376                     if (strcasecmp("false", optarg) == 0 ||
377                         strcasecmp("off", optarg) == 0 ||
378                         strcasecmp("no", optarg) == 0 ||
379                         strcasecmp("0", optarg) == 0 ||
380                         strcasecmp("(null)", optarg) == 0 ) {
381                         value.i = false;
382                     } else {
383                         value.i = true;
384                     }
385                     jackctl_parameter_set_value(param, &value);
386                     break;
387             }
388         } else {
389             if (jackctl_parameter_get_type(param) == JackParamBool) {
390                 value.i = true;
391             } else {
392                 value = jackctl_parameter_get_default_value(param);
393             }
394             jackctl_parameter_set_value(param, &value);
395         }
396     }
397 
398     free(options);
399     free(long_options);
400     return 0;
401 }
402 
jack_find_driver_descriptor(JSList * drivers,const char * name)403 jack_driver_desc_t* jack_find_driver_descriptor (JSList * drivers, const char* name)
404 {
405     jack_driver_desc_t* desc = 0;
406     JSList* node;
407 
408     for (node = drivers; node; node = jack_slist_next (node)) {
409         desc = (jack_driver_desc_t*) node->data;
410 
411         if (strcmp (desc->name, name) != 0) {
412             desc = NULL;
413         } else {
414             break;
415         }
416     }
417 
418     return desc;
419 }
420 
check_symbol(const file_char_t * sofile,const char * symbol,const file_char_t * driver_dir,void ** res_dllhandle=NULL)421 static void* check_symbol(const file_char_t* sofile, const char* symbol, const file_char_t* driver_dir, void** res_dllhandle = NULL)
422 {
423     void* dlhandle;
424     void* res = NULL;
425     file_char_t filename[1024];
426 #ifdef WIN32
427     swprintf(filename, 1022, L"%S/%S", driver_dir, sofile);
428 #else
429     snprintf(filename, 1022, "%s/%s", driver_dir, sofile);
430 #endif
431 
432     if ((dlhandle = LoadDriverModule(filename)) == NULL) {
433 #ifdef WIN32
434         jack_error ("Could not open component .dll '%S': %ld", filename, GetLastError());
435 #else
436         jack_error ("Could not open component .so '%s': %s", filename, dlerror());
437 #endif
438     } else {
439         res = (void*)GetDriverProc(dlhandle, symbol);
440         if (res_dllhandle) {
441             *res_dllhandle = dlhandle;
442         } else {
443             UnloadDriverModule(dlhandle);
444         }
445     }
446 
447     return res;
448 }
449 
jack_get_descriptor(JSList * drivers,const file_char_t * sofile,const char * symbol,const file_char_t * driver_dir)450 static jack_driver_desc_t* jack_get_descriptor (JSList* drivers, const file_char_t* sofile, const char* symbol, const file_char_t* driver_dir)
451 {
452     jack_driver_desc_t* descriptor = NULL;
453     jack_driver_desc_t* other_descriptor;
454     JackDriverDescFunction so_get_descriptor = NULL;
455     file_char_t filename[1024];
456     JSList* node;
457     void* dlhandle = NULL;
458 
459 #ifdef WIN32
460     swprintf(filename, 1022, L"%S/%S", driver_dir, sofile);
461 #else
462     snprintf(filename, 1022, "%s/%s", driver_dir, sofile);
463 #endif
464 
465     so_get_descriptor = (JackDriverDescFunction)check_symbol(sofile, symbol, driver_dir, &dlhandle);
466 
467     if (so_get_descriptor == NULL) {
468         jack_error("jack_get_descriptor : dll %S is not a driver", sofile);
469         goto error;
470     }
471 
472     if ((descriptor = so_get_descriptor ()) == NULL) {
473         jack_error("Driver from '%S' returned NULL descriptor", filename);
474         goto error;
475     }
476 
477     /* check it doesn't exist already */
478     for (node = drivers; node; node = jack_slist_next (node)) {
479         other_descriptor = (jack_driver_desc_t*) node->data;
480         if (strcmp(descriptor->name, other_descriptor->name) == 0) {
481             jack_error("The drivers in '%S' and '%S' both have the name '%S'; using the first",
482                        other_descriptor->file, filename, other_descriptor->name);
483             /* FIXME: delete the descriptor */
484             goto error;
485         }
486     }
487 
488 #ifdef WIN32
489     wcsncpy(descriptor->file, filename, JACK_PATH_MAX);
490 #else
491     strncpy(descriptor->file, filename, JACK_PATH_MAX);
492 #endif
493 
494 error:
495     if (dlhandle) {
496         UnloadDriverModule(dlhandle);
497     }
498     return descriptor;
499 }
500 
501 #ifdef WIN32
502 
jack_drivers_load(JSList * drivers)503 JSList * jack_drivers_load(JSList * drivers)
504 {
505     //char dll_filename[512];
506     WIN32_FIND_DATAW filedata;
507     HANDLE file;
508     const wchar_t* ptr = NULL;
509     JSList* driver_list = NULL;
510     jack_driver_desc_t* desc = NULL;
511 
512     wchar_t* driver_dir = locate_driver_dir(file, filedata);
513     if (!driver_dir) {
514         jack_error("Driver folder not found");
515         goto error;
516     }
517 
518     do {
519         /* check the filename is of the right format */
520         if (wcsncmp (L"jack_", filedata.cFileName, 5) != 0) {
521             continue;
522         }
523 
524         ptr = wcsrchr (filedata.cFileName, L'.');
525         if (!ptr) {
526             continue;
527         }
528 
529         ptr++;
530         if (wcsncmp (L"dll", ptr, 3) != 0) {
531             continue;
532         }
533 
534         /* check if dll is an internal client */
535         if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) != NULL) {
536             continue;
537         }
538 
539         desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor", driver_dir);
540         if (desc) {
541             driver_list = jack_slist_append (driver_list, desc);
542         } else {
543             jack_error ("jack_get_descriptor returns null for \'%S\'", filedata.cFileName);
544         }
545 
546     } while (FindNextFileW(file, &filedata));
547 
548     if (!driver_list) {
549         jack_error ("Could not find any drivers in %S!", driver_dir);
550     }
551 
552 error:
553     if (driver_dir) {
554         free(driver_dir);
555     }
556     FindClose(file);
557     return driver_list;
558 }
559 
560 #else
561 
jack_drivers_load(JSList * drivers)562 JSList* jack_drivers_load (JSList * drivers)
563 {
564     struct dirent * dir_entry;
565     DIR * dir_stream;
566     const char* ptr;
567     int err;
568     JSList* driver_list = NULL;
569     jack_driver_desc_t* desc = NULL;
570 
571     const char* driver_dir;
572     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
573         driver_dir = ADDON_DIR;
574     }
575 
576     /* search through the driver_dir and add get descriptors
577     from the .so files in it */
578     dir_stream = opendir (driver_dir);
579     if (!dir_stream) {
580         jack_error ("Could not open driver directory %s: %s",
581                     driver_dir, strerror (errno));
582         return NULL;
583     }
584 
585     while ((dir_entry = readdir(dir_stream))) {
586 
587         /* check the filename is of the right format */
588         if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
589             continue;
590         }
591 
592         ptr = strrchr (dir_entry->d_name, '.');
593         if (!ptr) {
594             continue;
595         }
596         ptr++;
597         if (strncmp ("so", ptr, 2) != 0) {
598             continue;
599         }
600 
601         /* check if dll is an internal client */
602         if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) != NULL) {
603             continue;
604         }
605 
606         desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor", driver_dir);
607         if (desc) {
608             driver_list = jack_slist_append (driver_list, desc);
609         } else {
610             jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
611         }
612     }
613 
614     err = closedir (dir_stream);
615     if (err) {
616         jack_error ("Error closing driver directory %s: %s",
617                     driver_dir, strerror (errno));
618     }
619 
620     if (!driver_list) {
621         jack_error ("Could not find any drivers in %s!", driver_dir);
622         return NULL;
623     }
624 
625     return driver_list;
626 }
627 
628 #endif
629 
630 #ifdef WIN32
631 
jack_internals_load(JSList * internals)632 JSList* jack_internals_load(JSList * internals)
633 {
634     ///char dll_filename[512];
635     WIN32_FIND_DATAW filedata;
636     HANDLE file;
637     const wchar_t* ptr = NULL;
638     JSList* driver_list = NULL;
639     jack_driver_desc_t* desc;
640 
641     wchar_t* driver_dir = locate_driver_dir(file, filedata);
642     if (!driver_dir) {
643         jack_error("Driver folder not found");
644         goto error;
645     }
646 
647     do {
648 
649         ptr = wcsrchr (filedata.cFileName, L'.');
650         if (!ptr) {
651             continue;
652         }
653 
654         ptr++;
655         if (wcsncmp (L"dll", ptr, 3) != 0) {
656             continue;
657         }
658 
659         /* check if dll is an internal client */
660         if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) == NULL) {
661             continue;
662         }
663 
664         desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor", driver_dir);
665         if (desc) {
666             driver_list = jack_slist_append (driver_list, desc);
667         } else {
668             jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
669         }
670 
671     } while (FindNextFileW(file, &filedata));
672 
673     if (!driver_list) {
674         jack_error ("Could not find any internals in %s!", driver_dir);
675     }
676 
677  error:
678     if (driver_dir) {
679         free(driver_dir);
680     }
681     FindClose(file);
682     return driver_list;
683 }
684 
685 #else
686 
jack_internals_load(JSList * internals)687 JSList* jack_internals_load(JSList * internals)
688 {
689     struct dirent * dir_entry;
690     DIR * dir_stream;
691     const char* ptr;
692     int err;
693     JSList* driver_list = NULL;
694     jack_driver_desc_t* desc;
695 
696     const char* driver_dir;
697     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
698         driver_dir = ADDON_DIR;
699     }
700 
701     /* search through the driver_dir and add get descriptors
702     from the .so files in it */
703     dir_stream = opendir (driver_dir);
704     if (!dir_stream) {
705         jack_error ("Could not open driver directory %s: %s\n",
706                     driver_dir, strerror (errno));
707         return NULL;
708     }
709 
710     while ((dir_entry = readdir(dir_stream))) {
711 
712         ptr = strrchr (dir_entry->d_name, '.');
713         if (!ptr) {
714             continue;
715         }
716 
717         ptr++;
718         if (strncmp ("so", ptr, 2) != 0) {
719             continue;
720         }
721 
722         /* check if dll is an internal client */
723         if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) == NULL) {
724             continue;
725         }
726 
727         desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor", driver_dir);
728         if (desc) {
729             driver_list = jack_slist_append (driver_list, desc);
730         } else {
731             jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
732         }
733     }
734 
735     err = closedir (dir_stream);
736     if (err) {
737         jack_error ("Error closing internal directory %s: %s\n",
738                     driver_dir, strerror (errno));
739     }
740 
741     if (!driver_list) {
742         jack_error ("Could not find any internals in %s!", driver_dir);
743         return NULL;
744     }
745 
746     return driver_list;
747 }
748 
749 #endif
750 
Open(jack_driver_desc_t * driver_desc,Jack::JackLockedEngine * engine,Jack::JackSynchro * synchro,const JSList * params)751 Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc,
752                                                     Jack::JackLockedEngine* engine,
753                                                     Jack::JackSynchro* synchro,
754                                                     const JSList* params)
755 {
756 #ifdef WIN32
757     int errstr;
758 #else
759     const char* errstr;
760 #endif
761 
762     fHandle = LoadDriverModule (driver_desc->file);
763 
764     if (fHandle == NULL) {
765 #ifdef WIN32
766         if ((errstr = GetLastError ()) != 0) {
767             jack_error ("Can't load \"%S\": %ld", driver_desc->file, errstr);
768 #else
769         if ((errstr = dlerror ()) != 0) {
770             jack_error ("Can't load \"%s\": %s", driver_desc->file, errstr);
771 #endif
772 
773         } else {
774 #ifdef WIN32
775           jack_error ("Error loading driver shared object %S", driver_desc->file);
776 #else
777           jack_error ("Error loading driver shared object %s", driver_desc->file);
778 #endif
779         }
780         return NULL;
781     }
782 
783 
784     //jack_error (" ---------------------------------  Successfully opened driver \"%S\"\n", driver_desc->file);
785 
786 
787     fInitialize = (driverInitialize)GetDriverProc(fHandle, "driver_initialize");
788 
789 #ifdef WIN32
790     if ((fInitialize == NULL) && (errstr = GetLastError ()) != 0) {
791 #else
792     if ((fInitialize == NULL) && (errstr = dlerror ()) != 0) {
793 #endif
794 
795 #ifdef WIN32
796         jack_error("No initialize function in shared object %S\n", driver_desc->file);
797 #else
798         jack_error("No initialize function in shared object %s\n", driver_desc->file);
799 #endif
800         return NULL;
801     }
802 
803     fBackend = fInitialize(engine, synchro, params);
804     return fBackend;
805 }
806 
807 JackDriverInfo::~JackDriverInfo()
808 {
809     delete fBackend;
810     if (fHandle) {
811         UnloadDriverModule(fHandle);
812     }
813 }
814 
815 SERVER_EXPORT jack_driver_desc_t* jack_driver_descriptor_construct(
816     const char * name,
817     jack_driver_type_t type,
818     const char * description,
819     jack_driver_desc_filler_t * filler_ptr)
820 {
821     size_t name_len;
822     size_t description_len;
823     jack_driver_desc_t* desc_ptr;
824 
825     name_len = strlen(name);
826     description_len = strlen(description);
827 
828     if (name_len > sizeof(desc_ptr->name) - 1 ||
829         description_len > sizeof(desc_ptr->desc) - 1) {
830         assert(false);
831         return 0;
832     }
833 
834     desc_ptr = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
835     if (desc_ptr == NULL) {
836         jack_error("Error calloc() failed to allocate memory for driver descriptor struct");
837         return 0;
838     }
839 
840     memcpy(desc_ptr->name, name, name_len + 1);
841     memcpy(desc_ptr->desc, description, description_len + 1);
842 
843     desc_ptr->nparams = 0;
844     desc_ptr->type = type;
845 
846     if (filler_ptr != NULL) {
847         filler_ptr->size = 0;
848     }
849 
850     return desc_ptr;
851 }
852 
853 SERVER_EXPORT int jack_driver_descriptor_add_parameter(
854     jack_driver_desc_t* desc_ptr,
855     jack_driver_desc_filler_t * filler_ptr,
856     const char* name,
857     char character,
858     jack_driver_param_type_t type,
859     const jack_driver_param_value_t * value_ptr,
860     jack_driver_param_constraint_desc_t * constraint,
861     const char* short_desc,
862     const char* long_desc)
863 {
864     size_t name_len;
865     size_t short_desc_len;
866     size_t long_desc_len;
867     jack_driver_param_desc_t * param_ptr;
868     size_t newsize;
869 
870     name_len = strlen(name);
871     short_desc_len = strlen(short_desc);
872 
873     if (long_desc != NULL) {
874         long_desc_len = strlen(long_desc);
875     } else {
876         long_desc = short_desc;
877         long_desc_len = short_desc_len;
878     }
879 
880     if (name_len > sizeof(param_ptr->name) - 1 ||
881         short_desc_len > sizeof(param_ptr->short_desc) - 1 ||
882         long_desc_len > sizeof(param_ptr->long_desc) - 1) {
883         assert(false);
884         return 0;
885     }
886 
887     if (desc_ptr->nparams == filler_ptr->size) {
888         newsize = filler_ptr->size + 20; // most drivers have less than 20 parameters
889         param_ptr = (jack_driver_param_desc_t*)realloc (desc_ptr->params, newsize * sizeof (jack_driver_param_desc_t));
890         if (param_ptr == NULL) {
891             jack_error("Error realloc() failed for parameter array of %zu elements", newsize);
892             return false;
893         }
894         filler_ptr->size = newsize;
895         desc_ptr->params = param_ptr;
896     }
897 
898     assert(desc_ptr->nparams < filler_ptr->size);
899     param_ptr = desc_ptr->params + desc_ptr->nparams;
900 
901     memcpy(param_ptr->name, name, name_len + 1);
902     param_ptr->character = character;
903     param_ptr->type = type;
904     param_ptr->value = *value_ptr;
905     param_ptr->constraint = constraint;
906     memcpy(param_ptr->short_desc, short_desc, short_desc_len + 1);
907     memcpy(param_ptr->long_desc, long_desc, long_desc_len + 1);
908 
909     desc_ptr->nparams++;
910     return true;
911 }
912 
913 SERVER_EXPORT
914 int
915 jack_constraint_add_enum(
916     jack_driver_param_constraint_desc_t ** constraint_ptr_ptr,
917     uint32_t * array_size_ptr,
918     jack_driver_param_value_t * value_ptr,
919     const char * short_desc)
920 {
921     jack_driver_param_constraint_desc_t * constraint_ptr;
922     uint32_t array_size;
923     jack_driver_param_value_enum_t * possible_value_ptr;
924     size_t len;
925 
926     len = strlen(short_desc) + 1;
927     if (len > sizeof(possible_value_ptr->short_desc))
928     {
929         assert(false);
930         return false;
931     }
932 
933     constraint_ptr = *constraint_ptr_ptr;
934     if (constraint_ptr == NULL)
935     {
936         constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_constraint_desc_t));
937         if (constraint_ptr == NULL)
938         {
939             jack_error("calloc() failed to allocate memory for param constraint struct");
940             return false;
941         }
942 
943         array_size = 0;
944     }
945     else
946     {
947         array_size = *array_size_ptr;
948     }
949 
950     if (constraint_ptr->constraint.enumeration.count == array_size)
951     {
952         array_size += 10;
953         possible_value_ptr =
954             (jack_driver_param_value_enum_t *)realloc(
955                 constraint_ptr->constraint.enumeration.possible_values_array,
956                 sizeof(jack_driver_param_value_enum_t) * array_size);
957         if (possible_value_ptr == NULL)
958         {
959             jack_error("realloc() failed to (re)allocate memory for possible values array");
960             return false;
961         }
962         constraint_ptr->constraint.enumeration.possible_values_array = possible_value_ptr;
963     }
964     else
965     {
966         possible_value_ptr = constraint_ptr->constraint.enumeration.possible_values_array;
967     }
968 
969     possible_value_ptr += constraint_ptr->constraint.enumeration.count;
970     constraint_ptr->constraint.enumeration.count++;
971 
972     possible_value_ptr->value = *value_ptr;
973     memcpy(possible_value_ptr->short_desc, short_desc, len);
974 
975     *constraint_ptr_ptr = constraint_ptr;
976     *array_size_ptr = array_size;
977 
978     return true;
979 }
980 
981 SERVER_EXPORT
982 void
983 jack_constraint_free(
984     jack_driver_param_constraint_desc_t * constraint_ptr)
985 {
986     if (constraint_ptr != NULL)
987     {
988         if ((constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0)
989         {
990             free(constraint_ptr->constraint.enumeration.possible_values_array);
991         }
992 
993         free(constraint_ptr);
994     }
995 }
996 
997 #define JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(type, copy)                   \
998 JACK_CONSTRAINT_COMPOSE_ENUM(type)                                      \
999 {                                                                       \
1000     jack_driver_param_constraint_desc_t * constraint_ptr;               \
1001     uint32_t array_size;                                                \
1002     jack_driver_param_value_t value;                                    \
1003     struct jack_constraint_enum_ ## type ## _descriptor * descr_ptr;    \
1004                                                                         \
1005     constraint_ptr = NULL;                                              \
1006     for (descr_ptr = descr_array_ptr;                                   \
1007          descr_ptr->value;                                              \
1008          descr_ptr++)                                                   \
1009     {                                                                   \
1010         copy;                                                           \
1011         if (!jack_constraint_add_enum(                                  \
1012                 &constraint_ptr,                                        \
1013                 &array_size,                                            \
1014                 &value,                                                 \
1015                 descr_ptr->short_desc))                                 \
1016         {                                                               \
1017             jack_constraint_free(constraint_ptr);                       \
1018             return NULL;                                                \
1019         }                                                               \
1020     }                                                                   \
1021                                                                         \
1022     constraint_ptr->flags = flags;                                      \
1023                                                                         \
1024     return constraint_ptr;                                              \
1025 }
1026 
1027 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(uint32, value.c = descr_ptr->value);
1028 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(sint32, value.c = descr_ptr->value);
1029 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(char,   value.c = descr_ptr->value);
1030 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(str, strcpy(value.str, descr_ptr->value));
1031