source: roaraudio/roard/roard.c @ 5192:4237437ca526

Last change on this file since 5192:4237437ca526 was 5192:4237437ca526, checked in by phi, 13 years ago

declare some stuff 'extern', this saves like 5.3KB of diskspace in plugin files and make them more resistant against changes in roard

File size: 75.5 KB
Line 
1//roard.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
5 *
6 *  This file is part of roard 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 *  RoarAudio 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 */
25
26/* ckport options:
27 * Stuff checked by configure:
28 * ckport: ignore-symbol: getuid of target win32
29 * ckport: ignore-symbol: setuid of target win32
30 * ckport: ignore-symbol: getgid of target win32
31 * ckport: ignore-symbol: setgid of target win32
32 * ckport: ignore-symbol: setsid of target win32
33 * ckport: ignore-symbol: kill of target win32
34 * ckport: ignore-symbol: chroot of target win32
35 * ckport: ignore-symbol: fork of target win32
36 * ckport: ignore-symbol: getservbyname of target win32
37 * ckport: ignore-symbol: nice of target win32
38 *
39 */
40
41#include "roard.h"
42
43enum action {
44 START,
45 STOP,
46 RESTART,
47 RESTART_RETRY,
48 SHUTDOWN
49};
50
51enum af_mode {
52 AF_MODE_NONE,
53 AF_MODE_LOAD,
54 AF_MODE_GEN
55};
56
57// some stuff we only define extern globally.
58int alive;
59#ifdef ROAR_SUPPORT_LISTEN
60int g_no_listen;
61#endif
62
63uint32_t g_pos; // current possition in output stream
64
65int g_standby;
66int g_autostandby;
67
68struct roard_listen g_listen[ROAR_MAX_LISTEN_SOCKETS];
69
70int g_self_client;
71
72int g_terminate;
73
74struct roar_audio_info * g_sa, * g_max_sa;
75// end of extern block.
76
77#ifdef ROAR_SUPPORT_LISTEN
78static char * server[ROAR_MAX_LISTEN_SOCKETS];
79#endif
80
81#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_FS_POSIX)
82#define SUPPORT_PIDFILE
83static char * pidfile = NULL;
84#endif
85
86#if defined(ROAR_HAVE_SETGID) || defined(ROAR_HAVE_SETUID)
87static int    setids    = 0;
88#endif
89
90#ifdef ROAR_HAVE_LIBX11
91static char * x11display = NULL;
92#endif
93
94void dbg_notify_cb(struct roar_notify_core * core, struct roar_event * event, void * userdata) {
95 char buf[1024] = "";
96 char estr[1024] = "/* ROAR_??? */";
97 char ttstr[1024] = "/* ROAR_OT_??? */";
98 const char * ttname;
99 uint32_t ev = ROAR_EVENT_GET_TYPE(event);
100 int i;
101
102 ttname = roar_ot2str(event->target_type);
103 if ( ttname != NULL ) {
104  snprintf(ttstr, sizeof(ttstr)-1, "/* ROAR_OT_%s */", ttname);
105  buf[sizeof(ttstr)-1] = 0;
106  for (i = 0; ttstr[i] != 0; i++)
107   if ( islower(ttstr[i]) )
108    ttstr[i] = toupper(ttstr[i]);
109 }
110
111 if ( ev == ROAR_NOTIFY_SPECIAL ) {
112  snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_SPECIAL */");
113 } else if ( ROAR_NOTIFY_IS_CMD(ev) ) {
114  if ( command_get_name(ROAR_NOTIFY_EVENT2CMD(ev), &ttname) == -1 ) {
115   snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_CMD2EVENT(%i) */", ROAR_NOTIFY_EVENT2CMD(ev));
116  } else {
117   snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_CMD2EVENT(ROAR_CMD_%s) */", ttname);
118   for (i = 0; estr[i] != 0; i++)
119    if ( islower(estr[i]) )
120     estr[i] = toupper(estr[i]);
121  }
122 } else if ( ROAR_NOTIFY_IS_EGRP(ev) ) {
123  snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_EGRP2EVENT(%i) */", ROAR_NOTIFY_EVENT2EGRP(ev));
124 } else if ( ROAR_NOTIFY_IS_OE(ev) ) {
125  switch (ev) {
126   // OE basics:
127   case ROAR_OE_BASICS_CHANGE_STATE:
128     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_CHANGE_STATE */");
129    break;
130   case ROAR_OE_BASICS_CHANGE_FLAGS:
131     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_CHANGE_FLAGS */");
132    break;
133   case ROAR_OE_BASICS_NEW:
134     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_NEW */");
135    break;
136   case ROAR_OE_BASICS_DELETE:
137     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_DELETE */");
138    break;
139   // OE Streams:
140   case ROAR_OE_STREAM_CHANGE_VOLUME:
141     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_STREAM_CHANGE_VOLUME */");
142    break;
143   case ROAR_OE_STREAM_XRUN:
144     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_STREAM_XRUN */");
145    break;
146   case ROAR_OE_STREAM_META_UPDATE:
147     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_STREAM_META_UPDATE */");
148    break;
149   // OE Default:
150   default:
151     snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_OE2EVENT(%i) */", ROAR_NOTIFY_EVENT2OE(ev));
152    break;
153  }
154 } else if ( ROAR_NOTIFY_IS_USER(ev) ) {
155  snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_USER2EVENT(%i) */", ROAR_NOTIFY_EVENT2USER(ev));
156 }
157
158 buf[sizeof(estr)-1] = 0;
159
160 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT ) {
161  snprintf(buf, sizeof(buf)-1, ".event_proxy=0x%.8x%s, ", (int)event->event_proxy, estr);
162  buf[sizeof(buf)-1] = 0;
163 }
164
165 ROAR_INFO("dbg_notify_cb(core=%p, event=%p{.flags=0x%.8x, event=0x%.8x%s, %s.emitter=%i, .target=%i, .target_type=%i%s, .arg0=%i, .arg1=%i, .arg2=%p}, userdata=%p) = (void)",
166           0 /* always print: minlevel = 0 */,
167           core, event,
168           (int)event->flags,
169           (int)event->event,
170           (event->flags & ROAR_EVENT_FLAG_PROXYEVENT ? "" : estr),
171           buf,
172           event->emitter,
173           event->target,
174           event->target_type,
175           ttstr,
176           event->arg0,
177           event->arg1,
178           event->arg2,
179           userdata);
180}
181
182void dbg_notify_cb_register (void) {
183 struct roar_event event;
184
185 memset(&event, 0, sizeof(event));
186
187 event.event = ROAR_EGRP_ANY_EVENT;
188
189 event.emitter = -1;
190 event.target = -1;
191 event.target_type = -1;
192
193 roar_notify_core_subscribe(NULL, &event, dbg_notify_cb, NULL);
194}
195
196#ifdef ROAR_HAVE_MAIN_ARGS
197void usage (void) {
198 printf("Usage: roard [OPTIONS]...\n\n");
199
200 printf("Misc Options:\n\n");
201 printf(
202#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
203        " --daemon              - Bring the server into background after init\n"
204#endif
205        " --verbose             - Be more verbose, can be used multiple times\n"
206        " --terminate           - Terminate after last client quited\n"
207        " --start               - No op parameter (starting roard is default operation)\n"
208        " --restart             - Trys to stop an old instance and start a new with new settings\n"
209        " --stop                - Stops a running roard (provide --pidfile!)\n"
210        " --shutdown            - Terminates a running roard (provide --pidfile!)\n"
211        " --realtime            - Trys to get realtime priority,\n"
212        "                         give multible times for being more realtime\n"
213        " --memlock LEVEL       - Set default memory locking level to LEVEL\n"
214#ifdef ROAR_HAVE_CHROOT
215        " --chroot DIR          - chroots to the given dir\n"
216#endif
217#ifdef ROAR_HAVE_SETGID
218        " --setgid              - GroupID to the audio group as specified via -G\n"
219#endif
220#ifdef ROAR_HAVE_SETUID
221        " --setuid              - UserID to the audio user as specified via -U\n"
222#endif
223        " --sysclocksync        - calculate exact sample rate using the system clock\n"
224        " --location  LOC       - Set lion readable location of server\n"
225        " --description  DESC   - Set lion readable description of server\n"
226#ifdef SUPPORT_PIDFILE
227        " --pidfile PIDFILE     - Write a pidfile at PIDFILE\n"
228#endif
229#ifdef ROAR_HAVE_SYSLOG
230        " --log-syslog          - Log Warnings, Errors, ... to syslog\n"
231#endif
232#ifdef ROAR_HAVE_SYSTEM
233        " --script-postdown S   - Run command lion S after complet shutdown.\n"
234#endif
235       );
236
237 printf("\nAuth Options:\n\n");
238 printf(
239        " --guest-acclev ACCLEV - Sets the access level for guest access to ACCLEV,\n"
240        "                         Use \"none\" to disable guest access.\n"
241        " --trust-acclev ACCLEV - Sets the access level for trust-authed\n"
242        "                         connections to ACCLEV. Use \"none\" to disable trust auth.\n"
243        " --trust-root          - Trust root user\n"
244        " --no-trust-root       - Don't trust root user\n"
245        " --authfile-gen FILE   - Generate an new authfile\n"
246        " --authfile-load FILE  - Load an authfile\n"
247        " --authfile-type TYPE  - Type of authfile\n"
248        " --authfile-acclev ACCLEV\n"
249        "                       - Sets the access level for authfile\n"
250        " --new-authfile        - Parameters for new authfile follow\n"
251       );
252
253 printf("\nPlugin Options:\n\n");
254 printf(
255        " --plugin-load FILE    - Load plugin FILE\n"
256       );
257
258 printf("\nAudio Options:\n\n");
259 printf(
260        " -R  --rate   RATE     - Set server rate\n"
261        " -B  --bits   BITS     - Set server bits\n"
262        " -C  --chans  CHANNELS - Set server channels\n"
263        " --aiprofile  PROFILE  - Use the given audio profile\n"
264       );
265
266 printf("\nStream Options:\n\n");
267 printf(
268        " --stream-flags D=F    - Set default flags for stream directions\n"
269        "                         D is the stream direction and F is a comma separated\n"
270        "                         list of flags in form +flag or -flag to set or unset\n"
271        "                         a flag as default or remove it from the default\n"
272       );
273 printf("\nStream Options:\n\n");
274 printf(
275        " --list-rolestack      - Show the current role stack\n"
276        " --rolestack-push R:A  - Add a rule for role R with action A on top\n"
277        "                         of the role stack.\n"
278       );
279
280 printf("\nOutput Options:\n\n");
281 printf(" -o  --odriver DRV     - Set the driver, use '--list-driver' to get a list\n");
282 printf(" -O  --odevice DEV     - Set the device\n");
283 printf(" -oO OPTS              - Set output options\n");
284 printf(" -oN                   - Adds another output\n");
285 printf(" -oP                   - Mark output as primary\n");
286#ifdef ROAR_DRIVER_DEFAULT
287 printf(" --list-driver         - List all drivers (default driver: %s)\n", ROAR_DRIVER_DEFAULT);
288#else
289 printf(" --list-driver         - List all drivers (default driver: (autodetect))\n");
290#endif
291
292#ifndef ROAR_WITHOUT_DCOMP_SOURCES
293 printf("\nSource Options:\n\n");
294 printf(" -s  --source DRV      - Use DRV as input driver\n"
295        " -S           DEV      - Use DEV as input device\n"
296        " -sO          OPTS     - Use OPTS as input options\n"
297        " -sN                   - Adds another source\n"
298        " -sP                   - Make souce as primary\n"
299       );
300 printf(" --list-sources        - List all sources\n");
301#endif
302
303#ifndef ROAR_WITHOUT_DCOMP_MIXER
304 printf("\nHardware Mixer Options:\n\n");
305 printf(" -m  --mixer  DRV      - Use DRV as mixer driver\n"
306        " -M           DEV      - Use DEV as mixer device\n"
307        " -mO          OPTS     - Use OPTS as mixer options\n"
308        " -mN                   - Adds another mixer\n"
309        " -mP                   - Make mixer as primary\n"
310       );
311 printf(" --list-mixers         - List all mixers\n");
312#endif
313
314 printf("\nCodec Filter Options:\n\n");
315 printf(" --list-cf             - List all codec filter\n"
316       );
317
318#ifndef ROAR_WITHOUT_DCOMP_MIDI
319 printf("\nMIDI Options:\n\n");
320 printf(" --midi-no-console     - Disable console based MIDI synth\n"
321        " --midi-console-enable - Enables the console based MIDI synth\n"
322        " --midi-console DEV    - Set device for MIDI console\n"
323#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
324        " --ssynth-enable       - Enable simple software synth\n"
325        " --ssynth-disable      - Disable simple software synth\n"
326#endif
327       );
328#endif
329
330#ifndef ROAR_WITHOUT_DCOMP_LIGHT
331 printf("\nLight Control Options:\n\n");
332 printf(" --light-channels NUM  - Sets the number of channels for Light control (default: %i)\n",
333                                  LIGHT_CHANNELS_DEFAULT
334       );
335#endif
336
337#ifndef ROAR_WITHOUT_DCOMP_RDTCS
338 printf("\nRadio Data and Transmitter Control System Options:\n\n");
339 printf(" --rds-pi   PI         - Sets the RDS Programme Identification (PI)\n"
340        " --rds-ps   PS         - Sets the RDS Programme Service Name (PS)\n"
341        " --rds-pty  PTY        - Sets the RDS Programme Type (PTY)\n"
342        " --rds-tp              - Sets the RDS Traffic Programme (TP) flag\n"
343        " --rds-ct              - Enables sending of RDS Clock Time (CT)\n"
344       );
345#endif
346
347#ifdef ROAR_HAVE_LIBX11
348 printf("\nX11 Options:\n\n");
349 printf(
350        " --x11-display DISPLAY - Set display for X11\n"
351        " --display DISPLAY     - Set display for X11\n"
352       );
353#endif
354
355 printf("\nServer Options:\n\n");
356 printf(" -t  --tcp             - Use TCP listen socket\n"
357#ifdef ROAR_HAVE_UNIX
358        " -u  --unix            - Use UNIX Domain listen socket (default)\n"
359#endif
360#ifdef ROAR_HAVE_LIBDNET
361        " -n  --decnet          - use DECnet listen socket\n"
362#endif
363        " -4                    - Use IPv4 connections (implies -t)\n"
364#ifdef AF_INET6
365        " -6                    - Use IPv6 connections (implies -t)\n"
366#endif
367#ifdef IPV6_ADDRFORM
368        " -64                   - Try to downgrade sockets from IPv6 into IPv4,\n"
369        "                         this is normaly not useful.\n"
370#endif
371        " -p  --port            - TCP Port to bind to\n"
372        " -b  --bind            - IP/Hostname to bind to\n"
373        "     --sock            - Filename for UNIX Domain Socket\n"
374        "     --proto PROTO     - Use PROTO as protocol on Socket\n"
375        "     --proto-dir DIR   - Set direction parameter for protocol\n"
376        "     --proto-rate RATE - Set sample rate parameter for protocol\n"
377        "     --proto-bits BITS - Set bits per sample parameter for protocol\n"
378        "     --proto-codec E   - Set codec parameter for protocol\n"
379        "     --proto-chans C   - Set number of channels parameter for protocol\n"
380        "     --proto-aiprofile PROFILE\n"
381        "                       - Sets the audio profile for socket\n"
382        "     --proto-profile P - Set profile for listen socket\n"
383        "     --list-proto      - List supported protocols\n"
384        "     --list-profiles   - List supported profiles for --proto-profile\n"
385        "     --list-aiprofiles - List supported profiles for --proto-aiprofile\n"
386        "     --new-sock        - Parameters for new socket follow\n"
387#ifdef ROAR_HAVE_LIBSLP
388        "     --slp             - Enable OpenSLP support\n"
389#endif
390#ifdef ROAR_HAVE_LIBX11
391        "     --x11             - Enable X11 support\n"
392#endif
393        " --jumbo-mtu MTU       - Sets the MTU for Jumbo Packets\n"
394        " -G  GROUP             - Sets the group for the UNIX Domain Socket, (default: %s)\n"
395        "                         You need the permissions to change the GID\n"
396        " -U  USER              - Sets the user for the UNIX Domain Socket, (default: do not set)\n"
397        "                         You need the permissions to change the UID (normaly only root has)\n"
398        " --no-listen           - Do not listen for new clients\n"
399        "                         (only useful for relaing, impleys --terminate)\n"
400        " --client-fh           - Comunicate with a client over this handle\n"
401        "                         (only useful for relaing)\n"
402        " --close-fh            - Closes the given fh\n"
403        " --standby             - Start in standby state\n"
404        " --auto-standby        - Automatical goes into standby if there are no streams\n",
405#ifdef ROAR_DEFAULT_SOCKGRP
406        ROAR_DEFAULT_SOCKGRP
407#else
408        "(none)"
409#endif
410       );
411// printf("\n Options:\n\n");
412 printf("\n");
413}
414
415static void list_proto (void) {
416 printf("  Protocol Flag Subsys - Description\n");
417 printf("------------------------------------------------------\n");
418 printf("  roar          WM LRX - RoarAudio native protocol\n");
419#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
420 printf("  esd           W      - EsounD emulation\n");
421#endif
422#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
423 printf("  simple        WM LRX - PulseAudio simple protocol\n");
424#endif
425#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
426 printf("  rsound        W      - RSound emulation\n");
427#endif
428#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
429 printf("  rplay         W      - RPlay emulation\n");
430#endif
431#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
432 printf("  gopher               - The Internet Gopher Protocol\n");
433#endif
434}
435
436#endif
437
438#define _pmsg(format, args...) roar_debug_msg(type, __LINE__, __FILE__, ROAR_DBG_PREFIX, format, ## args)
439#define _pmsgc(group, counter, name) _pmsg("  Counter %-10s: %llu", (name), (long long unsigned int)counters_get(group, counter))
440void counters_print(int type, int force) {
441 if ( type != ROAR_DEBUG_TYPE_INFO || force || (ROAR_DBG_INFOVAR) >= ROAR_DBG_INFO_INFO ) {
442  _pmsg("--- Counter Listing ---");
443  _pmsg(" Current:");
444  _pmsgc(cur, clients, "Clients");
445  _pmsgc(cur, streams, "Streams");
446  _pmsg(" Total:");
447  _pmsgc(sum, clients, "Clients");
448  _pmsgc(sum, streams, "Streams");
449  _pmsg("--- End of Counter Listing ---");
450 }
451}
452#undef _pmsgc
453#undef _pmsg
454
455int restart_server (char * server, int terminate) {
456 struct roar_connection con;
457#ifdef ROAR_HAVE_KILL
458 char buf[80];
459 ssize_t l;
460 struct roar_vio_calls fh;
461 pid_t pid;
462 int ok;
463
464 ROAR_INFO("restart_server(server='%s', terminate=%i): trying to restart server", ROAR_DBG_INFO_INFO, server, terminate);
465
466 if ( pidfile != NULL ) {
467  if ( roar_vio_open_file(&fh, pidfile, O_RDONLY, 0644) == -1 ) {
468   ROAR_WARN("restart_server(*): Can not read pidfile: %s", pidfile);
469  } else {
470   l = roar_vio_read(&fh, buf, 80);
471   roar_vio_close(&fh);
472   if ( l > 0 ) {
473    buf[l-1] = 0;
474    buf[79]  = 0;
475    pid = atoi(buf);
476    if ( terminate ) {
477     ok = kill(pid, SIGUSR1);
478    } else {
479     ok = kill(pid, SIGINT);
480    }
481    if ( ok == 0 ) {
482     return 0;
483    } else {
484     ROAR_WARN("restart_server(*): Can not kill roard by pidfile");
485    }
486   } else {
487    ROAR_WARN("restart_server(*): Can not find a PID in the pidfile");
488   }
489  }
490 }
491#endif
492
493 if ( roar_simple_connect(&con, server, "roard") == -1 ) {
494  return -1;
495 }
496
497 if ( roar_terminate(&con, terminate) == -1 ) {
498  return -1;
499 }
500
501 return roar_disconnect(&con);
502}
503
504#define R_SETUID 1
505#define R_SETGID 2
506
507int init_config (void) {
508 int i;
509
510 memset(g_config, 0, sizeof(struct roard_config));
511
512 for (i = 0; i < ROAR_DIR_DIRIDS; i++) {
513  g_config->streams[i].mixer_channels = 1;
514  g_config->streams[i].mixer.rpg_mul  = 1;
515  g_config->streams[i].mixer.rpg_div  = 1;
516  g_config->streams[i].mixer.scale    = 65535;
517  g_config->streams[i].mixer.mixer[0] = g_config->streams[i].mixer.scale;
518 }
519
520 g_config->streams[ROAR_DIR_PLAY    ].flags = ROAR_FLAG_META;
521 g_config->streams[ROAR_DIR_OUTPUT  ].flags = ROAR_FLAG_PASSMIXER;
522 g_config->streams[ROAR_DIR_FILTER  ].flags = ROAR_FLAG_SYNC;
523 g_config->streams[ROAR_DIR_MIDI_OUT].flags = ROAR_FLAG_SYNC;
524 g_config->streams[ROAR_DIR_BIDIR   ].flags = ROAR_FLAG_ANTIECHO;
525
526 g_config->location    = CONF_DEF_STRING;
527 g_config->description = CONF_DEF_STRING;
528
529 g_config->memlock_level = -1;
530
531#ifdef ROAR_HAVE_SYSTEM
532 g_config->scripts.post_shutdown = NULL;
533#endif
534
535 return 0;
536}
537
538#ifdef ROAR_SUPPORT_LISTEN
539int init_listening (void) {
540 int i;
541
542 memset(g_listen, 0, sizeof(g_listen));
543
544 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
545  g_listen[i].proto  = ROAR_PROTO_ROARAUDIO;
546  server[i]          = NULL;
547 }
548
549 return 0;
550}
551
552int get_listen(struct roard_listen ** sock, char *** sockname) {
553 int i;
554
555 if ( sock == NULL )
556  return -1;
557
558 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
559  if ( ! g_listen[i].used ) {
560   server[i] = NULL;
561   *sock = &(g_listen[i]);
562
563   if ( sockname != NULL )
564    *sockname = &(server[i]);
565
566   return 0;
567  }
568 }
569
570 return -1;
571}
572
573#ifdef ROAR_SUPPORT_LISTEN
574static struct _listen_profile {
575 const char * name;
576 int          type;
577 int          port;
578 const char * sockaddr;
579 int          proto;
580 int          dir;
581 const char * aiprofile;
582 const char * desc;
583} _g_listen_profiles[] = {
584 // RoarAudio:
585#ifdef ROAR_HAVE_UNIX
586 {"roar-usock",     ROAR_SOCKET_TYPE_UNIX,   0,                 "~/" ROAR_DEFAULT_SOCK_USER,
587                    ROAR_PROTO_ROARAUDIO, -1, NULL,
588                    "RoarAudio default user profile"},
589 {"roar-gsock",     ROAR_SOCKET_TYPE_UNIX,   0,                 ROAR_DEFAULT_SOCK_GLOBAL,
590                    ROAR_PROTO_ROARAUDIO, -1, NULL,
591                    "RoarAudio default global profile"},
592#endif
593#ifdef ROAR_HAVE_IPV4
594 {"roar-tcp",       ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PORT, ROAR_DEFAULT_INET4_HOST,
595                    ROAR_PROTO_ROARAUDIO, -1, NULL,
596                    "RoarAudio local TCP profile"},
597 {"roar-tcp-pub",   ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PORT, ROAR_NET_INET4_ANYHOST,
598                    ROAR_PROTO_ROARAUDIO, -1, NULL,
599                    "RoarAudio network TCP profile"},
600#endif
601#ifdef ROAR_HAVE_IPV6
602 {"roar-tcp6",      ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PORT, ROAR_DEFAULT_INET6_HOST,
603                    ROAR_PROTO_ROARAUDIO, -1, NULL,
604                    "RoarAudio local TCP profile"},
605 {"roar-tcp-pub6",  ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PORT, ROAR_NET_INET6_ANYHOST,
606                    ROAR_PROTO_ROARAUDIO, -1, NULL,
607                    "RoarAudio network TCP profile"},
608#endif
609#ifdef ROAR_HAVE_LIBDNET
610 {"roar-dnet",      ROAR_SOCKET_TYPE_DECNET, 0,                 ROAR_DEFAULT_LISTEN_OBJECT,
611                    ROAR_PROTO_ROARAUDIO, -1, NULL,
612                    "RoarAudio default DECnet"},
613#endif
614#ifdef ROAR_HAVE_UNIX
615 {"roar-abstract",  ROAR_SOCKET_TYPE_UNKNOWN,   0,              "+abstract",        ROAR_PROTO_ROARAUDIO, -1, NULL,
616                    "RoarAudio abstract namespace profile"},
617#endif
618
619 // EsounD:
620#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
621#ifdef ROAR_HAVE_UNIX
622 {"esd-unix",       ROAR_SOCKET_TYPE_UNIX,   0,                 ROAR_DEFAULT_ESD_GSOCK,
623                    ROAR_PROTO_ESOUND,    -1, NULL,
624                    "EsounD default local profile"},
625#endif
626#ifdef ROAR_HAVE_IPV4
627 {"esd-tcp",        ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET4_LOCALHOST,
628                    ROAR_PROTO_ESOUND,    -1, NULL,
629                    "EsounD local TCP profile"},
630 {"esd-tcp-pub",    ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET4_ANYHOST,
631                    ROAR_PROTO_ESOUND,    -1, NULL,
632                    "EsounD network TCP profile"},
633#endif
634#ifdef ROAR_HAVE_IPV6
635 {"esd-tcp6",       ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET6_LOCALHOST,
636                    ROAR_PROTO_ESOUND,    -1, NULL,
637                    "EsounD local TCP profile"},
638 {"esd-tcp-pub6",   ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET6_ANYHOST,
639                    ROAR_PROTO_ESOUND,    -1, NULL,
640                    "EsounD network TCP profile"},
641#endif
642#endif
643
644 // RSound:
645#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
646#ifdef ROAR_HAVE_UNIX
647 {"rsound-unix",    ROAR_SOCKET_TYPE_UNIX,   0,                 ROAR_DEFAULT_RSOUND_GSOCK,
648                    ROAR_PROTO_RSOUND,    -1, NULL,
649                    "RSound default local profile"},
650#endif
651#ifdef ROAR_HAVE_IPV4
652 {"rsound-tcp",     ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET4_LOCALHOST,
653                    ROAR_PROTO_RSOUND,    -1, NULL,
654                    "RSound local TCP profile"},
655 {"rsound-tcp-pub", ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET4_ANYHOST,
656                    ROAR_PROTO_RSOUND,    -1, NULL,
657                    "RSound network TCP profile"},
658#endif
659#ifdef ROAR_HAVE_IPV6
660 {"rsound-tcp6",    ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET6_LOCALHOST,
661                    ROAR_PROTO_RSOUND,    -1, NULL,
662                    "RSound local TCP profile"},
663 {"rsound-tcp-pub6", ROAR_SOCKET_TYPE_TCP6,  ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET6_ANYHOST,
664                    ROAR_PROTO_RSOUND,    -1, NULL,
665                    "RSound network TCP profile"},
666#endif
667#ifdef ROAR_HAVE_LIBDNET
668 {"rsound-dnet",    ROAR_SOCKET_TYPE_DECNET, 0,                 ROAR_DEFAULT_RSOUND_OBJECT,
669                    ROAR_PROTO_RSOUND,    -1, NULL,
670                    "RSound DECnet profile"},
671#endif
672#endif
673
674 // PulseAudio Simple:
675#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
676#ifdef ROAR_HAVE_IPV4
677 {"pas-play-tcp",   ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PA_PORT, ROAR_NET_INET4_ANYHOST,
678                    ROAR_PROTO_SIMPLE, ROAR_DIR_PLAY, "default",
679                    "PulseAudio Simple TCP play profile"},
680 {"pas-mon-tcp",    ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PA_PORT, ROAR_NET_INET4_ANYHOST,
681                    ROAR_PROTO_SIMPLE, ROAR_DIR_MONITOR, "default",
682                    "PulseAudio Simple TCP monitor profile"},
683#endif
684#ifdef ROAR_HAVE_IPV6
685 {"pas-play-tcp6",  ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PA_PORT, ROAR_NET_INET6_ANYHOST,
686                    ROAR_PROTO_SIMPLE, ROAR_DIR_PLAY, "default",
687                    "PulseAudio Simple TCP play profile"},
688 {"pas-mon-tcp6",   ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PA_PORT, ROAR_NET_INET6_ANYHOST,
689                    ROAR_PROTO_SIMPLE, ROAR_DIR_MONITOR, "default",
690                    "PulseAudio Simple TCP monitor profile"},
691#endif
692#endif
693
694 // RPlay:
695#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
696#ifdef ROAR_HAVE_IPV4
697 {"rplay-tcp",      ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET4_LOCALHOST,
698                    ROAR_PROTO_RPLAY,     -1, NULL,
699                    "RPlay local TCP profile"},
700 {"rplay-tcp-pub",  ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET4_ANYHOST,
701                    ROAR_PROTO_RPLAY,     -1, NULL,
702                    "RPlay network TCP profile"},
703#endif
704#ifdef ROAR_HAVE_IPV6
705 {"rplay-tcp6",     ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET6_LOCALHOST,
706                    ROAR_PROTO_RPLAY,     -1, NULL,
707                    "RPlay local TCP profile"},
708 {"rplay-tcp-pub6", ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET6_ANYHOST,
709                    ROAR_PROTO_RPLAY,     -1, NULL,
710                    "RPlay network TCP profile"},
711#endif
712#endif
713
714// Gopher:
715#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
716#ifdef ROAR_HAVE_IPV4
717 {"gopher-tcp",     ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET4_LOCALHOST,
718                    ROAR_PROTO_GOPHER,    -1, NULL,
719                    "Gopher local TCP profile"},
720 {"gopher-tcp-pub", ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET4_ANYHOST,
721                    ROAR_PROTO_GOPHER,    -1, NULL,
722                    "Gopher network TCP profile"},
723#endif
724#ifdef ROAR_HAVE_IPV6
725 {"gopher-tcp6",    ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET6_LOCALHOST,
726                    ROAR_PROTO_GOPHER,    -1, NULL,
727                    "Gopher local TCP profile"},
728 {"gopher-tcp-pub6", ROAR_SOCKET_TYPE_TCP6,  ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET6_ANYHOST,
729                    ROAR_PROTO_GOPHER,    -1, NULL,
730                    "Gopher network TCP profile"},
731#endif
732#endif
733
734 // End of List:
735 {NULL, -1, -1, NULL, -1, -1, NULL, NULL}
736};
737
738void listen_listen_profiles (void) {
739 struct _listen_profile * p;
740 char * type;
741 int i;
742 char port[8];
743
744 printf("Name            Type    Address          Port    Protocol  Dir        Audio Profile - Description\n");
745 printf("-------------------------------------------------------------------------------------------------\n");
746      //roar-tcp-pub 0.0.0.0       16002   RoarAudio unknown    (null) - (null)
747
748 for (i = 0; (p = &(_g_listen_profiles[i]))->name != NULL; i++) {
749  switch (p->type) {
750   case ROAR_SOCKET_TYPE_UNIX:   type = "UNIX";   break;
751   case ROAR_SOCKET_TYPE_TCP:    type = "TCP";    break;
752   case ROAR_SOCKET_TYPE_DECNET: type = "DECnet"; break;
753   case ROAR_SOCKET_TYPE_TCP6:   type = "TCP6";   break;
754   default:
755     type = "unknown";
756    break;
757  }
758
759  if ( p->port ) {
760   snprintf(port, sizeof(port)-1, "%i", p->port);
761   port[sizeof(port)-1] = 0;
762  } else {
763   strcpy(port, "(none)");
764  }
765
766  printf("%-15s %-7s %-16s %-7s %-9s %-10s %-13s - %s\n",
767           p->name,
768           type,
769           p->sockaddr, port,
770           roar_proto2str(p->proto),
771           p->dir == -1 ? "(none)" : roar_dir2str(p->dir), p->aiprofile == NULL ? "(none)" : p->aiprofile,
772           p->desc == NULL ? "" : p->desc);
773 }
774}
775
776int get_listen_profile (const char * name,
777                        int * port, char ** sockaddr, int * type,
778                        int * proto,
779                        int * dir, struct roar_audio_info * info) {
780 static char buf[1024];
781 struct _listen_profile * p;
782 int i;
783
784 for (i = 0; (p = &(_g_listen_profiles[i]))->name != NULL; i++) {
785  if ( !strcasecmp(p->name, name) ) {
786   *port     = p->port;
787
788   if ( p->type == ROAR_SOCKET_TYPE_UNIX && p->sockaddr[0] != '+' ) {
789    roar_env_render_path_r(buf, sizeof(buf), p->sockaddr);
790   } else {
791    strncpy(buf, p->sockaddr, sizeof(buf));
792   }
793   *sockaddr = buf;
794   *type     = p->type;
795
796   *proto    = p->proto;
797   *dir      = p->dir;
798
799   if ( p->aiprofile != NULL ) {
800    if ( roar_profile2info(info, p->aiprofile) == -1 ) {
801     ROAR_ERR("Unknown audio profile: %s", p->aiprofile);
802     return -1;
803    }
804   }
805   return 0;
806  }
807 }
808
809 return -1;
810}
811#endif
812
813int add_listen (char * addr, int port, int sock_type, char * user, char * group, int proto, int dir, struct roar_audio_info * info) {
814#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
815 struct group   * grp  = NULL;
816#endif
817#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
818 struct passwd  * pwd  = NULL;
819#endif
820#ifdef ROAR_HAVE_UNIX
821 char * env_roar_proxy_backup;
822#endif
823 int    sockid = -1;
824#ifdef ROAR_HAVE_UNIX
825 int    sock;
826#endif
827 int    i;
828
829 ROAR_INFO("add_listen(addr='%s', port=%i, sock_type=%i, user='%s', group='%s', proto=%s(%i), dir=%s(%i), info={.rate=%u, .bits=%u, .channels=%u, .codec=%s(%u)}): trying to add listen socket",
830            ROAR_DBG_INFO_INFO,
831            addr, port, sock_type, user, group, roar_proto2str(proto), proto, roar_dir2str(dir), dir,
832            info->rate, info->bits, info->channels, roar_codec2str(info->codec), info->codec);
833
834 if ( *addr != 0 ) {
835  for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
836   if ( ! g_listen[i].used ) {
837    sockid = i;
838    break;
839   }
840  }
841
842  if ( sockid == -1 )
843   return -1;
844
845  g_listen[sockid].proto = proto;
846
847  ROAR_DBG("add_listen(*): proto=0x%.4x", proto);
848
849  if ( roar_vio_open_socket_listen(&(g_listen[sockid].sock), sock_type, addr, port) == -1 ) {
850#ifdef ROAR_HAVE_UNIX
851   if ( *addr == '/' ) {
852    if ( (env_roar_proxy_backup = getenv("ROAR_PROXY")) != NULL ) {
853     env_roar_proxy_backup = roar_mm_strdup(env_roar_proxy_backup);
854     unsetenv("ROAR_PROXY");
855    }
856    if ( (sock = roar_socket_connect(addr, port)) != -1 ) {
857     close(sock);
858     ROAR_ERR("Can not open listen socket: Socket allready in use");
859     return -1;
860    } else {
861     unlink(addr);
862     if ( roar_vio_open_socket_listen(&(g_listen[sockid].sock), sock_type, addr, port) == -1 ) {
863      ROAR_ERR("Can not open listen socket: %s", strerror(errno));
864      return -1;
865     }
866    }
867    if ( env_roar_proxy_backup != NULL ) {
868     setenv("ROAR_PROXY", env_roar_proxy_backup, 0);
869     roar_mm_free(env_roar_proxy_backup);
870    }
871#else
872   if (0) { // noop
873#endif
874   } else {
875    ROAR_ERR("Can not open listen socket: %s", strerror(errno));
876    return -1;
877   }
878  }
879
880  ROAR_DBG("add_listen(*) = ?");
881
882#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
883  if ( group != NULL ) {
884   if ( (grp = getgrnam(group)) == NULL ) {
885    ROAR_ERR("Can not get GID for group %s: %s", group, strerror(errno));
886   }
887  }
888#endif
889
890  ROAR_DBG("add_listen(*) = ?");
891
892#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
893  if ( user != NULL ) {
894   if ( (pwd = getpwnam(user)) == NULL ) {
895    ROAR_ERR("Can not get UID for user %s: %s", user, strerror(errno));
896   }
897  }
898#endif
899
900  ROAR_DBG("add_listen(*) = ?");
901
902#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_UNIX)
903  if ( *addr == '/' ) {
904   if ( grp != NULL || pwd != NULL ) {
905     if ( chown(addr, pwd != NULL ? pwd->pw_uid : -1, grp != NULL ? grp->gr_gid : -1) == -1 )
906      return -1;
907   }
908#ifdef ROAR_HAVE_GETUID
909   if ( grp != NULL ) {
910    if ( getuid() == 0 )
911     if ( chmod(addr, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1 )
912      return -1;
913   }
914#endif
915  }
916#endif
917 }
918
919 ROAR_DBG("add_listen(*) = ?");
920
921 // in case we opened the listening socket correctly.
922 if ( dir == -1 )
923  dir = ROAR_DIR_PLAY;
924
925 g_listen[sockid].inst.stpl.dir = dir;
926 memcpy(&(g_listen[sockid].inst.stpl.info), info, sizeof(struct roar_audio_info));
927
928 switch (dir) {
929  case ROAR_DIR_PLAY:
930  case ROAR_DIR_RECORD:
931  case ROAR_DIR_MONITOR:
932  case ROAR_DIR_FILTER:
933  case ROAR_DIR_BIDIR:
934    if ( !g_listen[sockid].inst.stpl.info.rate )
935     g_listen[sockid].inst.stpl.info.rate = g_sa->rate;
936
937    if ( !g_listen[sockid].inst.stpl.info.bits )
938     g_listen[sockid].inst.stpl.info.bits = g_sa->bits;
939
940    if ( !g_listen[sockid].inst.stpl.info.channels )
941     g_listen[sockid].inst.stpl.info.channels = g_sa->channels;
942
943    if ( !g_listen[sockid].inst.stpl.info.codec )
944     g_listen[sockid].inst.stpl.info.codec = g_sa->codec;
945   break;
946 }
947
948 g_listen[sockid].used = 1;
949 server[sockid]        = addr;
950
951 return 0;
952}
953#endif
954
955static void list_aiprofiles (void) {
956 struct roar_audio_info info;
957 const char * list[1024];
958 const char * mime;
959 ssize_t ret;
960 ssize_t i;
961
962 ret = roar_profiles_list(list, 1024, 0);
963
964 if ( ret == -1 )
965  return;
966
967 printf("  Name       Rate  Bits  Channels  Codec\n");
968 printf("---------------------------------------------\n");
969 for (i = 0; i < ret; i++) {
970  if ( roar_profile2info(&info, list[i]) == -1 ) {
971   printf("  %-10s --- unknown parameters ---\n", list[i]);
972   continue;
973  }
974
975  mime = roar_codec2mime(info.codec);
976
977  printf("  %-10s %5u %4u  %8u  %3u (%s%s%s%s)\n", list[i],
978            info.rate, info.bits, info.channels,
979            info.codec, roar_codec2str(info.codec),
980            info.codec == ROAR_CODEC_DEFAULT ? " native" : "",
981            mime == NULL ? "" : " mimetype:",
982            mime == NULL ? "" : mime
983        );
984 }
985}
986
987int update_stream_flags (char * str) {
988 int    dir;
989 char * flags;
990 char * k;
991 int    op;
992 int    flag;
993
994 if ( (flags = strstr(str, "=")) == NULL )
995  return -1;
996
997 *flags = 0;
998  flags++;
999
1000 if ( (dir = roar_str2dir(str)) == -1 )
1001  return -1;
1002
1003 while (flags != NULL) {
1004  k = flags;
1005  flags = strstr(flags, ",");
1006
1007  if ( flags != NULL )
1008   *(flags++) = 0;
1009
1010  switch (*k) {
1011   case '+': k++; op = ROAR_SET_FLAG;   break;
1012   case '-': k++; op = ROAR_RESET_FLAG; break;
1013   default:
1014     op = ROAR_SET_FLAG;
1015  }
1016
1017  flag = 0;
1018
1019  if ( !strcmp(k, "sync") ) {
1020   flag = ROAR_FLAG_SYNC;
1021  } else if ( !strcmp(k, "meta") ) {
1022   flag = ROAR_FLAG_META;
1023  } else if ( !strcmp(k, "cleanmeta") ) {
1024   flag = ROAR_FLAG_CLEANMETA;
1025  } else if ( !strcmp(k, "pause") ) {
1026   flag = ROAR_FLAG_PAUSE;
1027  } else if ( !strcmp(k, "mute") ) {
1028   flag = ROAR_FLAG_MUTE;
1029  } else if ( !strcmp(k, "antiecho") ) {
1030   flag = ROAR_FLAG_ANTIECHO;
1031  } else if ( !strcmp(k, "passmixer") ) {
1032   flag = ROAR_FLAG_PASSMIXER;
1033  } else if ( !strcmp(k, "recsource") ) {
1034   flag = ROAR_FLAG_RECSOURCE;
1035  } else {
1036   return -1;
1037  }
1038
1039  g_config->streams[dir].flags |= flag;
1040
1041  if ( op == ROAR_RESET_FLAG )
1042   g_config->streams[dir].flags -= flag;
1043 }
1044
1045 return 0;
1046}
1047
1048int add_authfile (const char * file, const char * type, enum af_mode mode, enum roard_client_acclev acclev) {
1049 struct roar_authfile * authfile = NULL;
1050 struct roar_authfile_key *  key = NULL;
1051 int af_type = ROAR_AUTHFILE_TYPE_AUTO;
1052 void * keydata;
1053 int i;
1054
1055 if ( type == NULL ) {
1056  // noop.
1057 } else if ( !strcasecmp(type, "roar") ) {
1058  af_type = ROAR_AUTHFILE_TYPE_ROAR;
1059 } else if ( !strcasecmp(type, "roar") ) {
1060  af_type = ROAR_AUTHFILE_TYPE_ROAR;
1061 } else if ( !strcasecmp(type, "esd") ) {
1062  af_type = ROAR_AUTHFILE_TYPE_ESD;
1063 } else if ( !strcasecmp(type, "pulse") ) {
1064  af_type = ROAR_AUTHFILE_TYPE_PULSE;
1065 } else if ( !strcasecmp(type, "htpasswd") ) {
1066  af_type = ROAR_AUTHFILE_TYPE_HTPASSWD;
1067 } else if ( !strcasecmp(type, "xauth") ) {
1068  af_type = ROAR_AUTHFILE_TYPE_XAUTH;
1069 } else {
1070  ROAR_ERR("add_authfile(*): unknown authfile type '%s'.", type);
1071  return -1;
1072 }
1073
1074 if ( mode == AF_MODE_GEN && af_type == ROAR_AUTHFILE_TYPE_AUTO )
1075  af_type = ROAR_AUTHFILE_TYPE_ESD;
1076
1077 switch (mode) {
1078  case AF_MODE_NONE:
1079    return 0;
1080   break;
1081  case AF_MODE_GEN:
1082    switch (af_type) {
1083     case ROAR_AUTHFILE_TYPE_ESD:
1084       key = roar_authfile_key_new_random(ROAR_AUTH_T_COOKIE, 16, NULL);
1085      break;
1086     case ROAR_AUTHFILE_TYPE_PULSE:
1087       key = roar_authfile_key_new_random(ROAR_AUTH_T_COOKIE, 256, NULL);
1088      break;
1089     default:
1090       return -1;
1091      break;
1092    }
1093
1094    if ( key == NULL ) {
1095     ROAR_ERR("add_authfile(*): Can not generate key.");
1096     return -1;
1097    }
1098
1099    if ( (authfile = roar_authfile_open(af_type, file, 1, ROAR_AUTHFILE_VERSION_AUTO)) == NULL ) {
1100     roar_authfile_key_unref(key);
1101     return -1;
1102    }
1103
1104    if ( roar_authfile_add_key(authfile, key) == -1 ) {
1105     ROAR_WARN("add_authfile(*): Can not add key to authfile.");
1106    }
1107
1108    keydata = roar_mm_memdup(key->data, key->len);
1109
1110    if ( keydata == NULL ) {
1111     ROAR_WARN("add_authfile(*): Can not allocate memory for key.");
1112    } else if ( auth_addkey_cookie(acclev, keydata, key->len) == -1 ) {
1113     ROAR_WARN("add_authfile(*): Can not add key to internal key storage.");
1114    }
1115
1116    roar_authfile_key_unref(key);
1117    if ( roar_authfile_close(authfile) != 0 )
1118     return -1;
1119    return 0;
1120   break;
1121  case AF_MODE_LOAD:
1122    if ( (authfile = roar_authfile_open(af_type, file, 0, ROAR_AUTHFILE_VERSION_AUTO)) == NULL ) {
1123     return -1;
1124    }
1125
1126    for (i = 0; ; i++) {
1127     key = roar_authfile_lookup_key(authfile, ROAR_AUTH_T_AUTO, i, NULL);
1128     if ( key == NULL )
1129      break;
1130
1131     if ( key->type == ROAR_AUTH_T_COOKIE ) {
1132      keydata = roar_mm_memdup(key->data, key->len);
1133
1134      if ( keydata == NULL ) {
1135       ROAR_WARN("add_authfile(*): Can not allocate memory for key.");
1136      } else if ( auth_addkey_cookie(acclev, keydata, key->len) == -1 ) {
1137       ROAR_WARN("add_authfile(*): Can not add key to internal key storage.");
1138      }
1139     } else {
1140      ROAR_WARN("add_authfile(*): Unknown key type: %i", key->type);
1141     }
1142
1143     roar_authfile_key_unref(key);
1144    }
1145
1146    if ( roar_authfile_close(authfile) != 0 )
1147     return -1;
1148    return 0;
1149   break;
1150 }
1151
1152 return -1;
1153}
1154
1155// X11:
1156#ifdef ROAR_HAVE_LIBX11
1157int register_x11 (int unreg, char * sockname) {
1158 struct roar_x11_connection * x11con = NULL;
1159 int ret = 0;
1160
1161 if ( (x11con = roar_x11_connect(x11display)) == NULL ) {
1162  ROAR_ERR("Can not connect to X11 server for %sregistering", unreg ? "un" : "");
1163  return -1;
1164 }
1165
1166 if ( unreg ) {
1167  if ( roar_x11_delete_prop(x11con, "ROAR_SERVER") == -1 ) {
1168   ret = -1;
1169   ROAR_ERR("Error while unregistereing from X11", ROAR_DBG_INFO_INFO);
1170  } else {
1171   ROAR_INFO("Successfully unregistered from X11", ROAR_DBG_INFO_INFO);
1172  }
1173 } else {
1174  if ( roar_x11_set_prop(x11con, "ROAR_SERVER", sockname) == -1 ) {
1175   ret = -1;
1176   ROAR_ERR("Error while registereing to X11", ROAR_DBG_INFO_INFO);
1177  } else {
1178   ROAR_INFO("Successfully registered to X11", ROAR_DBG_INFO_INFO);
1179  }
1180 }
1181
1182 roar_x11_disconnect(x11con);
1183
1184 return ret;
1185}
1186#endif
1187
1188// SLP:
1189void register_slp_callback(SLPHandle hslp, SLPError errcode, void * cookie) {
1190 /* return the error code in the cookie */
1191 *(SLPError*)cookie = errcode;
1192}
1193
1194int register_slp (int unreg, char * sockname) {
1195#ifdef ROAR_HAVE_LIBSLP
1196 static int regged = 0;
1197 static char * sn = NULL;
1198 SLPError err;
1199 SLPError callbackerr;
1200 SLPHandle hslp;
1201 char addr[1024];
1202 char attr[1024] = "";
1203 char * location;
1204 char * description;
1205 char * standards;
1206
1207 if ( sockname != NULL )
1208  sn = sockname;
1209
1210 snprintf(addr, sizeof(addr), ROAR_SLP_URL_TYPE_ROAR "://%s", sn);
1211
1212 err = SLPOpen("en", SLP_FALSE, &hslp);
1213
1214 if (err != SLP_OK) {
1215  ROAR_ERR("Error opening slp handle: Error #%i", err);
1216  return -1;
1217 }
1218
1219 if (!unreg) {
1220
1221  if ( SLPEscape(g_config->location, &location, SLP_FALSE) != SLP_OK ) {
1222   ROAR_ERR("Error using SLPEscape() on server location, really bad!");
1223   SLPClose(hslp);
1224   return -1;
1225  }
1226
1227  if ( SLPEscape(g_config->description, &description, SLP_FALSE) != SLP_OK ) {
1228   ROAR_ERR("Error using SLPEscape() on server location, really bad!");
1229   SLPClose(hslp);
1230   return -1;
1231  }
1232
1233  standards = stds_string();
1234
1235  if ( standards == NULL ) {
1236   if ( (standards = roar_mm_malloc(1)) == NULL ) {
1237    SLPClose(hslp);
1238    return -1;
1239   }
1240   standards[0] = 0;
1241  }
1242
1243  snprintf(attr, sizeof(attr), "(wave-rate=%i),(wave-channels=%i),(wave-bits=%i),"
1244#ifndef ROAR_WITHOUT_DCOMP_LIGHT
1245                               "(light-channels=%i),"
1246#endif
1247                               "(standards=%s),"
1248                               "(location=%s),(description=%s)",
1249           g_sa->rate, g_sa->channels, g_sa->bits,
1250#ifndef ROAR_WITHOUT_DCOMP_LIGHT
1251           g_light_state.channels,
1252#endif
1253           standards,
1254           location, description
1255          );
1256
1257  roar_mm_free(standards);
1258
1259  /* Register a service with SLP */
1260  err = SLPReg(hslp,
1261               addr,
1262               SLP_LIFETIME_MAXIMUM,
1263               0,
1264               attr,
1265               SLP_TRUE,
1266               register_slp_callback,
1267               &callbackerr);
1268  regged = 1;
1269 } else if ( unreg && regged ) {
1270  err = SLPDereg(hslp, addr, register_slp_callback, &callbackerr);
1271  regged = 0;
1272 } else {
1273  SLPClose(hslp);
1274  return -1;
1275 }
1276
1277 /* err may contain an error code that occurred as the slp library    */
1278 /* _prepared_ to make the call.                                     */
1279 if ( err != SLP_OK ) {
1280  ROAR_ERR("Error (de)registering service with slp: Error #%i", err);
1281  return -1;
1282 }
1283
1284 /* callbackerr may contain an error code (that was assigned through */
1285 /* the callback cookie) that occurred as slp packets were sent on    */
1286 /* the wire */
1287 if (callbackerr != SLP_OK) {
1288  ROAR_ERR("Error (de)registering service with slp: Error #%i", callbackerr);
1289  return -1;
1290 }
1291
1292 SLPClose(hslp);
1293 return 0;
1294#else
1295 return -1;
1296#endif
1297}
1298
1299static int auth_setup (enum roard_client_acclev none_acclev,
1300                       enum roard_client_acclev trust_acclev, int trust_root, uid_t trust_uid, gid_t trust_gid) {
1301 union auth_typeunion * key;
1302 size_t i;
1303
1304 // Info:
1305 // if a authlevel is <= ACCLEV_IDENTED we do not need to add this to the keyring
1306 // as ACCLEV_IDENTED is already gained if IDENTIFY call was done correctly.
1307
1308 if ( !(none_acclev <= ACCLEV_IDENTED) ) {
1309  if ( auth_addkey_anonymous(none_acclev) == -1 )
1310   return -1;
1311 }
1312
1313 if ( !(trust_acclev <= ACCLEV_IDENTED) ) {
1314  if ( (key = auth_regkey_simple(ROAR_AUTH_T_TRUST, trust_acclev)) == NULL )
1315   return -1;
1316
1317  // zerosize all counters.
1318  memset(key, 0, sizeof(union auth_typeunion));
1319
1320  i = 0;
1321
1322  if ( trust_uid != -1 )
1323   key->trust.uids[i++] = trust_uid;
1324
1325#ifdef ROAR_ROOT_UID
1326  if ( trust_root )
1327   key->trust.uids[i++] = ROAR_ROOT_UID;
1328#endif
1329
1330  key->trust.uids_len = i;
1331
1332  i = 0;
1333
1334  if ( trust_gid != -1 )
1335   key->trust.gids[i++] = trust_gid;
1336
1337  key->trust.gids_len = i;
1338 }
1339
1340 return 0;
1341}
1342
1343
1344// MAIN:
1345
1346#define _CKHAVEARGS(x) if ( (i + (x)) >= argc ) { \
1347                        ROAR_ERR("Option %s requires more arguments. See --help for more details.", k); \
1348                        return 70; \
1349                       }
1350
1351#ifdef ROAR_HAVE_MAIN_ARGS
1352int main (int argc, char * argv[]) {
1353#else
1354int main (void) {
1355#endif
1356#ifdef ROAR_HAVE_MAIN_ARGS
1357 enum action action = START;
1358 int i;
1359 char * k;
1360 enum output_format print_format = FORMAT_NATIVE;
1361#endif
1362#if defined(ROAR_SUPPORT_LISTEN) && defined(ROAR_HAVE_GETUID)
1363 char user_sock[80]  = {0};
1364#endif
1365 struct roar_audio_info sa, max_sa;
1366 struct roard_config config;
1367 const struct rolestack * rolestack;
1368#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
1369 int    daemon       = 0;
1370#endif
1371 int    realtime     = 0;
1372 int    sysclocksync = 0;
1373// char * server = ROAR_DEFAULT_SOCK_GLOBAL;
1374#ifdef ROAR_SUPPORT_LISTEN
1375 int    port       = ROAR_DEFAULT_PORT;
1376 char * sock_addr  = NULL;
1377 int    sock_proto = ROAR_PROTO_ROARAUDIO;
1378 int    sock_dir   = -1;
1379 struct roar_audio_info sock_info = {0, 0, 0, 0};
1380#endif
1381#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1382 char * s_drv     = NULL;
1383 char * s_dev     = NULL;
1384 char * s_con     = NULL;
1385 char * s_opt     = NULL;
1386 int    s_prim    = 0;
1387#endif
1388 char * o_drv     = getenv("ROAR_DRIVER");
1389 char * o_dev     = getenv("ROAR_DEVICE");
1390 char * o_opts    = NULL;
1391 int    o_prim    = 0;
1392 int    o_count   = 0;
1393#ifndef ROAR_WITHOUT_DCOMP_MIXER
1394 char * m_drv     = NULL;
1395 char * m_dev     = NULL;
1396 char * m_opts    = NULL;
1397 int    m_prim    = 0;
1398 int    m_count   = 0;
1399#endif
1400 enum roard_client_acclev none_acclev  = ACCLEV_ALL;
1401 enum roard_client_acclev trust_acclev = ACCLEV_ALL;
1402 int                      trust_root   = 1;
1403 char * af_file                        = NULL;
1404 char * af_type                        = NULL;
1405 enum af_mode af_mode                  = AF_MODE_NONE;
1406 enum roard_client_acclev af_acclev    = ACCLEV_ALL;
1407#ifndef ROAR_WITHOUT_DCOMP_LIGHT
1408 int    light_channels = LIGHT_CHANNELS_DEFAULT;
1409#endif
1410#ifdef ROAR_DEFAULT_SOCKGRP
1411 char * sock_grp  = ROAR_DEFAULT_SOCKGRP;
1412#else
1413 char * sock_grp  = NULL;
1414#endif
1415 char * sock_user = NULL;
1416#ifdef ROAR_SUPPORT_LISTEN
1417 int    sock_type = ROAR_SOCKET_TYPE_UNKNOWN;
1418#endif
1419#ifdef ROAR_HAVE_LIBSLP
1420 int    reg_slp   = 0;
1421#endif
1422#ifdef ROAR_HAVE_LIBX11
1423 int    reg_x11   = 0;
1424#endif
1425#ifdef ROAR_HAVE_CHROOT
1426 char * chrootdir = NULL;
1427#endif
1428#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
1429 struct group   * grp  = NULL;
1430#endif
1431#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
1432 struct passwd  * pwd  = NULL;
1433#endif
1434#ifdef ROAR_HAVE_GETSERVBYNAME
1435 struct servent * serv = NULL;
1436#endif
1437 struct roar_client * self = NULL;
1438#ifdef ROAR_HAVE_LIBDNET
1439 char decnethost[80];
1440#endif
1441#ifdef SUPPORT_PIDFILE
1442 struct roar_vio_calls pidfile_vio;
1443#endif
1444
1445 ROAR_DBG("main(*): starting roard...");
1446
1447 g_standby       =  0;
1448 g_autostandby   =  0;
1449 alive           =  1;
1450#ifdef ROAR_SUPPORT_LISTEN
1451 g_no_listen     =  0;
1452#else
1453 g_terminate     =  1;
1454#endif
1455
1456 g_verbose       = ROAR_DBG_INFO_NONE;
1457
1458 _LIBROAR_IGNORE_RET(roar_profile2info(&sa, "default-server"));
1459
1460 g_sa        = &sa;
1461 g_max_sa    = &max_sa;
1462
1463 memcpy(g_max_sa, g_sa, sizeof(max_sa));
1464
1465 counters_init();
1466
1467 g_config = &config;
1468
1469 if ( init_config() == -1 ) {
1470  ROAR_ERR("Can not init default config!");
1471  return 1;
1472 }
1473
1474 // load config
1475 _LIBROAR_IGNORE_RET(roar_libroar_get_config());
1476
1477 // init notify core:
1478 // TODO: reconsider number of lists.
1479 if ( roar_notify_core_new_global(-1) == -1 ) {
1480  ROAR_ERR("Can not init notify core!");
1481  return 1;
1482 }
1483
1484 if ( roar_notify_core_register_proxy(NULL, roar_notify_proxy_std, NULL) == -1 ) {
1485  ROAR_ERR("Can not init notify core!");
1486  return 1;
1487 }
1488
1489#ifdef DEBUG
1490 // enable early in case we have DEBUG set.
1491 dbg_notify_cb_register();
1492#endif
1493
1494 rolestack_init();
1495
1496 if ( auth_init() == -1 ) {
1497  ROAR_ERR("Can not init auth subsystem!");
1498  return 1;
1499 }
1500
1501#ifdef ROAR_SUPPORT_LISTEN
1502 if ( init_listening() == -1 ) {
1503  ROAR_ERR("Can not init listening sockets!");
1504  return 1;
1505 }
1506#endif
1507
1508#ifndef ROAR_WITHOUT_DCOMP_MIDI
1509 if ( midi_init_config() == -1 ) {
1510  ROAR_ERR("Can not init MIDI config!");
1511  return 1;
1512 }
1513#endif
1514
1515#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
1516 if ( ssynth_init_config() == -1 ) {
1517  ROAR_ERR("Can not init ssynth config!");
1518  return 1;
1519 }
1520#endif
1521
1522#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1523 if ( rdtcs_init_config() == -1 ) {
1524  ROAR_ERR("Can not init RDTCS config!");
1525  return 1;
1526 }
1527#endif
1528
1529 if ( plugins_preinit() == -1 ) {
1530  ROAR_ERR("Can not pre-init plugins!");
1531  return 1;
1532 }
1533
1534#ifdef ROAR_SUPPORT_LISTEN
1535#ifndef ROAR_TARGET_WIN32
1536 sock_addr = ROAR_DEFAULT_SOCK_GLOBAL;
1537#else
1538 sock_addr = ROAR_DEFAULT_HOST;
1539#endif
1540
1541#ifdef ROAR_HAVE_GETUID
1542 if ( getuid() != 0 && getenv("HOME") != NULL ) {
1543/*
1544  snprintf(user_sock, 79, "%s/%s", (char*)getenv("HOME"), ROAR_DEFAULT_SOCK_USER);
1545*/
1546  roar_env_render_path_r(user_sock, sizeof(user_sock), "~/" ROAR_DEFAULT_SOCK_USER);
1547  sock_addr = user_sock;
1548  ROAR_DBG("main(*): setting sock_addr='%s'", sock_addr);
1549 }
1550#endif
1551
1552 if ( getenv("ROAR_SERVER") != NULL )
1553  sock_addr = getenv("ROAR_SERVER");
1554#endif
1555
1556 if ( clients_init() == -1 ) {
1557  ROAR_ERR("Can not init clients!");
1558  return 1;
1559 }
1560
1561 if ( streams_init() == -1 ) {
1562  ROAR_ERR("Can not init streams!");
1563  return 1;
1564 }
1565
1566 if ( (g_self_client = clients_new()) == -1 ) {
1567  ROAR_ERR("Can not create self client!");
1568  return 1;
1569 }
1570
1571#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1572 if ( sources_init() == -1 ) {
1573  ROAR_ERR("Can not init sources!");
1574  return 1;
1575 }
1576
1577 if ( (sources_set_client(g_self_client)) == -1 ) {
1578  ROAR_ERR("Can not init set source client!");
1579  return 1;
1580 }
1581#endif
1582
1583#ifdef ROAR_HAVE_MAIN_ARGS
1584 for (i = 1; i < argc; i++) {
1585  k = argv[i];
1586
1587  if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) {
1588   usage();
1589   return 0;
1590
1591  } else if ( strcmp(k, "--start") == 0 ) {
1592   // this is a no op
1593   action = START;
1594  } else if ( strcmp(k, "--restart") == 0 ) {
1595   action = RESTART;
1596#ifdef ROAR_SUPPORT_LISTEN
1597   if ( restart_server(sock_addr, 1) == -1 ) {
1598    ROAR_WARN("Can not terminate old server (not running at %s?), will retry later.", sock_addr);
1599    action = RESTART_RETRY;
1600   }
1601#else
1602   ROAR_ERR("--restart not supported");
1603#endif
1604  } else if ( strcmp(k, "--shutdown") == 0 ) {
1605   action = SHUTDOWN;
1606  } else if ( strcmp(k, "--stop") == 0 ) {
1607   action = STOP;
1608
1609
1610  } else if ( strcmp(k, "--demon") == 0 || strcmp(k, "--daemon") == 0 ) {
1611#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
1612   daemon = 1;
1613#else
1614   ROAR_ERR("--daemon not supported");
1615#endif
1616  } else if ( strcmp(k, "--verbose") == 0 ) {
1617   g_verbose++;
1618
1619  } else if ( strcmp(k, "--print-format") == 0 ) {
1620   k = argv[++i];
1621   if ( !strcasecmp(k, "native") ) {
1622    print_format = FORMAT_NATIVE;
1623   } else if ( !strcasecmp(k, "wiki") ) {
1624    print_format = FORMAT_WIKI;
1625   } else if ( !strcasecmp(k, "csv") ) {
1626    print_format = FORMAT_CSV;
1627   } else {
1628    ROAR_WARN("Unknown print format: %s", k);
1629   }
1630
1631  } else if ( strcmp(k, "--print-format") == 0 ) {
1632   _CKHAVEARGS(1);
1633
1634  } else if ( strcmp(k, "--terminate") == 0 ) {
1635   g_terminate = 1;
1636  } else if ( strcmp(k, "--sysclocksync") == 0 ) {
1637   sysclocksync = 1000;
1638  } else if ( strcmp(k, "--realtime") == 0 ) {
1639   realtime++;
1640  } else if ( strcmp(k, "--memlock") == 0 ) {
1641   _CKHAVEARGS(1);
1642   g_config->memlock_level = memlock_str2level(argv[++i]);
1643  } else if ( strcmp(k, "--chroot") == 0 ) {
1644   _CKHAVEARGS(1);
1645#ifdef ROAR_HAVE_CHROOT
1646   chrootdir = argv[++i];
1647#else
1648   ROAR_ERR("--chroot not supported");
1649   i++;
1650#endif
1651  } else if ( strcmp(k, "--setgid") == 0 ) {
1652#ifdef ROAR_HAVE_SETGID
1653   setids |= R_SETGID;
1654#else
1655   ROAR_ERR("--setgid not supported");
1656#endif
1657  } else if ( strcmp(k, "--setuid") == 0 ) {
1658#ifdef ROAR_HAVE_SETUID
1659   setids |= R_SETUID;
1660#else
1661   ROAR_ERR("--setuid not supported");
1662#endif
1663  } else if ( strcmp(k, "--location") == 0 ) {
1664   _CKHAVEARGS(1);
1665   g_config->location = argv[++i];
1666  } else if ( strcmp(k, "--description") == 0 ) {
1667   _CKHAVEARGS(1);
1668   g_config->description = argv[++i];
1669  } else if ( strcmp(k, "--pidfile") == 0 ) {
1670   _CKHAVEARGS(1);
1671#ifdef SUPPORT_PIDFILE
1672   pidfile = argv[++i];
1673#else
1674   ROAR_ERR("--pidfile not supported");
1675   i++;
1676#endif
1677  } else if ( strcmp(k, "--log-syslog") == 0 ) {
1678#ifdef ROAR_HAVE_SYSLOG
1679   roar_debug_set_stderr_mode(ROAR_DEBUG_MODE_SYSLOG);
1680#else
1681   ROAR_ERR("--log-syslog not supported");
1682#endif
1683  } else if ( strcmp(k, "--script-postdown") == 0 ) {
1684   _CKHAVEARGS(1);
1685#ifdef ROAR_HAVE_SYSTEM
1686   g_config->scripts.post_shutdown = argv[++i];
1687#else
1688   ROAR_ERR("--script-postdown not supported");
1689   i++;
1690#endif
1691
1692
1693  } else if ( strcmp(k, "--plugin-load") == 0 ) {
1694   _CKHAVEARGS(1);
1695   if ( plugins_load(argv[++i]) == -1 ) {
1696    ROAR_ERR("Can not load plugin");
1697   }
1698
1699  } else if ( strcmp(k, "--guest-acclev") == 0 ) {
1700   _CKHAVEARGS(1);
1701   none_acclev = clients_str2acclev(argv[++i]);
1702   if ( none_acclev == -1 ) {
1703    ROAR_ERR("Invalid access level: %s", argv[i]);
1704    return 1;
1705   }
1706  } else if ( strcmp(k, "--trust-acclev") == 0 ) {
1707   _CKHAVEARGS(1);
1708   trust_acclev = clients_str2acclev(argv[++i]);
1709   if ( trust_acclev == -1 ) {
1710    ROAR_ERR("Invalid access level: %s", argv[i]);
1711    return 1;
1712   }
1713  } else if ( strcmp(k, "--trust-root") == 0 ) {
1714   trust_root = 1;
1715  } else if ( strcmp(k, "--no-trust-root") == 0 ) {
1716   trust_root = 0;
1717
1718  } else if ( strcmp(k, "--authfile-gen") == 0 ) {
1719   _CKHAVEARGS(1);
1720   af_file = argv[++i];
1721   af_mode = AF_MODE_GEN;
1722  } else if ( strcmp(k, "--authfile-load") == 0 ) {
1723   _CKHAVEARGS(1);
1724   af_file = argv[++i];
1725   af_mode = AF_MODE_LOAD;
1726  } else if ( strcmp(k, "--authfile-type") == 0 ) {
1727   _CKHAVEARGS(1);
1728   af_type = argv[++i];
1729  } else if ( strcmp(k, "--authfile-acclev") == 0 ) {
1730   _CKHAVEARGS(1);
1731   af_acclev = clients_str2acclev(argv[++i]);
1732  } else if ( strcmp(k, "--new-authfile") == 0 ) {
1733   if ( af_mode != AF_MODE_NONE ) {
1734    if ( add_authfile(af_file, af_type, af_mode, af_acclev) == -1 ) {
1735     ROAR_ERR("main(*): adding authfile '%s' failed!", af_file);
1736    }
1737   }
1738   af_file   = NULL;
1739   af_type   = NULL;
1740   af_mode   = AF_MODE_NONE;
1741   af_acclev = ACCLEV_ALL;
1742
1743  } else if ( strcmp(k, "--list-cf") == 0 ) {
1744   print_codecfilterlist();
1745   return 0;
1746
1747  } else if ( strcmp(k, "-R") == 0 || strcmp(k, "--rate") == 0 ) {
1748   _CKHAVEARGS(1);
1749   sa.rate = atoi(argv[++i]);
1750  } else if ( strcmp(k, "-B") == 0 || strcmp(k, "--bits") == 0 ) {
1751   _CKHAVEARGS(1);
1752   sa.bits = atoi(argv[++i]);
1753  } else if ( strcmp(k, "-C") == 0 || strcmp(k, "--chans") == 0 ) {
1754   _CKHAVEARGS(1);
1755   sa.channels = atoi(argv[++i]);
1756
1757  } else if ( strcmp(k, "--aiprofile") == 0 ) {
1758   _CKHAVEARGS(1);
1759   if ( roar_profile2info(&sa, argv[++i]) == -1 ) {
1760    ROAR_ERR("Unknown audio profile: %s", argv[i]);
1761    return 1;
1762   }
1763   sa.codec    = ROAR_CODEC_DEFAULT;
1764
1765  } else if ( strcmp(k, "--stream-flags") == 0 ) {
1766   _CKHAVEARGS(1);
1767   if ( update_stream_flags(argv[++i]) == -1 ) {
1768    ROAR_ERR("Can not set stream flags");
1769    return 1;
1770   }
1771
1772  } else if ( strcmp(k, "--list-rolestack") == 0 ) {
1773   print_rolestack();
1774   return 0;
1775  } else if ( strcmp(k, "--rolestack-push") == 0 ) {
1776   _CKHAVEARGS(1);
1777  if ( (rolestack = rolestack_parse(argv[++i])) == NULL ) {
1778   ROAR_ERR("Can not parse rolestack request: %s", roar_error2str(roar_error));
1779  } else {
1780   if ( rolestack_push(rolestack) == -1 ) {
1781    ROAR_ERR("Can not push request to rolestack: %s", roar_error2str(roar_error));
1782   }
1783  }
1784
1785  } else if ( strcmp(k, "--list-aiprofiles") == 0 ) {
1786   list_aiprofiles();
1787   return 0;
1788
1789  } else if ( strcmp(k, "--list-driver") == 0 ) {
1790   print_driverlist(print_format);
1791   return 0;
1792
1793  } else if ( strcmp(k, "-o") == 0 || strcmp(k, "--odriver") == 0 ) {
1794   _CKHAVEARGS(1);
1795   o_drv  = argv[++i];
1796  } else if ( strcmp(k, "-O") == 0 || strcmp(k, "--odevice") == 0 ) {
1797   _CKHAVEARGS(1);
1798   o_dev  = argv[++i];
1799  } else if ( strcmp(k, "-oO") == 0 ) {
1800   _CKHAVEARGS(1);
1801   o_opts = argv[++i];
1802  } else if ( strcmp(k, "-oP") == 0 ) {
1803   o_prim = 1;
1804  } else if ( strcmp(k, "-oN") == 0 ) {
1805   if ( action == START || action == RESTART ) {
1806    if ( output_add(o_drv, o_dev, o_opts, o_prim, o_count) != -1 )
1807     o_count++;
1808
1809    o_drv  = o_dev = o_opts = NULL;
1810    o_prim = 0;
1811   }
1812
1813  } else if ( strcmp(k, "-s") == 0 || strcmp(k, "--source") == 0 ) {
1814   _CKHAVEARGS(1);
1815#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1816   s_drv = argv[++i];
1817#else
1818   ROAR_ERR("main(*): No support for sources compiled in");
1819   i++;
1820#endif
1821  } else if ( strcmp(k, "-S") == 0 ) {
1822   _CKHAVEARGS(1);
1823#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1824   s_dev = argv[++i];
1825#else
1826   ROAR_ERR("main(*): No support for sources compiled in");
1827   i++;
1828#endif
1829  } else if ( strcmp(k, "-sO") == 0 ) {
1830   _CKHAVEARGS(1);
1831#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1832   s_opt = argv[++i];
1833#else
1834   ROAR_ERR("main(*): No support for sources compiled in");
1835   i++;
1836#endif
1837  } else if ( strcmp(k, "-sC") == 0 ) {
1838   _CKHAVEARGS(1);
1839#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1840   s_con = argv[++i];
1841#else
1842   ROAR_ERR("main(*): No support for sources compiled in");
1843   i++;
1844#endif
1845  } else if ( strcmp(k, "-sP") == 0 ) {
1846#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1847   s_prim = 1;
1848#else
1849   ROAR_ERR("main(*): No support for sources compiled in");
1850#endif
1851  } else if ( strcmp(k, "-sN") == 0 ) {
1852#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1853   if ( sources_add(s_drv, s_dev, s_con, s_opt, s_prim) == -1 ) {
1854    ROAR_ERR("main(*): adding source '%s' via '%s' failed!", s_dev, s_drv);
1855   }
1856   s_opt = s_dev = s_con = NULL;
1857   s_drv = NULL;
1858   s_prim = 0;
1859#else
1860   ROAR_ERR("main(*): No support for sources compiled in");
1861#endif
1862  } else if ( strcmp(k, "--list-sources") == 0 ) {
1863#ifndef ROAR_WITHOUT_DCOMP_SOURCES
1864   print_sourcelist();
1865   return 0;
1866#else
1867   ROAR_ERR("main(*): No support for sources compiled in");
1868   return 1;
1869#endif
1870
1871  } else if ( strcmp(k, "-m") == 0 || strcmp(k, "--mixer") == 0 ) {
1872   _CKHAVEARGS(1);
1873#ifndef ROAR_WITHOUT_DCOMP_MIXER
1874   m_drv  = argv[++i];
1875#else
1876   ROAR_ERR("main(*): No support for mixer compiled in");
1877   return 1;
1878#endif
1879  } else if ( strcmp(k, "-M") == 0 ) {
1880   _CKHAVEARGS(1);
1881#ifndef ROAR_WITHOUT_DCOMP_MIXER
1882   m_dev  = argv[++i];
1883#else
1884   ROAR_ERR("main(*): No support for mixer compiled in");
1885   return 1;
1886#endif
1887  } else if ( strcmp(k, "-mO") == 0 ) {
1888   _CKHAVEARGS(1);
1889#ifndef ROAR_WITHOUT_DCOMP_MIXER
1890   m_opts = argv[++i];
1891#else
1892   ROAR_ERR("main(*): No support for mixer compiled in");
1893   return 1;
1894#endif
1895  } else if ( strcmp(k, "-mP") == 0 ) {
1896#ifndef ROAR_WITHOUT_DCOMP_MIXER
1897   m_prim = 1;
1898#else
1899   ROAR_ERR("main(*): No support for mixer compiled in");
1900   return 1;
1901#endif
1902  } else if ( strcmp(k, "-mN") == 0 ) {
1903#ifndef ROAR_WITHOUT_DCOMP_MIXER
1904   if ( hwmixer_add(m_drv, m_dev, m_opts, m_prim, m_count) != -1 )
1905    m_count++;
1906
1907   m_drv  = o_dev = o_opts = NULL;
1908   m_prim = 0;
1909#else
1910   ROAR_ERR("main(*): No support for mixer compiled in");
1911   return 1;
1912#endif
1913  } else if ( strcmp(k, "--list-mixers") == 0 ) {
1914#ifndef ROAR_WITHOUT_DCOMP_MIXER
1915   print_hwmixerlist();
1916   return 0;
1917#else
1918   ROAR_ERR("main(*): No support for mixer compiled in");
1919   return 1;
1920#endif
1921
1922  } else if ( strcmp(k, "--light-channels") == 0 ) {
1923   _CKHAVEARGS(1);
1924#ifndef ROAR_WITHOUT_DCOMP_LIGHT
1925   light_channels = atoi(argv[++i]);
1926#else
1927   ROAR_WARN("main(*): no light subsystem compiled in");
1928   i++;
1929#endif
1930
1931  } else if ( strcmp(k, "--rds-pi") == 0 ) {
1932   _CKHAVEARGS(1);
1933#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1934   g_rdtcs.rds.pi = atoi(argv[++i]);
1935#else
1936   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1937   i++;
1938#endif
1939  } else if ( strcmp(k, "--rds-ps") == 0 ) {
1940   _CKHAVEARGS(1);
1941#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1942   if ( rdtcs_rds_set_ps(argv[++i]) == -1 ) {
1943    ROAR_ERR("Can not set RDS PS to '%s' (longer than 8 chars?)", argv[i]);
1944    return 1;
1945   }
1946#else
1947   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1948   i++;
1949#endif
1950  } else if ( strcmp(k, "--rds-pty") == 0 ) {
1951   _CKHAVEARGS(1);
1952#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1953   if ( rdtcs_rds_set_pty(argv[++i]) == -1 ) {
1954    ROAR_ERR("Can not set RDS PTY to '%s'", argv[i]);
1955    return 1;
1956   }
1957#else
1958   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1959   i++;
1960#endif
1961  } else if ( strcmp(k, "--rds-tp") == 0 ) {
1962#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1963   if ( rdtcs_rds_set_flag(RDTCS_RDS_FLAG_TP, 0) == -1 ) {
1964    ROAR_ERR("Can not set RDS TP flag");
1965    return 1;
1966   }
1967#else
1968   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1969#endif
1970  } else if ( strcmp(k, "--rds-ct") == 0 ) {
1971#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1972   if ( rdtcs_rds_set_flag(RDTCS_RDS_FLAG_CT, 0) == -1 ) {
1973    ROAR_ERR("Can not set RDS CT flag");
1974    return 1;
1975   }
1976#else
1977   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1978#endif
1979
1980
1981  } else if ( strcmp(k, "--midi-no-console") == 0 ) {
1982#ifndef ROAR_WITHOUT_DCOMP_CB
1983   midi_config.init_cb = 0;
1984#else
1985   // no warning here as this is the disable option
1986#endif
1987  } else if ( strcmp(k, "--midi-console-enable") == 0 ) {
1988#ifndef ROAR_WITHOUT_DCOMP_CB
1989   midi_config.init_cb = 1;
1990#else
1991   ROAR_ERR("main(*): No support for MIDI subsystem part CB compiled in");
1992#endif
1993  } else if ( strcmp(k, "--midi-console") == 0 ) {
1994   _CKHAVEARGS(1);
1995#ifndef ROAR_WITHOUT_DCOMP_CB
1996   midi_config.console_dev = argv[++i];
1997   midi_config.init_cb = 1;
1998#else
1999   ROAR_ERR("main(*): No support for MIDI subsystem part CB compiled in");
2000   i++;
2001#endif
2002
2003  } else if ( strcmp(k, "--ssynth-enable") == 0 ) {
2004#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
2005   ssynth_conf.enable = 1;
2006#else
2007   ROAR_ERR("main(*): No support for ssynth compiled in");
2008#endif
2009  } else if ( strcmp(k, "--ssynth-disable") == 0 ) {
2010#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
2011   ssynth_conf.enable = 0;
2012#else
2013   // we can safely ignore the disable
2014#endif
2015
2016  } else if ( strcmp(k, "--x11-display") == 0 || strcmp(k, "--display") == 0 ) {
2017   _CKHAVEARGS(1);
2018#ifdef ROAR_HAVE_LIBX11
2019   x11display = argv[++i];
2020#else
2021   ROAR_ERR("No X11 support compiled in!");
2022   return 1;
2023#endif
2024
2025
2026  } else if ( strcmp(k, "-p") == 0 || strcmp(k, "--port") == 0 ) {
2027   _CKHAVEARGS(1);
2028   // This is only useful in INET not UNIX mode.
2029#ifdef ROAR_SUPPORT_LISTEN
2030   if ( *sock_addr == '/' )
2031    sock_addr = ROAR_DEFAULT_HOST;
2032
2033   errno = 0;
2034   if ( (port = atoi(argv[++i])) < 1 ) {
2035#ifdef ROAR_HAVE_GETSERVBYNAME
2036    if ( (serv = getservbyname(argv[i], "tcp")) == NULL ) {
2037     ROAR_ERR("Unknown service: %s: %s", argv[i], strerror(errno));
2038     return 1;
2039    }
2040    // NOTE: we need to use ROAR_NET2HOST16() here even if s_port is of type int!
2041    ROAR_DBG("main(*): serv = {s_name='%s', s_aliases={...}, s_port=%i, s_proto='%s'}",
2042            serv->s_name, ROAR_NET2HOST16(serv->s_port), serv->s_proto);
2043    port = ROAR_NET2HOST16(serv->s_port);
2044#else
2045    ROAR_ERR("invalite port number: %s", argv[i]);
2046    return 1;
2047#endif
2048   }
2049#endif
2050  } else if ( strcmp(k, "-b") == 0 || strcmp(k, "--bind") == 0 || strcmp(k, "--sock") == 0 ) {
2051   _CKHAVEARGS(1);
2052#ifdef ROAR_SUPPORT_LISTEN
2053   sock_addr = argv[++i];
2054#else
2055   i++;
2056#endif
2057
2058  } else if ( strcmp(k, "--proto") == 0 ) {
2059#ifdef ROAR_SUPPORT_LISTEN
2060   if ( (sock_proto = roar_str2proto(argv[++i])) == -1 ) {
2061    ROAR_ERR("Unknown protocol: %s", argv[i]);
2062    return 1;
2063   }
2064#endif
2065  } else if ( strcmp(k, "--proto-dir") == 0 ) {
2066   _CKHAVEARGS(1);
2067#ifdef ROAR_SUPPORT_LISTEN
2068   if ( (sock_dir = roar_str2dir(argv[++i])) == -1 ) {
2069    ROAR_ERR("Unknown stream direction: %s", argv[i]);
2070    return 1;
2071   }
2072#else
2073   i++;
2074#endif
2075  } else if ( strcmp(k, "--proto-rate") == 0 ) {
2076   _CKHAVEARGS(1);
2077#ifdef ROAR_SUPPORT_LISTEN
2078   sock_info.rate = atoi(argv[++i]);
2079#else
2080   i++;
2081#endif
2082  } else if ( strcmp(k, "--proto-bits") == 0 ) {
2083   _CKHAVEARGS(1);
2084#ifdef ROAR_SUPPORT_LISTEN
2085   sock_info.bits = atoi(argv[++i]);
2086#else
2087   i++;
2088#endif
2089  } else if ( strcmp(k, "--proto-chans") == 0 ) {
2090   _CKHAVEARGS(1);
2091#ifdef ROAR_SUPPORT_LISTEN
2092   sock_info.channels = atoi(argv[++i]);
2093#else
2094   i++;
2095#endif
2096  } else if ( strcmp(k, "--proto-codec") == 0 ) {
2097   _CKHAVEARGS(1);
2098#ifdef ROAR_SUPPORT_LISTEN
2099   if ( (sock_info.codec = roar_str2codec(argv[++i])) == -1 ) {
2100    ROAR_ERR("Unknown codec: %s", argv[i]);
2101    return 1;
2102   }
2103#else
2104   i++;
2105#endif
2106  } else if ( strcmp(k, "--proto-aiprofile") == 0 ) {
2107   _CKHAVEARGS(1);
2108#ifdef ROAR_SUPPORT_LISTEN
2109   if ( roar_profile2info(&sock_info, argv[++i]) == -1 ) {
2110    ROAR_ERR("Unknown audio profile: %s", argv[i]);
2111    return 1;
2112   }
2113#else
2114   i++;
2115#endif
2116  } else if ( strcmp(k, "--list-profiles") == 0 ) {
2117#ifdef ROAR_SUPPORT_LISTEN
2118   listen_listen_profiles();
2119   return 0;
2120#endif
2121  } else if ( strcmp(k, "--proto-profile") == 0 ) {
2122   _CKHAVEARGS(1);
2123#ifdef ROAR_SUPPORT_LISTEN
2124   if ( get_listen_profile(argv[++i], &port, &sock_addr, &sock_type, &sock_proto, &sock_dir, &sock_info) == -1 ) {
2125    ROAR_ERR("Unknown listen profile: %s", argv[i]);
2126    return 1;
2127   }
2128#else
2129   i++;
2130#endif
2131
2132
2133  } else if ( strcmp(k, "--list-proto") == 0 ) {
2134   list_proto();
2135   return 0;
2136
2137  } else if ( strcmp(k, "-t") == 0 || strcmp(k, "--tcp") == 0 ) {
2138#ifdef ROAR_SUPPORT_LISTEN
2139   if ( sock_type != ROAR_SOCKET_TYPE_TCP && sock_type != ROAR_SOCKET_TYPE_TCP6 )
2140    sock_type = ROAR_SOCKET_TYPE_TCP;
2141
2142   if ( *sock_addr == '/' )
2143    sock_addr = ROAR_DEFAULT_HOST;
2144#endif
2145
2146  } else if ( strcmp(k, "-4") == 0 ) {
2147#ifdef ROAR_SUPPORT_LISTEN
2148   sock_type = ROAR_SOCKET_TYPE_TCP;
2149   if ( *sock_addr == '/' )
2150    sock_addr = ROAR_DEFAULT_HOST;
2151#endif
2152  } else if ( strcmp(k, "-6") == 0 ) {
2153#ifdef ROAR_SUPPORT_LISTEN
2154#ifdef AF_INET6
2155   sock_type = ROAR_SOCKET_TYPE_TCP6;
2156   if ( *sock_addr == '/' )
2157    sock_addr = ROAR_DEFAULT_HOST;
2158#else
2159    ROAR_ERR("No IPv6 support compiled in!");
2160    return 1;
2161#endif
2162#endif
2163
2164  } else if ( strcmp(k, "-u") == 0 || strcmp(k, "--unix") == 0 ) {
2165#ifdef ROAR_SUPPORT_LISTEN
2166   // ignore this case as it is the default behavor.
2167   sock_type = ROAR_SOCKET_TYPE_UNIX;
2168#endif
2169
2170  } else if ( strcmp(k, "-n") == 0 || strcmp(k, "--decnet") == 0 ) {
2171#ifdef ROAR_SUPPORT_LISTEN
2172#ifdef ROAR_HAVE_LIBDNET
2173    port   = ROAR_DEFAULT_NUM;
2174    strcpy(decnethost, ROAR_DEFAULT_LISTEN_OBJECT);
2175    sock_addr = decnethost;
2176    sock_type = ROAR_SOCKET_TYPE_DECNET;
2177#else
2178    ROAR_ERR("No DECnet support compiled in!");
2179    return 1;
2180#endif
2181#endif
2182  } else if ( strcmp(k, "--new-sock") == 0 ) {
2183#ifdef ROAR_SUPPORT_LISTEN
2184   if ( action == START || action == RESTART ) {
2185    if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto, sock_dir, &sock_info) != 0 ) {
2186     ROAR_ERR("Can not open listen socket!");
2187     return 1;
2188    }
2189   }
2190#endif
2191
2192  } else if ( strcmp(k, "--slp") == 0 ) {
2193#ifdef ROAR_HAVE_LIBSLP
2194   reg_slp = 1;
2195#else
2196   ROAR_ERR("No OpenSLP support compiled in!");
2197   return 1;
2198#endif
2199
2200  } else if ( strcmp(k, "--x11") == 0 ) {
2201#ifdef ROAR_HAVE_LIBX11
2202   reg_x11 = 1;
2203#else
2204   ROAR_ERR("No X11 support compiled in!");
2205   return 1;
2206#endif
2207
2208
2209  } else if ( strcmp(k, "--jumbo-mtu") == 0 ) {
2210   _CKHAVEARGS(1);
2211   g_config->jumbo_mtu = atoi(argv[++i]);
2212
2213  } else if ( strcmp(k, "-G") == 0 ) {
2214   _CKHAVEARGS(1);
2215   sock_grp  = argv[++i];
2216  } else if ( strcmp(k, "-U") == 0 ) {
2217   _CKHAVEARGS(1);
2218   sock_user = argv[++i];
2219
2220  } else if ( strcmp(k, "--no-listen") == 0 ) {
2221#ifdef ROAR_SUPPORT_LISTEN
2222   sock_addr   = "";
2223   g_terminate = 1;
2224   g_no_listen = 1;
2225#endif
2226  } else if ( strcmp(k, "--client-fh") == 0 ) {
2227   _CKHAVEARGS(1);
2228   if ( clients_new_from_fh(atoi(argv[++i]), ROAR_PROTO_ROARAUDIO, ROAR_BYTEORDER_NETWORK, 1) == -1 ) {
2229    ROAR_ERR("main(*): Can not set client's fh");
2230    return 1;
2231   }
2232  } else if ( strcmp(k, "--close-fh") == 0 ) {
2233   _CKHAVEARGS(1);
2234#ifdef ROAR_HAVE_IO_POSIX
2235   close(atoi(argv[++i]));
2236#else
2237   i++;
2238   ROAR_WARN("can not close file handle %s (closing not supported)", argv[i]);
2239#endif
2240
2241  } else if ( strcmp(k, "--standby") == 0 ) {
2242   g_standby = 1;
2243  } else if ( strcmp(k, "--auto-standby") == 0 ) {
2244   g_autostandby = 1;
2245  } else {
2246   usage();
2247   return 1;
2248  }
2249
2250 }
2251#endif
2252
2253#ifdef ROAR_HAVE_MAIN_ARGS
2254 switch (action) {
2255  case START:
2256    // NO-OP.
2257   break;
2258  case RESTART:
2259    // NO-OP, done before.
2260   break;
2261  case STOP:
2262#ifdef ROAR_SUPPORT_LISTEN
2263    if ( restart_server(sock_addr, 0) == -1 ) {
2264     ROAR_WARN("Can not stop old server (not running at %s?)", sock_addr);
2265     return 1;
2266    }
2267    return 0;
2268#else
2269    ROAR_ERR("--stop not supported");
2270    return 1;
2271#endif
2272   break;
2273  case SHUTDOWN:
2274#ifdef ROAR_SUPPORT_LISTEN
2275    if ( restart_server(sock_addr, 1) == -1 ) {
2276     ROAR_WARN("Can not terminate old server (not running at %s?)", sock_addr);
2277     return 1;
2278    }
2279    return 0;
2280#else
2281    ROAR_ERR("--shutdown not supported");
2282    return 1;
2283#endif
2284   break;
2285  case RESTART_RETRY:
2286#ifdef ROAR_SUPPORT_LISTEN
2287    if ( restart_server(sock_addr, 1) == -1 ) {
2288     ROAR_WARN("Can not terminate old server (again) (not running at %s?), tring to continue anyway", sock_addr);
2289     action = RESTART;
2290    }
2291#endif
2292   break;
2293 }
2294#endif
2295
2296#ifndef DEBUG
2297 // notify dbg if requested, if in DEBUG mode
2298 // do not able because it got enabled early.
2299 if ( g_verbose >= 4 )
2300  dbg_notify_cb_register();
2301#endif
2302
2303 if ( af_mode != AF_MODE_NONE ) {
2304  if ( add_authfile(af_file, af_type, af_mode, af_acclev) == -1 ) {
2305   ROAR_ERR("main(*): adding authfile '%s' failed!", af_file);
2306  }
2307 }
2308
2309#ifndef ROAR_WITHOUT_DCOMP_MIXER
2310 if ( m_drv != NULL ) {
2311  if ( hwmixer_add(m_drv, m_dev, m_opts, m_prim, m_count) == -1 ) {
2312   ROAR_ERR("main(*): adding mixer '%s' via '%s' failed!", m_dev, m_drv);
2313  }
2314 }
2315#endif
2316
2317#ifndef ROAR_WITHOUT_DCOMP_SOURCES
2318 if ( s_drv != NULL || s_dev != NULL ) {
2319  if ( sources_add(s_drv, s_dev, s_con, s_opt, s_prim) == -1 ) {
2320   ROAR_ERR("main(*): adding source '%s' via '%s' failed!", s_dev, s_drv);
2321  }
2322 }
2323#endif
2324
2325 if ( output_add_default(o_drv, o_dev, o_opts, o_prim, o_count) == -1 ) {
2326  ROAR_ERR("Can not initialize default driver");
2327  return 1;
2328 }
2329
2330 ROAR_INFO("Server config: rate=%i, bits=%i, chans=%i", ROAR_DBG_INFO_NOTICE, sa.rate, sa.bits, sa.channels);
2331
2332 if ( waveform_init() == -1 ) {
2333  ROAR_ERR("Can not initialize Waveform subsystem");
2334  return 1;
2335 }
2336
2337#ifndef ROAR_WITHOUT_DCOMP_MIDI
2338 if ( midi_init() == -1 ) {
2339  ROAR_ERR("Can not initialize MIDI subsystem");
2340 }
2341#endif
2342
2343#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
2344 if ( ssynth_init() == -1 ) {
2345  ROAR_ERR("Can not initialize ssynth subsystem");
2346 }
2347#endif
2348
2349#ifndef ROAR_WITHOUT_DCOMP_LIGHT
2350 if ( light_init(light_channels) == -1 ) {
2351  ROAR_ERR("Can not initialize light control subsystem");
2352 }
2353#endif
2354
2355#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2356 if ( rdtcs_init() == -1 ) {
2357  ROAR_ERR("Can not initialize RDTCS subsystem");
2358 }
2359#endif
2360
2361 if ( plugins_init() == -1 ) {
2362  ROAR_ERR("Can not initialize plugins");
2363 }
2364
2365#ifdef ROAR_SUPPORT_LISTEN
2366 if ( !g_no_listen ) {
2367  if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto, sock_dir, &sock_info) != 0 ) {
2368   ROAR_ERR("Can not open listen socket!");
2369   return 1;
2370  }
2371 }
2372#endif
2373
2374 if ( output_buffer_init(&sa) == -1 ) {
2375  ROAR_ERR("Can not init output buffer!");
2376  return 1;
2377 }
2378
2379 if ( samples_init() == -1 ) {
2380  ROAR_ERR("Can not init samples!");
2381  return 1;
2382 }
2383
2384
2385 // we should handle this on microcontrollers, too.
2386#if !defined(ROAR_TARGET_MICROCONTROLLER) && !defined(ROAR_TARGET_WIN32)
2387 signal(SIGINT,  on_sig_int);
2388 signal(SIGTERM, on_sig_term);
2389 signal(SIGCHLD, on_sig_chld);
2390 signal(SIGUSR1, on_sig_usr1);
2391 signal(SIGPIPE, SIG_IGN);  // ignore broken pipes
2392#endif
2393
2394 if ( g_config->memlock_level == -1 ) {
2395  g_config->memlock_level = MEMLOCK_DEFAULT;
2396 }
2397
2398 if ( memlock_set_level(g_config->memlock_level) == -1 ) {
2399  ROAR_WARN("Can not set memory locking level to target level.");
2400 }
2401
2402 if ( realtime ) {
2403#ifdef DEBUG
2404  ROAR_WARN("compiled with -DDEBUG but realtime is enabled: for real realtime support compile without -DDEBUG");
2405#endif
2406
2407#ifdef ROAR_HAVE_NICE
2408  // this stupid error check is because type of returned data of nice() changed
2409  // too often. On some systems it may return 0/-1, on some new nice value or
2410  // mixed forms of both.
2411  errno = 0;
2412  (void)nice(-5*realtime); // -5 for each --realtime
2413  if ( errno ) {
2414   ROAR_WARN("Can not decrease nice value by %i: %s", 5*realtime, strerror(errno));
2415  }
2416#else
2417  ROAR_WARN("Can not decrease nice value by %i: %s", 5*realtime, strerror(errno));
2418#endif
2419/*
2420#ifdef __linux__
2421  if ( ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0)) == -1 )
2422   ROAR_WARN("Can not set io priority: %s", strerror(errno));
2423#endif
2424*/
2425 }
2426
2427#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
2428 if ( setids & R_SETGID ) {
2429  if ( sock_grp == NULL ) {
2430   ROAR_ERR("Can not set GID if no groupname is supplied");
2431   return 1;
2432  }
2433  if ( (grp = getgrnam(sock_grp)) == NULL ) {
2434   ROAR_ERR("Can not get GID for group %s: %s", sock_grp, strerror(errno));
2435   return 1;
2436  }
2437  if ( setgroups(0, (const gid_t *) NULL) == -1 ) {
2438   ROAR_ERR("Can not clear supplementary group IDs: %s", strerror(errno));
2439  }
2440  if ( grp == NULL || setgid(grp->gr_gid) == -1 ) {
2441   ROAR_ERR("Can not set GroupID: %s", strerror(errno));
2442  }
2443 }
2444#endif
2445
2446
2447 clients_set_pid(g_self_client, getpid());
2448#ifdef ROAR_HAVE_GETUID
2449 clients_set_uid(g_self_client, getuid());
2450#endif
2451#ifdef ROAR_HAVE_GETGID
2452 clients_set_gid(g_self_client, getgid());
2453#endif
2454 clients_get(g_self_client, &self);
2455
2456 if ( self == NULL ) {
2457  ROAR_ERR("Can not get self client!");
2458  return 1;
2459 }
2460
2461 strcpy(self->name, "RoarAudio daemon internal");
2462
2463 if ( roar_nnode_free(&(self->nnode)) == -1 )
2464  return 1;
2465
2466 // not fully correct but ok as workaorund
2467 // so tools assume that roard runs on the same machine as
2468 // they in case they use AF_UNIX:
2469 if ( roar_nnode_new(&(self->nnode), ROAR_SOCKET_TYPE_UNIX) == -1 )
2470  return 1;
2471
2472#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
2473 if ( daemon ) {
2474#ifdef ROAR_HAVE_SYSLOG
2475  roar_debug_set_stderr_mode(ROAR_DEBUG_MODE_SYSLOG);
2476#else
2477  roar_debug_set_stderr_fh(-1);
2478#endif
2479
2480#ifdef ROAR_TARGET_WIN32
2481  FreeConsole();
2482#else
2483
2484  close(ROAR_STDIN );
2485  close(ROAR_STDOUT);
2486  close(ROAR_STDERR);
2487
2488  if ( fork() )
2489   ROAR_U_EXIT(0);
2490
2491#ifdef ROAR_HAVE_SETSID
2492  setsid();
2493#endif
2494  clients_set_pid(g_self_client, getpid()); // reset pid as it changed
2495#endif
2496 }
2497#endif
2498
2499#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
2500 // early test for UID as we need this for the pidfile and the setuid()
2501 if ( sock_user != NULL ) {
2502  if ( (pwd = getpwnam(sock_user)) == NULL ) {
2503   ROAR_ERR("Can not get UID for user %s: %s", sock_user, strerror(errno));
2504   return 1;
2505  }
2506 }
2507#endif
2508
2509 ROAR_INFO("Process ID: %i", ROAR_DBG_INFO_INFO, (int)getpid());
2510
2511#ifdef SUPPORT_PIDFILE
2512 if ( pidfile != NULL ) {
2513  if ( roar_vio_open_file(&pidfile_vio, pidfile, O_WRONLY|O_CREAT, 0644) == -1 ) {
2514   ROAR_ERR("Can not write pidfile: %s", pidfile);
2515  } else {
2516   roar_vio_printf(&pidfile_vio, "%i\n", getpid());
2517   roar_vio_close(&pidfile_vio);
2518  }
2519#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
2520  if ( pwd != NULL || grp != NULL ) {
2521   if ( chown(pidfile, pwd != NULL ? pwd->pw_uid : -1, grp != NULL ? grp->gr_gid : -1) == -1 ) {
2522    ROAR_WARN("Can not change ownership of pidfile: %s: %s", pidfile, strerror(errno));
2523   }
2524  }
2525  if ( chmod(pidfile, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1 ) {
2526   ROAR_WARN("Can not change permissions of pidfile: %s: %s", pidfile, strerror(errno));
2527  }
2528#endif
2529 }
2530#endif
2531
2532#ifdef ROAR_HAVE_CHROOT
2533 if (chrootdir) {
2534  if ( chroot(chrootdir) == -1 ) {
2535   ROAR_ERR("Can not chroot to %s: %s", chrootdir, strerror(errno));
2536   return 2;
2537  }
2538  if ( chdir("/") == -1 ) {
2539   ROAR_ERR("Can not chdir to /: %s", strerror(errno));
2540   return 2;
2541  }
2542 }
2543#endif
2544
2545#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
2546 if ( setids & R_SETUID ) {
2547  if ( sock_user == NULL ) {
2548   ROAR_ERR("Can not set UID if no username is supplied");
2549   return 1;
2550  }
2551  if ( pwd == NULL || setuid(pwd->pw_uid) == -1 ) {
2552   ROAR_ERR("Can not set UserID: %s", strerror(errno));
2553   return 3;
2554  }
2555#ifdef ROAR_HAVE_GETUID
2556  clients_set_uid(g_self_client, getuid());
2557#endif
2558 }
2559#endif
2560
2561 // setup auth:
2562#if defined(ROAR_HAVE_GETUID) && defined(ROAR_HAVE_GETGID)
2563 if ( auth_setup(none_acclev, trust_acclev, trust_root, getuid(), getgid()) == -1 ) {
2564#else
2565 if ( auth_setup(none_acclev, trust_acclev, trust_root, -1, -1) == -1 ) {
2566#endif
2567  ROAR_ERR("Can not set up auth. Bad.");
2568  alive = 0;
2569 }
2570
2571 // Register with OpenSLP:
2572#ifdef ROAR_HAVE_LIBSLP
2573 if ( reg_slp ) {
2574  register_slp(0, sock_addr);
2575 }
2576#endif
2577
2578#ifdef ROAR_HAVE_LIBX11
2579 if ( reg_x11 ) {
2580  register_x11(0, sock_addr);
2581 }
2582#endif
2583
2584 // update sync counter.
2585 streams_change_sync_num(-1, 0);
2586
2587 ROAR_INFO("Startup complet", ROAR_DBG_INFO_INFO);
2588
2589 // start main loop...
2590 ROAR_INFO("Entering main loop", ROAR_DBG_INFO_INFO);
2591 main_loop(&sa, sysclocksync);
2592 ROAR_INFO("Left main loop", ROAR_DBG_INFO_INFO);
2593
2594 // clean up.
2595 clean_quit_prep();
2596 output_buffer_free();
2597
2598 roar_notify_core_free(NULL);
2599
2600 ROAR_INFO("Shuting down complete", ROAR_DBG_INFO_INFO);
2601
2602 if ( g_config->scripts.post_shutdown != NULL )
2603  system(g_config->scripts.post_shutdown);
2604
2605 ROAR_INFO("Exiting, no error", ROAR_DBG_INFO_INFO);
2606 return 0;
2607}
2608
2609void cleanup_listen_socket (int terminate) {
2610 int i;
2611
2612 ROAR_DBG("cleanup_listen_socket(terminate=%i) = (void)?", terminate);
2613
2614 ROAR_INFO("Cleaning up listen sockets", ROAR_DBG_INFO_INFO);
2615
2616 // Deregister from SLP:
2617#ifdef ROAR_HAVE_LIBSLP
2618 register_slp(1, NULL);
2619#endif
2620
2621#ifdef ROAR_HAVE_LIBX11
2622 register_x11(1, NULL);
2623#endif
2624
2625#ifdef ROAR_SUPPORT_LISTEN
2626 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
2627  if ( g_listen[i].used  ) {
2628   roar_vio_close(&(g_listen[i].sock));
2629
2630   g_listen[i].used = 0;
2631
2632#ifdef ROAR_HAVE_UNIX
2633   if ( server[i] != NULL )
2634    if ( *(server[i]) == '/' )
2635     unlink(server[i]);
2636#endif
2637  }
2638 }
2639
2640#endif
2641
2642 if ( terminate )
2643  g_terminate = 1;
2644}
2645
2646void clean_quit_prep (void) {
2647 cleanup_listen_socket(0);
2648
2649 plugins_free();
2650
2651#ifndef ROAR_WITHOUT_DCOMP_SOURCES
2652 sources_free();
2653#endif
2654 streams_free();
2655 clients_free();
2656#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
2657 ssynth_free();
2658#endif
2659#ifndef ROAR_WITHOUT_DCOMP_CB
2660 midi_cb_stop(); // stop console beep
2661#endif
2662#ifndef ROAR_WITHOUT_DCOMP_MIDI
2663 midi_free();
2664#endif
2665#ifndef ROAR_WITHOUT_DCOMP_LIGHT
2666 light_free();
2667#endif
2668#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2669 rdtcs_free();
2670#endif
2671
2672 waveform_free();
2673
2674#ifdef SUPPORT_PIDFILE
2675 if ( pidfile != NULL )
2676  unlink(pidfile);
2677#endif
2678
2679 auth_free();
2680}
2681
2682void clean_quit (void) {
2683 ROAR_INFO("Shuting down", ROAR_DBG_INFO_INFO);
2684
2685 counters_print(ROAR_DEBUG_TYPE_INFO, 0);
2686
2687 clean_quit_prep();
2688// output_buffer_free();
2689
2690 roar_notify_core_free(NULL);
2691
2692 ROAR_INFO("Shuting down complete", ROAR_DBG_INFO_INFO);
2693
2694 if ( g_config->scripts.post_shutdown != NULL )
2695  system(g_config->scripts.post_shutdown);
2696
2697 ROAR_INFO("Exiting, no error", ROAR_DBG_INFO_INFO);
2698 exit(0);
2699}
2700
2701//ll
Note: See TracBrowser for help on using the repository browser.