From 6b00b5183ad123cf968bc8cbe016c7aaf32f82eb Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Mon, 19 Mar 2018 09:25:12 -0400 Subject: [PATCH] Buffer send/recv in Bridge, better network error handling --- include/bridgeprotocol.hpp | 2 +- src/Core/AudioInterface.cpp | 1 - src/bridge.cpp | 99 +++++++++++++++++++++++-------------- 3 files changed, 62 insertions(+), 40 deletions(-) diff --git a/include/bridgeprotocol.hpp b/include/bridgeprotocol.hpp index 894e0988..646dc39d 100644 --- a/include/bridgeprotocol.hpp +++ b/include/bridgeprotocol.hpp @@ -36,7 +36,7 @@ enum BridgeCommand { send - uint8_t msg[3] */ - MIDI_MESSAGE_SEND_COMMAND, + MIDI_MESSAGE_COMMAND, /** Sets the audio sample rate send - uint32_t sampleRate diff --git a/src/Core/AudioInterface.cpp b/src/Core/AudioInterface.cpp index 539da76f..f3d16380 100644 --- a/src/Core/AudioInterface.cpp +++ b/src/Core/AudioInterface.cpp @@ -90,7 +90,6 @@ struct AudioInterfaceIO : AudioIO { } void onChannelsChange() override { - debug("Channels changed %d %d", numOutputs, numInputs); } }; diff --git a/src/bridge.cpp b/src/bridge.cpp index 3f5420e3..74cc0f82 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -49,10 +49,14 @@ struct BridgeClientConnection { #else int flags = 0; #endif - ssize_t actual = ::send(client, (const char*) buffer, length, flags); - if (actual != length) { - ready = false; - return false; + ssize_t remaining = 0; + while (remaining < length) { + ssize_t actual = ::send(client, (const char*) buffer, length, flags); + if (actual <= 0) { + ready = false; + return false; + } + remaining += actual; } return true; } @@ -72,10 +76,14 @@ struct BridgeClientConnection { #else int flags = 0; #endif - ssize_t actual = ::recv(client, (char*) buffer, length, flags); - if (actual != length) { - ready = false; - return false; + ssize_t remaining = 0; + while (remaining < length) { + ssize_t actual = ::recv(client, (char*) buffer + remaining, length - remaining, flags); + if (actual <= 0) { + ready = false; + return false; + } + remaining += actual; } return true; } @@ -86,14 +94,12 @@ struct BridgeClientConnection { } void flush() { - int err; // Turn off Nagle int flag = 1; - err = setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int)); + setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int)); // Turn on Nagle flag = 0; - err = setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int)); - (void) err; + setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int)); } void run() { @@ -118,9 +124,8 @@ struct BridgeClientConnection { /** Accepts a command from the client */ void step() { - uint8_t command = NO_COMMAND; + uint8_t command; if (!recv(&command)) { - ready = false; return; } @@ -132,7 +137,6 @@ struct BridgeClientConnection { } break; case QUIT_COMMAND: { - debug("Bridge client quitting"); ready = false; } break; @@ -142,10 +146,9 @@ struct BridgeClientConnection { setPort(port); } break; - case MIDI_MESSAGE_SEND_COMMAND: { + case MIDI_MESSAGE_COMMAND: { MidiMessage message; if (!recv(&message, 3)) { - ready = false; return; } processMidi(message); @@ -167,13 +170,17 @@ struct BridgeClientConnection { float input[BRIDGE_INPUTS * frames]; if (!recv(&input, BRIDGE_INPUTS * frames * sizeof(float))) { - ready = false; + debug("Failed to receive"); return; } + float output[BRIDGE_OUTPUTS * frames]; memset(&output, 0, sizeof(output)); processStream(input, output, frames); - send(&output, BRIDGE_OUTPUTS * frames * sizeof(float)); + if (!send(&output, BRIDGE_OUTPUTS * frames * sizeof(float))) { + debug("Failed to send"); + return; + } // flush(); } break; } @@ -232,23 +239,41 @@ struct BridgeClientConnection { static void clientRun(int client) { defer({ - close(client); +#ifdef ARCH_WIN + if (shutdown(client, SD_SEND)) { + warn("Bridge client shutdown() failed"); + } + if (closesocket(client)) { + warn("Bridge client closesocket() failed"); + } +#else + if (close(client)) { + warn("Bridge client close() failed"); + } +#endif }); - int err; - (void) err; #ifdef ARCH_MAC // Avoid SIGPIPE int flag = 1; - setsockopt(client, SOL_SOCKET, SO_NOSIGPIPE, &flag, sizeof(int)); + if (setsockopt(client, SOL_SOCKET, SO_NOSIGPIPE, &flag, sizeof(int))) { + warn("Bridge client setsockopt() failed"); + return; + } #endif // Disable non-blocking #ifdef ARCH_WIN unsigned long blockingMode = 0; - ioctlsocket(client, FIONBIO, &blockingMode); + if (ioctlsocket(client, FIONBIO, &blockingMode)) { + warn("Bridge client ioctlsocket() failed"); + return; + } #else - err = fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) & ~O_NONBLOCK); + if (fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) & ~O_NONBLOCK)) { + warn("Bridge client fcntl() failed"); + return; + } #endif BridgeClientConnection connection; @@ -258,19 +283,16 @@ static void clientRun(int client) { static void serverConnect() { - int err; - // Initialize sockets #ifdef ARCH_WIN WSADATA wsaData; - err = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { + warn("Bridge server WSAStartup() failed"); + return; + } defer({ WSACleanup(); }); - if (err) { - warn("Could not initialize Winsock"); - return; - } #endif // Get address @@ -295,15 +317,13 @@ static void serverConnect() { }); // Bind socket to address - err = bind(server, (struct sockaddr*) &addr, sizeof(addr)); - if (err) { + if (bind(server, (struct sockaddr*) &addr, sizeof(addr))) { warn("Bridge server bind() failed"); return; } // Listen for clients - err = listen(server, 20); - if (err) { + if (listen(server, 20)) { warn("Bridge server listen() failed"); return; } @@ -312,10 +332,13 @@ static void serverConnect() { // Enable non-blocking #ifdef ARCH_WIN unsigned long blockingMode = 1; - ioctlsocket(server, FIONBIO, &blockingMode); + if (ioctlsocket(server, FIONBIO, &blockingMode)) { + warn("Bridge server ioctlsocket() failed"); + return; + } #else int flags = fcntl(server, F_GETFL, 0); - err = fcntl(server, F_SETFL, flags | O_NONBLOCK); + fcntl(server, F_SETFL, flags | O_NONBLOCK); #endif // Accept clients