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 |