Send a crash report when a hung process is detected.
[chromium-blink-merge.git] / native_client_sdk / src / examples / api / socket / socket.cc
bloba988081428af8f7af9269eef1c93b08261368f6e
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.
5 #include <stdio.h>
6 #include <string.h>
7 #include <sstream>
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"
19 #ifdef WIN32
20 #undef PostMessage
21 // Allow 'this' in initializer list
22 #pragma warning(disable : 4355)
23 #endif
25 class ExampleInstance : public pp::Instance {
26 public:
27 explicit ExampleInstance(PP_Instance instance)
28 : pp::Instance(instance),
29 callback_factory_(this),
30 send_outstanding_(false),
31 echo_server_(NULL) {}
33 virtual ~ExampleInstance() {
34 delete echo_server_;
37 virtual void HandleMessage(const pp::Var& var_message);
39 private:
40 bool IsConnected();
41 bool IsUDP();
43 void Connect(const std::string& host, bool tcp);
44 void Close();
45 void Send(const std::string& message);
46 void Receive();
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'
67 #define MSG_SEND 's'
68 #define MSG_CLOSE 'c'
69 #define MSG_LISTEN 'l'
71 void ExampleInstance::HandleMessage(const pp::Var& var_message) {
72 if (!var_message.is_string())
73 return;
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] != ';')
78 return;
79 switch (message[0]) {
80 case MSG_CREATE_UDP:
81 // The command 'b' requests to create a UDP connection the
82 // specified HOST.
83 // HOST is passed as an argument like "t;HOST".
84 Connect(message.substr(2), false);
85 break;
86 case MSG_CREATE_TCP:
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);
90 break;
91 case MSG_CLOSE:
92 // The command 'c' requests to close without any argument like "c;"
93 Close();
94 break;
95 case MSG_LISTEN:
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);
100 break;
102 case MSG_SEND:
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));
106 break;
107 default:
108 std::ostringstream status;
109 status << "Unhandled message from JavaScript: " << message;
110 PostMessage(status.str());
111 break;
115 bool ExampleInstance::IsConnected() {
116 if (!tcp_socket_.is_null())
117 return true;
118 if (!udp_socket_.is_null())
119 return true;
121 return false;
124 bool ExampleInstance::IsUDP() {
125 return !udp_socket_.is_null();
128 void ExampleInstance::Connect(const std::string& host, bool tcp) {
129 if (IsConnected()) {
130 PostMessage("Already connected.");
131 return;
134 if (tcp) {
135 if (!pp::TCPSocket::IsAvailable()) {
136 PostMessage("TCPSocket not available");
137 return;
140 tcp_socket_ = pp::TCPSocket(this);
141 if (tcp_socket_.is_null()) {
142 PostMessage("Error creating TCPSocket.");
143 return;
145 } else {
146 if (!pp::UDPSocket::IsAvailable()) {
147 PostMessage("UDPSocket not available");
148 return;
151 udp_socket_ = pp::UDPSocket(this);
152 if (udp_socket_.is_null()) {
153 PostMessage("Error creating UDPSocket.");
154 return;
158 if (!pp::HostResolver::IsAvailable()) {
159 PostMessage("HostResolver not available");
160 return;
163 resolver_ = pp::HostResolver(this);
164 if (resolver_.is_null()) {
165 PostMessage("Error creating HostResolver.");
166 return;
169 int port = 80;
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.");
187 return;
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);
197 if (IsUDP()) {
198 PostMessage("Binding ...");
199 remote_host_ = addr;
200 PP_NetAddress_IPv4 ipv4_addr = { 0, { 0 } };
201 udp_socket_.Bind(pp::NetAddress(this, ipv4_addr), callback);
202 } else {
203 PostMessage("Connecting ...");
204 tcp_socket_.Connect(addr, callback);
208 void ExampleInstance::Close() {
209 if (!IsConnected()) {
210 PostMessage("Not connected.");
211 return;
214 if (tcp_socket_.is_null()) {
215 udp_socket_.Close();
216 udp_socket_ = pp::UDPSocket();
217 } else {
218 tcp_socket_.Close();
219 tcp_socket_ = pp::TCPSocket();
222 PostMessage("Closed connection.");
225 void ExampleInstance::Send(const std::string& message) {
226 if (!IsConnected()) {
227 PostMessage("Not connected.");
228 return;
231 if (send_outstanding_) {
232 PostMessage("Already sending.");
233 return;
236 uint32_t size = message.size();
237 const char* data = message.c_str();
238 pp::CompletionCallback callback =
239 callback_factory_.NewCallback(&ExampleInstance::OnSendCompletion);
240 int32_t result;
241 if (IsUDP())
242 result = udp_socket_.SendTo(data, size, remote_host_, callback);
243 else
244 result = tcp_socket_.Write(data, size, callback);
245 std::ostringstream status;
246 if (result < 0) {
247 if (result == PP_OK_COMPLETIONPENDING) {
248 status << "Sending bytes: " << size;
249 PostMessage(status.str());
250 send_outstanding_ = true;
251 } else {
252 status << "Send returned error: " << result;
253 PostMessage(status.str());
255 } else {
256 status << "Sent bytes synchronously: " << result;
257 PostMessage(status.str());
261 void ExampleInstance::Receive() {
262 memset(receive_buffer_, 0, kBufferSize);
263 if (IsUDP()) {
264 pp::CompletionCallbackWithOutput<pp::NetAddress> callback =
265 callback_factory_.NewCallbackWithOutput(
266 &ExampleInstance::OnReceiveFromCompletion);
267 udp_socket_.RecvFrom(receive_buffer_, kBufferSize, callback);
268 } else {
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());
280 return;
283 if (IsUDP()) {
284 pp::NetAddress addr = udp_socket_.GetBoundAddress();
285 PostMessage(std::string("Bound to: ") +
286 addr.DescribeAsString(true).AsString());
287 } else {
288 PostMessage("Connected");
291 Receive();
294 void ExampleInstance::OnReceiveFromCompletion(int32_t result,
295 pp::NetAddress source) {
296 OnReceiveCompletion(result);
299 void ExampleInstance::OnReceiveCompletion(int32_t result) {
300 if (result < 0) {
301 std::ostringstream status;
302 status << "Receive failed with: " << result;
303 PostMessage(status.str());
304 return;
307 PostMessage(std::string("Received: ") + std::string(receive_buffer_, result));
308 Receive();
311 void ExampleInstance::OnSendCompletion(int32_t result) {
312 std::ostringstream status;
313 if (result < 0) {
314 status << "Send failed with: " << result;
315 } else {
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 {
325 public:
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
335 // kind of Module.
336 namespace pp {
337 Module* CreateModule() { return new ExampleModule(); }
338 } // namespace pp