]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 't/misc'
authorAndre Noll <maan@systemlinux.org>
Sun, 30 Mar 2014 16:31:57 +0000 (18:31 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 30 Mar 2014 16:42:30 +0000 (18:42 +0200)
Various fixes, improvements, cleanups. Cooking since 2014-02-22.

* t/misc: (29 commits)
  build: Don't link with -lreadline if readline was not found.
  audiod: Skip NULL pointer check in compute_time_diff().
  audiod: Make compute_time_diff() return void.
  com_stat(): Remove pointless uptime variable.
  gcrypt: Fix gcc warning on Ubuntu Lucid.
  flac: Try to link also without -logg.
  version.c: Fix comment of version_single_line().
  doxygen: Expand all macros, in particular config.h.
  recv_common.c: Improve documentation of check_receiver_arg().
  audiod: get_time_string() comment fix.
  configure: Really print opus audio file handler if opus lib was found.
  Overhaul doxygen main page.
  afs.h: Don't try to list all supported audio formats.
  Change copyright year to 2014.
  Add link to sideband.h in doxygen main page.
  Doxify error2.c and add GPL header.
  Add -Wdeclaration-after-statement.
  Add some missing includes.
  Makefile.real: Add clean2 to the list of phony targets.
  mood.c: Fix a trivial whitespace issue.
  ...

30 files changed:
1  2 
NEWS
acl.c
afs.c
alsa_mix.c
audioc.c
audiod.c
audiod_command.c
client_common.c
command.c
configure.ac
crypt.c
crypt.h
crypt_backend.h
dccp_recv.c
dccp_send.c
error.h
fade.c
gcrypt.c
http_recv.c
http_send.c
m4/gengetopt/fade.m4
net.c
net.h
oss_mix.c
para.h
send_common.c
server.c
udp_recv.c
udp_send.c
vss.c

diff --combined NEWS
index 787bdde64d7cd797d93b73131256a9530be363bf,221be43e66f884ebf5250ebc9fcf715e09929afa..ab53a17697ea7c92f2d0b2107d4d8dcee95d9e4c
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,25 -1,10 +1,29 @@@
  NEWS
  ====
  
 ----------------------------------
 -0.5.2 (???) "orthogonal interior"
 ----------------------------------
 +---------------------------------------------
 +0.5.2 (to be announced) "orthogonal interior"
 +---------------------------------------------
  
- network code are the highlights of this release.
 +The new sync filter, the AES_CTR128 stream cipher and the overhauled
-       - Improvements to para_fade: the new set mode, multi-channal
++network code are the highlights of this release. It also includes a
++fair number of smaller fixes and improvements not mentioned here.
 +
 +      - The new sync filter synchronizes playback between multiple
 +        clients.
 +      - Connections between para_server and para_client are now
 +        encrypted by means of AES rather than RC4 if both sides
 +        support it. RC4 is still available as a fallback. This
 +        feature is fully transparent, i.e. no command line options
 +        are necessary, and a client linked against openssl can
 +        speak with a server linked against libgcrypt and vice versa.
 +      - Major cleanup of the networking subsystem.
++      - Improvements to para_fade: the new set mode, multi-channel
 +        initial volumes, better error logging.
++      - The man pages of para_audiod, para_filter, para_recv, and
++        para_write contain the relevant options for receivers, filters,
++        writers. This broke in 0.5.0.
 +      - Improved user manual.
        - Minor fixes to avoid clang warnings.
  
  ------------------------------------------
@@@ -45,6 -30,9 +49,9 @@@ of the build system
        - Many small bugs in the build system have been identified
          and fixed.
  
+ Downloads: ./releases/paraslash-0.5.1.tar.bz2 (tarball),
+ ./releases/paraslash-0.5.1.tar.bz2.asc (signature)
  ----------------------------------------
  0.5.0 (2013-08-23) "invertible validity"
  ----------------------------------------
diff --combined acl.c
index 7762a990d38a090ae661371cdee1066fb075c429,794a4fa2a25b53c96c0d7eb2a71a164f5e56b492..e1415050e6e47a1397689bbcbcdc341693834e71
--- 1/acl.c
--- 2/acl.c
+++ b/acl.c
@@@ -1,23 -1,19 +1,24 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file acl.c Access control lists for paraslash senders. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
  #include "string.h"
  #include "list.h"
  #include "net.h"
+ #include "acl.h"
  
  /**
   * Describes one entry in the blacklist/whitelist of a paraslash sender.
diff --combined afs.c
index 135888a7fc632e6760d2aba4e1b4b2b4738af618,d02082666cc48baee0bbb39db7c22a6a0ec2265e..fa4f4326cc110cd377ab6e8a7c30c74fe8148373
--- 1/afs.c
--- 2/afs.c
+++ b/afs.c
@@@ -1,20 -1,15 +1,20 @@@
  /*
-  * Copyright (C) 2007-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2007-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file afs.c Paraslash's audio file selector. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <signal.h>
  #include <fnmatch.h>
  #include <osl.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "server.cmdline.h"
  #include "para.h"
diff --combined alsa_mix.c
index c5daebc2682b13eb0d6e2a12b9956ae5b77ff4b8,1a19de29548498577d53abe7dfd9e0b94e57281d..be38e887af9babf8925bcda4d8065a79f991ff7c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2012-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2012-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -141,19 -141,19 +141,19 @@@ static int alsa_mix_set_channel(struct 
                PARA_NOTICE_LOG("unable to find simple control '%s',%i\n",
                        snd_mixer_selem_id_get_name(sid),
                        snd_mixer_selem_id_get_index(sid));
 -              return -E_ALSA_MIX_BAD_ELEM;
 +              return -E_BAD_CHANNEL;
        }
        ret = snd_mixer_selem_get_playback_volume_range(h->elem,
                &h->pmin, &h->pmax);
        if (ret < 0) {
                PARA_NOTICE_LOG("unable to get %s range (%s): %s\n",
                        mixer_channel, h->card, snd_strerror(ret));
 -              return -E_ALSA_MIX_BAD_ELEM;
 +              return -E_ALSA_MIX_RANGE;
        }
        if (h->pmin < 0 || h->pmax < 0 || h->pmin >= h->pmax) {
                PARA_NOTICE_LOG("alsa reported %s range %ld-%ld (%s)\n",
                        mixer_channel, h->pmin, h->pmax, h->card);
 -              return -E_ALSA_MIX_BAD_ELEM;
 +              return -E_ALSA_MIX_RANGE;
        }
        return 1;
  }
diff --combined audioc.c
index 79051a98bb03b542dbb7d53a76c0d4a426a484bc,597a5f58114f2b0053caf92138029f19083920d4..5f6b5ae1195645e3a8b4c2b458559625a036701c
+++ b/audioc.c
@@@ -1,18 -1,13 +1,18 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file audioc.c The client program used to connect to para_audiod. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  #include <stdbool.h>
  #include <signal.h>
  
diff --combined audiod.c
index f12dbc1b999a0892abdcea5791692f1f5dfab3c3,e207c7586625dbb49595cb85d992284f157e3d72..d815c4aa6c98e699dc48304cd96db1d14c28035b
+++ b/audiod.c
@@@ -1,18 -1,12 +1,18 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file audiod.c The paraslash's audio daemon. */
 +
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  #include <signal.h>
  
  #include "para.h"
@@@ -219,7 -213,7 +219,7 @@@ static int get_matching_audio_format_nu
   * from the status items received from para_server and the start time of the
   * (first) writer of the given slot.
   *
-  * It has to to take into account that probably the stream was not started at
+  * It has to take into account that the stream was probably not started at
   * the beginning of the file, that the clock between the server and the client
   * host may differ and that playback of the stream was delayed, e.g. because
   * the prebuffer filter is used in the filter configuration of the given slot.
@@@ -647,7 -641,7 +647,7 @@@ static bool must_start_decoder(void
        return true;
  }
  
- static unsigned compute_time_diff(const struct timeval *status_time)
+ static void compute_time_diff(const struct timeval *status_time)
  {
        struct timeval tmp, diff;
        static unsigned count;
        const struct timeval max_deviation = {0, 500 * 1000};
        const int time_smooth = 5;
  
-       if (!status_time)
-               return count;
        sign = tv_diff(status_time, now, &diff);
  //            PARA_NOTICE_LOG("%s: sign = %i, sa_time_diff_sign = %i\n", __func__,
  //                    sign, sa_time_diff_sign);
        );
  out:
        stat_task->sa_time_diff_sign = sa_time_diff_sign;
-       return count;
  }
  
  static int update_item(int itemnum, char *buf)
diff --combined audiod_command.c
index 1ffab87c0fbd5269d6da52b05428dc44132dd922,030206745080f4ba667f566ef84e3f8ce6ea2fef..4485d9e9df28ca0fb2d1689046c1e53cffc9f5a5
@@@ -1,18 -1,13 +1,18 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file audiod_command.c Commands for para_audiod. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "audiod.cmdline.h"
diff --combined client_common.c
index 3b8ed511090a5a637d867f48baf391338677c837,c426d6ed081e2016cd16f03fec867d42331938db..900d3653893dea7067330d60a929ce0a4b13d902
@@@ -1,18 -1,13 +1,18 @@@
  /*
-  * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1997-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file client_common.c Common functions of para_client and para_audiod. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
@@@ -336,8 -331,7 +336,8 @@@ static int client_post_select(struct sc
        case CL_RECEIVED_WELCOME: /* send auth command */
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
                        return 0;
 -              sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
 +              sprintf(buf, AUTH_REQUEST_MSG "%s sideband%s", ct->user,
 +                      has_feature("aes_ctr128", ct)? ",aes_ctr128" : "");
                PARA_INFO_LOG("--> %s\n", buf);
                ret = write_buffer(ct->scc.fd, buf);
                if (ret < 0)
                /* decrypted challenge/session key buffer */
                unsigned char crypt_buf[1024];
                struct sb_buffer sbb;
 +              bool use_aes;
  
                ret = recv_sb(ct, &s->rfds, &sbb);
                if (ret <= 0)
                        goto out;
                ct->challenge_hash = para_malloc(HASH_SIZE);
                hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
 -              ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
 +              use_aes = has_feature("aes_ctr128", ct);
 +              ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN, use_aes);
                ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
 -                      SESSION_KEY_LEN);
 +                      SESSION_KEY_LEN, use_aes);
                hash_to_asc(ct->challenge_hash, buf);
                PARA_INFO_LOG("--> %s\n", buf);
                ct->status = CL_RECEIVED_CHALLENGE;
diff --combined command.c
index 26126cc938cc0f8c9bb751b2cebf6f7ee52d5169,a8d479e95c7a237f4889ad389a7cf2bf46dc5433..eb15875c36b8affba5a3defdce8f787ad73026ba
+++ b/command.c
@@@ -1,20 -1,15 +1,20 @@@
  /*
-  * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1997-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file command.c Client authentication and server commands. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <signal.h>
  #include <sys/types.h>
  #include <osl.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
@@@ -115,7 -110,6 +115,6 @@@ static unsigned get_status(struct misc_
        char mtime[30] = "";
        char *status, *flags; /* vss status info */
        /* nobody updates our version of "now" */
-       char *ut = get_server_uptime_str(NULL);
        long offset = (nmmd->offset + 500) / 1000;
        struct timeval current_time;
        struct tm mtime_tm;
                (long unsigned)current_time.tv_usec);
        free(flags);
        free(status);
-       free(ut);
        *result = b.buf;
        return b.offset;
  }
@@@ -786,20 -779,14 +784,20 @@@ static void reset_signals(void
        para_sigaction(SIGHUP, SIG_DFL);
  }
  
 -static int parse_auth_request(char *buf, int len, struct user **u)
 +struct connection_features {
 +      bool sideband_requested;
 +      bool aes_ctr128_requested;
 +};
 +
 +static int parse_auth_request(char *buf, int len, struct user **u,
 +              struct connection_features *cf)
  {
        int ret;
        char *p, *username, **features = NULL;
        size_t auth_rq_len = strlen(AUTH_REQUEST_MSG);
 -      bool sideband_requested = false;
  
        *u = NULL;
 +      memset(cf, 0, sizeof(*cf));
        if (len < auth_rq_len + 2)
                return -E_AUTH_REQUEST;
        if (strncmp(buf, AUTH_REQUEST_MSG, auth_rq_len) != 0)
                create_argv(p, ",", &features);
                for (i = 0; features[i]; i++) {
                        if (strcmp(features[i], "sideband") == 0)
 -                              sideband_requested = true;
 +                              cf->sideband_requested = true;
 +                      else if (strcmp(features[i], "aes_ctr128") == 0)
 +                              cf->aes_ctr128_requested = true;
                        else {
                                ret = -E_BAD_FEATURE;
                                goto out;
                        }
                }
        }
 -      if (sideband_requested == false) { /* sideband is mandatory */
 -              PARA_ERROR_LOG("client did not request sideband\n");
 -              ret = -E_BAD_FEATURE;
 -              goto out;
 -      }
        PARA_DEBUG_LOG("received auth request for user %s\n", username);
        *u = lookup_user(username);
        ret = 1;
@@@ -898,11 -888,10 +896,11 @@@ __noreturn void handle_connect(int fd, 
        int ret;
        unsigned char rand_buf[CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
        unsigned char challenge_hash[HASH_SIZE];
 -      char *p, *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
 +      char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
        size_t numbytes;
        struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
        struct iovec iov;
 +      struct connection_features cf;
  
        cc->scc.fd = fd;
        reset_signals();
        /* send Welcome message */
        ret = write_va_buffer(fd, "This is para_server, version "
                PACKAGE_VERSION  ".\n"
 -              "Features: sideband\n"
 +              "Features: sideband,aes_ctr128\n"
        );
        if (ret < 0)
                goto net_err;
        ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE);
        if (ret < 0)
                goto net_err;
 -      ret = parse_auth_request(buf, ret, &cc->u);
 +      ret = parse_auth_request(buf, ret, &cc->u, &cf);
        if (ret < 0)
                goto net_err;
 -      p = buf + strlen(AUTH_REQUEST_MSG);
 -      PARA_DEBUG_LOG("received auth request for user %s\n", p);
 -      cc->u = lookup_user(p);
 +      if (!cf.sideband_requested) { /* sideband is mandatory */
 +              PARA_ERROR_LOG("client did not request sideband\n");
 +              ret = -E_BAD_FEATURE;
 +              goto net_err;
 +      }
        if (cc->u) {
                get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
                ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf),
                numbytes = 256;
                get_random_bytes_or_die((unsigned char *)buf, numbytes);
        }
 -      PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
 +      PARA_DEBUG_LOG("sending %u byte challenge + session key (%zu bytes)\n",
                CHALLENGE_SIZE, numbytes);
        ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
        buf = NULL;
        alarm(0);
        PARA_INFO_LOG("good auth for %s\n", cc->u->name);
        /* init stream cipher keys with the second part of the random buffer */
 -      cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
 -      cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN);
 +      cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN,
 +              cf.aes_ctr128_requested);
 +      cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
 +              SESSION_KEY_LEN, cf.aes_ctr128_requested);
        ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
        if (ret < 0)
                goto net_err;
diff --combined configure.ac
index cdbc0e56b0f51992973076a4ae602ca0a2d1e33a,75194ffc3ed785713406f592890ec6ea05694332..07ecffdd71f31e1246d8262bda5fbdd762212f99
@@@ -580,7 -580,11 +580,11 @@@ if test -n "$with_flac_libs"; the
        LDFLAGS="$LDFLAGS $flac_libs"
  fi
  AC_CHECK_HEADER(FLAC/stream_decoder.h, [], have_flac=no)
- AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [], have_flac=no, -logg -lm)
+ AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [], [
+       # nope, try again with -logg
+       AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [],
+               have_flac=no, -lm -logg)
+       ], -lm)
  if test "$have_flac" = "yes"; then
        AC_DEFINE(HAVE_FLAC, 1, define to 1 if you want to build the flacdec filter)
        AC_SUBST(flac_cppflags)
@@@ -728,15 -732,17 +732,17 @@@ AC_CHECK_HEADERS([readline/readline.h]
  ])
  
  if test "$have_readline" = "yes"; then
-       readline_ldflags="$readline_libs -lreadline"
-       AC_SEARCH_LIBS([rl_free_keymap], [readline], [], [have_readline="no"])
+       readline_ldflags="$readline_libs"
+       AC_SEARCH_LIBS([rl_free_keymap], [readline], [
+               readline_ldflags="$readline_ldflags -lreadline"
+       ], [have_readline="no"])
        if test "$have_readline" = "no"; then # try with -lcurses
                  # clear cache
                AC_MSG_NOTICE([trying again with -lcurses])
                  unset ac_cv_search_rl_free_keymap 2> /dev/null
                AC_SEARCH_LIBS([rl_free_keymap], [readline], [
                        have_readline=yes
-                       readline_ldflags="$readline_ldflags -lcurses"
+                       readline_ldflags="$readline_ldflags -lreadline -lcurses"
                ], [], [-lcurses])
        fi
        if test "$have_readline" = "no"; then # try with -ltermcap
                  unset ac_cv_search_rl_free_keymap 2> /dev/null
                AC_SEARCH_LIBS([rl_free_keymap], [readline], [
                        have_readline=yes
-                       readline_ldflags="$readline_ldflags -ltermcap"
+                       readline_ldflags="$readline_ldflags -lreadline -ltermcap"
                ], [], [-ltermcap])
        fi
  fi
@@@ -924,7 -930,6 +930,7 @@@ if test "$have_openssl" = "yes" -o "$ha
                amp_filter
                udp_recv
                prebuffer_filter
 +              sync_filter
        "
        audiod_errlist_objs="$audiod_errlist_objs
                audiod
                wma_common
                wmadec_filter
                buffer_tree
 +              sync_filter
        "
        if test "$have_openssl" = "yes"; then
                audiod_errlist_objs="$audiod_errlist_objs crypt"
@@@ -1107,7 -1111,6 +1113,7 @@@ filters=
        fecdec
        wmadec
        prebuffer
 +      sync
  "
  filter_errlist_objs="
        filter_common
        wmadec_filter
        buffer_tree
        net
 +      sync_filter
  "
  filter_cmdline_objs="
        filter
        compress_filter
        amp_filter
        prebuffer_filter
 +      sync_filter
  "
  
  if test "$have_vorbis" = "yes"; then
@@@ -1172,6 -1173,8 +1178,8 @@@ if test "$have_samplerate" = "yes"; the
        filter_cmdline_objs="$filter_cmdline_objs resample_filter"
        filters="$filters resample"
  fi
+ filters="$(echo $filters)"
+ AC_SUBST(filters)
  filter_objs="add_cmdline($filter_cmdline_objs) $filter_errlist_objs"
  
  AC_SUBST(filter_objs, add_dot_o($filter_objs))
@@@ -1236,6 -1239,7 +1244,7 @@@ if test "$have_flac" = "yes"; the
        recv_errlist_objs="$recv_errlist_objs flac_afh"
  fi
  recv_objs="add_cmdline($recv_cmdline_objs) $recv_errlist_objs"
+ AC_SUBST(receivers, "http dccp udp afh")
  AC_SUBST(recv_objs, add_dot_o($recv_objs))
  AC_DEFINE_UNQUOTED(INIT_RECV_ERRLISTS, objlist_to_errlist($recv_errlist_objs),
        errors used by para_recv)
@@@ -1269,6 -1273,7 +1278,7 @@@ if test "$have_speex" = "yes"; the
  fi
  if test "$have_opus" = "yes"; then
        afh_errlist_objs="$afh_errlist_objs opus_afh opus_common"
+       audio_format_handlers="$audio_format_handlers opus"
  fi
  if test "$have_faad" = "yes"; then
        afh_errlist_objs="$afh_errlist_objs aac_common aac_afh"
@@@ -1316,7 -1321,6 +1326,7 @@@ play_errlist_objs=
        write_common
        file_write
        version
 +      sync_filter
  "
  play_cmdline_objs="
        http_recv
        prebuffer_filter
        file_write
        play
 +      sync_filter
  "
  if test "$have_core_audio" = "yes"; then
        play_errlist_objs="$play_errlist_objs osx_write ipc"
@@@ -1428,6 -1431,7 +1438,7 @@@ if test "$have_alsa" = "yes"; the
        writers="$writers alsa"
        default_writer="ALSA_WRITE"
  fi
+ AC_SUBST(writers)
  write_objs="add_cmdline($write_cmdline_objs) $write_errlist_objs"
  AC_SUBST(write_objs, add_dot_o($write_objs))
  AC_DEFINE_UNQUOTED(INIT_WRITE_ERRLISTS,
@@@ -1546,7 -1550,7 +1557,7 @@@ unix socket credentials: $have_ucre
  readline (interactive CLIs): $have_readline
  audio formats handlers: $audio_format_handlers
  id3 version2 support: $have_libid3tag
- filters: $(echo $filters)
+ filters: $filters
  writers: $writers
  
  para_fade: $build_fade
diff --combined crypt.c
index e6a31e0e121f9235804664a303c742339caedec4,9790c8ce0d27932ece97df2929889668439682fd..0137e004cbb2b0e121373c1ffe1d5ee6e5f75b6e
+++ b/crypt.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -15,7 -15,6 +15,7 @@@
  #include <openssl/pem.h>
  #include <openssl/sha.h>
  #include <openssl/bn.h>
 +#include <openssl/aes.h>
  
  #include "para.h"
  #include "error.h"
@@@ -260,40 -259,14 +260,40 @@@ int pub_encrypt(struct asymmetric_key *
        return ret < 0? -E_ENCRYPT : ret;
  }
  
 +struct aes_ctr_128_context {
 +      AES_KEY key;
 +      unsigned char ivec[AES_CRT128_BLOCK_SIZE];
 +      unsigned char ecount[AES_CRT128_BLOCK_SIZE];
 +      unsigned int num;
 +};
 +
  struct stream_cipher {
 -      RC4_KEY key;
 +      bool use_aes;
 +      union {
 +              RC4_KEY rc4_key;
 +              struct aes_ctr_128_context aes;
 +      } context;
  };
  
 -struct stream_cipher *sc_new(const unsigned char *data, int len)
 +struct stream_cipher *sc_new(const unsigned char *data, int len,
 +              bool use_aes)
  {
 +      int ret;
        struct stream_cipher *sc = para_malloc(sizeof(*sc));
 -      RC4_set_key(&sc->key, len, data);
 +      struct aes_ctr_128_context *aes;
 +
 +      sc->use_aes = use_aes;
 +      if (!use_aes) {
 +              RC4_set_key(&sc->context.rc4_key, len, data);
 +              return sc;
 +      }
 +      assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
 +      aes = &sc->context.aes;
 +      ret = AES_set_encrypt_key(data, AES_CRT128_BLOCK_SIZE * 8 /* bits */,
 +              &aes->key);
 +      assert(ret == 0);
 +      memcpy(aes->ivec, data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
 +      aes->num = 0;
        return sc;
  }
  
@@@ -309,9 -282,10 +309,9 @@@ void sc_free(struct stream_cipher *sc
   */
  #define RC4_ALIGN 8
  
 -void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
 +static void rc4_crypt(RC4_KEY *key, struct iovec *src, struct iovec *dst)
  {
        size_t len = src->iov_len, l1, l2;
 -      RC4_KEY *key = &sc->key;
  
        assert(len > 0);
        assert(len < ((typeof(src->iov_len))-1) / 2);
        ((char *)dst->iov_base)[len] = '\0';
  }
  
 +static void aes_ctr128_crypt(struct aes_ctr_128_context *aes, struct iovec *src,
 +              struct iovec *dst)
 +{
 +      size_t len = src->iov_len;
 +
 +      *dst = (typeof(*dst)) {
 +              /* Add one for the terminating zero byte. */
 +              .iov_base = para_malloc(len + 1),
 +              .iov_len = len
 +      };
 +      AES_ctr128_encrypt(src->iov_base, dst->iov_base, len,
 +              &aes->key, aes->ivec, aes->ecount, &aes->num);
 +      ((char *)dst->iov_base)[len] = '\0';
 +}
 +
 +void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
 +{
 +      if (sc->use_aes)
 +              return aes_ctr128_crypt(&sc->context.aes, src, dst);
 +      return rc4_crypt(&sc->context.rc4_key, src, dst);
 +}
 +
  void hash_function(const char *data, unsigned long len, unsigned char *hash)
  {
        SHA_CTX c;
diff --combined crypt.h
index e9657ff5c0ae2b9c5a8875ea9f37e8e145ff9f64,d3d4f35a1e649de50d5f261750c66c1f2c417684..324a87b349a5b9f69443e47c44e242ffb0be04df
+++ b/crypt.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -123,12 -123,10 +123,12 @@@ struct stream_cipher_context 
   *
   * \param data The key.
   * \param len The size of the key.
 + * \param use_aes True: Use the aes_ctr128 stream cipher, false: Use RC4.
   *
   * \return A new stream cipher structure.
   */
 -struct stream_cipher *sc_new(const unsigned char *data, int len);
 +struct stream_cipher *sc_new(const unsigned char *data, int len,
 +              bool use_aes);
  
  /**
   * Encrypt or decrypt a buffer using a stream cipher.
diff --combined crypt_backend.h
index 3676fff1b1a7d822dcaaefaec62c0f64bd90b3db,b74bef93139a9e67adbac517779761f5543ac5da..ddebe62e16e547e243d808cf9155261698fecbec
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2011-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2011-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -8,9 -8,6 +8,9 @@@
  
  /* This should only be incuded from files which provide crypto functions. */
  
 +/** AES block size in bytes. */
 +#define AES_CRT128_BLOCK_SIZE 16
 +
  size_t is_ssh_rsa_key(char *data, size_t size);
  uint32_t read_ssh_u32(const void *vp);
  int uudecode(const char *src, unsigned char *target, size_t targsize);
diff --combined dccp_recv.c
index ca3432a31de2fc3eaadf13572cef68358f85c0a2,4cf8f5aedfe31c30f3f1ea890bc9569d816e5d15..796a7e6baf76fe15041386041e21d403b4c58cf0
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2006-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2006-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
   * (C) 2005 Ian McDonald <imcdnzl@gmail.com>
   */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
@@@ -58,7 -53,6 +58,7 @@@ static int dccp_recv_open(struct receiv
        }
  
        fd = makesock(IPPROTO_DCCP, 0, conf->host_arg, conf->port_arg, fo);
 +      flowopt_cleanup(fo);
        free(ccids);
        if (fd < 0)
                return fd;
diff --combined dccp_send.c
index 22f2bd1ba63467c7a13eb15951b000e67ccf3a62,df0dfce1a4ae5fa160ed721a0ced181f912a803b..1e95aac6401cf43cf7368a0ad61a2c37e6428587
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2006-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2006-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
   * (C) 2005 Ian McDonald <imcdnzl@gmail.com>
   */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
  #include <osl.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
diff --combined error.h
index 3b57680b92e2c2c057c55d9ef148fe8bb51d25c3,11562d7bb76f014b7389d62bdaa06fef71cd9a9e..301e2ca5e1ae36a045a044d8f69c072e82c62a88
+++ b/error.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2006-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2006-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -28,7 -28,7 +28,7 @@@ DEFINE_ERRLIST_OBJECT_ENUM
  #define GGO_ERRORS
  #define COLOR_ERRORS
  #define SIGNAL_ERRORS
 -#define FADE_ERRORS
 +#define OSS_MIX_ERRORS
  #define STDOUT_ERRORS
  #define FILE_WRITE_ERRORS
  #define STDIN_ERRORS
  #define VERSION_ERRORS
  #define SCHED_ERRORS
  
 -extern const char **para_errlist[];
  
 -#define OSS_MIX_ERRORS \
 -      PARA_ERROR(OSS_MIXER_CHANNEL, "invalid mixer channel"), \
 +extern const char **para_errlist[];
  
 +#define SYNC_FILTER_ERRORS\
 +      PARA_ERROR(SYNC_COMPLETE, "all buddies in sync"), \
 +      PARA_ERROR(SYNC_LISTEN_FD, "no fd to listen on"), \
  
  #define ALSA_MIX_ERRORS \
        PARA_ERROR(ALSA_MIX_OPEN, "could not open mixer"), \
 -      PARA_ERROR(ALSA_MIX_BAD_ELEM, "invalid/unsupported control element"), \
        PARA_ERROR(ALSA_MIX_GET_VAL, "could not read control element state"), \
        PARA_ERROR(ALSA_MIX_SET_VAL, "could not set control element state"), \
 +      PARA_ERROR(ALSA_MIX_RANGE, "value control element out of range"), \
  
  
  #define RESAMPLE_FILTER_ERRORS \
@@@ -79,8 -78,6 +79,8 @@@
        PARA_ERROR(NO_VALID_FILES, "no valid file found in playlist"), \
        PARA_ERROR(BAD_PLAY_CMD, "invalid command"), \
  
 +#define FADE_ERRORS \
 +      PARA_ERROR(BAD_CHANNEL, "invalid channel"), \
  
  #define FLACDEC_FILTER_ERRORS \
        PARA_ERROR(FLACDEC_DECODER_ALLOC, "could not allocate stream decoder"), \
diff --combined fade.c
index 0a3ccebb844326267f421044d998d77c27096356,c1d15d723b66aa252f10a349e27b4b52d5cd9552..543a666dd0e32fbf106d263d3cf96e1bb11ce136
--- 1/fade.c
--- 2/fade.c
+++ b/fade.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 1998-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1998-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -37,21 -37,13 +37,21 @@@ static __printf_2_3 void date_log(int l
                return;
        time(&t1);
        tm = localtime(&t1);
 -      printf("%d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec);
 +      fprintf(stderr, "%d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec);
        va_start(argp, fmt);
        vprintf(fmt, argp);
        va_end(argp);
  }
  __printf_2_3 void (*para_log)(int, const char*, ...) = date_log;
  
 +static int set_channel(struct mixer *m, struct mixer_handle *h, const char *channel)
 +{
 +
 +      PARA_NOTICE_LOG("using %s mixer channel\n", channel?
 +              channel : "default");
 +      return m->set_channel(h, channel);
 +}
 +
  /* Fade to new volume in fade_time seconds. */
  static int fade(struct mixer *m, struct mixer_handle *h, int new_vol, int fade_time)
  {
        if (fade_time <= 0)
                return m->set(h, new_vol);
        secs = fade_time;
 -      PARA_NOTICE_LOG("fading to %d in %d seconds\n", new_vol, secs);
        ret = m->get(h);
        if (ret < 0)
                goto out;
        vol = ret;
 +      PARA_NOTICE_LOG("fading %s from %d to %d in %d seconds\n",
 +              conf.mixer_channel_arg, vol, new_vol, secs);
        diff = new_vol - vol;
        if (!diff) {
                sleep(secs);
@@@ -121,7 -112,7 +121,7 @@@ fail
        exit(EXIT_FAILURE);
  }
  
 -static void change_afs_mode_and_play(char *afs_mode)
 +static void change_afs_mode(char *afs_mode)
  {
        char *cmd;
  
        cmd = make_message("select %s", afs_mode);
        client_cmd(cmd);
        free(cmd);
 -      client_cmd("play");
 +}
 +
 +static int set_initial_volume(struct mixer *m, struct mixer_handle *h)
 +{
 +      int i, ret;
 +
 +      for (i = 0; i < conf.ivol_given; i++) {
 +              char *p, *ch, *arg = para_strdup(conf.ivol_arg[i]);
 +              int32_t iv;
 +              p = strchr(arg, ':');
 +              if (p) {
 +                      *p = '\0';
 +                      p++;
 +                      ch = arg;
 +              } else {
 +                      p = arg;
 +                      ch = NULL;
 +              }
 +              ret = para_atoi32(p, &iv);
 +              if (ret < 0) {
 +                      free(arg);
 +                      return ret;
 +              }
 +              ret = set_channel(m, h, ch);
 +              if (!ch)
 +                      ch = "default";
 +              if (ret < 0) {
 +                      PARA_WARNING_LOG("ignoring channel %s\n", ch);
 +                      ret = 0;
 +              } else {
 +                      PARA_INFO_LOG("initial volume %s: %d\n", ch, iv);
 +                      ret = m->set(h, iv);
 +              }
 +              free(arg);
 +              if (ret < 0)
 +                      return ret;
 +      }
 +      return 1;
  }
  
  static int sweet_dreams(struct mixer *m, struct mixer_handle *h)
        int fot = conf.fo_time_arg;
        int fiv = conf.fi_vol_arg;
        int fov = conf.fo_vol_arg;
 -      int iv = conf.ivol_arg;
  
        /* calculate wake time */
        time(&t1);
        client_cmd("stop");
        sleep(1);
        if (fot) {
 -              PARA_INFO_LOG("initial volume: %d\n", iv);
 -              ret = m->set(h, iv);
 +              ret = set_initial_volume(m, h);
 +              if (ret < 0)
 +                      return ret;
 +              change_afs_mode(fo_mood);
 +              client_cmd("play");
 +              ret = set_channel(m, h, conf.mixer_channel_arg);
                if (ret < 0)
                        return ret;
 -              change_afs_mode_and_play(fo_mood);
                ret = fade(m, h, fov, fot);
                if (ret < 0)
                        return ret;
                if (ret < 0)
                        return ret;
        }
 -      if (conf.sleep_mood_given)
 -              change_afs_mode_and_play(sleep_mood);
 -      else
 +      if (conf.sleep_mood_given) {
 +              change_afs_mode(sleep_mood);
 +              client_cmd("play");
 +      } else
                client_cmd("stop");
        if (!fit)
                return 1;
 +      change_afs_mode(fi_mood);
        for (;;) {
                time(&t1);
                if (wake_time_epoch <= t1 + fit)
                        (delay % 3600) / 60);
                sleep(delay);
        }
 -      change_afs_mode_and_play(fi_mood);
 +      client_cmd("play");
        ret = fade(m, h, fiv, fit);
        PARA_INFO_LOG("fade complete, returning\n");
        return ret;
@@@ -296,9 -246,22 +296,9 @@@ static void init_mixers(void
        }
  }
  
 -static int set_channel(struct mixer *m, struct mixer_handle *h)
 +static int set_val(struct mixer *m, struct mixer_handle *h)
  {
 -      char *channels;
 -      int ret;
 -
 -      ret = m->set_channel(h, conf.mixer_channel_arg);
 -      if (ret >= 0) {
 -              PARA_NOTICE_LOG("using %s mixer channel\n",
 -                      conf.mixer_channel_arg?  conf.mixer_channel_arg
 -                              : "default");
 -              return ret;
 -      }
 -      channels = m->get_channels(h);
 -      printf("Available channels: %s\n", channels);
 -      free(channels);
 -      return ret;
 +      return m->set(h, conf.val_arg);
  }
  
  static struct mixer *get_mixer_or_die(void)
@@@ -367,12 -330,7 +367,12 @@@ int main(int argc, char *argv[]
        ret = m->open(conf.mixer_device_arg, &h);
        if (ret < 0)
                goto out;
 -      ret = set_channel(m, h);
 +      ret = set_channel(m, h, conf.mixer_channel_arg);
 +      if (ret == -E_BAD_CHANNEL) {
 +              char *channels = m->get_channels(h);
 +              printf("Available channels: %s\n", channels);
 +              free(channels);
 +      }
        if (ret < 0)
                goto out;
        switch (conf.mode_arg) {
        case mode_arg_snooze:
                ret = snooze(m, h);
                break;
 +      case mode_arg_set:
 +              ret = set_val(m, h);
 +              break;
        default: /* sleep mode */
                ret = sweet_dreams(m, h);
                break;
diff --combined gcrypt.c
index 2a1a90d357dc3fd3cc81803bd0a8ce46a2734f71,1cfd10964c20e9ab30d77cff432405106cdb6836..751c1a4a65d4d0b3b9e5a90242462a83d3fc6cf1
+++ b/gcrypt.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2011-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2011-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -97,7 -97,7 +97,7 @@@ static void mgf1(unsigned char *seed, s
  {
        gcry_error_t gret;
        gcry_md_hd_t handle;
-       size_t n;;
+       size_t n;
        unsigned char *md;
        unsigned char octet_string[4], *rp = result, *end = rp + result_len;
  
@@@ -912,25 -912,11 +912,25 @@@ struct stream_cipher 
        gcry_cipher_hd_t handle;
  };
  
 -struct stream_cipher *sc_new(const unsigned char *data, int len)
 +struct stream_cipher *sc_new(const unsigned char *data, int len,
 +              bool use_aes)
  {
        gcry_error_t gret;
 -
        struct stream_cipher *sc = para_malloc(sizeof(*sc));
 +
 +      if (use_aes) {
 +              assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
 +              gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,
 +                      GCRY_CIPHER_MODE_CTR, 0);
 +              assert(gret == 0);
 +              gret = gcry_cipher_setkey(sc->handle, data,
 +                      AES_CRT128_BLOCK_SIZE);
 +              assert(gret == 0);
 +              gret = gcry_cipher_setctr(sc->handle,
 +                      data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
 +              assert(gret == 0);
 +              return sc;
 +      }
        gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR,
                GCRY_CIPHER_MODE_STREAM, 0);
        if (gret) {
diff --combined http_recv.c
index 9c42a1a85817f6cca6aa827e0ed349a01312949b,c7ef862977e170cf62acc37f18f9512e5e4009d5..1f02e48d9ae5ad2e32ae3273110cb540912e67a0
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -7,12 -7,7 +7,12 @@@
  /** \file http_recv.c paraslash's http receiver */
  
  #include <regex.h>
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
diff --combined http_send.c
index 60b877c08082ffa7e1cd7fb41617ab32bb7a465a,1c4b26eae6db11639625bd56041a740a48c40ff7..3e9c95393c5120c82bd91cc4bd84e5ea9c56f60c
@@@ -1,19 -1,14 +1,19 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file http_send.c paraslash's http sender */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
  #include <osl.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
diff --combined m4/gengetopt/fade.m4
index d0883c49618c45147080edfc3285653872448c79,5a71cc6b7c425f7b1e952da45e94deb477e2b9a6..59389ffefb5105ee8af56e4d7b844377c9d5d9c7
@@@ -1,6 -1,6 +1,6 @@@
  args "--conf-parser --no-handle-version --no-handle-help"
  
- purpose "An alarm clock and volume-fader for OSS and ALSA."
+ purpose "An alarm clock and volume-fader for OSS and ALSA"
  
  include(header.m4)
  define(CURRENT_PROGRAM,para_fade)
@@@ -17,11 -17,11 +17,11 @@@ option "mode" 
  #~~~~~~~~~~~~~~
  "how to fade volume"
        enum typestr = "mode"
 -      values = "sleep", "snooze", "fade"
 +      values = "sleep", "fade", "set", "snooze"
        default = "sleep"
        optional
        details="
 -              para_fade knows three different fading modes:
 +              para_fade knows the following modes:
  
                sleep mode: Change to the initial volume and select
                the initial afs mood/playlist. Then fade out until
@@@ -33,8 -33,6 +33,8 @@@
                fade: Fade the volume to the given value in the
                given time.
  
 +              set: Just set the value and exit.
 +
                snooze: Fade out, sleep a bit and fade in.
  "
  
@@@ -88,15 -86,12 +88,15 @@@ section "Options for sleep mode
  option "ivol" -
  #~~~~~~~~~~~~~~
  "set initial volume"
 -      int typestr = "volume"
 +      string typestr = "[channel:]volume"
        default = "60"
        optional
 +      multiple
        details = "
                Used as the start volume, before fading out to the
 -              fade out volume.
 +              fade out volume. The channel part may be omitted, in
 +              which case the default channel is used. This option
 +              may be given multiple times.
        "
  
  option "fo-mood" -
@@@ -233,14 -228,4 +233,14 @@@ option "fade-time" 
        int typestr = "seconds"
        default = "5"
        optional
 +
 +section "Options for set mode"
 +##############################
 +
 +option "val" -
 +"value to set"
 +      int typestr = "value"
 +      default = "0"
 +      optional
 +
  </qu>
diff --combined net.c
index 986660fa8f12fd11649d9bd4b3310b01837811dc,503e4de955c54fe9ef2f99150b62fe9172503852..c11f67c4bac3f7f316daa317ae71ed8ebe6f10a9
--- 1/net.c
--- 2/net.c
+++ b/net.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
   */
  #define _GNU_SOURCE
  
 +#include <netinet/in.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <sys/types.h>
 +#include <sys/socket.h>
  #include <netdb.h>
  
  /* At least NetBSD needs these. */
@@@ -147,9 -142,9 +147,9 @@@ static bool host_string_ok(const char *
   * \param hostlen The maximum length of \a host.
   * \param port          To return the port number (if any) of \a url.
   *
 - * \return Pointer to \a host, or NULL if failed.
 - * If NULL is returned, \a host and \a portnum are undefined. If no
 - * port number was present in \a url, \a portnum is set to -1.
 + * \return Pointer to \a host, or \p NULL if failed.  If \p NULL is returned,
 + * \a host and \a port are undefined. If no port number was present in \a url,
 + * \a port is set to -1.
   *
   * \sa RFC 3986, 3.2.2/3.2.3
   */
@@@ -173,16 -168,16 +173,16 @@@ char *parse_url(const char *url
                if (*o++ != ']' || (*o != '\0' && *o != ':'))
                        goto failed;
        } else {
 -              for (; (*c = *o == ':'? '\0' : *o); c++, o++)
 -                      if (c == end)
 +              for (; (*c = *o == ':'? '\0' : *o); c++, o++) {
 +                      if (c == end && o[1])
                                goto failed;
 +              }
        }
  
        if (*o == ':')
                if (para_atoi32(++o, port) < 0 ||
                    *port < 0 || *port > 0xffff)
                        goto failed;
 -
        if (host_string_ok(host))
                return host;
  failed:
@@@ -333,14 -328,7 +333,14 @@@ static void flowopt_setopts(int sockfd
                }
  }
  
 -static void flowopt_cleanup(struct flowopts *fo)
 +/**
 + * Deallocate all resources of a flowopts structure.
 + *
 + * \param fo A pointer as returned from flowopt_new().
 + *
 + * It's OK to pass \p NULL here in which case the function does nothing.
 + */
 +void flowopt_cleanup(struct flowopts *fo)
  {
        struct pre_conn_opt *cur, *next;
  
  }
  
  /**
 - * Resolve IPv4/IPv6 address and create a ready-to-use active or passive socket.
 + * Resolve an IPv4/IPv6 address.
   *
   * \param l4type The layer-4 type (\p IPPROTO_xxx).
 - * \param passive Whether this is a passive (1) or active (0) socket.
 + * \param passive Whether \p AI_PASSIVE should be included as hint.
   * \param host Remote or local hostname or IPv/6 address string.
 - * \param port_number Decimal port number.
 - * \param fo Socket options to be set before making the connection.
 + * \param port_number Used to set the port in each returned address structure.
 + * \param result addrinfo structures are returned here.
   *
 - * This creates a ready-made IPv4/v6 socket structure after looking up the
 - * necessary parameters. The interpretation of \a host depends on the value of
 - * \a passive:
 - *    - on a passive socket host is interpreted as an interface IPv4/6 address
 - *      (can be left NULL);
 - *    - on an active socket, \a host is the peer DNS name or IPv4/6 address
 - *      to connect to;
 - *    - \a port_number is in either case the numeric port number (not service
 - *      string).
 - *
 - * Furthermore, bind(2) is called on passive sockets, and connect(2) on active
 - * sockets. The algorithm tries all possible address combinations until it
 - * succeeds. If \a fo is supplied, options are set and cleanup is performed.
 - *
 - * \return This function returns 1 on success and \a -E_ADDRESS_LOOKUP when no
 - * matching connection could be set up (with details in the error log).
 - *
 - *  \sa ipv6(7), getaddrinfo(3), bind(2), connect(2).
 + * The interpretation of \a host depends on the value of \a passive. On a
 + * passive socket host is interpreted as an interface IPv4/6 address (can be
 + * left NULL). On an active socket, \a host is the peer DNS name or IPv4/6
 + * address to connect to.
 + *
 + * \return Standard.
 + *
 + * \sa getaddrinfo(3).
   */
 -int makesock(unsigned l4type, bool passive,
 -           const char *host, uint16_t port_number,
 -           struct flowopts *fo)
 +int lookup_address(unsigned l4type, bool passive, const char *host,
 +              int port_number, struct addrinfo **result)
  {
 -      struct addrinfo *local = NULL, *src = NULL, *remote = NULL,
 -              *dst = NULL, hints;
 -      unsigned int    l3type = AF_UNSPEC;
 -      int             rc, on = 1, sockfd = -1,
 -                      socktype = sock_type(l4type);
 +      int ret;
        char port[6]; /* port number has at most 5 digits */
 +      struct addrinfo *addr = NULL, hints;
  
 -      sprintf(port, "%u", port_number);
 +      *result = NULL;
 +      sprintf(port, "%u", port_number & 0xffff);
        /* Set up address hint structure */
        memset(&hints, 0, sizeof(hints));
 -      hints.ai_family = l3type;
 -      hints.ai_socktype = socktype;
 -      /* 
 +      hints.ai_family = AF_UNSPEC;
 +      hints.ai_socktype = sock_type(l4type);
 +      /*
         * getaddrinfo does not support SOCK_DCCP, so for the sake of lookup
         * (and only then) pretend to be UDP.
         */
        if (l4type == IPPROTO_DCCP)
                hints.ai_socktype = SOCK_DGRAM;
 -
        /* only use addresses available on the host */
        hints.ai_flags = AI_ADDRCONFIG;
 -      if (l3type == AF_INET6)
 -              /* use v4-mapped-v6 if no v6 addresses found */
 -              hints.ai_flags |= AI_V4MAPPED | AI_ALL;
 -
        if (passive && host == NULL)
                hints.ai_flags |= AI_PASSIVE;
 -
        /* Obtain local/remote address information */
 -      if ((rc = getaddrinfo(host, port, &hints, passive ? &local : &remote))) {
 -              PARA_ERROR_LOG("can not resolve %s address %s#%s: %s.\n",
 -                              layer4_name(l4type),
 -                              host? host : (passive? "[loopback]" : "[localhost]"),
 -                              port, gai_strerror(rc));
 -              rc = -E_ADDRESS_LOOKUP;
 -              goto out;
 +      ret = getaddrinfo(host, port, &hints, &addr);
 +      if (ret != 0) {
 +              PARA_ERROR_LOG("can not resolve %s address %s#%s: %s\n",
 +                      layer4_name(l4type),
 +                      host? host : (passive? "[loopback]" : "[localhost]"),
 +                      port, gai_strerror(ret));
 +              return -E_ADDRESS_LOOKUP;
        }
 +      *result = addr;
 +      return 1;
 +}
  
 -      /* Iterate over all src/dst combination, exhausting dst first */
 -      for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
 -              if (src && dst && src->ai_family == AF_INET
 -                              && dst->ai_family == AF_INET6)
 -                      goto get_next_dst; /* v4 -> v6 is not possible */
 -
 -              sockfd = socket(src ? src->ai_family : dst->ai_family,
 -                      socktype, l4type);
 -              if (sockfd < 0)
 -                      goto get_next_dst;
 +/**
 + * Create an active or passive socket.
 + *
 + * \param l4type \p IPPROTO_TCP, \p IPPROTO_UDP, or \p IPPROTO_DCCP.
 + * \param passive Whether to call bind(2) or connect(2).
 + * \param ai Address information as obtained from \ref lookup_address().
 + * \param fo Socket options to be set before making the connection.
 + *
 + * bind(2) is called on passive sockets, and connect(2) on active sockets. The
 + * algorithm tries all possible address combinations until it succeeds. If \a
 + * fo is supplied, options are set but cleanup must be performed in the caller.
 + *
 + * \return File descriptor on success, \p E_MAKESOCK on errors.
 + *
 + * \sa \ref lookup_address(), \ref makesock(), ip(7), ipv6(7), bind(2),
 + * connect(2).
 + */
 +int makesock_addrinfo(unsigned l4type, bool passive, struct addrinfo *ai,
 +              struct flowopts *fo)
 +{
 +      int ret = -E_MAKESOCK, on = 1;
  
 +      for (; ai; ai = ai->ai_next) {
 +              int fd;
 +              ret = socket(ai->ai_family, sock_type(l4type), l4type);
 +              if (ret < 0)
 +                      continue;
 +              fd = ret;
 +              flowopt_setopts(fd, fo);
 +              if (!passive) {
 +                      if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0)
 +                              return fd;
 +                      close(fd);
 +                      continue;
 +              }
                /*
                 * Reuse the address on passive sockets to avoid failure on
                 * restart (protocols using listen()) and when creating
                 * multiple listener instances (UDP multicast).
                 */
 -              if (passive && setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
 -                                                &on, sizeof(on)) == -1) {
 -                      rc = errno;
 -                      close(sockfd);
 -                      PARA_ERROR_LOG("can not set SO_REUSEADDR: %s\n",
 -                                     strerror(rc));
 -                      rc = -ERRNO_TO_PARA_ERROR(rc);
 -                      break;
 -              }
 -              flowopt_setopts(sockfd, fo);
 -
 -              if (src) {
 -                      if (bind(sockfd, src->ai_addr, src->ai_addrlen) < 0) {
 -                              close(sockfd);
 -                              goto get_next_src;
 -                      }
 -                      if (!dst) /* bind-only completed successfully */
 -                              break;
 +              if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on,
 +                              sizeof(on)) == -1) {
 +                      close(fd);
 +                      continue;
                }
 -
 -              if (dst && connect(sockfd, dst->ai_addr, dst->ai_addrlen) == 0)
 -                      break; /* connection completed successfully */
 -              close(sockfd);
 -get_next_dst:
 -              if (dst && (dst = dst->ai_next))
 +              if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
 +                      close(fd);
                        continue;
 -get_next_src:
 -              if (src && (src = src->ai_next)) /* restart inner loop */
 -                      dst = remote;
 +              }
 +              return fd;
        }
 -out:
 -      if (local)
 -              freeaddrinfo(local);
 -      if (remote)
 -              freeaddrinfo(remote);
 -      flowopt_cleanup(fo);
 -
 -      if (src == NULL && dst == NULL) {
 -              if (rc >= 0)
 -                      rc = -E_MAKESOCK;
 -              PARA_ERROR_LOG("can not create %s socket %s#%s.\n",
 -                      layer4_name(l4type), host? host : (passive?
 -                      "[loopback]" : "[localhost]"), port);
 -              return rc;
 +      return -E_MAKESOCK;
 +}
 +
 +/**
 + * Resolve IPv4/IPv6 address and create a ready-to-use active or passive socket.
 + *
 + * \param l4type The layer-4 type (\p IPPROTO_xxx).
 + * \param passive Whether this is a passive or active socket.
 + * \param host Passed to \ref lookup_address().
 + * \param port_number Passed to \ref lookup_address().
 + * \param fo Passed to \ref makesock_addrinfo().
 + *
 + * This creates a ready-made IPv4/v6 socket structure after looking up the
 + * necessary parameters. The function first calls \ref lookup_address() and
 + * passes the address information to makesock_addrinfo() to create and
 + * initialize the socket.
 + *
 + * \return The newly created file descriptor on success, a negative error code
 + * on failure.
 + *
 + * \sa \ref lookup_address(), \ref makesock_addrinfo().
 + */
 +int makesock(unsigned l4type, bool passive, const char *host, uint16_t port_number,
 +              struct flowopts *fo)
 +{
 +      struct addrinfo *ai;
 +      int ret = lookup_address(l4type, passive, host, port_number, &ai);
 +
 +      if (ret >= 0)
 +              ret = makesock_addrinfo(l4type, passive, ai, fo);
 +      if (ai)
 +              freeaddrinfo(ai);
 +      if (ret < 0) {
 +              PARA_ERROR_LOG("can not create %s socket %s#%d.\n",
 +              layer4_name(l4type), host? host : (passive?
 +              "[loopback]" : "[localhost]"), port_number);
        }
 -      return sockfd;
 +      return ret;
  }
  
  /**
@@@ -710,32 -687,6 +710,32 @@@ void extract_v4_addr(const struct socka
                *ia = ((struct sockaddr_in *)sa)->sin_addr;
  }
  
 +/**
 + * Compare the address part of IPv4/6 addresses.
 + *
 + * \param sa1 First address.
 + * \param sa2 Second address.
 + *
 + * \return True iff the IP address of \a sa1 and \a sa2 match.
 + */
 +bool sockaddr_equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
 +{
 +      if (!sa1 || !sa2)
 +              return false;
 +      if (sa1->sa_family != sa2->sa_family)
 +              return false;
 +      if (sa1->sa_family == AF_INET) {
 +              struct sockaddr_in *a1 = (typeof(a1))sa1,
 +                      *a2 = (typeof (a2))sa2;
 +              return a1->sin_addr.s_addr == a2->sin_addr.s_addr;
 +      } else if (sa1->sa_family == AF_INET6) {
 +              struct sockaddr_in6 *a1 = (typeof(a1))sa1,
 +                      *a2 = (typeof (a2))sa2;
 +              return !memcmp(a1, a2, sizeof(*a1));
 +      } else
 +              return false;
 +}
 +
  /**
   * Receive data from a file descriptor.
   *
diff --combined net.h
index e249498e3901b307bb68c57fe9bb4ac4d33d93a2,9cbca0f44e92fd9f61dcbcac36122a2efdae1047..877d1cbbe537bcb70f3d4ededc91514f226e61c0
--- 1/net.h
--- 2/net.h
+++ b/net.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2006-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2006-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -61,7 -61,6 +61,7 @@@ struct flowopts
  extern struct flowopts *flowopt_new(void);
  extern void flowopt_add(struct flowopts *fo, int level, int opt,
                const char *name, const void *val, int len);
 +void flowopt_cleanup(struct flowopts *fo);
  /** Flowopt shortcut macros */
  #define OPT_ADD(fo, lev, opt, val, len)       flowopt_add(fo, lev, opt, #opt, val, len)
  
@@@ -102,17 -101,12 +102,17 @@@ _static_inline_ bool is_valid_ipv6_addr
        return inet_pton(AF_INET6, address, &test_it) != 0;
  }
  
 +int lookup_address(unsigned l4type, bool passive, const char *host,
 +              int port_number, struct addrinfo **result);
 +
  /**
   * Generic socket creation (passive and active sockets).
   */
 -extern int makesock(unsigned l4type, bool passive,
 -                  const char *host, uint16_t port_number,
 -                  struct flowopts *fo);
 +int makesock(unsigned l4type, bool passive, const char *host,
 +              uint16_t port_number, struct flowopts *fo);
 +
 +int makesock_addrinfo(unsigned l4type, bool passive, struct addrinfo *ai,
 +              struct flowopts *fo);
  
  static inline int para_connect_simple(unsigned l4type,
                                      const char *host, uint16_t port)
  }
  
  void extract_v4_addr(const struct sockaddr_storage *ss, struct in_addr *ia);
 +bool sockaddr_equal(const struct sockaddr *sa1, const struct sockaddr *sa2);
  
  /**
   * Functions to support listening sockets.
diff --combined oss_mix.c
index 7e19fcbe3f9e7dd473f49f20f15442683dfff32d,c325329f4d6f2db802c41d7125c50a7b650c0f31..5fbfea08e178a56f43a0ead27d3a88c603c4145b
+++ b/oss_mix.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 1998-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1998-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
@@@ -98,7 -98,7 +98,7 @@@ static int oss_mix_set_channel(struct m
                handle->id = i;
                return 1;
        }
 -      return -E_OSS_MIXER_CHANNEL;
 +      return -E_BAD_CHANNEL;
  }
  
  static int oss_mix_get(struct mixer_handle *handle)
diff --combined para.h
index d1e266fcfb249758b633860540a4bd637cc7152a,870656b163247a812f4b4d7091330838084c6945..6bd048d8c590cb2bc493a1f65860a30517f6230e
--- 1/para.h
--- 2/para.h
+++ b/para.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1997-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  #include <limits.h>
  #include <stdarg.h>
  #include <ctype.h>
 -#include <netinet/in.h>
 -#include <arpa/inet.h>
 -#include <sys/socket.h>
 -#include <sys/un.h> /* needed by create_pf_socket */
  #include <string.h>
  #include <assert.h>
  #include <stdbool.h>
 +#include <inttypes.h>
 +#include <sys/uio.h>
  #include "gcc-compat.h"
  
  /** used in various contexts */
diff --combined send_common.c
index a16869b07154022bfd9adf4a56250d34a2de16fb,77cdabae3cff8326027e0ded13b4856ee35e3dbb..0baac3a6f5c9713e810f97b53d13275f4178c610
@@@ -1,18 -1,13 +1,18 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file send_common.c Functions used by more than one paraslash sender. */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <osl.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
diff --combined server.c
index f92ef5518cd507ea5e1ef6026e03f841f4b37e37,342946abe0a3107ae40b2e17c973f0977b9b584d..fa19ce4225111e33ec7f192935f455c6cd5b2d76
+++ b/server.c
@@@ -1,77 -1,42 +1,48 @@@
  /*
-  * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1997-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file server.c Paraslash's main server. */
  
  /**
-  * \mainpage Starting points for getting an overview:
+  * \mainpage Main data structures:
   *
-  *    - The main programs: \ref server.c, \ref audiod.c, \ref client.c,
-  *      \ref audioc.c, \ref afh.c, \ref play.c,
   *    - Server: \ref server_command, \ref sender,
-  *    - Audio file selector: \ref audio_format_handler, \ref afs_table,
-  *    - Client: \ref receiver, \ref receiver_node, \ref filter,
-  *      \ref filter_node, \ref writer_node.
-  *
-  *
-  * The gory details, listed by topic:
-  *
-  *    - Audio format handlers: \ref send_common.c \ref mp3_afh.c,
-  *      \ref ogg_afh.c, \ref aac_afh.c, \ref wma_afh.c, \ref spx_afh.c
-  *    - Decoders: \ref mp3dec_filter.c, \ref oggdec_filter.c,
-  *      \ref aacdec_filter.c, \ref wmadec_filter.c, spxdec_filter.c,
-  *      \ref flacdec_filter.c,
-  *    - Volume normalizer: \ref compress_filter.c,
-  *    - Output: \ref alsa_write.c, \ref osx_write.c, \ref oss_write.c,
-  *    - http: \ref http_recv.c, \ref http_send.c,
-  *    - udp: \ref udp_recv.c, \ref udp_send.c,
-  *    - dccp: \ref dccp_recv.c, \ref dccp_send.c,
-  *    - Audio file selector: \ref afs.c, \ref aft.c, \ref mood.c,
-  *    - Afs structures: \ref afs_table, \ref audio_file_data,
-  *      \ref afs_info \ref afh_info,
-  *    - Afs tables: \ref aft.c, \ref mood.c, \ref playlist.c,
-  *      \ref attribute.c, \ref score.c,
-  *    - The virtual streaming system: \ref vss.c, \ref chunk_queue.c.
-  *
-  * Lower levels:
-  *
-  *    - Scheduling: \ref sched.c, \ref sched.h,
-  *    - Networking: \ref net.c,
-  *    - File descriptors: \ref fd.c,
-  *    - Signals: \ref signal.c,
-  *    - Daemons: \ref daemon.c,
-  *    - Strings: \ref string.c, \ref string.h,
+  *    - Audio file selector: \ref afs_info, \ref afs_table,
+  *    - Audio format handler: \ref audio_format_handler, \ref afh_info
+  *    - Receivers/filters/writers: \ref receiver, \ref receiver_node,
+  *      \ref filter, \ref filter_node, \ref writer_node, \ref writer.
+  *
+  * Selected APIs:
+  *
+  *    - Scheduling: \ref sched.h,
+  *    - Buffer trees: \ref buffer_tree.h,
+  *    - Sideband API: \ref sideband.h,
+  *    - Crypto: \ref crypt.h, \ref crypt_backend.h,
+  *    - Error subsystem: \ref error.h, \ref error2.c,
+  *    - Inter process communication: \ref ipc.h,
+  *    - Forward error correction: \ref fec.h,
+  *    - Daemons: \ref daemon.h,
+  *    - Mixer API: \ref mix.h,
+  *    - Interactive sessions: \ref interactive.h,
+  *    - File descriptors: \ref fd.h,
+  *    - Signals: \ref signal.h,
+  *    - Networking: \ref net.h,
   *    - Time: \ref time.c,
-  *    - Spawning processes: \ref exec.c,
-  *    - Inter process communication: \ref ipc.c,
-  *    - Blob tables: \ref blob.c,
-  *    - The error subsystem: \ref error.h.
-  *    - Access control for paraslash senders: \ref acl.c, \ref acl.h.
-  *    - Internal crypto API: \ref crypt.h.
-  *    - interactive sessions (libreadline): \ref interactive.c.
-  *
-  * Low-level data structures:
-  *
-  *    - Doubly linked lists: \ref list.h,
-  *    - Ring buffer: \ref ringbuffer.c, \ref ringbuffer.h,
-  *    - openssl: \ref crypt.c
-  *    - libgcrypt: \ref gcrypt.c
-  *    - Forward error correction: \ref fec.c.
+  *    - Doubly linked lists: \ref list.h.
   */
  
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <signal.h>
  #include <regex.h>
  #include <osl.h>
 +#include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
diff --combined udp_recv.c
index 96b6c73123acba4da30e34e9d50850cfa7b554ac,ca0cfc333e3233f61e7dadce080e8865755b3518..15cf73eb210dd0354b27abf795e60fdd1959377b
@@@ -1,18 -1,13 +1,18 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  /** \file udp_recv.c Paraslash's udp receiver */
  
 +#include <netinet/in.h>
  #include <regex.h>
  #include <sys/socket.h>
  #include <net/if.h>
 +#include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"
diff --combined udp_send.c
index 4580f009b3cb4b75d2f9e4c3a4e274cfc230e387,a74b63485fc17d4da2b08194ba4b05b35ec29e77..6ed5026ac31102932d4fb3b23e6e87d375002096
@@@ -1,22 -1,18 +1,22 @@@
  /*
-  * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 2005-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file udp_send.c Para_server's udp sender. */
  
 -
 +#include <netinet/in.h>
 +#include <sys/socket.h>
  #include <regex.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <netinet/udp.h>
  #include <net/if.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
  #include <osl.h>
 +#include <netdb.h>
  
  #include "server.cmdline.h"
  #include "para.h"
diff --combined vss.c
index 2349b0931cfcc22b4d54b01f6c26f6b545614e6a,d9e276c8fc61b10551c3cafbce1c7c95f338e5ef..3ace49e9e90e8fb27144964a0f61f1fae267e843
--- 1/vss.c
--- 2/vss.c
+++ b/vss.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
+  * Copyright (C) 1997-2014 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
   * senders.
   */
  
 +#include <sys/socket.h>
 +#include <netinet/in.h>
  #include <regex.h>
  #include <osl.h>
 +#include <sys/types.h>
 +#include <arpa/inet.h>
 +#include <sys/un.h>
 +#include <netdb.h>
  
  #include "para.h"
  #include "error.h"