aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2018-06-03 12:03:51 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2018-06-03 12:03:51 +0200
commitcb2836a5d2b26c1ac4fd11587501152aebbd9c7a (patch)
treea3e62196522eafeb4a1ebd9288e00fb3b6fbc679
parent9ccde92ebeb3a1d06859e7ac1ddfea013e15c07d (diff)
parent6ac38604dc1f898745a851af0df2393481caba01 (diff)
downloadsynthpod-cb2836a5d2b26c1ac4fd11587501152aebbd9c7a.tar.xz
Merge commit '6ac38604dc1f898745a851af0df2393481caba01'
-rw-r--r--osc.lv2/VERSION2
-rw-r--r--osc.lv2/meson.build2
-rw-r--r--osc.lv2/osc.lv2/stream.h876
-rw-r--r--osc.lv2/test/osc_test.c30
4 files changed, 613 insertions, 297 deletions
diff --git a/osc.lv2/VERSION b/osc.lv2/VERSION
index c0c68bab..7977b63f 100644
--- a/osc.lv2/VERSION
+++ b/osc.lv2/VERSION
@@ -1 +1 @@
-0.1.85
+0.1.93
diff --git a/osc.lv2/meson.build b/osc.lv2/meson.build
index ba60db10..d11a3be6 100644
--- a/osc.lv2/meson.build
+++ b/osc.lv2/meson.build
@@ -30,5 +30,7 @@ osc_test = executable('osc_test',
dependencies : deps,
install : false)
+# FIXME start virautl serial pair before test
+# socat -d -d pty,raw,echo=0 pty,raw,echo=0
test('Test', osc_test,
timeout : 240)
diff --git a/osc.lv2/osc.lv2/stream.h b/osc.lv2/osc.lv2/stream.h
index 85c1187f..59eed169 100644
--- a/osc.lv2/osc.lv2/stream.h
+++ b/osc.lv2/osc.lv2/stream.h
@@ -25,7 +25,9 @@
# include <sys/socket.h>
# include <net/if.h>
# include <netinet/tcp.h>
+# include <netinet/in.h>
# include <netdb.h>
+# include <termios.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
@@ -88,6 +90,7 @@ struct _LV2_OSC_Stream {
int protocol;
bool server;
bool slip;
+ bool serial;
bool connected;
int sock;
int fd;
@@ -101,27 +104,73 @@ struct _LV2_OSC_Stream {
};
typedef enum _LV2_OSC_Enum {
- LV2_OSC_NONE = (0 << 0),
- LV2_OSC_SEND = (1 << 0),
- LV2_OSC_RECV = (1 << 1)
+ LV2_OSC_NONE = 0x000000,
+
+ LV2_OSC_SEND = 0x800000,
+ LV2_OSC_RECV = 0x400000,
+ LV2_OSC_CONN = 0x200000,
+
+ LV2_OSC_ERR = 0x00ffff
} LV2_OSC_Enum;
static const char *udp_prefix = "osc.udp://";
static const char *tcp_prefix = "osc.tcp://";
static const char *tcp_slip_prefix = "osc.slip.tcp://";
static const char *tcp_prefix_prefix = "osc.prefix.tcp://";
+static const char *ser_prefix = "osc.serial://";
//FIXME serial
+
+static int
+_lv2_osc_stream_interface_attribs(int fd, int speed)
+{
+ struct termios tty;
+
+ if(tcgetattr(fd, &tty) < 0)
+ {
+ return -1;
+ }
+
+ cfsetospeed(&tty, (speed_t)speed);
+ cfsetispeed(&tty, (speed_t)speed);
+
+ tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
+ tty.c_cflag &= ~CSIZE;
+ tty.c_cflag |= CS8; /* 8-bit characters */
+ tty.c_cflag &= ~PARENB; /* no parity bit */
+ tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
+ tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
+
+ /* setup for non-canonical mode */
+ tty.c_iflag &= ~(IGNCR | ONLCR | IXON);
+ tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ tty.c_oflag &= ~OPOST;
+
+ /* fetch bytes as they become available */
+ tty.c_cc[VMIN] = 0;
+ tty.c_cc[VTIME] = 0;
+
+ if(tcsetattr(fd, TCSANOW, &tty) != 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+#define LV2_OSC_STREAM_ERRNO(EV, ERRNO) ( (EV & (~LV2_OSC_ERR)) | (ERRNO) )
+
static int
lv2_osc_stream_init(LV2_OSC_Stream *stream, const char *url,
const LV2_OSC_Driver *driv, void *data)
{
+ LV2_OSC_Enum ev = LV2_OSC_NONE;
memset(stream, 0x0, sizeof(LV2_OSC_Stream));
char *dup = strdup(url);
if(!dup)
{
- fprintf(stderr, "%s: out-of-memory\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, ENOMEM);
goto fail;
}
@@ -160,376 +209,408 @@ lv2_osc_stream_init(LV2_OSC_Stream *stream, const char *url,
stream->protocol = IPPROTO_TCP;
ptr += strlen(tcp_prefix_prefix);
}
+ else if(strncmp(ptr, ser_prefix, strlen(ser_prefix)) == 0)
+ {
+ stream->slip = true;
+ stream->serial = true;
+ ptr += strlen(ser_prefix);
+ }
else
{
- fprintf(stderr, "%s: invalid protocol\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, ENOPROTOOPT);
goto fail;
}
if(ptr[0] == '\0')
{
- fprintf(stderr, "%s: URI has no colon\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EDESTADDRREQ);
goto fail;
}
- const char *node = NULL;
- const char *iface = NULL;
- const char *service = NULL;
-
- // optional IPv6
- if(ptr[0] == '[')
- {
- stream->socket_family = AF_INET6;
- ++ptr;
- }
-
- node = ptr;
+ stream->driv = driv;
+ stream->data = data;
- // optional IPv6
- if( (tmp = strchr(ptr, '%')) )
+ if(stream->serial)
{
- if(stream->socket_family != AF_INET6)
+ stream->sock = open(ptr, O_RDWR | O_NOCTTY | O_NDELAY);
+ if(stream->sock < 0)
{
- fprintf(stderr, "%s: no IPv6 interface delimiter expected here\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
goto fail;
}
- ptr = tmp;
- ptr[0] = '\0';
- iface = ++ptr;
- }
-
- // optional IPv6
- if( (tmp = strchr(ptr, ']')) )
- if(ptr)
- {
- if(stream->socket_family != AF_INET6)
+ if(fcntl(stream->sock, F_SETFL, FNDELAY) == -1) //FIXME
{
- fprintf(stderr, "%s: no closing IPv6 bracket expected here\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
goto fail;
}
- ptr = tmp;
- ptr[0] = '\0';
- ++ptr;
- }
-
- // mandatory IPv4/6
- ptr = strchr(ptr, ':');
- if(!ptr)
- {
- fprintf(stderr, "%s: pre-service colon expected\n", __func__);
- goto fail;
- }
-
- ptr[0] = '\0';
-
- service = ++ptr;
+ if(_lv2_osc_stream_interface_attribs(stream->sock, B115200) == -1)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
- if(strlen(node) == 0)
- {
- node = NULL;
- stream->server = true;
+ stream->connected = true;
}
-
- stream->sock = socket(stream->socket_family, stream->socket_type,
- stream->protocol);
-
- if(stream->sock < 0)
+ else // !stream->serial
{
- fprintf(stderr, "%s: socket failed\n", __func__);
- goto fail;
- }
-
- if(fcntl(stream->sock, F_SETFL, O_NONBLOCK) == -1)
- {
- fprintf(stderr, "%s: fcntl failed\n", __func__);
- goto fail;
- }
-
- const int sendbuff = LV2_OSC_STREAM_SNDBUF;
- const int recvbuff = LV2_OSC_STREAM_RCVBUF;
+ const char *node = NULL;
+ const char *iface = NULL;
+ const char *service = NULL;
- if(setsockopt(stream->sock, SOL_SOCKET,
- SO_SNDBUF, &sendbuff, sizeof(int))== -1)
- {
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
- }
-
- if(setsockopt(stream->sock, SOL_SOCKET,
- SO_RCVBUF, &recvbuff, sizeof(int))== -1)
- {
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
- }
+ // optional IPv6
+ if(ptr[0] == '[')
+ {
+ stream->socket_family = AF_INET6;
+ ++ptr;
+ }
- stream->driv = driv;
- stream->data = data;
+ node = ptr;
- if(stream->socket_family == AF_INET) // IPv4
- {
- if(stream->server)
+ // optional IPv6
+ if( (tmp = strchr(ptr, '%')) )
{
- // resolve self address
- struct addrinfo hints;
- memset(&hints, 0x0, sizeof(struct addrinfo));
- hints.ai_family = stream->socket_family;
- hints.ai_socktype = stream->socket_type;
- hints.ai_protocol = stream->protocol;
-
- struct addrinfo *res;
- if(getaddrinfo(node, service, &hints, &res) != 0)
+ if(stream->socket_family != AF_INET6)
{
- fprintf(stderr, "%s: getaddrinfo failed\n", __func__);
- goto fail;
- }
- if(res->ai_addrlen != sizeof(stream->peer.in4))
- {
- fprintf(stderr, "%s: IPv4 address expected\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
goto fail;
}
- stream->self.len = res->ai_addrlen;
- stream->self.in = *res->ai_addr;
- stream->self.in4.sin_addr.s_addr = htonl(INADDR_ANY);
-
- freeaddrinfo(res);
+ ptr = tmp;
+ ptr[0] = '\0';
+ iface = ++ptr;
+ }
- if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
+ // optional IPv6
+ if( (tmp = strchr(ptr, ']')) )
+ if(ptr)
+ {
+ if(stream->socket_family != AF_INET6)
{
- fprintf(stderr, "%s: bind failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EDESTADDRREQ);
goto fail;
}
+
+ ptr = tmp;
+ ptr[0] = '\0';
+ ++ptr;
}
- else // client
+
+ // mandatory IPv4/6
+ ptr = strchr(ptr, ':');
+ if(!ptr)
{
- stream->self.len = sizeof(stream->self.in4);
- stream->self.in4.sin_family = stream->socket_family;
- stream->self.in4.sin_port = htons(0);
- stream->self.in4.sin_addr.s_addr = htonl(INADDR_ANY);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EDESTADDRREQ);
+ goto fail;
+ }
- if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
- {
- fprintf(stderr, "%s: bind failed\n", __func__);
- goto fail;
- }
+ ptr[0] = '\0';
- // resolve peer address
- struct addrinfo hints;
- memset(&hints, 0x0, sizeof(struct addrinfo));
- hints.ai_family = stream->socket_family;
- hints.ai_socktype = stream->socket_type;
- hints.ai_protocol = stream->protocol;
+ service = ++ptr;
- struct addrinfo *res;
- if(getaddrinfo(node, service, &hints, &res) != 0)
- {
- fprintf(stderr, "%s: getaddrinfo failed\n", __func__);
- goto fail;
- }
- if(res->ai_addrlen != sizeof(stream->peer.in4))
- {
- fprintf(stderr, "%s: IPv4 address failed\n", __func__);
- goto fail;
- }
+ if(strlen(node) == 0)
+ {
+ node = NULL;
+ stream->server = true;
+ }
- stream->peer.len = res->ai_addrlen;
- stream->peer.in = *res->ai_addr;
+ stream->sock = socket(stream->socket_family, stream->socket_type,
+ stream->protocol);
- freeaddrinfo(res);
+ if(stream->sock < 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
}
- if(stream->socket_type == SOCK_DGRAM)
+ if(fcntl(stream->sock, F_SETFL, O_NONBLOCK) == -1)
{
- const int broadcast = 1;
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
- if(setsockopt(stream->sock, SOL_SOCKET, SO_BROADCAST,
- &broadcast, sizeof(broadcast)) != 0)
- {
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
- }
+ const int sendbuff = LV2_OSC_STREAM_SNDBUF;
+ const int recvbuff = LV2_OSC_STREAM_RCVBUF;
- //FIXME handle multicast
+ if(setsockopt(stream->sock, SOL_SOCKET,
+ SO_SNDBUF, &sendbuff, sizeof(int))== -1)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
}
- else if(stream->socket_type == SOCK_STREAM)
+
+ if(setsockopt(stream->sock, SOL_SOCKET,
+ SO_RCVBUF, &recvbuff, sizeof(int))== -1)
{
- const int flag = 1;
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
- if(setsockopt(stream->sock, stream->protocol,
- TCP_NODELAY, &flag, sizeof(int)) != 0)
+ if(stream->socket_family == AF_INET) // IPv4
+ {
+ if(stream->server)
{
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
- }
+ // resolve self address
+ struct addrinfo hints;
+ memset(&hints, 0x0, sizeof(struct addrinfo));
+ hints.ai_family = stream->socket_family;
+ hints.ai_socktype = stream->socket_type;
+ hints.ai_protocol = stream->protocol;
+
+ struct addrinfo *res;
+ if(getaddrinfo(node, service, &hints, &res) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+ if(res->ai_addrlen != sizeof(stream->peer.in4))
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
+ goto fail;
+ }
- if(setsockopt(stream->sock, SOL_SOCKET,
- SO_KEEPALIVE, &flag, sizeof(int)) != 0)
- {
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
- }
+ stream->self.len = res->ai_addrlen;
+ stream->self.in = *res->ai_addr;
+ stream->self.in4.sin_addr.s_addr = htonl(INADDR_ANY);
- if(stream->server)
- {
- if(listen(stream->sock, 1) != 0)
+ freeaddrinfo(res);
+
+ if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
{
- fprintf(stderr, "%s: listen failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
goto fail;
}
}
else // client
{
- if(connect(stream->sock, &stream->peer.in, stream->peer.len) == 0)
+ stream->self.len = sizeof(stream->self.in4);
+ stream->self.in4.sin_family = stream->socket_family;
+ stream->self.in4.sin_port = htons(0);
+ stream->self.in4.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+
+ // resolve peer address
+ struct addrinfo hints;
+ memset(&hints, 0x0, sizeof(struct addrinfo));
+ hints.ai_family = stream->socket_family;
+ hints.ai_socktype = stream->socket_type;
+ hints.ai_protocol = stream->protocol;
+
+ struct addrinfo *res;
+ if(getaddrinfo(node, service, &hints, &res) != 0)
{
- stream->connected = true;
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
}
+ if(res->ai_addrlen != sizeof(stream->peer.in4))
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
+ goto fail;
+ }
+
+ stream->peer.len = res->ai_addrlen;
+ stream->peer.in = *res->ai_addr;
+
+ freeaddrinfo(res);
}
- }
- else
- {
- fprintf(stderr, "%s: invalid socket type\n", __func__);
- goto fail;
- }
- }
- else if(stream->socket_family == AF_INET6) // IPv6
- {
- if(stream->server)
- {
- // resolve self address
- struct addrinfo hints;
- memset(&hints, 0x0, sizeof(struct addrinfo));
- hints.ai_family = stream->socket_family;
- hints.ai_socktype = stream->socket_type;
- hints.ai_protocol = stream->protocol;
-
- struct addrinfo *res;
- if(getaddrinfo(node, service, &hints, &res) != 0)
+
+ if(stream->socket_type == SOCK_DGRAM)
{
- fprintf(stderr, "%s: getaddrinfo failed\n", __func__);
- goto fail;
+ const int broadcast = 1;
+
+ if(setsockopt(stream->sock, SOL_SOCKET, SO_BROADCAST,
+ &broadcast, sizeof(broadcast)) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+
+ //FIXME handle multicast
}
- if(res->ai_addrlen != sizeof(stream->peer.in6))
+ else if(stream->socket_type == SOCK_STREAM)
{
- fprintf(stderr, "%s: IPv6 address expected\n", __func__);
- goto fail;
- }
+ const int flag = 1;
- stream->self.len = res->ai_addrlen;
- stream->self.in = *res->ai_addr;
- stream->self.in6.sin6_addr = in6addr_any;
- if(iface)
- {
- stream->self.in6.sin6_scope_id = if_nametoindex(iface);
- }
+ if(setsockopt(stream->sock, stream->protocol,
+ TCP_NODELAY, &flag, sizeof(int)) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
- freeaddrinfo(res);
+ if(setsockopt(stream->sock, SOL_SOCKET,
+ SO_KEEPALIVE, &flag, sizeof(int)) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
- if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
+ if(stream->server)
+ {
+ if(listen(stream->sock, 1) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+ }
+ else // client
+ {
+ if(connect(stream->sock, &stream->peer.in, stream->peer.len) == 0)
+ {
+ stream->connected = true;
+ }
+ }
+ }
+ else
{
- fprintf(stderr, "%s: bind failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
goto fail;
}
}
- else // client
+ else if(stream->socket_family == AF_INET6) // IPv6
{
- stream->self.len = sizeof(stream->self.in6);
- stream->self.in6.sin6_family = stream->socket_family;
- stream->self.in6.sin6_port = htons(0);
- stream->self.in6.sin6_addr = in6addr_any;
- if(iface)
+ if(stream->server)
{
- stream->self.in6.sin6_scope_id = if_nametoindex(iface);
- }
+ // resolve self address
+ struct addrinfo hints;
+ memset(&hints, 0x0, sizeof(struct addrinfo));
+ hints.ai_family = stream->socket_family;
+ hints.ai_socktype = stream->socket_type;
+ hints.ai_protocol = stream->protocol;
+
+ struct addrinfo *res;
+ if(getaddrinfo(node, service, &hints, &res) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+ if(res->ai_addrlen != sizeof(stream->peer.in6))
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
+ goto fail;
+ }
- if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
- {
- fprintf(stderr, "%s: bind failed\n", __func__);
- goto fail;
- }
+ stream->self.len = res->ai_addrlen;
+ stream->self.in = *res->ai_addr;
+ stream->self.in6.sin6_addr = in6addr_any;
+ if(iface)
+ {
+ stream->self.in6.sin6_scope_id = if_nametoindex(iface);
+ }
- // resolve peer address
- struct addrinfo hints;
- memset(&hints, 0x0, sizeof(struct addrinfo));
- hints.ai_family = stream->socket_family;
- hints.ai_socktype = stream->socket_type;
- hints.ai_protocol = stream->protocol;
+ freeaddrinfo(res);
- struct addrinfo *res;
- if(getaddrinfo(node, service, &hints, &res) != 0)
- {
- fprintf(stderr, "%s: getaddrinfo failed\n", __func__);
- goto fail;
- }
- if(res->ai_addrlen != sizeof(stream->peer.in6))
- {
- fprintf(stderr, "%s: IPv6 address expected\n", __func__);
- goto fail;
+ if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
}
- stream->peer.len = res->ai_addrlen;
- stream->peer.in = *res->ai_addr;
- if(iface)
+ else // client
{
- stream->peer.in6.sin6_scope_id = if_nametoindex(iface);
- }
+ stream->self.len = sizeof(stream->self.in6);
+ stream->self.in6.sin6_family = stream->socket_family;
+ stream->self.in6.sin6_port = htons(0);
+ stream->self.in6.sin6_addr = in6addr_any;
+ if(iface)
+ {
+ stream->self.in6.sin6_scope_id = if_nametoindex(iface);
+ }
- freeaddrinfo(res);
- }
+ if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
- if(stream->socket_type == SOCK_DGRAM)
- {
- // nothing to do
- }
- else if(stream->socket_type == SOCK_STREAM)
- {
- const int flag = 1;
+ // resolve peer address
+ struct addrinfo hints;
+ memset(&hints, 0x0, sizeof(struct addrinfo));
+ hints.ai_family = stream->socket_family;
+ hints.ai_socktype = stream->socket_type;
+ hints.ai_protocol = stream->protocol;
- if(setsockopt(stream->sock, stream->protocol,
- TCP_NODELAY, &flag, sizeof(int)) != 0)
- {
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
+ struct addrinfo *res;
+ if(getaddrinfo(node, service, &hints, &res) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+ if(res->ai_addrlen != sizeof(stream->peer.in6))
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
+ goto fail;
+ }
+ stream->peer.len = res->ai_addrlen;
+ stream->peer.in = *res->ai_addr;
+ if(iface)
+ {
+ stream->peer.in6.sin6_scope_id = if_nametoindex(iface);
+ }
+
+ freeaddrinfo(res);
}
- if(setsockopt(stream->sock, SOL_SOCKET,
- SO_KEEPALIVE, &flag, sizeof(int)) != 0)
+ if(stream->socket_type == SOCK_DGRAM)
{
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
- goto fail;
+ // nothing to do
}
-
- if(stream->server)
+ else if(stream->socket_type == SOCK_STREAM)
{
- if(listen(stream->sock, 1) != 0)
+ const int flag = 1;
+
+ if(setsockopt(stream->sock, stream->protocol,
+ TCP_NODELAY, &flag, sizeof(int)) != 0)
{
- fprintf(stderr, "%s: listen failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
goto fail;
}
- }
- else // client
- {
- if(connect(stream->sock, &stream->peer.in, stream->peer.len) == 0)
+
+ if(setsockopt(stream->sock, SOL_SOCKET,
+ SO_KEEPALIVE, &flag, sizeof(int)) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+
+ if(stream->server)
+ {
+ if(listen(stream->sock, 1) != 0)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ goto fail;
+ }
+ }
+ else // client
{
- stream->connected = true;
+ if(connect(stream->sock, &stream->peer.in, stream->peer.len) == 0)
+ {
+ stream->connected = true;
+ }
}
}
+ else
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
+ goto fail;
+ }
}
else
{
- fprintf(stderr, "%s: invalid socket type\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE);
goto fail;
}
}
- else
- {
- fprintf(stderr, "%s: invalid socket family\n", __func__);
- goto fail;
- }
free(dup);
- return 0;
+ return ev;
fail:
if(dup)
@@ -543,7 +624,7 @@ fail:
stream->sock = -1;
}
- return -1;
+ return ev;
}
#define SLIP_END 0300 // 0xC0, 192, indicates end of packet
@@ -672,12 +753,12 @@ _lv2_osc_stream_run_udp(LV2_OSC_Stream *stream)
break;
}
- fprintf(stderr, "%s: sendto: %s\n", __func__, strerror(errno));
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
break;
}
else if(sent != (ssize_t)tosend)
{
- fprintf(stderr, "%s: only sent %zi of %zu bytes", __func__, sent, tosend);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EIO);
break;
}
@@ -708,7 +789,7 @@ _lv2_osc_stream_run_udp(LV2_OSC_Stream *stream)
break;
}
- fprintf(stderr, "%s: recv: %s\n", __func__, strerror(errno));
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
break;
}
else if(recvd == 0)
@@ -749,45 +830,41 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
if(fcntl(stream->fd, F_SETFL, O_NONBLOCK) == -1)
{
- fprintf(stderr, "%s: fcntl failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
}
if(setsockopt(stream->fd, stream->protocol,
TCP_NODELAY, &flag, sizeof(int)) != 0)
{
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
}
if(setsockopt(stream->sock, SOL_SOCKET,
SO_KEEPALIVE, &flag, sizeof(int)) != 0)
{
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
}
if(setsockopt(stream->fd, SOL_SOCKET,
SO_SNDBUF, &sendbuff, sizeof(int))== -1)
{
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
}
if(setsockopt(stream->fd, SOL_SOCKET,
SO_RCVBUF, &recvbuff, sizeof(int))== -1)
{
- fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
}
- stream->connected = true;
- //fprintf(stderr, "%s: orderly accept\n", __func__);
- //FIXME ev |=
+ stream->connected = true; // orderly accept
}
}
else
{
if(connect(stream->sock, &stream->peer.in, stream->peer.len) == 0)
{
- stream->connected = true;
- //fprintf(stderr, "%s: orderly (re)connect\n", __func__);
- //FIXME ev |=
+ stream->connected = true; // orderly (re)connect
}
}
}
@@ -855,12 +932,12 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
}
stream->connected = false;
- fprintf(stderr, "%s: send: %s\n", __func__, strerror(errno));
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
break;
}
else if(sent != (ssize_t)tosend)
{
- fprintf(stderr, "%s: only sent %zi of %zu bytes", __func__, sent, tosend);
+ ev = LV2_OSC_STREAM_ERRNO(ev, EIO);
break;
}
@@ -901,7 +978,7 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
}
stream->connected = false;
- fprintf(stderr, "%s: recv(slip): %s\n", __func__, strerror(errno));
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
break;
}
else if(recvd == 0)
@@ -913,8 +990,7 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
stream->fd = -1;
}
- stream->connected = false;
- //fprintf(stderr, "%s: recv(slip): %s\n", __func__, "orderly shutdown");
+ stream->connected = false; // orderly shutdown
break;
}
@@ -940,7 +1016,7 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
else
{
parsed = 0;
- fprintf(stderr, "%s: write buffer overflow\n", __func__);
+ ev = LV2_OSC_STREAM_ERRNO(ev, ENOMEM);
}
}
@@ -998,7 +1074,7 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
}
stream->connected = false;
- fprintf(stderr, "%s: recv(prefix): %s\n", __func__, strerror(errno));
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
break;
}
else if(recvd == 0)
@@ -1010,8 +1086,209 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
stream->fd = -1;
}
+ stream->connected = false; // orderly shutdown
+ break;
+ }
+
+ stream->driv->write_adv(stream->data, recvd);
+ ev |= LV2_OSC_RECV;
+ }
+ }
+ }
+ }
+
+ if(stream->connected)
+ {
+ ev |= LV2_OSC_CONN;
+ }
+
+ return ev;
+}
+
+static LV2_OSC_Enum
+_lv2_osc_stream_run_ser(LV2_OSC_Stream *stream)
+{
+ LV2_OSC_Enum ev = LV2_OSC_NONE;
+
+ // send everything
+ {
+ const int fd = stream->sock;
+
+ if(fd >= 0)
+ {
+ const uint8_t *buf;
+ size_t tosend;
+
+ while( (buf = stream->driv->read_req(stream->data, &tosend)) )
+ {
+ if(stream->slip) // SLIP framed
+ {
+ if(tosend <= sizeof(stream->tx_buf)) // check if there is enough memory
+ {
+ memcpy(stream->tx_buf, buf, tosend);
+ tosend = lv2_osc_slip_encode_inline(stream->tx_buf, tosend);
+ }
+ else
+ {
+ tosend = 0;
+ }
+ }
+ else // uint32_t prefix frames
+ {
+ const size_t nsize = tosend + sizeof(uint32_t);
+
+ if(nsize <= sizeof(stream->tx_buf)) // check if there is enough memory
+ {
+ const uint32_t prefix = htonl(tosend);
+
+ memcpy(stream->tx_buf, &prefix, sizeof(uint32_t));
+ memcpy(stream->tx_buf + sizeof(uint32_t), buf, tosend);
+ tosend = nsize;
+ }
+ else
+ {
+ tosend = 0;
+ }
+ }
+
+ const ssize_t sent = tosend
+ ? write(fd, stream->tx_buf, tosend)
+ : 0;
+
+ if(sent == -1)
+ {
+ if( (errno == EAGAIN) || (errno == EWOULDBLOCK) )
+ {
+ // empty queue
+ break;
+ }
+
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ break;
+ }
+ else if(sent != (ssize_t)tosend)
+ {
+ ev = LV2_OSC_STREAM_ERRNO(ev, EIO);
+ break;
+ }
+
+ stream->driv->read_adv(stream->data);
+ ev |= LV2_OSC_SEND;
+ }
+ }
+ }
+
+ // recv everything
+ {
+ const int fd = stream->sock;
+
+ if(fd >= 0)
+ {
+ if(stream->slip) // SLIP framed
+ {
+ while(true)
+ {
+ ssize_t recvd = read(fd, stream->rx_buf + stream->rx_off,
+ sizeof(stream->rx_buf) - stream->rx_off);
+
+ if(recvd == -1)
+ {
+ if( (errno == EAGAIN) || (errno == EWOULDBLOCK) )
+ {
+ // empty queue
+ break;
+ }
+
stream->connected = false;
- //fprintf(stderr, "%s: recv(prefix): %s\n", __func__, "orderly shutdown");
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ break;
+ }
+ else if(recvd == 0)
+ {
+ // orderly shutdown
+ break;
+ }
+
+ uint8_t *ptr = stream->rx_buf;
+ recvd += stream->rx_off;
+
+ while(recvd > 0)
+ {
+ size_t size;
+ size_t parsed = lv2_osc_slip_decode_inline(ptr, recvd, &size);
+
+ if(size) // dispatch
+ {
+ uint8_t *buf;
+
+ if( (buf = stream->driv->write_req(stream->data, size, NULL)) )
+ {
+ memcpy(buf, ptr, size);
+
+ stream->driv->write_adv(stream->data, size);
+ ev |= LV2_OSC_RECV;
+ }
+ else
+ {
+ parsed = 0;
+ ev = LV2_OSC_STREAM_ERRNO(ev, ENOMEM);
+ }
+ }
+
+ if(parsed)
+ {
+ ptr += parsed;
+ recvd -= parsed;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if(recvd > 0) // is there remaining chunk for next call?
+ {
+ memmove(stream->rx_buf, ptr, recvd);
+ stream->rx_off = recvd;
+ }
+ else
+ {
+ stream->rx_off = 0;
+ }
+
+ break;
+ }
+ }
+ else // uint32_t prefix frames
+ {
+ uint8_t *buf;
+
+ while( (buf = stream->driv->write_req(stream->data,
+ LV2_OSC_STREAM_REQBUF, NULL)) )
+ {
+ uint32_t prefix;
+
+ ssize_t recvd = read(fd, &prefix, sizeof(uint32_t));
+ if(recvd == sizeof(uint32_t))
+ {
+ prefix = ntohl(prefix); //FIXME check prefix <= max_len
+ recvd = read(fd, buf, prefix);
+ }
+ else if(recvd == -1)
+ {
+ if( (errno == EAGAIN) || (errno == EWOULDBLOCK) )
+ {
+ // empty queue
+ break;
+ }
+
+ stream->connected = false;
+ ev = LV2_OSC_STREAM_ERRNO(ev, errno);
+ break;
+ }
+ else if(recvd == 0)
+ {
+ // orderly shutdown
break;
}
@@ -1022,6 +1299,11 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
}
}
+ if(stream->connected)
+ {
+ ev |= LV2_OSC_CONN;
+ }
+
return ev;
}
@@ -1040,6 +1322,10 @@ lv2_osc_stream_run(LV2_OSC_Stream *stream)
{
ev |= _lv2_osc_stream_run_tcp(stream);
} break;
+ default:
+ {
+ ev |= _lv2_osc_stream_run_ser(stream);
+ } break;
}
return ev;
diff --git a/osc.lv2/test/osc_test.c b/osc.lv2/test/osc_test.c
index e9566d59..a5352777 100644
--- a/osc.lv2/test/osc_test.c
+++ b/osc.lv2/test/osc_test.c
@@ -627,6 +627,11 @@ _thread_1(void *data)
const time_t t1 = time(NULL);
const LV2_OSC_Enum ev = lv2_osc_stream_run(&stream);
+ if(ev & LV2_OSC_ERR)
+ {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR));
+ }
+
if(ev & LV2_OSC_RECV)
{
const uint8_t *buf_rx;
@@ -684,7 +689,12 @@ _thread_1(void *data)
do
{
ev = lv2_osc_stream_run(&stream);
- } while( (ev & LV2_OSC_SEND) || stream.connected );
+
+ if(ev & LV2_OSC_ERR)
+ {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR));
+ }
+ } while( (ev & LV2_OSC_SEND) || (ev & LV2_OSC_CONN) );
assert(pair->lossy || (count == COUNT) );
@@ -749,6 +759,11 @@ _thread_2(void *data)
const LV2_OSC_Enum ev = lv2_osc_stream_run(&stream);
+ if(ev & LV2_OSC_ERR)
+ {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR));
+ }
+
if(ev & LV2_OSC_RECV)
{
const uint8_t *buf_rx;
@@ -783,6 +798,11 @@ _thread_2(void *data)
const time_t t1 = time(NULL);
const LV2_OSC_Enum ev = lv2_osc_stream_run(&stream);
+ if(ev & LV2_OSC_ERR)
+ {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR));
+ }
+
if(ev & LV2_OSC_RECV)
{
const uint8_t *buf_rx;
@@ -895,6 +915,14 @@ static const pair_t pairs [] = {
.lossy = false
},
+#if 0
+ {
+ .server = "osc.serial:///dev/pts/4", //FIXME baudrate
+ .client = "osc.serial:///dev/pts/5",
+ .lossy = false
+ },
+#endif
+
{
.server = NULL,
.client = NULL,