- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / tests / extensions / socket / test_socket.cc
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