Alexandre Ratchov wrote:
> Initially aucat was designed to handle one device only so multiple
> audio devices used to be supported simply by starting multiple aucat
> processes (one per device), very simple. Then (~1.5 years ago) we
> added support for multiple audio devices (ie multiple -f options), and
> now it's time to finish the job and add a "device number" component in
> sndio(7) device names. Since this partially breaks compatibility, this
> is a opportunitiy to fix few other design mistakes (eg ':' being used
> by inet6, type name vs api name confusion, etc..). This leads to the
> following names:
>
> type[@hostname][,unit]/devnum[.option]
>
Hi Alexandre,
The highlighted code at the bottom of this mail contains comparisons like
this: strncmp("snd", str, len) == 0
This makes it possible to do things like:
$ aucat -fsnds/0 -i${HOME}/them.wav
snd0: snds/0: failed to open audio device => Ok, this should fail
$ aucat -fsn/0 -i${HOME}/them.wav => Not Ok ???, this plays the music
The second call doesn't fail because if len is smaller then strlen("snd")
than it potentially matches a partial "snd", allowing device types like "s"
and "sn" (in the case of type "snd"). I suppose this is not what you
intended.
I tend to do comparisons like this as follows,
strncmp(str, "snd", sizeof("snd")) == 0,
using the NUL character in "snd" as a sort of boundary check.
I'm not 100% sure though that this is always safe when strlen(str) <
sizeof("snd").
Maybe the safest option is to check if len == strlen("snd") before making
the comparison. This mail includes a PoC patch using this method.
After applying the patch aucat should behave like this:
$ aucat -fsnds/0 -i${HOME}/them.wav
snd0: snds/0: failed to open audio device
$ aucat -fsnd/0 -i${HOME}/them.wav => Ok, playing music
$ aucat -fsn/0 -i${HOME}/them.wav
snd0: sn/0: failed to open audio device
$ aucat -fs/0 -i${HOME}/them.wav
snd0: s/0: failed to open audio device
$ aucat -f/0 -i${HOME}/them.wav
snd0: /0: failed to open audio device
$ aucat -f0 -i${HOME}/them.wav
snd0: 0: failed to open audio device
Though I patched mio.c I didn't actually test midicat.
For this proof-of-concept I only tested aucat with device types snd and
rsnd, which seem to work for me.
Some other more or less random weirdness I found is that I can specify either
sun, sun: or sun:0 for the device and all three of them will play sound.
I'd expect only sun:0 to work. Device aucat hasn't got this problem. I haven't
tracked this down but I suspect some additional checking is going on outside
the sio_open function.
P.S.:
I added a comparison function sio_is_type. But I didn't know how to share it
properly between sio.c and mio.c so my solution might look a bit quick and
dirty. (especially the extern sio_is_type declaration in mio.c)
>
> Index: lib/libsndio/mio.c
> ===================================================================
> RCS file: /cvs/src/lib/libsndio/mio.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 mio.c
> --- lib/libsndio/mio.c 17 Oct 2011 21:09:11 -0000 1.12
> +++ lib/libsndio/mio.c 8 Nov 2011 19:18:19 -0000
> @@ -49,26 +46,23 @@ mio_open(const char *str, unsigned mode,
> if (str == NULL && !issetugid())
> str = getenv("MIDIDEVICE");
> if (str == NULL) {
> - hdl = mio_aucat_open("0", mode, nbio);
> + hdl = mio_aucat_open("/0", mode, nbio, 1);
> if (hdl != NULL)
> return hdl;
> - return mio_rmidi_open("0", mode, nbio);
> + return mio_rmidi_open("/0", mode, nbio);
> }
> - sep = strchr(str, ':');
> - if (sep == NULL) {
> - DPRINTF("mio_open: %s: ':' missing in device name\n", str);
> - return NULL;
> + for (len = 0; (c = str[len]) != '\0'; len++) {
> + /* XXX: remove ':' compat bits */
> + if (c == ':' || c == '@' || c == '/' || c == ',')
> + break;
> }
> - len = sep - str;
> - if (len == (sizeof(prefix_midithru) - 1) &&
> - memcmp(str, prefix_midithru, len) == 0)
> - return mio_aucat_open(sep + 1, mode, nbio);
> - if (len == (sizeof(prefix_aucat) - 1) &&
> - memcmp(str, prefix_aucat, len) == 0)
> - return mio_aucat_open(sep + 1, mode, nbio);
> - if (len == (sizeof(prefix_rmidi) - 1) &&
> - memcmp(str, prefix_rmidi, len) == 0)
> - return mio_rmidi_open(sep + 1, mode, nbio);
> + if (strncmp("snd", str, len) == 0 ||
> + strncmp("aucat", str, len) == 0)
> + return mio_aucat_open(str + len, mode, nbio, 0);
> + if (strncmp("midithru", str, len) == 0)
> + return mio_aucat_open(str + len, mode, nbio, 1);
> + if (strncmp("rmidi", str, len) == 0)
> + return mio_rmidi_open(str + len, mode, nbio);
> DPRINTF("mio_open: %s: unknown device type\n", str);
> return NULL;
> }
> Index: lib/libsndio/sio.c
> ===================================================================
> RCS file: /cvs/src/lib/libsndio/sio.c,v
> retrieving revision 1.6
> diff -u -p -r1.6 sio.c
> --- lib/libsndio/sio.c 9 May 2011 17:34:14 -0000 1.6
> +++ lib/libsndio/sio.c 8 Nov 2011 19:18:20 -0000
> @@ -67,22 +55,22 @@ sio_open(const char *str, unsigned mode,
> if (str == NULL && !issetugid())
> str = getenv("AUDIODEVICE");
> if (str == NULL) {
> - for (b = backends; b->prefix != NULL; b++) {
> - hdl = b->open(NULL, mode, nbio);
> - if (hdl != NULL)
> - return hdl;
> - }
> - return NULL;
> + hdl = sio_aucat_open("/0", mode, nbio);
> + if (hdl != NULL)
> + return hdl;
> + return sio_sun_open("", mode, nbio);
> }
> - sep = strchr(str, ':');
> - if (sep == NULL) {
> - DPRINTF("sio_open: %s: ':' missing in device name\n", str);
> - return NULL;
> + for (len = 0; (c = str[len]) != '\0'; len++) {
> + /* XXX: remove ':' compat bits */
> + if (c == ':' || c == '@' || c == '/' || c == ',')
> + break;
> }
> - len = sep - str;
> - for (b = backends; b->prefix != NULL; b++) {
> - if (strlen(b->prefix) == len && memcmp(b->prefix, str, len) ==
> 0)
> - return b->open(sep + 1, mode, nbio);
> + if (strncmp("snd", str, len) == 0 ||
> + strncmp("aucat", str, len) == 0)
> + return sio_aucat_open(str + len, mode, nbio);
> + if (strncmp("rsnd", str, len) == 0 ||
> + strncmp("sun", str, len) == 0) {
> + return sio_sun_open(str + len, mode, nbio);
> }
> DPRINTF("sio_open: %s: unknown device type\n", str);
> return NULL;
--- sio.c Wed Nov 9 14:21:24 2011
+++ sio.c.new Wed Nov 9 14:09:44 2011
@@ -40,6 +40,17 @@
par->__magic = SIO_PAR_MAGIC;
}
+
+int
+sio_is_type(const char *str, size_t nstr, const char *type)
+{
+ if (nstr != strlen(type))
+ return (0);
+
+ return (strncmp(str, type, nstr) == 0);
+}
+
+
struct sio_hdl *
sio_open(const char *str, unsigned mode, int nbio)
{
@@ -65,13 +76,12 @@
if (c == ':' || c == '@' || c == '/' || c == ',')
break;
}
- if (strncmp("snd", str, len) == 0 ||
- strncmp("aucat", str, len) == 0)
+ if (sio_is_type(str, len, "snd") ||
+ sio_is_type(str, len, "aucat"))
return sio_aucat_open(str + len, mode, nbio);
- if (strncmp("rsnd", str, len) == 0 ||
- strncmp("sun", str, len) == 0) {
+ if (sio_is_type(str, len, "rsnd") ||
+ sio_is_type(str, len, "sun"))
return sio_sun_open(str + len, mode, nbio);
- }
DPRINTF("sio_open: %s: unknown device type\n", str);
return NULL;
}
--- mio.c Wed Nov 9 14:21:24 2011
+++ mio.c.new Wed Nov 9 14:24:25 2011
@@ -31,6 +31,8 @@
#include "debug.h"
#include "mio_priv.h"
+extern int sio_is_type(const char *, size_t, const char *);
+
struct mio_hdl *
mio_open(const char *str, unsigned mode, int nbio)
{
@@ -56,12 +58,12 @@
if (c == ':' || c == '@' || c == '/' || c == ',')
break;
}
- if (strncmp("snd", str, len) == 0 ||
- strncmp("aucat", str, len) == 0)
+ if (sio_is_type(str, len, "snd") ||
+ sio_is_type(str, len, "aucat"))
return mio_aucat_open(str + len, mode, nbio, 0);
- if (strncmp("midithru", str, len) == 0)
+ if (sio_is_type(str, len, "midithru"))
return mio_aucat_open(str + len, mode, nbio, 1);
- if (strncmp("rmidi", str, len) == 0)
+ if (sio_is_type(str, len, "rmidi"))
return mio_rmidi_open(str + len, mode, nbio);
DPRINTF("mio_open: %s: unknown device type\n", str);
return NULL;