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