Index: libraries/nacl-mounts/net/SocketSubSystem.cc |
=================================================================== |
--- libraries/nacl-mounts/net/SocketSubSystem.cc (revision 0) |
+++ libraries/nacl-mounts/net/SocketSubSystem.cc (revision 0) |
@@ -0,0 +1,310 @@ |
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <arpa/inet.h> |
+#include <irt.h> |
+#include <netinet/in.h> |
+#include <signal.h> |
+#include <string.h> |
+#include <sys/socket.h> |
+ |
+#include "base/KernelProxy.h" |
+#include "net/SocketSubSystem.h" |
+#include "net/TcpServerSocket.h" |
+#include "net/TcpSocket.h" |
+#include "ppapi/cpp/file_ref.h" |
+#include "util/DebugPrint.h" |
+ |
+FileStream* const SocketSubSystem::kBadFileStream = |
+ reinterpret_cast<FileStream*>(-1); |
+ |
+SocketSubSystem* SocketSubSystem::instance_ = NULL; |
+ |
+SocketSubSystem::SocketSubSystem(pp::Instance* instance) |
+ : pp_instance_(instance) |
+ , first_unused_addr_(kFirstAddr) { |
+ AddHostAddress("localhost", 0x7F000001); |
+ instance_ = this; |
+} |
+ |
+void SocketSubSystem::AddHostAddress(const char* name, unsigned long addr) { |
+ addr = htonl(addr); |
+ hosts_[name] = addr; |
+ addrs_[addr] = name; |
+} |
+ |
+unsigned long SocketSubSystem::gethostbyname(const char* name) { |
+ Mutex::Lock lock(mutex_); |
+ HostMap::iterator it = hosts_.find(name); |
+ if (it != hosts_.end()) |
+ return it->second; |
+ |
+ int addr = htonl(first_unused_addr_++); |
+ hosts_[name] = addr; |
+ addrs_[addr] = name; |
+ return addr; |
+} |
+ |
+int SocketSubSystem::socket(int socket_family, int socket_type, int protocol) { |
+ Mutex::Lock lock(mutex_); |
+ int fd = KernelProxy::KPInstance()->CreateSocket(); |
+ return fd; |
+} |
+ |
+int SocketSubSystem::GetFirstUnusedDescriptor() { |
+ return KernelProxy::KPInstance()->CreateSocket(); |
+} |
+ |
+bool SocketSubSystem::IsKnowDescriptor(int fd) { |
+ return KernelProxy::KPInstance()->GetFileHandle(fd) != 0 && |
+ KernelProxy::KPInstance()->GetFileHandle(fd)->stream != kBadFileStream; |
+} |
+ |
+FileStream* SocketSubSystem::GetStream(int fd) { |
+ return KernelProxy::KPInstance()->GetFileHandle(fd)->stream; |
+} |
+ |
+int SocketSubSystem::bind(FileHandle* handle, unsigned long addr, |
+ unsigned short port) { |
+ Mutex::Lock lock(mutex_); |
+ |
+ std::string host; |
+ AddressMap::iterator it = addrs_.find(addr); |
+ if (it != addrs_.end()) { |
+ host = it->second; |
+ } else { |
+ in_addr iaddr; |
+ iaddr.s_addr = addr; |
+ host = inet_ntoa(iaddr); |
+ } |
+ |
+ handle->stream = new TCPServerSocket(0, host.c_str(), port); |
+ return 0; |
+} |
+ |
+int SocketSubSystem::connect(FileHandle* handle, unsigned long addr, |
+ unsigned short port) { |
+ Mutex::Lock lock(mutex_); |
+ |
+ std::string host; |
+ AddressMap::iterator it = addrs_.find(addr); |
+ if (it != addrs_.end()) { |
+ host = it->second; |
+ } else { |
+ in_addr iaddr; |
+ iaddr.s_addr = addr; |
+ host = inet_ntoa(iaddr); |
+ } |
+ |
+ FileStream* stream = NULL; |
+ TCPSocket* socket = new TCPSocket(O_RDWR); |
+ if (!socket->connect(host.c_str(), port)) { |
+ errno = ECONNREFUSED; |
+ socket->release(); |
+ return -1; |
+ } |
+ stream = socket; |
+ |
+ handle->stream = stream; |
+ return 0; |
+} |
+ |
+SocketSubSystem::~SocketSubSystem() { |
+} |
+ |
+int SocketSubSystem::shutdown(int fd, int how) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = GetStream(fd); |
+ if (stream && stream != kBadFileStream) { |
+ // Actually shutdown should be something more complicated by for now |
+ // it works. Method close can be called multiple time. |
+ stream->close(); |
+ return 0; |
+ } else { |
+ errno = EBADF; |
+ return -1; |
+ } |
+} |
+ |
+int SocketSubSystem::close(int fd) { |
+ Mutex::Lock lock(mutex_); |
+ if (!IsKnowDescriptor(fd)) |
+ return EBADF; |
+ |
+ FileStream* stream = GetStream(fd); |
+ if (stream && stream != kBadFileStream) { |
+ stream->close(); |
+ stream->release(); |
+ } |
+ KernelProxy::KPInstance()->RemoveFileStream(fd); |
+ return 0; |
+} |
+ |
+int SocketSubSystem::read(FileHandle* handle, char* buf, size_t count, |
+ size_t* nread) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = handle->stream; |
+ if (stream && stream != kBadFileStream) |
+ return stream->read(buf, count, nread); |
+ else |
+ return EBADF; |
+} |
+ |
+int SocketSubSystem::write(FileHandle* handle, const char* buf, size_t count, |
+ size_t* nwrote) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = handle->stream; |
+ if (stream && stream != kBadFileStream) |
+ return stream->write(buf, count, nwrote); |
+ else |
+ return EBADF; |
+} |
+ |
+int SocketSubSystem::seek(FileHandle* handle, nacl_abi_off_t offset, int whence, |
+ nacl_abi_off_t* new_offset) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = handle->stream; |
+ if (stream && stream != kBadFileStream) |
+ return stream->seek(offset, whence, new_offset); |
+ else |
+ return EBADF; |
+} |
+ |
+/*int SocketSubSystem::dup(int fd, int *newfd) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = GetStream(fd); |
+ if (!stream || stream == kBadFileStream) |
+ return EBADF; |
+ |
+ // Mark as used. |
+ *newfd = KernelProxy::KPInstance()->AddFileStream(NULL); |
+ FileStream* new_stream = stream->dup(*newfd); |
+ if (!new_stream) { |
+ KernelProxy::KPInstance()->RemoveFileStream(*newfd); |
+ return EACCES; |
+ } |
+ |
+ // TODO(vissi): check it |
+ KernelProxy::KPInstance()->GetFileHandle(*newfd)->stream = new_stream; |
+ return 0; |
+} |
+ |
+int SocketSubSystem::dup2(int fd, int newfd) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = GetStream(fd); |
+ if (!stream || stream == kBadFileStream) |
+ return EBADF; |
+ |
+ FileStream* new_stream = GetStream(newfd); |
+ if (stream == kBadFileStream) { |
+ return EBADF; |
+ } else if (!new_stream) { |
+ new_stream->close(); |
+ new_stream->release(); |
+ KernelProxy::KPInstance()->RemoveFileStream(newfd); |
+ } |
+ |
+ KernelProxy::KPInstance()->GetFileHandle(newfd)->stream |
+ = stream->dup(newfd); |
+ if (!new_stream) |
+ return EACCES; |
+ |
+ // TODO(vissi): AddFileStream(newfd, new_stream); |
+ return 0; |
+}*/ |
+ |
+int SocketSubSystem::fstat(FileHandle* handle, nacl_abi_stat* out) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = handle->stream; |
+ if (stream && stream != kBadFileStream) |
+ return stream->fstat(out); |
+ else |
+ return EBADF; |
+} |
+ |
+int SocketSubSystem::fcntl(FileHandle* handle, int cmd, va_list ap) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = handle->stream; |
+ if (stream && stream != kBadFileStream) { |
+ return stream->fcntl(cmd, ap); |
+ } else { |
+ errno = EBADF; |
+ return -1; |
+ } |
+} |
+ |
+int SocketSubSystem::ioctl(FileHandle* handle, int request, va_list ap) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream* stream = handle->stream; |
+ if (stream && stream != kBadFileStream) { |
+ return stream->ioctl(request, ap); |
+ } else { |
+ errno = EBADF; |
+ return -1; |
+ } |
+} |
+ |
+int SocketSubSystem::IsReady(int nfds, fd_set* fds, |
+ bool (FileStream::*is_ready)(), bool apply) { |
+ if (!fds) |
+ return 0; |
+ |
+ int nset = 0; |
+ for (int i = 0; i < nfds; i++) { |
+ if (FD_ISSET(i, fds)) { |
+ FileStream* stream = GetStream(i); |
+ if (!stream) |
+ return -1; |
+ if ((stream->*is_ready)()) { |
+ if (!apply) |
+ return 1; |
+ else |
+ nset++; |
+ } else { |
+ if (apply) |
+ FD_CLR(i, fds); |
+ } |
+ } |
+ } |
+ return nset; |
+} |
+ |
+int SocketSubSystem::listen(FileHandle *handle, int backlog) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream *stream = handle->stream; |
+ if (stream && stream != kBadFileStream) { |
+ if (static_cast<TCPServerSocket*>(stream)->listen(backlog)) { |
+ return 0; |
+ } else { |
+ errno = EACCES; |
+ return -1; |
+ } |
+ } else { |
+ errno = EBADF; |
+ return -1; |
+ } |
+} |
+ |
+int SocketSubSystem::accept(FileHandle* handle, struct sockaddr *addr, |
+ socklen_t* addrlen) { |
+ Mutex::Lock lock(mutex_); |
+ FileStream *stream = handle->stream; |
+ if (stream && stream != kBadFileStream) { |
+ PP_Resource resource = static_cast<TCPServerSocket*>(stream)->accept(); |
+ if (resource) { |
+ TCPSocket* socket = new TCPSocket(O_RDWR); |
+ if (socket->accept(resource)) { |
+ return KernelProxy::KPInstance()->AddFileStream(socket); |
+ } else { |
+ socket->release(); |
+ } |
+ } |
+ errno = EINVAL; |
+ return -1; |
+ } else { |
+ errno = EBADF; |
+ return -1; |
+ } |
+} |
+ |