OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |