mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 974410: Added watcher classes for Unix file descriptors, r=kyle
These new classes encasulate file-descriptor watchers, basic file descriptors, and socket connections. Each class contains callback methods for it's implemented functionality. Users should inherit from the classes and overload the callback with their own code.
This commit is contained in:
parent
c71b7cc20d
commit
51ec78121a
@ -21,9 +21,9 @@ if CONFIG['MOZ_NFC']:
|
||||
DIRS += ['nfc']
|
||||
|
||||
if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
DIRS += ['unixsocket']
|
||||
DIRS += ['unixfd', 'unixsocket']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
DIRS += ['netd', 'keystore']
|
||||
DIRS += ['keystore', 'netd']
|
||||
|
||||
TOOL_DIRS += ['app']
|
||||
|
119
ipc/unixfd/UnixFdWatcher.cpp
Normal file
119
ipc/unixfd/UnixFdWatcher.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "UnixFdWatcher.h"
|
||||
|
||||
#ifdef CHROMIUM_LOG
|
||||
#undef CHROMIUM_LOG
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args);
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define IODEBUG true
|
||||
#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
UnixFdWatcher::~UnixFdWatcher()
|
||||
{
|
||||
NS_WARN_IF(IsOpen()); /* mFd should have been closed already */
|
||||
}
|
||||
|
||||
void
|
||||
UnixFdWatcher::Close()
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
|
||||
|
||||
if (NS_WARN_IF(!IsOpen())) {
|
||||
/* mFd should have been open */
|
||||
return;
|
||||
}
|
||||
OnClose();
|
||||
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
|
||||
mFd.dispose();
|
||||
}
|
||||
|
||||
void
|
||||
UnixFdWatcher::AddWatchers(unsigned long aWatchers, bool aPersistent)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
|
||||
MOZ_ASSERT(IsOpen());
|
||||
|
||||
// Before we add a watcher, we need to remove it! Removing is always
|
||||
// safe, but adding the same watcher twice can lead to endless loops
|
||||
// inside libevent.
|
||||
RemoveWatchers(aWatchers);
|
||||
|
||||
if (aWatchers & READ_WATCHER) {
|
||||
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||
mFd,
|
||||
aPersistent,
|
||||
MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher,
|
||||
this);
|
||||
}
|
||||
if (aWatchers & WRITE_WATCHER) {
|
||||
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||
mFd,
|
||||
aPersistent,
|
||||
MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnixFdWatcher::RemoveWatchers(unsigned long aWatchers)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
|
||||
MOZ_ASSERT(IsOpen());
|
||||
|
||||
if (aWatchers & READ_WATCHER) {
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
if (aWatchers & WRITE_WATCHER) {
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnixFdWatcher::OnError(const char* aFunction, int aErrno)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
|
||||
|
||||
CHROMIUM_LOG("%s failed with error %d (%s)",
|
||||
aFunction, aErrno, strerror(aErrno));
|
||||
}
|
||||
|
||||
UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop)
|
||||
: mIOLoop(aIOLoop)
|
||||
{
|
||||
MOZ_ASSERT(mIOLoop);
|
||||
}
|
||||
|
||||
UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop, int aFd)
|
||||
: mIOLoop(aIOLoop)
|
||||
, mFd(aFd)
|
||||
{
|
||||
MOZ_ASSERT(mIOLoop);
|
||||
}
|
||||
|
||||
void
|
||||
UnixFdWatcher::SetFd(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
|
||||
MOZ_ASSERT(!IsOpen());
|
||||
|
||||
mFd = aFd;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
62
ipc/unixfd/UnixFdWatcher.h
Normal file
62
ipc/unixfd/UnixFdWatcher.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class UnixFdWatcher : public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
READ_WATCHER = 1<<0,
|
||||
WRITE_WATCHER = 1<<1
|
||||
};
|
||||
|
||||
virtual ~UnixFdWatcher();
|
||||
|
||||
MessageLoop* GetIOLoop() const
|
||||
{
|
||||
return mIOLoop;
|
||||
}
|
||||
|
||||
int GetFd() const
|
||||
{
|
||||
return mFd;
|
||||
}
|
||||
|
||||
bool IsOpen() const
|
||||
{
|
||||
return GetFd() >= 0;
|
||||
}
|
||||
|
||||
virtual void Close();
|
||||
|
||||
void AddWatchers(unsigned long aWatchers, bool aPersistent);
|
||||
void RemoveWatchers(unsigned long aWatchers);
|
||||
|
||||
// Callback method that's run before closing the file descriptor
|
||||
virtual void OnClose() {};
|
||||
|
||||
// Callback method that's run on POSIX errors
|
||||
virtual void OnError(const char* aFunction, int aErrno);
|
||||
|
||||
protected:
|
||||
UnixFdWatcher(MessageLoop* aIOLoop);
|
||||
UnixFdWatcher(MessageLoop* aIOLoop, int aFd);
|
||||
void SetFd(int aFd);
|
||||
|
||||
private:
|
||||
MessageLoop* mIOLoop;
|
||||
ScopedClose mFd;
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
44
ipc/unixfd/UnixFileWatcher.cpp
Normal file
44
ipc/unixfd/UnixFileWatcher.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "UnixFileWatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
UnixFileWatcher::~UnixFileWatcher()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnixFileWatcher::Open(const char* aFilename, int aFlags, mode_t aMode)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
|
||||
int fd = TEMP_FAILURE_RETRY(open(aFilename, aFlags, aMode));
|
||||
if (fd < 0) {
|
||||
OnError("open", errno);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SetFd(fd);
|
||||
OnOpened();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop)
|
||||
: UnixFdWatcher(aIOLoop)
|
||||
{
|
||||
}
|
||||
|
||||
UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop, int aFd)
|
||||
: UnixFdWatcher(aIOLoop, aFd)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
28
ipc/unixfd/UnixFileWatcher.h
Normal file
28
ipc/unixfd/UnixFileWatcher.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "UnixFdWatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class UnixFileWatcher : public UnixFdWatcher
|
||||
{
|
||||
public:
|
||||
virtual ~UnixFileWatcher();
|
||||
|
||||
nsresult Open(const char* aFilename, int aFlags, mode_t aMode = 0);
|
||||
|
||||
// Callback method for successful open requests
|
||||
virtual void OnOpened() {};
|
||||
|
||||
protected:
|
||||
UnixFileWatcher(MessageLoop* aIOLoop);
|
||||
UnixFileWatcher(MessageLoop* aIOLoop, int aFd);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
155
ipc/unixfd/UnixSocketWatcher.cpp
Normal file
155
ipc/unixfd/UnixSocketWatcher.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "UnixSocketWatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
UnixSocketWatcher::~UnixSocketWatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void UnixSocketWatcher::Close()
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
|
||||
mConnectionStatus = SOCKET_IS_DISCONNECTED;
|
||||
UnixFdWatcher::Close();
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
MOZ_ASSERT(IsOpen());
|
||||
MOZ_ASSERT(aAddr || !aAddrLen);
|
||||
|
||||
// Select non-blocking IO.
|
||||
if (TEMP_FAILURE_RETRY(fcntl(GetFd(), F_SETFL, O_NONBLOCK)) < 0) {
|
||||
OnError("fcntl", errno);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (connect(GetFd(), aAddr, aAddrLen) < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
// Select blocking IO again, since we've now at least queue'd the connect
|
||||
// as nonblock.
|
||||
int flags = TEMP_FAILURE_RETRY(fcntl(GetFd(), F_GETFL, 0));
|
||||
if (flags < 0) {
|
||||
OnError("fcntl", errno);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY(fcntl(GetFd(), F_SETFL, flags&~O_NONBLOCK)) < 0) {
|
||||
OnError("fcntl", errno);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mConnectionStatus = SOCKET_IS_CONNECTING;
|
||||
// Set up a write watch to receive the connect signal
|
||||
AddWatchers(WRITE_WATCHER, false);
|
||||
} else {
|
||||
OnError("connect", errno);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mConnectionStatus = SOCKET_IS_CONNECTED;
|
||||
OnConnected();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
MOZ_ASSERT(IsOpen());
|
||||
MOZ_ASSERT(aAddr || !aAddrLen);
|
||||
|
||||
if (bind(GetFd(), aAddr, aAddrLen) < 0) {
|
||||
OnError("bind", errno);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (listen(GetFd(), 1) < 0) {
|
||||
OnError("listen", errno);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mConnectionStatus = SOCKET_IS_LISTENING;
|
||||
OnListening();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop)
|
||||
: UnixFdWatcher(aIOLoop)
|
||||
, mConnectionStatus(SOCKET_IS_DISCONNECTED)
|
||||
{
|
||||
}
|
||||
|
||||
UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
|
||||
ConnectionStatus aConnectionStatus)
|
||||
: UnixFdWatcher(aIOLoop, aFd)
|
||||
, mConnectionStatus(aConnectionStatus)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
|
||||
SetFd(aFd);
|
||||
mConnectionStatus = aConnectionStatus;
|
||||
}
|
||||
|
||||
void
|
||||
UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
MOZ_ASSERT(aFd == GetFd());
|
||||
|
||||
if (mConnectionStatus == SOCKET_IS_CONNECTED) {
|
||||
OnSocketCanReceiveWithoutBlocking();
|
||||
} else if (mConnectionStatus == SOCKET_IS_LISTENING) {
|
||||
int fd = TEMP_FAILURE_RETRY(accept(GetFd(), NULL, NULL));
|
||||
if (fd < 0) {
|
||||
OnError("accept", errno);
|
||||
} else {
|
||||
OnAccepted(fd);
|
||||
}
|
||||
} else {
|
||||
NS_NOTREACHED("invalid connection state for reading");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
|
||||
MOZ_ASSERT(aFd == GetFd());
|
||||
|
||||
if (mConnectionStatus == SOCKET_IS_CONNECTED) {
|
||||
OnSocketCanSendWithoutBlocking();
|
||||
} else if (mConnectionStatus == SOCKET_IS_CONNECTING) {
|
||||
RemoveWatchers(WRITE_WATCHER);
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
|
||||
OnError("getsockopt", errno);
|
||||
} else if (error) {
|
||||
OnError("connect", error);
|
||||
} else {
|
||||
mConnectionStatus = SOCKET_IS_CONNECTED;
|
||||
OnConnected();
|
||||
}
|
||||
} else {
|
||||
NS_NOTREACHED("invalid connection state for writing");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
66
ipc/unixfd/UnixSocketWatcher.h
Normal file
66
ipc/unixfd/UnixSocketWatcher.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "UnixFdWatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class UnixSocketWatcher : public UnixFdWatcher
|
||||
{
|
||||
public:
|
||||
enum ConnectionStatus {
|
||||
SOCKET_IS_DISCONNECTED = 0,
|
||||
SOCKET_IS_LISTENING,
|
||||
SOCKET_IS_CONNECTING,
|
||||
SOCKET_IS_CONNECTED
|
||||
};
|
||||
|
||||
virtual ~UnixSocketWatcher();
|
||||
|
||||
virtual void Close() MOZ_OVERRIDE;
|
||||
|
||||
ConnectionStatus GetConnectionStatus() const
|
||||
{
|
||||
return mConnectionStatus;
|
||||
}
|
||||
|
||||
// Connect to a peer
|
||||
nsresult Connect(const struct sockaddr* aAddr, socklen_t aAddrLen);
|
||||
|
||||
// Listen on socket for incomming connection requests
|
||||
nsresult Listen(const struct sockaddr* aAddr, socklen_t aAddrLen);
|
||||
|
||||
// Callback method for accepted connections
|
||||
virtual void OnAccepted(int aFd) {};
|
||||
|
||||
// Callback method for successful connection requests
|
||||
virtual void OnConnected() {};
|
||||
|
||||
// Callback method for successful listen requests
|
||||
virtual void OnListening() {};
|
||||
|
||||
// Callback method for receiving from socket
|
||||
virtual void OnSocketCanReceiveWithoutBlocking() {};
|
||||
|
||||
// Callback method for sending on socket
|
||||
virtual void OnSocketCanSendWithoutBlocking() {};
|
||||
|
||||
protected:
|
||||
UnixSocketWatcher(MessageLoop* aIOLoop);
|
||||
UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
|
||||
ConnectionStatus aConnectionStatus);
|
||||
void SetSocket(int aFd, ConnectionStatus aConnectionStatus);
|
||||
|
||||
private:
|
||||
void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE;
|
||||
void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE;
|
||||
|
||||
ConnectionStatus mConnectionStatus;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
23
ipc/unixfd/moz.build
Normal file
23
ipc/unixfd/moz.build
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.ipc += [
|
||||
'UnixFdWatcher.h',
|
||||
'UnixFileWatcher.h',
|
||||
'UnixSocketWatcher.h'
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'UnixFdWatcher.cpp',
|
||||
'UnixFileWatcher.cpp',
|
||||
'UnixSocketWatcher.cpp'
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
Loading…
Reference in New Issue
Block a user