source: roaraudio/roard/roard.c @ 4882:e6ef52e26c53

Last change on this file since 4882:e6ef52e26c53 was 4882:e6ef52e26c53, checked in by phi, 13 years ago

Improved listing of audio profiles.

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