diff options
-rw-r--r-- | backends/rtpmidi.c | 105 | ||||
-rw-r--r-- | backends/rtpmidi.h | 7 |
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; |