diff --git a/source/eventcore/driver.d b/source/eventcore/driver.d index eab444f..ed9059c 100644 --- a/source/eventcore/driver.d +++ b/source/eventcore/driver.d @@ -216,7 +216,7 @@ interface EventDriverSockets { void setKeepAlive(StreamSocketFD socket, bool enable); /** Enables keepalive for the TCP socket and sets additional parameters. - Silently ignores unsupported systems. + Silently ignores unsupported systems (anything but Windows and Linux). Params: socket = Socket file descriptor to set options on. diff --git a/source/eventcore/drivers/posix/sockets.d b/source/eventcore/drivers/posix/sockets.d index 3d0c1fd..53361d0 100644 --- a/source/eventcore/drivers/posix/sockets.d +++ b/source/eventcore/drivers/posix/sockets.d @@ -51,11 +51,16 @@ version (linux) { // Linux-specific TCP options // https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h#L95 // Some day we should siply import core.sys.linux.netinet.tcp; - enum SOL_TCP = 6; - enum TCP_KEEPIDLE = 4; - enum TCP_KEEPINTVL = 5; - enum TCP_KEEPCNT = 6; - enum TCP_USER_TIMEOUT = 18; + static if (!is(typeof(SOL_TCP))) + enum SOL_TCP = 6; + static if (!is(typeof(TCP_KEEPIDLE))) + enum TCP_KEEPIDLE = 4; + static if (!is(typeof(TCP_KEEPINTVL))) + enum TCP_KEEPINTVL = 5; + static if (!is(typeof(TCP_KEEPCNT))) + enum TCP_KEEPCNT = 6; + static if (!is(typeof(TCP_USER_TIMEOUT))) + enum TCP_USER_TIMEOUT = 18; } version(OSX) { static if (__VERSION__ < 2077) { @@ -310,36 +315,29 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets int opt = enable; int err = setsockopt(cast(sock_t)socket, SOL_SOCKET, SO_KEEPALIVE, &opt, int.sizeof); if (err != 0) - { - print("sock error %s", getSocketError); - assert(0, "unable to set SO_KEEPALIVE option"); - } + print("sock error in setKeepAlive: %s", getSocketError); } 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) { setKeepAlive(socket, true); int int_opt = cast(int) idle.total!"seconds"(); int err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPIDLE, &int_opt, int.sizeof); - if (err != 0) - { - print("sock error %s", getSocketError); - assert(0, "unable to set TCP_KEEPIDLE option"); + if (err != 0) { + print("sock error on setsockopt TCP_KEEPIDLE: %s", getSocketError); + return; } int_opt = cast(int) interval.total!"seconds"(); err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPINTVL, &int_opt, int.sizeof); - if (err != 0) - { - print("sock error %s", getSocketError); - assert(0, "unable to set TCP_KEEPINTVL option"); + if (err != 0) { + print("sock error on setsockopt TCP_KEEPINTVL: %s", getSocketError); + return; } err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPCNT, &probeCount, int.sizeof); if (err != 0) - { - print("sock error %s", getSocketError); - assert(0, "unable to set TCP_KEEPCNT option"); - } + print("sock error on setsockopt TCP_KEEPCNT: %s", getSocketError); } } @@ -349,10 +347,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets uint tmsecs = cast(uint) timeout.total!"msecs"; int err = setsockopt(cast(sock_t)socket, SOL_TCP, TCP_USER_TIMEOUT, &tmsecs, uint.sizeof); if (err != 0) - { - print("sock error %s", getSocketError); - assert(0, "unable to set TCP_USER_TIMEOUT option"); - } + print("sock error on setsockopt TCP_USER_TIMEOUT %s", getSocketError); } } diff --git a/source/eventcore/drivers/winapi/sockets.d b/source/eventcore/drivers/winapi/sockets.d index fb31517..28512d3 100644 --- a/source/eventcore/drivers/winapi/sockets.d +++ b/source/eventcore/drivers/winapi/sockets.d @@ -225,15 +225,12 @@ final class WinAPIEventDriverSockets : EventDriverSockets { override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted { - tcp_keepalive opts = tcp_keepalive(1, cast(ulong) idle.total!"msecs"(), - cast(ulong) interval.total!"msecs"); - int result = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &opts, cast(uint) tcp_keepalive.sizeof, + tcp_keepalive opts = tcp_keepalive(1, cast(c_ulong) idle.total!"msecs"(), + cast(c_ulong) interval.total!"msecs"); + int result = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &opts, cast(DWORD) tcp_keepalive.sizeof, null, 0, null, null, null); if (result != 0) - { - print("WSAIoctl SIO_KEEPALIVE_VALS returned %d", result); - assert(0, "unable to set TCP keepAlive parameters"); - } + print("WSAIoctl error on SIO_KEEPALIVE_VALS: %d", WSAGetLastError()); } override void setUserTimeout(StreamSocketFD socket, Duration timeout) {} diff --git a/source/eventcore/internal/win32.d b/source/eventcore/internal/win32.d index 2662502..9a4a599 100644 --- a/source/eventcore/internal/win32.d +++ b/source/eventcore/internal/win32.d @@ -4,6 +4,7 @@ version(Windows): public import core.sys.windows.windows; public import core.sys.windows.winsock2; +public import core.stdc.config: c_ulong; extern(System) nothrow: @@ -106,9 +107,9 @@ struct ADDRINFOW { // https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx struct tcp_keepalive { - ulong onoff; - ulong keepalivetime; - ulong keepaliveinterval; + c_ulong onoff; + c_ulong keepalivetime; + c_ulong keepaliveinterval; }; // https://gist.github.com/piscisaureus/906386#file-winsock2-h-L1099 diff --git a/source/eventcore/socket.d b/source/eventcore/socket.d index 837cded..0dc573f 100644 --- a/source/eventcore/socket.d +++ b/source/eventcore/socket.d @@ -2,6 +2,7 @@ module eventcore.socket; import eventcore.core : eventDriver; import eventcore.driver; +import core.time: Duration; import std.exception : enforce; import std.socket : Address; @@ -49,6 +50,11 @@ struct StreamSocket { @property ConnectionState state() { return eventDriver.sockets.getConnectionState(m_fd); } @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) diff --git a/tests/0-tcp-readwait.d b/tests/0-tcp-readwait.d index 3b8bfae..e668280 100644 --- a/tests/0-tcp-readwait.d +++ b/tests/0-tcp-readwait.d @@ -19,7 +19,7 @@ void main() writeln("This doesn't work on macOS. Skipping this test until it is determined that this special case should stay supported."); return; } else { - + static ubyte[] pack1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; auto baddr = new InternetAddress(0x7F000001, 40002); diff --git a/tests/0-tcp.d b/tests/0-tcp.d index 75cc479..e7f1760 100644 --- a/tests/0-tcp.d +++ b/tests/0-tcp.d @@ -8,7 +8,7 @@ import eventcore.core; import eventcore.socket; import eventcore.internal.utils : print; import std.socket : InternetAddress; -import core.time : Duration, msecs; +import core.time : Duration, msecs, seconds; ubyte[256] s_rbuf; bool s_done; @@ -69,6 +69,10 @@ void main() client = sock; assert(status == ConnectStatus.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"); client.write!((wstatus, bytes) { print("Initial write done");