• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 "base/async_socket_io_handler.h"
6 
7 #include <fcntl.h>
8 
9 #include "base/posix/eintr_wrapper.h"
10 
11 namespace base {
12 
AsyncSocketIoHandler()13 AsyncSocketIoHandler::AsyncSocketIoHandler()
14     : socket_(base::SyncSocket::kInvalidHandle),
15       pending_buffer_(NULL),
16       pending_buffer_len_(0),
17       is_watching_(false) {
18 }
19 
~AsyncSocketIoHandler()20 AsyncSocketIoHandler::~AsyncSocketIoHandler() {
21   DCHECK(CalledOnValidThread());
22 }
23 
OnFileCanReadWithoutBlocking(int socket)24 void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
25   DCHECK(CalledOnValidThread());
26   DCHECK_EQ(socket, socket_);
27   DCHECK(!read_complete_.is_null());
28 
29   if (pending_buffer_) {
30     int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
31                                        pending_buffer_len_));
32     DCHECK_GE(bytes_read, 0);
33     pending_buffer_ = NULL;
34     pending_buffer_len_ = 0;
35     read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
36   } else {
37     // We're getting notifications that we can read from the socket while
38     // we're not waiting for data.  In order to not starve the message loop,
39     // let's stop watching the fd and restart the watch when Read() is called.
40     is_watching_ = false;
41     socket_watcher_.StopWatchingFileDescriptor();
42   }
43 }
44 
Read(char * buffer,int buffer_len)45 bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
46   DCHECK(CalledOnValidThread());
47   DCHECK(!read_complete_.is_null());
48   DCHECK(!pending_buffer_);
49 
50   EnsureWatchingSocket();
51 
52   int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
53   if (bytes_read < 0) {
54     if (errno == EAGAIN) {
55       pending_buffer_ = buffer;
56       pending_buffer_len_ = buffer_len;
57     } else {
58       NOTREACHED() << "read(): " << errno;
59       return false;
60     }
61   } else {
62     read_complete_.Run(bytes_read);
63   }
64   return true;
65 }
66 
Initialize(base::SyncSocket::Handle socket,const ReadCompleteCallback & callback)67 bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
68                                       const ReadCompleteCallback& callback) {
69   DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
70 
71   DetachFromThread();
72 
73   socket_ = socket;
74   read_complete_ = callback;
75 
76   // SyncSocket is blocking by default, so let's convert it to non-blocking.
77   int value = fcntl(socket, F_GETFL);
78   if (!(value & O_NONBLOCK)) {
79     // Set the socket to be non-blocking so we can do async reads.
80     if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
81       NOTREACHED();
82       return false;
83     }
84   }
85 
86   return true;
87 }
88 
EnsureWatchingSocket()89 void AsyncSocketIoHandler::EnsureWatchingSocket() {
90   DCHECK(CalledOnValidThread());
91   if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
92     is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
93         socket_, true, base::MessageLoopForIO::WATCH_READ,
94         &socket_watcher_, this);
95   }
96 }
97 
98 }  // namespace base.
99