tcp_listen_socket.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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 27using std::string; 28 29namespace net { 30 31// static 32scoped_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 42TCPListenSocket::TCPListenSocket(SocketDescriptor s, 43 StreamListenSocket::Delegate* del) 44 : StreamListenSocket(s, del) { 45} 46 47TCPListenSocket::~TCPListenSocket() {} 48 49SocketDescriptor 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 79SocketDescriptor 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 103void 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 116TCPListenSocketFactory::TCPListenSocketFactory(const string& ip, int port) 117 : ip_(ip), 118 port_(port) { 119} 120 121TCPListenSocketFactory::~TCPListenSocketFactory() {} 122 123scoped_refptr<StreamListenSocket> TCPListenSocketFactory::CreateAndListen( 124 StreamListenSocket::Delegate* delegate) const { 125 return TCPListenSocket::CreateAndListen(ip_, port_, delegate); 126} 127 128} // namespace net 129