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

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

Issue 10389007: Change TCPListenSocket::SendInternal to use a non-blocking implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: 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
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 "build/build_config.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/eintr_wrapper.h" 21 #include "base/eintr_wrapper.h"
21 #include "base/sys_byteorder.h" 22 #include "base/sys_byteorder.h"
22 #include "base/threading/platform_thread.h" 23 #include "base/threading/platform_thread.h"
23 #include "net/base/net_util.h" 24 #include "net/base/net_util.h"
24 #include "net/base/tcp_listen_socket.h" 25 #include "net/base/tcp_listen_socket.h"
25 26
26 #if defined(OS_WIN) 27 #if defined(OS_WIN)
27 typedef int socklen_t; 28 typedef int socklen_t;
29 #include "net/base/winsock_init.h"
28 #endif // defined(OS_WIN) 30 #endif // defined(OS_WIN)
29 31
30 namespace net { 32 namespace net {
31 33
32 namespace { 34 namespace {
33 35
34 const int kReadBufSize = 4096; 36 const int kReadBufSize = 4096;
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 };
35 64
36 } // namespace 65 } // namespace
37 66
38 #if defined(OS_WIN) 67 #if defined(OS_WIN)
39 const SOCKET TCPListenSocket::kInvalidSocket = INVALID_SOCKET; 68 const SOCKET TCPListenSocket::kInvalidSocket = INVALID_SOCKET;
40 const int TCPListenSocket::kSocketError = SOCKET_ERROR; 69 const int TCPListenSocket::kSocketError = SOCKET_ERROR;
41 #elif defined(OS_POSIX) 70 #elif defined(OS_POSIX)
42 const SOCKET TCPListenSocket::kInvalidSocket = -1; 71 const SOCKET TCPListenSocket::kInvalidSocket = -1;
43 const int TCPListenSocket::kSocketError = -1; 72 const int TCPListenSocket::kSocketError = -1;
44 #endif 73 #endif
(...skipping 23 matching lines...) Expand all
68 has_pending_reads_ = false; 97 has_pending_reads_ = false;
69 Read(); 98 Read();
70 } 99 }
71 } 100 }
72 101
73 TCPListenSocket::TCPListenSocket(SOCKET s, 102 TCPListenSocket::TCPListenSocket(SOCKET s,
74 ListenSocket::ListenSocketDelegate *del) 103 ListenSocket::ListenSocketDelegate *del)
75 : ListenSocket(del), 104 : ListenSocket(del),
76 socket_(s), 105 socket_(s),
77 reads_paused_(false), 106 reads_paused_(false),
78 has_pending_reads_(false) { 107 has_pending_reads_(false),
108 send_pending_size_(0),
109 send_error_(false),
110 send_backoff_(&kSendBackoffPolicy) {
79 #if defined(OS_WIN) 111 #if defined(OS_WIN)
80 socket_event_ = WSACreateEvent(); 112 socket_event_ = WSACreateEvent();
81 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT 113 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT
82 WatchSocket(NOT_WAITING); 114 WatchSocket(NOT_WAITING);
83 #elif defined(OS_POSIX) 115 #elif defined(OS_POSIX)
84 wait_state_ = NOT_WAITING; 116 wait_state_ = NOT_WAITING;
85 #endif 117 #endif
86 } 118 }
87 119
88 TCPListenSocket::~TCPListenSocket() { 120 TCPListenSocket::~TCPListenSocket() {
89 #if defined(OS_WIN) 121 #if defined(OS_WIN)
90 if (socket_event_) { 122 if (socket_event_) {
91 WSACloseEvent(socket_event_); 123 WSACloseEvent(socket_event_);
92 socket_event_ = WSA_INVALID_EVENT; 124 socket_event_ = WSA_INVALID_EVENT;
93 } 125 }
94 #endif 126 #endif
95 CloseSocket(socket_); 127 CloseSocket(socket_);
96 } 128 }
97 129
98 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) { 130 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) {
131 #if defined(OS_WIN)
132 EnsureWinsockInit();
133 #endif
134
99 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 135 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
100 if (s != kInvalidSocket) { 136 if (s != kInvalidSocket) {
101 #if defined(OS_POSIX) 137 #if defined(OS_POSIX)
102 // Allow rapid reuse. 138 // Allow rapid reuse.
103 static const int kOn = 1; 139 static const int kOn = 1;
104 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 140 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
105 #endif 141 #endif
106 sockaddr_in addr; 142 sockaddr_in addr;
107 memset(&addr, 0, sizeof(addr)); 143 memset(&addr, 0, sizeof(addr));
108 addr.sin_family = AF_INET; 144 addr.sin_family = AF_INET;
(...skipping 16 matching lines...) Expand all
125 socklen_t from_len = sizeof(from); 161 socklen_t from_len = sizeof(from);
126 SOCKET conn = 162 SOCKET conn =
127 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len)); 163 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len));
128 if (conn != kInvalidSocket) { 164 if (conn != kInvalidSocket) {
129 SetNonBlocking(conn); 165 SetNonBlocking(conn);
130 } 166 }
131 return conn; 167 return conn;
132 } 168 }
133 169
134 void TCPListenSocket::SendInternal(const char* bytes, int len) { 170 void TCPListenSocket::SendInternal(const char* bytes, int len) {
135 char* send_buf = const_cast<char *>(bytes); 171 DCHECK(bytes);
136 int len_left = len; 172 DCHECK_GT(len, 0);
137 while (true) { 173
138 int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0)); 174 if (send_error_)
139 if (sent == len_left) { // A shortcut to avoid extraneous checks. 175 return;
140 break; 176
141 } 177 if (send_pending_size_ + len > kMaxSendBufSize) {
142 if (sent == kSocketError) { 178 // Too much of a backup, stop trying to add more data.
michaeln 2012/05/10 16:52:21 nit: given the log error message immediately below
Marshall 2012/05/10 19:01:09 Done.
143 #if defined(OS_WIN) 179 LOG(ERROR) << "send failed: buffer overrun";
144 if (WSAGetLastError() != WSAEWOULDBLOCK) { 180 send_buffers_.clear();
145 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); 181 send_pending_size_ = 0;
146 #elif defined(OS_POSIX) 182 send_error_ = true;
147 if (errno != EWOULDBLOCK && errno != EAGAIN) { 183 return;
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 } 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();
162 } 193 }
163 194
164 void TCPListenSocket::Listen() { 195 void TCPListenSocket::Listen() {
165 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? 196 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
166 listen(socket_, backlog); 197 listen(socket_, backlog);
167 // TODO(erikkay): error handling 198 // TODO(erikkay): error handling
168 #if defined(OS_POSIX) 199 #if defined(OS_POSIX)
169 WatchSocket(WAITING_ACCEPT); 200 WatchSocket(WAITING_ACCEPT);
170 #endif 201 #endif
171 } 202 }
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 } 343 }
313 344
314 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) { 345 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
315 // MessagePumpLibevent callback, we don't listen for write events 346 // MessagePumpLibevent callback, we don't listen for write events
316 // so we shouldn't ever reach here. 347 // so we shouldn't ever reach here.
317 NOTREACHED(); 348 NOTREACHED();
318 } 349 }
319 350
320 #endif 351 #endif
321 352
353 void TCPListenSocket::SendData() {
354 // This method should never be called when the send buffer is empty.
michaeln 2012/05/10 16:52:21 nit: the dcheck effectively says this
Marshall 2012/05/10 19:01:09 Done.
355 DCHECK(!send_buffers_.empty());
356
357 int total_sent = 0;
358
359 // Send data until all buffers have been sent or a call would block.
360 while (!send_buffers_.empty()) {
361 scoped_refptr<DrainableIOBuffer> buffer = send_buffers_.front();
362
363 int len_left = buffer->BytesRemaining();
364 int sent = HANDLE_EINTR(send(socket_, buffer->data(), len_left, 0));
365 DCHECK(sent > 0 || sent == kSocketError);
366
367 if (sent > 0) {
368 if (sent == len_left) {
369 // All data has been sent. Remove the buffer from the list and move on
370 // to the next buffer, if any.
371 send_buffers_.erase(send_buffers_.begin());
mmenke 2012/05/10 17:17:19 nit: send_buffers_.pop_front()
Marshall 2012/05/10 19:01:09 Done.
372 } else {
373 // The buffer was partially sent.
374 buffer->DidConsume(sent);
michaeln 2012/05/10 16:52:21 style nit: would less text be more readable? if (
Marshall 2012/05/10 19:01:09 Done.
375 }
376
377 total_sent += sent;
378 } else if (sent == kSocketError) {
379 #if defined(OS_WIN)
380 if (WSAGetLastError() != WSAEWOULDBLOCK) {
381 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
382 #elif defined(OS_POSIX)
383 if (errno != EWOULDBLOCK && errno != EAGAIN) {
384 LOG(ERROR) << "send failed: errno==" << errno;
385 #endif
386 // Don't try to re-send data after a socket error.
387 send_buffers_.clear();
388 send_pending_size_ = 0;
389 send_error_ = true;
390 return;
391 }
392
393 // The call would block. Don't send any more data at this time.
394 break;
395 }
396 }
397
398 if (total_sent > 0) {
399 send_pending_size_ -= total_sent;
400 DCHECK_GE(send_pending_size_, 0);
401
402 // Clear the back-off delay.
403 send_backoff_.Reset();
404 } else {
405 // Increase the back-off delay.
406 send_backoff_.InformOfRequest(false);
michaeln 2012/05/10 16:52:21 the comments about how these affect the back-off d
407 }
408
409 if (!send_buffers_.empty()) {
michaeln 2012/05/10 16:52:21 maybe DCHECK_GT(send_pending_size_, 0)
Marshall 2012/05/10 19:01:09 That's probably not necessary because we DCHECK at
410 DCHECK(!send_timer_.IsRunning());
411 send_timer_.Start(FROM_HERE, send_backoff_.GetTimeUntilRelease(),
412 this, &TCPListenSocket::SendData);
413 }
414 }
415
322 } // namespace net 416 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698