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