Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1468)

Unified Diff: libraries/nacl-mounts/net/SocketSubSystem.cc

Issue 10392070: Socket subsystem implementation (Closed) Base URL: http://naclports.googlecode.com/svn/trunk/src/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,480 @@
+// 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>
+
+#ifdef __GLIBC__
+#include "../net/SocketSubSystem.h"
+#include "../net/TcpServerSocket.h"
+#include "../net/TcpSocket.h"
+#include "ppapi/cpp/file_ref.h"
+#include "../ppapi/cpp/private/net_address_private.h"
+#include "../util/DebugPrint.h"
+#include "../util/PthreadHelpers.h"
+
+static const unsigned long kFirstAddr = 0x00000000;
+
+SocketSubSystem::SocketSubSystem(pp::Instance* instance)
+ : pp_instance_(instance)
+ , factory_(this)
+ , first_unused_addr_(kFirstAddr)
+ , host_resolver_(NULL) {
+ AddHostAddress("localhost", 0x7F000001);
+}
+
+uint32_t SocketSubSystem::AddHostAddress(const char* name, uint32_t addr) {
+ return addr;
+}
+
+addrinfo* SocketSubSystem::CreateAddrInfo(const PP_NetAddress_Private& netaddr,
+ const addrinfo* hints,
+ const char* name) {
+ addrinfo* ai = new addrinfo();
+ sockaddr_in6* addr = new sockaddr_in6();
+
+ ai->ai_addr = reinterpret_cast<sockaddr*>(addr);
+ ai->ai_addrlen = sizeof(*addr);
+
+ PP_NetAddressFamily_Private family =
+ pp::NetAddressPrivate::GetFamily(netaddr);
+ if (family == PP_NETADDRESSFAMILY_IPV4)
+ ai->ai_addr->sa_family = ai->ai_family = AF_INET;
+ else if (family == PP_NETADDRESSFAMILY_IPV6)
+ ai->ai_addr->sa_family = ai->ai_family = AF_INET6;
+
+ ai->ai_canonname = strdup(name);
+ addr->sin6_port = pp::NetAddressPrivate::GetPort(netaddr);
+ if (family == PP_NETADDRESSFAMILY_IPV6) {
+ pp::NetAddressPrivate::GetAddress(
+ netaddr, &addr->sin6_addr, sizeof(in6_addr));
+ } else {
+ pp::NetAddressPrivate::GetAddress(
+ netaddr, &((sockaddr_in*)addr)->sin_addr, sizeof(in_addr));
+ }
+
+ if(hints && hints->ai_socktype)
+ ai->ai_socktype = hints->ai_socktype;
+ else
+ ai->ai_socktype = SOCK_STREAM;
+
+ if (hints && hints->ai_protocol)
+ ai->ai_protocol = hints->ai_protocol;
+
+ return ai;
+}
+
+addrinfo* SocketSubSystem::GetFakeAddress(const char* hostname, uint16_t port,
+ const addrinfo* hints) {
+ uint32_t addr;
+ HostMap::iterator it = hosts_.find(hostname);
+ if (it != hosts_.end())
+ addr = it->second;
+ else
+ addr = AddHostAddress(hostname, first_unused_addr_++);
+
+ addrinfo* ai = new addrinfo();
+ sockaddr_in* addr_in = new sockaddr_in();
+ ai->ai_addr = reinterpret_cast<sockaddr*>(addr_in);
+ ai->ai_addrlen = sizeof(sockaddr_in);
+ ai->ai_family = addr_in->sin_family = AF_INET;
+ addr_in->sin_port = port;
+ addr_in->sin_addr.s_addr = addr;
+
+ if(hints && hints->ai_socktype)
+ ai->ai_socktype = hints->ai_socktype;
+ else
+ ai->ai_socktype = SOCK_STREAM;
+
+ if (hints && hints->ai_protocol)
+ ai->ai_protocol = hints->ai_protocol;
+
+ return ai;
+}
+
+int SocketSubSystem::getaddrinfo(const char* hostname, const char* servname,
+ const addrinfo* hints, addrinfo** res) {
+ SimpleAutoLock lock(mutex());
+ GetAddrInfoParams params;
+ params.hostname = hostname;
+ params.servname = servname;
+ params.hints = hints;
+ params.res = res;
+ int32_t result = PP_OK_COMPLETIONPENDING;
+ pp::Module::Get()->core()->CallOnMainThread(0, factory_.NewCallback(
+ &SocketSubSystem::Resolve, &params, &result));
+ while(result == PP_OK_COMPLETIONPENDING)
+ cond().wait(mutex());
+ return result == PP_OK ? 0 : EAI_FAIL;
+}
+
+void SocketSubSystem::Resolve(int32_t result, GetAddrInfoParams* params,
+ int32_t* pres) {
+ SimpleAutoLock lock(mutex());
+ const char* hostname = params->hostname;
+ const char* servname = params->servname;
+ const addrinfo* hints = params->hints;
+ addrinfo** res = params->res;
+
+ if (hints && hints->ai_family != AF_UNSPEC &&
+ hints->ai_family != AF_INET &&
+ hints->ai_family != AF_INET6) {
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+
+ long port = 0;
+ if (servname != NULL) {
+ char* cp;
+ port = strtol(servname, &cp, 10);
+ if (port > 0 && port <= 65535 && *cp == '\0') {
+ port = htons(port);
+ } else {
+ dbgprintf("Bad port number %s\n", servname);
+ port = 0;
+ }
+ }
+
+ bool is_ipv6 = hints ? hints->ai_family == AF_INET6 : false;
+ in6_addr in = {};
+ bool is_numeric = hostname &&
+ inet_pton(is_ipv6 ? AF_INET6 : AF_INET, hostname, &in);
+
+ if (is_numeric) {
+ PP_NetAddress_Private addr = {};
+ if (is_ipv6) {
+ // TODO: handle scope_id
+ if (!pp::NetAddressPrivate::CreateFromIPv6Address(
+ in.s6_addr, 0, port, &addr)) {
+ dbgprintf("NetAddressPrivate::CreateFromIPv6Address failed!\n");
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+ } else {
+ if (!pp::NetAddressPrivate::CreateFromIPv4Address(
+ in.s6_addr, port, &addr)) {
+ dbgprintf("NetAddressPrivate::CreateFromIPv4Address failed!\n");
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+ }
+ *res = CreateAddrInfo(addr, hints, "");
+ *pres = PP_OK;
+ cond().broadcast();
+ return;
+ }
+
+ if (hints && hints->ai_flags & AI_PASSIVE) {
+ // Numeric case we considered above so the only remaining case is any.
+ PP_NetAddress_Private addr = {};
+ if (!pp::NetAddressPrivate::GetAnyAddress(is_ipv6, &addr)) {
+ dbgprintf("NetAddressPrivate::GetAnyAddress failed!\n");
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+ *res = CreateAddrInfo(addr, hints, "");
+ *pres = PP_OK;
+ cond().broadcast();
+ return;
+ }
+
+ if (!hostname) {
+ PP_NetAddress_Private localhost = {};
+ if (is_ipv6) {
+ uint8_t localhost_ip[16] = {};
+ localhost_ip[15] = 1;
+ // TODO: handle scope_id
+ if (!pp::NetAddressPrivate::CreateFromIPv6Address(
+ localhost_ip, 0, port, &localhost)) {
+ dbgprintf("NetAddressPrivate::CreateFromIPv6Address failed!\n");
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+ } else {
+ uint8_t localhost_ip[4] = { 127, 0, 0, 1 };
+ if (!pp::NetAddressPrivate::CreateFromIPv4Address(
+ localhost_ip, port, &localhost)) {
+ dbgprintf("NetAddressPrivate::CreateFromIPv4Address failed!\n");
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+ }
+ *res = CreateAddrInfo(localhost, hints, "");
+ *pres = PP_OK;
+ cond().broadcast();
+ return;
+ }
+
+ if (hints && hints->ai_flags & AI_NUMERICHOST) {
+ *pres = PP_ERROR_FAILED;
+ cond().broadcast();
+ return;
+ }
+
+ // In case of JS socket don't use local host resolver.
+ if (pp::HostResolverPrivate::IsAvailable()) {
+ PP_HostResolver_Private_Hint hint = { PP_NETADDRESSFAMILY_UNSPECIFIED, 0 };
+ if (hints) {
+ if (hints->ai_family == AF_INET)
+ hint.family = PP_NETADDRESSFAMILY_IPV4;
+ else if (hints->ai_family == AF_INET6)
+ hint.family = PP_NETADDRESSFAMILY_IPV6;
+ if (hints->ai_flags & AI_CANONNAME)
+ hint.flags = PP_HOST_RESOLVER_FLAGS_CANONNAME;
+ }
+
+ assert(host_resolver_ == NULL);
+ host_resolver_ = new pp::HostResolverPrivate(instance());
+ *pres = host_resolver_->Resolve(hostname, port, hint,
+ factory_.NewCallback(&SocketSubSystem::OnResolve, params, pres));
+ if (*pres != PP_OK_COMPLETIONPENDING) {
+ delete host_resolver_;
+ host_resolver_ = NULL;
+ cond().broadcast();
+ }
+ } else {
+ *res = GetFakeAddress(hostname, port, hints);
+ *pres = PP_OK;
+ cond().broadcast();
+ return;
+ }
+}
+
+void SocketSubSystem::OnResolve(int32_t result, GetAddrInfoParams* params,
+ int32_t* pres) {
+ SimpleAutoLock lock(mutex());
+ assert(host_resolver_);
+ const addrinfo* hints = params->hints;
+ addrinfo** res = params->res;
+ std::string host_name = host_resolver_->GetCanonicalName().AsString();
+ if (result == PP_OK) {
+ size_t size = host_resolver_->GetSize();
+ for (size_t i = 0; i < size; i++) {
+ PP_NetAddress_Private address = {};
+ if (host_resolver_->GetNetAddress(i, &address)) {
+ *res = CreateAddrInfo(address, hints, host_name.c_str());
+ res = &(*res)->ai_next;
+ }
+ }
+ } else {
+ char* cp;
+ uint16_t port = htons(strtol(params->servname, &cp, 10));
+ *res = GetFakeAddress(params->hostname, port, hints);
+ result = PP_OK;
+ }
+ delete host_resolver_;
+ host_resolver_ = NULL;
+ *pres = result;
+ cond().broadcast();
+}
+
+void SocketSubSystem::freeaddrinfo(addrinfo* ai) {
+ while (ai != NULL) {
+ addrinfo* next = ai->ai_next;
+ free(ai->ai_canonname);
+ delete ai->ai_addr;
+ delete ai;
+ ai = next;
+ }
+}
+
+int SocketSubSystem::getnameinfo(const sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags) {
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ return EAI_FAMILY;
+
+ if (serv)
+ snprintf(serv, servlen, "%d", ntohs(((sockaddr_in*)sa)->sin_port));
+
+ if (host) {
+ if (sa->sa_family == AF_INET6)
+ inet_ntop(AF_INET6, &((sockaddr_in6*)sa)->sin6_addr, host, hostlen);
+ else
+ inet_ntop(AF_INET, &((sockaddr_in*)sa)->sin_addr, host, hostlen);
+ }
+
+ return 0;
+}
+
+bool SocketSubSystem::GetHostPort(const sockaddr* serv_addr, socklen_t addrlen,
+ std::string* hostname, uint16_t* port) {
+ if (serv_addr->sa_family == AF_INET) {
+ const sockaddr_in* sin4 = reinterpret_cast<const sockaddr_in*>(serv_addr);
+ *port = ntohs(sin4->sin_port);
+ AddressMap::iterator it = addrs_.find(sin4->sin_addr.s_addr);
+ if (it != addrs_.end()) {
+ *hostname = it->second;
+ } else {
+ char buf[NI_MAXHOST];
+ inet_ntop(AF_INET, &sin4->sin_addr, buf, sizeof(buf));
+ *hostname = buf;
+ }
+ } else {
+ const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(serv_addr);
+ *port = ntohs(sin6->sin6_port);
+ char buf[NI_MAXHOST];
+ inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf));
+ *hostname = buf;
+ }
+ return true;
+}
+
+int SocketSubSystem::connect(Socket** stream, const sockaddr* serv_addr,
+ socklen_t addrlen) {
+ uint16_t port;
+ std::string hostname;
+ if (!GetHostPort(serv_addr, addrlen, &hostname, &port)) {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ dbgprintf("SocketSubSystem::connect: [%s] port %d\n", hostname.c_str(), port);
+
+ TCPSocket* socket = new TCPSocket(this, O_RDWR);
+ if (!socket->connect(hostname.c_str(), port)) {
+ errno = ECONNREFUSED;
+ socket->release();
+ return -1;
+ }
+ *stream = socket;
+
+ return 0;
+}
+
+int SocketSubSystem::bind(Socket** stream, const sockaddr* addr,
+ socklen_t addrlen) {
+ *stream = (new TCPServerSocket(this, 0, addr, addrlen));
+ return 0;
+}
+
+unsigned long SocketSubSystem::gethostbyname(const char* name) {
Evgeniy Stepanov 2012/06/04 10:27:20 Do we still need this fake implementation? This sh
+ SimpleAutoLock lock(host_mutex_);
+ HostMap::iterator it = hosts_.find(name);
+ if (it != hosts_.end())
+ return it->second;
+
+ int addr = AddHostAddress(name, first_unused_addr_++);
+ hosts_[name] = addr;
+ addrs_[addr] = name;
+ return addr;
+}
+
+SocketSubSystem::~SocketSubSystem() {
+}
+
+int SocketSubSystem::shutdown(Socket* stream, int how) {
+ if (stream) {
+ // 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(Socket* stream) {
+ if (stream) {
+ stream->close();
+ stream->release();
+ }
+ return 0;
+}
+
+int SocketSubSystem::read(Socket* stream, char* buf, size_t count,
+ size_t* nread) {
+ if (stream)
+ return stream->read(buf, count, nread);
+ else
+ return EBADF;
+}
+
+int SocketSubSystem::write(Socket* stream, const char* buf, size_t count,
+ size_t* nwrote) {
+ if (stream)
+ return stream->write(buf, count, nwrote);
+ else
+ return EBADF;
+}
+
+int SocketSubSystem::seek(Socket* stream, nacl_abi_off_t offset, int whence,
+ nacl_abi_off_t* new_offset) {
+ if (stream)
+ return stream->seek(offset, whence, new_offset);
+ else
+ return EBADF;
+}
+
+int SocketSubSystem::fstat(Socket* stream, nacl_abi_stat* out) {
+ if (stream)
+ return stream->fstat(out);
+ else
+ return EBADF;
+}
+
+int SocketSubSystem::fcntl(Socket* stream, int cmd, va_list ap) {
+ if (stream) {
+ return stream->fcntl(cmd, ap);
+ } else {
+ errno = EBADF;
+ return -1;
+ }
+}
+
+int SocketSubSystem::ioctl(Socket* stream, int request, va_list ap) {
+ if (stream) {
+ return stream->ioctl(request, ap);
+ } else {
+ errno = EBADF;
+ return -1;
+ }
+}
+
+int SocketSubSystem::listen(Socket* stream, int backlog) {
+ if (stream) {
+ if (static_cast<TCPServerSocket*>(stream)->listen(backlog)) {
+ return 0;
+ } else {
+ errno = EACCES;
+ return -1;
+ }
+ } else {
+ errno = EBADF;
+ return -1;
+ }
+}
+
+Socket* SocketSubSystem::accept(Socket* stream, struct sockaddr *addr,
+ socklen_t* addrlen) {
+ if (stream) {
+ PP_Resource resource = static_cast<TCPServerSocket*>(stream)->accept();
+ if (resource) {
+ TCPSocket* socket = new TCPSocket(this, O_RDWR);
+ if (socket->acceptFrom(resource)) {
+ return socket;
+ } else {
+ socket->release();
+ }
+ }
+ errno = EINVAL;
+ return 0;
+ } else {
+ errno = EBADF;
+ return 0;
+ }
+}
+
+#endif // __GLIBC__
+

Powered by Google App Engine
This is Rietveld 408576698