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 "echo_server.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/cpp/var.h"
12 #include "ppapi/utility/completion_callback_factory.h"
18 // Number of connections to queue up on the listening
19 // socket before new ones get "Connection Refused"
20 static const int kBacklog
= 10;
22 // Implement htons locally. Even though this is provided by
23 // nacl_io we don't want to include nacl_io in this simple
25 static uint16_t Htons(uint16_t hostshort
) {
26 uint8_t result_bytes
[2];
27 result_bytes
[0] = (uint8_t) ((hostshort
>> 8) & 0xFF);
28 result_bytes
[1] = (uint8_t) (hostshort
& 0xFF);
31 memcpy(&result
, result_bytes
, 2);
35 void EchoServer::Start(uint16_t port
) {
36 if (!pp::TCPSocket::IsAvailable()) {
37 instance_
->PostMessage("TCPSocket not available");
41 listening_socket_
= pp::TCPSocket(instance_
);
42 if (listening_socket_
.is_null()) {
43 instance_
->PostMessage("Error creating TCPSocket.");
47 std::ostringstream status
;
48 status
<< "Starting server on port: " << port
;
49 instance_
->PostMessage(status
.str());
51 // Attempt to listen on all interfaces (0.0.0.0)
52 // on the given port number.
53 PP_NetAddress_IPv4 ipv4_addr
= { Htons(port
), { 0 } };
54 pp::NetAddress
addr(instance_
, ipv4_addr
);
55 pp::CompletionCallback callback
=
56 callback_factory_
.NewCallback(&EchoServer::OnBindCompletion
);
57 int32_t rtn
= listening_socket_
.Bind(addr
, callback
);
58 if (rtn
!= PP_OK_COMPLETIONPENDING
) {
59 instance_
->PostMessage("Error binding listening socket.");
64 void EchoServer::OnBindCompletion(int32_t result
) {
65 if (result
!= PP_OK
) {
66 std::ostringstream status
;
67 status
<< "server: Bind failed with: " << result
;
68 instance_
->PostMessage(status
.str());
72 pp::CompletionCallback callback
=
73 callback_factory_
.NewCallback(&EchoServer::OnListenCompletion
);
75 int32_t rtn
= listening_socket_
.Listen(kBacklog
, callback
);
76 if (rtn
!= PP_OK_COMPLETIONPENDING
) {
77 instance_
->PostMessage("server: Error listening on server socket.");
82 void EchoServer::OnListenCompletion(int32_t result
) {
83 std::ostringstream status
;
84 if (result
!= PP_OK
) {
85 status
<< "server: Listen failed with: " << result
;
86 instance_
->PostMessage(status
.str());
90 pp::NetAddress addr
= listening_socket_
.GetLocalAddress();
91 status
<< "server: Listening on: " << addr
.DescribeAsString(true).AsString();
92 instance_
->PostMessage(status
.str());
97 void EchoServer::OnAcceptCompletion(int32_t result
, pp::TCPSocket socket
) {
98 std::ostringstream status
;
100 if (result
!= PP_OK
) {
101 status
<< "server: Accept failed: " << result
;
102 instance_
->PostMessage(status
.str());
106 pp::NetAddress addr
= socket
.GetLocalAddress();
107 status
<< "server: New connection from: ";
108 status
<< addr
.DescribeAsString(true).AsString();
109 instance_
->PostMessage(status
.str());
110 incoming_socket_
= socket
;
115 void EchoServer::OnReadCompletion(int32_t result
) {
116 std::ostringstream status
;
119 status
<< "server: client disconnected";
121 status
<< "server: Read failed: " << result
;
122 instance_
->PostMessage(status
.str());
124 // Remove the current incoming socket and try
125 // to accept the next one.
126 incoming_socket_
.Close();
127 incoming_socket_
= pp::TCPSocket();
132 status
<< "server: Read " << result
<< " bytes";
133 instance_
->PostMessage(status
.str());
135 // Echo the bytes back to the client
136 pp::CompletionCallback callback
=
137 callback_factory_
.NewCallback(&EchoServer::OnWriteCompletion
);
138 result
= incoming_socket_
.Write(receive_buffer_
, result
, callback
);
139 if (result
!= PP_OK_COMPLETIONPENDING
) {
140 status
<< "server: Write failed: " << result
;
141 instance_
->PostMessage(status
.str());
145 void EchoServer::OnWriteCompletion(int32_t result
) {
146 std::ostringstream status
;
148 status
<< "server: Write failed: " << result
;
149 instance_
->PostMessage(status
.str());
153 status
<< "server: Wrote " << result
<< " bytes";
154 instance_
->PostMessage(status
.str());
156 // Try and read more bytes from the client
160 void EchoServer::TryRead() {
161 pp::CompletionCallback callback
=
162 callback_factory_
.NewCallback(&EchoServer::OnReadCompletion
);
163 incoming_socket_
.Read(receive_buffer_
, kBufferSize
, callback
);
166 void EchoServer::TryAccept() {
167 pp::CompletionCallbackWithOutput
<pp::TCPSocket
> callback
=
168 callback_factory_
.NewCallbackWithOutput(
169 &EchoServer::OnAcceptCompletion
);
170 listening_socket_
.Accept(callback
);