chromium/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_host_resolver_interface.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "fake_ppapi/fake_host_resolver_interface.h"

#include <netinet/in.h>

#include "fake_ppapi/fake_pepper_interface.h"
#include "fake_ppapi/fake_resource_manager.h"
#include "fake_ppapi/fake_var_manager.h"
#include "fake_ppapi/fake_util.h"
#include "gtest/gtest.h"

namespace {

class FakeHostResolverResource : public FakeResource {
 public:
  FakeHostResolverResource() : resolved(false) {}
  static const char* classname() { return "FakeHostResolverResource"; }

  bool resolved;
  PP_HostResolver_Hint hints;
};
}

FakeHostResolverInterface::FakeHostResolverInterface(FakePepperInterface* ppapi)
    : ppapi_(ppapi) {}

PP_Resource FakeHostResolverInterface::Create(PP_Instance instance) {
  if (instance != ppapi_->GetInstance())
    return PP_ERROR_BADRESOURCE;

  FakeHostResolverResource* resolver_resource = new FakeHostResolverResource();

  return CREATE_RESOURCE(ppapi_->resource_manager(), FakeHostResolverResource,
                         resolver_resource);
}

int32_t FakeHostResolverInterface::Resolve(PP_Resource resource,
                                           const char* hostname,
                                           uint16_t,
                                           const PP_HostResolver_Hint* hints,
                                           PP_CompletionCallback callback) {
  FakeHostResolverResource* resolver =
      ppapi_->resource_manager()->Get<FakeHostResolverResource>(resource);
  resolver->resolved = false;
  resolver->hints = *hints;
  if (!fake_hostname.empty() && fake_hostname == hostname) {
    resolver->resolved = true;
    return RunCompletionCallback(&callback, PP_OK);
  }
  return RunCompletionCallback(&callback, PP_ERROR_NAME_NOT_RESOLVED);
}

PP_Var FakeHostResolverInterface::GetCanonicalName(PP_Resource resource) {
  FakeHostResolverResource* res =
      ppapi_->resource_manager()->Get<FakeHostResolverResource>(resource);
  if (!res->resolved)
    return PP_Var();
  return ppapi_->GetVarInterface()->VarFromUtf8(fake_hostname.data(),
                                                fake_hostname.length());
}

uint32_t FakeHostResolverInterface::GetNetAddressCount(PP_Resource resolver) {
  FakeHostResolverResource* res =
      ppapi_->resource_manager()->Get<FakeHostResolverResource>(resolver);
  if (!res->resolved)
    return 0;

  uint32_t rtn = 0;
  if (res->hints.family == PP_NETADDRESS_FAMILY_IPV6 ||
      res->hints.family == PP_NETADDRESS_FAMILY_UNSPECIFIED)
    rtn += fake_addresses_v6.size();

  if (res->hints.family == PP_NETADDRESS_FAMILY_IPV4 ||
      res->hints.family == PP_NETADDRESS_FAMILY_UNSPECIFIED)
    rtn += fake_addresses_v4.size();

  return rtn;
}

PP_Resource FakeHostResolverInterface::GetNetAddress(PP_Resource resource,
                                                     uint32_t index) {
  FakeHostResolverResource* res =
      ppapi_->resource_manager()->Get<FakeHostResolverResource>(resource);
  if (!res->resolved)
    return 0;

  bool include_v4 = false;
  int max_index = 0;
  switch (res->hints.family) {
    case PP_NETADDRESS_FAMILY_IPV4:
      max_index = fake_addresses_v4.size();
      include_v4 = true;
      break;
    case PP_NETADDRESS_FAMILY_IPV6:
      max_index = fake_addresses_v6.size();
      break;
    case PP_NETADDRESS_FAMILY_UNSPECIFIED:
      include_v4 = true;
      max_index = fake_addresses_v4.size() + fake_addresses_v6.size();
      break;
    default:
      return 0;
  }

  if (index >= max_index)
    return 0;

  nacl_io::NetAddressInterface* iface = ppapi_->GetNetAddressInterface();

  // Create a new NetAddress resource and return it.
  if (include_v4 && index < fake_addresses_v4.size()) {
    PP_NetAddress_IPv4 addr;
    sockaddr_in& addr4 = fake_addresses_v4[index];
    memcpy(addr.addr, &addr4.sin_addr, sizeof(addr4.sin_addr));
    return iface->CreateFromIPv4Address(ppapi_->GetInstance(), &addr);
  } else {
    if (include_v4)
      index -= fake_addresses_v4.size();
    PP_NetAddress_IPv6 addr;
    sockaddr_in6& addr6 = fake_addresses_v6[index];
    memcpy(addr.addr, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
    return iface->CreateFromIPv6Address(ppapi_->GetInstance(), &addr);
  }
}