Chromium Code Reviews| Index: libraries/nacl-mounts/base/KernelProxy.cc |
| =================================================================== |
| --- libraries/nacl-mounts/base/KernelProxy.cc (revision 583) |
| +++ libraries/nacl-mounts/base/KernelProxy.cc (working copy) |
| @@ -3,13 +3,18 @@ |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| +#include "KernelProxy.h" |
| #include <assert.h> |
| +#include <netinet/in.h> |
| +#include <sys/time.h> |
| #include <list> |
| #include <utility> |
| -#include "../console/ConsoleMount.h" |
| -#include "../dev/DevMount.h" |
| -#include "KernelProxy.h" |
| +#include "console/ConsoleMount.h" |
| +#include "dev/DevMount.h" |
| #include "MountManager.h" |
| +#include "net/SocketSubSystem.h" |
| +#include "net/BaseSocketSubSystem.h" |
| +#include "util/DebugPrint.h" |
| static pthread_once_t kp_once_ = PTHREAD_ONCE_INIT; |
| KernelProxy *KernelProxy::kp_instance_; |
| @@ -42,6 +47,54 @@ |
| assert(fd == 2); |
| } |
| +void KernelProxy::SetSocketSubSystem(BaseSocketSubSystem* bss) { |
| + ss = bss; |
| +} |
| + |
| +void KernelProxy::RemoveFileStream(int fd) { |
| + this->close(fd); |
| +} |
| + |
| +int KernelProxy::AddFileStream(FileStream* stream, int fd) { |
| + SimpleAutoLock lock(&kp_lock_); |
| + |
| + // Setup file handle. |
| + int handle_slot = open_files_.AllocAt(fd); |
| + if (fds_.AllocAt(fd) != fd) return -1; |
| + FileDescriptor* file = fds_.At(fd); |
| + file->handle = handle_slot; |
| + FileHandle* handle = open_files_.At(handle_slot); |
| + |
| + // init should be safe because we have the kernel proxy lock |
| + if (pthread_mutex_init(&handle->lock, NULL)) assert(0); |
| + |
| + handle->mount = (Mount*) NULL; |
| + handle->stream = (FileStream*) NULL; |
| + handle->use_count = 1; |
| + |
| + return fd; |
| +} |
| + |
| +int KernelProxy::AddFileStream(FileStream* stream) { |
| + SimpleAutoLock lock(&kp_lock_); |
| + |
| + // Setup file handle. |
| + int handle_slot = open_files_.Alloc(); |
| + int fd = fds_.Alloc(); |
| + FileDescriptor* file = fds_.At(fd); |
| + file->handle = handle_slot; |
| + FileHandle* handle = open_files_.At(handle_slot); |
| + |
| + // init should be safe because we have the kernel proxy lock |
| + if (pthread_mutex_init(&handle->lock, NULL)) assert(0); |
| + |
| + handle->mount = (Mount*) NULL; |
| + handle->stream = (FileStream*) NULL; |
| + handle->use_count = 1; |
| + |
| + return fd; |
| +} |
| + |
| KernelProxy *KernelProxy::KPInstance() { |
| pthread_once(&kp_once_, Instantiate); |
| return kp_instance_; |
| @@ -177,12 +230,13 @@ |
| int fd = fds_.Alloc(); |
| FileDescriptor* file = fds_.At(fd); |
| file->handle = handle_slot; |
| - FileHandle *handle = open_files_.At(handle_slot); |
| + FileHandle* handle = open_files_.At(handle_slot); |
| // init should be safe because we have the kernel proxy lock |
| if (pthread_mutex_init(&handle->lock, NULL)) assert(0); |
| handle->mount = mount; |
| + handle->stream = NULL; |
| handle->node = st.st_ino; |
| handle->flags = flags; |
| handle->use_count = 1; |
| @@ -196,6 +250,32 @@ |
| return fd; |
| } |
| +ino_t KernelProxy::CreateSocket() { |
|
Evgeniy Stepanov
2012/05/25 12:05:57
move into socket()
vissi
2012/05/25 13:07:09
Done.
|
| + SimpleAutoLock lock(&kp_lock_); |
| + int handle_slot = open_files_.Alloc(); |
| + int fd = fds_.Alloc(); |
| + FileDescriptor* file = fds_.At(fd); |
| + file->handle = handle_slot; |
| + FileHandle* handle = open_files_.At(handle_slot); |
| + handle->mount = NULL; |
| + handle->stream = NULL; |
|
Evgeniy Stepanov
2012/05/25 12:05:57
a comment somewhere that (NULL, NULL) means a gene
vissi
2012/05/25 13:07:09
Done.
|
| + handle->use_count = 1; |
| + return fd; |
| +} |
| + |
| +struct hostent* KernelProxy::gethostbyname(const char* name) { |
| + struct hostent *res = (struct hostent*) malloc(sizeof(struct hostent)); |
| + if (!res) return NULL; |
| + res->h_addr_list = (char**) malloc(sizeof(char*) * 2); |
| + if (!res->h_addr_list) return NULL; |
| + res->h_addr_list[0] = (char*) malloc(sizeof(long int)); |
| + if (!res->h_addr_list[0]) return NULL; |
| + *((long int*)res->h_addr_list[0]) = ss->gethostbyname(name); |
| + res->h_addr_list[1] = NULL; |
| + res->h_length = sizeof(long int); |
| + return res; |
| +} |
| + |
| int KernelProxy::open(const std::string& path, int flags, mode_t mode) { |
| if (path.empty()) { |
| errno = EINVAL; |
| @@ -228,24 +308,28 @@ |
| } |
| int h = file->handle; |
| fds_.Free(fd); |
| - FileHandle *handle = open_files_.At(h); |
| + FileHandle* handle = open_files_.At(h); |
| if (handle == NULL) { |
| errno = EBADF; |
| return -1; |
| } |
| handle->use_count--; |
| ino_t node = handle->node; |
| - Mount *mount = handle->mount; |
| - if (handle->use_count <= 0) { |
| - open_files_.Free(h); |
| - mount->Unref(node); |
| + if (handle->mount) { |
| + Mount* mount = handle->mount; |
| + if (handle->use_count <= 0) { |
| + open_files_.Free(h); |
| + mount->Unref(node); |
| + } |
| + mount->Unref(); |
| + } else { |
| + ss->close(handle->stream); |
| } |
| - mount->Unref(); |
| return 0; |
| } |
| ssize_t KernelProxy::read(int fd, void *buf, size_t count) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
|
Evgeniy Stepanov
2012/05/25 12:05:57
TODO handle sockets in read and write
vissi
2012/05/25 13:07:09
Done.
|
| // check if fd is valid and handle exists |
| if (!(handle = GetFileHandle(fd))) { |
| errno = EBADF; |
| @@ -269,7 +353,7 @@ |
| } |
| ssize_t KernelProxy::write(int fd, const void *buf, size_t count) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
| // check if fd is valid and handle exists |
| if (!(handle = GetFileHandle(fd))) { |
| @@ -295,7 +379,7 @@ |
| } |
| int KernelProxy::fstat(int fd, struct stat *buf) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
| // check if fd is valid and handle exists |
| if (!(handle = GetFileHandle(fd))) { |
| @@ -321,7 +405,7 @@ |
| } |
| int KernelProxy::getdents(int fd, void *buf, unsigned int count) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
| // check if fd is valid and handle exists |
| if (!(handle = GetFileHandle(fd))) { |
| @@ -343,7 +427,7 @@ |
| } |
| int KernelProxy::fsync(int fd) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
| if (!(handle = GetFileHandle(fd))) { |
| errno = EBADF; |
| @@ -354,19 +438,89 @@ |
| } |
| int KernelProxy::isatty(int fd) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
| if (!(handle = GetFileHandle(fd))) { |
| errno = EBADF; |
| return 0; |
| } |
| - SimpleAutoLock(&handle->lock); |
| return handle->mount->Isatty(handle->node); |
| } |
| +int KernelProxy::dup2(int fd, int newfd) { |
| + // TODO lock??? |
| + FileStream* stream = GetFileHandle(fd) > 0 |
| + ? GetFileHandle(fd)->stream : kBadFileStream; |
| + if (!stream || stream == kBadFileStream) |
| + return EBADF; |
| + |
| + FileStream* new_stream = GetFileHandle(newfd) > 0 |
| + ? GetFileHandle(newfd)->stream : kBadFileStream; |
| + if (stream == kBadFileStream) { |
| + return EBADF; |
| + } else if (!new_stream) { |
| + new_stream->close(); |
|
Evgeniy Stepanov
2012/05/25 12:05:57
this will crash
vissi
2012/05/25 13:07:09
Removed
|
| + new_stream->release(); |
| + RemoveFileStream(newfd); |
| + } |
| + |
| + GetFileHandle(newfd)->stream |
| + = stream->dup(newfd); |
|
Evgeniy Stepanov
2012/05/25 12:05:57
no need to dup streams, new handle should hold a r
vissi
2012/05/25 13:07:09
Done.
|
| + if (!new_stream) |
| + return EACCES; |
| + |
| + AddFileStream(new_stream, newfd); |
| + return 0; |
| +} |
| + |
| +int KernelProxy::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 = GetFileHandle(i) > 0 ? |
| + GetFileHandle(i)->stream : kBadFileStream; |
| + if (!stream) |
| + return -1; |
| + if ((stream->*is_ready)()) { |
| + if (!apply) |
| + return 1; |
| + else |
| + nset++; |
| + } else { |
| + if (apply) |
| + FD_CLR(i, fds); |
| + } |
| + } |
| + } |
| + return nset; |
| +} |
| + |
| int KernelProxy::dup(int oldfd) { |
| SimpleAutoLock lock(&kp_lock_); |
| + FileHandle* fh = GetFileHandle(oldfd); |
| + if (!fh) { |
| + errno = EBADF; |
| + return -1; |
| + } |
| + if (fh->mount == NULL) { |
| + FileStream* stream = GetFileHandle(oldfd) > 0 |
| + ? GetFileHandle(oldfd)->stream : kBadFileStream; |
| + if (!stream || stream == kBadFileStream) |
| + return EBADF; |
| + int new_fd = AddFileStream(NULL); |
| + FileStream* new_stream = stream->dup(new_fd); |
|
Evgeniy Stepanov
2012/05/25 12:05:57
dup does not create new stream or handle, just a n
vissi
2012/05/25 13:07:09
Done.
|
| + if (!new_stream) { |
| + RemoveFileStream(new_fd); |
| + return EACCES; |
| + } |
| + GetFileHandle(new_fd)->stream = new_stream; |
| + return new_fd; |
| + } |
| FileDescriptor* oldfile = fds_.At(oldfd); |
| if (oldfile == NULL) { |
| errno = EBADF; |
| @@ -376,7 +530,7 @@ |
| FileDescriptor *newfile = fds_.At(newfd); |
| int h = oldfile->handle; |
| newfile->handle = h; |
| - FileHandle *handle = open_files_.At(h); |
| + FileHandle* handle = open_files_.At(h); |
| // init should be safe because we have the kernel proxy lock |
| if (pthread_mutex_init(&handle->lock, NULL)) assert(0); |
| @@ -391,7 +545,7 @@ |
| } |
| off_t KernelProxy::lseek(int fd, off_t offset, int whence) { |
| - FileHandle *handle; |
| + FileHandle* handle; |
| // check if fd is valid and handle exists |
| if (!(handle = GetFileHandle(fd))) { |
| errno = EBADF; |
| @@ -618,7 +772,7 @@ |
| return 0; |
| } |
| -KernelProxy::FileHandle *KernelProxy::GetFileHandle(int fd) { |
| +FileHandle* KernelProxy::GetFileHandle(int fd) { |
| SimpleAutoLock lock(&kp_lock_); |
| FileDescriptor *file = fds_.At(fd); |
| if (!file) { |
| @@ -676,42 +830,45 @@ |
| #ifdef __GLIBC__ |
| int KernelProxy::socket(int domain, int type, int protocol) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "socket has not been implemented!\n"); |
| - return -1; |
| + return CreateSocket(); |
| } |
| int KernelProxy::accept(int sockfd, struct sockaddr *addr, |
| socklen_t* addrlen) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "accept has not been implemented!\n"); |
| - return -1; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + FileStream* ret = ss->accept(GetFileHandle(sockfd)->stream, addr, addrlen); |
| + if (!ret) |
| + return AddFileStream(ret); |
| + else |
| + return -1; |
| } |
| int KernelProxy::bind(int sockfd, const struct sockaddr *addr, |
| socklen_t addrlen) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "bind has not been implemented!\n"); |
| - return -1; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + struct sockaddr_in* in_addr = (struct sockaddr_in*)addr; |
| + return ss->bind(&(GetFileHandle(sockfd)->stream), in_addr->sin_addr.s_addr, |
| + (unsigned short) ntohs(in_addr->sin_port)); |
| } |
| int KernelProxy::listen(int sockfd, int backlog) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "listen has not been implemented!\n"); |
| - return -1; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + return ss->listen(GetFileHandle(sockfd)->stream, backlog); |
| } |
| int KernelProxy::connect(int sockfd, const struct sockaddr *addr, |
| socklen_t addrlen) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "connect has not been implemented!\n"); |
| - return -1; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + struct sockaddr_in* in_addr = (struct sockaddr_in*)addr; |
| + return ss->connect(&(GetFileHandle(sockfd)->stream), in_addr->sin_addr.s_addr, |
| + (unsigned short) ntohs(in_addr->sin_port)); |
| } |
| int KernelProxy::send(int sockfd, const void *buf, size_t len, int flags) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "send has not been implemented!\n"); |
| - return -1; |
| + size_t nwr; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + ss->write(GetFileHandle(sockfd)->stream, (const char*)buf, len, &nwr); |
| + return nwr; |
| } |
| int KernelProxy::sendmsg(int sockfd, const struct msghdr *msg, int flags) { |
| @@ -728,9 +885,11 @@ |
| } |
| int KernelProxy::recv(int sockfd, void *buf, size_t len, int flags) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "recv has not been implemented!\n"); |
| - return -1; |
| + size_t nread; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + ss->read(GetFileHandle(sockfd)->stream, |
| + reinterpret_cast<char*>(buf), len, &nread); |
| + return nread; |
| } |
| int KernelProxy::recvmsg(int sockfd, struct msghdr *msg, int flags) { |
| @@ -748,9 +907,53 @@ |
| int KernelProxy::select(int nfds, fd_set *readfds, fd_set *writefds, |
| fd_set* exceptfds, const struct timeval *timeout) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "select has not been implemented!\n"); |
| - return -1; |
| + dbgprintf("int select() before mutex\n"); |
| + Mutex::Lock lock(ss->mutex()); |
| + dbgprintf("int select() after mutex\n"); |
| + |
| + timespec ts_abs; |
| + if (timeout) { |
| + timespec ts; |
| + TIMEVAL_TO_TIMESPEC(timeout, &ts); |
| + timeval tv_now; |
| + gettimeofday(&tv_now, NULL); |
| + int64_t current_time_us = |
| + tv_now.tv_sec * kMicrosecondsPerSecond + tv_now.tv_usec; |
| + int64_t wakeup_time_us = |
| + current_time_us + |
| + timeout->tv_sec * kMicrosecondsPerSecond + timeout->tv_usec; |
| + ts_abs.tv_sec = wakeup_time_us / kMicrosecondsPerSecond; |
| + ts_abs.tv_nsec = |
| + (wakeup_time_us - ts_abs.tv_sec * kMicrosecondsPerSecond) * |
| + kNanosecondsPerMicrosecond; |
| + } |
| + |
| + while (!(IsReady(nfds, readfds, &FileStream::is_read_ready, false) || |
| + IsReady(nfds, writefds, &FileStream::is_write_ready, false) || |
| + IsReady(nfds, exceptfds, &FileStream::is_exception, false))) { |
| + if (timeout) { |
| + if (!timeout->tv_sec && !timeout->tv_usec) |
| + break; |
| + |
| + if (ss->cond().timedwait(ss->mutex(), &ts_abs)) { |
| + if (errno == ETIMEDOUT) |
| + break; |
| + else |
| + return -1; |
| + } |
| + } else { |
| + ss->cond().wait(ss->mutex()); |
| + } |
| + } |
| + |
| + int nread = IsReady(nfds, readfds, &FileStream::is_read_ready, true); |
| + int nwrite = IsReady(nfds, writefds, &FileStream::is_write_ready, true); |
| + int nexcpt = IsReady(nfds, exceptfds, &FileStream::is_exception, true); |
| + if (nread < 0 || nwrite < 0 || nexcpt < 0) { |
| + errno = EBADF; |
| + return -1; |
| + } |
| + return nread + nwrite + nexcpt; |
| } |
| int KernelProxy::pselect(int nfds, fd_set *readfds, fd_set *writefds, |
| @@ -789,9 +992,8 @@ |
| } |
| int KernelProxy::shutdown(int sockfd, int how) { |
| - errno = ENOSYS; |
| - fprintf(stderr, "shutdown has not been implemented!\n"); |
| - return -1; |
| + if (GetFileHandle(sockfd) == 0) return EBADF; |
| + return ss->shutdown(GetFileHandle(sockfd)->stream, how); |
| } |
| int KernelProxy::epoll_create(int size) { |