1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 /**************************************************************************
25 Connections
26
27 Commonality across all platforms -- move out as required.
28
29 **************************************************************************/
30 #include "tscore/ink_platform.h"
31
32 #include "P_Net.h"
33
34 // set in the OS
35 // #define RECV_BUF_SIZE (1024*64)
36 // #define SEND_BUF_SIZE (1024*64)
37 #define FIRST_RANDOM_PORT 16000
38 #define LAST_RANDOM_PORT 32000
39
40 #define ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y))
41
42 int
get_listen_backlog()43 get_listen_backlog()
44 {
45 int listen_backlog;
46
47 REC_ReadConfigInteger(listen_backlog, "proxy.config.net.listen_backlog");
48 return (0 < listen_backlog && listen_backlog <= 65535) ? listen_backlog : ats_tcp_somaxconn();
49 }
50
51 //
52 // Functions
53 //
54 char const *
toString(addr_bind_style s)55 NetVCOptions::toString(addr_bind_style s)
56 {
57 return ANY_ADDR == s ? "any" : INTF_ADDR == s ? "interface" : "foreign";
58 }
59
Connection()60 Connection::Connection() : fd(NO_FD)
61 {
62 memset(&addr, 0, sizeof(addr));
63 }
64
~Connection()65 Connection::~Connection()
66 {
67 close();
68 }
69
70 int
accept(Connection * c)71 Server::accept(Connection *c)
72 {
73 int res = 0;
74 socklen_t sz = sizeof(c->addr);
75
76 res = socketManager.accept4(fd, &c->addr.sa, &sz, SOCK_NONBLOCK | SOCK_CLOEXEC);
77 if (res < 0) {
78 return res;
79 }
80 c->fd = res;
81 if (is_debug_tag_set("iocore_net_server")) {
82 ip_port_text_buffer ipb1, ipb2;
83 Debug("iocore_net_server", "Connection accepted [Server]. %s -> %s", ats_ip_nptop(&c->addr, ipb2, sizeof(ipb2)),
84 ats_ip_nptop(&addr, ipb1, sizeof(ipb1)));
85 }
86
87 #ifdef SEND_BUF_SIZE
88 socketManager.set_sndbuf_size(c->fd, SEND_BUF_SIZE);
89 #endif
90
91 return 0;
92 }
93
94 int
close()95 Connection::close()
96 {
97 is_connected = false;
98 is_bound = false;
99 // don't close any of the standards
100 if (fd >= 2) {
101 int fd_save = fd;
102 fd = NO_FD;
103 return socketManager.close(fd_save);
104 } else {
105 fd = NO_FD;
106 return -EBADF;
107 }
108 }
109
110 /**
111 * Move control of the socket from the argument object orig to the current object.
112 * Orig is marked as zombie, so when it is freed, the socket will not be closed
113 */
114 void
move(Connection & orig)115 Connection::move(Connection &orig)
116 {
117 this->is_connected = orig.is_connected;
118 this->is_bound = orig.is_bound;
119 this->fd = orig.fd;
120 // The target has taken ownership of the file descriptor
121 orig.fd = NO_FD;
122 this->addr = orig.addr;
123 this->sock_type = orig.sock_type;
124 }
125
126 static int
add_http_filter(int fd ATS_UNUSED)127 add_http_filter(int fd ATS_UNUSED)
128 {
129 int err = -1;
130 #if defined(SOL_FILTER) && defined(FIL_ATTACH)
131 err = setsockopt(fd, SOL_FILTER, FIL_ATTACH, "httpfilt", 9);
132 #endif
133 return err;
134 }
135
136 int
setup_fd_for_listen(bool non_blocking,const NetProcessor::AcceptOptions & opt)137 Server::setup_fd_for_listen(bool non_blocking, const NetProcessor::AcceptOptions &opt)
138 {
139 int res = 0;
140 int listen_per_thread = 0;
141
142 ink_assert(fd != NO_FD);
143
144 if (opt.etype == ET_NET && opt.defer_accept > 0) {
145 http_accept_filter = true;
146 add_http_filter(fd);
147 }
148
149 #ifdef SEND_BUF_SIZE
150 {
151 int send_buf_size = SEND_BUF_SIZE;
152 if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&send_buf_size, sizeof(int)) < 0)) {
153 goto Lerror;
154 }
155 }
156 #endif
157
158 #ifdef RECV_BUF_SIZE
159 {
160 int recv_buf_size = RECV_BUF_SIZE;
161 if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&recv_buf_size, sizeof(int))) < 0) {
162 goto Lerror;
163 }
164 }
165 #endif
166
167 if (opt.recv_bufsize) {
168 if (socketManager.set_rcvbuf_size(fd, opt.recv_bufsize)) {
169 // Round down until success
170 int rbufsz = ROUNDUP(opt.recv_bufsize, 1024);
171 while (rbufsz) {
172 if (socketManager.set_rcvbuf_size(fd, rbufsz)) {
173 rbufsz -= 1024;
174 } else {
175 break;
176 }
177 }
178 }
179 }
180
181 if (opt.send_bufsize) {
182 if (socketManager.set_sndbuf_size(fd, opt.send_bufsize)) {
183 // Round down until success
184 int sbufsz = ROUNDUP(opt.send_bufsize, 1024);
185 while (sbufsz) {
186 if (socketManager.set_sndbuf_size(fd, sbufsz)) {
187 sbufsz -= 1024;
188 } else {
189 break;
190 }
191 }
192 }
193 }
194
195 if (safe_fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
196 goto Lerror;
197 }
198
199 {
200 struct linger l;
201 l.l_onoff = 0;
202 l.l_linger = 0;
203 if ((opt.sockopt_flags & NetVCOptions::SOCK_OPT_LINGER_ON) &&
204 safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&l), sizeof(l)) < 0) {
205 goto Lerror;
206 }
207 }
208
209 if (ats_is_ip6(&addr) && safe_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, SOCKOPT_ON, sizeof(int)) < 0) {
210 goto Lerror;
211 }
212
213 if (safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, SOCKOPT_ON, sizeof(int)) < 0) {
214 goto Lerror;
215 }
216 REC_ReadConfigInteger(listen_per_thread, "proxy.config.exec_thread.listen");
217 if (listen_per_thread == 1) {
218 if (safe_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, SOCKOPT_ON, sizeof(int)) < 0) {
219 goto Lerror;
220 }
221 #ifdef SO_REUSEPORT_LB
222 if (safe_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, SOCKOPT_ON, sizeof(int)) < 0) {
223 goto Lerror;
224 }
225 #endif
226 }
227
228 if ((opt.sockopt_flags & NetVCOptions::SOCK_OPT_NO_DELAY) &&
229 safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, SOCKOPT_ON, sizeof(int)) < 0) {
230 goto Lerror;
231 }
232
233 // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
234 if ((opt.sockopt_flags & NetVCOptions::SOCK_OPT_KEEP_ALIVE) &&
235 safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, SOCKOPT_ON, sizeof(int)) < 0) {
236 goto Lerror;
237 }
238
239 #ifdef TCP_FASTOPEN
240 if ((opt.sockopt_flags & NetVCOptions::SOCK_OPT_TCP_FAST_OPEN) &&
241 safe_setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, (char *)&opt.tfo_queue_length, sizeof(int))) {
242 goto Lerror;
243 }
244 #endif
245
246 if (opt.f_inbound_transparent) {
247 #if TS_USE_TPROXY
248 Debug("http_tproxy", "Listen port inbound transparency enabled.");
249 if (safe_setsockopt(fd, SOL_IP, TS_IP_TRANSPARENT, SOCKOPT_ON, sizeof(int)) < 0) {
250 Fatal("[Server::listen] Unable to set transparent socket option [%d] %s\n", errno, strerror(errno));
251 }
252 #else
253 Error("[Server::listen] Transparency requested but TPROXY not configured\n");
254 #endif
255 }
256
257 if (opt.f_proxy_protocol) {
258 Debug("proxyprotocol", "Proxy Protocol enabled.");
259 }
260
261 #if defined(TCP_MAXSEG)
262 if (NetProcessor::accept_mss > 0) {
263 if (safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, reinterpret_cast<char *>(&NetProcessor::accept_mss), sizeof(int)) < 0) {
264 goto Lerror;
265 }
266 }
267 #endif
268
269 if (opt.f_mptcp) {
270 #if MPTCP_ENABLED
271 if (safe_setsockopt(fd, IPPROTO_TCP, MPTCP_ENABLED, SOCKOPT_ON, sizeof(int)) < 0) {
272 Error("[Server::listen] Unable to enable MPTCP socket-option [%d] %s\n", errno, strerror(errno));
273 goto Lerror;
274 }
275 #else
276 Error("[Server::listen] Multipath TCP requested but not configured on this host\n");
277 #endif
278 }
279
280 #ifdef TCP_DEFER_ACCEPT
281 // set tcp defer accept timeout if it is configured, this will not trigger an accept until there is
282 // data on the socket ready to be read
283 if (opt.defer_accept > 0 && setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &opt.defer_accept, sizeof(int)) < 0) {
284 // FIXME: should we go to the error
285 // goto error;
286 Error("[Server::listen] Defer accept is configured but set failed: %d", errno);
287 }
288 #endif
289
290 if (non_blocking) {
291 if (safe_nonblocking(fd) < 0) {
292 goto Lerror;
293 }
294 }
295
296 return 0;
297
298 Lerror:
299 res = -errno;
300
301 // coverity[check_after_sink]
302 if (fd != NO_FD) {
303 close();
304 }
305
306 return res;
307 }
308
309 int
listen(bool non_blocking,const NetProcessor::AcceptOptions & opt)310 Server::listen(bool non_blocking, const NetProcessor::AcceptOptions &opt)
311 {
312 ink_assert(fd == NO_FD);
313 int res = 0;
314 int namelen;
315
316 if (!ats_is_ip(&accept_addr)) {
317 ats_ip4_set(&addr, INADDR_ANY, 0);
318 } else {
319 ats_ip_copy(&addr, &accept_addr);
320 }
321
322 fd = res = socketManager.socket(addr.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
323 if (res < 0) {
324 goto Lerror;
325 }
326
327 res = setup_fd_for_listen(non_blocking, opt);
328 if (res < 0) {
329 goto Lerror;
330 }
331
332 if ((res = socketManager.ink_bind(fd, &addr.sa, ats_ip_size(&addr.sa), IPPROTO_TCP)) < 0) {
333 goto Lerror;
334 }
335
336 if ((res = safe_listen(fd, get_listen_backlog())) < 0) {
337 goto Lerror;
338 }
339
340 // Original just did this on port == 0.
341 namelen = sizeof(addr);
342 if ((res = safe_getsockname(fd, &addr.sa, &namelen))) {
343 goto Lerror;
344 }
345
346 return 0;
347
348 Lerror:
349 if (fd != NO_FD) {
350 close();
351 fd = NO_FD;
352 }
353
354 Error("Could not bind or listen to port %d (error: %d)", ats_ip_port_host_order(&addr), res);
355 return res;
356 }
357