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.
...
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.
------------------------------------------
- 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"
----------------------------------------
/*
- * 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.
/*
- * 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"
/*
- * 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.
*/
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;
}
/*
- * 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>
/*
- * 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"
* 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.
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)
/*
- * 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"
/*
- * 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"
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;
/*
- * 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"
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;
}
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;
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;
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)
])
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
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"
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
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))
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)
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"
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"
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,
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
/*
- * 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.
*/
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
+#include <openssl/aes.h>
#include "para.h"
#include "error.h"
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;
}
*/
#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;
/*
- * 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.
*/
*
* \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.
/*
- * 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.
*/
/* 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);
/*
- * 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"
}
fd = makesock(IPPROTO_DCCP, 0, conf->host_arg, conf->port_arg, fo);
+ flowopt_cleanup(fo);
free(ccids);
if (fd < 0)
return fd;
/*
- * 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"
/*
- * 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.
*/
#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 \
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"), \
/*
- * 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.
*/
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);
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;
}
}
-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)
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;
/*
- * 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.
*/
{
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;
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) {
/*
- * 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_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"
/*
- * 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"
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)
#~~~~~~~~~~~~~~
"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
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.
"
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" -
int typestr = "seconds"
default = "5"
optional
+
+section "Options for set mode"
+##############################
+
+option "val" -
+"value to set"
+ int typestr = "value"
+ default = "0"
+ optional
+
</qu>
/*
- * 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. */
* \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
*/
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:
}
}
-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;
}
/**
*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.
*
/*
- * 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.
*/
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)
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.
/*
- * 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.
*/
handle->id = i;
return 1;
}
- return -E_OSS_MIXER_CHANNEL;
+ return -E_BAD_CHANNEL;
}
static int oss_mix_get(struct mixer_handle *handle)
/*
- * 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 */
/*
- * 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"
/*
- * 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"
/*
- * 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"
/*
- * 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"
/*
- * 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"