1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "net/tools/flip_server/create_listener.h"
672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <arpa/inet.h>   // for inet_ntop
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <errno.h>       // for strerror
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <netdb.h>       // for getaddrinfo and getnameinfo
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <netinet/in.h>  // for IPPROTO_*, etc.
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdlib.h>      // for EXIT_FAILURE
12201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <netinet/tcp.h> // For TCP_NODELAY
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/socket.h>  // for getaddrinfo and getnameinfo
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/types.h>   // "
15201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <fcntl.h>
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <unistd.h>      // for exit()
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <ostream>
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// used to ensure we delete the addrinfo structure
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// alloc'd by getaddrinfo
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass AddrinfoGuard {
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott protected:
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  struct addrinfo * addrinfo_ptr_;
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  explicit AddrinfoGuard(struct addrinfo* addrinfo_ptr) :
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    addrinfo_ptr_(addrinfo_ptr) {}
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~AddrinfoGuard() {
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    freeaddrinfo(addrinfo_ptr_);
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott////////////////////////////////////////////////////////////////////////////////
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott////////////////////////////////////////////////////////////////////////////////
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Summary:
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   Closes a socket, with option to attempt it multiple times.
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   Why do this? Well, if the system-call gets interrupted, close
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   can fail with EINTR. In that case you should just retry.. Unfortunately,
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   we can't be sure that errno is properly set since we're using a
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   multithreaded approach in the filter proxy, so we should just retry.
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Args:
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   fd - the socket to close
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   tries - the number of tries to close the socket.
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Returns:
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   true - if socket was closed
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   false - if socket was NOT closed.
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Side-effects:
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   sets *fd to -1 if socket was closed.
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool CloseSocket(int *fd, int tries) {
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < tries; ++i) {
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!close(*fd)) {
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      *fd = -1;
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return true;
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false;
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott////////////////////////////////////////////////////////////////////////////////
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott////////////////////////////////////////////////////////////////////////////////
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
69201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Sets an FD to be nonblocking.
70201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid SetNonBlocking(int fd) {
71201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_GE(fd, 0);
72201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
73201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int fcntl_return = fcntl(fd, F_GETFL, 0);
74201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  CHECK_NE(fcntl_return, -1)
75201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    << "error doing fcntl(fd, F_GETFL, 0) fd: " << fd
76201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    << " errno=" << errno;
77201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
78201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (fcntl_return & O_NONBLOCK)
79201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return;
80201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
81201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  fcntl_return = fcntl(fd, F_SETFL, fcntl_return | O_NONBLOCK);
82201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  CHECK_NE(fcntl_return, -1)
83201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    << "error doing fcntl(fd, F_SETFL, fcntl_return) fd: " << fd
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    << " errno=" << errno;
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
86201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
87201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochint SetDisableNagle(int fd) {
88201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int on = 1;
89201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int rc;
90201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  rc = setsockopt(fd, IPPROTO_TCP,  TCP_NODELAY,
91201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  reinterpret_cast<char*>(&on), sizeof(on));
92201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (rc < 0) {
93201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    close(fd);
94201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(FATAL) << "setsockopt() TCP_NODELAY: failed on fd " << fd;
95201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return 0;
96201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
97201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return 1;
98201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
99201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// see header for documentation of this function.
101201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochint CreateListeningSocket(const std::string& host,
102201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          const std::string& port,
103201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          bool is_numeric_host_address,
104201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          int backlog,
105201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          bool reuseaddr,
106201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          bool reuseport,
107201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          bool wait_for_iface,
108201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          bool disable_nagle,
109201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          int * listen_fd ) {
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // start out by assuming things will fail.
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *listen_fd = -1;
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char* node = NULL;
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char* service = NULL;
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!host.empty()) node = host.c_str();
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!port.empty()) service = port.c_str();
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  struct addrinfo *results = 0;
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  struct addrinfo hints;
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memset(&hints, 0, sizeof(hints));
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (is_numeric_host_address) {
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    hints.ai_flags = AI_NUMERICHOST;  // iff you know the name is numeric.
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  hints.ai_flags |= AI_PASSIVE;
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  hints.ai_family = PF_INET;
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  hints.ai_socktype = SOCK_STREAM;
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int err = 0;
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if ((err=getaddrinfo(node, service, &hints, &results))) {
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // gai_strerror -is- threadsafe, so we get to use it here.
134201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(ERROR) << "getaddrinfo " << " for (" << host << ":" << port
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  << ") " << gai_strerror(err) << "\n";
136201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return -1;
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // this will delete the addrinfo memory when we return from this function.
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AddrinfoGuard addrinfo_guard(results);
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int sock = socket(results->ai_family,
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    results->ai_socktype,
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    results->ai_protocol);
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (sock == -1) {
145201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(ERROR) << "Unable to create socket for (" << host << ":"
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      << port << "): " << strerror(errno) << "\n";
147201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return -1;
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (reuseaddr) {
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // set SO_REUSEADDR on the listening socket.
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int on = 1;
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rc;
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rc = setsockopt(sock, SOL_SOCKET,  SO_REUSEADDR,
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    reinterpret_cast<char *>(&on), sizeof(on));
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rc < 0) {
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      close(sock);
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(FATAL) << "setsockopt() failed fd=" << listen_fd << "\n";
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifndef SO_REUSEPORT
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define SO_REUSEPORT 15
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (reuseport) {
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // set SO_REUSEADDR on the listening socket.
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int on = 1;
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rc;
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rc = setsockopt(sock, SOL_SOCKET,  SO_REUSEPORT,
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    reinterpret_cast<char *>(&on), sizeof(on));
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rc < 0) {
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      close(sock);
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(FATAL) << "setsockopt() failed fd=" << listen_fd << "\n";
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bind(sock, results->ai_addr, results->ai_addrlen)) {
177201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // If we are waiting for the interface to be raised, such as in an
178201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // HA environment, ignore reporting any errors.
179201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int saved_errno = errno;
180201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if ( !wait_for_iface || errno != EADDRNOTAVAIL) {
181201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "Bind was unsuccessful for (" << host << ":"
182201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        << port << "): " << strerror(errno) << "\n";
183201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // if we knew that we were not multithreaded, we could do the following:
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // " : " << strerror(errno) << "\n";
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (CloseSocket(&sock, 100)) {
187201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      if ( saved_errno == EADDRNOTAVAIL ) {
188201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        return -3;
189201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      }
190201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return -2;
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // couldn't even close the dang socket?!
193201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "Unable to close the socket.. Considering this a fatal "
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      "error, and exiting\n";
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      exit(EXIT_FAILURE);
196201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return -1;
197201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
198201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
199201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
200201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (disable_nagle) {
201201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (!SetDisableNagle(sock)) {
202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return -1;
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (listen(sock, backlog)) {
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // listen was unsuccessful.
208201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(ERROR) << "Listen was unsuccessful for (" << host << ":"
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      << port << "): " << strerror(errno) << "\n";
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // if we knew that we were not multithreaded, we could do the following:
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // " : " << strerror(errno) << "\n";
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (CloseSocket(&sock, 100)) {
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      sock = -1;
215201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return -1;
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // couldn't even close the dang socket?!
218201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(FATAL) << "Unable to close the socket.. Considering this a fatal "
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      "error, and exiting\n";
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
222201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If we've gotten to here, Yeay! Success!
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *listen_fd = sock;
225201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
226201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return 0;
227201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
228201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
229201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochint CreateConnectedSocket( int *connect_fd,
230201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                           const std::string& host,
231201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                           const std::string& port,
232201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                           bool is_numeric_host_address,
233201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                           bool disable_nagle ) {
234201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  const char* node = NULL;
235201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  const char* service = NULL;
236201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
237201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  *connect_fd = -1;
238201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!host.empty())
239201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    node = host.c_str();
240201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!port.empty())
241201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    service = port.c_str();
242201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
243201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  struct addrinfo *results = 0;
244201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  struct addrinfo hints;
245201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  memset(&hints, 0, sizeof(hints));
246201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
247201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (is_numeric_host_address)
248201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    hints.ai_flags = AI_NUMERICHOST;  // iff you know the name is numeric.
249201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  hints.ai_flags |= AI_PASSIVE;
250201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  hints.ai_family = PF_INET;
252201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  hints.ai_socktype = SOCK_STREAM;
253201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
254201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int err = 0;
255201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if ((err=getaddrinfo(node, service, &hints, &results))) {
256201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // gai_strerror -is- threadsafe, so we get to use it here.
257201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(ERROR) << "getaddrinfo for (" << node << ":" << service << "): "
258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch               << gai_strerror(err);
259201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return -1;
260201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
261201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // this will delete the addrinfo memory when we return from this function.
262201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  AddrinfoGuard addrinfo_guard(results);
263201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
264201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int sock = socket(results->ai_family,
265201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                    results->ai_socktype,
266201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                    results->ai_protocol);
267201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (sock == -1) {
268201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(ERROR) << "Unable to create socket for (" << node << ":" << service
269201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch               << "): " << strerror( errno );
270201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return -1;
271201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
272201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
273201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SetNonBlocking( sock );
274201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
275201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (disable_nagle) {
276201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (!SetDisableNagle(sock)) {
277201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return -1;
278201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
280201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
281201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int ret_val = 0;
282201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if ( connect( sock, results->ai_addr, results->ai_addrlen ) ) {
283201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if ( errno != EINPROGRESS ) {
284201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "Connect was unsuccessful for (" << node << ":" << service
285201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 << "): " << strerror(errno);
286201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      close( sock );
287201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return -1;
288201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
289201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  } else {
290201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    ret_val = 1;
291201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
292201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
293201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // If we've gotten to here, Yeay! Success!
294201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  *connect_fd = sock;
295201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
296201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return ret_val;
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
301