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

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;
35 37
36 } // namespace 38 } // namespace
37 39
(...skipping 30 matching lines...) Expand all
68 has_pending_reads_ = false; 70 has_pending_reads_ = false;
69 Read(); 71 Read();
70 } 72 }
71 } 73 }
72 74
73 TCPListenSocket::TCPListenSocket(SOCKET s, 75 TCPListenSocket::TCPListenSocket(SOCKET s,
74 ListenSocket::ListenSocketDelegate *del) 76 ListenSocket::ListenSocketDelegate *del)
75 : ListenSocket(del), 77 : ListenSocket(del),
76 socket_(s), 78 socket_(s),
77 reads_paused_(false), 79 reads_paused_(false),
78 has_pending_reads_(false) { 80 has_pending_reads_(false),
81 has_pending_writes_(false),
82 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
79 #if defined(OS_WIN) 83 #if defined(OS_WIN)
80 socket_event_ = WSACreateEvent(); 84 socket_event_ = WSACreateEvent();
81 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT 85 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT
82 WatchSocket(NOT_WAITING); 86 WatchSocket(NOT_WAITING);
83 #elif defined(OS_POSIX) 87 #elif defined(OS_POSIX)
84 wait_state_ = NOT_WAITING; 88 wait_state_ = NOT_WAITING;
85 #endif 89 #endif
86 } 90 }
87 91
88 TCPListenSocket::~TCPListenSocket() { 92 TCPListenSocket::~TCPListenSocket() {
89 #if defined(OS_WIN) 93 #if defined(OS_WIN)
90 if (socket_event_) { 94 if (socket_event_) {
91 WSACloseEvent(socket_event_); 95 WSACloseEvent(socket_event_);
92 socket_event_ = WSA_INVALID_EVENT; 96 socket_event_ = WSA_INVALID_EVENT;
93 } 97 }
94 #endif 98 #endif
95 CloseSocket(socket_); 99 CloseSocket(socket_);
96 } 100 }
97 101
98 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) { 102 SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) {
103 #if defined(OS_WIN)
104 EnsureWinsockInit();
105 #endif
106
99 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 107 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
100 if (s != kInvalidSocket) { 108 if (s != kInvalidSocket) {
101 #if defined(OS_POSIX) 109 #if defined(OS_POSIX)
102 // Allow rapid reuse. 110 // Allow rapid reuse.
103 static const int kOn = 1; 111 static const int kOn = 1;
104 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 112 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
105 #endif 113 #endif
106 sockaddr_in addr; 114 sockaddr_in addr;
107 memset(&addr, 0, sizeof(addr)); 115 memset(&addr, 0, sizeof(addr));
108 addr.sin_family = AF_INET; 116 addr.sin_family = AF_INET;
(...skipping 15 matching lines...) Expand all
124 sockaddr_in from; 132 sockaddr_in from;
125 socklen_t from_len = sizeof(from); 133 socklen_t from_len = sizeof(from);
126 SOCKET conn = 134 SOCKET conn =
127 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len)); 135 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len));
128 if (conn != kInvalidSocket) { 136 if (conn != kInvalidSocket) {
129 SetNonBlocking(conn); 137 SetNonBlocking(conn);
130 } 138 }
131 return conn; 139 return conn;
132 } 140 }
133 141
134 void TCPListenSocket::SendInternal(const char* bytes, int len) { 142 void TCPListenSocket::SendInternal(const char* bytes, int len) {
michaeln 2012/05/08 18:17:12 Are there any consumers of this class that could b
Marshall 2012/05/08 20:27:07 From what I can tell TCPListenSocket is only used
mmenke 2012/05/08 20:51:43 It's also used by chrome_frame/test/test_server
135 char* send_buf = const_cast<char *>(bytes); 143 if (bytes == NULL && len == 0) {
136 int len_left = len; 144 // Executing the asynchronous send callback. Clear the pending flag.
137 while (true) { 145 DCHECK(has_pending_writes_);
138 int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0)); 146 has_pending_writes_ = false;
139 if (sent == len_left) { // A shortcut to avoid extraneous checks. 147
140 break; 148 // Another send call may have already emptied the buffer.
141 } 149 if (send_data_.empty())
150 return;
151 }
152
153 if (send_data_.empty()) {
154 // Nothing in the buffer currently. Try sending the new data without adding
155 // to the buffer.
156 DCHECK(bytes);
157 DCHECK_GT(len, 0);
158 int sent = HANDLE_EINTR(send(socket_, bytes, len, 0));
159 if (sent == len) // All data has been sent.
160 return;
161
142 if (sent == kSocketError) { 162 if (sent == kSocketError) {
143 #if defined(OS_WIN) 163 #if defined(OS_WIN)
144 if (WSAGetLastError() != WSAEWOULDBLOCK) { 164 if (WSAGetLastError() != WSAEWOULDBLOCK) {
145 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); 165 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
146 #elif defined(OS_POSIX) 166 #elif defined(OS_POSIX)
147 if (errno != EWOULDBLOCK && errno != EAGAIN) { 167 if (errno != EWOULDBLOCK && errno != EAGAIN) {
148 LOG(ERROR) << "send failed: errno==" << errno; 168 LOG(ERROR) << "send failed: errno==" << errno;
149 #endif 169 #endif
150 break; 170 // Don't try to re-send data after a socket error.
171 return;
151 } 172 }
152 // Otherwise we would block, and now we have to wait for a retry. 173 }
153 // Fall through to PlatformThread::YieldCurrentThread() 174
175 if (sent > 0) {
176 // Add the remaining bytes to the send buffer.
177 send_data_.append(bytes + sent, len - sent);
mmenke 2012/05/08 15:51:57 nit: Since send_data_ is empty, suggest you just
Marshall 2012/05/08 20:27:07 Done.
154 } else { 178 } else {
155 // sent != len_left according to the shortcut above. 179 // Add all bytes to the send buffer.
156 // Shift the buffer start and send the remainder after a short while. 180 send_data_.append(bytes, len);
157 send_buf += sent;
158 len_left -= sent;
159 } 181 }
160 base::PlatformThread::YieldCurrentThread(); 182
183 if (!has_pending_writes_) {
184 // Fire a new asychronous continuation callback.
185 has_pending_writes_ = true;
186 MessageLoop::current()->PostTask(FROM_HERE,
michaeln 2012/05/08 18:17:12 I would expect this to spin pretty hard when netwo
Marshall 2012/05/08 20:27:07 I've implemented an exponential back-off using net
187 base::Bind(&TCPListenSocket::SendInternal, weak_factory_.GetWeakPtr(),
188 static_cast<const char*>(NULL), 0));
mmenke 2012/05/08 15:51:57 I think you should at least use a different functi
Marshall 2012/05/08 20:27:07 Done.
189 }
190 return;
191 }
mmenke 2012/05/08 15:51:57 I wonder if we really need two copies of the send
Marshall 2012/05/08 20:27:07 Done.
192
193 if (bytes != NULL && len > 0) {
194 // Add the bytes to the end of the send data buffer.
195 send_data_.append(bytes, len);
michaeln 2012/05/08 18:17:12 What if no progress is made for a very long time,
Marshall 2012/05/08 20:27:07 I've implemented a maximum buffer size of 5MB. In
mmenke 2012/05/08 20:51:43 In the medium to long term, we do intend to eventu
mmenke 2012/05/08 20:51:43 "Tends to?" How strong of an assurance do we have
Marshall 2012/05/08 21:04:57 Not a very strong assurance at all, at least with
196 }
197
198 int len_left = static_cast<int>(send_data_.length());
199 int sent = HANDLE_EINTR(send(socket_, send_data_.c_str(), len_left, 0));
200 if (sent == len_left) {
201 // All data has been sent.
202 send_data_.clear();
203 return;
204 }
205
206 if (sent == kSocketError) {
207 #if defined(OS_WIN)
208 if (WSAGetLastError() != WSAEWOULDBLOCK) {
209 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
210 #elif defined(OS_POSIX)
211 if (errno != EWOULDBLOCK && errno != EAGAIN) {
212 LOG(ERROR) << "send failed: errno==" << errno;
213 #endif
214 // Don't try to re-send data after a socket error.
215 send_data_.clear();
216 return;
217 }
218 }
219
220 if (sent > 0) {
221 // Remove the sent bytes from the buffer.
222 send_data_ = send_data_.substr(sent, len_left - sent);
mmenke 2012/05/08 17:08:46 This is so ugly...you may want to use a scoped_arr
Marshall 2012/05/08 20:27:07 The buffer can grow to > 1MB in size. Do we want t
mmenke 2012/05/08 20:51:43 I think that's reasonable. The one problem with a
Marshall 2012/05/08 21:04:57 Are there any currently existing ring buffer imple
mmenke 2012/05/08 21:21:35 I don't believe so. Our main socket class (TcpCli
Marshall 2012/05/08 21:53:44 Keeping a list of send buffers sounds like a good
223 }
224
225 if (!has_pending_writes_) {
mmenke 2012/05/08 15:51:57 May be a little simpler to use a OneShotTimer, rat
Marshall 2012/05/08 20:27:07 Done.
226 // Fire a new asychronous continuation callback.
227 has_pending_writes_ = true;
228 MessageLoop::current()->PostTask(FROM_HERE,
229 base::Bind(&TCPListenSocket::SendInternal, weak_factory_.GetWeakPtr(),
230 static_cast<const char*>(NULL), 0));
161 } 231 }
162 } 232 }
163 233
164 void TCPListenSocket::Listen() { 234 void TCPListenSocket::Listen() {
165 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? 235 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
166 listen(socket_, backlog); 236 listen(socket_, backlog);
167 // TODO(erikkay): error handling 237 // TODO(erikkay): error handling
168 #if defined(OS_POSIX) 238 #if defined(OS_POSIX)
169 WatchSocket(WAITING_ACCEPT); 239 WatchSocket(WAITING_ACCEPT);
170 #endif 240 #endif
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 383
314 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) { 384 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
315 // MessagePumpLibevent callback, we don't listen for write events 385 // MessagePumpLibevent callback, we don't listen for write events
316 // so we shouldn't ever reach here. 386 // so we shouldn't ever reach here.
317 NOTREACHED(); 387 NOTREACHED();
318 } 388 }
319 389
320 #endif 390 #endif
321 391
322 } // namespace net 392 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698