14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "echo_server.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string.h>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <sstream>
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ppapi/c/pp_errors.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ppapi/cpp/var.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#ifdef WIN32
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#undef PostMessage
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Number of connections to queue up on the listening
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// socket before new ones get "Connection Refused"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static const int kBacklog = 10;
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Implement htons locally.  Even though this is provided by
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// nacl_io we don't want to include nacl_io in this simple
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// example.
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static uint16_t Htons(uint16_t hostshort) {
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint8_t result_bytes[2];
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result_bytes[0] = (uint8_t) ((hostshort >> 8) & 0xFF);
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result_bytes[1] = (uint8_t) (hostshort & 0xFF);
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint16_t result;
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  memcpy(&result, result_bytes, 2);
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return result;
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::Start(uint16_t port) {
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!pp::TCPSocket::IsAvailable()) {
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage("TCPSocket not available");
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  listening_socket_ = pp::TCPSocket(instance_);
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (listening_socket_.is_null()) {
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage("Error creating TCPSocket.");
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::ostringstream status;
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status << "Starting server on port: " << port;
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  instance_->PostMessage(status.str());
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Attempt to listen on all interfaces (0.0.0.0)
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // on the given port number.
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  PP_NetAddress_IPv4 ipv4_addr = { Htons(port), { 0 } };
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::NetAddress addr(instance_, ipv4_addr);
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      callback_factory_.NewCallback(&EchoServer::OnBindCompletion);
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int32_t rtn = listening_socket_.Bind(addr, callback);
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (rtn != PP_OK_COMPLETIONPENDING) {
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage("Error binding listening socket.");
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::OnBindCompletion(int32_t result) {
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (result != PP_OK) {
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::ostringstream status;
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    status << "server: Bind failed with: " << result;
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage(status.str());
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      callback_factory_.NewCallback(&EchoServer::OnListenCompletion);
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int32_t rtn = listening_socket_.Listen(kBacklog, callback);
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (rtn != PP_OK_COMPLETIONPENDING) {
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage("server: Error listening on server socket.");
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::OnListenCompletion(int32_t result) {
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::ostringstream status;
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (result != PP_OK) {
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    status << "server: Listen failed with: " << result;
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage(status.str());
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::NetAddress addr = listening_socket_.GetLocalAddress();
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status << "server: Listening on: " << addr.DescribeAsString(true).AsString();
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  instance_->PostMessage(status.str());
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TryAccept();
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::OnAcceptCompletion(int32_t result, pp::TCPSocket socket) {
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::ostringstream status;
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (result != PP_OK) {
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    status << "server: Accept failed: " << result;
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage(status.str());
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::NetAddress addr = socket.GetLocalAddress();
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status << "server: New connection from: ";
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status << addr.DescribeAsString(true).AsString();
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  instance_->PostMessage(status.str());
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  incoming_socket_ = socket;
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TryRead();
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::OnReadCompletion(int32_t result) {
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::ostringstream status;
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (result <= 0) {
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (result == 0)
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      status << "server: client disconnected";
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    else
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      status << "server: Read failed: " << result;
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage(status.str());
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Remove the current incoming socket and try
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // to accept the next one.
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    incoming_socket_.Close();
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    incoming_socket_ = pp::TCPSocket();
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    TryAccept();
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status << "server: Read " << result << " bytes";
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  instance_->PostMessage(status.str());
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Echo the bytes back to the client
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      callback_factory_.NewCallback(&EchoServer::OnWriteCompletion);
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result = incoming_socket_.Write(receive_buffer_, result, callback);
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (result != PP_OK_COMPLETIONPENDING) {
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    status << "server: Write failed: " << result;
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage(status.str());
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::OnWriteCompletion(int32_t result) {
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::ostringstream status;
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (result < 0) {
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    status << "server: Write failed: " << result;
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    instance_->PostMessage(status.str());
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status << "server: Wrote " << result << " bytes";
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  instance_->PostMessage(status.str());
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Try and read more bytes from the client
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TryRead();
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::TryRead() {
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallback callback =
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      callback_factory_.NewCallback(&EchoServer::OnReadCompletion);
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  incoming_socket_.Read(receive_buffer_, kBufferSize, callback);
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EchoServer::TryAccept() {
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::CompletionCallbackWithOutput<pp::TCPSocket> callback =
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      callback_factory_.NewCallbackWithOutput(
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          &EchoServer::OnAcceptCompletion);
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  listening_socket_.Accept(callback);
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
172