Skip to content

Commit fe3fd39

Browse files
committed
CDRIVER-2176 Enable and configure TCP Keepalive by default
1 parent c31a8ca commit fe3fd39

File tree

1 file changed

+161
-3
lines changed

1 file changed

+161
-3
lines changed

src/mongoc/mongoc-socket.c

Lines changed: 161 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include "mongoc-host-list.h"
2525
#include "mongoc-socket-private.h"
2626
#include "mongoc-trace-private.h"
27+
#ifdef _WIN32
28+
#include <Mstcpip.h>
29+
#endif
2730

2831
#undef MONGOC_LOG_DOMAIN
2932
#define MONGOC_LOG_DOMAIN "socket"
@@ -257,6 +260,158 @@ mongoc_socket_poll (mongoc_socket_poll_t *sds, /* IN */
257260
}
258261

259262

263+
/* https://jira.mongodb.org/browse/CDRIVER-2176 */
264+
#define MONGODB_KEEPALIVEINTVL 10
265+
#define MONGODB_KEEPALIVETIME 300
266+
#define MONGODB_KEEPALIVECNT 9
267+
268+
static void
269+
#ifdef _WIN32
270+
_mongoc_socket_setkeepalive (SOCKET sd) /* IN */
271+
#else
272+
_mongoc_socket_setkeepalive (int sd) /* IN */
273+
#endif
274+
{
275+
#ifdef _WIN32
276+
BOOL optval = 1;
277+
struct tcp_keepalive keepalive;
278+
DWORD lpcbBytesReturned = 0;
279+
HKEY hKey;
280+
DWORD type;
281+
DWORD data;
282+
DWORD data_size = sizeof data;
283+
const char *reg_key =
284+
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
285+
#else
286+
int optval = 1;
287+
mongoc_socklen_t optlen;
288+
#endif
289+
#ifdef SOL_TCP
290+
int level = SOL_TCP;
291+
#else
292+
int level = SOL_SOCKET;
293+
#endif
294+
295+
ENTRY;
296+
297+
#ifdef SO_KEEPALIVE
298+
if (setsockopt (sd, level, SO_KEEPALIVE, (char *) &optval, sizeof optval)) {
299+
TRACE ("Setting SO_KEEPALIVE failed");
300+
}
301+
#else
302+
TRACE ("SO_KEEPALIVE not available");
303+
#endif
304+
305+
#ifdef _WIN32
306+
keepalive.onoff = true;
307+
keepalive.keepalivetime = MONGODB_KEEPALIVETIME * 1000;
308+
keepalive.keepaliveinterval = MONGODB_KEEPALIVEINTVL * 1000;
309+
/*
310+
* Windows hardcodes probes to 10:
311+
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
312+
* "On Windows Vista and later, the number of keep-alive probes (data
313+
* retransmissions) is set to 10 and cannot be changed."
314+
*
315+
* Note that win2k (and seeminly all versions thereafter) do not set the
316+
* registry value by default so there is no way to derive the default value
317+
* programmatically. It is however listed in the docs. A user can however
318+
* change the default value by setting the registry values.
319+
*/
320+
321+
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, reg_key, 0, KEY_QUERY_VALUE, &hKey) ==
322+
ERROR_SUCCESS) {
323+
/* https://technet.microsoft.com/en-us/library/cc957549.aspx */
324+
DWORD default_keepalivetime = 7200000; /* 2 hours */
325+
/* https://technet.microsoft.com/en-us/library/cc957548.aspx */
326+
DWORD default_keepaliveinterval = 1000; /* 1 second */
327+
328+
if (RegQueryValueEx (
329+
hKey, "KeepAliveTime", NULL, &type, (LPBYTE) &data, &data_size) ==
330+
ERROR_SUCCESS) {
331+
if (type == REG_DWORD && data < keepalive.keepalivetime) {
332+
keepalive.keepalivetime = data;
333+
}
334+
} else if (default_keepalivetime < keepalive.keepalivetime) {
335+
keepalive.keepalivetime = default_keepalivetime;
336+
}
337+
338+
if (RegQueryValueEx (hKey,
339+
"KeepAliveInterval",
340+
NULL,
341+
&type,
342+
(LPBYTE) &data,
343+
&data_size) == ERROR_SUCCESS) {
344+
if (type == REG_DWORD && data < keepalive.keepaliveinterval) {
345+
keepalive.keepaliveinterval = data;
346+
}
347+
} else if (default_keepaliveinterval < keepalive.keepaliveinterval) {
348+
keepalive.keepaliveinterval = default_keepaliveinterval;
349+
}
350+
RegCloseKey (hKey);
351+
}
352+
if (WSAIoctl (sd,
353+
SIO_KEEPALIVE_VALS,
354+
&keepalive,
355+
sizeof keepalive,
356+
NULL,
357+
0,
358+
&lpcbBytesReturned,
359+
NULL,
360+
NULL) == SOCKET_ERROR) {
361+
TRACE ("Could not set keepalive values");
362+
}
363+
#else
364+
#ifdef TCP_KEEPIDLE
365+
optlen = sizeof optval;
366+
if (!getsockopt (sd, level, TCP_KEEPIDLE, (char *) &optval, &optlen)) {
367+
TRACE ("TCP_KEEPIDLE value currently %d", (int) optval);
368+
if (optval > MONGODB_KEEPALIVETIME) {
369+
optval = MONGODB_KEEPALIVETIME;
370+
if (setsockopt (
371+
sd, level, TCP_KEEPIDLE, (char *) &optval, sizeof optval)) {
372+
TRACE ("Setting TCP_KEEPIDLE failed");
373+
} else {
374+
TRACE ("TCP_KEEPIDLE value changed to %d", (int) optval);
375+
}
376+
}
377+
}
378+
#endif
379+
380+
#ifdef TCP_KEEPINTVL
381+
optlen = sizeof optval;
382+
if (!getsockopt (sd, level, TCP_KEEPINTVL, (char *) &optval, &optlen)) {
383+
TRACE ("TCP_KEEPINTL value currently %d", (int) optval);
384+
if (optval > MONGODB_KEEPALIVEINTVL) {
385+
optval = MONGODB_KEEPALIVEINTVL;
386+
if (setsockopt (
387+
sd, level, TCP_KEEPINTVL, (char *) &optval, sizeof optval)) {
388+
TRACE ("Setting TCP_KEEPINTVL failed");
389+
} else {
390+
TRACE ("TCP_KEEPINTVL value changed to %d", (int) optval);
391+
}
392+
}
393+
}
394+
#endif
395+
396+
#ifdef TCP_KEEPCNT
397+
optlen = sizeof optval;
398+
if (!getsockopt (sd, level, TCP_KEEPCNT, (char *) &optval, &optlen)) {
399+
TRACE ("TCP_KEEPCNT value currently %d", (int) optval);
400+
if (optval > MONGODB_KEEPALIVECNT) {
401+
optval = MONGODB_KEEPALIVECNT;
402+
if (setsockopt (
403+
sd, level, TCP_KEEPCNT, (char *) &optval, sizeof optval)) {
404+
TRACE ("Setting TCP_KEEPCNT failed");
405+
} else {
406+
TRACE ("TCP_KEEPCNT value changed to %d", (int) optval);
407+
}
408+
}
409+
}
410+
#endif
411+
#endif /* _WIN32 */
412+
}
413+
414+
260415
static bool
261416
#ifdef _WIN32
262417
_mongoc_socket_setnodelay (SOCKET sd) /* IN */
@@ -536,7 +691,7 @@ mongoc_socket_close (mongoc_socket_t *sock) /* IN */
536691
#else
537692
if (sock->sd != -1) {
538693
if (owned) {
539-
shutdown (sock->sd, SHUT_RDWR);
694+
shutdown (sock->sd, SHUT_RDWR);
540695
}
541696

542697
if (0 == close (sock->sd)) {
@@ -734,8 +889,11 @@ mongoc_socket_new (int domain, /* IN */
734889
GOTO (fail);
735890
}
736891

737-
if (domain != AF_UNIX && !_mongoc_socket_setnodelay (sd)) {
738-
MONGOC_WARNING ("Failed to enable TCP_NODELAY.");
892+
if (domain != AF_UNIX) {
893+
if (!_mongoc_socket_setnodelay (sd)) {
894+
MONGOC_WARNING ("Failed to enable TCP_NODELAY.");
895+
}
896+
_mongoc_socket_setkeepalive (sd);
739897
}
740898

741899
sock = (mongoc_socket_t *) bson_malloc0 (sizeof *sock);

0 commit comments

Comments
 (0)