Home | History | Annotate | Download | only in socket
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <cstdarg>
      6 #include <cstdio>
      7 #include <cstdlib>
      8 #include <cstring>
      9 
     10 #include "ppapi/c/ppb_console.h"
     11 #include "ppapi/cpp/extensions/dev/socket_dev.h"
     12 #include "ppapi/cpp/instance.h"
     13 #include "ppapi/cpp/module.h"
     14 #include "ppapi/cpp/var.h"
     15 #include "ppapi/cpp/var_array_buffer.h"
     16 #include "ppapi/tests/test_utils.h"
     17 
     18 using namespace pp;
     19 using namespace pp::ext;
     20 
     21 namespace {
     22 
     23 const char* const kSendContents = "0100000005320000005hello";
     24 const char* const kReceiveContentsPrefix = "0100000005320000005";
     25 const size_t kReceiveContentsSuffixSize = 11;
     26 
     27 const char* const kMulticastAddress = "237.132.100.133";
     28 const int32_t kMulticastPort = 11103;
     29 const char* const kMulticastMessage = "hello world!";
     30 
     31 }  // namespace
     32 
     33 class MyInstance : public Instance {
     34  public:
     35   explicit MyInstance(PP_Instance instance)
     36       : Instance(instance),
     37         socket_(InstanceHandle(instance)),
     38         console_interface_(NULL),
     39         port_(0) {
     40   }
     41   virtual ~MyInstance() {
     42   }
     43 
     44   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
     45     console_interface_ = static_cast<const PPB_Console*>(
     46         Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
     47 
     48     if (!console_interface_)
     49       return false;
     50 
     51     PostMessage(Var("ready"));
     52     return true;
     53   }
     54 
     55   virtual void HandleMessage(const pp::Var& message_data) {
     56     std::string output;
     57     do {
     58       if (!message_data.is_string()) {
     59         output = "Invalid control message.";
     60         break;
     61       }
     62 
     63       std::string control_message = message_data.AsString();
     64       std::vector<std::string> parts;
     65       size_t pos = 0;
     66       size_t next_match = 0;
     67       while (pos < control_message.size()) {
     68         next_match = control_message.find(':', pos);
     69         if (next_match == std::string::npos)
     70           next_match = control_message.size();
     71         parts.push_back(control_message.substr(pos, next_match - pos));
     72         pos = next_match + 1;
     73       }
     74 
     75       if (parts.size() != 3) {
     76         output = "Invalid protocol/address/port input.";
     77         break;
     78       }
     79 
     80       test_type_ = parts[0];
     81       address_ = parts[1];
     82       port_ = atoi(parts[2].c_str());
     83       Log(PP_LOGLEVEL_LOG, "Running tests, protocol %s, server %s:%d",
     84           test_type_.c_str(), address_.c_str(), port_);
     85 
     86       if (test_type_ == "tcp_server") {
     87         output = TestServerSocket();
     88       } else if (test_type_ == "multicast") {
     89         output = TestMulticast();
     90       } else {
     91         output = TestClientSocket();
     92       }
     93     } while (false);
     94 
     95     NotifyTestDone(output);
     96   }
     97 
     98  private:
     99   std::string TestServerSocket() {
    100     int32_t socket_id = 0;
    101     {
    102       TestExtCompletionCallbackWithOutput<socket::CreateInfo_Dev>
    103           callback(pp_instance());
    104       callback.WaitForResult(socket_.Create(
    105           socket::SocketType_Dev(socket::SocketType_Dev::TCP),
    106           Optional<socket::CreateOptions_Dev>(), callback.GetCallback()));
    107       if (callback.result() != PP_OK)
    108         return "Create(): failed.";
    109       socket_id = callback.output().socket_id();
    110       if (socket_id <= 0)
    111         return "Create(): invalid socket ID.";
    112     }
    113 
    114     {
    115       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    116       callback.WaitForResult(socket_.Listen(
    117           socket_id, address_, port_, Optional<int32_t>(),
    118           callback.GetCallback()));
    119       if (callback.result() != PP_OK)
    120         return "Listen(): failed.";
    121       if (callback.output() != 0)
    122         return "Listen(): failed.";
    123     }
    124 
    125     int32_t client_socket_id = 0;
    126     {
    127       TestExtCompletionCallbackWithOutput<socket::CreateInfo_Dev>
    128           callback(pp_instance());
    129       callback.WaitForResult(socket_.Create(
    130           socket::SocketType_Dev(socket::SocketType_Dev::TCP),
    131           Optional<socket::CreateOptions_Dev>(), callback.GetCallback()));
    132       if (callback.result() != PP_OK)
    133         return "Create(): failed.";
    134       client_socket_id = callback.output().socket_id();
    135       if (client_socket_id <= 0)
    136         return "Create(): invalid socket ID.";
    137     }
    138 
    139     {
    140       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    141       callback.WaitForResult(socket_.Connect(
    142           client_socket_id, address_, port_, callback.GetCallback()));
    143       if (callback.result() != PP_OK)
    144         return "Connect(): failed.";
    145       if (callback.output() != 0)
    146         return "Connect(): failed.";
    147     }
    148 
    149     int32_t accepted_socket_id = 0;
    150     {
    151       TestExtCompletionCallbackWithOutput<socket::AcceptInfo_Dev>
    152           callback(pp_instance());
    153       callback.WaitForResult(socket_.Accept(socket_id, callback.GetCallback()));
    154       if (callback.result() != PP_OK)
    155         return "Accept(): failed.";
    156       socket::AcceptInfo_Dev accept_info = callback.output();
    157       if (accept_info.result_code() != 0 || !accept_info.socket_id().IsSet())
    158         return "Accept(): failed.";
    159       accepted_socket_id = *accept_info.socket_id();
    160     }
    161 
    162     size_t bytes_written = 0;
    163     {
    164       TestExtCompletionCallbackWithOutput<socket::WriteInfo_Dev>
    165           callback(pp_instance());
    166       VarArrayBuffer array_buffer = ConvertToArrayBuffer(kSendContents);
    167       callback.WaitForResult(socket_.Write(client_socket_id, array_buffer,
    168                                            callback.GetCallback()));
    169       if (callback.result() != PP_OK)
    170         return "Write(): failed.";
    171       socket::WriteInfo_Dev write_info = callback.output();
    172       bytes_written = static_cast<size_t>(write_info.bytes_written());
    173       if (bytes_written <= 0)
    174         return "Write(): did not write any bytes.";
    175     }
    176 
    177     {
    178       TestExtCompletionCallbackWithOutput<socket::ReadInfo_Dev>
    179           callback(pp_instance());
    180       callback.WaitForResult(socket_.Read(
    181           accepted_socket_id, Optional<int32_t>(), callback.GetCallback()));
    182       if (callback.result() != PP_OK)
    183         return "Read(): failed.";
    184 
    185       std::string data_string = ConvertFromArrayBuffer(
    186           &callback.output().data());
    187       if (data_string.compare(0, std::string::npos, kSendContents,
    188                               bytes_written) != 0) {
    189         return "Read(): Received data does not match.";
    190       }
    191     }
    192 
    193     socket_.Destroy(client_socket_id);
    194     socket_.Destroy(accepted_socket_id);
    195     socket_.Destroy(socket_id);
    196     return std::string();
    197   }
    198 
    199   std::string TestMulticast() {
    200     int32_t socket_id = 0;
    201     {
    202       TestExtCompletionCallbackWithOutput<socket::CreateInfo_Dev>
    203           callback(pp_instance());
    204       callback.WaitForResult(socket_.Create(
    205           socket::SocketType_Dev::UDP, Optional<socket::CreateOptions_Dev>(),
    206           callback.GetCallback()));
    207       if (callback.result() != PP_OK)
    208         return "Create(): failed.";
    209       socket_id = callback.output().socket_id();
    210       if (socket_id <= 0)
    211         return "Create(): invalid socket ID.";
    212     }
    213 
    214     {
    215       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    216       callback.WaitForResult(socket_.SetMulticastTimeToLive(
    217           socket_id, 0, callback.GetCallback()));
    218       if (callback.result() != PP_OK || callback.output() != 0)
    219         return "SetMulticastTimeToLive(): failed.";
    220     }
    221 
    222     {
    223       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    224       callback.WaitForResult(socket_.SetMulticastTimeToLive(
    225           socket_id, -3, callback.GetCallback()));
    226       if (callback.result() == PP_OK)
    227         return "SetMulticastTimeToLive(): succeeded unexpectedly.";
    228       if (callback.output() != -4)
    229         return "SetMulticastTimeToLive(): returned unexpected result.";
    230     }
    231 
    232     {
    233       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    234       callback.WaitForResult(socket_.SetMulticastLoopbackMode(
    235           socket_id, false, callback.GetCallback()));
    236       if (callback.result() != PP_OK || callback.output() != 0)
    237         return "SetMulticastLoopbackMode(): failed.";
    238     }
    239 
    240     {
    241       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    242       callback.WaitForResult(socket_.SetMulticastLoopbackMode(
    243           socket_id, true, callback.GetCallback()));
    244       if (callback.result() != PP_OK || callback.output() != 0)
    245         return "SetMulticastLoopbackMode(): failed.";
    246     }
    247 
    248     socket_.Destroy(socket_id);
    249     socket_id = 0;
    250 
    251     int32_t server_socket_id = 0;
    252     {
    253       TestExtCompletionCallbackWithOutput<socket::CreateInfo_Dev>
    254           callback(pp_instance());
    255       callback.WaitForResult(socket_.Create(
    256           socket::SocketType_Dev::UDP, Optional<socket::CreateOptions_Dev>(),
    257           callback.GetCallback()));
    258       if (callback.result() != PP_OK)
    259         return "Create(): failed.";
    260       server_socket_id = callback.output().socket_id();
    261       if (server_socket_id <= 0)
    262         return "Create(): invalid socket ID.";
    263     }
    264 
    265     {
    266       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    267       callback.WaitForResult(socket_.Bind(
    268           server_socket_id, "0.0.0.0", kMulticastPort, callback.GetCallback()));
    269       if (callback.result() != PP_OK || callback.output() != 0)
    270         return "Bind(): failed";
    271     }
    272 
    273     {
    274       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    275       callback.WaitForResult(socket_.JoinGroup(
    276           server_socket_id, kMulticastAddress, callback.GetCallback()));
    277       if (callback.result() != PP_OK || callback.output() != 0)
    278         return "JoinGroup(): failed.";
    279     }
    280 
    281     {
    282       TestExtCompletionCallbackWithOutput<std::vector<std::string> >
    283           callback(pp_instance());
    284       callback.WaitForResult(socket_.GetJoinedGroups(
    285           server_socket_id, callback.GetCallback()));
    286       if (callback.result() != PP_OK)
    287         return "GetJoinedGroups(): failed.";
    288       std::vector<std::string> groups = callback.output();
    289       if (groups.size() != 1 || groups[0] != kMulticastAddress) {
    290         return "GetJoinedGroups(): the returned groups didn't match those "
    291                "joined.";
    292       }
    293     }
    294 
    295     int32_t client_socket_id = 0;
    296     {
    297       TestExtCompletionCallbackWithOutput<socket::CreateInfo_Dev>
    298           callback(pp_instance());
    299       callback.WaitForResult(socket_.Create(
    300           socket::SocketType_Dev::UDP, Optional<socket::CreateOptions_Dev>(),
    301           callback.GetCallback()));
    302       if (callback.result() != PP_OK)
    303         return "Create(): failed.";
    304       client_socket_id = callback.output().socket_id();
    305       if (client_socket_id <= 0)
    306         return "Create(): invalid socket ID.";
    307     }
    308 
    309     {
    310       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    311       callback.WaitForResult(socket_.SetMulticastTimeToLive(
    312           client_socket_id, 0, callback.GetCallback()));
    313       if (callback.result() != PP_OK || callback.output() != 0)
    314         return "SetMulticastTimeToLive(): failed.";
    315     }
    316 
    317     {
    318       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    319       callback.WaitForResult(socket_.Connect(
    320           client_socket_id, kMulticastAddress, kMulticastPort,
    321           callback.GetCallback()));
    322       if (callback.result() != PP_OK || callback.output() != 0)
    323         return "Connnect(): failed.";
    324     }
    325 
    326     {
    327       VarArrayBuffer input_array_buffer =
    328           ConvertToArrayBuffer(kMulticastMessage);
    329       size_t bytes_written = 0;
    330       int32_t result_code = 0;
    331       VarArrayBuffer data;
    332 
    333       TestExtCompletionCallbackWithOutput<socket::RecvFromInfo_Dev>
    334           recv_from_callback(pp_instance());
    335       int32_t recv_from_result = socket_.RecvFrom(
    336           server_socket_id, 1024, recv_from_callback.GetCallback());
    337       if (recv_from_result != PP_OK_COMPLETIONPENDING)
    338         return "RecvFrom(): did not wait for data.";
    339 
    340       TestExtCompletionCallbackWithOutput<socket::WriteInfo_Dev>
    341           write_callback(pp_instance());
    342       write_callback.WaitForResult(socket_.Write(
    343           client_socket_id, input_array_buffer, write_callback.GetCallback()));
    344       if (write_callback.result() != PP_OK)
    345         return "Write(): failed.";
    346       bytes_written = static_cast<size_t>(
    347           write_callback.output().bytes_written());
    348 
    349       recv_from_callback.WaitForResult(recv_from_result);
    350       if (recv_from_callback.result() != PP_OK)
    351         return "RecvFrom(): failed.";
    352       socket::RecvFromInfo_Dev recv_from_info = recv_from_callback.output();
    353       result_code = recv_from_info.result_code();
    354       data = recv_from_info.data();
    355 
    356       if (bytes_written != strlen(kMulticastMessage))
    357         return "Write(): did not send the whole data buffer.";
    358 
    359       if (result_code > 0 &&
    360           static_cast<uint32_t>(result_code) != data.ByteLength()) {
    361         return "RecvFrom(): inconsistent result code and byte length.";
    362       }
    363 
    364       std::string output_string = ConvertFromArrayBuffer(&data);
    365       if (output_string != kMulticastMessage) {
    366         return std::string("RecvFrom(): mismatched data: ").append(
    367             output_string);
    368       }
    369     }
    370 
    371     {
    372       TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    373       callback.WaitForResult(socket_.LeaveGroup(
    374           server_socket_id, kMulticastAddress, callback.GetCallback()));
    375       if (callback.result() != PP_OK || callback.output() != 0)
    376         return "LeaveGroup(): failed.";
    377     }
    378 
    379     socket_.Destroy(server_socket_id);
    380     socket_.Destroy(client_socket_id);
    381     return std::string();
    382   }
    383 
    384   std::string TestClientSocket() {
    385     socket::SocketType_Dev socket_type;
    386     if (!socket_type.Populate(Var(test_type_).pp_var()))
    387       return "Invalid socket type.";
    388 
    389     int32_t socket_id = 0;
    390     {
    391       TestExtCompletionCallbackWithOutput<socket::CreateInfo_Dev>
    392           callback(pp_instance());
    393       callback.WaitForResult(socket_.Create(
    394           socket_type, Optional<socket::CreateOptions_Dev>(),
    395           callback.GetCallback()));
    396       if (callback.result() != PP_OK)
    397         return "Create(): failed.";
    398       socket_id = callback.output().socket_id();
    399       if (socket_id <= 0)
    400         return "Create(): invalid socket ID.";
    401     }
    402 
    403     {
    404       TestExtCompletionCallbackWithOutput<socket::SocketInfo_Dev>
    405           callback(pp_instance());
    406       callback.WaitForResult(socket_.GetInfo(socket_id,
    407                                              callback.GetCallback()));
    408       if (callback.result() != PP_OK)
    409         return "GetInfo(): failed.";
    410 
    411       socket::SocketInfo_Dev socket_info = callback.output();
    412       if (socket_info.socket_type().value != socket_type.value)
    413         return "GetInfo(): inconsistent socket type.";
    414       if (socket_info.connected())
    415         return "GetInfo(): socket should not be connected.";
    416       if (socket_info.peer_address().IsSet() || socket_info.peer_port().IsSet())
    417         return "GetInfo(): unconnected socket should not have peer.";
    418       if (socket_info.local_address().IsSet() ||
    419           socket_info.local_port().IsSet()) {
    420         return "GetInfo(): unconnected socket should not have local binding.";
    421       }
    422     }
    423 
    424     {
    425       if (socket_type.value == socket::SocketType_Dev::TCP) {
    426         TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    427         callback.WaitForResult(socket_.Connect(
    428             socket_id, address_, port_, callback.GetCallback()));
    429         if (callback.result() != PP_OK)
    430           return "Connect(): failed.";
    431         if (callback.output() != 0)
    432           return "Connect(): failed.";
    433       } else {
    434         TestExtCompletionCallbackWithOutput<int32_t> callback(pp_instance());
    435         callback.WaitForResult(socket_.Bind(
    436             socket_id, "0.0.0.0", 0, callback.GetCallback()));
    437         if (callback.result() != PP_OK)
    438           return "Bind(): failed.";
    439         if (callback.output() != 0)
    440           return "Bind(): failed.";
    441       }
    442     }
    443 
    444     {
    445       TestExtCompletionCallbackWithOutput<socket::SocketInfo_Dev>
    446           callback(pp_instance());
    447       callback.WaitForResult(socket_.GetInfo(socket_id,
    448                                              callback.GetCallback()));
    449       if (callback.result() != PP_OK)
    450         return "GetInfo(): failed.";
    451 
    452       socket::SocketInfo_Dev socket_info = callback.output();
    453       if (socket_info.socket_type().value != socket_type.value)
    454         return "GetInfo(): inconsistent socket type.";
    455       if (!socket_info.local_address().IsSet() ||
    456           !socket_info.local_port().IsSet()) {
    457         return "GetInfo(): bound socket should have local address and port.";
    458       }
    459       if (socket_type.value == socket::SocketType_Dev::TCP) {
    460         if (!socket_info.connected())
    461           return "GetInfo(): TCP socket should be connected.";
    462         if (!socket_info.peer_address().IsSet() ||
    463             !socket_info.peer_port().IsSet()) {
    464           return "GetInfo(): connected TCP socket should have peer address and "
    465                  "port";
    466         }
    467         if (*socket_info.peer_address() != "127.0.0.1" ||
    468             *socket_info.peer_port() != port_) {
    469           return "GetInfo(): peer address and port should match the listening "
    470                  "server.";
    471         }
    472       } else {
    473         if (socket_info.connected())
    474           return "GetInfo(): UDP socket should not be connected.";
    475         if (socket_info.peer_address().IsSet() ||
    476             socket_info.peer_port().IsSet()) {
    477           return "GetInfo(): unconnected UDP socket should not have peer "
    478                  "address or port.";
    479         }
    480       }
    481     }
    482 
    483     {
    484       TestExtCompletionCallbackWithOutput<bool> callback(pp_instance());
    485       callback.WaitForResult(socket_.SetNoDelay(
    486           socket_id, true, callback.GetCallback()));
    487       if (callback.result() != PP_OK)
    488         return "SetNoDelay(): failed.";
    489       if (socket_type.value == socket::SocketType_Dev::TCP) {
    490         if (!callback.output())
    491           return "SetNoDelay(): failed for TCP.";
    492       } else {
    493         if (callback.output())
    494           return "SetNoDelay(): did not fail for UDP.";
    495       }
    496     }
    497 
    498     {
    499       TestExtCompletionCallbackWithOutput<bool> callback(pp_instance());
    500       callback.WaitForResult(socket_.SetKeepAlive(
    501           socket_id, true, 1000, callback.GetCallback()));
    502       if (callback.result() != PP_OK)
    503         return "SetKeepAlive(): failed.";
    504       if (socket_type.value == socket::SocketType_Dev::TCP) {
    505         if (!callback.output())
    506           return "SetKeepAlive(): failed for TCP.";
    507       } else {
    508         if (callback.output())
    509           return "SetKeepAlive(): did not fail for UDP.";
    510       }
    511     }
    512 
    513     {
    514       VarArrayBuffer input_array_buffer = ConvertToArrayBuffer(kSendContents);
    515       size_t bytes_written = 0;
    516       int32_t result_code = 0;
    517       VarArrayBuffer data;
    518       if (socket_type.value == socket::SocketType_Dev::TCP) {
    519         TestExtCompletionCallbackWithOutput<socket::ReadInfo_Dev>
    520             read_callback(pp_instance());
    521         int32_t read_result = socket_.Read(socket_id, Optional<int32_t>(),
    522                                            read_callback.GetCallback());
    523         if (read_result != PP_OK_COMPLETIONPENDING)
    524           return "Read(): did not wait for data.";
    525 
    526         TestExtCompletionCallbackWithOutput<socket::WriteInfo_Dev>
    527             write_callback(pp_instance());
    528         write_callback.WaitForResult(socket_.Write(
    529             socket_id, input_array_buffer, write_callback.GetCallback()));
    530         if (write_callback.result() != PP_OK)
    531           return "Write(): failed.";
    532         bytes_written = static_cast<size_t>(
    533             write_callback.output().bytes_written());
    534 
    535         read_callback.WaitForResult(read_result);
    536         if (read_callback.result() != PP_OK)
    537           return "Read(): failed.";
    538         socket::ReadInfo_Dev read_info = read_callback.output();
    539         result_code = read_info.result_code(),
    540         data = read_info.data();
    541       } else {
    542         TestExtCompletionCallbackWithOutput<socket::RecvFromInfo_Dev>
    543             recv_from_callback(pp_instance());
    544         int32_t recv_from_result = socket_.RecvFrom(
    545             socket_id, Optional<int32_t>(), recv_from_callback.GetCallback());
    546         if (recv_from_result != PP_OK_COMPLETIONPENDING)
    547           return "RecvFrom(): did not wait for data.";
    548 
    549         TestExtCompletionCallbackWithOutput<socket::WriteInfo_Dev>
    550             send_to_callback(pp_instance());
    551         send_to_callback.WaitForResult(socket_.SendTo(
    552             socket_id, input_array_buffer, address_, port_,
    553             send_to_callback.GetCallback()));
    554         if (send_to_callback.result() != PP_OK)
    555           return "SendTo(): failed.";
    556         bytes_written = static_cast<size_t>(
    557             send_to_callback.output().bytes_written());
    558 
    559         recv_from_callback.WaitForResult(recv_from_result);
    560         if (recv_from_callback.result() != PP_OK)
    561           return "RecvFrom(): failed.";
    562         socket::RecvFromInfo_Dev recv_from_info = recv_from_callback.output();
    563         result_code = recv_from_info.result_code();
    564         data = recv_from_info.data();
    565       }
    566 
    567       if (bytes_written != strlen(kSendContents))
    568         return "SendTo() or Write(): did not send the whole data buffer.";
    569 
    570       if (result_code > 0 &&
    571           static_cast<uint32_t>(result_code) != data.ByteLength()) {
    572         return "Read() or RecvFrom(): inconsistent result code and byte "
    573                "length.";
    574       }
    575 
    576       std::string output_string = ConvertFromArrayBuffer(&data);
    577       size_t prefix_len = strlen(kReceiveContentsPrefix);
    578       if (output_string.size() != prefix_len + kReceiveContentsSuffixSize ||
    579           output_string.compare(0, prefix_len, kReceiveContentsPrefix) != 0) {
    580         return std::string("Read() or RecvFrom(): mismatched data: ").append(
    581             output_string);
    582       }
    583     }
    584 
    585     {
    586       TestExtCompletionCallbackWithOutput<
    587           std::vector<socket::NetworkInterface_Dev> > callback(pp_instance());
    588       callback.WaitForResult(socket_.GetNetworkList(callback.GetCallback()));
    589       if (callback.result() != PP_OK)
    590         return "GetNetworkList(): failed.";
    591       if (callback.output().empty())
    592         return "GetNetworkList(): returned an empty list.";
    593     }
    594 
    595     socket_.Destroy(socket_id);
    596     return std::string();
    597   }
    598 
    599   void Log(PP_LogLevel level, const char* format, ...) {
    600     va_list args;
    601     va_start(args, format);
    602     char buf[512];
    603     vsnprintf(buf, sizeof(buf) - 1, format, args);
    604     buf[sizeof(buf) - 1] = '\0';
    605     va_end(args);
    606 
    607     Var value(buf);
    608     console_interface_->Log(pp_instance(), level, value.pp_var());
    609   }
    610 
    611   void NotifyTestDone(const std::string& message) {
    612     PostMessage(message);
    613   }
    614 
    615   VarArrayBuffer ConvertToArrayBuffer(const std::string data) {
    616     VarArrayBuffer array_buffer(data.size());
    617     memcpy(array_buffer.Map(), data.c_str(), data.size());
    618     array_buffer.Unmap();
    619     return array_buffer;
    620   }
    621 
    622   std::string ConvertFromArrayBuffer(VarArrayBuffer* array_buffer) {
    623     std::string result(static_cast<const char*>(array_buffer->Map()),
    624                        array_buffer->ByteLength());
    625     array_buffer->Unmap();
    626     return result;
    627   }
    628 
    629   socket::Socket_Dev socket_;
    630   const PPB_Console* console_interface_;
    631 
    632   std::string test_type_;
    633   std::string address_;
    634   int32_t port_;
    635 };
    636 
    637 class MyModule : public Module {
    638  public:
    639   MyModule() : Module() {}
    640   virtual ~MyModule() {}
    641 
    642   virtual Instance* CreateInstance(PP_Instance instance) {
    643     return new MyInstance(instance);
    644   }
    645 };
    646 
    647 namespace pp {
    648 
    649 Module* CreateModule() {
    650   return new MyModule();
    651 }
    652 
    653 }  // namespace pp
    654 
    655