Index: chrome/test/data/extensions/api_test/socket/ppapi/test_socket.cc |
diff --git a/chrome/test/data/extensions/api_test/socket/ppapi/test_socket.cc b/chrome/test/data/extensions/api_test/socket/ppapi/test_socket.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..03192073a1095a5c76cd3d4397a2ff1609514349 |
--- /dev/null |
+++ b/chrome/test/data/extensions/api_test/socket/ppapi/test_socket.cc |
@@ -0,0 +1,511 @@ |
+// 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 <cstdarg> |
+#include <cstdio> |
+#include <cstdlib> |
+#include <cstring> |
+ |
+#include "ppapi/c/ppb_console.h" |
+#include "ppapi/cpp/extensions/dev/socket_dev.h" |
+#include "ppapi/cpp/instance.h" |
+#include "ppapi/cpp/module.h" |
+#include "ppapi/cpp/var.h" |
+#include "ppapi/cpp/var_array_buffer.h" |
+#include "ppapi/tests/test_utils.h" |
+ |
+using namespace pp; |
+using namespace pp::ext; |
+ |
+namespace { |
+ |
+const char* const kSendContents = "0100000005320000005hello"; |
+const char* const kReceiveContentsPrefix = "0100000005320000005"; |
+const size_t kReceiveContentsSuffixSize = 11; |
+ |
+} // namespace |
+ |
+class MyInstance : public Instance { |
+ public: |
+ explicit MyInstance(PP_Instance instance) |
+ : Instance(instance), |
+ socket_(InstanceHandle(instance)), |
+ console_interface_(NULL), |
+ socket_interface_(NULL), |
+ port_(0) { |
+ } |
+ virtual ~MyInstance() { |
+ } |
+ |
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
+ console_interface_ = static_cast<const PPB_Console*>( |
+ Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE)); |
+ |
+ // TODO(yzshen): Remove this one once the cpp wrapper supports all socket |
+ // functions. |
+ socket_interface_ = static_cast<const PPB_Ext_Socket_Dev*>( |
+ Module::Get()->GetBrowserInterface(PPB_EXT_SOCKET_DEV_INTERFACE)); |
+ if (!console_interface_ || !socket_interface_) |
+ return false; |
+ |
+ PostMessage(Var("ready")); |
+ return true; |
+ } |
+ |
+ virtual void HandleMessage(const pp::Var& message_data) { |
+ std::string output; |
+ do { |
+ if (!message_data.is_string()) { |
+ output = "Invalid control message."; |
+ break; |
+ } |
+ |
+ std::string control_message = message_data.AsString(); |
+ std::vector<std::string> parts; |
+ size_t pos = 0; |
+ size_t next_match = 0; |
+ while (pos < control_message.size()) { |
+ next_match = control_message.find(':', pos); |
+ if (next_match == std::string::npos) |
+ next_match = control_message.size(); |
+ parts.push_back(control_message.substr(pos, next_match - pos)); |
+ pos = next_match + 1; |
+ } |
+ |
+ if (parts.size() != 3) { |
+ output = "Invalid protocol/address/port input."; |
+ break; |
+ } |
+ |
+ test_type_ = parts[0]; |
+ address_ = parts[1]; |
+ port_ = atoi(parts[2].c_str()); |
+ Log(PP_LOGLEVEL_LOG, "Running tests, protocol %s, server %s:%d", |
+ test_type_.c_str(), address_.c_str(), port_); |
+ |
+ if (test_type_ == "tcp_server") { |
+ output = TestServerSocket(); |
+ } else { |
+ output = TestClientSocket(); |
+ } |
+ } while (false); |
+ |
+ NotifyTestDone(output); |
+ } |
+ |
+ private: |
+ std::string TestServerSocket() { |
+ int32_t socket_id = 0; |
+ { |
+ TestCompletionCallbackWithOutput<socket::CreateInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.Create( |
+ socket::SocketType_Dev(socket::SocketType_Dev::TCP), |
+ Optional<socket::CreateOptions_Dev>(), callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Create(): failed."; |
+ socket_id = callback.output().socket_id(); |
+ if (socket_id <= 0) |
+ return "Create(): invalid socket ID."; |
+ } |
+ |
+ { |
+ TestCompletionCallback callback(pp_instance()); |
+ PP_Var output = PP_MakeUndefined(); |
+ int32_t result = socket_interface_->Listen( |
+ pp_instance(), Var(socket_id).pp_var(), Var(address_).pp_var(), |
+ Var(port_).pp_var(), PP_MakeUndefined(), &output, |
+ callback.GetCallback().pp_completion_callback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Listen(): failed."; |
+ Var output_var(PASS_REF, output); |
+ if (output_var.AsInt() != 0) |
+ return "Listen(): failed."; |
+ } |
+ |
+ int32_t client_socket_id = 0; |
+ { |
+ TestCompletionCallbackWithOutput<socket::CreateInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.Create( |
+ socket::SocketType_Dev(socket::SocketType_Dev::TCP), |
+ Optional<socket::CreateOptions_Dev>(), callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Create(): failed."; |
+ client_socket_id = callback.output().socket_id(); |
+ if (client_socket_id <= 0) |
+ return "Create(): invalid socket ID."; |
+ } |
+ |
+ { |
+ TestCompletionCallback callback(pp_instance()); |
+ PP_Var output = PP_MakeUndefined(); |
+ int32_t result = socket_interface_->Connect( |
+ pp_instance(), Var(client_socket_id).pp_var(), Var(address_).pp_var(), |
+ Var(port_).pp_var(), &output, |
+ callback.GetCallback().pp_completion_callback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Connect(): failed."; |
+ Var output_var(PASS_REF, output); |
+ if (output_var.AsInt() != 0) |
+ return "Connect(): failed."; |
+ } |
+ |
+ int32_t accepted_socket_id = 0; |
+ { |
+ TestCompletionCallbackWithOutput<socket::AcceptInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.Accept(socket_id, callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ socket::AcceptInfo_Dev accept_info = callback.output(); |
+ if (accept_info.result_code() != 0 || !accept_info.socket_id().IsSet()) |
+ return "Accept(): failed."; |
+ accepted_socket_id = *accept_info.socket_id(); |
+ } |
+ |
+ size_t bytes_written = 0; |
+ { |
+ TestCompletionCallbackWithOutput<socket::WriteInfo_Dev> |
+ callback(pp_instance()); |
+ VarArrayBuffer array_buffer = ConvertToArrayBuffer(kSendContents); |
+ int32_t result = socket_.Write(client_socket_id, array_buffer, |
+ callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Write(): failed."; |
+ socket::WriteInfo_Dev write_info = callback.output(); |
+ bytes_written = static_cast<size_t>(write_info.bytes_written()); |
+ if (bytes_written <= 0) |
+ return "Write(): did not write any bytes."; |
+ } |
+ |
+ { |
+ TestCompletionCallbackWithOutput<socket::ReadInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.Read(accepted_socket_id, Optional<int32_t>(), |
+ callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Read(): failed."; |
+ |
+ VarArrayBuffer array_buffer(callback.output().data()); |
+ std::string data_string = ConvertFromArrayBuffer(&array_buffer); |
+ if (data_string.compare(0, std::string::npos, kSendContents, |
+ bytes_written) != 0) { |
+ return "Read(): Received data does not match."; |
+ } |
+ } |
+ |
+ socket_.Destroy(client_socket_id); |
+ socket_.Destroy(accepted_socket_id); |
+ socket_.Destroy(socket_id); |
+ return std::string(); |
+ } |
+ |
+ std::string TestClientSocket() { |
+ socket::SocketType_Dev socket_type; |
+ if (!socket_type.Populate(Var(test_type_).pp_var())) |
+ return "Invalid socket type."; |
+ |
+ int32_t socket_id = 0; |
+ { |
+ TestCompletionCallbackWithOutput<socket::CreateInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.Create(socket_type, |
+ Optional<socket::CreateOptions_Dev>(), |
+ callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Create(): failed."; |
+ socket_id = callback.output().socket_id(); |
+ if (socket_id <= 0) |
+ return "Create(): invalid socket ID."; |
+ } |
+ |
+ { |
+ TestCompletionCallbackWithOutput<socket::SocketInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.GetInfo(socket_id, callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "GetInfo(): failed."; |
+ |
+ socket::SocketInfo_Dev socket_info = callback.output(); |
+ if (socket_info.socket_type().value != socket_type.value) |
+ return "GetInfo(): inconsistent socket type."; |
+ if (socket_info.connected()) |
+ return "GetInfo(): socket should not be connected."; |
+ if (socket_info.peer_address().IsSet() || socket_info.peer_port().IsSet()) |
+ return "GetInfo(): unconnected socket should not have peer."; |
+ if (socket_info.local_address().IsSet() || |
+ socket_info.local_port().IsSet()) { |
+ return "GetInfo(): unconnected socket should not have local binding."; |
+ } |
+ } |
+ |
+ { |
+ if (socket_type.value == socket::SocketType_Dev::TCP) { |
+ TestCompletionCallback callback(pp_instance()); |
+ PP_Var output = PP_MakeUndefined(); |
+ int32_t result = socket_interface_->Connect( |
+ pp_instance(), Var(socket_id).pp_var(), Var(address_).pp_var(), |
+ Var(port_).pp_var(), &output, |
+ callback.GetCallback().pp_completion_callback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Connect(): failed."; |
+ Var output_var(PASS_REF, output); |
+ if (output_var.AsInt() != 0) |
+ return "Connect(): failed."; |
+ } else { |
+ TestCompletionCallback callback(pp_instance()); |
+ PP_Var output = PP_MakeUndefined(); |
+ int32_t result = socket_interface_->Bind( |
+ pp_instance(), Var(socket_id).pp_var(), Var("0.0.0.0").pp_var(), |
+ Var(0).pp_var(), &output, |
+ callback.GetCallback().pp_completion_callback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Bind(): failed."; |
+ Var output_var(PASS_REF, output); |
+ if (output_var.AsInt() != 0) |
+ return "Bind(): failed."; |
+ } |
+ } |
+ |
+ { |
+ TestCompletionCallbackWithOutput<socket::SocketInfo_Dev> |
+ callback(pp_instance()); |
+ int32_t result = socket_.GetInfo(socket_id, callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "GetInfo(): failed."; |
+ |
+ socket::SocketInfo_Dev socket_info = callback.output(); |
+ if (socket_info.socket_type().value != socket_type.value) |
+ return "GetInfo(): inconsistent socket type."; |
+ if (!socket_info.local_address().IsSet() || |
+ !socket_info.local_port().IsSet()) { |
+ return "GetInfo(): bound socket should have local address and port."; |
+ } |
+ if (socket_type.value == socket::SocketType_Dev::TCP) { |
+ if (!socket_info.connected()) |
+ return "GetInfo(): TCP socket should be connected."; |
+ if (!socket_info.peer_address().IsSet() || |
+ !socket_info.peer_port().IsSet()) { |
+ return "GetInfo(): connected TCP socket should have peer address and " |
+ "port"; |
+ } |
+ if (*socket_info.peer_address() != "127.0.0.1" || |
+ *socket_info.peer_port() != port_) { |
+ return "GetInfo(): peer address and port should match the listening " |
+ "server."; |
+ } |
+ } else { |
+ if (socket_info.connected()) |
+ return "GetInfo(): UDP socket should not be connected."; |
+ if (socket_info.peer_address().IsSet() || |
+ socket_info.peer_port().IsSet()) { |
+ return "GetInfo(): unconnected UDP socket should not have peer " |
+ "address or port."; |
+ } |
+ } |
+ } |
+ |
+ { |
+ TestCompletionCallback callback(pp_instance()); |
+ PP_Var output = PP_MakeUndefined(); |
+ int32_t result = socket_interface_->SetNoDelay( |
+ pp_instance(), Var(socket_id).pp_var(), Var(true).pp_var(), |
+ &output, callback.GetCallback().pp_completion_callback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "SetNoDelay(): failed."; |
+ Var output_var(PASS_REF, output); |
+ if (socket_type.value == socket::SocketType_Dev::TCP) { |
+ if (!output_var.AsBool()) |
+ return "SetNoDelay(): failed for TCP."; |
+ } else { |
+ if (output_var.AsBool()) |
+ return "SetNoDelay(): did not fail for UDP."; |
+ } |
+ } |
+ |
+ { |
+ TestCompletionCallback callback(pp_instance()); |
+ PP_Var output = PP_MakeUndefined(); |
+ int32_t result = socket_interface_->SetKeepAlive( |
+ pp_instance(), Var(socket_id).pp_var(), Var(true).pp_var(), |
+ Var(1000).pp_var(), &output, |
+ callback.GetCallback().pp_completion_callback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "SetKeepAlive(): failed."; |
+ Var output_var(PASS_REF, output); |
+ if (socket_type.value == socket::SocketType_Dev::TCP) { |
+ if (!output_var.AsBool()) |
+ return "SetKeepAlive(): failed for TCP."; |
+ } else { |
+ if (output_var.AsBool()) |
+ return "SetKeepAlive(): did not fail for UDP."; |
+ } |
+ } |
+ |
+ { |
+ VarArrayBuffer input_array_buffer = ConvertToArrayBuffer(kSendContents); |
+ size_t bytes_written = 0; |
+ int32_t result_code = 0; |
+ Var data; |
+ if (socket_type.value == socket::SocketType_Dev::TCP) { |
+ TestCompletionCallbackWithOutput<socket::ReadInfo_Dev> |
+ read_callback(pp_instance()); |
+ int32_t result = socket_.Read(socket_id, Optional<int32_t>(), |
+ read_callback.GetCallback()); |
+ if (result != PP_OK_COMPLETIONPENDING) |
+ return "Read(): did not wait for data."; |
+ |
+ TestCompletionCallbackWithOutput<socket::WriteInfo_Dev> |
+ write_callback(pp_instance()); |
+ result = socket_.Write(socket_id, input_array_buffer, |
+ write_callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = write_callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Write(): failed."; |
+ bytes_written = static_cast<size_t>( |
+ write_callback.output().bytes_written()); |
+ |
+ result = read_callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "Read(): failed."; |
+ socket::ReadInfo_Dev read_info = read_callback.output(); |
+ result_code = read_info.result_code(), |
+ data = read_info.data(); |
+ } else { |
+ TestCompletionCallbackWithOutput<socket::RecvFromInfo_Dev> |
+ recv_from_callback(pp_instance()); |
+ int32_t result = socket_.RecvFrom(socket_id, Optional<int32_t>(), |
+ recv_from_callback.GetCallback()); |
+ if (result != PP_OK_COMPLETIONPENDING) |
+ return "RecvFrom(): did not wait for data."; |
+ |
+ TestCompletionCallbackWithOutput<socket::WriteInfo_Dev> |
+ send_to_callback(pp_instance()); |
+ result = socket_.SendTo(socket_id, input_array_buffer, address_, port_, |
+ send_to_callback.GetCallback()); |
+ if (result == PP_OK_COMPLETIONPENDING) |
+ result = send_to_callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "SendTo(): failed."; |
+ bytes_written = static_cast<size_t>( |
+ send_to_callback.output().bytes_written()); |
+ |
+ result = recv_from_callback.WaitForResult(); |
+ if (result != PP_OK) |
+ return "RecvFrom(): failed."; |
+ socket::RecvFromInfo_Dev recv_from_info = recv_from_callback.output(); |
+ result_code = recv_from_info.result_code(); |
+ data = recv_from_info.data(); |
+ } |
+ |
+ if (bytes_written != strlen(kSendContents)) |
+ return "SendTo() or Write(): did not send the whole data buffer."; |
+ |
+ VarArrayBuffer output_array_buffer(data); |
+ if (result_code > 0 && |
+ static_cast<uint32_t>(result_code) != |
+ output_array_buffer.ByteLength()) { |
+ return "Read() or RecvFrom(): inconsistent result code and byte " |
+ "length."; |
+ } |
+ |
+ std::string output_string = ConvertFromArrayBuffer( |
+ &output_array_buffer); |
+ size_t prefix_len = strlen(kReceiveContentsPrefix); |
+ if (output_string.size() != prefix_len + kReceiveContentsSuffixSize || |
+ output_string.compare(0, prefix_len, kReceiveContentsPrefix) != 0) { |
+ return std::string("Read() or RecvFrom(): mismatch data: ").append( |
+ output_string); |
+ } |
+ } |
+ |
+ socket_.Destroy(socket_id); |
+ return std::string(); |
+ } |
+ |
+ void Log(PP_LogLevel level, const char* format, ...) { |
+ va_list args; |
+ va_start(args, format); |
+ char buf[512]; |
+ vsnprintf(buf, sizeof(buf) - 1, format, args); |
+ buf[sizeof(buf) - 1] = '\0'; |
+ va_end(args); |
+ |
+ Var value(buf); |
+ console_interface_->Log(pp_instance(), level, value.pp_var()); |
+ } |
+ |
+ void NotifyTestDone(const std::string& message) { |
+ PostMessage(message); |
+ } |
+ |
+ VarArrayBuffer ConvertToArrayBuffer(const std::string data) { |
+ VarArrayBuffer array_buffer(data.size()); |
+ memcpy(array_buffer.Map(), data.c_str(), data.size()); |
+ array_buffer.Unmap(); |
+ return array_buffer; |
+ } |
+ |
+ std::string ConvertFromArrayBuffer(VarArrayBuffer* array_buffer) { |
+ std::string result(static_cast<const char*>(array_buffer->Map()), |
+ array_buffer->ByteLength()); |
+ array_buffer->Unmap(); |
+ return result; |
+ } |
+ |
+ socket::Socket_Dev socket_; |
+ const PPB_Console* console_interface_; |
+ const PPB_Ext_Socket_Dev* socket_interface_; |
+ |
+ std::string test_type_; |
+ std::string address_; |
+ int32_t port_; |
+}; |
+ |
+class MyModule : public Module { |
+ public: |
+ MyModule() : Module() {} |
+ virtual ~MyModule() {} |
+ |
+ virtual Instance* CreateInstance(PP_Instance instance) { |
+ return new MyInstance(instance); |
+ } |
+}; |
+ |
+namespace pp { |
+ |
+Module* CreateModule() { |
+ return new MyModule(); |
+} |
+ |
+} // namespace pp |
+ |