| Index: libraries/nacl-mounts/net/TcpServerSocket.cc
|
| ===================================================================
|
| --- libraries/nacl-mounts/net/TcpServerSocket.cc (revision 0)
|
| +++ libraries/nacl-mounts/net/TcpServerSocket.cc (revision 0)
|
| @@ -0,0 +1,172 @@
|
| +// 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 "net/TcpServerSocket.h"
|
| +
|
| +#include <assert.h>
|
| +#include <string.h>
|
| +
|
| +#include "../net/SocketSubSystem.h"
|
| +#include "ppapi/c/pp_errors.h"
|
| +#include "ppapi/cpp/module.h"
|
| +#include "ppapi/cpp/private/net_address_private.h"
|
| +#include "../util/DebugPrint.h"
|
| +#include "../util/PthreadHelpers.h"
|
| +
|
| +TCPServerSocket::TCPServerSocket(SocketSubSystem* sys, int oflag,
|
| + const sockaddr* saddr, socklen_t addrlen)
|
| + : ref_(1), oflag_(oflag), factory_(this), socket_(NULL),
|
| + resource_(0), sys_(sys) {
|
| + assert(sizeof(sin6_) >= addrlen);
|
| + memcpy(&sin6_, saddr, std::min(sizeof(sin6_), addrlen));
|
| +}
|
| +
|
| +TCPServerSocket::~TCPServerSocket() {
|
| + assert(!socket_);
|
| + assert(!ref_);
|
| +}
|
| +
|
| +void TCPServerSocket::addref() {
|
| + ++ref_;
|
| +}
|
| +
|
| +void TCPServerSocket::release() {
|
| + if (!--ref_)
|
| + delete this;
|
| +}
|
| +
|
| +int TCPServerSocket::read(char* buf, size_t count, size_t* nread) {
|
| + return -1;
|
| +}
|
| +
|
| +int TCPServerSocket::write(const char* buf, size_t count, size_t* nwrote) {
|
| + return -1;
|
| +}
|
| +
|
| +void TCPServerSocket::close() {
|
| + SimpleAutoLock lock(sys_->mutex());
|
| + if (socket_) {
|
| + int32_t result = PP_OK_COMPLETIONPENDING;
|
| + pp::Module::Get()->core()->CallOnMainThread(0,
|
| + factory_.NewCallback(&TCPServerSocket::Close, &result));
|
| + while (result == PP_OK_COMPLETIONPENDING)
|
| + sys_->cond().wait(sys_->mutex());
|
| + }
|
| +}
|
| +
|
| +int TCPServerSocket::fcntl(int cmd, va_list ap) {
|
| + if (cmd == F_GETFL) {
|
| + return oflag_;
|
| + } else if (cmd == F_SETFL) {
|
| + oflag_ = va_arg(ap, long);
|
| + return 0;
|
| + } else {
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +bool TCPServerSocket::is_read_ready() {
|
| + return !is_open() || resource_;
|
| +}
|
| +
|
| +bool TCPServerSocket::is_write_ready() {
|
| + return !is_open();
|
| +}
|
| +
|
| +bool TCPServerSocket::is_exception() {
|
| + return !is_open();
|
| +}
|
| +
|
| +bool TCPServerSocket::listen(int backlog) {
|
| + SimpleAutoLock lock(sys_->mutex());
|
| + int32_t result = PP_OK_COMPLETIONPENDING;
|
| + pp::Module::Get()->core()->CallOnMainThread(0,
|
| + factory_.NewCallback(&TCPServerSocket::Listen, backlog, &result));
|
| + while (result == PP_OK_COMPLETIONPENDING)
|
| + sys_->cond().wait(sys_->mutex());
|
| + return result == PP_OK;
|
| +}
|
| +
|
| +PP_Resource TCPServerSocket::accept() {
|
| + if (!resource_)
|
| + return 0;
|
| +
|
| + PP_Resource ret = resource_;
|
| + resource_ = 0;
|
| + pp::Module::Get()->core()->CallOnMainThread(0,
|
| + factory_.NewCallback(&TCPServerSocket::Accept,
|
| + static_cast<int32_t*>(NULL)));
|
| +
|
| + return ret;
|
| +}
|
| +
|
| +bool TCPServerSocket::CreateNetAddress(const sockaddr* saddr,
|
| + PP_NetAddress_Private* addr) {
|
| + if (saddr->sa_family == AF_INET) {
|
| + const sockaddr_in* sin4 = reinterpret_cast<const sockaddr_in*>(saddr);
|
| + if (!pp::NetAddressPrivate::CreateFromIPv4Address(
|
| + reinterpret_cast<const uint8_t*>(&sin4->sin_addr),
|
| + ntohs(sin4->sin_port), addr)) {
|
| + return false;
|
| + }
|
| + } else {
|
| + const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(saddr);
|
| + if (!pp::NetAddressPrivate::CreateFromIPv6Address(
|
| + reinterpret_cast<const uint8_t*>(&sin6->sin6_addr), 0,
|
| + ntohs(sin6->sin6_port), addr)) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void TCPServerSocket::Listen(int32_t result, int backlog, int32_t* pres) {
|
| + SimpleAutoLock lock(sys_->mutex());
|
| + assert(!socket_);
|
| + socket_ = new pp::TCPServerSocketPrivate(sys_->instance());
|
| +
|
| + PP_NetAddress_Private addr = {};
|
| + if (CreateNetAddress(reinterpret_cast<const sockaddr*>(&sin6_), &addr)) {
|
| + dbgprintf("TCPServerSocket::Listen: %s\n",
|
| + pp::NetAddressPrivate::Describe(addr, true).c_str());
|
| + *pres = socket_->Listen(&addr, backlog,
|
| + factory_.NewCallback(&TCPServerSocket::Accept, pres));
|
| + } else {
|
| + dbgprintf("Listen failed: %s\n",
|
| + pp::NetAddressPrivate::Describe(addr, true).c_str());
|
| + *pres = PP_ERROR_FAILED;
|
| + }
|
| + if (*pres != PP_OK_COMPLETIONPENDING) {
|
| + sys_->cond().broadcast();
|
| + }
|
| +}
|
| +
|
| +void TCPServerSocket::Accept(int32_t result, int32_t* pres) {
|
| + SimpleAutoLock lock(sys_->mutex());
|
| + assert(socket_);
|
| + if (result == PP_OK) {
|
| + result = socket_->Accept(&resource_,
|
| + factory_.NewCallback(&TCPServerSocket::OnAccept));
|
| + if (result == PP_OK_COMPLETIONPENDING)
|
| + result = PP_OK;
|
| + }
|
| + if (pres)
|
| + *pres = result;
|
| + sys_->cond().broadcast();
|
| +}
|
| +
|
| +void TCPServerSocket::OnAccept(int32_t result) {
|
| + SimpleAutoLock lock(sys_->mutex());
|
| + assert(socket_);
|
| + sys_->cond().broadcast();
|
| +}
|
| +
|
| +void TCPServerSocket::Close(int32_t result, int32_t* pres) {
|
| + SimpleAutoLock lock(sys_->mutex());
|
| + delete socket_;
|
| + socket_ = NULL;
|
| + *pres = PP_OK;
|
| + sys_->cond().broadcast();
|
| +}
|
| +
|
|
|