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"
11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/cpp/var.h"
13 #include "ppapi/utility/completion_callback_factory.h"
19 // Number of connections to queue up on the listening
20 // socket before new ones get "Connection Refused"
21 static const int kBacklog
= 10;
23 // Implement htons locally. Even though this is provided by
24 // nacl_io we don't want to include nacl_io in this simple
26 static uint16_t Htons(uint16_t hostshort
) {
27 uint8_t result_bytes
[2];
28 result_bytes
[0] = (uint8_t) ((hostshort
>> 8) & 0xFF);
29 result_bytes
[1] = (uint8_t) (hostshort
& 0xFF);
32 memcpy(&result
, result_bytes
, 2);
36 void EchoServer::Start(uint16_t port
) {
37 if (!pp::TCPSocket::IsAvailable()) {
38 Log("TCPSocket not available");
42 listening_socket_
= pp::TCPSocket(instance_
);
43 if (listening_socket_
.is_null()) {
44 Log("Error creating TCPSocket.");
48 std::ostringstream status
;
49 status
<< "Starting server on port: " << port
;
50 Log(status
.str().c_str());
52 // Attempt to listen on all interfaces (0.0.0.0)
53 // on the given port number.
54 PP_NetAddress_IPv4 ipv4_addr
= { Htons(port
), { 0 } };
55 pp::NetAddress
addr(instance_
, ipv4_addr
);
56 pp::CompletionCallback callback
=
57 callback_factory_
.NewCallback(&EchoServer::OnBindCompletion
);
58 int32_t rtn
= listening_socket_
.Bind(addr
, callback
);
59 if (rtn
!= PP_OK_COMPLETIONPENDING
) {
60 Log("Error binding listening socket.");
65 void EchoServer::OnBindCompletion(int32_t result
) {
66 if (result
!= PP_OK
) {
67 std::ostringstream status
;
68 status
<< "server: Bind failed with: " << result
;
69 Log(status
.str().c_str());
73 pp::CompletionCallback callback
=
74 callback_factory_
.NewCallback(&EchoServer::OnListenCompletion
);
76 int32_t rtn
= listening_socket_
.Listen(kBacklog
, callback
);
77 if (rtn
!= PP_OK_COMPLETIONPENDING
) {
78 Log("server: Error listening on server socket.");
83 void EchoServer::OnListenCompletion(int32_t result
) {
84 std::ostringstream status
;
85 if (result
!= PP_OK
) {
86 status
<< "server: Listen failed with: " << result
;
87 Log(status
.str().c_str());
91 pp::NetAddress addr
= listening_socket_
.GetLocalAddress();
92 status
<< "server: Listening on: " << addr
.DescribeAsString(true).AsString();
93 Log(status
.str().c_str());
97 pthread_mutex_lock(ready_lock_
);
98 pthread_cond_signal(ready_cond_
);
99 pthread_mutex_unlock(ready_lock_
);
105 void EchoServer::OnAcceptCompletion(int32_t result
, pp::TCPSocket socket
) {
106 std::ostringstream status
;
108 if (result
!= PP_OK
) {
109 status
<< "server: Accept failed: " << result
;
110 Log(status
.str().c_str());
114 pp::NetAddress addr
= socket
.GetLocalAddress();
115 status
<< "server: New connection from: ";
116 status
<< addr
.DescribeAsString(true).AsString();
117 Log(status
.str().c_str());
118 incoming_socket_
= socket
;
123 void EchoServer::OnReadCompletion(int32_t result
) {
124 std::ostringstream status
;
127 status
<< "server: client disconnected";
129 status
<< "server: Read failed: " << result
;
130 Log(status
.str().c_str());
132 // Remove the current incoming socket and try
133 // to accept the next one.
134 incoming_socket_
.Close();
135 incoming_socket_
= pp::TCPSocket();
140 status
<< "server: Read " << result
<< " bytes";
141 Log(status
.str().c_str());
143 // Echo the bytes back to the client
144 pp::CompletionCallback callback
=
145 callback_factory_
.NewCallback(&EchoServer::OnWriteCompletion
);
146 result
= incoming_socket_
.Write(receive_buffer_
, result
, callback
);
147 if (result
!= PP_OK_COMPLETIONPENDING
) {
148 status
<< "server: Write failed: " << result
;
149 Log(status
.str().c_str());
153 void EchoServer::OnWriteCompletion(int32_t result
) {
154 std::ostringstream status
;
156 status
<< "server: Write failed: " << result
;
157 Log(status
.str().c_str());
161 status
<< "server: Wrote " << result
<< " bytes";
162 Log(status
.str().c_str());
164 // Try and read more bytes from the client
168 void EchoServer::TryRead() {
169 pp::CompletionCallback callback
=
170 callback_factory_
.NewCallback(&EchoServer::OnReadCompletion
);
171 incoming_socket_
.Read(receive_buffer_
, kBufferSize
, callback
);
174 void EchoServer::TryAccept() {
175 pp::CompletionCallbackWithOutput
<pp::TCPSocket
> callback
=
176 callback_factory_
.NewCallbackWithOutput(
177 &EchoServer::OnAcceptCompletion
);
178 listening_socket_
.Accept(callback
);