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.
9 #include "echo_server.h"
11 #include "ppapi/cpp/host_resolver.h"
12 #include "ppapi/cpp/instance.h"
13 #include "ppapi/cpp/module.h"
14 #include "ppapi/cpp/tcp_socket.h"
15 #include "ppapi/cpp/udp_socket.h"
16 #include "ppapi/cpp/var.h"
17 #include "ppapi/utility/completion_callback_factory.h"
21 // Allow 'this' in initializer list
22 #pragma warning(disable : 4355)
25 class ExampleInstance
: public pp::Instance
{
27 explicit ExampleInstance(PP_Instance instance
)
28 : pp::Instance(instance
),
29 callback_factory_(this),
30 send_outstanding_(false),
33 virtual ~ExampleInstance() {
37 virtual void HandleMessage(const pp::Var
& var_message
);
43 void Connect(const std::string
& host
, bool tcp
);
45 void Send(const std::string
& message
);
48 void OnConnectCompletion(int32_t result
);
49 void OnResolveCompletion(int32_t result
);
50 void OnReceiveCompletion(int32_t result
);
51 void OnReceiveFromCompletion(int32_t result
, pp::NetAddress source
);
52 void OnSendCompletion(int32_t result
);
54 pp::CompletionCallbackFactory
<ExampleInstance
> callback_factory_
;
55 pp::TCPSocket tcp_socket_
;
56 pp::UDPSocket udp_socket_
;
57 pp::HostResolver resolver_
;
58 pp::NetAddress remote_host_
;
60 char receive_buffer_
[kBufferSize
];
61 bool send_outstanding_
;
62 EchoServer
* echo_server_
;
65 #define MSG_CREATE_TCP 't'
66 #define MSG_CREATE_UDP 'u'
69 #define MSG_LISTEN 'l'
71 void ExampleInstance::HandleMessage(const pp::Var
& var_message
) {
72 if (!var_message
.is_string())
74 std::string message
= var_message
.AsString();
75 // This message must contain a command character followed by ';' and
76 // arguments like "X;arguments".
77 if (message
.length() < 2 || message
[1] != ';')
81 // The command 'b' requests to create a UDP connection the
83 // HOST is passed as an argument like "t;HOST".
84 Connect(message
.substr(2), false);
87 // The command 'o' requests to connect to the specified HOST.
88 // HOST is passed as an argument like "u;HOST".
89 Connect(message
.substr(2), true);
92 // The command 'c' requests to close without any argument like "c;"
97 // The command 'l' starts a listening socket (server).
98 int port
= atoi(message
.substr(2).c_str());
99 echo_server_
= new EchoServer(this, port
);
103 // The command 't' requests to send a message as a text frame. The
104 // message passed as an argument like "t;message".
105 Send(message
.substr(2));
108 std::ostringstream status
;
109 status
<< "Unhandled message from JavaScript: " << message
;
110 PostMessage(status
.str());
115 bool ExampleInstance::IsConnected() {
116 if (!tcp_socket_
.is_null())
118 if (!udp_socket_
.is_null())
124 bool ExampleInstance::IsUDP() {
125 return !udp_socket_
.is_null();
128 void ExampleInstance::Connect(const std::string
& host
, bool tcp
) {
130 PostMessage("Already connected.");
135 if (!pp::TCPSocket::IsAvailable()) {
136 PostMessage("TCPSocket not available");
140 tcp_socket_
= pp::TCPSocket(this);
141 if (tcp_socket_
.is_null()) {
142 PostMessage("Error creating TCPSocket.");
146 if (!pp::UDPSocket::IsAvailable()) {
147 PostMessage("UDPSocket not available");
151 udp_socket_
= pp::UDPSocket(this);
152 if (udp_socket_
.is_null()) {
153 PostMessage("Error creating UDPSocket.");
158 if (!pp::HostResolver::IsAvailable()) {
159 PostMessage("HostResolver not available");
163 resolver_
= pp::HostResolver(this);
164 if (resolver_
.is_null()) {
165 PostMessage("Error creating HostResolver.");
170 std::string hostname
= host
;
171 size_t pos
= host
.rfind(':');
172 if (pos
!= std::string::npos
) {
173 hostname
= host
.substr(0, pos
);
174 port
= atoi(host
.substr(pos
+1).c_str());
177 pp::CompletionCallback callback
=
178 callback_factory_
.NewCallback(&ExampleInstance::OnResolveCompletion
);
179 PP_HostResolver_Hint hint
= { PP_NETADDRESS_FAMILY_UNSPECIFIED
, 0 };
180 resolver_
.Resolve(hostname
.c_str(), port
, hint
, callback
);
181 PostMessage("Resolving ...");
184 void ExampleInstance::OnResolveCompletion(int32_t result
) {
185 if (result
!= PP_OK
) {
186 PostMessage("Resolve failed.");
190 pp::NetAddress addr
= resolver_
.GetNetAddress(0);
191 PostMessage(std::string("Resolved: ") +
192 addr
.DescribeAsString(true).AsString());
194 pp::CompletionCallback callback
=
195 callback_factory_
.NewCallback(&ExampleInstance::OnConnectCompletion
);
198 PostMessage("Binding ...");
200 PP_NetAddress_IPv4 ipv4_addr
= { 0, { 0 } };
201 udp_socket_
.Bind(pp::NetAddress(this, ipv4_addr
), callback
);
203 PostMessage("Connecting ...");
204 tcp_socket_
.Connect(addr
, callback
);
208 void ExampleInstance::Close() {
209 if (!IsConnected()) {
210 PostMessage("Not connected.");
214 if (tcp_socket_
.is_null()) {
216 udp_socket_
= pp::UDPSocket();
219 tcp_socket_
= pp::TCPSocket();
222 PostMessage("Closed connection.");
225 void ExampleInstance::Send(const std::string
& message
) {
226 if (!IsConnected()) {
227 PostMessage("Not connected.");
231 if (send_outstanding_
) {
232 PostMessage("Already sending.");
236 uint32_t size
= message
.size();
237 const char* data
= message
.c_str();
238 pp::CompletionCallback callback
=
239 callback_factory_
.NewCallback(&ExampleInstance::OnSendCompletion
);
242 result
= udp_socket_
.SendTo(data
, size
, remote_host_
, callback
);
244 result
= tcp_socket_
.Write(data
, size
, callback
);
245 std::ostringstream status
;
247 if (result
== PP_OK_COMPLETIONPENDING
) {
248 status
<< "Sending bytes: " << size
;
249 PostMessage(status
.str());
250 send_outstanding_
= true;
252 status
<< "Send returned error: " << result
;
253 PostMessage(status
.str());
256 status
<< "Sent bytes synchronously: " << result
;
257 PostMessage(status
.str());
261 void ExampleInstance::Receive() {
262 memset(receive_buffer_
, 0, kBufferSize
);
264 pp::CompletionCallbackWithOutput
<pp::NetAddress
> callback
=
265 callback_factory_
.NewCallbackWithOutput(
266 &ExampleInstance::OnReceiveFromCompletion
);
267 udp_socket_
.RecvFrom(receive_buffer_
, kBufferSize
, callback
);
269 pp::CompletionCallback callback
=
270 callback_factory_
.NewCallback(&ExampleInstance::OnReceiveCompletion
);
271 tcp_socket_
.Read(receive_buffer_
, kBufferSize
, callback
);
275 void ExampleInstance::OnConnectCompletion(int32_t result
) {
276 if (result
!= PP_OK
) {
277 std::ostringstream status
;
278 status
<< "Connection failed: " << result
;
279 PostMessage(status
.str());
284 pp::NetAddress addr
= udp_socket_
.GetBoundAddress();
285 PostMessage(std::string("Bound to: ") +
286 addr
.DescribeAsString(true).AsString());
288 PostMessage("Connected");
294 void ExampleInstance::OnReceiveFromCompletion(int32_t result
,
295 pp::NetAddress source
) {
296 OnReceiveCompletion(result
);
299 void ExampleInstance::OnReceiveCompletion(int32_t result
) {
301 std::ostringstream status
;
302 status
<< "Receive failed with: " << result
;
303 PostMessage(status
.str());
307 PostMessage(std::string("Received: ") + std::string(receive_buffer_
, result
));
311 void ExampleInstance::OnSendCompletion(int32_t result
) {
312 std::ostringstream status
;
314 status
<< "Send failed with: " << result
;
316 status
<< "Sent bytes: " << result
;
318 send_outstanding_
= false;
319 PostMessage(status
.str());
322 // The ExampleModule provides an implementation of pp::Module that creates
323 // ExampleInstance objects when invoked.
324 class ExampleModule
: public pp::Module
{
326 ExampleModule() : pp::Module() {}
327 virtual ~ExampleModule() {}
329 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
330 return new ExampleInstance(instance
);
334 // Implement the required pp::CreateModule function that creates our specific
337 Module
* CreateModule() { return new ExampleModule(); }