aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--backends/rtpmidi.c105
-rw-r--r--backends/rtpmidi.h7
2 files changed, 58 insertions, 54 deletions
diff --git a/backends/rtpmidi.c b/backends/rtpmidi.c
index b7d938b..85665fd 100644
--- a/backends/rtpmidi.c
+++ b/backends/rtpmidi.c
@@ -238,7 +238,7 @@ bail:
//TODO this should be trimmed down a bit
static int rtpmidi_announce_addrs(){
- char repr[INET6_ADDRSTRLEN + 1] = "", iface[1024] = "";
+ char repr[INET6_ADDRSTRLEN + 1] = "", iface[2048] = "";
union {
struct sockaddr_in* in4;
struct sockaddr_in6* in6;
@@ -247,13 +247,16 @@ static int rtpmidi_announce_addrs(){
#ifdef _WIN32
IP_ADAPTER_UNICAST_ADDRESS_LH* unicast_addr = NULL;
- IP_ADAPTER_ADDRESSES addrs[50] , *iter = NULL;
+ IP_ADAPTER_ADDRESSES addrs[250] , *iter = NULL;
size_t bytes_alloc = sizeof(addrs);
- if(GetAdaptersAddresses(0, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
- NULL, addrs, (unsigned long*) &bytes_alloc) != ERROR_SUCCESS){
+ unsigned long status = GetAdaptersAddresses(0, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
+ NULL, addrs, (unsigned long*) &bytes_alloc);
+ if(status != ERROR_SUCCESS){
//FIXME might try to resize the result list and retry at some point...
- LOG("Failed to query local interface addresses");
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), iface, sizeof(iface), NULL);
+ LOGPF("Failed to query local interface addresses (%lu): %s", status, iface);
return 1;
}
@@ -401,11 +404,12 @@ static char* rtpmidi_type_name(uint8_t type){
return "unknown";
}
-static int rtpmidi_push_peer(rtpmidi_instance_data* data, struct sockaddr_storage sock_addr, socklen_t sock_len, uint8_t learned, uint8_t connected){
+static int rtpmidi_push_peer(rtpmidi_instance_data* data, struct sockaddr_storage sock_addr, socklen_t sock_len, uint8_t learned, uint8_t connected, ssize_t invite_reference){
size_t u, p = data->peers;
for(u = 0; u < data->peers; u++){
//check whether the peer is already in the list
+ //TODO this probably should take into account the invite_reference (-1 for initiator peers or if unknown but may be present)
if(data->peer[u].active
&& sock_len == data->peer[u].dest_len
&& !memcmp(&data->peer[u].dest, &sock_addr, sock_len)){
@@ -433,6 +437,7 @@ static int rtpmidi_push_peer(rtpmidi_instance_data* data, struct sockaddr_storag
data->peer[p].active = 1;
data->peer[p].learned = learned;
data->peer[p].connected = connected;
+ data->peer[p].invite = invite_reference;
data->peer[p].dest = sock_addr;
data->peer[p].dest_len = sock_len;
return 0;
@@ -490,6 +495,37 @@ static int rtpmidi_push_invite(instance* inst, char* peer){
return 0;
}
+static ssize_t rtpmidi_applecommand(instance* inst, struct sockaddr* dest, socklen_t dest_len, uint8_t control, applemidi_command command){
+ rtpmidi_instance_data* data = (rtpmidi_instance_data*) inst->impl;
+ uint8_t frame[RTPMIDI_PACKET_BUFFER] = "";
+
+ apple_command* cmd = (apple_command*) &frame;
+ cmd->res1 = 0xFFFF;
+ cmd->command = htobe16(command);
+ cmd->version = htobe32(2);
+ cmd->token = ((uint32_t) rand()) << 16 | rand();
+ cmd->ssrc = htobe32(data->ssrc);
+
+ //append session name to packet
+ memcpy(frame + sizeof(apple_command), data->title ? data->title : RTPMIDI_DEFAULT_NAME, strlen((data->title ? data->title : RTPMIDI_DEFAULT_NAME)) + 1);
+
+ //FIXME should we match sending/receiving ports? if the reference does this, it should be documented
+ return sendto(control ? data->control_fd : data->fd, frame, sizeof(apple_command) + strlen((data->title ? data->title : RTPMIDI_DEFAULT_NAME)) + 1, 0, dest, dest_len);
+}
+
+static ssize_t rtpmidi_peer_applecommand(instance* inst, size_t peer, uint8_t control, applemidi_command command){
+ rtpmidi_instance_data* data = (rtpmidi_instance_data*) inst->impl;
+ struct sockaddr_storage dest_addr;
+
+ memcpy(&dest_addr, &(data->peer[peer].dest), min(sizeof(dest_addr), data->peer[peer].dest_len));
+ if(control){
+ //calculate remote control port from data port
+ ((struct sockaddr_in*) &dest_addr)->sin_port = be16toh(htobe16(((struct sockaddr_in*) &dest_addr)->sin_port) - 1);
+ }
+
+ return rtpmidi_applecommand(inst, (struct sockaddr*) &dest_addr, data->peer[peer].dest_len, control, command);
+}
+
static int rtpmidi_configure_instance(instance* inst, char* option, char* value){
rtpmidi_instance_data* data = (rtpmidi_instance_data*) inst->impl;
char* host = NULL, *port = NULL;
@@ -563,7 +599,7 @@ static int rtpmidi_configure_instance(instance* inst, char* option, char* value)
((struct sockaddr_in*) &sock_addr)->sin_port = be16toh(htobe16(((struct sockaddr_in*) &sock_addr)->sin_port) + 1);
}
- return rtpmidi_push_peer(data, sock_addr, sock_len, 0, 0);
+ return rtpmidi_push_peer(data, sock_addr, sock_len, 0, 0, -1);
}
else if(!strcmp(option, "title")){
if(data->mode != apple){
@@ -773,56 +809,36 @@ static int rtpmidi_handle_applemidi(instance* inst, int fd, uint8_t* frame, size
//accept the invitation
LOGPF("Instance %s accepting invitation to session %s%s", inst->name, session_name ? session_name : "UNNAMED", (fd == data->control_fd) ? " (control)":"");
//send accept message
- apple_command* accept = (apple_command*) response;
- accept->res1 = 0xFFFF;
- accept->command = htobe16(apple_accept);
- accept->version = htobe32(2);
- accept->token = command->token;
- accept->ssrc = htobe32(data->ssrc);
- //add local name to response
- //FIXME use instance title instead of mdns_name
- memcpy(response + sizeof(apple_command), cfg.mdns_name ? cfg.mdns_name : RTPMIDI_DEFAULT_NAME, strlen((cfg.mdns_name ? cfg.mdns_name : RTPMIDI_DEFAULT_NAME)) + 1);
- sendto(fd, response, sizeof(apple_command) + strlen(cfg.mdns_name ? cfg.mdns_name : RTPMIDI_DEFAULT_NAME) + 1, 0, (struct sockaddr*) peer, peer_len);
+ //TODO accept->token = command->token;
+ rtpmidi_applecommand(inst, (struct sockaddr*) peer, peer_len, (fd == data->control_fd) ? 1 : 0, apple_accept);
//push peer
if(fd != data->control_fd){
- return rtpmidi_push_peer(data, *peer, peer_len, 1, 1);
+ return rtpmidi_push_peer(data, *peer, peer_len, 1, 1, -1);
}
return 0;
}
else{
//send reject message
LOGPF("Instance %s rejecting invitation to session %s", inst->name, session_name ? session_name : "UNNAMED");
- apple_command reject = {
- .res1 = 0xFFFF,
- .command = htobe16(apple_reject),
- .version = htobe32(2),
- .token = command->token,
- .ssrc = htobe32(data->ssrc)
- };
- sendto(fd, (uint8_t*) &reject, sizeof(apple_command), 0, (struct sockaddr*) peer, peer_len);
+ //TODO .token = command->token,
+ rtpmidi_applecommand(inst, (struct sockaddr*) peer, peer_len, (fd == data->control_fd) ? 1 : 0, apple_reject);
}
return 0;
}
else if(command->command == apple_accept){
if(fd != data->control_fd){
LOGPF("Instance %s negotiated new peer", inst->name);
- return rtpmidi_push_peer(data, *peer, peer_len, 1, 1);
+ return rtpmidi_push_peer(data, *peer, peer_len, 1, 1, -1);
//FIXME store ssrc, start timesync
}
else{
- //send invite on data fd
+ //invite peer data port
LOGPF("Instance %s peer accepted on control port, inviting data port", inst->name);
- apple_command* invite = (apple_command*) response;
- invite->res1 = 0xFFFF;
- invite->command = htobe16(apple_invite);
- invite->version = htobe32(2);
- invite->token = command->token;
- invite->ssrc = htobe32(data->ssrc);
- memcpy(response + sizeof(apple_command), data->title ? data->title : RTPMIDI_DEFAULT_NAME, strlen((data->title ? data->title : RTPMIDI_DEFAULT_NAME)) + 1);
//calculate data port
((struct sockaddr_in*) peer)->sin_port = be16toh(htobe16(((struct sockaddr_in*) peer)->sin_port) + 1);
- sendto(data->fd, response, sizeof(apple_command) + strlen(data->title ? data->title : RTPMIDI_DEFAULT_NAME) + 1, 0, (struct sockaddr*) peer, peer_len);
+ //send invite
+ rtpmidi_applecommand(inst, (struct sockaddr*) peer, peer_len, 0, apple_invite);
}
return 0;
}
@@ -1064,7 +1080,7 @@ static int rtpmidi_handle_data(instance* inst){
if(u == data->peers){
LOGPF("Learned new peer on %s", inst->name);
- return rtpmidi_push_peer(data, sock_addr, sock_len, 1, 1);
+ return rtpmidi_push_peer(data, sock_addr, sock_len, 1, 1, -1);
}
}
return 0;
@@ -1281,7 +1297,6 @@ static int rtpmidi_service(){
size_t n, u, p;
instance** inst = NULL;
rtpmidi_instance_data* data = NULL;
- uint8_t frame[RTPMIDI_PACKET_BUFFER] = "";
struct sockaddr_storage control_peer;
//prepare commands
@@ -1294,11 +1309,6 @@ static int rtpmidi_service(){
mm_timestamp() * 10
}
};
- apple_command* invite = (apple_command*) &frame;
- invite->res1 = 0xFFFF;
- invite->command = htobe16(apple_invite);
- invite->version = htobe32(2);
- invite->token = ((uint32_t) rand()) << 16 | rand();
if(mm_backend_instances(BACKEND_NAME, &n, &inst)){
LOG("Failed to fetch instances");
@@ -1329,14 +1339,7 @@ static int rtpmidi_service(){
else if(data->peer[p].active && !data->peer[p].learned && (mm_timestamp() / 1000) % 10 == 0){
//try to invite pre-defined unconnected applemidi peers
DBGPF("Instance %s inviting configured peer %" PRIsize_t, inst[u]->name, p);
- invite->ssrc = htobe32(data->ssrc);
- //calculate remote control port from data port
- memcpy(&control_peer, &(data->peer[u].dest), sizeof(control_peer));
- ((struct sockaddr_in*) &control_peer)->sin_port = be16toh(htobe16(((struct sockaddr_in*) &control_peer)->sin_port) - 1);
- //append session name to packet
- memcpy(frame + sizeof(apple_command), data->title ? data->title : RTPMIDI_DEFAULT_NAME, strlen((data->title ? data->title : RTPMIDI_DEFAULT_NAME)) + 1);
-
- sendto(data->control_fd, (char*) invite, sizeof(apple_command) + strlen((data->title ? data->title : RTPMIDI_DEFAULT_NAME)) + 1, 0, (struct sockaddr*) &control_peer, data->peer[u].dest_len);
+ rtpmidi_peer_applecommand(inst[u], p, 1, apple_invite);
}
}
}
diff --git a/backends/rtpmidi.h b/backends/rtpmidi.h
index de610cd..a5d4f4c 100644
--- a/backends/rtpmidi.h
+++ b/backends/rtpmidi.h
@@ -61,8 +61,9 @@ typedef struct /*_rtpmidi_peer*/ {
socklen_t dest_len;
//uint32_t ssrc;
uint8_t active; //marked for reuse
- uint8_t learned; //learned / configured peer
+ uint8_t learned; //learned / configured peer (learned peers are marked inactive on session shutdown)
uint8_t connected; //currently in active session
+ ssize_t invite; //invite-list index for apple-mode learned peers
} rtpmidi_peer;
typedef struct /*_rtmidi_instance_data*/ {
@@ -98,14 +99,14 @@ typedef struct /*_rtpmidi_addr*/ {
uint8_t addr[sizeof(struct sockaddr_storage)];
} rtpmidi_addr;
-enum applemidi_command {
+typedef enum {
apple_invite = 0x494E, //IN
apple_accept = 0x4F4B, //OK
apple_reject = 0x4E4F, //NO
apple_leave = 0x4259, //BY
apple_sync = 0x434B, //CK
apple_feedback = 0x5253 //RS
-};
+} applemidi_command;
typedef struct /*_dns_name*/ {
size_t alloc;