1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/tools/flip_server/create_listener.h"
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
18 #include "base/logging.h"
22 // used to ensure we delete the addrinfo structure
23 // alloc'd by getaddrinfo
26 struct addrinfo
* addrinfo_ptr_
;
29 explicit AddrinfoGuard(struct addrinfo
* addrinfo_ptr
)
30 : addrinfo_ptr_(addrinfo_ptr
) {}
32 ~AddrinfoGuard() { freeaddrinfo(addrinfo_ptr_
); }
36 // Closes a socket, with option to attempt it multiple times.
37 // Why do this? Well, if the system-call gets interrupted, close
38 // can fail with EINTR. In that case you should just retry.. Unfortunately,
39 // we can't be sure that errno is properly set since we're using a
40 // multithreaded approach in the filter proxy, so we should just retry.
42 // fd - the socket to close
43 // tries - the number of tries to close the socket.
45 // true - if socket was closed
46 // false - if socket was NOT closed.
48 // sets *fd to -1 if socket was closed.
50 bool CloseSocket(int* fd
, int tries
) {
51 for (int i
= 0; i
< tries
; ++i
) {
60 // Sets an FD to be nonblocking.
61 void FlipSetNonBlocking(int fd
) {
64 int fcntl_return
= fcntl(fd
, F_GETFL
, 0);
65 CHECK_NE(fcntl_return
, -1) << "error doing fcntl(fd, F_GETFL, 0) fd: " << fd
66 << " errno=" << errno
;
68 if (fcntl_return
& O_NONBLOCK
)
71 fcntl_return
= fcntl(fd
, F_SETFL
, fcntl_return
| O_NONBLOCK
);
72 CHECK_NE(fcntl_return
, -1)
73 << "error doing fcntl(fd, F_SETFL, fcntl_return) fd: " << fd
74 << " errno=" << errno
;
77 int SetDisableNagle(int fd
) {
81 fd
, IPPROTO_TCP
, TCP_NODELAY
, reinterpret_cast<char*>(&on
), sizeof(on
));
84 LOG(FATAL
) << "setsockopt() TCP_NODELAY: failed on fd " << fd
;
90 // see header for documentation of this function.
91 int CreateListeningSocket(const std::string
& host
,
92 const std::string
& port
,
93 bool is_numeric_host_address
,
100 // start out by assuming things will fail.
103 const char* node
= NULL
;
104 const char* service
= NULL
;
109 service
= port
.c_str();
111 struct addrinfo
* results
= 0;
112 struct addrinfo hints
;
113 memset(&hints
, 0, sizeof(hints
));
115 if (is_numeric_host_address
) {
116 hints
.ai_flags
= AI_NUMERICHOST
; // iff you know the name is numeric.
118 hints
.ai_flags
|= AI_PASSIVE
;
120 hints
.ai_family
= PF_INET
;
121 hints
.ai_socktype
= SOCK_STREAM
;
124 if ((err
= getaddrinfo(node
, service
, &hints
, &results
))) {
125 // gai_strerror -is- threadsafe, so we get to use it here.
126 LOG(ERROR
) << "getaddrinfo "
127 << " for (" << host
<< ":" << port
<< ") " << gai_strerror(err
)
131 // this will delete the addrinfo memory when we return from this function.
132 AddrinfoGuard
addrinfo_guard(results
);
135 socket(results
->ai_family
, results
->ai_socktype
, results
->ai_protocol
);
137 LOG(ERROR
) << "Unable to create socket for (" << host
<< ":" << port
138 << "): " << strerror(errno
) << "\n";
143 // set SO_REUSEADDR on the listening socket.
146 rc
= setsockopt(sock
,
149 reinterpret_cast<char*>(&on
),
153 LOG(FATAL
) << "setsockopt() failed fd=" << listen_fd
<< "\n";
157 #define SO_REUSEPORT 15
160 // set SO_REUSEADDR on the listening socket.
163 rc
= setsockopt(sock
,
166 reinterpret_cast<char*>(&on
),
170 LOG(FATAL
) << "setsockopt() failed fd=" << listen_fd
<< "\n";
174 if (bind(sock
, results
->ai_addr
, results
->ai_addrlen
)) {
175 // If we are waiting for the interface to be raised, such as in an
176 // HA environment, ignore reporting any errors.
177 int saved_errno
= errno
;
178 if (!wait_for_iface
|| errno
!= EADDRNOTAVAIL
) {
179 LOG(ERROR
) << "Bind was unsuccessful for (" << host
<< ":" << port
180 << "): " << strerror(errno
) << "\n";
182 // if we knew that we were not multithreaded, we could do the following:
183 // " : " << strerror(errno) << "\n";
184 if (CloseSocket(&sock
, 100)) {
185 if (saved_errno
== EADDRNOTAVAIL
) {
190 // couldn't even close the dang socket?!
191 LOG(ERROR
) << "Unable to close the socket.. Considering this a fatal "
192 "error, and exiting\n";
199 if (!SetDisableNagle(sock
)) {
204 if (listen(sock
, backlog
)) {
205 // listen was unsuccessful.
206 LOG(ERROR
) << "Listen was unsuccessful for (" << host
<< ":" << port
207 << "): " << strerror(errno
) << "\n";
208 // if we knew that we were not multithreaded, we could do the following:
209 // " : " << strerror(errno) << "\n";
211 if (CloseSocket(&sock
, 100)) {
215 // couldn't even close the dang socket?!
216 LOG(FATAL
) << "Unable to close the socket.. Considering this a fatal "
217 "error, and exiting\n";
221 // If we've gotten to here, Yeay! Success!
227 int CreateConnectedSocket(int* connect_fd
,
228 const std::string
& host
,
229 const std::string
& port
,
230 bool is_numeric_host_address
,
231 bool disable_nagle
) {
232 const char* node
= NULL
;
233 const char* service
= NULL
;
239 service
= port
.c_str();
241 struct addrinfo
* results
= 0;
242 struct addrinfo hints
;
243 memset(&hints
, 0, sizeof(hints
));
245 if (is_numeric_host_address
)
246 hints
.ai_flags
= AI_NUMERICHOST
; // iff you know the name is numeric.
247 hints
.ai_flags
|= AI_PASSIVE
;
249 hints
.ai_family
= PF_INET
;
250 hints
.ai_socktype
= SOCK_STREAM
;
253 if ((err
= getaddrinfo(node
, service
, &hints
, &results
))) {
254 // gai_strerror -is- threadsafe, so we get to use it here.
255 LOG(ERROR
) << "getaddrinfo for (" << node
<< ":" << service
256 << "): " << gai_strerror(err
);
259 // this will delete the addrinfo memory when we return from this function.
260 AddrinfoGuard
addrinfo_guard(results
);
263 socket(results
->ai_family
, results
->ai_socktype
, results
->ai_protocol
);
265 LOG(ERROR
) << "Unable to create socket for (" << node
<< ":" << service
266 << "): " << strerror(errno
);
270 FlipSetNonBlocking(sock
);
273 if (!SetDisableNagle(sock
)) {
279 if (connect(sock
, results
->ai_addr
, results
->ai_addrlen
)) {
280 if (errno
!= EINPROGRESS
) {
281 LOG(ERROR
) << "Connect was unsuccessful for (" << node
<< ":" << service
282 << "): " << strerror(errno
);
290 // If we've gotten to here, Yeay! Success!