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 #include "net/socket/socket_descriptor.h" 27 28 using std::string; 29 30 namespace net { 31 32 // static 33 scoped_ptr<TCPListenSocket> TCPListenSocket::CreateAndListen( 34 const string& ip, int port, StreamListenSocket::Delegate* del) { 35 SocketDescriptor s = CreateAndBind(ip, port); 36 if (s == kInvalidSocket) 37 return scoped_ptr<TCPListenSocket>(); 38 scoped_ptr<TCPListenSocket> sock(new TCPListenSocket(s, del)); 39 sock->Listen(); 40 return sock.Pass(); 41 } 42 43 TCPListenSocket::TCPListenSocket(SocketDescriptor s, 44 StreamListenSocket::Delegate* del) 45 : StreamListenSocket(s, del) { 46 } 47 48 TCPListenSocket::~TCPListenSocket() {} 49 50 SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, int port) { 51 SocketDescriptor s = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 52 if (s != kInvalidSocket) { 53 #if defined(OS_POSIX) 54 // Allow rapid reuse. 55 static const int kOn = 1; 56 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 57 #endif 58 sockaddr_in addr; 59 memset(&addr, 0, sizeof(addr)); 60 addr.sin_family = AF_INET; 61 addr.sin_addr.s_addr = inet_addr(ip.c_str()); 62 addr.sin_port = base::HostToNet16(port); 63 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) { 64 #if defined(OS_WIN) 65 closesocket(s); 66 #elif defined(OS_POSIX) 67 close(s); 68 #endif 69 LOG(ERROR) << "Could not bind socket to " << ip << ":" << port; 70 s = kInvalidSocket; 71 } 72 } 73 return s; 74 } 75 76 SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip, 77 int* port) { 78 SocketDescriptor s = CreateAndBind(ip, 0); 79 if (s == kInvalidSocket) 80 return kInvalidSocket; 81 sockaddr_in addr; 82 socklen_t addr_size = sizeof(addr); 83 bool failed = getsockname(s, reinterpret_cast<struct sockaddr*>(&addr), 84 &addr_size) != 0; 85 if (addr_size != sizeof(addr)) 86 failed = true; 87 if (failed) { 88 LOG(ERROR) << "Could not determine bound port, getsockname() failed"; 89 #if defined(OS_WIN) 90 closesocket(s); 91 #elif defined(OS_POSIX) 92 close(s); 93 #endif 94 return kInvalidSocket; 95 } 96 *port = base::NetToHost16(addr.sin_port); 97 return s; 98 } 99 100 void TCPListenSocket::Accept() { 101 SocketDescriptor conn = AcceptSocket(); 102 if (conn == kInvalidSocket) 103 return; 104 scoped_ptr<TCPListenSocket> sock( 105 new TCPListenSocket(conn, socket_delegate_)); 106 // It's up to the delegate to AddRef if it wants to keep it around. 107 #if defined(OS_POSIX) 108 sock->WatchSocket(WAITING_READ); 109 #endif 110 socket_delegate_->DidAccept(this, sock.PassAs<StreamListenSocket>()); 111 } 112 113 TCPListenSocketFactory::TCPListenSocketFactory(const string& ip, int port) 114 : ip_(ip), 115 port_(port) { 116 } 117 118 TCPListenSocketFactory::~TCPListenSocketFactory() {} 119 120 scoped_ptr<StreamListenSocket> TCPListenSocketFactory::CreateAndListen( 121 StreamListenSocket::Delegate* delegate) const { 122 return TCPListenSocket::CreateAndListen(ip_, port_, delegate) 123 .PassAs<StreamListenSocket>(); 124 } 125 126 } // namespace net 127