Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Side by Side Diff: net/base/tcp_listen_socket.cc

Issue 10161005: Add DefaultListenSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix build on Windows Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/tcp_listen_socket.h ('k') | net/base/tcp_listen_socket_unittest.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "base/bind.h" 20 #include "base/logging.h"
21 #include "base/eintr_wrapper.h"
22 #include "base/sys_byteorder.h" 21 #include "base/sys_byteorder.h"
23 #include "base/threading/platform_thread.h" 22 #include "base/threading/platform_thread.h"
23 #include "build/build_config.h"
24 #include "net/base/net_util.h" 24 #include "net/base/net_util.h"
25 #include "net/base/tcp_listen_socket.h" 25 #include "net/base/winsock_init.h"
26 26
27 #if defined(OS_WIN) 27 using std::string;
28 typedef int socklen_t;
29 #include "net/base/winsock_init.h"
30 #endif // defined(OS_WIN)
31 28
32 namespace net { 29 namespace net {
33 30
34 namespace { 31 // static
35 32 scoped_refptr<TCPListenSocket> TCPListenSocket::CreateAndListen(
36 const int kReadBufSize = 4096; 33 const string& ip, int port, StreamListenSocket::Delegate* del) {
37 const int kMaxSendBufSize = 1024 * 1024 * 5; // 5MB
38
39 const net::BackoffEntry::Policy kSendBackoffPolicy = {
40 // Number of initial errors (in sequence) to ignore before applying
41 // exponential back-off rules.
42 0,
43
44 // Initial delay for exponential back-off in ms.
45 25,
46
47 // Factor by which the waiting time will be multiplied.
48 2,
49
50 // Fuzzing percentage. ex: 10% will spread requests randomly
51 // between 90%-100% of the calculated time.
52 0,
53
54 // Maximum amount of time we are willing to delay our request in ms.
55 100,
56
57 // Time to keep an entry from being discarded even when it
58 // has no significant state, -1 to never discard.
59 -1,
60
61 // Don't use initial delay unless the last request was an error.
62 false,
63 };
64
65 } // namespace
66
67 #if defined(OS_WIN)
68 const SOCKET TCPListenSocket::kInvalidSocket = INVALID_SOCKET;
69 const int TCPListenSocket::kSocketError = SOCKET_ERROR;
70 #elif defined(OS_POSIX)
71 const SOCKET TCPListenSocket::kInvalidSocket = -1;
72 const int TCPListenSocket::kSocketError = -1;
73 #endif
74
75 TCPListenSocket* TCPListenSocket::CreateAndListen(
76 const std::string& ip, int port, ListenSocket::ListenSocketDelegate *del) {
77 SOCKET s = CreateAndBind(ip, port); 34 SOCKET s = CreateAndBind(ip, port);
78 if (s == kInvalidSocket) { 35 if (s == kInvalidSocket)
79 // TODO(erikkay): error handling 36 return NULL;
80 } else { 37 scoped_refptr<TCPListenSocket> sock(new TCPListenSocket(s, del));
81 TCPListenSocket* sock = new TCPListenSocket(s, del); 38 sock->Listen();
82 sock->Listen(); 39 return sock;
83 return sock;
84 }
85 return NULL;
86 } 40 }
87 41
88 void TCPListenSocket::PauseReads() { 42 TCPListenSocket::TCPListenSocket(SOCKET s, StreamListenSocket::Delegate* del)
89 DCHECK(!reads_paused_); 43 : StreamListenSocket(s, del) {
90 reads_paused_ = true;
91 } 44 }
92 45
93 void TCPListenSocket::ResumeReads() { 46 TCPListenSocket::~TCPListenSocket() {}
94 DCHECK(reads_paused_);
95 reads_paused_ = false;
96 if (has_pending_reads_) {
97 has_pending_reads_ = false;
98 Read();
99 }
100 }
101 47
102 TCPListenSocket::TCPListenSocket(SOCKET s, 48 SOCKET TCPListenSocket::CreateAndBind(const string& ip, int port) {
103 ListenSocket::ListenSocketDelegate *del)
104 : ListenSocket(del),
105 socket_(s),
106 reads_paused_(false),
107 has_pending_reads_(false),
108 send_pending_size_(0),
109 send_error_(false),
110 send_backoff_(&kSendBackoffPolicy) {
111 #if defined(OS_WIN)
112 socket_event_ = WSACreateEvent();
113 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT
114 WatchSocket(NOT_WAITING);
115 #elif defined(OS_POSIX)
116 wait_state_ = NOT_WAITING;
117 #endif
118 }
119
120 TCPListenSocket::~TCPListenSocket() {
121 #if defined(OS_WIN)
122 if (socket_event_) {
123 WSACloseEvent(socket_event_);
124 socket_event_ = WSA_INVALID_EVENT;
125 }
126 #endif
127 CloseSocket(socket_);
128 }
129
130 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) {
131 #if defined(OS_WIN) 49 #if defined(OS_WIN)
132 EnsureWinsockInit(); 50 EnsureWinsockInit();
133 #endif 51 #endif
134 52
135 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 53 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
136 if (s != kInvalidSocket) { 54 if (s != kInvalidSocket) {
137 #if defined(OS_POSIX) 55 #if defined(OS_POSIX)
138 // Allow rapid reuse. 56 // Allow rapid reuse.
139 static const int kOn = 1; 57 static const int kOn = 1;
140 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 58 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
141 #endif 59 #endif
142 sockaddr_in addr; 60 sockaddr_in addr;
143 memset(&addr, 0, sizeof(addr)); 61 memset(&addr, 0, sizeof(addr));
144 addr.sin_family = AF_INET; 62 addr.sin_family = AF_INET;
145 addr.sin_addr.s_addr = inet_addr(ip.c_str()); 63 addr.sin_addr.s_addr = inet_addr(ip.c_str());
146 addr.sin_port = base::HostToNet16(port); 64 addr.sin_port = base::HostToNet16(port);
147 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) { 65 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
148 #if defined(OS_WIN) 66 #if defined(OS_WIN)
149 closesocket(s); 67 closesocket(s);
150 #elif defined(OS_POSIX) 68 #elif defined(OS_POSIX)
151 close(s); 69 close(s);
152 #endif 70 #endif
71 LOG(ERROR) << "Could not bind socket to " << ip << ":" << port;
153 s = kInvalidSocket; 72 s = kInvalidSocket;
154 } 73 }
155 } 74 }
156 return s; 75 return s;
157 } 76 }
158 77
159 SOCKET TCPListenSocket::Accept(SOCKET s) { 78 void TCPListenSocket::Accept() {
160 sockaddr_in from; 79 SOCKET conn = AcceptSocket();
161 socklen_t from_len = sizeof(from); 80 if (conn == kInvalidSocket)
162 SOCKET conn =
163 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len));
164 if (conn != kInvalidSocket) {
165 SetNonBlocking(conn);
166 }
167 return conn;
168 }
169
170 void TCPListenSocket::SendInternal(const char* bytes, int len) {
171 DCHECK(bytes);
172 if (!bytes || len <= 0)
173 return; 81 return;
174 82 scoped_refptr<TCPListenSocket> sock(
175 if (send_error_) 83 new TCPListenSocket(conn, socket_delegate_));
176 return; 84 // It's up to the delegate to AddRef if it wants to keep it around.
177
178 if (send_pending_size_ + len > kMaxSendBufSize) {
179 LOG(ERROR) << "send failed: buffer overrun";
180 send_buffers_.clear();
181 send_pending_size_ = 0;
182 send_error_ = true;
183 return;
184 }
185
186 scoped_refptr<IOBuffer> buffer(new IOBuffer(len));
187 memcpy(buffer->data(), bytes, len);
188 send_buffers_.push_back(new DrainableIOBuffer(buffer, len));
189 send_pending_size_ += len;
190
191 if (!send_timer_.IsRunning())
192 SendData();
193 }
194
195 void TCPListenSocket::Listen() {
196 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
197 listen(socket_, backlog);
198 // TODO(erikkay): error handling
199 #if defined(OS_POSIX) 85 #if defined(OS_POSIX)
200 WatchSocket(WAITING_ACCEPT); 86 sock->WatchSocket(WAITING_READ);
201 #endif 87 #endif
202 } 88 socket_delegate_->DidAccept(this, sock);
203
204 void TCPListenSocket::Accept() {
205 SOCKET conn = Accept(socket_);
206 if (conn != kInvalidSocket) {
207 scoped_refptr<TCPListenSocket> sock(
208 new TCPListenSocket(conn, socket_delegate_));
209 // it's up to the delegate to AddRef if it wants to keep it around
210 #if defined(OS_POSIX)
211 sock->WatchSocket(WAITING_READ);
212 #endif
213 socket_delegate_->DidAccept(this, sock);
214 } else {
215 // TODO(ibrar): some error handling required here
216 }
217 }
218
219 void TCPListenSocket::Read() {
220 char buf[kReadBufSize + 1]; // +1 for null termination
221 int len;
222 do {
223 len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0));
224 if (len == kSocketError) {
225 #if defined(OS_WIN)
226 int err = WSAGetLastError();
227 if (err == WSAEWOULDBLOCK) {
228 #elif defined(OS_POSIX)
229 if (errno == EWOULDBLOCK || errno == EAGAIN) {
230 #endif
231 break;
232 } else {
233 // TODO(ibrar): some error handling required here
234 break;
235 }
236 } else if (len == 0) {
237 // In Windows, Close() is called by OnObjectSignaled. In POSIX, we need
238 // to call it here.
239 #if defined(OS_POSIX)
240 Close();
241 #endif
242 } else {
243 // TODO(ibrar): maybe change DidRead to take a length instead
244 DCHECK_GT(len, 0);
245 DCHECK_LE(len, kReadBufSize);
246 buf[len] = 0; // already create a buffer with +1 length
247 socket_delegate_->DidRead(this, buf, len);
248 }
249 } while (len == kReadBufSize);
250 }
251
252 void TCPListenSocket::Close() {
253 #if defined(OS_POSIX)
254 if (wait_state_ == NOT_WAITING)
255 return;
256 wait_state_ = NOT_WAITING;
257 #endif
258 UnwatchSocket();
259 socket_delegate_->DidClose(this);
260 }
261
262 void TCPListenSocket::CloseSocket(SOCKET s) {
263 if (s && s != kInvalidSocket) {
264 UnwatchSocket();
265 #if defined(OS_WIN)
266 closesocket(s);
267 #elif defined(OS_POSIX)
268 close(s);
269 #endif
270 }
271 }
272
273 void TCPListenSocket::WatchSocket(WaitState state) {
274 #if defined(OS_WIN)
275 WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ);
276 watcher_.StartWatching(socket_event_, this);
277 #elif defined(OS_POSIX)
278 // Implicitly calls StartWatchingFileDescriptor().
279 MessageLoopForIO::current()->WatchFileDescriptor(
280 socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
281 wait_state_ = state;
282 #endif
283 }
284
285 void TCPListenSocket::UnwatchSocket() {
286 #if defined(OS_WIN)
287 watcher_.StopWatching();
288 #elif defined(OS_POSIX)
289 watcher_.StopWatchingFileDescriptor();
290 #endif
291 }
292
293 // TODO(ibrar): We can add these functions into OS dependent files
294 #if defined(OS_WIN)
295 // MessageLoop watcher callback
296 void TCPListenSocket::OnObjectSignaled(HANDLE object) {
297 WSANETWORKEVENTS ev;
298 if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) {
299 // TODO
300 return;
301 }
302
303 // The object was reset by WSAEnumNetworkEvents. Watch for the next signal.
304 watcher_.StartWatching(object, this);
305
306 if (ev.lNetworkEvents == 0) {
307 // Occasionally the event is set even though there is no new data.
308 // The net seems to think that this is ignorable.
309 return;
310 }
311 if (ev.lNetworkEvents & FD_ACCEPT) {
312 Accept();
313 }
314 if (ev.lNetworkEvents & FD_READ) {
315 if (reads_paused_) {
316 has_pending_reads_ = true;
317 } else {
318 Read();
319 }
320 }
321 if (ev.lNetworkEvents & FD_CLOSE) {
322 Close();
323 }
324 }
325 #elif defined(OS_POSIX)
326 void TCPListenSocket::OnFileCanReadWithoutBlocking(int fd) {
327 switch (wait_state_) {
328 case WAITING_ACCEPT:
329 Accept();
330 break;
331 case WAITING_READ:
332 if (reads_paused_) {
333 has_pending_reads_ = true;
334 } else {
335 Read();
336 }
337 break;
338 default:
339 // Close() is called by Read() in the Linux case.
340 NOTREACHED();
341 break;
342 }
343 }
344
345 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
346 // MessagePumpLibevent callback, we don't listen for write events
347 // so we shouldn't ever reach here.
348 NOTREACHED();
349 }
350
351 #endif
352
353 void TCPListenSocket::SendData() {
354 DCHECK(!send_buffers_.empty());
355
356 int total_sent = 0;
357
358 // Send data until all buffers have been sent or a call would block.
359 while (!send_buffers_.empty()) {
360 scoped_refptr<DrainableIOBuffer> buffer = send_buffers_.front();
361
362 int len_left = buffer->BytesRemaining();
363 int sent = HANDLE_EINTR(send(socket_, buffer->data(), len_left, 0));
364 if (sent > 0) {
365 if (sent == len_left)
366 send_buffers_.pop_front();
367 else
368 buffer->DidConsume(sent);
369
370 total_sent += sent;
371 } else if (sent == kSocketError) {
372 #if defined(OS_WIN)
373 if (WSAGetLastError() != WSAEWOULDBLOCK) {
374 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
375 #elif defined(OS_POSIX)
376 if (errno != EWOULDBLOCK && errno != EAGAIN) {
377 LOG(ERROR) << "send failed: errno==" << errno;
378 #endif
379 // Don't try to re-send data after a socket error.
380 send_buffers_.clear();
381 send_pending_size_ = 0;
382 send_error_ = true;
383 return;
384 }
385
386 // The call would block. Don't send any more data at this time.
387 break;
388 } else {
389 NOTREACHED();
390 break;
391 }
392 }
393
394 if (total_sent > 0) {
395 send_pending_size_ -= total_sent;
396 DCHECK_GE(send_pending_size_, 0);
397
398 // Clear the back-off delay.
399 send_backoff_.Reset();
400 } else {
401 // Increase the back-off delay.
402 send_backoff_.InformOfRequest(false);
403 }
404
405 if (!send_buffers_.empty()) {
406 DCHECK(!send_timer_.IsRunning());
407 send_timer_.Start(FROM_HERE, send_backoff_.GetTimeUntilRelease(),
408 this, &TCPListenSocket::SendData);
409 }
410 } 89 }
411 90
412 } // namespace net 91 } // namespace net
OLDNEW
« no previous file with comments | « net/base/tcp_listen_socket.h ('k') | net/base/tcp_listen_socket_unittest.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698