mirror of https://github.com/ericonr/sndio.git
add TCP transport
This commit is contained in:
parent
6c7f04bf10
commit
3f1215502b
|
@ -33,6 +33,7 @@
|
||||||
.Op Fl h Ar fmt
|
.Op Fl h Ar fmt
|
||||||
.Op Fl i Ar file
|
.Op Fl i Ar file
|
||||||
.Op Fl j Ar flag
|
.Op Fl j Ar flag
|
||||||
|
.Op Fl L Ar addr
|
||||||
.Op Fl m Ar mode
|
.Op Fl m Ar mode
|
||||||
.Op Fl o Ar file
|
.Op Fl o Ar file
|
||||||
.Op Fl q Ar device
|
.Op Fl q Ar device
|
||||||
|
@ -140,6 +141,13 @@ For instance, this feature could be used to request mono streams to
|
||||||
be sent on multiple outputs or to record a stereo input into a mono stream.
|
be sent on multiple outputs or to record a stereo input into a mono stream.
|
||||||
The default is
|
The default is
|
||||||
.Ar on .
|
.Ar on .
|
||||||
|
.It Fl L Ar addr
|
||||||
|
Listen on the given address for incoming TCP connections.
|
||||||
|
Without this option,
|
||||||
|
.Nm
|
||||||
|
listens only on the Unix-domain socket, thus it's not reachable
|
||||||
|
from the network.
|
||||||
|
The port number is 6523 plus the unit number.
|
||||||
.It Fl l
|
.It Fl l
|
||||||
Detach and become a daemon.
|
Detach and become a daemon.
|
||||||
.It Fl m Ar mode
|
.It Fl m Ar mode
|
||||||
|
|
|
@ -260,6 +260,16 @@ struct cfdev {
|
||||||
|
|
||||||
SLIST_HEAD(cfdevlist, cfdev);
|
SLIST_HEAD(cfdevlist, cfdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TCP addresses to listen on
|
||||||
|
*/
|
||||||
|
struct cfnet {
|
||||||
|
SLIST_ENTRY(cfnet) entry;
|
||||||
|
char *addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
SLIST_HEAD(cfnetlist, cfnet);
|
||||||
|
|
||||||
void
|
void
|
||||||
cfdev_add(struct cfdevlist *list, struct cfdev *templ, char *path)
|
cfdev_add(struct cfdevlist *list, struct cfdev *templ, char *path)
|
||||||
{
|
{
|
||||||
|
@ -319,6 +329,20 @@ cfmid_add(struct cfmidlist *list, char *path)
|
||||||
SLIST_INSERT_HEAD(list, cm, entry);
|
SLIST_INSERT_HEAD(list, cm, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfnet_add(struct cfnetlist *list, char *addr)
|
||||||
|
{
|
||||||
|
struct cfnet *cn;
|
||||||
|
|
||||||
|
cn = malloc(sizeof(struct cfnet));
|
||||||
|
if (cn == NULL) {
|
||||||
|
perror("malloc");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
cn->addr = addr;
|
||||||
|
SLIST_INSERT_HEAD(list, cn, entry);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
setsig(void)
|
setsig(void)
|
||||||
{
|
{
|
||||||
|
@ -416,11 +440,11 @@ aucat_usage(void)
|
||||||
{
|
{
|
||||||
(void)fputs("usage: " PROG_AUCAT " [-dlnu] [-a flag] [-b nframes] "
|
(void)fputs("usage: " PROG_AUCAT " [-dlnu] [-a flag] [-b nframes] "
|
||||||
"[-C min:max] [-c min:max] [-e enc]\n\t"
|
"[-C min:max] [-c min:max] [-e enc]\n\t"
|
||||||
"[-f device] [-h fmt] [-i file] [-j flag] [-m mode]"
|
"[-f device] [-h fmt] [-i file] [-j flag] [-L addr] [-m mode] "
|
||||||
"[-o file] [-q device]\n\t"
|
"[-o file]\n\t"
|
||||||
"[-r rate] [-s name] [-t mode] [-U unit] "
|
"[-q device] [-r rate] [-s name] [-t mode] [-U unit] "
|
||||||
"[-v volume] [-x policy]\n\t"
|
"[-v volume]\n\t"
|
||||||
"[-z nframes]\n",
|
"[-x policy] [-z nframes]\n",
|
||||||
stderr);
|
stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,10 +452,11 @@ int
|
||||||
aucat_main(int argc, char **argv)
|
aucat_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct cfdevlist cfdevs;
|
struct cfdevlist cfdevs;
|
||||||
|
struct cfnetlist cfnets;
|
||||||
struct cfmid *cm;
|
struct cfmid *cm;
|
||||||
struct cfstr *cs;
|
struct cfstr *cs;
|
||||||
struct cfdev *cd;
|
struct cfdev *cd;
|
||||||
struct listen *listen = NULL;
|
struct cfnet *cn;
|
||||||
int c, u_flag, d_flag, l_flag, n_flag, unit;
|
int c, u_flag, d_flag, l_flag, n_flag, unit;
|
||||||
char base[PATH_MAX], path[PATH_MAX];
|
char base[PATH_MAX], path[PATH_MAX];
|
||||||
unsigned mode, rate;
|
unsigned mode, rate;
|
||||||
|
@ -450,6 +475,7 @@ aucat_main(int argc, char **argv)
|
||||||
l_flag = 0;
|
l_flag = 0;
|
||||||
n_flag = 0;
|
n_flag = 0;
|
||||||
SLIST_INIT(&cfdevs);
|
SLIST_INIT(&cfdevs);
|
||||||
|
SLIST_INIT(&cfnets);
|
||||||
nfile = nsock = 0;
|
nfile = nsock = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -488,7 +514,7 @@ aucat_main(int argc, char **argv)
|
||||||
cd->round = 0;
|
cd->round = 0;
|
||||||
cd->hold = 1;
|
cd->hold = 1;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "a:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:t:j:z:")) != -1) {
|
while ((c = getopt(argc, argv, "a:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:L:t:j:z:")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -508,6 +534,9 @@ aucat_main(int argc, char **argv)
|
||||||
if (str)
|
if (str)
|
||||||
errx(1, "%s: unit number is %s", optarg, str);
|
errx(1, "%s: unit number is %s", optarg, str);
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
cfnet_add(&cfnets, optarg);
|
||||||
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
cs->mode = opt_mode();
|
cs->mode = opt_mode();
|
||||||
cd->mode = cs->mode;
|
cd->mode = cs->mode;
|
||||||
|
@ -768,9 +797,12 @@ aucat_main(int argc, char **argv)
|
||||||
if (nsock > 0) {
|
if (nsock > 0) {
|
||||||
snprintf(path, sizeof(path), "%s/%s%u", base,
|
snprintf(path, sizeof(path), "%s/%s%u", base,
|
||||||
AUCAT_PATH, unit);
|
AUCAT_PATH, unit);
|
||||||
listen = listen_new(&listen_ops, path);
|
listen_new_un(path);
|
||||||
if (listen == NULL)
|
while (!SLIST_EMPTY(&cfnets)) {
|
||||||
exit(1);
|
cn = SLIST_FIRST(&cfnets);
|
||||||
|
SLIST_REMOVE_HEAD(&cfnets, entry);
|
||||||
|
listen_new_tcp(cn->addr, AUCAT_PORT + unit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (geteuid() == 0)
|
if (geteuid() == 0)
|
||||||
privdrop();
|
privdrop();
|
||||||
|
@ -805,8 +837,8 @@ aucat_main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fatal:
|
fatal:
|
||||||
if (nsock > 0)
|
listen_closeall();
|
||||||
file_close(&listen->file);
|
|
||||||
/*
|
/*
|
||||||
* give a chance to drain
|
* give a chance to drain
|
||||||
*/
|
*/
|
||||||
|
@ -830,7 +862,7 @@ void
|
||||||
midicat_usage(void)
|
midicat_usage(void)
|
||||||
{
|
{
|
||||||
(void)fputs("usage: " PROG_MIDICAT " [-dl] "
|
(void)fputs("usage: " PROG_MIDICAT " [-dl] "
|
||||||
"[-i file] [-o file] [-q port] [-s name] [-U unit]\n",
|
"[-i file] [-L addr] [-o file] [-q port] [-s name] [-U unit]\n",
|
||||||
stderr);
|
stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,10 +870,11 @@ int
|
||||||
midicat_main(int argc, char **argv)
|
midicat_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct cfdevlist cfdevs;
|
struct cfdevlist cfdevs;
|
||||||
|
struct cfnetlist cfnets;
|
||||||
struct cfmid *cm;
|
struct cfmid *cm;
|
||||||
struct cfstr *cs;
|
struct cfstr *cs;
|
||||||
struct cfdev *cd;
|
struct cfdev *cd;
|
||||||
struct listen *listen = NULL;
|
struct cfnet *cn;
|
||||||
int c, d_flag, l_flag, unit, fd;
|
int c, d_flag, l_flag, unit, fd;
|
||||||
char base[PATH_MAX], path[PATH_MAX];
|
char base[PATH_MAX], path[PATH_MAX];
|
||||||
struct file *stdx;
|
struct file *stdx;
|
||||||
|
@ -858,6 +891,7 @@ midicat_main(int argc, char **argv)
|
||||||
d_flag = 0;
|
d_flag = 0;
|
||||||
l_flag = 0;
|
l_flag = 0;
|
||||||
SLIST_INIT(&cfdevs);
|
SLIST_INIT(&cfdevs);
|
||||||
|
SLIST_INIT(&cfnets);
|
||||||
nsock = 0;
|
nsock = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -916,6 +950,9 @@ midicat_main(int argc, char **argv)
|
||||||
if (str)
|
if (str)
|
||||||
errx(1, "%s: unit number is %s", optarg, str);
|
errx(1, "%s: unit number is %s", optarg, str);
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
cfnet_add(&cfnets, optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
midicat_usage();
|
midicat_usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -1038,9 +1075,12 @@ midicat_main(int argc, char **argv)
|
||||||
if (nsock > 0) {
|
if (nsock > 0) {
|
||||||
snprintf(path, sizeof(path), "%s/%s%u", base,
|
snprintf(path, sizeof(path), "%s/%s%u", base,
|
||||||
MIDICAT_PATH, unit);
|
MIDICAT_PATH, unit);
|
||||||
listen = listen_new(&listen_ops, path);
|
listen_new_un(path);
|
||||||
if (listen == NULL)
|
while (!SLIST_EMPTY(&cfnets)) {
|
||||||
exit(1);
|
cn = SLIST_FIRST(&cfnets);
|
||||||
|
SLIST_REMOVE_HEAD(&cfnets, entry);
|
||||||
|
listen_new_tcp(cn->addr, MIDICAT_PORT + unit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (geteuid() == 0)
|
if (geteuid() == 0)
|
||||||
privdrop();
|
privdrop();
|
||||||
|
@ -1068,8 +1108,8 @@ midicat_main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fatal:
|
fatal:
|
||||||
if (nsock > 0)
|
listen_closeall();
|
||||||
file_close(&listen->file);
|
|
||||||
/*
|
/*
|
||||||
* give a chance to drain
|
* give a chance to drain
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,8 @@ extern int debug_level;
|
||||||
*/
|
*/
|
||||||
#define MIDICAT_PATH "midicat"
|
#define MIDICAT_PATH "midicat"
|
||||||
#define AUCAT_PATH "aucat"
|
#define AUCAT_PATH "aucat"
|
||||||
|
#define MIDICAT_PORT 6533
|
||||||
|
#define AUCAT_PORT 6523
|
||||||
#define DEFAULT_OPT "default"
|
#define DEFAULT_OPT "default"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -29,6 +32,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "file.h"
|
||||||
#include "listen.h"
|
#include "listen.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
#ifdef COMPAT_STRLCPY
|
#ifdef COMPAT_STRLCPY
|
||||||
|
@ -48,8 +52,8 @@ struct fileops listen_ops = {
|
||||||
listen_revents
|
listen_revents
|
||||||
};
|
};
|
||||||
|
|
||||||
struct listen *
|
void
|
||||||
listen_new(struct fileops *ops, char *path)
|
listen_new_un(char *path)
|
||||||
{
|
{
|
||||||
int sock, oldumask;
|
int sock, oldumask;
|
||||||
struct sockaddr_un sockname;
|
struct sockaddr_un sockname;
|
||||||
|
@ -58,7 +62,7 @@ listen_new(struct fileops *ops, char *path)
|
||||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
return NULL;
|
exit(1);
|
||||||
}
|
}
|
||||||
if (unlink(path) < 0 && errno != ENOENT) {
|
if (unlink(path) < 0 && errno != ENOENT) {
|
||||||
perror("unlink");
|
perror("unlink");
|
||||||
|
@ -77,7 +81,7 @@ listen_new(struct fileops *ops, char *path)
|
||||||
perror("listen");
|
perror("listen");
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
}
|
}
|
||||||
f = (struct listen *)file_new(ops, path, 1);
|
f = (struct listen *)file_new(&listen_ops, path, 1);
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
f->path = strdup(path);
|
f->path = strdup(path);
|
||||||
|
@ -86,10 +90,70 @@ listen_new(struct fileops *ops, char *path)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
f->fd = sock;
|
f->fd = sock;
|
||||||
return f;
|
return;
|
||||||
bad_close:
|
bad_close:
|
||||||
close(sock);
|
close(sock);
|
||||||
return NULL;
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
listen_new_tcp(char *addr, unsigned port)
|
||||||
|
{
|
||||||
|
char serv[sizeof(unsigned) * 3 + 1];
|
||||||
|
struct addrinfo *ailist, *ai, aihints;
|
||||||
|
struct listen *f;
|
||||||
|
int s, error, opt = 1, n = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* obtain a list of possible addresses for the host/port
|
||||||
|
*/
|
||||||
|
memset(&aihints, 0, sizeof(struct addrinfo));
|
||||||
|
snprintf(serv, sizeof(serv), "%u", port);
|
||||||
|
aihints.ai_flags |= AI_PASSIVE;
|
||||||
|
aihints.ai_socktype = SOCK_STREAM;
|
||||||
|
aihints.ai_protocol = IPPROTO_TCP;
|
||||||
|
error = getaddrinfo(addr, serv, &aihints, &ailist);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for each address, try create a listening socket bound on
|
||||||
|
* that address
|
||||||
|
*/
|
||||||
|
for (ai = ailist; ai != NULL; ai = ai->ai_next) {
|
||||||
|
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
|
if (s < 0) {
|
||||||
|
perror("socket");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
opt = 1;
|
||||||
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) < 0) {
|
||||||
|
perror("setsockopt");
|
||||||
|
goto bad_close;
|
||||||
|
}
|
||||||
|
if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||||
|
perror("bind");
|
||||||
|
goto bad_close;
|
||||||
|
}
|
||||||
|
if (listen(s, 1) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
goto bad_close;
|
||||||
|
}
|
||||||
|
f = (struct listen *)file_new(&listen_ops, addr, 1);
|
||||||
|
if (f == NULL) {
|
||||||
|
bad_close:
|
||||||
|
close(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
f->path = NULL;
|
||||||
|
f->fd = s;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
freeaddrinfo(ailist);
|
||||||
|
if (n == 0)
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -119,6 +183,7 @@ listen_revents(struct file *file, struct pollfd *pfd)
|
||||||
caddrlen = sizeof(caddrlen);
|
caddrlen = sizeof(caddrlen);
|
||||||
sock = accept(f->fd, &caddr, &caddrlen);
|
sock = accept(f->fd, &caddr, &caddrlen);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
|
/* XXX: should kill the socket */
|
||||||
perror("accept");
|
perror("accept");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +205,21 @@ listen_close(struct file *file)
|
||||||
{
|
{
|
||||||
struct listen *f = (struct listen *)file;
|
struct listen *f = (struct listen *)file;
|
||||||
|
|
||||||
unlink(f->path);
|
if (f->path != NULL) {
|
||||||
free(f->path);
|
unlink(f->path);
|
||||||
|
free(f->path);
|
||||||
|
}
|
||||||
close(f->fd);
|
close(f->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
listen_closeall(void)
|
||||||
|
{
|
||||||
|
struct file *f, *fnext;
|
||||||
|
|
||||||
|
for (f = LIST_FIRST(&file_list); f != NULL; f = fnext) {
|
||||||
|
fnext = LIST_NEXT(f, entry);
|
||||||
|
if (f->ops == &listen_ops)
|
||||||
|
file_close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: listen.h,v 1.5 2009/07/25 10:52:19 ratchov Exp $ */
|
/* $OpenBSD$ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
|
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
|
||||||
*
|
*
|
||||||
|
@ -28,11 +28,12 @@ struct listen {
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct listen *listen_new(struct fileops *, char *);
|
void listen_new_un(char *);
|
||||||
|
void listen_new_tcp(char *, unsigned);
|
||||||
int listen_nfds(struct file *);
|
int listen_nfds(struct file *);
|
||||||
int listen_pollfd(struct file *, struct pollfd *, int);
|
int listen_pollfd(struct file *, struct pollfd *, int);
|
||||||
int listen_revents(struct file *, struct pollfd *);
|
int listen_revents(struct file *, struct pollfd *);
|
||||||
void listen_close(struct file *);
|
void listen_close(struct file *);
|
||||||
extern struct fileops listen_ops;
|
void listen_closeall(void);
|
||||||
|
|
||||||
#endif /* !defined(LISTEN_H) */
|
#endif /* !defined(LISTEN_H) */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
.Nm midicat
|
.Nm midicat
|
||||||
.Op Fl dl
|
.Op Fl dl
|
||||||
.Op Fl i Ar file
|
.Op Fl i Ar file
|
||||||
|
.Op Fl L Ar addr
|
||||||
.Op Fl o Ar file
|
.Op Fl o Ar file
|
||||||
.Op Fl q Ar port
|
.Op Fl q Ar port
|
||||||
.Op Fl s Ar name
|
.Op Fl s Ar name
|
||||||
|
@ -57,6 +58,13 @@ Read data to send from this file.
|
||||||
If the option argument is
|
If the option argument is
|
||||||
.Sq -
|
.Sq -
|
||||||
then standard input will be used.
|
then standard input will be used.
|
||||||
|
.It Fl L Ar addr
|
||||||
|
Listen on the given address for incoming TCP connections.
|
||||||
|
Without this option,
|
||||||
|
.Nm
|
||||||
|
listens only on the Unix-domain socket, thus it's not reachable
|
||||||
|
from the network.
|
||||||
|
The port number is 6533 plus the unit number.
|
||||||
.It Fl l
|
.It Fl l
|
||||||
Detach and become a daemon.
|
Detach and become a daemon.
|
||||||
.It Fl o Ar file
|
.It Fl o Ar file
|
||||||
|
|
|
@ -27,7 +27,7 @@ prefix=/usr/local # where to install sndio
|
||||||
so="libsndio.so.\${MAJ}.\${MIN}" # shared libs to build
|
so="libsndio.so.\${MAJ}.\${MIN}" # shared libs to build
|
||||||
alsa=no # do we want alsa support ?
|
alsa=no # do we want alsa support ?
|
||||||
sun=no # do we want sun support ?
|
sun=no # do we want sun support ?
|
||||||
precision=16 # aucat arithmetic precision
|
precision=16 # aucat arithmetic precision
|
||||||
unset vars # variables passed as arguments
|
unset vars # variables passed as arguments
|
||||||
unset bindir # path where to install binaries
|
unset bindir # path where to install binaries
|
||||||
unset datadir # path where to install doc
|
unset datadir # path where to install doc
|
||||||
|
@ -47,7 +47,7 @@ case `uname` in
|
||||||
so="$so libsndio.so.\${MAJ} libsndio.so"
|
so="$so libsndio.so.\${MAJ} libsndio.so"
|
||||||
defs='-DCOMPAT_GETPEEREID -DCOMPAT_ISSETUGID \\\
|
defs='-DCOMPAT_GETPEEREID -DCOMPAT_ISSETUGID \\\
|
||||||
-DCOMPAT_STRLCPY -DCOMPAT_STRTONUM \\\
|
-DCOMPAT_STRLCPY -DCOMPAT_STRTONUM \\\
|
||||||
-DCOMPAT_LETOH -DCOMPAT_PACKED'
|
-DCOMPAT_LETOH -DCOMPAT_PACKED -DDEV_RANDOM=\\"/dev/urandom\\"'
|
||||||
;;
|
;;
|
||||||
OpenBSD)
|
OpenBSD)
|
||||||
sun=yes
|
sun=yes
|
||||||
|
|
178
libsndio/aucat.c
178
libsndio/aucat.c
|
@ -19,7 +19,8 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <netinet/in.h> /* IPPROTO_XXX */
|
||||||
|
#include <netdb.h> /* gethostbyname */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include "sndio.h"
|
||||||
|
|
||||||
#include "aucat.h"
|
#include "aucat.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
@ -35,6 +37,10 @@
|
||||||
#include "bsd-compat.h"
|
#include "bsd-compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEV_RANDOM
|
||||||
|
#define DEV_RANDOM "/dev/arandom"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* read a message, return 0 if not completed
|
* read a message, return 0 if not completed
|
||||||
*/
|
*/
|
||||||
|
@ -199,7 +205,26 @@ aucat_wdata(struct aucat *hdl, const void *buf, size_t len, unsigned wbpf, int *
|
||||||
int
|
int
|
||||||
aucat_gencookie(unsigned char *cookie)
|
aucat_gencookie(unsigned char *cookie)
|
||||||
{
|
{
|
||||||
arc4random_buf(cookie, AMSG_COOKIELEN);
|
int fd;
|
||||||
|
ssize_t n, len;
|
||||||
|
|
||||||
|
fd = open(DEV_RANDOM, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
DPERROR(DEV_RANDOM);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len = AMSG_COOKIELEN;
|
||||||
|
while (len > 0) {
|
||||||
|
n = read(fd, cookie, AMSG_COOKIELEN);
|
||||||
|
if (n < 0) {
|
||||||
|
DPERROR(DEV_RANDOM);
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cookie += n;
|
||||||
|
len -= n;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,16 +285,121 @@ bad_gen:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
aucat_connect_tcp(struct aucat *hdl, char *host, char *unit, unsigned mode)
|
||||||
|
{
|
||||||
|
int s, error;
|
||||||
|
struct addrinfo *ailist, *ai, aihints;
|
||||||
|
unsigned port;
|
||||||
|
char serv[NI_MAXSERV];
|
||||||
|
|
||||||
|
if (sscanf(unit, "%u", &port) != 1) {
|
||||||
|
DPRINTF("%s: bad unit number\n", unit);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (mode & (MIO_IN | MIO_OUT)) {
|
||||||
|
port += MIDICAT_PORT;
|
||||||
|
} else if (mode & (SIO_PLAY | SIO_REC)) {
|
||||||
|
port += AUCAT_PORT;
|
||||||
|
} else {
|
||||||
|
DPRINTF("aucat_connect_tcp: unknown mode\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
snprintf(serv, sizeof(serv), "%u", port);
|
||||||
|
memset(&aihints, 0, sizeof(struct addrinfo));
|
||||||
|
aihints.ai_socktype = SOCK_STREAM;
|
||||||
|
aihints.ai_protocol = IPPROTO_TCP;
|
||||||
|
error = getaddrinfo(host, serv, &aihints, &ailist);
|
||||||
|
if (error) {
|
||||||
|
DPRINTF("%s: %s\n", host, gai_strerror(error));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s = -1;
|
||||||
|
for (ai = ailist; ai != NULL; ai = ai->ai_next) {
|
||||||
|
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
|
if (s < 0) {
|
||||||
|
DPERROR("socket");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||||
|
DPERROR("connect");
|
||||||
|
close(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(ailist);
|
||||||
|
if (s < 0)
|
||||||
|
return 0;
|
||||||
|
hdl->fd = s;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
aucat_connect_un(struct aucat *hdl, char *unit, unsigned mode)
|
||||||
|
{
|
||||||
|
struct sockaddr_un ca;
|
||||||
|
socklen_t len = sizeof(struct sockaddr_un);
|
||||||
|
char *sock;
|
||||||
|
uid_t uid;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if (mode & (MIO_IN | MIO_OUT)) {
|
||||||
|
sock = MIDICAT_PATH;
|
||||||
|
} else if (mode & (SIO_PLAY | SIO_REC)) {
|
||||||
|
sock = AUCAT_PATH;
|
||||||
|
} else {
|
||||||
|
DPRINTF("aucat_connect_un: unknown mode\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
uid = geteuid();
|
||||||
|
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
||||||
|
"/tmp/aucat-%u/%s%s", uid, sock, unit);
|
||||||
|
ca.sun_family = AF_UNIX;
|
||||||
|
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (s < 0)
|
||||||
|
return 0;
|
||||||
|
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
DPERROR("aucat_init: connect");
|
||||||
|
/* try shared server */
|
||||||
|
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
||||||
|
"/tmp/aucat/%s%s", sock, unit);
|
||||||
|
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
DPERROR("aucat_init: connect");
|
||||||
|
close(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hdl->fd = s;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nbio)
|
aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nbio)
|
||||||
{
|
{
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
int s, eof;
|
int eof, hashost;
|
||||||
char unit[4], *sep, *opt;
|
char unit[4], *sep, *opt;
|
||||||
struct sockaddr_un ca;
|
char host[NI_MAXHOST];
|
||||||
socklen_t len = sizeof(struct sockaddr_un);
|
|
||||||
uid_t uid;
|
|
||||||
|
|
||||||
|
sep = strchr(str, '/');
|
||||||
|
if (sep == NULL) {
|
||||||
|
hashost = 0;
|
||||||
|
} else {
|
||||||
|
if (sep - str >= sizeof(host)) {
|
||||||
|
DPRINTF("aucat_open: %s: host too long\n", str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(host, str, sep - str);
|
||||||
|
host[sep - str] = '\0';
|
||||||
|
hashost = 1;
|
||||||
|
str = sep + 1;
|
||||||
|
}
|
||||||
sep = strchr(str, '.');
|
sep = strchr(str, '.');
|
||||||
if (sep == NULL) {
|
if (sep == NULL) {
|
||||||
opt = "default";
|
opt = "default";
|
||||||
|
@ -283,36 +413,17 @@ aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nb
|
||||||
strlcpy(unit, str, opt - str);
|
strlcpy(unit, str, opt - str);
|
||||||
}
|
}
|
||||||
DPRINTF("aucat_init: trying %s -> %s.%s\n", str, unit, opt);
|
DPRINTF("aucat_init: trying %s -> %s.%s\n", str, unit, opt);
|
||||||
uid = geteuid();
|
if (hashost) {
|
||||||
if (strchr(str, '/') != NULL)
|
if (!aucat_connect_tcp(hdl, host, unit, mode))
|
||||||
return 0;
|
return 0;
|
||||||
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
} else {
|
||||||
"/tmp/aucat-%u/%s%s", uid, sock, unit);
|
if (!aucat_connect_un(hdl, unit, mode))
|
||||||
ca.sun_family = AF_UNIX;
|
return 0;
|
||||||
|
|
||||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (s < 0)
|
|
||||||
goto bad_free;
|
|
||||||
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
DPERROR("aucat_init: connect");
|
|
||||||
/* try shared server */
|
|
||||||
snprintf(ca.sun_path, sizeof(ca.sun_path),
|
|
||||||
"/tmp/aucat/%s%s", sock, unit);
|
|
||||||
while (connect(s, (struct sockaddr *)&ca, len) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
DPERROR("aucat_init: connect");
|
|
||||||
goto bad_connect;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) < 0) {
|
if (fcntl(hdl->fd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||||
DPERROR("FD_CLOEXEC");
|
DPERROR("FD_CLOEXEC");
|
||||||
goto bad_connect;
|
goto bad_connect;
|
||||||
}
|
}
|
||||||
hdl->fd = s;
|
|
||||||
hdl->rstate = RSTATE_MSG;
|
hdl->rstate = RSTATE_MSG;
|
||||||
hdl->rtodo = sizeof(struct amsg);
|
hdl->rtodo = sizeof(struct amsg);
|
||||||
hdl->wstate = WSTATE_IDLE;
|
hdl->wstate = WSTATE_IDLE;
|
||||||
|
@ -350,9 +461,8 @@ aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nb
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
bad_connect:
|
bad_connect:
|
||||||
while (close(s) < 0 && errno == EINTR)
|
while (close(hdl->fd) < 0 && errno == EINTR)
|
||||||
; /* retry */
|
; /* retry */
|
||||||
bad_free:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue