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

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.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 "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 LOG(ERROR) << "send failed: buffer overrun";
143 #if defined(OS_WIN) 179 send_buffers_.clear();
144 if (WSAGetLastError() != WSAEWOULDBLOCK) { 180 send_pending_size_ = 0;
145 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); 181 send_error_ = true;
146 #elif defined(OS_POSIX) 182 return;
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 } 183 }
184
185 scoped_refptr<IOBuffer> buffer(new IOBuffer(len));
186 memcpy(buffer->data(), bytes, len);
187 send_buffers_.push_back(new DrainableIOBuffer(buffer, len));
188 send_pending_size_ += len;
189
190 if (!send_timer_.IsRunning())
191 SendData();
162 } 192 }
163 193
164 void TCPListenSocket::Listen() { 194 void TCPListenSocket::Listen() {
165 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? 195 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
166 listen(socket_, backlog); 196 listen(socket_, backlog);
167 // TODO(erikkay): error handling 197 // TODO(erikkay): error handling
168 #if defined(OS_POSIX) 198 #if defined(OS_POSIX)
169 WatchSocket(WAITING_ACCEPT); 199 WatchSocket(WAITING_ACCEPT);
170 #endif 200 #endif
171 } 201 }
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 } 342 }
313 343
314 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) { 344 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
315 // MessagePumpLibevent callback, we don't listen for write events 345 // MessagePumpLibevent callback, we don't listen for write events
316 // so we shouldn't ever reach here. 346 // so we shouldn't ever reach here.
317 NOTREACHED(); 347 NOTREACHED();
318 } 348 }
319 349
320 #endif 350 #endif
321 351
352 void TCPListenSocket::SendData() {
353 DCHECK(!send_buffers_.empty());
354
355 int total_sent = 0;
356
357 // Send data until all buffers have been sent or a call would block.
358 while (!send_buffers_.empty()) {
359 scoped_refptr<DrainableIOBuffer> buffer = send_buffers_.front();
360
361 int len_left = buffer->BytesRemaining();
362 int sent = HANDLE_EINTR(send(socket_, buffer->data(), len_left, 0));
363 if (sent > 0) {
364 if (sent == len_left)
365 send_buffers_.pop_front();
366 else
367 buffer->DidConsume(sent);
368
369 total_sent += sent;
370 } else if (sent == kSocketError) {
371 #if defined(OS_WIN)
372 if (WSAGetLastError() != WSAEWOULDBLOCK) {
373 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
374 #elif defined(OS_POSIX)
375 if (errno != EWOULDBLOCK && errno != EAGAIN) {
376 LOG(ERROR) << "send failed: errno==" << errno;
377 #endif
378 // Don't try to re-send data after a socket error.
379 send_buffers_.clear();
380 send_pending_size_ = 0;
381 send_error_ = true;
382 return;
383 }
384
385 // The call would block. Don't send any more data at this time.
386 break;
387 } else {
388 NOTREACHED();
389 break;
390 }
391 }
392
393 if (total_sent > 0) {
394 send_pending_size_ -= total_sent;
395 DCHECK_GE(send_pending_size_, 0);
396
397 // Clear the back-off delay.
398 send_backoff_.Reset();
399 } else {
400 // Increase the back-off delay.
401 send_backoff_.InformOfRequest(false);
402 }
403
404 if (!send_buffers_.empty()) {
405 DCHECK(!send_timer_.IsRunning());
406 send_timer_.Start(FROM_HERE, send_backoff_.GetTimeUntilRelease(),
407 this, &TCPListenSocket::SendData);
408 }
409 }
410
322 } // namespace net 411 } // 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