summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Noll <maan@tuebingen.mpg.de>2026-10-21 01:27:33 +0200
committerAndre Noll <maan@tuebingen.mpg.de>2026-10-21 01:27:33 +0200
commitd4c394fb16e51b117a652fd4700bfd3fff6726c1 (patch)
treecab9445c6f15f7955926980ef1b4a57a2d079b21
parent681f731fbf7cfbe6f4ed41f4fe60673aedbcfb79 (diff)
parent532eca24d41745ade0c1538f768883132c0c85e2 (diff)
Merge topic branch t/mixer into pupu
para_mixer improvements ----------------------- Link para_mixer with audioc_common.o to make it single threaded. * t/mixer: Make para_mixer single-threaded. mixer: Introduce die(). crypt: use {con,de}structor to init/shutdown the library. client: Use a named enumeration for the client status. Introduce struct client_config to hide context from public API. mixer: Link with audioc_common.o Move recv_buffer() and recv_bin_buffer() from net.c to fd.c. mixer: Rename client_cmd() -> run_client_cmd(). mixer: Rename audioc_cmd() -> run_audioc_cmd().
-rw-r--r--Makefile21
-rw-r--r--audioc.c6
-rw-r--r--audiod.c3
-rw-r--r--client.c3
-rw-r--r--client.h18
-rw-r--r--client_common.c243
-rw-r--r--crypt.h16
-rw-r--r--fd.c50
-rw-r--r--fd.h2
-rw-r--r--gcrypt.c9
-rw-r--r--gui.c4
-rw-r--r--m4/lls/mixer.suite.m41
-rw-r--r--mixer.c164
-rw-r--r--net.c52
-rw-r--r--net.h3
-rw-r--r--openssl.c21
-rw-r--r--server.c3
17 files changed, 354 insertions, 265 deletions
diff --git a/Makefile b/Makefile
index 4961c8bd..d0a65563 100644
--- a/Makefile
+++ b/Makefile
@@ -217,13 +217,17 @@ ifneq ($(CRYPTOLIB),)
endif
endif
ifneq ($(HAVE_OSS)-$(HAVE_ALSA),no-no)
- executables += mixer
- mixer_objs := $(addsuffix .o, mixer exec string fd time lsu version)
- ifeq ($(HAVE_OSS),yes)
- mixer_objs += oss_mix.o
- endif
- ifeq ($(HAVE_ALSA),yes)
- mixer_objs += alsa_mix.o
+ ifneq ($(CRYPTOLIB),)
+ executables += mixer
+ mixer_objs := $(addsuffix .o, mixer string fd time lsu version \
+ audioc_common net buffer_tree crypt_common \
+ $(CRYPTOLIB) sched client_common sideband)
+ ifeq ($(HAVE_OSS),yes)
+ mixer_objs += oss_mix.o
+ endif
+ ifeq ($(HAVE_ALSA),yes)
+ mixer_objs += alsa_mix.o
+ endif
endif
endif
ifeq ($(HAVE_CURSES),yes)
@@ -388,7 +392,7 @@ audioc_objs += audioc.lsg.o
audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod write) \
client.lsg.o audiod.lsg.o
client_objs += client.lsg.o
-mixer_objs += mixer.lsg.o
+mixer_objs += mixer.lsg.o client.lsg.o
filter_objs += filter_cmd.lsg.o filter.lsg.o
gui_objs += gui.lsg.o
play_objs += $(addsuffix _cmd.lsg.o, recv filter play write) play.lsg.o
@@ -577,6 +581,7 @@ para_gui: LDFLAGS += $(curses_ldflags)
para_server \
para_client \
para_audiod \
+para_mixer \
:LDFLAGS += \
$(crypto_ldflags)
diff --git a/audioc.c b/audioc.c
index 2816c919..7f443a37 100644
--- a/audioc.c
+++ b/audioc.c
@@ -14,12 +14,7 @@
#include "para.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 <signal.h>
#include <lopsub.h>
@@ -28,7 +23,6 @@
#include "audioc.h"
#include "error.h"
#include "lsu.h"
-#include "net.h"
#include "string.h"
#include "fd.h"
#include "sideband.h"
diff --git a/audiod.c b/audiod.c
index 593e2906..a4c7d92e 100644
--- a/audiod.c
+++ b/audiod.c
@@ -30,7 +30,6 @@
#include "para.h"
#include "error.h"
#include "lsu.h"
-#include "crypt.h"
#include "list.h"
#include "sched.h"
#include "buffer_tree.h"
@@ -1356,7 +1355,6 @@ int main(int argc, char *argv[])
version_handle_flag("audiod", OPT_GIVEN(VERSION));
handle_help_flags();
parse_config_or_die();
- crypt_init();
daemon_set_priority(OPT_UINT32_VAL(PRIORITY));
if (daemon_init_colors_or_die(OPT_UINT32_VAL(COLOR), COLOR_AUTO,
COLOR_NO, OPT_GIVEN(LOGFILE))) {
@@ -1386,7 +1384,6 @@ int main(int argc, char *argv[])
ret = init_tasks_and_schedule();
audiod_cleanup();
sched_shutdown(sched);
- crypt_shutdown();
out:
lls_free_parse_result(lpr, CMD_PTR);
if (errctx)
diff --git a/client.c b/client.c
index 4579f282..09c7ad61 100644
--- a/client.c
+++ b/client.c
@@ -17,7 +17,6 @@
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "crypt.h"
#include "string.h"
#include "stdin.h"
#include "stdout.h"
@@ -685,7 +684,6 @@ int main(int argc, char *argv[])
{
int ret;
- crypt_init();
ret = client_parse_config(argc, argv, &ct);
if (ret < 0)
goto out;
@@ -727,7 +725,6 @@ int main(int argc, char *argv[])
}
}
sched_shutdown(sched);
- crypt_shutdown();
stdout_free(sot);
free_sit:
stdin_free(sit);
diff --git a/client.h b/client.h
index e7b5fa5b..9ce7212f 100644
--- a/client.h
+++ b/client.h
@@ -3,7 +3,7 @@
/** \file client.h Common client functions and exported symbols from client_common.c. */
/** The different states of a connection from the view of the client. */
-enum {
+enum client_status {
/** TCP connection is established. */
CL_CONNECTED,
/** Server sends the welcome message. */
@@ -25,25 +25,13 @@ enum {
/** Data specific to a client task. */
struct client_task {
/** The state of the connection. */
- int status;
- /** The file descriptor and the session keys. */
- struct stream_cipher_context scc;
- /** The sideband contexts for receiving/sending. */
- struct sb_context *sbc[2];
+ enum client_status status;
/** The buffer tree nodes for receiving/sending. */
struct btr_node *btrn[2];
- /** The hash value of the decrypted challenge. */
- unsigned char *challenge_hash;
/** The parsed command line (including the command). */
struct lls_parse_result *lpr;
- /** The RSA private key. */
- char *key_file;
- /** Paraslash user name. */
- char *user;
/** The client task structure. */
struct task *task;
- /** List of features supported by the server. */
- char **features;
};
#define CLIENT_CMD_PTR (lls_cmd(0, client_suite))
@@ -56,6 +44,7 @@ struct client_task {
#define CLIENT_OPT_STRING_VAL(_name, _lpr) \
(lls_string_val(0, CLIENT_OPT_RESULT(_name, _lpr)))
+struct sched; /* avoid gcc warning */
void client_close(struct client_task *ct);
int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr);
int client_connect(struct client_task *ct, struct sched *s,
@@ -63,3 +52,4 @@ int client_connect(struct client_task *ct, struct sched *s,
int client_open(int argc, char *argv[], struct client_task **ct_ptr,
struct btr_node *parent, struct btr_node *child,
struct sched *sched);
+int client_run(int argc, char *argv[], char **result);
diff --git a/client_common.c b/client_common.c
index 398e577b..9116d5a3 100644
--- a/client_common.c
+++ b/client_common.c
@@ -24,9 +24,31 @@
#include "client.h"
#include "buffer_tree.h"
-/** The size of the receiving buffer. */
+/* The size of the receiving buffer. */
#define CLIENT_BUFSIZE 4000
+struct client_config {
+ struct client_task client_task;
+ /* The file descriptor and the session keys. */
+ struct stream_cipher_context scc;
+ /* The sideband contexts for receiving/sending. */
+ struct sb_context *sbc[2];
+ /* List of features supported by the server. */
+ char **features;
+ /* The RSA private key. */
+ char *key_file;
+ /* Paraslash user name. */
+ char *user;
+ /* The hash value of the decrypted challenge. */
+ unsigned char *challenge_hash;
+};
+
+static struct client_config *client_config_of(struct client_task *client_task)
+{
+ return (struct client_config *)((char *)client_task
+ - offsetof(struct client_config, client_task));
+}
+
/**
* Close the connection to para_server and free all resources.
*
@@ -36,14 +58,17 @@
*/
void client_close(struct client_task *ct)
{
+ struct client_config *cc;
+
if (!ct)
return;
- free(ct->user);
- free(ct->key_file);
+ cc = client_config_of(ct);
+ free(cc->user);
+ free(cc->key_file);
lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
- free(ct->challenge_hash);
- sb_free(ct->sbc[0]);
- sb_free(ct->sbc[1]);
+ free(cc->challenge_hash);
+ sb_free(cc->sbc[0]);
+ sb_free(cc->sbc[1]);
free(ct);
}
@@ -59,20 +84,21 @@ static void client_pre_monitor(struct sched *s, void *context)
{
int ret;
struct client_task *ct = context;
+ struct client_config *cc = client_config_of(ct);
- if (ct->scc.fd < 0)
+ if (cc->scc.fd < 0)
return;
switch (ct->status) {
case CL_CONNECTED:
case CL_SENT_AUTH:
case CL_SENT_CH_RESPONSE:
- sched_monitor_readfd(ct->scc.fd, s);
+ sched_monitor_readfd(cc->scc.fd, s);
return;
case CL_RECEIVED_WELCOME:
case CL_RECEIVED_PROCEED:
case CL_RECEIVED_CHALLENGE:
- sched_monitor_writefd(ct->scc.fd, s);
+ sched_monitor_writefd(cc->scc.fd, s);
return;
case CL_SENDING:
@@ -81,7 +107,7 @@ static void client_pre_monitor(struct sched *s, void *context)
if (ret < 0)
sched_min_delay(s);
else if (ret > 0)
- sched_monitor_writefd(ct->scc.fd, s);
+ sched_monitor_writefd(cc->scc.fd, s);
}
__attribute__ ((fallthrough));
case CL_EXECUTING:
@@ -90,7 +116,7 @@ static void client_pre_monitor(struct sched *s, void *context)
if (ret < 0)
sched_min_delay(s);
else if (ret > 0)
- sched_monitor_readfd(ct->scc.fd, s);
+ sched_monitor_readfd(cc->scc.fd, s);
}
return;
}
@@ -99,25 +125,26 @@ static void client_pre_monitor(struct sched *s, void *context)
static int send_sb(struct client_task *ct, int channel, void *buf, size_t numbytes,
enum sb_designator band, bool dont_free)
{
- int ret, fd = ct->scc.fd;
+ struct client_config *cc = client_config_of(ct);
+ int ret, fd = cc->scc.fd;
struct iovec iov[2];
- if (!ct->sbc[channel]) {
+ if (!cc->sbc[channel]) {
struct sb_buffer sbb;
sb_transformation trafo = ct->status < CL_RECEIVED_PROCEED?
NULL : sc_trafo;
sbb = (typeof(sbb))SBB_INIT(band, buf, numbytes);
- ct->sbc[channel] = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
+ cc->sbc[channel] = sb_new_send(&sbb, dont_free, trafo, cc->scc.send);
}
- ret = sb_get_send_buffers(ct->sbc[channel], iov);
+ ret = sb_get_send_buffers(cc->sbc[channel], iov);
ret = xwritev(fd, iov, ret);
if (ret < 0) {
- sb_free(ct->sbc[channel]);
- ct->sbc[channel] = NULL;
+ sb_free(cc->sbc[channel]);
+ cc->sbc[channel] = NULL;
return ret;
}
- if (sb_sent(ct->sbc[channel], ret)) {
- ct->sbc[channel] = NULL;
+ if (sb_sent(cc->sbc[channel], ret)) {
+ cc->sbc[channel] = NULL;
return 1;
}
return 0;
@@ -130,35 +157,35 @@ static int recv_sb(struct client_task *ct, struct sb_buffer *result)
sb_transformation trafo;
void *trafo_context;
struct iovec iov;
+ struct client_config *cc = client_config_of(ct);
if (ct->status < CL_SENT_CH_RESPONSE)
trafo = trafo_context = NULL;
else {
trafo = sc_trafo;
- trafo_context = ct->scc.recv;
+ trafo_context = cc->scc.recv;
}
- if (!ct->sbc[0])
- ct->sbc[0] = sb_new_recv(0, trafo, trafo_context);
+ if (!cc->sbc[0])
+ cc->sbc[0] = sb_new_recv(0, trafo, trafo_context);
again:
- sb_get_recv_buffer(ct->sbc[0], &iov);
- ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, &n);
+ sb_get_recv_buffer(cc->sbc[0], &iov);
+ ret = read_nonblock(cc->scc.fd, iov.iov_base, iov.iov_len, &n);
if (ret < 0) {
- sb_free(ct->sbc[0]);
- ct->sbc[0] = NULL;
+ sb_free(cc->sbc[0]);
+ cc->sbc[0] = NULL;
return ret;
}
if (n == 0)
return 0;
- ret = sb_received(ct->sbc[0], n, result);
+ ret = sb_received(cc->sbc[0], n, result);
if (ret < 0)
return ret;
if (ret == 0)
goto again;
- ct->sbc[0] = NULL;
+ cc->sbc[0] = NULL;
return 1;
}
-
static char **parse_features(char *buf)
{
int i;
@@ -217,8 +244,9 @@ static int send_sb_command(struct client_task *ct)
char *command, *p;
size_t len = 0;
unsigned num_inputs = lls_num_inputs(ct->lpr);
+ struct client_config *cc = client_config_of(ct);
- if (ct->sbc[1])
+ if (cc->sbc[1])
return send_sb(ct, 0, NULL, 0, 0, false);
for (i = 0; i < num_inputs; i++)
@@ -247,6 +275,7 @@ static int send_sb_command(struct client_task *ct)
static int client_post_monitor(struct sched *s, void *context)
{
struct client_task *ct = context;
+ struct client_config *cc = client_config_of(ct);
int ret = 0;
size_t n;
char buf[CLIENT_BUFSIZE];
@@ -254,14 +283,14 @@ static int client_post_monitor(struct sched *s, void *context)
ret = task_get_notification(ct->task);
if (ret < 0)
goto out;
- if (ct->scc.fd < 0)
+ if (cc->scc.fd < 0)
return 0;
switch (ct->status) {
case CL_CONNECTED: /* receive welcome message */
- ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &n);
+ ret = read_nonblock(cc->scc.fd, buf, sizeof(buf), &n);
if (ret < 0 || n == 0)
goto out;
- ct->features = parse_features(buf);
+ cc->features = parse_features(buf);
ct->status = CL_RECEIVED_WELCOME;
return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
@@ -270,11 +299,11 @@ static int client_post_monitor(struct sched *s, void *context)
* Request and use the sha256 feature unconditionally. After
* 0.8.0 we no longer need to request it.
*/
- if (!sched_write_ok(ct->scc.fd, s))
+ if (!sched_write_ok(cc->scc.fd, s))
return 0;
- sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
+ sprintf(buf, AUTH_REQUEST_MSG "%s", cc->user);
PARA_INFO_LOG("--> %s\n", buf);
- ret = write_buffer(ct->scc.fd, buf);
+ ret = write_buffer(cc->scc.fd, buf);
if (ret < 0)
goto out;
ct->status = CL_SENT_AUTH;
@@ -300,7 +329,7 @@ static int client_post_monitor(struct sched *s, void *context)
}
n = sbb.iov.iov_len;
PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
- ret = apc_priv_decrypt(ct->key_file, &crypt_buf,
+ ret = apc_priv_decrypt(cc->key_file, &crypt_buf,
sbb.iov.iov_base, n);
free(sbb.iov.iov_base);
if (ret < 0)
@@ -310,13 +339,13 @@ static int client_post_monitor(struct sched *s, void *context)
ret = -E_DECRYPT;
goto out;
}
- ct->challenge_hash = alloc(HASH_SIZE);
+ cc->challenge_hash = alloc(HASH_SIZE);
hash_function((char *)crypt_buf, APC_CHALLENGE_SIZE,
- ct->challenge_hash);
- hash_to_asc(ct->challenge_hash, buf);
- ct->scc.send = sc_new(crypt_buf + APC_CHALLENGE_SIZE,
+ cc->challenge_hash);
+ hash_to_asc(cc->challenge_hash, buf);
+ cc->scc.send = sc_new(crypt_buf + APC_CHALLENGE_SIZE,
SESSION_KEY_LEN);
- ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE
+ cc->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE
+ SESSION_KEY_LEN, SESSION_KEY_LEN);
free(crypt_buf);
PARA_INFO_LOG("--> %s\n", buf);
@@ -324,10 +353,10 @@ static int client_post_monitor(struct sched *s, void *context)
return 0;
}
case CL_RECEIVED_CHALLENGE:
- ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+ ret = send_sb(ct, 0, cc->challenge_hash, HASH_SIZE,
SBD_CHALLENGE_RESPONSE, false);
if (ret != 0)
- ct->challenge_hash = NULL;
+ cc->challenge_hash = NULL;
if (ret <= 0)
goto out;
ct->status = CL_SENT_CH_RESPONSE;
@@ -347,7 +376,7 @@ static int client_post_monitor(struct sched *s, void *context)
}
case CL_RECEIVED_PROCEED: /* concat args and send command */
{
- if (!sched_write_ok(ct->scc.fd, s))
+ if (!sched_write_ok(cc->scc.fd, s))
return 0;
ret = send_sb_command(ct);
if (ret <= 0)
@@ -369,7 +398,7 @@ static int client_post_monitor(struct sched *s, void *context)
}
if (ret < 0)
goto close1;
- if (ret > 0 && sched_write_ok(ct->scc.fd, s)) {
+ if (ret > 0 && sched_write_ok(cc->scc.fd, s)) {
sz = btr_next_buffer(ct->btrn[1], &buf2);
assert(sz);
ret = send_sb(ct, 1, buf2, sz, SBD_BLOB_DATA, true);
@@ -385,7 +414,7 @@ static int client_post_monitor(struct sched *s, void *context)
ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
if (ret < 0)
goto close0;
- if (ret > 0 && sched_read_ok(ct->scc.fd, s)) {
+ if (ret > 0 && sched_read_ok(cc->scc.fd, s)) {
struct sb_buffer sbb;
ret = recv_sb(ct, &sbb);
if (ret < 0)
@@ -417,16 +446,15 @@ out:
btr_remove_node(&ct->btrn[0]);
btr_remove_node(&ct->btrn[1]);
PARA_NOTICE_LOG("closing connection (%s)\n", para_strerror(-ret));
- if (ct->scc.fd >= 0) {
- close(ct->scc.fd);
- ct->scc.fd = -1;
+ if (cc->scc.fd >= 0) {
+ close(cc->scc.fd);
+ cc->scc.fd = -1;
}
- free_argv(ct->features);
- ct->features = NULL;
- sc_free(ct->scc.recv);
- ct->scc.recv = NULL;
- sc_free(ct->scc.send);
- ct->scc.send = NULL;
+ free_argv(cc->features);
+ sc_free(cc->scc.recv);
+ cc->scc.recv = NULL;
+ sc_free(cc->scc.send);
+ cc->scc.send = NULL;
return ret;
}
@@ -449,14 +477,15 @@ int client_connect(struct client_task *ct, struct sched *s,
int ret;
const char *host = CLIENT_OPT_STRING_VAL(HOSTNAME, ct->lpr);
uint32_t port = CLIENT_OPT_UINT32_VAL(SERVER_PORT, ct->lpr);
+ struct client_config *cc = client_config_of(ct);
PARA_NOTICE_LOG("connecting %s:%u\n", host, port);
- ct->scc.fd = -1;
+ cc->scc.fd = -1;
ret = para_connect(IPPROTO_TCP, host, port);
if (ret < 0)
return ret;
- ct->scc.fd = ret;
- ret = mark_fd_nonblocking(ct->scc.fd);
+ cc->scc.fd = ret;
+ ret = mark_fd_nonblocking(cc->scc.fd);
if (ret < 0)
goto err_out;
ct->status = CL_CONNECTED;
@@ -473,8 +502,8 @@ int client_connect(struct client_task *ct, struct sched *s,
}, s);
return 1;
err_out:
- close(ct->scc.fd);
- ct->scc.fd = -1;
+ close(cc->scc.fd);
+ cc->scc.fd = -1;
return ret;
}
@@ -515,7 +544,7 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr)
const struct lls_command *cmd = CLIENT_CMD_PTR;
struct lls_parse_result *lpr;
int ret;
- struct client_task *ct;
+ struct client_config *cc;
char *kf = NULL, *user, *errctx, *home = para_homedir();
ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
@@ -544,12 +573,12 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr)
}
PARA_INFO_LOG("user: %s\n", user);
PARA_INFO_LOG("key file: %s\n", kf);
- ct = zalloc(sizeof(*ct));
- ct->scc.fd = -1;
- ct->lpr = lpr;
- ct->key_file = kf;
- ct->user = user;
- *ct_ptr = ct;
+ cc = zalloc(sizeof(*cc));
+ cc->scc.fd = -1;
+ cc->client_task.lpr = lpr;
+ cc->key_file = kf;
+ cc->user = user;
+ *ct_ptr = &cc->client_task;
ret = lls_num_inputs(lpr);
out:
free(home);
@@ -601,3 +630,81 @@ fail:
*ct_ptr = NULL;
return ret;
}
+
+struct client_run_instance {
+ struct sched *s;
+ struct btr_node *stdout_btrn;
+ struct client_task *ct;
+ char *result_buf;
+ size_t result_size;
+};
+
+static void run_pre_monitor(struct sched *s, void *context)
+{
+ struct client_run_instance *cri = context;
+
+ if (btr_node_status(cri->stdout_btrn, 0, BTR_NT_LEAF) != 0)
+ sched_min_delay(s);
+}
+
+static int run_post_monitor(__a_unused struct sched *s, void *context)
+{
+ struct client_run_instance *cri = context;
+ char *buf;
+ size_t sz;
+ int ret;
+
+ ret = btr_node_status(cri->stdout_btrn, 0, BTR_NT_LEAF);
+ if (ret < 0)
+ btr_remove_node(&cri->stdout_btrn);
+ if (ret <= 0)
+ return ret;
+ sz = btr_next_buffer(cri->stdout_btrn, &buf);
+ if (sz == 0)
+ return 0;
+ cri->result_buf = para_realloc(cri->result_buf, cri->result_size + sz);
+ memcpy(cri->result_buf + cri->result_size, buf, sz);
+ cri->result_size += sz;
+ btr_consume(cri->stdout_btrn, sz);
+ return 1;
+}
+
+int client_run(int argc, char *argv[], char **result)
+{
+ int ret;
+ struct client_run_instance _cri = {.result_buf = NULL}, *cri = &_cri;
+ char **new_argv;;
+
+ cri->s = sched_new(NULL);
+ new_argv = arr_alloc(argc + 1, sizeof(char *));
+ new_argv[0] = "para_client";
+ for (int i = 0; i < argc; i++)
+ new_argv[i + 1] = argv[i];
+ ret = client_open(argc + 1, new_argv, &cri->ct, NULL, NULL, cri->s);
+ if (ret < 0)
+ goto shutdown_shed;
+ cri->stdout_btrn = btr_new_node(&(struct btr_node_description)
+ EMBRACE(.name = "client stdout", .parent = cri->ct->btrn[0]));
+ task_register(&(struct task_info) {
+ .name = "client run",
+ .pre_monitor = run_pre_monitor,
+ .post_monitor = run_post_monitor,
+ .context = cri,
+ }, cri->s);
+ ret = schedule(cri->s);
+ client_close(cri->ct);
+shutdown_shed:
+ sched_shutdown(cri->s);
+ free(new_argv);
+ if (!result || ret < 0)
+ free(cri->result_buf);
+ if (ret < 0 && result)
+ *result = NULL;
+ if (ret >= 0 && result) {
+ cri->result_buf = para_realloc(cri->result_buf,
+ cri->result_size + 1);
+ cri->result_buf[cri->result_size] = '\0';
+ *result = cri->result_buf;
+ }
+ return ret;
+}
diff --git a/crypt.h b/crypt.h
index 2855f41f..156dcda7 100644
--- a/crypt.h
+++ b/crypt.h
@@ -93,22 +93,6 @@ void apc_free_pubkey(struct asymmetric_key *key);
*/
void get_random_bytes_or_die(unsigned char *buf, int num);
-/**
- * Initialize the crypto backend.
- *
- * This function initializes the crypto library and seeds the pseudo random
- * number generator used by random() with a random seed obtained from the
- * crypto implementation. On errors, an error message is logged and the
- * function calls exit().
- *
- * \sa \ref get_random_bytes_or_die(), srandom(3), random(3), \ref
- * para_random().
- */
-void crypt_init(void);
-
-/** Allocate all resources of the crypto backend. */
-void crypt_shutdown(void);
-
/** Opaque structure for stream ciphers. */
struct stream_cipher;
diff --git a/fd.c b/fd.c
index fe68b8bd..83abff94 100644
--- a/fd.c
+++ b/fd.c
@@ -5,6 +5,7 @@
#include <sys/types.h>
#include <dirent.h>
#include <sys/mman.h>
+#include <sys/socket.h>
#include "para.h"
#include "error.h"
@@ -12,6 +13,55 @@
#include "fd.h"
/**
+ * Receive data from a file descriptor.
+ *
+ * \param fd The file descriptor.
+ * \param buf The buffer to write the data to.
+ * \param size The size of the buffer.
+ *
+ * \return The number of bytes received on success, negative on errors,
+ * zero if the peer has performed an orderly shutdown.
+ *
+ * \sa recv(2)
+ */
+__must_check int recv_bin_buffer(int fd, char *buf, size_t size)
+{
+ ssize_t n;
+
+ n = recv(fd, buf, size, 0);
+ if (n == -1)
+ return -ERRNO_TO_PARA_ERROR(errno);
+ return n;
+}
+
+/**
+ * Receive and write a terminating NUL byte.
+ *
+ * \param fd The file descriptor.
+ * \param buf The buffer to write the data to.
+ * \param size The size of the buffer, must be positive.
+ *
+ * Read at most size - 1 bytes and write a NUL byte at the end of the
+ * received data.
+ *
+ * \return The return value of the underlying call to \ref recv_bin_buffer().
+ *
+ * \sa \ref recv_bin_buffer()
+ */
+int recv_buffer(int fd, char *buf, size_t size)
+{
+ int n;
+
+ assert(size);
+ n = recv_bin_buffer(fd, buf, size - 1);
+ if (n >= 0)
+ buf[n] = '\0';
+ else
+ *buf = '\0';
+ return n;
+}
+
+/**
* Write an array of buffers, handling non-fatal errors.
*
* \param fd The file descriptor to write to.
diff --git a/fd.h b/fd.h
index dc14b6c0..c30198a4 100644
--- a/fd.h
+++ b/fd.h
@@ -2,6 +2,8 @@
/** \file fd.h exported symbols from fd.c */
+int recv_bin_buffer(int fd, char *buf, size_t size);
+int recv_buffer(int fd, char *buf, size_t size);
int write_all(int fd, const void *buf, size_t len);
__printf_2_3 int write_va_buffer(int fd, const char *fmt, ...);
int xpoll(struct pollfd *fds, nfds_t nfds, int timeout);
diff --git a/gcrypt.c b/gcrypt.c
index 9baa6904..c1b6a633 100644
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -54,13 +54,14 @@ void get_random_bytes_or_die(unsigned char *buf, int num)
* call to gcry_check_version() initializes the gcrypt library and checks that
* we have at least the minimal required version.
*/
-void crypt_init(void)
+__attribute__ ((constructor))
+static void gcrypt_init(void)
{
const char *req_ver = "1.5.0";
int seed;
if (!gcry_check_version(req_ver)) {
- PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
+ fprintf(stderr, "fatal: need at least libgcrypt-%s, have: %s\n",
req_ver, gcry_check_version(NULL));
exit(EXIT_FAILURE);
}
@@ -78,8 +79,10 @@ void crypt_init(void)
srandom(seed);
}
-void crypt_shutdown(void)
+__attribute__ ((destructor))
+static void gcrypt_shutdown(void)
{
+ PARA_DEBUG_LOG("(noop)\n");
/*
* WK does not see a way to apply a patch for the sake of Valgrind, so
* as of 2018 libgrypt has no deinitialization routine to free the
diff --git a/gui.c b/gui.c
index 4c81b43e..60279545 100644
--- a/gui.c
+++ b/gui.c
@@ -28,9 +28,6 @@
#include <sys/time.h>
#include <lopsub.h>
#include <langinfo.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#include "gui.lsg.h"
#include "para.h"
@@ -45,7 +42,6 @@
#include "signal.h"
#include "audioc.h"
#include "sideband.h"
-#include "net.h"
DEFINE_PARA_ERRLIST;
diff --git a/m4/lls/mixer.suite.m4 b/m4/lls/mixer.suite.m4
index b51fab4c..1e01d873 100644
--- a/m4/lls/mixer.suite.m4
+++ b/m4/lls/mixer.suite.m4
@@ -18,6 +18,7 @@ caption = List of subcommands
m4_include(version.m4)
m4_include(config-file.m4)
m4_include(loglevel.m4)
+ m4_include(socket.m4)
m4_include(per-command-options-section.m4)
[help]
These options apply to several subcommands.
diff --git a/mixer.c b/mixer.c
index 7c11c640..81674130 100644
--- a/mixer.c
+++ b/mixer.c
@@ -24,11 +24,14 @@
#include "mixer.lsg.h"
#include "para.h"
+#include "audioc.h"
#include "lsu.h"
#include "fd.h"
#include "string.h"
#include "mix.h"
#include "error.h"
+#include "sideband.h"
+#include "client.h"
DEFINE_PARA_ERRLIST;
@@ -59,6 +62,12 @@ typedef int (*mixer_subcommand_handler_t)(const struct mixer *);
#define EXPORT_CMD(_cmd) const mixer_subcommand_handler_t \
lsg_mixer_com_ ## _cmd ## _user_data = &com_ ## _cmd;
+
+#define die(f,...) { \
+ para_log(LL_EMERG, "%s: " f, __func__, ## __VA_ARGS__); \
+ exit(EXIT_FAILURE); \
+ }
+
static int loglevel;
static __printf_2_3 void date_log(int ll, const char *fmt, ...)
{
@@ -202,80 +211,83 @@ static int com_fade(const struct mixer *m)
}
EXPORT_CMD(fade);
-static void run(const char *exe, const char *cmd)
+static void run_client_cmd_argv(int argc, char **argv)
{
- int ret, status, fds[3] = {0, 0, 0};
- pid_t pid;
- char *cmdline = make_message("%s %s", exe, cmd);
+ char *result = NULL;
+ int ret = client_run(argc, argv, &result);
- PARA_INFO_LOG("%s\n", cmdline);
- ret = xexec(&pid, cmdline, fds);
- free(cmdline);
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- goto fail;
- }
- do
- ret = waitpid(pid, &status, 0);
- while (ret == -1 && errno == EINTR);
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", strerror(errno));
- goto fail;
- }
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- goto fail;
- return;
-fail:
- PARA_EMERG_LOG("command \"%s\" failed\n", cmd);
- exit(EXIT_FAILURE);
+ PARA_INFO_LOG("cmd: %s\n", argv[0]);
+ if (ret < 0)
+ die("client_run(%s): %s\n", argv[0], para_strerror(-ret));
+ if (result && *result)
+ PARA_INFO_LOG("result: %s\n", result);
+ free(result);
}
-static char *get_status_item(const char *status_item_name)
+static void run_client_cmd(char *cmd)
{
- pid_t pid;
- int ret, fds[3] = {0, 1, 0};
- char *buf, *p, *item = NULL, *cmdline;
-
- cmdline = make_message("para_audioc -- stat --one-shot %s",
- status_item_name);
- ret = xexec(&pid, cmdline, fds);
- free(cmdline);
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- return para_strdup(NULL);
- }
- buf = alloc(100);
- ret = read(fds[1], buf, 99);
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", strerror(errno));
- goto free_buf;
+ char *argv[] = {cmd};
+ run_client_cmd_argv(1, argv);
+}
+
+static char *get_status_item(char *status_item_name)
+{
+ char *argv[] = {"stat", "--one-shot", status_item_name};
+ int argc = ARRAY_SIZE(argv), ret, fd;
+ char *p;
+ struct iovec iov;
+ struct sb_buffer sbb;
+ struct sb_context *ctx;
+
+ ret = connect_audiod(OPT_STRING_VAL(PARA_MIXER, SOCKET), argc, argv);
+ if (ret < 0)
+ die("connect_audiod stat %s: %s\n", status_item_name,
+ para_strerror(-ret));
+ fd = ret;
+ ctx = sb_new_recv(100, NULL, NULL);
+ for (;;) {
+ sb_get_recv_buffer(ctx, &iov);
+ ret = recv_bin_buffer(fd, iov.iov_base, iov.iov_len);
+ if (ret < 0)
+ die("recv_bin_buffer: %s\n", para_strerror(-ret));
+ if (ret == 0)
+ die("unexpected eof\n");
+ ret = sb_received(ctx, ret, &sbb);
+ if (ret < 0)
+ die("sb_received: %s\n", para_strerror(-ret));
+ if (ret > 0)
+ break;
}
- buf[ret] = '\0';
- p = strrchr(buf, '\n');
+
+ p = strrchr(sbb.iov.iov_base, '\n');
if (!p)
- goto free_buf;
+ goto parse_error;
*p = '\0';
- p = strchr(buf, ':');
+ p = strchr(sbb.iov.iov_base, ':');
if (!p || p[1] == '\0')
- goto free_buf;
- item = para_strdup(p + 2);
-free_buf:
- free(buf);
- close(fds[1]);
- do
- ret = waitpid(pid, NULL, 0);
- while (ret == -1 && errno == EINTR);
- return item? item : para_strdup(NULL);
+ goto parse_error;
+ p = para_strdup(p + 2);
+ free(sbb.iov.iov_base);
+ return p;
+parse_error:
+ die("parse error for item %s, buf=%s\n", status_item_name,
+ (char *)sbb.iov.iov_base);
}
-static void client_cmd(const char *cmd)
+static void run_audioc_cmd(const char *cmd)
{
- run("para_client", cmd);
-}
+ char **argv;
+ int argc, ret;
-static void audioc_cmd(const char *cmd)
-{
- run("para_audioc", cmd);
+ ret = create_argv(cmd, " ", &argv);
+ if (ret < 0)
+ die("create_argv %s: %s\n", cmd, para_strerror(-ret));
+ argc = ret;
+ ret = connect_audiod(OPT_STRING_VAL(PARA_MIXER, SOCKET), argc, argv);
+ free_argv(argv);
+ if (ret < 0)
+ die("connect_audiod %s: %s\n", cmd, para_strerror(-ret));
+ close(ret);
}
static int set_initial_volume(const struct mixer *m, struct mixer_handle *h)
@@ -321,7 +333,7 @@ static int change_mop(const char *mop, const struct mixer *m,
struct mixer_handle *h)
{
int ret;
- char *current_mop, *status, *cmd;
+ char *current_mop, *status;
static bool initial_volume_set, playing;
if (!mop || !*mop)
@@ -331,6 +343,7 @@ static int change_mop(const char *mop, const struct mixer *m,
PARA_INFO_LOG("afs_mode: %s, status: %s\n", current_mop, status);
playing = !strcmp(status, "playing");
if (strcmp(current_mop, mop)) {
+ char *argv[2] = {"select"};
if (playing) {
uint32_t old_vol;
ret = m->get(h);
@@ -340,19 +353,19 @@ static int change_mop(const char *mop, const struct mixer *m,
ret = fade(m, h, 0, 3, false);
if (ret < 0)
goto free_status;
- audioc_cmd("off");
- client_cmd("stop");
+ run_audioc_cmd("off");
+ run_client_cmd("stop");
playing = false;
- audioc_cmd("on");
+ run_audioc_cmd("on");
ret = m->set(h, old_vol);
if (ret < 0)
goto free_status;
} else if (!strcmp(status, "paused"))
- client_cmd("next");
+ run_client_cmd("next");
PARA_NOTICE_LOG("switching to %s\n", mop);
- cmd = make_message("select %s", mop);
- client_cmd(cmd);
- free(cmd);
+ argv[1] = para_strdup(mop);
+ run_client_cmd_argv(2, argv);
+ free(argv[1]);
}
if (!initial_volume_set) {
initial_volume_set = true;
@@ -361,7 +374,7 @@ static int change_mop(const char *mop, const struct mixer *m,
goto free_status;
}
if (!playing)
- client_cmd("play");
+ run_client_cmd("play");
ret = 1;
free_status:
free(status);
@@ -425,7 +438,7 @@ static int com_sleep(const struct mixer *m)
ret = change_mop(initial_mood, m, h);
if (ret < 0)
goto close_mixer;
- audioc_cmd("on");
+ run_audioc_cmd("on");
if (ret > 0) /* playing initial mood */
sleep(OPT_UINT32_VAL(SLEEP, INITIAL_DELAY));
ret = change_mop(fo_mood, m, h);
@@ -438,7 +451,7 @@ static int com_sleep(const struct mixer *m)
if (ret < 0)
goto close_mixer;
if (ret == 0) /* no sleep mood */
- client_cmd("stop");
+ run_client_cmd("stop");
time(&t1);
if (wake_time_epoch > t1 + fit)
sleep(wake_time_epoch - t1 - fit);
@@ -467,10 +480,10 @@ static int com_snooze(const struct mixer *m)
ret = fade(m, h, sovol, sotime, true);
if (ret < 0)
goto close_mixer;
- client_cmd("pause");
+ run_client_cmd("pause");
PARA_NOTICE_LOG("%" PRIu32 " seconds snooze time...\n", stime);
sleep(stime);
- client_cmd("play");
+ run_client_cmd("play");
ret = fade(m, h, sivol, sitime, true);
close_mixer:
m->close(h);
@@ -654,6 +667,5 @@ fail:
if (errctx)
PARA_ERROR_LOG("%s\n", errctx);
free(errctx);
- PARA_EMERG_LOG("%s\n", para_strerror(-ret));
- return EXIT_FAILURE;
+ die("%s\n", para_strerror(-ret));
}
diff --git a/net.c b/net.c
index aad39f04..32c60ca9 100644
--- a/net.c
+++ b/net.c
@@ -553,58 +553,6 @@ bool sockaddr_equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
} else
return false;
}
-
-/**
- * Receive data from a file descriptor.
- *
- * \param fd The file descriptor.
- * \param buf The buffer to write the data to.
- * \param size The size of \a buf.
- *
- * Receive at most \a size bytes from file descriptor \a fd.
- *
- * \return The number of bytes received on success, negative on errors, zero if
- * the peer has performed an orderly shutdown.
- *
- * \sa recv(2).
- */
-__must_check int recv_bin_buffer(int fd, char *buf, size_t size)
-{
- ssize_t n;
-
- n = recv(fd, buf, size, 0);
- if (n == -1)
- return -ERRNO_TO_PARA_ERROR(errno);
- return n;
-}
-
-/**
- * Receive and write terminating NULL byte.
- *
- * \param fd The file descriptor.
- * \param buf The buffer to write the data to.
- * \param size The size of \a buf.
- *
- * Read at most \a size - 1 bytes from file descriptor \a fd and
- * write a NULL byte at the end of the received data.
- *
- * \return The return value of the underlying call to \a recv_bin_buffer().
- *
- * \sa \ref recv_bin_buffer()
- */
-int recv_buffer(int fd, char *buf, size_t size)
-{
- int n;
-
- assert(size);
- n = recv_bin_buffer(fd, buf, size - 1);
- if (n >= 0)
- buf[n] = '\0';
- else
- *buf = '\0';
- return n;
-}
-
/**
* Wrapper around the accept system call.
*
diff --git a/net.h b/net.h
index fde0424d..c2d35fed 100644
--- a/net.h
+++ b/net.h
@@ -44,9 +44,6 @@ int para_listen_simple(unsigned l4type, uint16_t port);
/** Pretty-printing of IPv4/6 socket addresses */
char *remote_name(int sockfd);
-int recv_bin_buffer(int fd, char *buf, size_t size);
-int recv_buffer(int fd, char *buf, size_t size);
-
int para_accept(int fd, void *addr, socklen_t size, int *new_fd);
int create_local_socket(const char *name);
int connect_local_socket(const char *name);
diff --git a/openssl.c b/openssl.c
index b83ee087..30e2b793 100644
--- a/openssl.c
+++ b/openssl.c
@@ -47,20 +47,29 @@ void get_random_bytes_or_die(unsigned char *buf, int num)
* Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Then seed the
* PRNG used by random(3) with a random seed obtained from SSL.
*/
-void crypt_init(void)
+__attribute__ ((constructor))
+static void openssl_init(void)
{
- int seed, ret = RAND_load_file("/dev/urandom", 64);
+ unsigned char seed[sizeof(int)];
+ int ret;
+ ret = RAND_load_file("/dev/urandom", 64);
if (ret != 64) {
- PARA_EMERG_LOG("could not seed PRNG (ret = %d)\n", ret);
+ fprintf(stderr, "could not load urandom (ret = %d)\n", ret);
+ exit(EXIT_FAILURE);
+ }
+ if (RAND_bytes(seed, sizeof(seed)) != 1) { /* failure */
+ ret = openssl_perror("RAND_bytes");
+ fprintf(stderr, "%s\n", strerror(-ret));
exit(EXIT_FAILURE);
}
- get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed));
- srandom(seed);
+ srandom(*(int *)seed);
}
-void crypt_shutdown(void)
+__attribute__ ((destructor))
+static void openssl_shutdown(void)
{
+ PARA_DEBUG_LOG("stopping threads and freeing EVP context\n");
OPENSSL_thread_stop();
EVP_cleanup();
}
diff --git a/server.c b/server.c
index afa6e137..a766968a 100644
--- a/server.c
+++ b/server.c
@@ -786,7 +786,6 @@ static int init_afs(int argc, char **argv)
int i;
afs_pid = getpid();
- crypt_shutdown();
user_list_deplete();
for (i = argc - 1; i >= 0; i--)
memset(argv[i], 0, strlen(argv[i]));
@@ -869,7 +868,6 @@ static struct sched *server_init(int argc, char **argv,
if (OPT_GIVEN(DAEMON))
daemon_pipe = daemonize(true /* parent waits for SIGTERM */);
server_pid = getpid();
- crypt_init();
daemon_log_welcome("server");
init_ipc_or_die(); /* init mmd struct, mmd and log mutex */
daemon_set_start_time();
@@ -960,7 +958,6 @@ int main(int argc, char *argv[])
*/
mutex_unlock(mmd_mutex);
sched_shutdown(sched);
- crypt_shutdown();
if (!process_is_command_handler()) { /* parent (server) */
mutex_destroy(mmd_mutex);
daemon_set_hooks(NULL, NULL); /* only one process remaining */