OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "net/base/tcp_listen_socket.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 // winsock2.h must be included first in order to ensure it is included before | 8 // winsock2.h must be included first in order to ensure it is included before |
9 // windows.h. | 9 // windows.h. |
10 #include <winsock2.h> | 10 #include <winsock2.h> |
11 #elif defined(OS_POSIX) | 11 #elif defined(OS_POSIX) |
12 #include <errno.h> | 12 #include <errno.h> |
13 #include <sys/types.h> | 13 #include <sys/types.h> |
14 #include <sys/socket.h> | 14 #include <sys/socket.h> |
15 #include <netinet/in.h> | 15 #include <netinet/in.h> |
16 #include <arpa/inet.h> | 16 #include <arpa/inet.h> |
17 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
18 #endif | 18 #endif |
19 | 19 |
20 #include "build/build_config.h" | |
20 #include "base/eintr_wrapper.h" | 21 #include "base/eintr_wrapper.h" |
22 #include "base/logging.h" | |
21 #include "base/sys_byteorder.h" | 23 #include "base/sys_byteorder.h" |
22 #include "base/threading/platform_thread.h" | 24 #include "base/threading/platform_thread.h" |
23 #include "net/base/net_util.h" | 25 #include "net/base/net_util.h" |
24 #include "net/base/tcp_listen_socket.h" | |
25 | 26 |
26 #if defined(OS_WIN) | 27 using std::string; |
27 typedef int socklen_t; | |
28 #endif // defined(OS_WIN) | |
29 | 28 |
30 namespace net { | 29 namespace net { |
31 | 30 |
32 namespace { | |
33 | |
34 const int kReadBufSize = 4096; | |
35 | |
36 } // namespace | |
37 | |
38 #if defined(OS_WIN) | |
39 const SOCKET TCPListenSocket::kInvalidSocket = INVALID_SOCKET; | |
40 const int TCPListenSocket::kSocketError = SOCKET_ERROR; | |
41 #elif defined(OS_POSIX) | |
42 const SOCKET TCPListenSocket::kInvalidSocket = -1; | |
43 const int TCPListenSocket::kSocketError = -1; | |
44 #endif | |
45 | |
46 TCPListenSocket* TCPListenSocket::CreateAndListen( | 31 TCPListenSocket* TCPListenSocket::CreateAndListen( |
mmenke
2012/04/25 17:25:31
nit: While you're here, this function should have
Philippe
2012/04/30 06:55:21
Done.
| |
47 std::string ip, int port, ListenSocket::ListenSocketDelegate *del) { | 32 const string& ip, int port, ListenSocket::ListenSocketDelegate *del) { |
48 SOCKET s = CreateAndBind(ip, port); | 33 SOCKET s = CreateAndBind(ip, port); |
49 if (s == kInvalidSocket) { | 34 if (s == kInvalidSocket) |
50 // TODO(erikkay): error handling | 35 return NULL; |
51 } else { | 36 TCPListenSocket* sock = new TCPListenSocket(s, del); |
52 TCPListenSocket* sock = new TCPListenSocket(s, del); | 37 sock->Listen(); |
53 sock->Listen(); | 38 return sock; |
54 return sock; | |
55 } | |
56 return NULL; | |
57 } | |
58 | |
59 void TCPListenSocket::PauseReads() { | |
60 DCHECK(!reads_paused_); | |
61 reads_paused_ = true; | |
62 } | |
63 | |
64 void TCPListenSocket::ResumeReads() { | |
65 DCHECK(reads_paused_); | |
66 reads_paused_ = false; | |
67 if (has_pending_reads_) { | |
68 has_pending_reads_ = false; | |
69 Read(); | |
70 } | |
71 } | 39 } |
72 | 40 |
73 TCPListenSocket::TCPListenSocket(SOCKET s, | 41 TCPListenSocket::TCPListenSocket(SOCKET s, |
74 ListenSocket::ListenSocketDelegate *del) | 42 ListenSocket::ListenSocketDelegate *del) |
75 : ListenSocket(del), | 43 : DefaultListenSocket(s, del) { |
76 socket_(s), | 44 |
77 reads_paused_(false), | |
78 has_pending_reads_(false) { | |
79 #if defined(OS_WIN) | |
80 socket_event_ = WSACreateEvent(); | |
81 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT | |
82 WatchSocket(NOT_WAITING); | |
83 #elif defined(OS_POSIX) | |
84 wait_state_ = NOT_WAITING; | |
85 #endif | |
86 } | 45 } |
87 | 46 |
88 TCPListenSocket::~TCPListenSocket() { | 47 TCPListenSocket::~TCPListenSocket() {} |
89 #if defined(OS_WIN) | |
90 if (socket_event_) { | |
91 WSACloseEvent(socket_event_); | |
92 socket_event_ = WSA_INVALID_EVENT; | |
93 } | |
94 #endif | |
95 CloseSocket(socket_); | |
96 } | |
97 | 48 |
98 SOCKET TCPListenSocket::CreateAndBind(std::string ip, int port) { | 49 SOCKET TCPListenSocket::CreateAndBind(const string& ip, int port) { |
99 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | 50 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
100 if (s != kInvalidSocket) { | 51 if (s != kInvalidSocket) { |
101 #if defined(OS_POSIX) | 52 #if defined(OS_POSIX) |
102 // Allow rapid reuse. | 53 // Allow rapid reuse. |
103 static const int kOn = 1; | 54 static const int kOn = 1; |
104 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); | 55 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); |
105 #endif | 56 #endif |
106 sockaddr_in addr; | 57 sockaddr_in addr; |
107 memset(&addr, 0, sizeof(addr)); | 58 memset(&addr, 0, sizeof(addr)); |
108 addr.sin_family = AF_INET; | 59 addr.sin_family = AF_INET; |
109 addr.sin_addr.s_addr = inet_addr(ip.c_str()); | 60 addr.sin_addr.s_addr = inet_addr(ip.c_str()); |
110 addr.sin_port = base::HostToNet16(port); | 61 addr.sin_port = base::HostToNet16(port); |
111 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) { | 62 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) { |
112 #if defined(OS_WIN) | 63 #if defined(OS_WIN) |
113 closesocket(s); | 64 closesocket(s); |
114 #elif defined(OS_POSIX) | 65 #elif defined(OS_POSIX) |
115 close(s); | 66 close(s); |
116 #endif | 67 #endif |
68 LOG(ERROR) << "Could not bind socket to " << ip << ":" << port; | |
117 s = kInvalidSocket; | 69 s = kInvalidSocket; |
118 } | 70 } |
119 } | 71 } |
120 return s; | 72 return s; |
121 } | 73 } |
122 | 74 |
123 SOCKET TCPListenSocket::Accept(SOCKET s) { | 75 void TCPListenSocket::AcceptInternal() { |
124 sockaddr_in from; | 76 SOCKET conn = DefaultListenSocket::Accept(socket_); |
mmenke
2012/04/25 17:25:31
This is a little unusual. Generally, a parent cla
Philippe
2012/04/30 06:55:21
I renamed this method to Accept() and the other on
| |
125 socklen_t from_len = sizeof(from); | 77 if (conn == kInvalidSocket) |
126 SOCKET conn = | 78 return; |
127 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len)); | 79 scoped_refptr<TCPListenSocket> sock( |
128 if (conn != kInvalidSocket) { | 80 new TCPListenSocket(conn, socket_delegate_)); |
129 SetNonBlocking(conn); | 81 // it's up to the delegate to AddRef if it wants to keep it around |
mmenke
2012/04/25 17:25:31
nit: While you're here, could you capitalize this
Philippe
2012/04/30 06:55:21
Sure. I also fixed some other places.
| |
130 } | 82 #if defined(OS_POSIX) |
131 return conn; | 83 sock->WatchSocket(WAITING_READ); |
84 #endif | |
85 socket_delegate_->DidAccept(this, sock); | |
132 } | 86 } |
133 | 87 |
134 void TCPListenSocket::SendInternal(const char* bytes, int len) { | |
135 char* send_buf = const_cast<char *>(bytes); | |
136 int len_left = len; | |
137 while (true) { | |
138 int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0)); | |
139 if (sent == len_left) { // A shortcut to avoid extraneous checks. | |
140 break; | |
141 } | |
142 if (sent == kSocketError) { | |
143 #if defined(OS_WIN) | |
144 if (WSAGetLastError() != WSAEWOULDBLOCK) { | |
145 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); | |
146 #elif defined(OS_POSIX) | |
147 if (errno != EWOULDBLOCK && errno != EAGAIN) { | |
148 LOG(ERROR) << "send failed: errno==" << errno; | |
149 #endif | |
150 break; | |
151 } | |
152 // Otherwise we would block, and now we have to wait for a retry. | |
153 // Fall through to PlatformThread::YieldCurrentThread() | |
154 } else { | |
155 // sent != len_left according to the shortcut above. | |
156 // Shift the buffer start and send the remainder after a short while. | |
157 send_buf += sent; | |
158 len_left -= sent; | |
159 } | |
160 base::PlatformThread::YieldCurrentThread(); | |
161 } | |
162 } | |
163 | |
164 void TCPListenSocket::Listen() { | |
165 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? | |
166 listen(socket_, backlog); | |
167 // TODO(erikkay): error handling | |
168 #if defined(OS_POSIX) | |
169 WatchSocket(WAITING_ACCEPT); | |
170 #endif | |
171 } | |
172 | |
173 void TCPListenSocket::Accept() { | |
174 SOCKET conn = Accept(socket_); | |
175 if (conn != kInvalidSocket) { | |
176 scoped_refptr<TCPListenSocket> sock( | |
177 new TCPListenSocket(conn, socket_delegate_)); | |
178 // it's up to the delegate to AddRef if it wants to keep it around | |
179 #if defined(OS_POSIX) | |
180 sock->WatchSocket(WAITING_READ); | |
181 #endif | |
182 socket_delegate_->DidAccept(this, sock); | |
183 } else { | |
184 // TODO(ibrar): some error handling required here | |
185 } | |
186 } | |
187 | |
188 void TCPListenSocket::Read() { | |
189 char buf[kReadBufSize + 1]; // +1 for null termination | |
190 int len; | |
191 do { | |
192 len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0)); | |
193 if (len == kSocketError) { | |
194 #if defined(OS_WIN) | |
195 int err = WSAGetLastError(); | |
196 if (err == WSAEWOULDBLOCK) { | |
197 #elif defined(OS_POSIX) | |
198 if (errno == EWOULDBLOCK || errno == EAGAIN) { | |
199 #endif | |
200 break; | |
201 } else { | |
202 // TODO(ibrar): some error handling required here | |
203 break; | |
204 } | |
205 } else if (len == 0) { | |
206 // In Windows, Close() is called by OnObjectSignaled. In POSIX, we need | |
207 // to call it here. | |
208 #if defined(OS_POSIX) | |
209 Close(); | |
210 #endif | |
211 } else { | |
212 // TODO(ibrar): maybe change DidRead to take a length instead | |
213 DCHECK_GT(len, 0); | |
214 DCHECK_LE(len, kReadBufSize); | |
215 buf[len] = 0; // already create a buffer with +1 length | |
216 socket_delegate_->DidRead(this, buf, len); | |
217 } | |
218 } while (len == kReadBufSize); | |
219 } | |
220 | |
221 void TCPListenSocket::Close() { | |
222 #if defined(OS_POSIX) | |
223 if (wait_state_ == NOT_WAITING) | |
224 return; | |
225 wait_state_ = NOT_WAITING; | |
226 #endif | |
227 UnwatchSocket(); | |
228 socket_delegate_->DidClose(this); | |
229 } | |
230 | |
231 void TCPListenSocket::CloseSocket(SOCKET s) { | |
232 if (s && s != kInvalidSocket) { | |
233 UnwatchSocket(); | |
234 #if defined(OS_WIN) | |
235 closesocket(s); | |
236 #elif defined(OS_POSIX) | |
237 close(s); | |
238 #endif | |
239 } | |
240 } | |
241 | |
242 void TCPListenSocket::WatchSocket(WaitState state) { | |
243 #if defined(OS_WIN) | |
244 WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ); | |
245 watcher_.StartWatching(socket_event_, this); | |
246 #elif defined(OS_POSIX) | |
247 // Implicitly calls StartWatchingFileDescriptor(). | |
248 MessageLoopForIO::current()->WatchFileDescriptor( | |
249 socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this); | |
250 wait_state_ = state; | |
251 #endif | |
252 } | |
253 | |
254 void TCPListenSocket::UnwatchSocket() { | |
255 #if defined(OS_WIN) | |
256 watcher_.StopWatching(); | |
257 #elif defined(OS_POSIX) | |
258 watcher_.StopWatchingFileDescriptor(); | |
259 #endif | |
260 } | |
261 | |
262 // TODO(ibrar): We can add these functions into OS dependent files | |
263 #if defined(OS_WIN) | |
264 // MessageLoop watcher callback | |
265 void TCPListenSocket::OnObjectSignaled(HANDLE object) { | |
266 WSANETWORKEVENTS ev; | |
267 if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) { | |
268 // TODO | |
269 return; | |
270 } | |
271 | |
272 // The object was reset by WSAEnumNetworkEvents. Watch for the next signal. | |
273 watcher_.StartWatching(object, this); | |
274 | |
275 if (ev.lNetworkEvents == 0) { | |
276 // Occasionally the event is set even though there is no new data. | |
277 // The net seems to think that this is ignorable. | |
278 return; | |
279 } | |
280 if (ev.lNetworkEvents & FD_ACCEPT) { | |
281 Accept(); | |
282 } | |
283 if (ev.lNetworkEvents & FD_READ) { | |
284 if (reads_paused_) { | |
285 has_pending_reads_ = true; | |
286 } else { | |
287 Read(); | |
288 } | |
289 } | |
290 if (ev.lNetworkEvents & FD_CLOSE) { | |
291 Close(); | |
292 } | |
293 } | |
294 #elif defined(OS_POSIX) | |
295 void TCPListenSocket::OnFileCanReadWithoutBlocking(int fd) { | |
296 switch (wait_state_) { | |
297 case WAITING_ACCEPT: | |
298 Accept(); | |
299 break; | |
300 case WAITING_READ: | |
301 if (reads_paused_) { | |
302 has_pending_reads_ = true; | |
303 } else { | |
304 Read(); | |
305 } | |
306 break; | |
307 default: | |
308 // Close() is called by Read() in the Linux case. | |
309 NOTREACHED(); | |
310 break; | |
311 } | |
312 } | |
313 | |
314 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) { | |
315 // MessagePumpLibevent callback, we don't listen for write events | |
316 // so we shouldn't ever reach here. | |
317 NOTREACHED(); | |
318 } | |
319 | |
320 #endif | |
321 | |
322 } // namespace net | 88 } // namespace net |
OLD | NEW |