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