This source file includes following definitions.
- signal_emitter_
- Init
- RegisterFsType
- UnregisterFsType
- RegisterExitHandler
- open_resource
- open
- pipe
- close
- dup
- dup2
- chdir
- exit
- getcwd
- getwd
- chmod
- chown
- fchown
- lchown
- utime
- mkdir
- rmdir
- stat
- mount
- umount
- read
- write
- fstat
- getdents
- fchdir
- ftruncate
- fsync
- fdatasync
- isatty
- ioctl
- lseek
- unlink
- truncate
- lstat
- rename
- remove
- fchmod
- fcntl
- access
- readlink
- utimes
- link
- symlink
- mmap
- munmap
- tcflush
- tcgetattr
- tcsetattr
- kill
- sigaction
- select
- poll
- accept
- bind
- connect
- freeaddrinfo
- getaddrinfo
- gethostbyname
- getpeername
- getsockname
- getsockopt
- listen
- recv
- recvfrom
- recvmsg
- send
- sendto
- sendmsg
- setsockopt
- shutdown
- socket
- socketpair
- AcquireSocketHandle
#include "nacl_io/kernel_proxy.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <iterator>
#include <string>
#include "nacl_io/devfs/dev_fs.h"
#include "nacl_io/filesystem.h"
#include "nacl_io/fusefs/fuse_fs_factory.h"
#include "nacl_io/host_resolver.h"
#include "nacl_io/html5fs/html5_fs.h"
#include "nacl_io/httpfs/http_fs.h"
#include "nacl_io/kernel_handle.h"
#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/memfs/mem_fs.h"
#include "nacl_io/node.h"
#include "nacl_io/osmman.h"
#include "nacl_io/ossocket.h"
#include "nacl_io/osstat.h"
#include "nacl_io/passthroughfs/passthrough_fs.h"
#include "nacl_io/path.h"
#include "nacl_io/pepper_interface.h"
#include "nacl_io/pipe/pipe_node.h"
#include "nacl_io/socket/tcp_node.h"
#include "nacl_io/socket/udp_node.h"
#include "nacl_io/stream/stream_fs.h"
#include "nacl_io/typed_fs_factory.h"
#include "sdk_util/auto_lock.h"
#include "sdk_util/ref_object.h"
#include "sdk_util/string_util.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif
namespace nacl_io {
KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL),
exit_handler_(NULL),
signal_emitter_(new EventEmitter) {
memset(&sigwinch_handler_, 0, sizeof(sigwinch_handler_));
sigwinch_handler_.sa_handler = SIG_DFL;
}
KernelProxy::~KernelProxy() {
for (FsFactoryMap_t::iterator i = factories_.begin(); i != factories_.end();
++i) {
delete i->second;
}
delete ppapi_;
}
Error KernelProxy::Init(PepperInterface* ppapi) {
Error rtn = 0;
ppapi_ = ppapi;
dev_ = 1;
factories_["memfs"] = new TypedFsFactory<MemFs>;
factories_["dev"] = new TypedFsFactory<DevFs>;
factories_["html5fs"] = new TypedFsFactory<Html5Fs>;
factories_["httpfs"] = new TypedFsFactory<HttpFs>;
factories_["passthroughfs"] = new TypedFsFactory<PassthroughFs>;
int result;
result = mount("", "/", "passthroughfs", 0, NULL);
if (result != 0) {
assert(false);
rtn = errno;
}
result = mount("", "/dev", "dev", 0, NULL);
if (result != 0) {
assert(false);
rtn = errno;
}
int fd;
fd = open("/dev/stdin", O_RDONLY);
assert(fd == 0);
if (fd < 0)
rtn = errno;
fd = open("/dev/stdout", O_WRONLY);
assert(fd == 1);
if (fd < 0)
rtn = errno;
fd = open("/dev/stderr", O_WRONLY);
assert(fd == 2);
if (fd < 0)
rtn = errno;
#ifdef PROVIDES_SOCKET_API
host_resolver_.Init(ppapi_);
#endif
FsInitArgs args;
args.dev = dev_++;
args.ppapi = ppapi_;
stream_mount_.reset(new StreamFs());
result = stream_mount_->Init(args);
if (result != 0) {
assert(false);
rtn = result;
}
return rtn;
}
bool KernelProxy::RegisterFsType(const char* fs_type,
fuse_operations* fuse_ops) {
FsFactoryMap_t::iterator iter = factories_.find(fs_type);
if (iter != factories_.end())
return false;
factories_[fs_type] = new FuseFsFactory(fuse_ops);
return true;
}
bool KernelProxy::UnregisterFsType(const char* fs_type) {
FsFactoryMap_t::iterator iter = factories_.find(fs_type);
if (iter == factories_.end())
return false;
delete iter->second;
factories_.erase(iter);
return true;
}
bool KernelProxy::RegisterExitHandler(nacl_io_exit_handler_t exit_handler,
void* user_data) {
if (exit_handler_ != NULL)
return false;
exit_handler_ = exit_handler;
exit_handler_user_data_ = user_data;
return true;
}
int KernelProxy::open_resource(const char* path) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
ScopedNode node;
error = fs->OpenResource(rel, &node);
if (error) {
error = fs->Open(rel, O_RDONLY, &node);
if (error) {
errno = error;
return -1;
}
}
ScopedKernelHandle handle(new KernelHandle(fs, node));
error = handle->Init(O_RDONLY);
if (error) {
errno = error;
return -1;
}
return AllocateFD(handle, path);
}
int KernelProxy::open(const char* path, int open_flags) {
ScopedFilesystem fs;
ScopedNode node;
Error error = AcquireFsAndNode(path, open_flags, &fs, &node);
if (error) {
errno = error;
return -1;
}
ScopedKernelHandle handle(new KernelHandle(fs, node));
error = handle->Init(open_flags);
if (error) {
errno = error;
return -1;
}
return AllocateFD(handle, path);
}
int KernelProxy::pipe(int pipefds[2]) {
PipeNode* pipe = new PipeNode(stream_mount_.get());
ScopedNode node(pipe);
if (pipe->Init(O_RDWR) == 0) {
ScopedKernelHandle handle0(new KernelHandle(stream_mount_, node));
ScopedKernelHandle handle1(new KernelHandle(stream_mount_, node));
if (handle0->Init(O_RDONLY) || handle1->Init(O_WRONLY)) {
errno = EACCES;
return -1;
}
pipefds[0] = AllocateFD(handle0);
pipefds[1] = AllocateFD(handle1);
return 0;
}
errno = ENOSYS;
return -1;
}
int KernelProxy::close(int fd) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
FreeFD(fd);
return 0;
}
int KernelProxy::dup(int oldfd) {
ScopedKernelHandle handle;
std::string path;
Error error = AcquireHandleAndPath(oldfd, &handle, &path);
if (error) {
errno = error;
return -1;
}
return AllocateFD(handle, path);
}
int KernelProxy::dup2(int oldfd, int newfd) {
if (oldfd == newfd)
return newfd;
ScopedKernelHandle old_handle;
std::string old_path;
Error error = AcquireHandleAndPath(oldfd, &old_handle, &old_path);
if (error) {
errno = error;
return -1;
}
FreeAndReassignFD(newfd, old_handle, old_path);
return newfd;
}
int KernelProxy::chdir(const char* path) {
Error error = SetCWD(path);
if (error) {
errno = error;
return -1;
}
return 0;
}
void KernelProxy::exit(int status) {
if (exit_handler_)
exit_handler_(status, exit_handler_user_data_);
}
char* KernelProxy::getcwd(char* buf, size_t size) {
if (NULL == buf) {
errno = EFAULT;
return NULL;
}
std::string cwd = GetCWD();
if (size <= cwd.size()) {
errno = ERANGE;
return NULL;
}
strcpy(buf, cwd.c_str());
return buf;
}
char* KernelProxy::getwd(char* buf) {
if (NULL == buf) {
errno = EFAULT;
return NULL;
}
return getcwd(buf, MAXPATHLEN);
}
int KernelProxy::chmod(const char* path, mode_t mode) {
int fd = KernelProxy::open(path, O_RDONLY);
if (-1 == fd)
return -1;
int result = fchmod(fd, mode);
close(fd);
return result;
}
int KernelProxy::chown(const char* path, uid_t owner, gid_t group) {
return 0;
}
int KernelProxy::fchown(int fd, uid_t owner, gid_t group) {
return 0;
}
int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) {
return 0;
}
int KernelProxy::utime(const char* filename, const struct utimbuf* times) {
return 0;
}
int KernelProxy::mkdir(const char* path, mode_t mode) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
error = fs->Mkdir(rel, mode);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::rmdir(const char* path) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
error = fs->Rmdir(rel);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::stat(const char* path, struct stat* buf) {
int fd = open(path, O_RDONLY);
if (-1 == fd)
return -1;
int result = fstat(fd, buf);
close(fd);
return result;
}
int KernelProxy::mount(const char* source,
const char* target,
const char* filesystemtype,
unsigned long mountflags,
const void* data) {
std::string abs_path = GetAbsParts(target).Join();
FsFactoryMap_t::iterator factory = factories_.find(filesystemtype);
if (factory == factories_.end()) {
errno = ENODEV;
return -1;
}
StringMap_t smap;
smap["SOURCE"] = source;
smap["TARGET"] = abs_path;
if (data) {
std::vector<std::string> elements;
sdk_util::SplitString(static_cast<const char*>(data), ',', &elements);
for (std::vector<std::string>::const_iterator it = elements.begin();
it != elements.end(); ++it) {
size_t location = it->find('=');
if (location != std::string::npos) {
std::string key = it->substr(0, location);
std::string val = it->substr(location + 1);
smap[key] = val;
} else {
smap[*it] = "TRUE";
}
}
}
FsInitArgs args;
args.dev = dev_++;
args.string_map = smap;
args.ppapi = ppapi_;
ScopedFilesystem fs;
Error error = factory->second->CreateFilesystem(args, &fs);
if (error) {
errno = error;
return -1;
}
error = AttachFsAtPath(fs, abs_path);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::umount(const char* path) {
Error error = DetachFsAtPath(path);
if (error) {
errno = error;
return -1;
}
return 0;
}
ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int cnt = 0;
error = handle->Read(buf, nbytes, &cnt);
if (error) {
errno = error;
return -1;
}
return cnt;
}
ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int cnt = 0;
error = handle->Write(buf, nbytes, &cnt);
if (error) {
errno = error;
return -1;
}
return cnt;
}
int KernelProxy::fstat(int fd, struct stat* buf) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->GetStat(buf);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::getdents(int fd, void* buf, unsigned int count) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int cnt = 0;
error = handle->GetDents(static_cast<dirent*>(buf), count, &cnt);
if (error)
errno = error;
return cnt;
}
int KernelProxy::fchdir(int fd) {
ScopedKernelHandle handle;
std::string path;
Error error = AcquireHandleAndPath(fd, &handle, &path);
if (error) {
errno = error;
return -1;
}
if (!handle->node()->IsaDir()) {
errno = ENOTDIR;
return -1;
}
if (path.empty()) {
errno = EBADF;
return -1;
}
error = SetCWD(path);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::ftruncate(int fd, off_t length) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->FTruncate(length);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::fsync(int fd) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->FSync();
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::fdatasync(int fd) {
errno = ENOSYS;
return -1;
}
int KernelProxy::isatty(int fd) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return 0;
}
error = handle->node()->Isatty();
if (error) {
errno = error;
return 0;
}
return 1;
}
int KernelProxy::ioctl(int fd, int request, va_list args) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->VIoctl(request, args);
if (error) {
errno = error;
return -1;
}
return 0;
}
off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
off_t new_offset;
error = handle->Seek(offset, whence, &new_offset);
if (error) {
errno = error;
return -1;
}
return new_offset;
}
int KernelProxy::unlink(const char* path) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
error = fs->Unlink(rel);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::truncate(const char* path, off_t len) {
int fd = KernelProxy::open(path, O_WRONLY);
if (-1 == fd)
return -1;
int result = ftruncate(fd, len);
close(fd);
return result;
}
int KernelProxy::lstat(const char* path, struct stat* buf) {
return stat(path, buf);
}
int KernelProxy::rename(const char* path, const char* newpath) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
ScopedFilesystem newfs;
Path newrel;
error = AcquireFsAndRelPath(newpath, &newfs, &newrel);
if (error) {
errno = error;
return -1;
}
if (newfs.get() != fs.get()) {
errno = EXDEV;
return -1;
}
if (rel == newrel)
return 0;
error = fs->Rename(rel, newrel);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::remove(const char* path) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
error = fs->Remove(rel);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::fchmod(int fd, int mode) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::fcntl(int fd, int request, va_list args) {
Error error = 0;
switch (request) {
case F_GETFD: {
int rtn = -1;
error = GetFDFlags(fd, &rtn);
if (error) {
errno = error;
return -1;
}
return rtn;
}
case F_SETFD: {
int flags = va_arg(args, int);
error = SetFDFlags(fd, flags);
if (error) {
errno = error;
return -1;
}
return 0;
}
}
ScopedKernelHandle handle;
error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int rtn = 0;
error = handle->VFcntl(request, &rtn, args);
if (error) {
errno = error;
return -1;
}
return rtn;
}
int KernelProxy::access(const char* path, int amode) {
ScopedFilesystem fs;
Path rel;
Error error = AcquireFsAndRelPath(path, &fs, &rel);
if (error) {
errno = error;
return -1;
}
error = fs->Access(rel, amode);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::readlink(const char *path, char *buf, size_t count) {
errno = EINVAL;
return -1;
}
int KernelProxy::utimes(const char *filename, const struct timeval times[2]) {
errno = EINVAL;
return -1;
}
int KernelProxy::link(const char* oldpath, const char* newpath) {
errno = EINVAL;
return -1;
}
int KernelProxy::symlink(const char* oldpath, const char* newpath) {
errno = EINVAL;
return -1;
}
void* KernelProxy::mmap(void* addr,
size_t length,
int prot,
int flags,
int fd,
size_t offset) {
assert((flags & MAP_ANONYMOUS) == 0);
assert(fd != -1);
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return MAP_FAILED;
}
void* new_addr;
error = handle->node()->MMap(addr, length, prot, flags, offset, &new_addr);
if (error) {
errno = error;
return MAP_FAILED;
}
return new_addr;
}
int KernelProxy::munmap(void* addr, size_t length) {
return 0;
}
int KernelProxy::tcflush(int fd, int queue_selector) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->Tcflush(queue_selector);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::tcgetattr(int fd, struct termios* termios_p) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->Tcgetattr(termios_p);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::tcsetattr(int fd, int optional_actions,
const struct termios *termios_p) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->node()->Tcsetattr(optional_actions, termios_p);
if (error) {
errno = error;
return -1;
}
return 0;
}
int KernelProxy::kill(pid_t pid, int sig) {
if (pid != getpid() && pid != -1 && pid != 0) {
errno = ESRCH;
return -1;
}
AUTO_LOCK(signal_emitter_->GetLock())
signal_emitter_->RaiseEvents_Locked(POLLERR);
switch (sig) {
case SIGWINCH:
if (sigwinch_handler_.sa_handler != SIG_IGN &&
sigwinch_handler_.sa_handler != SIG_DFL) {
sigwinch_handler_.sa_handler(SIGWINCH);
}
break;
case SIGUSR1:
case SIGUSR2:
break;
default:
errno = EINVAL;
return -1;
}
return 0;
}
int KernelProxy::sigaction(int signum, const struct sigaction* action,
struct sigaction* oaction) {
if (action && action->sa_flags & SA_SIGINFO) {
errno = EINVAL;
return -1;
}
switch (signum) {
case SIGWINCH: {
if (oaction)
*oaction = sigwinch_handler_;
if (action) {
sigwinch_handler_ = *action;
}
return 0;
}
case SIGHUP:
case SIGINT:
case SIGPIPE:
case SIGPOLL:
case SIGPROF:
case SIGTERM:
case SIGCHLD:
case SIGURG:
case SIGFPE:
case SIGILL:
case SIGQUIT:
case SIGSEGV:
case SIGTRAP:
if (action && action->sa_handler != SIG_DFL) {
errno = EINVAL;
return -1;
}
if (oaction) {
memset(oaction, 0, sizeof(*oaction));
oaction->sa_handler = SIG_DFL;
}
return 0;
case SIGKILL:
case SIGSTOP:
errno = EINVAL;
return -1;
}
errno = EINVAL;
return -1;
}
#ifdef PROVIDES_SOCKET_API
int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
fd_set* exceptfds, struct timeval* timeout) {
fd_set ignore;
std::vector<pollfd> pollfds;
FD_ZERO(&ignore);
if (NULL == readfds)
readfds = &ignore;
if (NULL == writefds)
writefds = &ignore;
if (NULL == exceptfds)
exceptfds = &ignore;
for (int fd = 0; fd < nfds; fd++) {
int events = 0;
if (FD_ISSET(fd, readfds))
events |= POLLIN;
if (FD_ISSET(fd, writefds))
events |= POLLOUT;
if (FD_ISSET(fd, exceptfds))
events |= POLLERR | POLLHUP;
if (events) {
pollfd info;
info.fd = fd;
info.events = events;
pollfds.push_back(info);
}
}
FD_ZERO(readfds);
FD_ZERO(writefds);
FD_ZERO(exceptfds);
int ms_timeout = -1;
if (timeout != NULL) {
int64_t ms = timeout->tv_sec * 1000 + ((timeout->tv_usec + 500) / 1000);
if ((timeout->tv_sec < 0) || (timeout->tv_sec >= (INT_MAX / 1000)) ||
(timeout->tv_usec < 0) || (timeout->tv_usec >= 1000000) ||
(ms < 0) || (ms >= INT_MAX)) {
errno = EINVAL;
return -1;
}
ms_timeout = static_cast<int>(ms);
}
int result = poll(&pollfds[0], pollfds.size(), ms_timeout);
if (result == -1)
return -1;
int event_cnt = 0;
for (size_t index = 0; index < pollfds.size(); index++) {
pollfd* info = &pollfds[index];
if (info->revents & POLLIN) {
FD_SET(info->fd, readfds);
event_cnt++;
}
if (info->revents & POLLOUT) {
FD_SET(info->fd, writefds);
event_cnt++;
}
if (info->revents & (POLLHUP | POLLERR)) {
FD_SET(info->fd, exceptfds);
event_cnt++;
}
}
return event_cnt;
}
struct PollInfo {
PollInfo() : index(-1) {};
std::vector<struct pollfd*> fds;
int index;
};
typedef std::map<EventEmitter*, PollInfo> EventPollMap_t;
int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
EventPollMap_t event_map;
std::vector<EventRequest> requests;
size_t event_cnt = 0;
for (int index = 0; static_cast<nfds_t>(index) < nfds; index++) {
ScopedKernelHandle handle;
struct pollfd* fd_info = &fds[index];
Error err = AcquireHandle(fd_info->fd, &handle);
fd_info->revents = 0;
if (err != 0) {
fd_info->revents = POLLNVAL;
event_cnt++;
continue;
}
ScopedEventEmitter emitter(handle->node()->GetEventEmitter());
int events = POLLIN | POLLOUT;
if (emitter)
events = emitter->GetEventStatus();
if (events & fd_info->events) {
fd_info->revents = events & fd_info->events;
event_cnt++;
continue;
}
if (NULL == emitter) {
fd_info->revents = POLLNVAL;
event_cnt++;
continue;
}
PollInfo* info = &event_map[emitter.get()];
if (info->index == -1) {
EventRequest request;
request.emitter = emitter;
request.filter = fd_info->events;
request.events = 0;
info->index = requests.size();
requests.push_back(request);
}
info->fds.push_back(fd_info);
requests[info->index].filter |= fd_info->events;
}
if (0 == event_cnt) {
EventListenerPoll wait;
Error err = wait.WaitOnAny(&requests[0], requests.size(), timeout);
if ((err != 0) && (err != ETIMEDOUT)) {
errno = err;
return -1;
}
for (size_t rindex = 0; rindex < requests.size(); rindex++) {
EventRequest* request = &requests[rindex];
if (request->events) {
PollInfo* poll_info = &event_map[request->emitter.get()];
for (size_t findex = 0; findex < poll_info->fds.size(); findex++) {
struct pollfd* fd_info = poll_info->fds[findex];
uint32_t events = fd_info->events & request->events;
if (events) {
fd_info->revents = events;
event_cnt++;
}
}
}
}
}
return event_cnt;
}
int KernelProxy::accept(int fd, struct sockaddr* addr, socklen_t* len) {
if (NULL == addr || NULL == len) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
PP_Resource new_sock = 0;
error = handle->Accept(&new_sock, addr, len);
if (error != 0) {
errno = error;
return -1;
}
SocketNode* sock = new TcpNode(stream_mount_.get(), new_sock);
ppapi_->ReleaseResource(new_sock);
error = sock->Init(O_RDWR);
if (error != 0) {
errno = error;
return -1;
}
ScopedNode node(sock);
ScopedKernelHandle new_handle(new KernelHandle(stream_mount_, node));
error = new_handle->Init(O_RDWR);
if (error != 0) {
errno = error;
return -1;
}
return AllocateFD(new_handle);
}
int KernelProxy::bind(int fd, const struct sockaddr* addr, socklen_t len) {
if (NULL == addr) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->Bind(addr, len);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
int KernelProxy::connect(int fd, const struct sockaddr* addr, socklen_t len) {
if (NULL == addr) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
error = handle->Connect(addr, len);
if (error != 0) {
errno = error;
return -1;
}
return 0;
}
void KernelProxy::freeaddrinfo(struct addrinfo *res) {
return host_resolver_.freeaddrinfo(res);
}
int KernelProxy::getaddrinfo(const char* node, const char* service,
const struct addrinfo* hints,
struct addrinfo** res) {
return host_resolver_.getaddrinfo(node, service, hints, res);
}
struct hostent* KernelProxy::gethostbyname(const char* name) {
return host_resolver_.gethostbyname(name);
}
int KernelProxy::getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
if (NULL == addr || NULL == len) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->GetPeerName(addr, len);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
int KernelProxy::getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
if (NULL == addr || NULL == len) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->GetSockName(addr, len);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
int KernelProxy::getsockopt(int fd,
int lvl,
int optname,
void* optval,
socklen_t* len) {
if (NULL == optval || NULL == len) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->GetSockOpt(lvl, optname, optval, len);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
int KernelProxy::listen(int fd, int backlog) {
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->Listen(backlog);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
ssize_t KernelProxy::recv(int fd,
void* buf,
size_t len,
int flags) {
if (NULL == buf) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int out_len = 0;
error = handle->Recv(buf, len, flags, &out_len);
if (error != 0) {
errno = error;
return -1;
}
return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::recvfrom(int fd,
void* buf,
size_t len,
int flags,
struct sockaddr* addr,
socklen_t* addrlen) {
if (NULL == addr) {
return recv(fd, buf, len, flags);
}
if (NULL == buf || NULL == addrlen) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int out_len = 0;
error = handle->RecvFrom(buf, len, flags, addr, addrlen, &out_len);
if (error != 0) {
errno = error;
return -1;
}
return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::recvmsg(int fd, struct msghdr* msg, int flags) {
if (NULL == msg ) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
errno = EOPNOTSUPP;
return -1;
}
ssize_t KernelProxy::send(int fd, const void* buf, size_t len, int flags) {
if (NULL == buf) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int out_len = 0;
error = handle->Send(buf, len, flags, &out_len);
if (error != 0) {
errno = error;
return -1;
}
return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::sendto(int fd,
const void* buf,
size_t len,
int flags,
const struct sockaddr* addr,
socklen_t addrlen) {
if (NULL == addr) {
return send(fd, buf, len, flags);
}
if (NULL == buf) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
int out_len = 0;
error = handle->SendTo(buf, len, flags, addr, addrlen, &out_len);
if (error != 0) {
errno = error;
return -1;
}
return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::sendmsg(int fd, const struct msghdr* msg, int flags) {
if (NULL == msg) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
errno = EOPNOTSUPP;
return -1;
}
int KernelProxy::setsockopt(int fd,
int lvl,
int optname,
const void* optval,
socklen_t len) {
if (NULL == optval) {
errno = EFAULT;
return -1;
}
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->SetSockOpt(lvl, optname, optval, len);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
int KernelProxy::shutdown(int fd, int how) {
ScopedKernelHandle handle;
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
Error err = handle->socket_node()->Shutdown(how);
if (err != 0) {
errno = err;
return -1;
}
return 0;
}
int KernelProxy::socket(int domain, int type, int protocol) {
if (AF_INET != domain && AF_INET6 != domain) {
errno = EAFNOSUPPORT;
return -1;
}
int open_flags = O_RDWR;
if (type & SOCK_CLOEXEC) {
#ifdef O_CLOEXEC
open_flags |= O_CLOEXEC;
#endif
type &= ~SOCK_CLOEXEC;
}
if (type & SOCK_NONBLOCK) {
open_flags |= O_NONBLOCK;
type &= ~SOCK_NONBLOCK;
}
SocketNode* sock = NULL;
switch (type) {
case SOCK_DGRAM:
sock = new UdpNode(stream_mount_.get());
break;
case SOCK_STREAM:
sock = new TcpNode(stream_mount_.get());
break;
case SOCK_SEQPACKET:
case SOCK_RDM:
case SOCK_RAW:
errno = EPROTONOSUPPORT;
return -1;
default:
errno = EINVAL;
return -1;
}
ScopedNode node(sock);
Error rtn = sock->Init(O_RDWR);
if (rtn != 0) {
errno = rtn;
return -1;
}
ScopedKernelHandle handle(new KernelHandle(stream_mount_, node));
rtn = handle->Init(open_flags);
if (rtn != 0) {
errno = rtn;
return -1;
}
return AllocateFD(handle);
}
int KernelProxy::socketpair(int domain, int type, int protocol, int* sv) {
if (NULL == sv) {
errno = EFAULT;
return -1;
}
if (AF_UNIX != domain) {
errno = EPROTONOSUPPORT;
return -1;
}
if (AF_INET != domain && AF_INET6 != domain) {
errno = EAFNOSUPPORT;
return -1;
}
errno = ENOSYS;
return -1;
}
int KernelProxy::AcquireSocketHandle(int fd, ScopedKernelHandle* handle) {
Error error = AcquireHandle(fd, handle);
if (error) {
errno = error;
return -1;
}
if ((handle->get()->node_->GetType() & S_IFSOCK) == 0) {
errno = ENOTSOCK;
return -1;
}
return 0;
}
#endif
}