add setKeepAliveParams method

This commit is contained in:
Boris-Barboris 2018-04-02 11:11:28 +00:00
parent 242432c416
commit cdb141ba4a
4 changed files with 71 additions and 0 deletions

View file

@ -215,6 +215,19 @@ interface EventDriverSockets {
/// Sets to `SO_KEEPALIVE` socket option on a socket. /// Sets to `SO_KEEPALIVE` socket option on a socket.
void setKeepAlive(StreamSocketFD socket, bool enable); void setKeepAlive(StreamSocketFD socket, bool enable);
/** Enables keepalive for the TCP socket and sets additional parameters.
Silently ignores unsupported systems.
Params:
socket = Socket file descriptor to set options on.
idle = The time the connection needs to remain idle
before TCP starts sending keepalive probes.
interval = The time between individual keepalive probes.
probeCount = The maximum number of keepalive probes TCP should send
before dropping the connection. Has no effect on Windows.
*/
void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount = 5);
/** Reads data from a stream socket. /** Reads data from a stream socket.
Note that only a single read operation is allowed at once. The caller Note that only a single read operation is allowed at once. The caller

View file

@ -8,6 +8,8 @@ import eventcore.internal.utils;
import std.algorithm.comparison : among, min, max; import std.algorithm.comparison : among, min, max;
import std.socket : Address, AddressFamily, InternetAddress, Internet6Address, UnknownAddress; import std.socket : Address, AddressFamily, InternetAddress, Internet6Address, UnknownAddress;
import core.time: Duration;
version (Posix) { version (Posix) {
import std.socket : UnixAddress; import std.socket : UnixAddress;
import core.sys.posix.netdb : AI_ADDRCONFIG, AI_V4MAPPED, addrinfo, freeaddrinfo, getaddrinfo; import core.sys.posix.netdb : AI_ADDRCONFIG, AI_V4MAPPED, addrinfo, freeaddrinfo, getaddrinfo;
@ -45,6 +47,13 @@ version (linux) {
} }
else else
import core.sys.linux.netinet.in_ : IP_ADD_MEMBERSHIP, IP_MULTICAST_LOOP; import core.sys.linux.netinet.in_ : IP_ADD_MEMBERSHIP, IP_MULTICAST_LOOP;
// Linux-specific TCP options
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h#L95
enum SOL_TCP = 6;
enum TCP_KEEPIDLE = 4;
enum TCP_KEEPINTVL = 5;
enum TCP_KEEPCNT = 6;
} }
version(OSX) { version(OSX) {
static if (__VERSION__ < 2077) { static if (__VERSION__ < 2077) {
@ -300,6 +309,19 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
() @trusted { setsockopt(cast(sock_t)socket, SOL_SOCKET, SO_KEEPALIVE, cast(char*)&opt, opt.sizeof); } (); () @trusted { setsockopt(cast(sock_t)socket, SOL_SOCKET, SO_KEEPALIVE, cast(char*)&opt, opt.sizeof); } ();
} }
override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted
{
version (linux) {
ubyte opt = 1;
setsockopt(cast(sock_t)socket, SOL_SOCKET, SO_KEEPALIVE, cast(char*)&opt, opt.sizeof);
int int_opt = cast(int) idle.total!"seconds"();
setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPIDLE, &int_opt, int.sizeof);
int_opt = cast(int) interval.total!"seconds"();
setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPINTVL, &int_opt, int.sizeof);
setsockopt(cast(sock_t)socket, SOL_TCP, TCP_KEEPCNT, &probeCount, int.sizeof);
}
}
final override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish) final override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish)
{ {
/*if (buffer.length == 0) { /*if (buffer.length == 0) {

View file

@ -221,6 +221,18 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &eni, eni.sizeof); setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &eni, eni.sizeof);
} }
override void setKeepAliveParams(StreamSocketFD socket, Duration idle, Duration interval, int probeCount) @trusted
{
if (idle < Duration.zero)
assert(0, "negative idle duration");
if (interval < Duration.zero)
assert(0, "negative interval duration");
tcp_keepalive opts = tcp_keepalive(1, cast(ulong) idle.total!"msecs"(),
cast(ulong) interval.total!"msecs");
int result = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &opts, tcp_keepalive.sizeof, null, 0, null, null);
assert(result == 0);
}
override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish) override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish)
{ {
auto slot = () @trusted { return &m_sockets[socket].streamSocket(); } (); auto slot = () @trusted { return &m_sockets[socket].streamSocket(); } ();

View file

@ -104,6 +104,29 @@ struct ADDRINFOW {
ADDRINFOW* ai_next; ADDRINFOW* ai_next;
} }
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
struct tcp_keepalive {
ulong onoff;
ulong keepalivetime;
ulong keepaliveinterval;
};
// https://gist.github.com/piscisaureus/906386#file-winsock2-h-L1099
enum : ulong {
IOC_VENDOR = 0x18000000,
IOC_OUT = 0x40000000,
IOC_IN = 0x80000000
}
ulong _WSAIOW(ulong x, ulong y) pure @safe
{
return IOC_IN | x | y;
}
enum : ulong {
SIO_KEEPALIVE_VALS = _WSAIOW(IOC_VENDOR, 4)
}
struct WSAPROTOCOL_INFO { struct WSAPROTOCOL_INFO {
DWORD dwServiceFlags1; DWORD dwServiceFlags1;
DWORD dwServiceFlags2; DWORD dwServiceFlags2;
@ -154,6 +177,7 @@ void FreeAddrInfoExW(ADDRINFOEXW* pAddrInfo);
void freeaddrinfo(ADDRINFOA* ai); void freeaddrinfo(ADDRINFOA* ai);
BOOL TransmitFile(SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, OVERLAPPED* lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwFlags); BOOL TransmitFile(SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, OVERLAPPED* lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwFlags);
BOOL CancelIoEx(HANDLE hFile, LPOVERLAPPED lpOverlapped); BOOL CancelIoEx(HANDLE hFile, LPOVERLAPPED lpOverlapped);
int WSAIoctl(SOCKET s, DWORD dwIoControlCode, void* lpvInBuffer, DWORD cbInBuffer, void* lpvOutBuffer, DWORD cbOutBuffer, DWORD* lpcbBytesReturned, in WSAOVERLAPPEDX* lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINEX lpCompletionRoutine);
/*struct WSAOVERLAPPEDX { /*struct WSAOVERLAPPEDX {
ULONG_PTR Internal; ULONG_PTR Internal;