1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file.
4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <stdio.h>
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <string.h>
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <sstream>
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "echo_server.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/host_resolver.h"
12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/instance.h"
13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/module.h"
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/tcp_socket.h"
15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/udp_socket.h"
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/var.h"
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#ifdef WIN32
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#undef PostMessage
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Allow 'this' in initializer list
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#pragma warning(disable : 4355)
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class ExampleInstance : public pp::Instance {
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public:
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  explicit ExampleInstance(PP_Instance instance)
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    : pp::Instance(instance),
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      callback_factory_(this),
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      send_outstanding_(false),
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      echo_server_(NULL) {}
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~ExampleInstance() {
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    delete echo_server_;
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual void HandleMessage(const pp::Var& var_message);
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private:
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool IsConnected();
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool IsUDP();
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Connect(const std::string& host, bool tcp);
44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Close();
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Send(const std::string& message);
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Receive();
47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnConnectCompletion(int32_t result);
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnResolveCompletion(int32_t result);
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnReceiveCompletion(int32_t result);
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnReceiveFromCompletion(int32_t result, pp::NetAddress source);
52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnSendCompletion(int32_t result);
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pp::CompletionCallbackFactory<ExampleInstance> callback_factory_;
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pp::TCPSocket tcp_socket_;
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pp::UDPSocket udp_socket_;
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pp::HostResolver resolver_;
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pp::NetAddress remote_host_;
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  char receive_buffer_[kBufferSize];
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool send_outstanding_;
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EchoServer* echo_server_;
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)};
64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#define MSG_CREATE_TCP 't'
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#define MSG_CREATE_UDP 'u'
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#define MSG_SEND 's'
68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#define MSG_CLOSE 'c'
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#define MSG_LISTEN 'l'
70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::HandleMessage(const pp::Var& var_message) {
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!var_message.is_string())
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::string message = var_message.AsString();
75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // This message must contain a command character followed by ';' and
76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // arguments like "X;arguments".
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (message.length() < 2 || message[1] != ';')
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
79a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  switch (message[0]) {
80a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    case MSG_CREATE_UDP:
81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // The command 'b' requests to create a UDP connection the
82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // specified HOST.
83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // HOST is passed as an argument like "t;HOST".
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Connect(message.substr(2), false);
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    case MSG_CREATE_TCP:
87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // The command 'o' requests to connect to the specified HOST.
88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // HOST is passed as an argument like "u;HOST".
89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Connect(message.substr(2), true);
90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    case MSG_CLOSE:
92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // The command 'c' requests to close without any argument like "c;"
93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Close();
94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case MSG_LISTEN:
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // The command 'l' starts a listening socket (server).
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        int port = atoi(message.substr(2).c_str());
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        echo_server_ = new EchoServer(this, port);
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    case MSG_SEND:
103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // The command 't' requests to send a message as a text frame. The
104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // message passed as an argument like "t;message".
105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Send(message.substr(2));
106a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    default:
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      std::ostringstream status;
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      status << "Unhandled message from JavaScript: " << message;
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      PostMessage(status.str());
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool ExampleInstance::IsConnected() {
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!tcp_socket_.is_null())
117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return true;
118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!udp_socket_.is_null())
119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return true;
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return false;
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool ExampleInstance::IsUDP() {
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return !udp_socket_.is_null();
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::Connect(const std::string& host, bool tcp) {
129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (IsConnected()) {
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Already connected.");
131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (tcp) {
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!pp::TCPSocket::IsAvailable()) {
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      PostMessage("TCPSocket not available");
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    tcp_socket_ = pp::TCPSocket(this);
141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (tcp_socket_.is_null()) {
142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      PostMessage("Error creating TCPSocket.");
143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!pp::UDPSocket::IsAvailable()) {
147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      PostMessage("UDPSocket not available");
148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    udp_socket_ = pp::UDPSocket(this);
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (udp_socket_.is_null()) {
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      PostMessage("Error creating UDPSocket.");
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!pp::HostResolver::IsAvailable()) {
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("HostResolver not available");
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  resolver_ = pp::HostResolver(this);
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (resolver_.is_null()) {
165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Error creating HostResolver.");
166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
169a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int port = 80;
170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::string hostname = host;
171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  size_t pos = host.rfind(':');
172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (pos != std::string::npos) {
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    hostname = host.substr(0, pos);
174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    port = atoi(host.substr(pos+1).c_str());
175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
178a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      callback_factory_.NewCallback(&ExampleInstance::OnResolveCompletion);
179a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  PP_HostResolver_Hint hint = { PP_NETADDRESS_FAMILY_UNSPECIFIED, 0 };
180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  resolver_.Resolve(hostname.c_str(), port, hint, callback);
181a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  PostMessage("Resolving ...");
182a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
183a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::OnResolveCompletion(int32_t result) {
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (result != PP_OK) {
186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Resolve failed.");
187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pp::NetAddress addr = resolver_.GetNetAddress(0);
191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  PostMessage(std::string("Resolved: ") +
192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              addr.DescribeAsString(true).AsString());
193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      callback_factory_.NewCallback(&ExampleInstance::OnConnectCompletion);
196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (IsUDP()) {
198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Binding ...");
199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    remote_host_ = addr;
200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PP_NetAddress_IPv4 ipv4_addr = { 0, { 0 } };
201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    udp_socket_.Bind(pp::NetAddress(this, ipv4_addr), callback);
202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
203a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Connecting ...");
204a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    tcp_socket_.Connect(addr, callback);
205a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
206a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
208a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::Close() {
209a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!IsConnected()) {
210a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Not connected.");
211a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
212a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
214a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (tcp_socket_.is_null()) {
215a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    udp_socket_.Close();
216a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    udp_socket_ = pp::UDPSocket();
217a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
218a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    tcp_socket_.Close();
219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    tcp_socket_ = pp::TCPSocket();
220a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
221a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
222a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  PostMessage("Closed connection.");
223a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
224a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::Send(const std::string& message) {
226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!IsConnected()) {
227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Not connected.");
228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
229a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (send_outstanding_) {
232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Already sending.");
233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  uint32_t size = message.size();
237a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const char* data = message.c_str();
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      callback_factory_.NewCallback(&ExampleInstance::OnSendCompletion);
240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int32_t result;
241a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (IsUDP())
242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     result = udp_socket_.SendTo(data, size, remote_host_, callback);
243a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  else
244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     result = tcp_socket_.Write(data, size, callback);
245a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::ostringstream status;
246a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (result < 0) {
247a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (result == PP_OK_COMPLETIONPENDING) {
248a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      status << "Sending bytes: " << size;
249a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      PostMessage(status.str());
250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      send_outstanding_ = true;
251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    } else {
252a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      status << "Send returned error: " << result;
253a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      PostMessage(status.str());
254a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
255a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
256a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status << "Sent bytes synchronously: " << result;
257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage(status.str());
258a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
260a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::Receive() {
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  memset(receive_buffer_, 0, kBufferSize);
263a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (IsUDP()) {
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    pp::CompletionCallbackWithOutput<pp::NetAddress> callback =
265a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        callback_factory_.NewCallbackWithOutput(
266a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            &ExampleInstance::OnReceiveFromCompletion);
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    udp_socket_.RecvFrom(receive_buffer_, kBufferSize, callback);
268a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    pp::CompletionCallback callback =
270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        callback_factory_.NewCallback(&ExampleInstance::OnReceiveCompletion);
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tcp_socket_.Read(receive_buffer_, kBufferSize, callback);
272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
273a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
274a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::OnConnectCompletion(int32_t result) {
276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (result != PP_OK) {
277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::ostringstream status;
278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status << "Connection failed: " << result;
279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage(status.str());
280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
283a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (IsUDP()) {
284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    pp::NetAddress addr = udp_socket_.GetBoundAddress();
285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage(std::string("Bound to: ") +
286a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                addr.DescribeAsString(true).AsString());
287a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
288a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage("Connected");
289a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
290a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
291a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Receive();
292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
293a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
294a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::OnReceiveFromCompletion(int32_t result,
295a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                              pp::NetAddress source) {
296a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  OnReceiveCompletion(result);
297a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
298a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
299a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::OnReceiveCompletion(int32_t result) {
300a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (result < 0) {
301a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::ostringstream status;
302a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status << "Receive failed with: " << result;
303a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostMessage(status.str());
304a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
305a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
306a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  PostMessage(std::string("Received: ") + std::string(receive_buffer_, result));
308a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Receive();
309a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
310a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
311a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExampleInstance::OnSendCompletion(int32_t result) {
312a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::ostringstream status;
313a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (result < 0) {
314a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status << "Send failed with: " << result;
315a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
316a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status << "Sent bytes: " << result;
317a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
318a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  send_outstanding_ = false;
319a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  PostMessage(status.str());
320a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
321a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
322a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// The ExampleModule provides an implementation of pp::Module that creates
323a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// ExampleInstance objects when invoked.
324a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class ExampleModule : public pp::Module {
325a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public:
326a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ExampleModule() : pp::Module() {}
327a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual ~ExampleModule() {}
328a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
329a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual pp::Instance* CreateInstance(PP_Instance instance) {
330a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return new ExampleInstance(instance);
331a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
332a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)};
333a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
334a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Implement the required pp::CreateModule function that creates our specific
335a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// kind of Module.
336a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)namespace pp {
337a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)Module* CreateModule() { return new ExampleModule(); }
338a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}  // namespace pp
339