root/ppapi/tests/test_udp_socket_private.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Init
  2. RunTests
  3. GetLocalAddress
  4. SetBroadcastOptions
  5. BindUDPSocket
  6. LookupPortAndBindUDPSocket
  7. BindUDPSocketFailure
  8. ReadSocket
  9. PassMessage
  10. TestConnect
  11. TestConnectFailure
  12. TestBroadcast
  13. TestSetSocketFeatureErrors

// Copyright (c) 2012 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 <cstring>
#include <vector>

#include "ppapi/cpp/module.h"
#include "ppapi/cpp/private/net_address_private.h"
#include "ppapi/cpp/private/tcp_socket_private.h"
#include "ppapi/cpp/var.h"
#include "ppapi/tests/test_udp_socket_private.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"

REGISTER_TEST_CASE(UDPSocketPrivate);

namespace {

const uint16_t kPortScanFrom = 1024;
const uint16_t kPortScanTo = 4096;

}  // namespace

TestUDPSocketPrivate::TestUDPSocketPrivate(
    TestingInstance* instance)
    : TestCase(instance) {
}

bool TestUDPSocketPrivate::Init() {
  bool tcp_socket_private_is_available = pp::TCPSocketPrivate::IsAvailable();
  if (!tcp_socket_private_is_available)
    instance_->AppendError("PPB_TCPSocket_Private interface not available");

  bool udp_socket_private_is_available = pp::UDPSocketPrivate::IsAvailable();
  if (!udp_socket_private_is_available)
    instance_->AppendError("PPB_UDPSocket_Private interface not available");

  bool net_address_private_is_available = pp::NetAddressPrivate::IsAvailable();
  if (!net_address_private_is_available)
    instance_->AppendError("PPB_NetAddress_Private interface not available");

  bool init_host_port = GetLocalHostPort(instance_->pp_instance(),
                                         &host_, &port_);
  if (!init_host_port)
    instance_->AppendError("Can't init host and port");

  return tcp_socket_private_is_available &&
      udp_socket_private_is_available &&
      net_address_private_is_available &&
      init_host_port &&
      CheckTestingInterface() &&
      EnsureRunningOverHTTP();
}

void TestUDPSocketPrivate::RunTests(const std::string& filter) {
  RUN_CALLBACK_TEST(TestUDPSocketPrivate, Connect, filter);
  RUN_CALLBACK_TEST(TestUDPSocketPrivate, ConnectFailure, filter);
  RUN_CALLBACK_TEST(TestUDPSocketPrivate, Broadcast, filter);
  RUN_CALLBACK_TEST(TestUDPSocketPrivate, SetSocketFeatureErrors, filter);
}

std::string TestUDPSocketPrivate::GetLocalAddress(
    PP_NetAddress_Private* address) {
  pp::TCPSocketPrivate socket(instance_);
  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  callback.WaitForResult(
      socket.Connect(host_.c_str(), port_, callback.GetCallback()));
  CHECK_CALLBACK_BEHAVIOR(callback);
  ASSERT_EQ(PP_OK, callback.result());
  ASSERT_TRUE(socket.GetLocalAddress(address));
  socket.Disconnect();
  PASS();
}

std::string TestUDPSocketPrivate::SetBroadcastOptions(
    pp::UDPSocketPrivate* socket) {
  int32_t rv = socket->SetSocketFeature(
      PP_UDPSOCKETFEATURE_PRIVATE_ADDRESS_REUSE, pp::Var(true));
  if (rv != PP_OK)
    return ReportError("PPB_UDPSocket_Private::SetSocketFeature", rv);

  rv = socket->SetSocketFeature(PP_UDPSOCKETFEATURE_PRIVATE_BROADCAST,
                                pp::Var(true));
  if (rv != PP_OK)
    return ReportError("PPB_UDPSocket_Private::SetSocketFeature", rv);

  PASS();
}

std::string TestUDPSocketPrivate::BindUDPSocket(
    pp::UDPSocketPrivate* socket,
    PP_NetAddress_Private* address) {
  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  callback.WaitForResult(socket->Bind(address, callback.GetCallback()));
  CHECK_CALLBACK_BEHAVIOR(callback);
  ASSERT_EQ(PP_OK, callback.result());
  PASS();
}

std::string TestUDPSocketPrivate::LookupPortAndBindUDPSocket(
    pp::UDPSocketPrivate* socket,
    PP_NetAddress_Private *address) {
  PP_NetAddress_Private base_address;
  ASSERT_SUBTEST_SUCCESS(GetLocalAddress(&base_address));

  bool is_free_port_found = false;
  for (uint16_t port = kPortScanFrom; port < kPortScanTo; ++port) {
    if (!pp::NetAddressPrivate::ReplacePort(base_address, port, address))
      return "PPB_NetAddress_Private::ReplacePort: Failed";
    if (BindUDPSocket(socket, address).empty()) {
      is_free_port_found = true;
      break;
    }
  }
  if (!is_free_port_found)
    return "Can't find available port";
  if (!socket->GetBoundAddress(address))
    return "PPB_UDPSocket_Private::GetBoundAddress: Failed";
  PASS();
}

std::string TestUDPSocketPrivate::BindUDPSocketFailure(
    pp::UDPSocketPrivate* socket,
    PP_NetAddress_Private *address) {
  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  callback.WaitForResult(socket->Bind(address, callback.GetCallback()));
  CHECK_CALLBACK_BEHAVIOR(callback);
  ASSERT_NE(PP_OK, callback.result());
  ASSERT_FALSE(socket->GetBoundAddress(address));
  PASS();
}

std::string TestUDPSocketPrivate::ReadSocket(pp::UDPSocketPrivate* socket,
                                             PP_NetAddress_Private* address,
                                             size_t size,
                                             std::string* message) {
  std::vector<char> buffer(size);
  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  callback.WaitForResult(
      socket->RecvFrom(&buffer[0], size, callback.GetCallback()));
  CHECK_CALLBACK_BEHAVIOR(callback);
  ASSERT_FALSE(callback.result() < 0);
  ASSERT_EQ(size, static_cast<size_t>(callback.result()));
  message->assign(buffer.begin(), buffer.end());
  PASS();
}

std::string TestUDPSocketPrivate::PassMessage(pp::UDPSocketPrivate* target,
                                              pp::UDPSocketPrivate* source,
                                              PP_NetAddress_Private* address,
                                              const std::string& message) {
  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  int32_t rv = source->SendTo(message.c_str(), message.size(), address,
                              callback.GetCallback());
  std::string str;
  ASSERT_SUBTEST_SUCCESS(ReadSocket(target, address, message.size(), &str));

  callback.WaitForResult(rv);
  CHECK_CALLBACK_BEHAVIOR(callback);
  ASSERT_FALSE(callback.result() < 0);
  ASSERT_EQ(message.size(), static_cast<size_t>(callback.result()));
  ASSERT_EQ(message, str);
  PASS();
}

std::string TestUDPSocketPrivate::TestConnect() {
  pp::UDPSocketPrivate server_socket(instance_), client_socket(instance_);
  PP_NetAddress_Private server_address, client_address;

  ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&server_socket,
                                                    &server_address));
  ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&client_socket,
                                                    &client_address));
  const std::string message = "Simple message that will be sent via UDP";
  ASSERT_SUBTEST_SUCCESS(PassMessage(&server_socket, &client_socket,
                                     &server_address,
                                     message));
  PP_NetAddress_Private recv_from_address;
  ASSERT_TRUE(server_socket.GetRecvFromAddress(&recv_from_address));
  ASSERT_TRUE(pp::NetAddressPrivate::AreEqual(recv_from_address,
                                              client_address));

  server_socket.Close();
  client_socket.Close();

  if (server_socket.GetBoundAddress(&server_address))
    return "PPB_UDPSocket_Private::GetBoundAddress: expected Failure";
  PASS();
}

std::string TestUDPSocketPrivate::TestConnectFailure() {
  pp::UDPSocketPrivate socket(instance_);
  PP_NetAddress_Private invalid_address = {};

  std::string error_message = BindUDPSocketFailure(&socket, &invalid_address);
  if (!error_message.empty())
    return error_message;

  PASS();
}

std::string TestUDPSocketPrivate::TestBroadcast() {
  const uint8_t broadcast_ip[4] = { 0xff, 0xff, 0xff, 0xff };

  pp::UDPSocketPrivate server1(instance_), server2(instance_);

  ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&server1));
  ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&server2));
  PP_NetAddress_Private server_address;
  ASSERT_TRUE(pp::NetAddressPrivate::GetAnyAddress(false, &server_address));
  ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&server1, &server_address));
  // Fill port field of |server_address|.
  ASSERT_TRUE(server1.GetBoundAddress(&server_address));
  ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&server2, &server_address));

  const uint16_t port = pp::NetAddressPrivate::GetPort(server_address);
  PP_NetAddress_Private broadcast_address;
  ASSERT_TRUE(pp::NetAddressPrivate::CreateFromIPv4Address(
      broadcast_ip, port, &broadcast_address));

  std::string message;
  const std::string first_message = "first message";
  const std::string second_message = "second_message";

  ASSERT_SUBTEST_SUCCESS(PassMessage(&server1, &server2,
                                     &broadcast_address,
                                     first_message));
  // |first_message| also arrived to |server2|.
  ASSERT_SUBTEST_SUCCESS(ReadSocket(&server2, &broadcast_address,
                                    first_message.size(), &message));
  ASSERT_EQ(first_message, message);

  ASSERT_SUBTEST_SUCCESS(PassMessage(&server2, &server1,
                                     &broadcast_address,
                                     second_message));
  // |second_message| also arrived to |server1|.
  ASSERT_SUBTEST_SUCCESS(ReadSocket(&server1, &broadcast_address,
                                    second_message.size(), &message));
  ASSERT_EQ(second_message, message);

  server1.Close();
  server2.Close();
  PASS();
}

std::string TestUDPSocketPrivate::TestSetSocketFeatureErrors() {
  pp::UDPSocketPrivate socket(instance_);
  // Try to pass incorrect feature name.
  int32_t rv = socket.SetSocketFeature(PP_UDPSOCKETFEATURE_PRIVATE_COUNT,
                                       pp::Var(true));
  ASSERT_EQ(PP_ERROR_BADARGUMENT, rv);

  // Try to pass incorrect feature value's type.
  rv = socket.SetSocketFeature(PP_UDPSOCKETFEATURE_PRIVATE_ADDRESS_REUSE,
                               pp::Var(1));
  ASSERT_EQ(PP_ERROR_BADARGUMENT, rv);
  PASS();
}

/* [<][>][^][v][top][bottom][index][help] */