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

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
« no previous file with comments | « net/base/tcp_listen_socket.h ('k') | net/base/tcp_listen_socket_unittest.cc » ('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 "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 kSendDataBackoffPolicy = {
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 100,
mmenke 2012/05/08 21:23:38 If we're sending megabytes locally, 100 millisecon
Marshall 2012/05/08 21:44:51 Reduced to 25ms.
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 500,
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_data_error_(false),
109 send_data_backoff_(&kSendDataBackoffPolicy) {
79 #if defined(OS_WIN) 110 #if defined(OS_WIN)
80 socket_event_ = WSACreateEvent(); 111 socket_event_ = WSACreateEvent();
81 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT 112 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT
82 WatchSocket(NOT_WAITING); 113 WatchSocket(NOT_WAITING);
83 #elif defined(OS_POSIX) 114 #elif defined(OS_POSIX)
84 wait_state_ = NOT_WAITING; 115 wait_state_ = NOT_WAITING;
85 #endif 116 #endif
86 } 117 }
87 118
88 TCPListenSocket::~TCPListenSocket() { 119 TCPListenSocket::~TCPListenSocket() {
89 #if defined(OS_WIN) 120 #if defined(OS_WIN)
90 if (socket_event_) { 121 if (socket_event_) {
91 WSACloseEvent(socket_event_); 122 WSACloseEvent(socket_event_);
92 socket_event_ = WSA_INVALID_EVENT; 123 socket_event_ = WSA_INVALID_EVENT;
93 } 124 }
94 #endif 125 #endif
95 CloseSocket(socket_); 126 CloseSocket(socket_);
96 } 127 }
97 128
98 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) { 129 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) {
130 #if defined(OS_WIN)
131 EnsureWinsockInit();
132 #endif
133
99 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 134 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
100 if (s != kInvalidSocket) { 135 if (s != kInvalidSocket) {
101 #if defined(OS_POSIX) 136 #if defined(OS_POSIX)
102 // Allow rapid reuse. 137 // Allow rapid reuse.
103 static const int kOn = 1; 138 static const int kOn = 1;
104 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 139 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
105 #endif 140 #endif
106 sockaddr_in addr; 141 sockaddr_in addr;
107 memset(&addr, 0, sizeof(addr)); 142 memset(&addr, 0, sizeof(addr));
108 addr.sin_family = AF_INET; 143 addr.sin_family = AF_INET;
(...skipping 16 matching lines...) Expand all
125 socklen_t from_len = sizeof(from); 160 socklen_t from_len = sizeof(from);
126 SOCKET conn = 161 SOCKET conn =
127 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len)); 162 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len));
128 if (conn != kInvalidSocket) { 163 if (conn != kInvalidSocket) {
129 SetNonBlocking(conn); 164 SetNonBlocking(conn);
130 } 165 }
131 return conn; 166 return conn;
132 } 167 }
133 168
134 void TCPListenSocket::SendInternal(const char* bytes, int len) { 169 void TCPListenSocket::SendInternal(const char* bytes, int len) {
135 char* send_buf = const_cast<char *>(bytes); 170 DCHECK(bytes);
136 int len_left = len; 171 DCHECK_GT(len, 0);
137 while (true) { 172
138 int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0)); 173 if (send_data_error_)
139 if (sent == len_left) { // A shortcut to avoid extraneous checks. 174 return;
140 break; 175
141 } 176 // Add all bytes to the send buffer.
142 if (sent == kSocketError) { 177 if (send_data_.empty()) {
143 #if defined(OS_WIN) 178 send_data_.assign(bytes, len);
144 if (WSAGetLastError() != WSAEWOULDBLOCK) { 179 } else if (send_data_.size() > kMaxSendBufSize) {
mmenke 2012/05/08 20:51:43 Should this be send_data_.size() + len? We'd stil
Marshall 2012/05/08 21:44:51 Done.
145 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); 180 // Too much of a backup, stop trying to add more data.
146 #elif defined(OS_POSIX) 181 LOG(ERROR) << "send failed: buffer overrun";
147 if (errno != EWOULDBLOCK && errno != EAGAIN) { 182 send_data_error_ = true;
mmenke 2012/05/08 20:51:43 send_data_.clear()?
Marshall 2012/05/08 21:44:51 Done.
148 LOG(ERROR) << "send failed: errno==" << errno; 183 return;
149 #endif 184 } else {
150 break; 185 send_data_.append(bytes, len);
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 } 186 }
187
188 if (!send_data_backoff_.ShouldRejectRequest())
189 SendData();
162 } 190 }
163 191
164 void TCPListenSocket::Listen() { 192 void TCPListenSocket::Listen() {
165 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? 193 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
166 listen(socket_, backlog); 194 listen(socket_, backlog);
167 // TODO(erikkay): error handling 195 // TODO(erikkay): error handling
168 #if defined(OS_POSIX) 196 #if defined(OS_POSIX)
169 WatchSocket(WAITING_ACCEPT); 197 WatchSocket(WAITING_ACCEPT);
170 #endif 198 #endif
171 } 199 }
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 } 340 }
313 341
314 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) { 342 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
315 // MessagePumpLibevent callback, we don't listen for write events 343 // MessagePumpLibevent callback, we don't listen for write events
316 // so we shouldn't ever reach here. 344 // so we shouldn't ever reach here.
317 NOTREACHED(); 345 NOTREACHED();
318 } 346 }
319 347
320 #endif 348 #endif
321 349
350 void TCPListenSocket::SendData() {
351 // Another send call may have already emptied the buffer.
352 if (send_data_.empty())
353 return;
354
355 int len_left = static_cast<int>(send_data_.length());
356 int sent = HANDLE_EINTR(send(socket_, send_data_.c_str(), len_left, 0));
357 if (sent == len_left) {
358 // All data has been sent.
359 send_data_.clear();
360
361 // Successfully sending all data clears the backoff state.
362 send_data_backoff_.Reset();
363 return;
364 }
365
366 if (sent == kSocketError) {
367 #if defined(OS_WIN)
368 if (WSAGetLastError() != WSAEWOULDBLOCK) {
369 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
370 #elif defined(OS_POSIX)
371 if (errno != EWOULDBLOCK && errno != EAGAIN) {
372 LOG(ERROR) << "send failed: errno==" << errno;
373 #endif
374 // Don't try to re-send data after a socket error.
375 send_data_.clear();
376 send_data_error_ = true;
377 return;
378 }
379
380 // Blocking is considered a failure.
381 send_data_backoff_.InformOfRequest(false);
382 }
383
384 if (sent > 0) {
385 // Remove the sent bytes from the buffer.
386 send_data_ = send_data_.substr(sent, len_left - sent);
387
388 // Sending any data is considered a success.
389 send_data_backoff_.InformOfRequest(true);
390 }
391
392 if (!send_timer_.IsRunning()) {
393 // Schedule a timer to continue sending data asynchronously.
394 send_timer_.Start(FROM_HERE, send_data_backoff_.GetTimeUntilRelease(),
395 this, &TCPListenSocket::SendData);
396 }
397 }
398
322 } // namespace net 399 } // namespace net
OLDNEW
« no previous file with comments | « net/base/tcp_listen_socket.h ('k') | net/base/tcp_listen_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698