michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include "UnixSocketWatcher.h" michael@0: michael@0: namespace mozilla { michael@0: namespace ipc { michael@0: michael@0: UnixSocketWatcher::~UnixSocketWatcher() michael@0: { michael@0: } michael@0: michael@0: void UnixSocketWatcher::Close() michael@0: { michael@0: MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); michael@0: michael@0: mConnectionStatus = SOCKET_IS_DISCONNECTED; michael@0: UnixFdWatcher::Close(); michael@0: } michael@0: michael@0: nsresult michael@0: UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen) michael@0: { michael@0: MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); michael@0: MOZ_ASSERT(IsOpen()); michael@0: MOZ_ASSERT(aAddr || !aAddrLen); michael@0: michael@0: if (connect(GetFd(), aAddr, aAddrLen) < 0) { michael@0: if (errno == EINPROGRESS) { michael@0: mConnectionStatus = SOCKET_IS_CONNECTING; michael@0: // Set up a write watch to receive the connect signal michael@0: AddWatchers(WRITE_WATCHER, false); michael@0: } else { michael@0: OnError("connect", errno); michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mConnectionStatus = SOCKET_IS_CONNECTED; michael@0: OnConnected(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen) michael@0: { michael@0: MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); michael@0: MOZ_ASSERT(IsOpen()); michael@0: MOZ_ASSERT(aAddr || !aAddrLen); michael@0: michael@0: if (bind(GetFd(), aAddr, aAddrLen) < 0) { michael@0: OnError("bind", errno); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: if (listen(GetFd(), 1) < 0) { michael@0: OnError("listen", errno); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: mConnectionStatus = SOCKET_IS_LISTENING; michael@0: OnListening(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop) michael@0: : UnixFdWatcher(aIOLoop) michael@0: , mConnectionStatus(SOCKET_IS_DISCONNECTED) michael@0: { michael@0: } michael@0: michael@0: UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd, michael@0: ConnectionStatus aConnectionStatus) michael@0: : UnixFdWatcher(aIOLoop, aFd) michael@0: , mConnectionStatus(aConnectionStatus) michael@0: { michael@0: } michael@0: michael@0: void michael@0: UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus) michael@0: { michael@0: MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); michael@0: michael@0: SetFd(aFd); michael@0: mConnectionStatus = aConnectionStatus; michael@0: } michael@0: michael@0: void michael@0: UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd) michael@0: { michael@0: MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); michael@0: MOZ_ASSERT(aFd == GetFd()); michael@0: michael@0: if (mConnectionStatus == SOCKET_IS_CONNECTED) { michael@0: OnSocketCanReceiveWithoutBlocking(); michael@0: } else if (mConnectionStatus == SOCKET_IS_LISTENING) { michael@0: sockaddr_any addr; michael@0: socklen_t addrLen = sizeof(addr); michael@0: int fd = TEMP_FAILURE_RETRY(accept(GetFd(), michael@0: reinterpret_cast(&addr), &addrLen)); michael@0: if (fd < 0) { michael@0: OnError("accept", errno); michael@0: } else { michael@0: OnAccepted(fd, &addr, addrLen); michael@0: } michael@0: } else { michael@0: NS_NOTREACHED("invalid connection state for reading"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd) michael@0: { michael@0: MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); michael@0: MOZ_ASSERT(aFd == GetFd()); michael@0: michael@0: if (mConnectionStatus == SOCKET_IS_CONNECTED) { michael@0: OnSocketCanSendWithoutBlocking(); michael@0: } else if (mConnectionStatus == SOCKET_IS_CONNECTING) { michael@0: RemoveWatchers(WRITE_WATCHER); michael@0: int error = 0; michael@0: socklen_t len = sizeof(error); michael@0: if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) { michael@0: OnError("getsockopt", errno); michael@0: } else if (error) { michael@0: OnError("connect", error); michael@0: } else { michael@0: mConnectionStatus = SOCKET_IS_CONNECTED; michael@0: OnConnected(); michael@0: } michael@0: } else { michael@0: NS_NOTREACHED("invalid connection state for writing"); michael@0: } michael@0: } michael@0: michael@0: } michael@0: }