track open/close state in connection, disconnect on read error, clarify error codes a little

This commit is contained in:
Chris Marsh 2017-07-31 14:42:36 -07:00
parent c3c27c730d
commit d5e6c4c11a
5 changed files with 47 additions and 5 deletions

View file

@ -11,6 +11,7 @@ int GetProcessId();
struct BaseConnection { struct BaseConnection {
static BaseConnection* Create(); static BaseConnection* Create();
static void Destroy(BaseConnection*&); static void Destroy(BaseConnection*&);
bool isOpen{false};
bool Open(); bool Open();
bool Close(); bool Close();
bool Write(const void* data, size_t length); bool Write(const void* data, size_t length);

View file

@ -1,5 +1,6 @@
#include "connection.h" #include "connection.h"
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -18,7 +19,12 @@ struct BaseConnectionUnix : public BaseConnection {
}; };
static BaseConnectionUnix Connection; static BaseConnectionUnix Connection;
sockaddr_un PipeAddr{}; static sockaddr_un PipeAddr{};
#ifdef MSG_NOSIGNAL
static int MsgFlags = MSG_NOSIGNAL;
#else
static int MsgFlags = 0;
#endif
static const char* GetTempPath() static const char* GetTempPath()
{ {
@ -52,11 +58,17 @@ bool BaseConnection::Open()
return false; return false;
} }
fcntl(self->sock, F_SETFL, O_NONBLOCK); fcntl(self->sock, F_SETFL, O_NONBLOCK);
#ifdef SO_NOSIGPIPE
int optval = 1;
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
#endif
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
snprintf( snprintf(
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum); PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr)); int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr));
if (err == 0) { if (err == 0) {
self->isOpen = true;
return true; return true;
} }
} }
@ -72,6 +84,7 @@ bool BaseConnection::Close()
} }
close(self->sock); close(self->sock);
self->sock = -1; self->sock = -1;
self->isOpen = false;
return true; return true;
} }
@ -83,7 +96,10 @@ bool BaseConnection::Write(const void* data, size_t length)
return false; return false;
} }
ssize_t sentBytes = send(self->sock, data, length, 0); ssize_t sentBytes = send(self->sock, data, length, MsgFlags);
if (sentBytes < 0) {
Close();
}
return sentBytes == (ssize_t)length; return sentBytes == (ssize_t)length;
} }
@ -95,6 +111,12 @@ bool BaseConnection::Read(void* data, size_t length)
return false; return false;
} }
int res = recv(self->sock, data, length, 0); int res = recv(self->sock, data, length, MsgFlags);
if (res < 0) {
if (errno == EAGAIN) {
return false;
}
Close();
}
return res == (int)length; return res == (int)length;
} }

View file

@ -39,6 +39,7 @@ bool BaseConnection::Open()
self->pipe = ::CreateFileW( self->pipe = ::CreateFileW(
pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (self->pipe != INVALID_HANDLE_VALUE) { if (self->pipe != INVALID_HANDLE_VALUE) {
self->isOpen = true;
return true; return true;
} }
@ -64,6 +65,7 @@ bool BaseConnection::Close()
auto self = reinterpret_cast<BaseConnectionWin*>(this); auto self = reinterpret_cast<BaseConnectionWin*>(this);
::CloseHandle(self->pipe); ::CloseHandle(self->pipe);
self->pipe = INVALID_HANDLE_VALUE; self->pipe = INVALID_HANDLE_VALUE;
self->isOpen = false;
return true; return true;
} }
@ -82,7 +84,13 @@ bool BaseConnection::Read(void* data, size_t length)
if (::ReadFile(self->pipe, data, length, nullptr, nullptr) == TRUE) { if (::ReadFile(self->pipe, data, length, nullptr, nullptr) == TRUE) {
return true; return true;
} }
else {
Close();
}
} }
} }
else {
Close();
}
return false; return false;
} }

View file

@ -97,13 +97,18 @@ bool RpcConnection::Read(JsonDocument& message)
for (;;) { for (;;) {
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader)); bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
if (!didRead) { if (!didRead) {
if (!connection->isOpen) {
lastErrorCode = (int)ErrorCode::PipeClosed;
StringCopy(lastErrorMessage, "Pipe closed");
Close();
}
return false; return false;
} }
if (readFrame.length > 0) { if (readFrame.length > 0) {
didRead = connection->Read(readFrame.message, readFrame.length); didRead = connection->Read(readFrame.message, readFrame.length);
if (!didRead) { if (!didRead) {
lastErrorCode = -2; lastErrorCode = (int)ErrorCode::ReadCorrupt;
StringCopy(lastErrorMessage, "Partial data in frame"); StringCopy(lastErrorMessage, "Partial data in frame");
Close(); Close();
return false; return false;
@ -132,7 +137,7 @@ bool RpcConnection::Read(JsonDocument& message)
break; break;
default: default:
// something bad happened // something bad happened
lastErrorCode = -1; lastErrorCode = (int)ErrorCode::ReadCorrupt;
StringCopy(lastErrorMessage, "Bad ipc frame"); StringCopy(lastErrorMessage, "Bad ipc frame");
Close(); Close();
return false; return false;

View file

@ -8,6 +8,12 @@
constexpr size_t MaxRpcFrameSize = 64 * 1024; constexpr size_t MaxRpcFrameSize = 64 * 1024;
struct RpcConnection { struct RpcConnection {
enum class ErrorCode : int {
Success = 0,
PipeClosed = 1,
ReadCorrupt = 2,
};
enum class Opcode : uint32_t { enum class Opcode : uint32_t {
Handshake = 0, Handshake = 0,
Frame = 1, Frame = 1,