Chromium Code Reviews| Index: native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc |
| diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..139f478d28fc5a2eab6fe41c46bfe53eaa7cd51c |
| --- /dev/null |
| +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc |
| @@ -0,0 +1,300 @@ |
| +// Copyright (c) 2013 The Chromium 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 "nacl_io/ossocket.h" |
| +#ifdef PROVIDES_SOCKET_API |
| + |
| +#include <errno.h> |
| +#include <string.h> |
| + |
| +#include "nacl_io/mount.h" |
| +#include "nacl_io/mount_node_socket.h" |
| +#include "nacl_io/pepper_interface.h" |
| + |
| +#include "ppapi/c/pp_resource.h" |
| +#include "ppapi/c/ppb_net_address.h" |
| + |
| +const uint32_t DEFAULT_MAX_BUFFER = 65536 * 2; |
|
binji
2013/08/09 19:28:06
make this static or put in an anonymous namespace.
binji
2013/08/09 19:28:06
Also, kDefaultMaxBuffer
noelallen1
2013/08/09 22:53:22
Done.
|
| + |
| +namespace nacl_io { |
| + |
| +MountNodeSocket::MountNodeSocket(Mount* mount) |
| + : MountNode(mount), |
| + socket_resource_(0), |
| + local_addr_(0), |
| + remote_addr_(0) { |
| + stat_.st_mode |= S_IFSOCK; |
| +} |
| + |
| +void MountNodeSocket::Destroy() { |
| + if (socket_resource_) |
| + mount_->ppapi()->ReleaseResource(socket_resource_); |
| + if (local_addr_) |
| + mount_->ppapi()->ReleaseResource(local_addr_); |
| + if (remote_addr_) |
| + mount_->ppapi()->ReleaseResource(remote_addr_); |
| +} |
| + |
| +// Declared in EventEmitter, default to regular files which always return |
| +// a ready of TRUE for read, write, or error. |
|
binji
2013/08/09 19:28:06
incorrect comment?
noelallen1
2013/08/09 22:53:22
Done.
|
| +uint32_t MountNodeSocket::GetEventStatus() { |
| + return POLLIN | POLLOUT; |
| +} |
| + |
| +// Assume that |addr| and |out_addr| are non-NULL. |
| +Error MountNodeSocket::MMap(void* addr, |
| + size_t length, |
| + int prot, |
| + int flags, |
| + size_t offset, |
| + void** out_addr) { |
| + return EACCES; |
| +} |
| + |
| +// Normal read/write operations on a file |
| +Error MountNodeSocket::Read(size_t offs, |
| + void* buf, |
| + size_t count, |
| + int* out_bytes) { |
| + return Recv(buf, count, 0, out_bytes); |
| +} |
| + |
| +Error MountNodeSocket::Write(size_t offs, |
| + const void* buf, |
| + size_t count, |
| + int* out_bytes) { |
| + if (0 == remote_addr_) |
| + return EDESTADDRREQ; |
| + |
| + return Send(buf, count, 0, out_bytes); |
| +} |
| + |
| +NetAddressInterface* MountNodeSocket::NetAddress() { |
| + return mount_->ppapi()->GetNetAddressInterface(); |
| +} |
| + |
| +Error MountNodeSocket::PPErrorToErrno(int error) { |
|
binji
2013/08/09 19:28:06
can you extend the one in pepper_interface.cc inst
noelallen1
2013/08/09 22:53:22
Didn't know there was one. :)
Done.
|
| + if (error >= 0) |
| + return error; |
| + |
| + switch(error) { |
| + case PP_ERROR_NOACCESS: |
| + return EACCES; |
| + |
| + case PP_ERROR_FAILED: |
| + case PP_ERROR_BADARGUMENT: |
| + return EINVAL; |
| + |
| + case PP_ERROR_CONNECTION_ABORTED: |
| + return ECONNABORTED; |
| + |
| + case PP_ERROR_CONNECTION_REFUSED: |
| + case PP_ERROR_CONNECTION_FAILED: |
| + return ECONNREFUSED; |
| + |
| + case PP_ERROR_CONNECTION_TIMEDOUT: |
| + return ETIMEDOUT; |
| + |
| + case PP_ERROR_ADDRESS_UNREACHABLE: |
| + return ENETUNREACH; |
| + |
| + case PP_ERROR_ADDRESS_IN_USE: |
| + return EADDRINUSE; |
| + } |
| + |
| + return EINVAL; |
| +} |
| + |
| +PP_Resource MountNodeSocket::SockAddrToResource(const struct sockaddr* addr, |
| + socklen_t len) { |
| + if (AF_INET == addr->sa_family) { |
| + PP_NetAddress_IPv4 addr4; |
| + const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr); |
| + |
| + if (len != sizeof(sockaddr_in)) |
| + return 0; |
| + |
| + memset(&addr4, 0, sizeof(addr4)); |
| + |
| + addr4.port = sin->sin_port; |
| + memcpy(addr4.addr, &sin->sin_addr, sizeof(addr4.addr)); |
| + return mount_->ppapi()->GetNetAddressInterface()->CreateFromIPv4Address( |
| + mount_->ppapi()->GetInstance(), &addr4); |
|
binji
2013/08/09 19:28:06
nit: weird indent. Just indent 4 spaces. (same for
noelallen1
2013/08/09 22:53:22
Done.
|
| + } |
| + |
| + if (AF_INET6 == addr->sa_family) { |
| + PP_NetAddress_IPv6 addr6; |
| + const sockaddr_in6* sin = reinterpret_cast<const sockaddr_in6*>(addr); |
| + |
| + if (len != sizeof(sockaddr_in6)) |
| + return 0; |
| + |
| + memset(&addr6, 0, sizeof(addr6)); |
| + |
| + addr6.port = sin->sin6_port; |
| + memcpy(addr6.addr, &sin->sin6_addr, sizeof(addr6.addr)); |
| + return mount_->ppapi()->GetNetAddressInterface()->CreateFromIPv6Address( |
| + mount_->ppapi()->GetInstance(), &addr6); |
| + } |
| + return 0; |
| +} |
| + |
| + |
| +socklen_t MountNodeSocket::ResourceToSockAddr(PP_Resource addr, |
| + socklen_t len, |
| + struct sockaddr* out_addr) { |
| + if (0 == addr) |
| + return 0; |
| + |
| + PP_NetAddress_IPv4 ipv4; |
| + PP_NetAddress_IPv6 ipv6; |
| + |
| + if (PP_TRUE == NetAddress()->DescribeAsIPv4Address(addr, &ipv4)) { |
| + sockaddr_in addr4; |
| + addr4.sin_family = AF_INET; |
| + addr4.sin_port = ipv4.port; |
| + memcpy(&addr4.sin_addr, ipv4.addr, sizeof(ipv4.addr)); |
| + memcpy(out_addr, &addr4, len); |
| + return sizeof(sockaddr_in); |
|
binji
2013/08/09 19:28:06
I was a bit surprised that this returns the socket
noelallen1
2013/08/09 22:53:22
Done.
|
| + } |
| + |
| + if (PP_TRUE == NetAddress()->DescribeAsIPv6Address(addr, &ipv6)) { |
| + sockaddr_in6 addr6; |
| + addr6.sin6_family = AF_INET6; |
| + addr6.sin6_port = ipv6.port; |
| + memcpy(&addr6.sin6_addr, ipv6.addr, sizeof(ipv6.addr)); |
| + memcpy(out_addr, &addr6, len); |
| + return sizeof(sockaddr_in6); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +bool MountNodeSocket::EquivalentAddress(PP_Resource addr1, PP_Resource addr2) { |
| + if (addr1 == addr2) |
| + return true; |
| + |
| + char data1[sizeof(sockaddr_in6)]; |
| + char data2[sizeof(sockaddr_in6)]; |
| + |
| + sockaddr* saddr1 = (sockaddr*) data1; |
|
binji
2013/08/09 19:28:06
reinterpret_cast
noelallen1
2013/08/09 22:53:22
Done.
|
| + sockaddr* saddr2 = (sockaddr*) data2; |
| + |
| + socklen_t len1 = ResourceToSockAddr(addr1, sizeof(data1), saddr1); |
| + socklen_t len2 = ResourceToSockAddr(addr2, sizeof(data2), saddr2); |
| + |
| + if (len1 != len2) |
| + return false; |
| + |
| + return memcmp(saddr1, saddr2, len1) == 0; |
| +} |
| + |
| + |
| +Error MountNodeSocket::Accept(const struct sockaddr* addr, socklen_t len) { |
| + // Firewall forbids |
| + return EPERM; |
|
binji
2013/08/09 19:28:06
Why EPERM? maybe just ENOSYS for now, because it's
noelallen1
2013/08/09 22:53:22
Done.
|
| +} |
| + |
| +Error MountNodeSocket::Connect(const struct sockaddr* addr, socklen_t len) { |
| + if (len < 1) |
| + return EINVAL; |
| + |
| + if (NULL == addr) |
| + return EFAULT; |
| + |
| + return EOPNOTSUPP; |
| +} |
| + |
| +Error MountNodeSocket::Listen(int backlog) { |
| + return EOPNOTSUPP; |
| +} |
| + |
| +Error MountNodeSocket::GetSockOpt(int lvl, |
| + int optname, |
| + void* optval, |
| + socklen_t* len) { |
| + return EINVAL; |
| +} |
| + |
| +Error MountNodeSocket::SetSockOpt(int lvl, |
| + int optname, |
| + const void* optval, |
| + socklen_t len) { |
| + return EINVAL; |
| +} |
| + |
| +Error MountNodeSocket::Bind(const struct sockaddr* addr, socklen_t len) { |
| + return EINVAL; |
| +} |
| + |
| +Error MountNodeSocket::Recv(void* buf, size_t len, int flags, int* out_len) { |
| + return EINVAL; |
| +} |
| + |
| +Error MountNodeSocket::RecvFrom(void* buf, |
| + size_t len, |
| + int flags, |
| + struct sockaddr* src_addr, |
| + socklen_t* addrlen, |
| + int* out_len) { |
| + return EISCONN; |
|
binji
2013/08/09 19:28:06
why EISCONN?
noelallen1
2013/08/09 22:53:22
Done.
|
| +} |
| + |
| +Error MountNodeSocket::Send(const void* buf, |
| + size_t len, |
| + int flags, |
| + int* out_len) { |
| + return ENOTCONN; |
| +} |
| + |
| +Error MountNodeSocket::SendTo(const void* buf, |
| + size_t len, |
| + int flags, |
| + const struct sockaddr* dest_addr, |
| + socklen_t addrlen, |
| + int* out_len) { |
| + return EISCONN; |
|
binji
2013/08/09 19:28:06
why EISCONN?
noelallen1
2013/08/09 22:53:22
Done.
|
| +} |
| + |
| +Error MountNodeSocket::Shutdown(int how) { |
| + return ENOTCONN; |
| +} |
| + |
| + |
| +Error MountNodeSocket::GetPeerName(struct sockaddr* addr, socklen_t* len) { |
| + if (NULL == addr || NULL == len) |
| + return EFAULT; |
| + |
| + if (*len < 1) |
|
binji
2013/08/09 19:28:06
0 is invalid? linux man pages say len can't be neg
noelallen1
2013/08/09 22:53:22
We define socklet_t as unsigned int, but it could
|
| + return EINVAL; |
| + |
| + AUTO_LOCK(node_lock_); |
| + if (remote_addr_ != 0) { |
| + *len = ResourceToSockAddr(remote_addr_, *len, addr); |
| + return 0; |
| + } |
| + |
| + return ENOTCONN; |
| +} |
| + |
| +Error MountNodeSocket::GetSockName(struct sockaddr* addr, socklen_t* len) { |
| + if (NULL == addr || NULL == len) |
| + return EFAULT; |
| + |
| + if (*len < 1) |
| + return EINVAL; |
| + |
| + AUTO_LOCK(node_lock_); |
| + if (local_addr_ != 0) { |
| + *len = ResourceToSockAddr(local_addr_, *len, addr); |
| + return 0; |
| + } |
| + |
| + return ENOTCONN; |
| +} |
| + |
| + |
| +} // namespace nacl_io |
| + |
| +#endif // PROVIDES_SOCKET_API |