1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/unixfd/UnixSocketWatcher.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,141 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <fcntl.h> 1.11 +#include "UnixSocketWatcher.h" 1.12 + 1.13 +namespace mozilla { 1.14 +namespace ipc { 1.15 + 1.16 +UnixSocketWatcher::~UnixSocketWatcher() 1.17 +{ 1.18 +} 1.19 + 1.20 +void UnixSocketWatcher::Close() 1.21 +{ 1.22 + MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); 1.23 + 1.24 + mConnectionStatus = SOCKET_IS_DISCONNECTED; 1.25 + UnixFdWatcher::Close(); 1.26 +} 1.27 + 1.28 +nsresult 1.29 +UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen) 1.30 +{ 1.31 + MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); 1.32 + MOZ_ASSERT(IsOpen()); 1.33 + MOZ_ASSERT(aAddr || !aAddrLen); 1.34 + 1.35 + if (connect(GetFd(), aAddr, aAddrLen) < 0) { 1.36 + if (errno == EINPROGRESS) { 1.37 + mConnectionStatus = SOCKET_IS_CONNECTING; 1.38 + // Set up a write watch to receive the connect signal 1.39 + AddWatchers(WRITE_WATCHER, false); 1.40 + } else { 1.41 + OnError("connect", errno); 1.42 + } 1.43 + return NS_ERROR_FAILURE; 1.44 + } 1.45 + 1.46 + mConnectionStatus = SOCKET_IS_CONNECTED; 1.47 + OnConnected(); 1.48 + 1.49 + return NS_OK; 1.50 +} 1.51 + 1.52 +nsresult 1.53 +UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen) 1.54 +{ 1.55 + MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); 1.56 + MOZ_ASSERT(IsOpen()); 1.57 + MOZ_ASSERT(aAddr || !aAddrLen); 1.58 + 1.59 + if (bind(GetFd(), aAddr, aAddrLen) < 0) { 1.60 + OnError("bind", errno); 1.61 + return NS_ERROR_FAILURE; 1.62 + } 1.63 + if (listen(GetFd(), 1) < 0) { 1.64 + OnError("listen", errno); 1.65 + return NS_ERROR_FAILURE; 1.66 + } 1.67 + mConnectionStatus = SOCKET_IS_LISTENING; 1.68 + OnListening(); 1.69 + 1.70 + return NS_OK; 1.71 +} 1.72 + 1.73 +UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop) 1.74 +: UnixFdWatcher(aIOLoop) 1.75 +, mConnectionStatus(SOCKET_IS_DISCONNECTED) 1.76 +{ 1.77 +} 1.78 + 1.79 +UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd, 1.80 + ConnectionStatus aConnectionStatus) 1.81 +: UnixFdWatcher(aIOLoop, aFd) 1.82 +, mConnectionStatus(aConnectionStatus) 1.83 +{ 1.84 +} 1.85 + 1.86 +void 1.87 +UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus) 1.88 +{ 1.89 + MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); 1.90 + 1.91 + SetFd(aFd); 1.92 + mConnectionStatus = aConnectionStatus; 1.93 +} 1.94 + 1.95 +void 1.96 +UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd) 1.97 +{ 1.98 + MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); 1.99 + MOZ_ASSERT(aFd == GetFd()); 1.100 + 1.101 + if (mConnectionStatus == SOCKET_IS_CONNECTED) { 1.102 + OnSocketCanReceiveWithoutBlocking(); 1.103 + } else if (mConnectionStatus == SOCKET_IS_LISTENING) { 1.104 + sockaddr_any addr; 1.105 + socklen_t addrLen = sizeof(addr); 1.106 + int fd = TEMP_FAILURE_RETRY(accept(GetFd(), 1.107 + reinterpret_cast<struct sockaddr*>(&addr), &addrLen)); 1.108 + if (fd < 0) { 1.109 + OnError("accept", errno); 1.110 + } else { 1.111 + OnAccepted(fd, &addr, addrLen); 1.112 + } 1.113 + } else { 1.114 + NS_NOTREACHED("invalid connection state for reading"); 1.115 + } 1.116 +} 1.117 + 1.118 +void 1.119 +UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd) 1.120 +{ 1.121 + MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); 1.122 + MOZ_ASSERT(aFd == GetFd()); 1.123 + 1.124 + if (mConnectionStatus == SOCKET_IS_CONNECTED) { 1.125 + OnSocketCanSendWithoutBlocking(); 1.126 + } else if (mConnectionStatus == SOCKET_IS_CONNECTING) { 1.127 + RemoveWatchers(WRITE_WATCHER); 1.128 + int error = 0; 1.129 + socklen_t len = sizeof(error); 1.130 + if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 1.131 + OnError("getsockopt", errno); 1.132 + } else if (error) { 1.133 + OnError("connect", error); 1.134 + } else { 1.135 + mConnectionStatus = SOCKET_IS_CONNECTED; 1.136 + OnConnected(); 1.137 + } 1.138 + } else { 1.139 + NS_NOTREACHED("invalid connection state for writing"); 1.140 + } 1.141 +} 1.142 + 1.143 +} 1.144 +}