1 // Copyright (c) 2012 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. 4 5 #include "net/socket/tcp_listen_socket.h" 6 7 #if defined(OS_WIN) 8 // winsock2.h must be included first in order to ensure it is included before 9 // windows.h. 10 #include <winsock2.h> 11 #elif defined(OS_POSIX) 12 #include <arpa/inet.h> 13 #include <errno.h> 14 #include <netinet/in.h> 15 #include <sys/socket.h> 16 #include <sys/types.h> 17 #include "net/base/net_errors.h" 18 #endif 19 20 #include "base/logging.h" 21 #include "base/sys_byteorder.h" 22 #include "base/threading/platform_thread.h" 23 #include "build/build_config.h" 24 #include "net/base/net_util.h" 25 #include "net/base/winsock_init.h" 26 27 using std::string; 28 29 namespace net { 30 31 // static 32 scoped_refptr<TCPListenSocket> TCPListenSocket::CreateAndListen( 33 const string& ip, int port, StreamListenSocket::Delegate* del) { 34 SocketDescriptor s = CreateAndBind(ip, port); 35 if (s == kInvalidSocket) 36 return NULL; 37 scoped_refptr<TCPListenSocket> sock(new TCPListenSocket(s, del)); 38 sock->Listen(); 39 return sock; 40 } 41 42 TCPListenSocket::TCPListenSocket(SocketDescriptor s, 43 StreamListenSocket::Delegate* del) 44 : StreamListenSocket(s, del) { 45 } 46 47 TCPListenSocket::~TCPListenSocket() {} 48 49 SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, int port) { 50 #if defined(OS_WIN) 51 EnsureWinsockInit(); 52 #endif 53 54 SocketDescriptor s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 55 if (s != kInvalidSocket) { 56 #if defined(OS_POSIX) 57 // Allow rapid reuse. 58 static const int kOn = 1; 59 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 60 #endif 61 sockaddr_in addr; 62 memset(&addr, 0, sizeof(addr)); 63 addr.sin_family = AF_INET; 64 addr.sin_addr.s_addr = inet_addr(ip.c_str()); 65 addr.sin_port = base::HostToNet16(port); 66 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) { 67 #if defined(OS_WIN) 68 closesocket(s); 69 #elif defined(OS_POSIX) 70 close(s); 71 #endif 72 LOG(ERROR) << "Could not bind socket to " << ip << ":" << port; 73 s = kInvalidSocket; 74 } 75 } 76 return s; 77 } 78 79 SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip, 80 int* port) { 81 SocketDescriptor s = CreateAndBind(ip, 0); 82 if (s == kInvalidSocket) 83 return kInvalidSocket; 84 sockaddr_in addr; 85 socklen_t addr_size = sizeof(addr); 86 bool failed = getsockname(s, reinterpret_cast<struct sockaddr*>(&addr), 87 &addr_size) != 0; 88 if (addr_size != sizeof(addr)) 89 failed = true; 90 if (failed) { 91 LOG(ERROR) << "Could not determine bound port, getsockname() failed"; 92 #if defined(OS_WIN) 93 closesocket(s); 94 #elif defined(OS_POSIX) 95 close(s); 96 #endif 97 return kInvalidSocket; 98 } 99 *port = base::NetToHost16(addr.sin_port); 100 return s; 101 } 102 103 void TCPListenSocket::Accept() { 104 SocketDescriptor conn = AcceptSocket(); 105 if (conn == kInvalidSocket) 106 return; 107 scoped_refptr<TCPListenSocket> sock( 108 new TCPListenSocket(conn, socket_delegate_)); 109 // It's up to the delegate to AddRef if it wants to keep it around. 110 #if defined(OS_POSIX) 111 sock->WatchSocket(WAITING_READ); 112 #endif 113 socket_delegate_->DidAccept(this, sock.get()); 114 } 115 116 TCPListenSocketFactory::TCPListenSocketFactory(const string& ip, int port) 117 : ip_(ip), 118 port_(port) { 119 } 120 121 TCPListenSocketFactory::~TCPListenSocketFactory() {} 122 123 scoped_refptr<StreamListenSocket> TCPListenSocketFactory::CreateAndListen( 124 StreamListenSocket::Delegate* delegate) const { 125 return TCPListenSocket::CreateAndListen(ip_, port_, delegate); 126 } 127 128 } // namespace net 129