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