aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--meson.build2
-rw-r--r--osc.lv2/stream.h806
-rw-r--r--test/osc_test.c8
4 files changed, 551 insertions, 267 deletions
diff --git a/VERSION b/VERSION
index c0c68ba..ef2f8c8 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.85
+0.1.87
diff --git a/meson.build b/meson.build
index ba60db1..d11a3be 100644
--- a/meson.build
+++ b/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/stream.h b/osc.lv2/stream.h
index 85c1187..3f53d43 100644
--- a/osc.lv2/stream.h
+++ b/osc.lv2/stream.h
@@ -26,6 +26,7 @@
# include <net/if.h>
# include <netinet/tcp.h>
# include <netdb.h>
+# include <termios.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
@@ -88,6 +89,7 @@ struct _LV2_OSC_Stream {
int protocol;
bool server;
bool slip;
+ bool serial;
bool connected;
int sock;
int fd;
@@ -110,8 +112,47 @@ 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_set_interface_attribs(int fd, int speed)
+{
+ struct termios tty;
+
+ if(tcgetattr(fd, &tty) < 0)
+ {
+ return errno;
+ }
+
+ 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 errno;
+ }
+
+ return 0;
+}
+
static int
lv2_osc_stream_init(LV2_OSC_Stream *stream, const char *url,
const LV2_OSC_Driver *driv, void *data)
@@ -160,6 +201,12 @@ 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__);
@@ -168,364 +215,390 @@ lv2_osc_stream_init(LV2_OSC_Stream *stream, const char *url,
if(ptr[0] == '\0')
{
- fprintf(stderr, "%s: URI has no colon\n", __func__);
+ fprintf(stderr, "%s: URI is incomplete\n", __func__);
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__);
+ fprintf(stderr, "%s: open failed\n", __func__);
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__);
+ fprintf(stderr, "%s: fcntl failed\n", __func__);
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(strlen(node) == 0)
- {
- node = NULL;
- stream->server = true;
- }
-
- stream->sock = socket(stream->socket_family, stream->socket_type,
- stream->protocol);
+ if(_lv2_set_interface_attribs(stream->sock, B115200) < 0)
+ {
+ fprintf(stderr, "%s: setting attributes failed\n", __func__);
+ goto fail;
+ }
- if(stream->sock < 0)
- {
- fprintf(stderr, "%s: socket failed\n", __func__);
- goto fail;
+ stream->connected = true;
}
-
- if(fcntl(stream->sock, F_SETFL, O_NONBLOCK) == -1)
+ else // !stream->serial
{
- 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__);
+ fprintf(stderr, "%s: no IPv6 interface delimiter expected here\n", __func__);
goto fail;
}
- if(res->ai_addrlen != sizeof(stream->peer.in4))
- {
- fprintf(stderr, "%s: IPv4 address expected\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);
- 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__);
+ fprintf(stderr, "%s: no closing IPv6 bracket expected here\n", __func__);
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);
+ fprintf(stderr, "%s: pre-service colon expected\n", __func__);
+ 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)
+ {
+ fprintf(stderr, "%s: socket failed\n", __func__);
+ goto fail;
}
- if(stream->socket_type == SOCK_DGRAM)
+ if(fcntl(stream->sock, F_SETFL, O_NONBLOCK) == -1)
{
- const int broadcast = 1;
+ fprintf(stderr, "%s: fcntl failed\n", __func__);
+ 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)
+ {
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ 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;
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ 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)
+ {
+ 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__);
+ 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__);
+ fprintf(stderr, "%s: bind failed\n", __func__);
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)
{
- stream->connected = true;
+ fprintf(stderr, "%s: bind failed\n", __func__);
+ 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)
+ {
+ 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;
+ }
+
+ 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)
+ {
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ 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)
+ {
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ goto fail;
+ }
- freeaddrinfo(res);
+ if(setsockopt(stream->sock, SOL_SOCKET,
+ SO_KEEPALIVE, &flag, sizeof(int)) != 0)
+ {
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ goto fail;
+ }
- if(bind(stream->sock, &stream->self.in, stream->self.len) != 0)
+ if(stream->server)
+ {
+ if(listen(stream->sock, 1) != 0)
+ {
+ fprintf(stderr, "%s: listen failed\n", __func__);
+ 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__);
+ fprintf(stderr, "%s: invalid socket type\n", __func__);
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)
+ {
+ 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)
- {
- 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)
+ {
+ fprintf(stderr, "%s: bind failed\n", __func__);
+ 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)
+ {
+ fprintf(stderr, "%s: bind failed\n", __func__);
+ 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)
+ {
+ 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;
+ }
+ 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__);
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
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)
{
- stream->connected = true;
+ fprintf(stderr, "%s: setsockopt failed\n", __func__);
+ goto fail;
}
+
+ if(stream->server)
+ {
+ if(listen(stream->sock, 1) != 0)
+ {
+ fprintf(stderr, "%s: listen failed\n", __func__);
+ goto fail;
+ }
+ }
+ else // client
+ {
+ if(connect(stream->sock, &stream->peer.in, stream->peer.len) == 0)
+ {
+ stream->connected = true;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s: invalid socket type\n", __func__);
+ goto fail;
}
}
else
{
- fprintf(stderr, "%s: invalid socket type\n", __func__);
+ fprintf(stderr, "%s: invalid socket family\n", __func__);
goto fail;
}
}
- else
- {
- fprintf(stderr, "%s: invalid socket family\n", __func__);
- goto fail;
- }
free(dup);
@@ -1026,6 +1099,203 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream)
}
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;
+ }
+
+ fprintf(stderr, "%s: write: %s\n", __func__, strerror(errno));
+ break;
+ }
+ else if(sent != (ssize_t)tosend)
+ {
+ fprintf(stderr, "%s: only written %zi of %zu bytes", __func__, sent, tosend);
+ 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: read(slip): %s\n", __func__, strerror(errno));
+ break;
+ }
+ else if(recvd == 0)
+ {
+ //fprintf(stderr, "%s: read(slip): %s\n", __func__, "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;
+ fprintf(stderr, "%s: read buffer overflow\n", __func__);
+ }
+ }
+
+ 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;
+ fprintf(stderr, "%s: read(prefix): %s\n", __func__, strerror(errno));
+ break;
+ }
+ else if(recvd == 0)
+ {
+ //fprintf(stderr, "%s: read(prefix): %s\n", __func__, "orderly shutdown");
+ break;
+ }
+
+ stream->driv->write_adv(stream->data, recvd);
+ ev |= LV2_OSC_RECV;
+ }
+ }
+ }
+ }
+
+ return ev;
+}
+
+static LV2_OSC_Enum
lv2_osc_stream_run(LV2_OSC_Stream *stream)
{
LV2_OSC_Enum ev = LV2_OSC_NONE;
@@ -1040,6 +1310,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/test/osc_test.c b/test/osc_test.c
index e9566d5..0179e5d 100644
--- a/test/osc_test.c
+++ b/test/osc_test.c
@@ -895,6 +895,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,