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

Side by Side Diff: net/socket/socket_libevent.cc

Issue 348803003: Refactor tcp socket and unix domain socket. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix net_unittests for iOS Created 6 years, 6 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
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/socket/socket_libevent.h"
6
7 #include <errno.h>
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10
11 #include "base/callback_helpers.h"
12 #include "base/logging.h"
13 #include "base/posix/eintr_wrapper.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/ip_endpoint.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/net_util.h"
18
19 namespace net {
20
21 namespace {
22
23 int MapAcceptError(int os_error) {
24 switch (os_error) {
25 // If the client aborts the connection before the server calls accept,
26 // POSIX specifies accept should fail with ECONNABORTED. The server can
27 // ignore the error and just call accept again, so we map the error to
28 // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec.
29 // 5.11, "Connection Abort before accept Returns".
30 case ECONNABORTED:
31 return ERR_IO_PENDING;
32 default:
33 return MapSystemError(os_error);
34 }
35 }
36
37 int MapConnectError(int os_error) {
38 switch (os_error) {
39 case EINPROGRESS:
40 return ERR_IO_PENDING;
41 case EACCES:
42 return ERR_NETWORK_ACCESS_DENIED;
43 case ETIMEDOUT:
44 return ERR_CONNECTION_TIMED_OUT;
45 default: {
46 int net_error = MapSystemError(os_error);
47 if (net_error == ERR_FAILED)
48 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
49 return net_error;
50 }
51 }
52 }
53
54 void CopyAddress(const SockaddrStorage& from, SockaddrStorage* to) {
55 // SockaddrStorage doesn't have correct copy constructor. Need to copy
56 // members manually.
mmenke 2014/06/26 15:36:11 I think it would make more sense to give SockaddrS
byungchul 2014/06/26 18:09:23 Done.
57 to->addr_len = from.addr_len;
58 memcpy(to->addr, from.addr, from.addr_len);
59 }
60
61 } // namespace
62
63 SocketLibevent::SocketLibevent()
64 : socket_fd_(kInvalidSocket),
65 read_buf_len_(0),
66 write_buf_len_(0),
67 waiting_connect_(false) {
68 }
69
70 SocketLibevent::~SocketLibevent() {
71 Close();
72 }
73
74 int SocketLibevent::Open(int address_family) {
75 DCHECK(thread_checker_.CalledOnValidThread());
76 DCHECK_EQ(socket_fd_, kInvalidSocket);
mmenke 2014/06/26 15:36:11 Put expected before actual (Matters more for EXPEC
byungchul 2014/06/26 18:09:23 Done.
77
78 socket_fd_ = CreatePlatformSocket(
79 address_family,
80 SOCK_STREAM,
81 address_family == AF_UNIX ? 0 : IPPROTO_TCP);
mmenke 2014/06/26 15:36:11 Maybe DCHECK on address family? Or just take prot
byungchul 2014/06/26 18:09:23 Done.
82 if (socket_fd_ < 0) {
83 PLOG(ERROR) << "CreatePlatformSocket() returned an error, errno=" << errno;
84 return MapSystemError(errno);
85 }
86
87 if (SetNonBlocking(socket_fd_)) {
88 int rv = MapSystemError(errno);
89 Close();
90 return rv;
91 }
92
93 return OK;
94 }
95
96 int SocketLibevent::AdoptConnectedSocket(SocketDescriptor socket,
97 const SockaddrStorage& address) {
98 DCHECK(thread_checker_.CalledOnValidThread());
99 DCHECK_EQ(socket_fd_, kInvalidSocket);
mmenke 2014/06/26 15:36:11 nit: Switch order (Not going to point out the res
byungchul 2014/06/26 18:09:23 Done.
100
101 socket_fd_ = socket;
102
103 if (SetNonBlocking(socket_fd_)) {
104 int rv = MapSystemError(errno);
105 Close();
106 return rv;
107 }
108
109 SetPeerAddress(address);
110 return OK;
111 }
112
113 int SocketLibevent::Bind(const SockaddrStorage& address) {
114 DCHECK(thread_checker_.CalledOnValidThread());
115 DCHECK_NE(socket_fd_, kInvalidSocket);
116
117 int rv = bind(socket_fd_, address.addr, address.addr_len);
118 if (rv < 0) {
119 PLOG(ERROR) << "bind() returned an error, errno=" << errno;
120 return MapSystemError(errno);
121 }
122
123 return OK;
124 }
125
126 int SocketLibevent::Listen(int backlog) {
127 DCHECK(thread_checker_.CalledOnValidThread());
128 DCHECK_NE(socket_fd_, kInvalidSocket);
129 DCHECK_GT(backlog, 0);
130
131 int rv = listen(socket_fd_, backlog);
132 if (rv < 0) {
133 PLOG(ERROR) << "listen() returned an error, errno=" << errno;
134 return MapSystemError(errno);
135 }
136
137 return OK;
138 }
139
140 int SocketLibevent::Accept(scoped_ptr<SocketLibevent>* socket,
141 const CompletionCallback& callback) {
142 DCHECK(thread_checker_.CalledOnValidThread());
143 DCHECK_NE(socket_fd_, kInvalidSocket);
144 DCHECK(accept_callback_.is_null());
145 DCHECK(socket);
146 DCHECK(!callback.is_null());
147
148 int rv = DoAccept(socket);
149 if (rv != ERR_IO_PENDING)
150 return rv;
151
152 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
153 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
154 &accept_socket_watcher_, this)) {
155 PLOG(ERROR) << "WatchFileDescriptor failed on accept, errno " << errno;
156 return MapSystemError(errno);
157 }
158
159 accept_socket_ = socket;
160 accept_callback_ = callback;
161 return ERR_IO_PENDING;
162 }
163
164 int SocketLibevent::Connect(const SockaddrStorage& address,
165 const CompletionCallback& callback) {
166 DCHECK(thread_checker_.CalledOnValidThread());
167 DCHECK_NE(socket_fd_, kInvalidSocket);
168 DCHECK(!waiting_connect_);
169 DCHECK(!callback.is_null());
mmenke 2014/06/26 15:36:11 Maybe throw in a DCHECK(!IsConnected()); while you
byungchul 2014/06/26 18:09:23 I have a bit concern about calling IsConnected() w
170
171 SetPeerAddress(address);
172
173 int rv = DoConnect();
174 if (rv != ERR_IO_PENDING) {
175 return rv;
176 }
mmenke 2014/06/26 15:36:10 nit: Should be consistent about using braces for
byungchul 2014/06/26 18:09:23 Done. Though I understand it is common, it introdu
177
178 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
179 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
180 &write_socket_watcher_, this)) {
181 PLOG(ERROR) << "WatchFileDescriptor failed on connect, errno " << errno;
182 return MapSystemError(errno);
183 }
184
185 write_callback_ = callback;
186 waiting_connect_ = true;
187 return ERR_IO_PENDING;
188 }
189
190 bool SocketLibevent::IsConnected() const {
191 DCHECK(thread_checker_.CalledOnValidThread());
192
193 if (socket_fd_ == kInvalidSocket || waiting_connect_)
194 return false;
195
196 // Checks if connection is alive.
197 char c;
198 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
199 if (rv == 0)
200 return false;
201 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
202 return false;
203
204 return true;
205 }
206
207 bool SocketLibevent::IsConnectedAndIdle() const {
208 DCHECK(thread_checker_.CalledOnValidThread());
209
210 if (socket_fd_ == kInvalidSocket || waiting_connect_)
211 return false;
212
213 // Check if connection is alive and we haven't received any data
214 // unexpectedly.
215 char c;
216 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
217 if (rv >= 0)
218 return false;
219 if (errno != EAGAIN && errno != EWOULDBLOCK)
220 return false;
221
222 return true;
223 }
224
225 int SocketLibevent::Read(IOBuffer* buf,
226 int buf_len,
227 const CompletionCallback& callback) {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 DCHECK_NE(socket_fd_, kInvalidSocket);
230 DCHECK(!waiting_connect_);
231 DCHECK(read_callback_.is_null());
232 // Synchronous operation not supported
233 DCHECK(!callback.is_null());
234 DCHECK_GT(buf_len, 0);
235
236 int rv = DoRead(buf, buf_len);
237 if (rv != ERR_IO_PENDING)
238 return rv;
239
240 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
241 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
242 &read_socket_watcher_, this)) {
243 PLOG(ERROR) << "WatchFileDescriptor failed on read, errno " << errno;
244 return MapSystemError(errno);
245 }
246
247 read_buf_ = buf;
248 read_buf_len_ = buf_len;
249 read_callback_ = callback;
250 return ERR_IO_PENDING;
251 }
252
253 int SocketLibevent::Write(IOBuffer* buf,
254 int buf_len,
255 const CompletionCallback& callback) {
256 DCHECK(thread_checker_.CalledOnValidThread());
257 DCHECK_NE(socket_fd_, kInvalidSocket);
258 DCHECK(!waiting_connect_);
259 DCHECK(write_callback_.is_null());
260 // Synchronous operation not supported
261 DCHECK(!callback.is_null());
262 DCHECK_GT(buf_len, 0);
263
264 int rv = DoWrite(buf, buf_len);
265 if (rv == ERR_IO_PENDING)
266 rv = WaitForWrite(buf, buf_len, callback);
267 return rv;
268 }
269
270 int SocketLibevent::WaitForWrite(IOBuffer* buf,
271 int buf_len,
272 const CompletionCallback& callback) {
273 DCHECK(thread_checker_.CalledOnValidThread());
274 DCHECK(write_callback_.is_null());
275 // Synchronous operation not supported
276 DCHECK(!callback.is_null());
277 DCHECK_GT(buf_len, 0);
278
279 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
280 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
281 &write_socket_watcher_, this)) {
282 PLOG(ERROR) << "WatchFileDescriptor failed on write, errno " << errno;
283 return MapSystemError(errno);
284 }
285
286 write_buf_ = buf;
287 write_buf_len_ = buf_len;
288 write_callback_ = callback;
289 return ERR_IO_PENDING;
290 }
291
292 int SocketLibevent::GetLocalAddress(SockaddrStorage* address) const {
293 DCHECK(thread_checker_.CalledOnValidThread());
294 DCHECK(address);
295
296 if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0)
297 return MapSystemError(errno);
298 return OK;
299 }
300
301 int SocketLibevent::GetPeerAddress(SockaddrStorage* address) const {
302 DCHECK(thread_checker_.CalledOnValidThread());
303 DCHECK(address);
304
305 if (!HasPeerAddress())
306 return ERR_SOCKET_NOT_CONNECTED;
307
308 CopyAddress(*peer_address_, address);
309 return OK;
310 }
311
312 void SocketLibevent::SetPeerAddress(const SockaddrStorage& address) {
313 DCHECK(thread_checker_.CalledOnValidThread());
314 // |peer_address_| will be non-NULL if Connect() has been called. Unless
315 // Close() is called to reset the internal state, a second call to Connect()
316 // is not allowed.
317 // Please note that we don't allow a second Connect() even if the previous
318 // Connect() has failed. Connecting the same |socket_| again after a
319 // connection attempt failed results in unspecified behavior according to
320 // POSIX.
321 DCHECK(!peer_address_);
322 peer_address_.reset(new SockaddrStorage);
323 CopyAddress(address, peer_address_.get());
324 }
325
326 bool SocketLibevent::HasPeerAddress() const {
327 DCHECK(thread_checker_.CalledOnValidThread());
328 return peer_address_ != NULL;
329 }
330
331 void SocketLibevent::Close() {
332 DCHECK(thread_checker_.CalledOnValidThread());
333
334 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
335 DCHECK(ok);
336 ok = read_socket_watcher_.StopWatchingFileDescriptor();
337 DCHECK(ok);
338 ok = write_socket_watcher_.StopWatchingFileDescriptor();
339 DCHECK(ok);
340
341 if (socket_fd_ != kInvalidSocket) {
342 if (IGNORE_EINTR(close(socket_fd_)) < 0)
343 PLOG(ERROR) << "close() returned an error, errno=" << errno;
344 socket_fd_ = kInvalidSocket;
345 }
346
347 if (!accept_callback_.is_null()) {
348 accept_socket_ = NULL;
349 accept_callback_.Reset();
350 }
351
352 if (!read_callback_.is_null()) {
353 read_buf_ = NULL;
354 read_buf_len_ = 0;
355 read_callback_.Reset();
356 }
357
358 if (!write_callback_.is_null()) {
359 write_buf_ = NULL;
360 write_buf_len_ = 0;
361 write_callback_.Reset();
362 }
363
364 waiting_connect_ = false;
365 peer_address_.reset();
366 }
367
368 void SocketLibevent::OnFileCanReadWithoutBlocking(int fd) {
369 DCHECK(!accept_callback_.is_null() || !read_callback_.is_null());
370 if (!accept_callback_.is_null()) {
371 AcceptCompleted();
372 } else { // !read_callback_.is_null()
373 ReadCompleted();
374 }
375 }
376
377 void SocketLibevent::OnFileCanWriteWithoutBlocking(int fd) {
378 DCHECK(!write_callback_.is_null());
379 if (waiting_connect_) {
380 ConnectCompleted();
381 } else {
382 WriteCompleted();
383 }
384 }
385
386 int SocketLibevent::DoAccept(scoped_ptr<SocketLibevent>* socket) {
387 SockaddrStorage new_peer_address;
388 int new_socket = HANDLE_EINTR(accept(socket_fd_,
389 new_peer_address.addr,
390 &new_peer_address.addr_len));
391 if (new_socket < 0)
392 return MapAcceptError(errno);
393
394 scoped_ptr<SocketLibevent> accepted_socket(new SocketLibevent);
395 int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address);
396 if (rv != OK)
397 return rv;
398
399 *socket = accepted_socket.Pass();
400 return OK;
401 }
402
403 void SocketLibevent::AcceptCompleted() {
404 DCHECK(accept_socket_);
405 int rv = DoAccept(accept_socket_);
406 if (rv == ERR_IO_PENDING)
407 return;
408
409 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
410 DCHECK(ok);
411 accept_socket_ = NULL;
412 base::ResetAndReturn(&accept_callback_).Run(rv);
413 }
414
415 int SocketLibevent::DoConnect() {
416 int rv = HANDLE_EINTR(connect(socket_fd_,
417 peer_address_->addr,
418 peer_address_->addr_len));
419 DCHECK_LE(rv, 0);
420 return rv == OK ? OK : MapConnectError(errno);
mmenke 2014/06/26 15:36:11 the first "OK" should be a "0"
byungchul 2014/06/26 18:09:23 Done.
421 }
422
423 void SocketLibevent::ConnectCompleted() {
424 // Get the error that connect() completed with.
425 int os_error = 0;
426 socklen_t len = sizeof(os_error);
427 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0)
428 os_error = errno;
429
430 int rv = MapConnectError(os_error);
431 if (rv == ERR_IO_PENDING)
432 return;
433
434 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
435 DCHECK(ok);
436 waiting_connect_ = false;
437 base::ResetAndReturn(&write_callback_).Run(rv);
438 }
439
440 int SocketLibevent::DoRead(IOBuffer* buf, int buf_len) {
441 int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len));
442 return rv >= 0 ? rv : MapSystemError(errno);
443 }
444
445 void SocketLibevent::ReadCompleted() {
446 int rv = DoRead(read_buf_, read_buf_len_);
447 if (rv == ERR_IO_PENDING)
448 return;
449
450 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
451 DCHECK(ok);
452 read_buf_ = NULL;
453 read_buf_len_ = 0;
454 base::ResetAndReturn(&read_callback_).Run(rv);
455 }
456
457 int SocketLibevent::DoWrite(IOBuffer* buf, int buf_len) {
458 int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len));
459 return rv >= 0 ? rv : MapSystemError(errno);
460 }
461
462 void SocketLibevent::WriteCompleted() {
463 int rv = DoWrite(write_buf_, write_buf_len_);
464 if (rv == ERR_IO_PENDING)
465 return;
466
467 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
468 DCHECK(ok);
469 write_buf_ = NULL;
470 write_buf_len_ = 0;
471 base::ResetAndReturn(&write_callback_).Run(rv);
472 }
473
474 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698