[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 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_server_socket_win.h" |
| 6 | |
| 7 | #include <mstcpip.h> |
| 8 | |
| 9 | #include "net/base/ip_endpoint.h" |
| 10 | #include "net/base/net_errors.h" |
| 11 | #include "net/base/net_util.h" |
| 12 | #include "net/base/winsock_init.h" |
| 13 | #include "net/base/winsock_util.h" |
[email protected] | 3aa4af04 | 2012-06-14 21:02:31 | [diff] [blame] | 14 | #include "net/socket/socket_net_log_params.h" |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 15 | #include "net/socket/tcp_client_socket.h" |
| 16 | |
| 17 | namespace net { |
| 18 | |
| 19 | TCPServerSocketWin::TCPServerSocketWin(net::NetLog* net_log, |
| 20 | const net::NetLog::Source& source) |
| 21 | : socket_(INVALID_SOCKET), |
| 22 | socket_event_(WSA_INVALID_EVENT), |
| 23 | accept_socket_(NULL), |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 24 | net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { |
[email protected] | 3aa4af04 | 2012-06-14 21:02:31 | [diff] [blame] | 25 | net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, |
| 26 | source.ToEventParametersCallback()); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 27 | EnsureWinsockInit(); |
| 28 | } |
| 29 | |
| 30 | TCPServerSocketWin::~TCPServerSocketWin() { |
| 31 | Close(); |
[email protected] | 3aa4af04 | 2012-06-14 21:02:31 | [diff] [blame] | 32 | net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 33 | } |
| 34 | |
| 35 | int TCPServerSocketWin::Listen(const IPEndPoint& address, int backlog) { |
| 36 | DCHECK(CalledOnValidThread()); |
| 37 | DCHECK_GT(backlog, 0); |
| 38 | DCHECK_EQ(socket_, INVALID_SOCKET); |
| 39 | DCHECK_EQ(socket_event_, WSA_INVALID_EVENT); |
| 40 | |
| 41 | socket_event_ = WSACreateEvent(); |
| 42 | if (socket_event_ == WSA_INVALID_EVENT) { |
| 43 | PLOG(ERROR) << "WSACreateEvent()"; |
| 44 | return ERR_FAILED; |
| 45 | } |
| 46 | |
[email protected] | 03ec2538 | 2011-05-27 21:50:28 | [diff] [blame] | 47 | socket_ = socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 48 | if (socket_ < 0) { |
| 49 | PLOG(ERROR) << "socket() returned an error"; |
| 50 | return MapSystemError(WSAGetLastError()); |
| 51 | } |
| 52 | |
| 53 | if (SetNonBlocking(socket_)) { |
| 54 | int result = MapSystemError(WSAGetLastError()); |
| 55 | Close(); |
| 56 | return result; |
| 57 | } |
| 58 | |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 59 | SockaddrStorage storage; |
| 60 | if (!address.ToSockAddr(storage.addr, &storage.addr_len)) |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 61 | return ERR_INVALID_ARGUMENT; |
| 62 | |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 63 | int result = bind(socket_, storage.addr, storage.addr_len); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 64 | if (result < 0) { |
| 65 | PLOG(ERROR) << "bind() returned an error"; |
| 66 | result = MapSystemError(WSAGetLastError()); |
| 67 | Close(); |
| 68 | return result; |
| 69 | } |
| 70 | |
| 71 | result = listen(socket_, backlog); |
| 72 | if (result < 0) { |
| 73 | PLOG(ERROR) << "listen() returned an error"; |
| 74 | result = MapSystemError(WSAGetLastError()); |
| 75 | Close(); |
| 76 | return result; |
| 77 | } |
| 78 | |
| 79 | return OK; |
| 80 | } |
| 81 | |
| 82 | int TCPServerSocketWin::GetLocalAddress(IPEndPoint* address) const { |
| 83 | DCHECK(CalledOnValidThread()); |
| 84 | DCHECK(address); |
| 85 | |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 86 | SockaddrStorage storage; |
| 87 | if (getsockname(socket_, storage.addr, &storage.addr_len)) |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 88 | return MapSystemError(WSAGetLastError()); |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 89 | if (!address->FromSockAddr(storage.addr, storage.addr_len)) |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 90 | return ERR_FAILED; |
| 91 | |
| 92 | return OK; |
| 93 | } |
| 94 | |
| 95 | int TCPServerSocketWin::Accept( |
[email protected] | df7a30d | 2011-12-03 04:16:50 | [diff] [blame] | 96 | scoped_ptr<StreamSocket>* socket, const CompletionCallback& callback) { |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 97 | DCHECK(CalledOnValidThread()); |
| 98 | DCHECK(socket); |
[email protected] | df7a30d | 2011-12-03 04:16:50 | [diff] [blame] | 99 | DCHECK(!callback.is_null()); |
| 100 | DCHECK(accept_callback_.is_null()); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 101 | |
[email protected] | 3aa4af04 | 2012-06-14 21:02:31 | [diff] [blame] | 102 | net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 103 | |
| 104 | int result = AcceptInternal(socket); |
| 105 | |
| 106 | if (result == ERR_IO_PENDING) { |
| 107 | // Start watching |
| 108 | WSAEventSelect(socket_, socket_event_, FD_ACCEPT); |
| 109 | accept_watcher_.StartWatching(socket_event_, this); |
| 110 | |
| 111 | accept_socket_ = socket; |
| 112 | accept_callback_ = callback; |
| 113 | } |
| 114 | |
| 115 | return result; |
| 116 | } |
| 117 | |
[email protected] | 3268023f | 2011-05-05 00:08:10 | [diff] [blame] | 118 | int TCPServerSocketWin::AcceptInternal(scoped_ptr<StreamSocket>* socket) { |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 119 | SockaddrStorage storage; |
| 120 | int new_socket = accept(socket_, storage.addr, &storage.addr_len); |
[email protected] | 03ec2538 | 2011-05-27 21:50:28 | [diff] [blame] | 121 | if (new_socket < 0) { |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 122 | int net_error = MapSystemError(WSAGetLastError()); |
| 123 | if (net_error != ERR_IO_PENDING) |
| 124 | net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error); |
| 125 | return net_error; |
| 126 | } |
| 127 | |
| 128 | IPEndPoint address; |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 129 | if (!address.FromSockAddr(storage.addr, storage.addr_len)) { |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 130 | NOTREACHED(); |
[email protected] | 03ec2538 | 2011-05-27 21:50:28 | [diff] [blame] | 131 | if (closesocket(new_socket) < 0) |
[email protected] | a75c745 | 2011-04-18 23:19:38 | [diff] [blame] | 132 | PLOG(ERROR) << "closesocket"; |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 133 | net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED); |
| 134 | return ERR_FAILED; |
| 135 | } |
[email protected] | 03ec2538 | 2011-05-27 21:50:28 | [diff] [blame] | 136 | scoped_ptr<TCPClientSocket> tcp_socket(new TCPClientSocket( |
[email protected] | 7054e78f | 2012-05-07 21:44:56 | [diff] [blame] | 137 | AddressList(address), |
[email protected] | 03ec2538 | 2011-05-27 21:50:28 | [diff] [blame] | 138 | net_log_.net_log(), net_log_.source())); |
| 139 | int adopt_result = tcp_socket->AdoptSocket(new_socket); |
| 140 | if (adopt_result != OK) { |
| 141 | if (closesocket(new_socket) < 0) |
| 142 | PLOG(ERROR) << "closesocket"; |
| 143 | net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result); |
| 144 | return adopt_result; |
| 145 | } |
| 146 | socket->reset(tcp_socket.release()); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 147 | net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT, |
[email protected] | 3aa4af04 | 2012-06-14 21:02:31 | [diff] [blame] | 148 | CreateNetLogIPEndPointCallback(&address)); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 149 | return OK; |
| 150 | } |
| 151 | |
| 152 | void TCPServerSocketWin::Close() { |
| 153 | if (socket_ != INVALID_SOCKET) { |
[email protected] | a75c745 | 2011-04-18 23:19:38 | [diff] [blame] | 154 | if (closesocket(socket_) < 0) |
| 155 | PLOG(ERROR) << "closesocket"; |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 156 | socket_ = INVALID_SOCKET; |
| 157 | } |
| 158 | |
| 159 | if (socket_event_) { |
| 160 | WSACloseEvent(socket_event_); |
| 161 | socket_event_ = WSA_INVALID_EVENT; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | void TCPServerSocketWin::OnObjectSignaled(HANDLE object) { |
| 166 | WSANETWORKEVENTS ev; |
| 167 | if (WSAEnumNetworkEvents(socket_, socket_event_, &ev) == SOCKET_ERROR) { |
| 168 | PLOG(ERROR) << "WSAEnumNetworkEvents()"; |
| 169 | return; |
| 170 | } |
| 171 | |
| 172 | if (ev.lNetworkEvents & FD_ACCEPT) { |
| 173 | int result = AcceptInternal(accept_socket_); |
| 174 | if (result != ERR_IO_PENDING) { |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 175 | accept_socket_ = NULL; |
[email protected] | e756022 | 2012-03-31 00:35:38 | [diff] [blame] | 176 | CompletionCallback callback = accept_callback_; |
[email protected] | df7a30d | 2011-12-03 04:16:50 | [diff] [blame] | 177 | accept_callback_.Reset(); |
[email protected] | e756022 | 2012-03-31 00:35:38 | [diff] [blame] | 178 | callback.Run(result); |
[email protected] | 3871252 | 2011-04-18 23:03:32 | [diff] [blame] | 179 | } |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | } // namespace net |