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

Side by Side Diff: mojo/shell/domain_socket/socket_libevent.cc

Issue 775343004: Move //mojo/shell to //shell (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years 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 "mojo/shell/domain_socket/socket_libevent.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <netinet/in.h>
10 #include <sys/socket.h>
11 #include <unistd.h>
12
13 #include "base/callback_helpers.h"
14 #include "base/logging.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "mojo/shell/domain_socket/net_errors.h"
17
18 namespace mojo {
19 namespace shell {
20
21 SockaddrStorage::SockaddrStorage(const SockaddrStorage& other)
22 : addr_len(other.addr_len),
23 addr(reinterpret_cast<struct sockaddr*>(&addr_storage)) {
24 memcpy(addr, other.addr, addr_len);
25 }
26
27 void SockaddrStorage::operator=(const SockaddrStorage& other) {
28 addr_len = other.addr_len;
29 // addr is already set to &this->addr_storage by default ctor.
30 memcpy(addr, other.addr, addr_len);
31 }
32
33 namespace {
34
35 int MapAcceptError(int os_error) {
36 switch (os_error) {
37 // If the client aborts the connection before the server calls accept,
38 // POSIX specifies accept should fail with ECONNABORTED. The server can
39 // ignore the error and just call accept again, so we map the error to
40 // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec.
41 // 5.11, "Connection Abort before accept Returns".
42 case ECONNABORTED:
43 return net::ERR_IO_PENDING;
44 default:
45 return net::MapSystemError(os_error);
46 }
47 }
48
49 int MapConnectError(int os_error) {
50 switch (os_error) {
51 case EINPROGRESS:
52 return net::ERR_IO_PENDING;
53 case EACCES:
54 return net::ERR_NETWORK_ACCESS_DENIED;
55 case ETIMEDOUT:
56 return net::ERR_CONNECTION_TIMED_OUT;
57 default: {
58 int net_error = net::MapSystemError(os_error);
59 if (net_error == net::ERR_FAILED)
60 return net::ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
61 return net_error;
62 }
63 }
64 }
65
66 int SetNonBlocking(int fd) {
67 int flags = fcntl(fd, F_GETFL, 0);
68 if (-1 == flags)
69 return flags;
70 return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
71 }
72
73 } // namespace
74
75 SocketLibevent::SocketLibevent()
76 : socket_fd_(kInvalidSocket), waiting_connect_(false) {
77 }
78
79 SocketLibevent::~SocketLibevent() {
80 Close();
81 }
82
83 int SocketLibevent::Open(int address_family) {
84 DCHECK(thread_checker_.CalledOnValidThread());
85 DCHECK_EQ(kInvalidSocket, socket_fd_);
86 DCHECK(address_family == AF_INET || address_family == AF_INET6 ||
87 address_family == AF_UNIX);
88
89 int socket_type = SOCK_STREAM;
90 #ifdef SOCK_NONBLOCK
91 socket_type |= SOCK_NONBLOCK;
92 #endif
93 socket_fd_ = ::socket(address_family,
94 socket_type,
95 address_family == AF_UNIX ? 0 : IPPROTO_TCP);
96 #ifndef SOCK_NONBLOCK
97 if (SetNonBlocking(socket_fd_) != 0) {
98 PLOG(ERROR) << "SetNonBlocking() returned an error, errno=" << errno;
99 return net::MapSystemError(errno);
100 }
101 #endif
102 if (socket_fd_ < 0) {
103 PLOG(ERROR) << "CreatePlatformSocket() returned an error, errno=" << errno;
104 return net::MapSystemError(errno);
105 }
106
107 return net::OK;
108 }
109
110 int SocketLibevent::AdoptConnectedSocket(SocketDescriptor socket,
111 const SockaddrStorage& address) {
112 DCHECK(thread_checker_.CalledOnValidThread());
113 DCHECK_EQ(kInvalidSocket, socket_fd_);
114
115 socket_fd_ = socket;
116
117 if (SetNonBlocking(socket_fd_)) {
118 int rv = net::MapSystemError(errno);
119 Close();
120 return rv;
121 }
122
123 SetPeerAddress(address);
124 return net::OK;
125 }
126
127 SocketDescriptor SocketLibevent::ReleaseConnectedSocket() {
128 StopWatchingAndCleanUp();
129 SocketDescriptor socket_fd = socket_fd_;
130 socket_fd_ = kInvalidSocket;
131 return socket_fd;
132 }
133
134 int SocketLibevent::Bind(const SockaddrStorage& address) {
135 DCHECK(thread_checker_.CalledOnValidThread());
136 DCHECK_NE(kInvalidSocket, socket_fd_);
137
138 int rv = bind(socket_fd_, address.addr, address.addr_len);
139 if (rv < 0) {
140 PLOG(ERROR) << "bind() returned an error, errno=" << errno;
141 return net::MapSystemError(errno);
142 }
143
144 return net::OK;
145 }
146
147 int SocketLibevent::Listen(int backlog) {
148 DCHECK(thread_checker_.CalledOnValidThread());
149 DCHECK_NE(kInvalidSocket, socket_fd_);
150 DCHECK_LT(0, backlog);
151
152 int rv = listen(socket_fd_, backlog);
153 if (rv < 0) {
154 PLOG(ERROR) << "listen() returned an error, errno=" << errno;
155 return net::MapSystemError(errno);
156 }
157
158 return net::OK;
159 }
160
161 int SocketLibevent::Accept(scoped_ptr<SocketLibevent>* socket,
162 const CompletionCallback& callback) {
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DCHECK_NE(kInvalidSocket, socket_fd_);
165 DCHECK(accept_callback_.is_null());
166 DCHECK(socket);
167 DCHECK(!callback.is_null());
168
169 int rv = DoAccept(socket);
170 if (rv != net::ERR_IO_PENDING)
171 return rv;
172
173 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
174 socket_fd_,
175 true,
176 base::MessageLoopForIO::WATCH_READ,
177 &accept_socket_watcher_,
178 this)) {
179 PLOG(ERROR) << "WatchFileDescriptor failed on accept, errno " << errno;
180 return net::MapSystemError(errno);
181 }
182
183 accept_socket_ = socket;
184 accept_callback_ = callback;
185 return net::ERR_IO_PENDING;
186 }
187
188 int SocketLibevent::Connect(const SockaddrStorage& address,
189 const CompletionCallback& callback) {
190 DCHECK(thread_checker_.CalledOnValidThread());
191 DCHECK_NE(kInvalidSocket, socket_fd_);
192 DCHECK(!waiting_connect_);
193 DCHECK(!callback.is_null());
194
195 SetPeerAddress(address);
196
197 int rv = DoConnect();
198 if (rv != net::ERR_IO_PENDING)
199 return rv;
200
201 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
202 socket_fd_,
203 true,
204 base::MessageLoopForIO::WATCH_WRITE,
205 &write_socket_watcher_,
206 this)) {
207 PLOG(ERROR) << "WatchFileDescriptor failed on connect, errno " << errno;
208 return net::MapSystemError(errno);
209 }
210
211 write_callback_ = callback;
212 waiting_connect_ = true;
213 return net::ERR_IO_PENDING;
214 }
215
216 bool SocketLibevent::IsConnected() const {
217 DCHECK(thread_checker_.CalledOnValidThread());
218
219 if (socket_fd_ == kInvalidSocket || waiting_connect_)
220 return false;
221
222 // Checks if connection is alive.
223 char c;
224 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
225 if (rv == 0)
226 return false;
227 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
228 return false;
229
230 return true;
231 }
232
233 bool SocketLibevent::IsConnectedAndIdle() const {
234 DCHECK(thread_checker_.CalledOnValidThread());
235
236 if (socket_fd_ == kInvalidSocket || waiting_connect_)
237 return false;
238
239 // Check if connection is alive and we haven't received any data
240 // unexpectedly.
241 char c;
242 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
243 if (rv >= 0)
244 return false;
245 if (errno != EAGAIN && errno != EWOULDBLOCK)
246 return false;
247
248 return true;
249 }
250
251 int SocketLibevent::GetLocalAddress(SockaddrStorage* address) const {
252 DCHECK(thread_checker_.CalledOnValidThread());
253 DCHECK(address);
254
255 if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0)
256 return net::MapSystemError(errno);
257 return net::OK;
258 }
259
260 int SocketLibevent::GetPeerAddress(SockaddrStorage* address) const {
261 DCHECK(thread_checker_.CalledOnValidThread());
262 DCHECK(address);
263
264 if (!HasPeerAddress())
265 return net::ERR_SOCKET_NOT_CONNECTED;
266
267 *address = *peer_address_;
268 return net::OK;
269 }
270
271 void SocketLibevent::SetPeerAddress(const SockaddrStorage& address) {
272 DCHECK(thread_checker_.CalledOnValidThread());
273 // |peer_address_| will be non-NULL if Connect() has been called. Unless
274 // Close() is called to reset the internal state, a second call to Connect()
275 // is not allowed.
276 // Please note that we don't allow a second Connect() even if the previous
277 // Connect() has failed. Connecting the same |socket_| again after a
278 // connection attempt failed results in unspecified behavior according to
279 // POSIX.
280 DCHECK(!peer_address_);
281 peer_address_.reset(new SockaddrStorage(address));
282 }
283
284 bool SocketLibevent::HasPeerAddress() const {
285 DCHECK(thread_checker_.CalledOnValidThread());
286 return peer_address_ != NULL;
287 }
288
289 void SocketLibevent::Close() {
290 DCHECK(thread_checker_.CalledOnValidThread());
291
292 StopWatchingAndCleanUp();
293
294 if (socket_fd_ != kInvalidSocket) {
295 if (IGNORE_EINTR(close(socket_fd_)) < 0)
296 PLOG(ERROR) << "close() returned an error, errno=" << errno;
297 socket_fd_ = kInvalidSocket;
298 }
299 }
300
301 void SocketLibevent::OnFileCanReadWithoutBlocking(int fd) {
302 DCHECK(!accept_callback_.is_null() || !read_callback_.is_null());
303 if (!accept_callback_.is_null()) {
304 AcceptCompleted();
305 } else { // !read_callback_.is_null()
306 NOTREACHED();
307 }
308 }
309
310 void SocketLibevent::OnFileCanWriteWithoutBlocking(int fd) {
311 DCHECK(!write_callback_.is_null());
312 if (waiting_connect_) {
313 ConnectCompleted();
314 } else {
315 NOTREACHED();
316 }
317 }
318
319 int SocketLibevent::DoAccept(scoped_ptr<SocketLibevent>* socket) {
320 SockaddrStorage new_peer_address;
321 int new_socket = HANDLE_EINTR(
322 accept(socket_fd_, new_peer_address.addr, &new_peer_address.addr_len));
323 if (new_socket < 0)
324 return MapAcceptError(errno);
325
326 scoped_ptr<SocketLibevent> accepted_socket(new SocketLibevent);
327 int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address);
328 if (rv != net::OK)
329 return rv;
330
331 *socket = accepted_socket.Pass();
332 return net::OK;
333 }
334
335 void SocketLibevent::AcceptCompleted() {
336 DCHECK(accept_socket_);
337 int rv = DoAccept(accept_socket_);
338 if (rv == net::ERR_IO_PENDING)
339 return;
340
341 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
342 DCHECK(ok);
343 accept_socket_ = NULL;
344 base::ResetAndReturn(&accept_callback_).Run(rv);
345 }
346
347 int SocketLibevent::DoConnect() {
348 int rv = HANDLE_EINTR(
349 connect(socket_fd_, peer_address_->addr, peer_address_->addr_len));
350 DCHECK_GE(0, rv);
351 return rv == 0 ? net::OK : MapConnectError(errno);
352 }
353
354 void SocketLibevent::ConnectCompleted() {
355 // Get the error that connect() completed with.
356 int os_error = 0;
357 socklen_t len = sizeof(os_error);
358 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
359 // TCPSocketLibevent expects errno to be set.
360 errno = os_error;
361 }
362
363 int rv = MapConnectError(errno);
364 if (rv == net::ERR_IO_PENDING)
365 return;
366
367 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
368 DCHECK(ok);
369 waiting_connect_ = false;
370 base::ResetAndReturn(&write_callback_).Run(rv);
371 }
372
373 void SocketLibevent::StopWatchingAndCleanUp() {
374 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
375 DCHECK(ok);
376
377 if (!accept_callback_.is_null()) {
378 accept_socket_ = NULL;
379 accept_callback_.Reset();
380 }
381
382 waiting_connect_ = false;
383 peer_address_.reset();
384 }
385
386 } // namespace shell
387 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/domain_socket/socket_libevent.h ('k') | mojo/shell/domain_socket/test_completion_callback.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698