|
24 | 24 | #include "mongoc-host-list.h"
|
25 | 25 | #include "mongoc-socket-private.h"
|
26 | 26 | #include "mongoc-trace-private.h"
|
| 27 | +#ifdef _WIN32 |
| 28 | +#include <Mstcpip.h> |
| 29 | +#endif |
27 | 30 |
|
28 | 31 | #undef MONGOC_LOG_DOMAIN
|
29 | 32 | #define MONGOC_LOG_DOMAIN "socket"
|
@@ -257,6 +260,158 @@ mongoc_socket_poll (mongoc_socket_poll_t *sds, /* IN */
|
257 | 260 | }
|
258 | 261 |
|
259 | 262 |
|
| 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 | + |
260 | 415 | static bool
|
261 | 416 | #ifdef _WIN32
|
262 | 417 | _mongoc_socket_setnodelay (SOCKET sd) /* IN */
|
@@ -536,7 +691,7 @@ mongoc_socket_close (mongoc_socket_t *sock) /* IN */
|
536 | 691 | #else
|
537 | 692 | if (sock->sd != -1) {
|
538 | 693 | if (owned) {
|
539 |
| - shutdown (sock->sd, SHUT_RDWR); |
| 694 | + shutdown (sock->sd, SHUT_RDWR); |
540 | 695 | }
|
541 | 696 |
|
542 | 697 | if (0 == close (sock->sd)) {
|
@@ -734,8 +889,11 @@ mongoc_socket_new (int domain, /* IN */
|
734 | 889 | GOTO (fail);
|
735 | 890 | }
|
736 | 891 |
|
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); |
739 | 897 | }
|
740 | 898 |
|
741 | 899 | sock = (mongoc_socket_t *) bson_malloc0 (sizeof *sock);
|
|
0 commit comments