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

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

Issue 10161005: Add DefaultListenSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix year in license header Created 8 years, 8 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 "net/base/tcp_listen_socket.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 "build/build_config.h"
20 #include "base/eintr_wrapper.h" 21 #include "base/eintr_wrapper.h"
22 #include "base/logging.h"
21 #include "base/sys_byteorder.h" 23 #include "base/sys_byteorder.h"
22 #include "base/threading/platform_thread.h" 24 #include "base/threading/platform_thread.h"
23 #include "net/base/net_util.h" 25 #include "net/base/net_util.h"
24 #include "net/base/tcp_listen_socket.h"
25 26
26 #if defined(OS_WIN) 27 using std::string;
27 typedef int socklen_t;
28 #endif // defined(OS_WIN)
29 28
30 namespace net { 29 namespace net {
31 30
32 namespace {
33
34 const int kReadBufSize = 4096;
35
36 } // namespace
37
38 #if defined(OS_WIN)
39 const SOCKET TCPListenSocket::kInvalidSocket = INVALID_SOCKET;
40 const int TCPListenSocket::kSocketError = SOCKET_ERROR;
41 #elif defined(OS_POSIX)
42 const SOCKET TCPListenSocket::kInvalidSocket = -1;
43 const int TCPListenSocket::kSocketError = -1;
44 #endif
45
46 TCPListenSocket* TCPListenSocket::CreateAndListen( 31 TCPListenSocket* TCPListenSocket::CreateAndListen(
mmenke 2012/04/25 17:25:31 nit: While you're here, this function should have
Philippe 2012/04/30 06:55:21 Done.
47 std::string ip, int port, ListenSocket::ListenSocketDelegate *del) { 32 const string& ip, int port, ListenSocket::ListenSocketDelegate *del) {
48 SOCKET s = CreateAndBind(ip, port); 33 SOCKET s = CreateAndBind(ip, port);
49 if (s == kInvalidSocket) { 34 if (s == kInvalidSocket)
50 // TODO(erikkay): error handling 35 return NULL;
51 } else { 36 TCPListenSocket* sock = new TCPListenSocket(s, del);
52 TCPListenSocket* sock = new TCPListenSocket(s, del); 37 sock->Listen();
53 sock->Listen(); 38 return sock;
54 return sock;
55 }
56 return NULL;
57 }
58
59 void TCPListenSocket::PauseReads() {
60 DCHECK(!reads_paused_);
61 reads_paused_ = true;
62 }
63
64 void TCPListenSocket::ResumeReads() {
65 DCHECK(reads_paused_);
66 reads_paused_ = false;
67 if (has_pending_reads_) {
68 has_pending_reads_ = false;
69 Read();
70 }
71 } 39 }
72 40
73 TCPListenSocket::TCPListenSocket(SOCKET s, 41 TCPListenSocket::TCPListenSocket(SOCKET s,
74 ListenSocket::ListenSocketDelegate *del) 42 ListenSocket::ListenSocketDelegate *del)
75 : ListenSocket(del), 43 : DefaultListenSocket(s, del) {
76 socket_(s), 44
77 reads_paused_(false),
78 has_pending_reads_(false) {
79 #if defined(OS_WIN)
80 socket_event_ = WSACreateEvent();
81 // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT
82 WatchSocket(NOT_WAITING);
83 #elif defined(OS_POSIX)
84 wait_state_ = NOT_WAITING;
85 #endif
86 } 45 }
87 46
88 TCPListenSocket::~TCPListenSocket() { 47 TCPListenSocket::~TCPListenSocket() {}
89 #if defined(OS_WIN)
90 if (socket_event_) {
91 WSACloseEvent(socket_event_);
92 socket_event_ = WSA_INVALID_EVENT;
93 }
94 #endif
95 CloseSocket(socket_);
96 }
97 48
98 SOCKET TCPListenSocket::CreateAndBind(std::string ip, int port) { 49 SOCKET TCPListenSocket::CreateAndBind(const string& ip, int port) {
99 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 50 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
100 if (s != kInvalidSocket) { 51 if (s != kInvalidSocket) {
101 #if defined(OS_POSIX) 52 #if defined(OS_POSIX)
102 // Allow rapid reuse. 53 // Allow rapid reuse.
103 static const int kOn = 1; 54 static const int kOn = 1;
104 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 55 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
105 #endif 56 #endif
106 sockaddr_in addr; 57 sockaddr_in addr;
107 memset(&addr, 0, sizeof(addr)); 58 memset(&addr, 0, sizeof(addr));
108 addr.sin_family = AF_INET; 59 addr.sin_family = AF_INET;
109 addr.sin_addr.s_addr = inet_addr(ip.c_str()); 60 addr.sin_addr.s_addr = inet_addr(ip.c_str());
110 addr.sin_port = base::HostToNet16(port); 61 addr.sin_port = base::HostToNet16(port);
111 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) { 62 if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
112 #if defined(OS_WIN) 63 #if defined(OS_WIN)
113 closesocket(s); 64 closesocket(s);
114 #elif defined(OS_POSIX) 65 #elif defined(OS_POSIX)
115 close(s); 66 close(s);
116 #endif 67 #endif
68 LOG(ERROR) << "Could not bind socket to " << ip << ":" << port;
117 s = kInvalidSocket; 69 s = kInvalidSocket;
118 } 70 }
119 } 71 }
120 return s; 72 return s;
121 } 73 }
122 74
123 SOCKET TCPListenSocket::Accept(SOCKET s) { 75 void TCPListenSocket::AcceptInternal() {
124 sockaddr_in from; 76 SOCKET conn = DefaultListenSocket::Accept(socket_);
mmenke 2012/04/25 17:25:31 This is a little unusual. Generally, a parent cla
Philippe 2012/04/30 06:55:21 I renamed this method to Accept() and the other on
125 socklen_t from_len = sizeof(from); 77 if (conn == kInvalidSocket)
126 SOCKET conn = 78 return;
127 HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len)); 79 scoped_refptr<TCPListenSocket> sock(
128 if (conn != kInvalidSocket) { 80 new TCPListenSocket(conn, socket_delegate_));
129 SetNonBlocking(conn); 81 // it's up to the delegate to AddRef if it wants to keep it around
mmenke 2012/04/25 17:25:31 nit: While you're here, could you capitalize this
Philippe 2012/04/30 06:55:21 Sure. I also fixed some other places.
130 } 82 #if defined(OS_POSIX)
131 return conn; 83 sock->WatchSocket(WAITING_READ);
84 #endif
85 socket_delegate_->DidAccept(this, sock);
132 } 86 }
133 87
134 void TCPListenSocket::SendInternal(const char* bytes, int len) {
135 char* send_buf = const_cast<char *>(bytes);
136 int len_left = len;
137 while (true) {
138 int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0));
139 if (sent == len_left) { // A shortcut to avoid extraneous checks.
140 break;
141 }
142 if (sent == kSocketError) {
143 #if defined(OS_WIN)
144 if (WSAGetLastError() != WSAEWOULDBLOCK) {
145 LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
146 #elif defined(OS_POSIX)
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 }
162 }
163
164 void TCPListenSocket::Listen() {
165 int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
166 listen(socket_, backlog);
167 // TODO(erikkay): error handling
168 #if defined(OS_POSIX)
169 WatchSocket(WAITING_ACCEPT);
170 #endif
171 }
172
173 void TCPListenSocket::Accept() {
174 SOCKET conn = Accept(socket_);
175 if (conn != kInvalidSocket) {
176 scoped_refptr<TCPListenSocket> sock(
177 new TCPListenSocket(conn, socket_delegate_));
178 // it's up to the delegate to AddRef if it wants to keep it around
179 #if defined(OS_POSIX)
180 sock->WatchSocket(WAITING_READ);
181 #endif
182 socket_delegate_->DidAccept(this, sock);
183 } else {
184 // TODO(ibrar): some error handling required here
185 }
186 }
187
188 void TCPListenSocket::Read() {
189 char buf[kReadBufSize + 1]; // +1 for null termination
190 int len;
191 do {
192 len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0));
193 if (len == kSocketError) {
194 #if defined(OS_WIN)
195 int err = WSAGetLastError();
196 if (err == WSAEWOULDBLOCK) {
197 #elif defined(OS_POSIX)
198 if (errno == EWOULDBLOCK || errno == EAGAIN) {
199 #endif
200 break;
201 } else {
202 // TODO(ibrar): some error handling required here
203 break;
204 }
205 } else if (len == 0) {
206 // In Windows, Close() is called by OnObjectSignaled. In POSIX, we need
207 // to call it here.
208 #if defined(OS_POSIX)
209 Close();
210 #endif
211 } else {
212 // TODO(ibrar): maybe change DidRead to take a length instead
213 DCHECK_GT(len, 0);
214 DCHECK_LE(len, kReadBufSize);
215 buf[len] = 0; // already create a buffer with +1 length
216 socket_delegate_->DidRead(this, buf, len);
217 }
218 } while (len == kReadBufSize);
219 }
220
221 void TCPListenSocket::Close() {
222 #if defined(OS_POSIX)
223 if (wait_state_ == NOT_WAITING)
224 return;
225 wait_state_ = NOT_WAITING;
226 #endif
227 UnwatchSocket();
228 socket_delegate_->DidClose(this);
229 }
230
231 void TCPListenSocket::CloseSocket(SOCKET s) {
232 if (s && s != kInvalidSocket) {
233 UnwatchSocket();
234 #if defined(OS_WIN)
235 closesocket(s);
236 #elif defined(OS_POSIX)
237 close(s);
238 #endif
239 }
240 }
241
242 void TCPListenSocket::WatchSocket(WaitState state) {
243 #if defined(OS_WIN)
244 WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ);
245 watcher_.StartWatching(socket_event_, this);
246 #elif defined(OS_POSIX)
247 // Implicitly calls StartWatchingFileDescriptor().
248 MessageLoopForIO::current()->WatchFileDescriptor(
249 socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
250 wait_state_ = state;
251 #endif
252 }
253
254 void TCPListenSocket::UnwatchSocket() {
255 #if defined(OS_WIN)
256 watcher_.StopWatching();
257 #elif defined(OS_POSIX)
258 watcher_.StopWatchingFileDescriptor();
259 #endif
260 }
261
262 // TODO(ibrar): We can add these functions into OS dependent files
263 #if defined(OS_WIN)
264 // MessageLoop watcher callback
265 void TCPListenSocket::OnObjectSignaled(HANDLE object) {
266 WSANETWORKEVENTS ev;
267 if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) {
268 // TODO
269 return;
270 }
271
272 // The object was reset by WSAEnumNetworkEvents. Watch for the next signal.
273 watcher_.StartWatching(object, this);
274
275 if (ev.lNetworkEvents == 0) {
276 // Occasionally the event is set even though there is no new data.
277 // The net seems to think that this is ignorable.
278 return;
279 }
280 if (ev.lNetworkEvents & FD_ACCEPT) {
281 Accept();
282 }
283 if (ev.lNetworkEvents & FD_READ) {
284 if (reads_paused_) {
285 has_pending_reads_ = true;
286 } else {
287 Read();
288 }
289 }
290 if (ev.lNetworkEvents & FD_CLOSE) {
291 Close();
292 }
293 }
294 #elif defined(OS_POSIX)
295 void TCPListenSocket::OnFileCanReadWithoutBlocking(int fd) {
296 switch (wait_state_) {
297 case WAITING_ACCEPT:
298 Accept();
299 break;
300 case WAITING_READ:
301 if (reads_paused_) {
302 has_pending_reads_ = true;
303 } else {
304 Read();
305 }
306 break;
307 default:
308 // Close() is called by Read() in the Linux case.
309 NOTREACHED();
310 break;
311 }
312 }
313
314 void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
315 // MessagePumpLibevent callback, we don't listen for write events
316 // so we shouldn't ever reach here.
317 NOTREACHED();
318 }
319
320 #endif
321
322 } // namespace net 88 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698