aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--backends/Makefile14
-rw-r--r--backends/artnet.c131
-rw-r--r--backends/libmmbackend.c117
-rw-r--r--backends/libmmbackend.h31
-rw-r--r--backends/osc.c123
-rw-r--r--backends/sacn.c131
6 files changed, 206 insertions, 341 deletions
diff --git a/backends/Makefile b/backends/Makefile
index aef39c4..a7ea35a 100644
--- a/backends/Makefile
+++ b/backends/Makefile
@@ -2,6 +2,7 @@
OPTIONAL_BACKENDS = ola.so
LINUX_BACKENDS = midi.so evdev.so
BACKENDS = artnet.so osc.so loopback.so sacn.so
+BACKEND_LIB = libmmbackend.o
SYSTEM := $(shell uname -s)
@@ -18,6 +19,9 @@ ifeq ($(SYSTEM),Darwin)
LDFLAGS += -undefined dynamic_lookup
endif
+artnet.so: ADDITIONAL_OBJS += $(BACKEND_LIB)
+osc.so: ADDITIONAL_OBJS += $(BACKEND_LIB)
+sacn.so: ADDITIONAL_OBJS += $(BACKEND_LIB)
midi.so: LDLIBS = -lasound
evdev.so: CFLAGS += $(shell pkg-config --cflags libevdev)
evdev.so: LDLIBS = $(shell pkg-config --libs libevdev)
@@ -25,14 +29,14 @@ ola.so: LDLIBS = -lola
ola.so: CPPFLAGS += -Wno-write-strings
%.so :: %.c %.h
- $(CC) $(CFLAGS) $(LDLIBS) $< -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS)
%.so :: %.cpp %.h
- $(CXX) $(CPPFLAGS) $(LDLIBS) $< -o $@ $(LDFLAGS)
+ $(CXX) $(CPPFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS)
-all: $(BACKENDS)
+all: $(BACKEND_LIB) $(BACKENDS)
-full: $(BACKENDS) $(OPTIONAL_BACKENDS)
+full: $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS)
clean:
- $(RM) $(BACKENDS) $(OPTIONAL_BACKENDS)
+ $(RM) $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS)
diff --git a/backends/artnet.c b/backends/artnet.c
index d9ebfe5..8b404a6 100644
--- a/backends/artnet.c
+++ b/backends/artnet.c
@@ -1,12 +1,9 @@
#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
+#include "libmmbackend.h"
+
#include "artnet.h"
#define MAX_FDS 255
#define BACKEND_NAME "artnet"
@@ -16,68 +13,14 @@ static size_t artnet_fds = 0;
static artnet_descriptor* artnet_fd = NULL;
static int artnet_listener(char* host, char* port){
- int fd = -1, status, yes = 1, flags;
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM,
- .ai_flags = AI_PASSIVE
- };
- struct addrinfo* info;
- struct addrinfo* addr_it;
-
+ int fd;
if(artnet_fds >= MAX_FDS){
fprintf(stderr, "ArtNet backend descriptor limit reached\n");
return -1;
}
- status = getaddrinfo(host, port, &hints, &info);
- if(status){
- fprintf(stderr, "Failed to get socket info for %s port %s: %s\n", host, port, gai_strerror(status));
- return -1;
- }
-
- for(addr_it = info; addr_it != NULL; addr_it = addr_it->ai_next){
- fd = socket(addr_it->ai_family, addr_it->ai_socktype, addr_it->ai_protocol);
- if(fd < 0){
- continue;
- }
-
- yes = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to set SO_REUSEADDR on socket\n");
- }
-
- yes = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to set SO_BROADCAST on socket\n");
- }
-
- yes = 0;
- if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to unset IP_MULTICAST_LOOP option: %s\n", strerror(errno));
- }
-
- status = bind(fd, addr_it->ai_addr, addr_it->ai_addrlen);
- if(status < 0){
- close(fd);
- continue;
- }
-
- break;
- }
-
- freeaddrinfo(info);
-
- if(!addr_it){
- fprintf(stderr, "Failed to create listening socket for %s port %s\n", host, port);
- return -1;
- }
-
- //set nonblocking
- flags = fcntl(fd, F_GETFL, 0);
- if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){
- fprintf(stderr, "Failed to set ArtNet descriptor nonblocking\n");
- close(fd);
+ fd = mmbackend_socket(host, port, SOCK_DGRAM, 1);
+ if(fd < 0){
return -1;
}
@@ -98,50 +41,6 @@ static int artnet_listener(char* host, char* port){
return 0;
}
-static int artnet_parse_addr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len){
- struct addrinfo* head;
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM
- };
-
- int error = getaddrinfo(host, port, &hints, &head);
- if(error || !head){
- fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(error));
- return 1;
- }
-
- memcpy(addr, head->ai_addr, head->ai_addrlen);
- *len = head->ai_addrlen;
-
- freeaddrinfo(head);
- return 0;
-}
-
-static int artnet_separate_hostspec(char* in, char** host, char** port){
- size_t u;
-
- if(!in || !host || !port){
- return 1;
- }
-
- for(u = 0; in[u] && !isspace(in[u]); u++){
- }
-
- //guess
- *host = in;
-
- if(in[u]){
- in[u] = 0;
- *port = in + u + 1;
- }
- else{
- //no port given
- *port = ARTNET_PORT;
- }
- return 0;
-}
-
int init(){
backend artnet = {
.name = BACKEND_NAME,
@@ -171,8 +70,14 @@ static int artnet_configure(char* option, char* value){
return 0;
}
else if(!strcmp(option, "bind")){
- if(artnet_separate_hostspec(value, &host, &port)){
- fprintf(stderr, "Not a valid ArtNet bind address: %s\n", value);
+ mmbackend_parse_hostspec(value, &host, &port);
+
+ if(!port){
+ port = ARTNET_PORT;
+ }
+
+ if(!host){
+ fprintf(stderr, "Not valid ArtNet bind address given\n");
return 1;
}
@@ -228,12 +133,18 @@ static int artnet_configure_instance(instance* inst, char* option, char* value){
return 0;
}
else if(!strcmp(option, "dest") || !strcmp(option, "destination")){
- if(artnet_separate_hostspec(value, &host, &port)){
+ mmbackend_parse_hostspec(value, &host, &port);
+
+ if(!port){
+ port = ARTNET_PORT;
+ }
+
+ if(!host){
fprintf(stderr, "Not a valid ArtNet destination for instance %s\n", inst->name);
return 1;
}
- return artnet_parse_addr(host, port, &data->dest_addr, &data->dest_len);
+ return mmbackend_parse_sockaddr(host, port, &data->dest_addr, &data->dest_len);
}
fprintf(stderr, "Unknown ArtNet option %s for instance %s\n", option, inst->name);
diff --git a/backends/libmmbackend.c b/backends/libmmbackend.c
new file mode 100644
index 0000000..6320611
--- /dev/null
+++ b/backends/libmmbackend.c
@@ -0,0 +1,117 @@
+#include "libmmbackend.h"
+
+void mmbackend_parse_hostspec(char* spec, char** host, char** port){
+ size_t u = 0;
+
+ if(!spec || !host || !port){
+ return;
+ }
+
+ *port = NULL;
+
+ //skip leading spaces
+ for(; spec[u] && isspace(spec[u]); u++){
+ }
+
+ if(!spec[u]){
+ *host = NULL;
+ return;
+ }
+
+ *host = spec + u;
+
+ //scan until string end or space
+ for(; spec[u] && !isspace(spec[u]); u++){
+ }
+
+ //if space, the rest should be the port
+ if(spec[u]){
+ spec[u] = 0;
+ *port = spec + u + 1;
+ }
+}
+
+int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len){
+ struct addrinfo* head;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC
+ };
+
+ int error = getaddrinfo(host, port, &hints, &head);
+ if(error || !head){
+ fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(error));
+ return 1;
+ }
+
+ memcpy(addr, head->ai_addr, head->ai_addrlen);
+ if(len){
+ *len = head->ai_addrlen;
+ }
+
+ freeaddrinfo(head);
+ return 0;
+}
+
+int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener){
+ int fd = -1, status, yes = 1, flags;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = socktype,
+ .ai_flags = (listener ? AI_PASSIVE : 0)
+ };
+ struct addrinfo *info, *addr_it;
+
+ status = getaddrinfo(host, port, &hints, &info);
+ if(status){
+ fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(status));
+ return -1;
+ }
+
+ //traverse the result list
+ for(addr_it = info; addr_it; addr_it = addr_it->ai_next){
+ fd = socket(addr_it->ai_family, addr_it->ai_socktype, addr_it->ai_protocol);
+ if(fd < 0){
+ continue;
+ }
+
+ //set required socket options
+ yes = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){
+ fprintf(stderr, "Failed to enable SO_REUSEADDR on socket\n");
+ }
+
+ yes = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&yes, sizeof(yes)) < 0){
+ fprintf(stderr, "Failed to enable SO_BROADCAST on socket\n");
+ }
+
+ yes = 0;
+ if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){
+ fprintf(stderr, "Failed to disable IP_MULTICAST_LOOP on socket: %s\n", strerror(errno));
+ }
+
+ status = bind(fd, addr_it->ai_addr, addr_it->ai_addrlen);
+ if(status < 0){
+ close(fd);
+ continue;
+ }
+
+ break;
+ }
+ freeaddrinfo(info);
+
+ if(!addr_it){
+ fprintf(stderr, "Failed to create socket for %s port %s\n", host, port);
+ return -1;
+ }
+
+ //set nonblocking
+ flags = fcntl(fd, F_GETFL, 0);
+ if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){
+ fprintf(stderr, "Failed to set socket nonblocking\n");
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
diff --git a/backends/libmmbackend.h b/backends/libmmbackend.h
new file mode 100644
index 0000000..38bfca0
--- /dev/null
+++ b/backends/libmmbackend.h
@@ -0,0 +1,31 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Parse spec as host specification in the form
+ * host port
+ * into its constituent parts.
+ * Returns offsets into the original string and modifies it.
+ * Returns NULL in *port if none given.
+ * Returns NULL in both *port and *host if spec was an empty string.
+ */
+void mmbackend_parse_hostspec(char* spec, char** host, char** port);
+
+/* Parse a given host / port combination into a sockaddr_storage
+ * suitable for usage with connect / sendto
+ * Returns 0 on success
+ */
+int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len);
+
+/* Create a socket of given type and mode for a bind / connect host.
+ * Returns -1 on failure, a valid file descriptor for the socket on success.
+ */
+int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener);
diff --git a/backends/osc.c b/backends/osc.c
index 5f94ec2..9996f68 100644
--- a/backends/osc.c
+++ b/backends/osc.c
@@ -1,9 +1,8 @@
#include <string.h>
-#include <unistd.h>
#include <ctype.h>
-#include <netdb.h>
#include <errno.h>
-#include <fcntl.h>
+#include "libmmbackend.h"
+
#include "osc.h"
/*
@@ -254,114 +253,6 @@ static int osc_validate_path(char* path){
return 0;
}
-static int osc_separate_hostspec(char* in, char** host, char** port){
- size_t u;
-
- if(!in || !host || !port){
- return 1;
- }
-
- for(u = 0; in[u] && !isspace(in[u]); u++){
- }
-
- //guess
- *host = in;
-
- if(in[u]){
- in[u] = 0;
- *port = in + u + 1;
- }
- else{
- //no port given
- *port = NULL;
- }
- return 0;
-}
-
-static int osc_listener(char* host, char* port){
- int fd = -1, status, yes = 1, flags;
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM,
- .ai_flags = AI_PASSIVE
- };
- struct addrinfo* info;
- struct addrinfo* addr_it;
-
- status = getaddrinfo(host, port, &hints, &info);
- if(status){
- fprintf(stderr, "Failed to get socket info for %s port %s: %s\n", host, port, gai_strerror(status));
- return -1;
- }
-
- for(addr_it = info; addr_it != NULL; addr_it = addr_it->ai_next){
- fd = socket(addr_it->ai_family, addr_it->ai_socktype, addr_it->ai_protocol);
- if(fd < 0){
- continue;
- }
-
- yes = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to set SO_REUSEADDR on socket\n");
- }
-
- yes = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to set SO_BROADCAST on socket\n");
- }
-
- yes = 0;
- if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to unset IP_MULTICAST_LOOP option: %s\n", strerror(errno));
- }
-
- status = bind(fd, addr_it->ai_addr, addr_it->ai_addrlen);
- if(status < 0){
- close(fd);
- continue;
- }
-
- break;
- }
-
- freeaddrinfo(info);
-
- if(!addr_it){
- fprintf(stderr, "Failed to create listening socket for %s port %s\n", host, port);
- return -1;
- }
-
- //set nonblocking
- flags = fcntl(fd, F_GETFL, 0);
- if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){
- close(fd);
- fprintf(stderr, "Failed to set OSC descriptor nonblocking\n");
- return -1;
- }
-
- return fd;
-}
-
-static int osc_parse_addr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len){
- struct addrinfo* head;
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM
- };
-
- int error = getaddrinfo(host, port, &hints, &head);
- if(error || !head){
- fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(error));
- return 1;
- }
-
- memcpy(addr, head->ai_addr, head->ai_addrlen);
- *len = head->ai_addrlen;
-
- freeaddrinfo(head);
- return 0;
-}
-
static int backend_configure(char* option, char* value){
fprintf(stderr, "The OSC backend does not take any global configuration\n");
return 1;
@@ -390,12 +281,13 @@ static int backend_configure_instance(instance* inst, char* option, char* value)
return 0;
}
else if(!strcmp(option, "bind")){
- if(osc_separate_hostspec(value, &host, &port)){
+ mmbackend_parse_hostspec(value, &host, &port);
+ if(!host || !port){
fprintf(stderr, "Invalid bind address for instance %s\n", inst->name);
return 1;
}
- data->fd = osc_listener(host, port);
+ data->fd = mmbackend_socket(host, port, SOCK_DGRAM, 1);
if(data->fd < 0){
fprintf(stderr, "Failed to bind for instance %s\n", inst->name);
return 1;
@@ -413,12 +305,13 @@ static int backend_configure_instance(instance* inst, char* option, char* value)
return 0;
}
- if(osc_separate_hostspec(value, &host, &port)){
+ mmbackend_parse_hostspec(value, &host, &port);
+ if(!host || !port){
fprintf(stderr, "Invalid destination address for instance %s\n", inst->name);
return 1;
}
- if(osc_parse_addr(host, port, &data->dest, &data->dest_len)){
+ if(mmbackend_parse_sockaddr(host, port, &data->dest, &data->dest_len)){
fprintf(stderr, "Failed to parse destination address for instance %s\n", inst->name);
return 1;
}
diff --git a/backends/sacn.c b/backends/sacn.c
index fde8d90..75bb76f 100644
--- a/backends/sacn.c
+++ b/backends/sacn.c
@@ -8,6 +8,8 @@
#include <ctype.h>
#include <netinet/in.h>
+#include "libmmbackend.h"
+
#include "sacn.h"
//upper limit imposed by using the fd index as 16-bit part of the instance id
#define MAX_FDS 4096
@@ -50,68 +52,14 @@ int init(){
}
static int sacn_listener(char* host, char* port, uint8_t fd_flags){
- int fd = -1, status, yes = 1, flags;
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM,
- .ai_flags = AI_PASSIVE
- };
- struct addrinfo* info;
- struct addrinfo* addr_it;
-
+ int fd = -1;
if(global_cfg.fds >= MAX_FDS){
fprintf(stderr, "sACN backend descriptor limit reached\n");
return -1;
}
- status = getaddrinfo(host, port, &hints, &info);
- if(status){
- fprintf(stderr, "Failed to get socket info for %s port %s: %s\n", host, port, gai_strerror(status));
- return -1;
- }
-
- for(addr_it = info; addr_it != NULL; addr_it = addr_it->ai_next){
- fd = socket(addr_it->ai_family, addr_it->ai_socktype, addr_it->ai_protocol);
- if(fd < 0){
- continue;
- }
-
- yes = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to set SO_REUSEADDR on socket\n");
- }
-
- yes = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to set SO_BROADCAST on socket\n");
- }
-
- yes = 0;
- if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){
- fprintf(stderr, "Failed to unset IP_MULTICAST_LOOP option: %s\n", strerror(errno));
- }
-
- status = bind(fd, addr_it->ai_addr, addr_it->ai_addrlen);
- if(status < 0){
- close(fd);
- continue;
- }
-
- break;
- }
-
- freeaddrinfo(info);
-
- if(!addr_it){
- fprintf(stderr, "Failed to create listening socket for %s port %s\n", host, port);
- return -1;
- }
-
- //set nonblocking
- flags = fcntl(fd, F_GETFL, 0);
- if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){
- fprintf(stderr, "Failed to set sACN descriptor nonblocking\n");
- close(fd);
+ fd = mmbackend_socket(host, port, SOCK_DGRAM, 1);
+ if(fd < 0){
return -1;
}
@@ -133,55 +81,6 @@ static int sacn_listener(char* host, char* port, uint8_t fd_flags){
return 0;
}
-static int sacn_parse_addr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len){
- struct addrinfo* head;
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM
- };
-
- int error = getaddrinfo(host, port, &hints, &head);
- if(error || !head){
- fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(error));
- return 1;
- }
-
- memcpy(addr, head->ai_addr, head->ai_addrlen);
- *len = head->ai_addrlen;
-
- freeaddrinfo(head);
- return 0;
-}
-
-static int sacn_parse_hostspec(char* in, char** host, char** port, uint8_t* flags){
- size_t u;
-
- if(!in || !host || !port){
- return 1;
- }
-
- for(u = 0; in[u] && !isspace(in[u]); u++){
- }
-
- //guess
- *host = in;
-
- if(in[u]){
- in[u] = 0;
- *port = in + u + 1;
- }
- else{
- //no port given
- *port = SACN_PORT;
- }
-
- if(flags){
- //TODO parse hostspec trailing data for options
- *flags = 0;
- }
- return 0;
-}
-
static int sacn_configure(char* option, char* value){
char* host = NULL, *port = NULL, *next = NULL;
uint8_t flags = 0;
@@ -204,8 +103,13 @@ static int sacn_configure(char* option, char* value){
}
}
else if(!strcmp(option, "bind")){
- if(sacn_parse_hostspec(value, &host, &port, &flags)){
- fprintf(stderr, "Not a valid sACN bind address: %s\n", value);
+ mmbackend_parse_hostspec(value, &host, &port);
+ if(!port){
+ port = SACN_PORT;
+ }
+
+ if(!host){
+ fprintf(stderr, "No valid sACN bind address provided\n");
return 1;
}
@@ -243,12 +147,17 @@ static int sacn_configure_instance(instance* inst, char* option, char* value){
return 0;
}
else if(!strcmp(option, "destination")){
- if(sacn_parse_hostspec(value, &host, &port, NULL)){
- fprintf(stderr, "Not a valid sACN destination for instance %s: %s\n", inst->name, value);
+ mmbackend_parse_hostspec(value, &host, &port);
+ if(!port){
+ port = SACN_PORT;
+ }
+
+ if(!host){
+ fprintf(stderr, "No valid sACN destination for instance %s\n", inst->name);
return 1;
}
- return sacn_parse_addr(host, port, &data->dest_addr, &data->dest_len);
+ return mmbackend_parse_sockaddr(host, port, &data->dest_addr, &data->dest_len);
}
else if(!strcmp(option, "from")){
next = value;