ease asserting, constants wrapped for future robustness

This commit is contained in:
Boris-Barboris 2018-06-06 10:41:20 +00:00
parent a2d96f1831
commit ed9fdcd467
7 changed files with 41 additions and 38 deletions

View file

@ -216,7 +216,7 @@ interface EventDriverSockets {
void setKeepAlive(StreamSocketFD socket, bool enable); void setKeepAlive(StreamSocketFD socket, bool enable);
/** Enables keepalive for the TCP socket and sets additional parameters. /** Enables keepalive for the TCP socket and sets additional parameters.
Silently ignores unsupported systems. Silently ignores unsupported systems (anything but Windows and Linux).
Params: Params:
socket = Socket file descriptor to set options on. socket = Socket file descriptor to set options on.

View file

@ -51,10 +51,15 @@ version (linux) {
// Linux-specific TCP options // Linux-specific TCP options
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h#L95 // https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h#L95
// Some day we should siply import core.sys.linux.netinet.tcp; // Some day we should siply import core.sys.linux.netinet.tcp;
static if (!is(typeof(SOL_TCP)))
enum SOL_TCP = 6; enum SOL_TCP = 6;
static if (!is(typeof(TCP_KEEPIDLE)))
enum TCP_KEEPIDLE = 4; enum TCP_KEEPIDLE = 4;
static if (!is(typeof(TCP_KEEPINTVL)))
enum TCP_KEEPINTVL = 5; enum TCP_KEEPINTVL = 5;
static if (!is(typeof(TCP_KEEPCNT)))
enum TCP_KEEPCNT = 6; enum TCP_KEEPCNT = 6;
static if (!is(typeof(TCP_USER_TIMEOUT)))
enum TCP_USER_TIMEOUT = 18; enum TCP_USER_TIMEOUT = 18;
} }
version(OSX) { version(OSX) {
@ -310,36 +315,29 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
int opt = enable; int opt = enable;
int err = setsockopt(cast(sock_t)socket, SOL_SOCKET, SO_KEEPALIVE, &opt, int.sizeof); int err = setsockopt(cast(sock_t)socket, SOL_SOCKET, SO_KEEPALIVE, &opt, int.sizeof);
if (err != 0) if (err != 0)
{ print("sock error in setKeepAlive: %s", getSocketError);
print("sock error %s", getSocketError);
assert(0, "unable to set SO_KEEPALIVE option");
}
} }
override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted
{ {
// dunnno about BSD\OSX, maybe someone should fix it for them later
version (linux) { version (linux) {
setKeepAlive(socket, true); setKeepAlive(socket, true);
int int_opt = cast(int) idle.total!"seconds"(); int int_opt = cast(int) idle.total!"seconds"();
int err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPIDLE, &int_opt, int.sizeof); int err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPIDLE, &int_opt, int.sizeof);
if (err != 0) if (err != 0) {
{ print("sock error on setsockopt TCP_KEEPIDLE: %s", getSocketError);
print("sock error %s", getSocketError); return;
assert(0, "unable to set TCP_KEEPIDLE option");
} }
int_opt = cast(int) interval.total!"seconds"(); int_opt = cast(int) interval.total!"seconds"();
err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPINTVL, &int_opt, int.sizeof); err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPINTVL, &int_opt, int.sizeof);
if (err != 0) if (err != 0) {
{ print("sock error on setsockopt TCP_KEEPINTVL: %s", getSocketError);
print("sock error %s", getSocketError); return;
assert(0, "unable to set TCP_KEEPINTVL option");
} }
err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPCNT, &probeCount, int.sizeof); err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPCNT, &probeCount, int.sizeof);
if (err != 0) if (err != 0)
{ print("sock error on setsockopt TCP_KEEPCNT: %s", getSocketError);
print("sock error %s", getSocketError);
assert(0, "unable to set TCP_KEEPCNT option");
}
} }
} }
@ -349,10 +347,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
uint tmsecs = cast(uint) timeout.total!"msecs"; uint tmsecs = cast(uint) timeout.total!"msecs";
int err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_USER_TIMEOUT, &tmsecs, uint.sizeof); int err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_USER_TIMEOUT, &tmsecs, uint.sizeof);
if (err != 0) if (err != 0)
{ print("sock error on setsockopt TCP_USER_TIMEOUT %s", getSocketError);
print("sock error %s", getSocketError);
assert(0, "unable to set TCP_USER_TIMEOUT option");
}
} }
} }

View file

@ -225,15 +225,12 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted
{ {
tcp_keepalive opts = tcp_keepalive(1, cast(ulong) idle.total!"msecs"(), tcp_keepalive opts = tcp_keepalive(1, cast(c_ulong) idle.total!"msecs"(),
cast(ulong) interval.total!"msecs"); cast(c_ulong) interval.total!"msecs");
int result = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &opts, cast(uint) tcp_keepalive.sizeof, int result = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &opts, cast(DWORD) tcp_keepalive.sizeof,
null, 0, null, null, null); null, 0, null, null, null);
if (result != 0) if (result != 0)
{ print("WSAIoctl error on SIO_KEEPALIVE_VALS: %d", WSAGetLastError());
print("WSAIoctl SIO_KEEPALIVE_VALS returned %d", result);
assert(0, "unable to set TCP keepAlive parameters");
}
} }
override void setUserTimeout(StreamSocketFD socket, Duration timeout) {} override void setUserTimeout(StreamSocketFD socket, Duration timeout) {}

View file

@ -4,6 +4,7 @@ version(Windows):
public import core.sys.windows.windows; public import core.sys.windows.windows;
public import core.sys.windows.winsock2; public import core.sys.windows.winsock2;
public import core.stdc.config: c_ulong;
extern(System) nothrow: extern(System) nothrow:
@ -106,9 +107,9 @@ struct ADDRINFOW {
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
struct tcp_keepalive { struct tcp_keepalive {
ulong onoff; c_ulong onoff;
ulong keepalivetime; c_ulong keepalivetime;
ulong keepaliveinterval; c_ulong keepaliveinterval;
}; };
// https://gist.github.com/piscisaureus/906386#file-winsock2-h-L1099 // https://gist.github.com/piscisaureus/906386#file-winsock2-h-L1099

View file

@ -2,6 +2,7 @@ module eventcore.socket;
import eventcore.core : eventDriver; import eventcore.core : eventDriver;
import eventcore.driver; import eventcore.driver;
import core.time: Duration;
import std.exception : enforce; import std.exception : enforce;
import std.socket : Address; import std.socket : Address;
@ -49,6 +50,11 @@ struct StreamSocket {
@property ConnectionState state() { return eventDriver.sockets.getConnectionState(m_fd); } @property ConnectionState state() { return eventDriver.sockets.getConnectionState(m_fd); }
@property void tcpNoDelay(bool enable) { eventDriver.sockets.setTCPNoDelay(m_fd, enable); } @property void tcpNoDelay(bool enable) { eventDriver.sockets.setTCPNoDelay(m_fd, enable); }
void setKeepAlive(bool enable) { eventDriver.sockets.setKeepAlive(m_fd, enable); }
void setKeepAliveParams(Duration idle, Duration interval, int probeCount = 5) {
eventDriver.sockets.setKeepAliveParams(m_fd, idle, interval, probeCount);
}
void setUserTimeout(Duration timeout) { eventDriver.sockets.setUserTimeout(m_fd, timeout); }
} }
void read(alias callback)(ref StreamSocket socket, ubyte[] buffer, IOMode mode) void read(alias callback)(ref StreamSocket socket, ubyte[] buffer, IOMode mode)

View file

@ -8,7 +8,7 @@ import eventcore.core;
import eventcore.socket; import eventcore.socket;
import eventcore.internal.utils : print; import eventcore.internal.utils : print;
import std.socket : InternetAddress; import std.socket : InternetAddress;
import core.time : Duration, msecs; import core.time : Duration, msecs, seconds;
ubyte[256] s_rbuf; ubyte[256] s_rbuf;
bool s_done; bool s_done;
@ -69,6 +69,10 @@ void main()
client = sock; client = sock;
assert(status == ConnectStatus.connected); assert(status == ConnectStatus.connected);
assert(sock.state == ConnectionState.connected); assert(sock.state == ConnectionState.connected);
print("Setting keepalive and timeout options");
client.setKeepAlive(true);
client.setKeepAliveParams(10.seconds, 10.seconds, 4);
client.setUserTimeout(5.seconds);
print("Initial write"); print("Initial write");
client.write!((wstatus, bytes) { client.write!((wstatus, bytes) {
print("Initial write done"); print("Initial write done");