diff options
author | Hanspeter Portner <dev@open-music-kontrollers.ch> | 2018-09-19 22:31:39 +0200 |
---|---|---|
committer | Hanspeter Portner <dev@open-music-kontrollers.ch> | 2018-09-19 22:31:39 +0200 |
commit | 817b9886509ad36964bb6eadc4a966edaf1ad4d5 (patch) | |
tree | 1c02d54bbfa138d403b04e09074f3e6ad2ac935c /osc.lv2 | |
parent | a74cb9f22f3aee9d552aa9f0b47409ba30e3bccc (diff) | |
parent | 810007230c91881ecdccd4286c09a4d1d54449ae (diff) | |
download | moony.lv2-817b9886509ad36964bb6eadc4a966edaf1ad4d5.tar.xz |
Merge commit '810007230c91881ecdccd4286c09a4d1d54449ae'
Diffstat (limited to 'osc.lv2')
-rw-r--r-- | osc.lv2/VERSION | 2 | ||||
-rw-r--r-- | osc.lv2/meson.build | 2 | ||||
-rw-r--r-- | osc.lv2/osc.lv2/stream.h | 902 | ||||
-rw-r--r-- | osc.lv2/test/osc_test.c | 30 |
4 files changed, 631 insertions, 305 deletions
diff --git a/osc.lv2/VERSION b/osc.lv2/VERSION index c0c68ba..9c178d3 100644 --- a/osc.lv2/VERSION +++ b/osc.lv2/VERSION @@ -1 +1 @@ -0.1.85 +0.1.95 diff --git a/osc.lv2/meson.build b/osc.lv2/meson.build index ba60db1..d11a3be 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 85c1187..85d3209 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> @@ -69,7 +71,6 @@ typedef struct _LV2_OSC_Stream LV2_OSC_Stream; struct _LV2_OSC_Address { socklen_t len; union { - struct sockaddr in; struct sockaddr_in in4; struct sockaddr_in6 in6; }; @@ -88,6 +89,7 @@ struct _LV2_OSC_Stream { int protocol; bool server; bool slip; + bool serial; bool connected; int sock; int fd; @@ -101,27 +103,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 +208,416 @@ 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(strlen(node) == 0) - { - node = NULL; - stream->server = true; - } - - stream->sock = socket(stream->socket_family, stream->socket_type, - stream->protocol); - - if(stream->sock < 0) - { - fprintf(stderr, "%s: socket failed\n", __func__); - goto fail; - } + if(_lv2_osc_stream_interface_attribs(stream->sock, B115200) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } - if(fcntl(stream->sock, F_SETFL, O_NONBLOCK) == -1) - { - fprintf(stderr, "%s: fcntl failed\n", __func__); - goto fail; + stream->connected = true; } - - const int sendbuff = LV2_OSC_STREAM_SNDBUF; - const int recvbuff = LV2_OSC_STREAM_RCVBUF; - - if(setsockopt(stream->sock, SOL_SOCKET, - SO_SNDBUF, &sendbuff, sizeof(int))== -1) + else // !stream->serial { - fprintf(stderr, "%s: setsockopt failed\n", __func__); - goto fail; - } + const char *node = NULL; + const char *iface = NULL; + const char *service = NULL; - 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) - { - fprintf(stderr, "%s: getaddrinfo failed\n", __func__); - goto fail; - } - if(res->ai_addrlen != sizeof(stream->peer.in4)) + if(stream->socket_family != AF_INET6) { - 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; + memcpy(&stream->self.in4, res->ai_addr, res->ai_addrlen); + 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, (struct sockaddr *)&stream->self.in4, + 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, (struct sockaddr *)&stream->self.in4, + 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; + memcpy(&stream->peer.in4, res->ai_addr, res->ai_addrlen); + + 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, (struct sockaddr *)&stream->peer.in4, + 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; + memcpy(&stream->self.in6, res->ai_addr, res->ai_addrlen); + 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, (struct sockaddr *)&stream->self.in6, + 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, (struct sockaddr *)&stream->self.in6, + 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; + memcpy(&stream->peer.in6, res->ai_addr, res->ai_addrlen); + + 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, (struct sockaddr *)&stream->peer.in6, + 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 +631,7 @@ fail: stream->sock = -1; } - return -1; + return ev; } #define SLIP_END 0300 // 0xC0, 192, indicates end of packet @@ -662,7 +750,7 @@ _lv2_osc_stream_run_udp(LV2_OSC_Stream *stream) while( (buf = stream->driv->read_req(stream->data, &tosend)) ) { const ssize_t sent = sendto(stream->sock, buf, tosend, 0, - &stream->peer.in, stream->peer.len); + (struct sockaddr *)&stream->peer.in6, stream->peer.len); if(sent == -1) { @@ -672,12 +760,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; } @@ -694,11 +782,12 @@ _lv2_osc_stream_run_udp(LV2_OSC_Stream *stream) while( (buf = stream->driv->write_req(stream->data, LV2_OSC_STREAM_REQBUF, &max_len)) ) { - struct sockaddr in; + struct sockaddr_in6 in; socklen_t in_len = sizeof(in); + memset(&in, 0, in_len); const ssize_t recvd = recvfrom(stream->sock, buf, max_len, 0, - &in, &in_len); + (struct sockaddr *)&in, &in_len); if(recvd == -1) { @@ -708,7 +797,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) @@ -718,7 +807,7 @@ _lv2_osc_stream_run_udp(LV2_OSC_Stream *stream) } stream->peer.len = in_len; - stream->peer.in = in; + memcpy(&stream->peer.in6, &in, in_len); stream->driv->write_adv(stream->data, recvd); ev |= LV2_OSC_RECV; @@ -738,8 +827,9 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream) { if(stream->server) { - stream->peer.len = sizeof(stream->peer.in); - stream->fd = accept(stream->sock, &stream->peer.in, &stream->peer.len); + stream->peer.len = sizeof(stream->peer.in6); + stream->fd = accept(stream->sock, (struct sockaddr *)&stream->peer.in6, + &stream->peer.len); if(stream->fd >= 0) { @@ -749,45 +839,42 @@ _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) + if(connect(stream->sock, (struct sockaddr *)&stream->peer.in6, + 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 +942,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 +988,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 +1000,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 +1026,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 +1084,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 +1096,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 +1309,11 @@ _lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream) } } + if(stream->connected) + { + ev |= LV2_OSC_CONN; + } + return ev; } @@ -1040,6 +1332,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 e9566d5..a535277 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, |