]>
Commit | Line | Data |
---|---|---|
1dde4660 AJ |
1 | /* |
2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors | |
3 | * | |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
9 | /* DEBUG: section 05 TCP Socket Functions */ | |
10 | ||
11 | #include "squid.h" | |
12 | #include "comm/Tcp.h" | |
13 | #include "Debug.h" | |
14 | ||
15 | #if HAVE_NETINET_TCP_H | |
16 | #include <netinet/tcp.h> | |
17 | #endif | |
61e38858 FC |
18 | #if HAVE_SYS_SOCKET_H |
19 | #include <sys/socket.h> | |
20 | #endif | |
1dde4660 AJ |
21 | #include <type_traits> |
22 | ||
23 | /// setsockopt(2) wrapper | |
24 | template <typename Option> | |
25 | static bool | |
26 | SetSocketOption(const int fd, const int level, const int optName, const Option &optValue) | |
27 | { | |
28 | #if HAVE_STD_IS_TRIVIALLY_COPYABLE | |
29 | static_assert(std::is_trivially_copyable<Option>::value, "setsockopt() expects POD-like options"); | |
30 | #endif | |
31 | static_assert(!std::is_same<Option, bool>::value, "setsockopt() uses int to represent boolean options"); | |
32 | if (setsockopt(fd, level, optName, &optValue, sizeof(optValue)) < 0) { | |
33 | const auto xerrno = errno; | |
34 | debugs(5, DBG_IMPORTANT, "ERROR: setsockopt(2) failure: " << xstrerr(xerrno)); | |
35 | // TODO: Generalize to throw on errors when some callers need that. | |
36 | return false; | |
37 | } | |
38 | return true; | |
39 | } | |
40 | ||
41 | /// setsockopt(2) wrapper for setting typical on/off options | |
42 | static bool | |
43 | SetBooleanSocketOption(const int fd, const int level, const int optName, const bool enable) | |
44 | { | |
45 | const int optValue = enable ? 1 : 0; | |
46 | return SetSocketOption(fd, level, optName, optValue); | |
47 | } | |
48 | ||
49 | void | |
50 | Comm::ApplyTcpKeepAlive(int fd, const TcpKeepAlive &cfg) | |
51 | { | |
52 | if (!cfg.enabled) | |
53 | return; | |
54 | ||
55 | #if defined(TCP_KEEPCNT) | |
56 | if (cfg.timeout && cfg.interval) { | |
57 | const int count = (cfg.timeout + cfg.interval - 1) / cfg.interval; // XXX: unsigned-to-signed conversion | |
58 | (void)SetSocketOption(fd, IPPROTO_TCP, TCP_KEEPCNT, count); | |
59 | } | |
60 | #endif | |
61 | #if defined(TCP_KEEPIDLE) | |
62 | if (cfg.idle) { | |
63 | // XXX: TCP_KEEPIDLE expects an int; cfg.idle is unsigned | |
64 | (void)SetSocketOption(fd, IPPROTO_TCP, TCP_KEEPIDLE, cfg.idle); | |
65 | } | |
66 | #endif | |
67 | #if defined(TCP_KEEPINTVL) | |
68 | if (cfg.interval) { | |
69 | // XXX: TCP_KEEPINTVL expects an int; cfg.interval is unsigned | |
70 | (void)SetSocketOption(fd, IPPROTO_TCP, TCP_KEEPINTVL, cfg.interval); | |
71 | } | |
72 | #endif | |
73 | (void)SetBooleanSocketOption(fd, SOL_SOCKET, SO_KEEPALIVE, true); | |
74 | } |