- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / examples / api / socket / echo_server.cc
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.
4
5 #include "echo_server.h"
6
7 #include <string.h>
8 #include <sstream>
9
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/cpp/var.h"
12 #include "ppapi/utility/completion_callback_factory.h"
13
14 #ifdef WIN32
15 #undef PostMessage
16 #endif
17
18 // Number of connections to queue up on the listening
19 // socket before new ones get "Connection Refused"
20 static const int kBacklog = 10;
21
22 // Implement htons locally.  Even though this is provided by
23 // nacl_io we don't want to include nacl_io in this simple
24 // example.
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);
29
30   uint16_t result;
31   memcpy(&result, result_bytes, 2);
32   return result;
33 }
34
35 void EchoServer::Start(uint16_t port) {
36   if (!pp::TCPSocket::IsAvailable()) {
37     instance_->PostMessage("TCPSocket not available");
38     return;
39   }
40
41   listening_socket_ = pp::TCPSocket(instance_);
42   if (listening_socket_.is_null()) {
43     instance_->PostMessage("Error creating TCPSocket.");
44     return;
45   }
46
47   std::ostringstream status;
48   status << "Starting server on port: " << port;
49   instance_->PostMessage(status.str());
50
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.");
60     return;
61   }
62 }
63
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());
69     return;
70   }
71
72   pp::CompletionCallback callback =
73       callback_factory_.NewCallback(&EchoServer::OnListenCompletion);
74
75   int32_t rtn = listening_socket_.Listen(kBacklog, callback);
76   if (rtn != PP_OK_COMPLETIONPENDING) {
77     instance_->PostMessage("server: Error listening on server socket.");
78     return;
79   }
80 }
81
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());
87     return;
88   }
89
90   pp::NetAddress addr = listening_socket_.GetLocalAddress();
91   status << "server: Listening on: " << addr.DescribeAsString(true).AsString();
92   instance_->PostMessage(status.str());
93
94   TryAccept();
95 }
96
97 void EchoServer::OnAcceptCompletion(int32_t result, pp::TCPSocket socket) {
98   std::ostringstream status;
99
100   if (result != PP_OK) {
101     status << "server: Accept failed: " << result;
102     instance_->PostMessage(status.str());
103     return;
104   }
105
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;
111
112   TryRead();
113 }
114
115 void EchoServer::OnReadCompletion(int32_t result) {
116   std::ostringstream status;
117   if (result <= 0) {
118     if (result == 0)
119       status << "server: client disconnected";
120     else
121       status << "server: Read failed: " << result;
122     instance_->PostMessage(status.str());
123
124     // Remove the current incoming socket and try
125     // to accept the next one.
126     incoming_socket_.Close();
127     incoming_socket_ = pp::TCPSocket();
128     TryAccept();
129     return;
130   }
131
132   status << "server: Read " << result << " bytes";
133   instance_->PostMessage(status.str());
134
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());
142   }
143 }
144
145 void EchoServer::OnWriteCompletion(int32_t result) {
146   std::ostringstream status;
147   if (result < 0) {
148     status << "server: Write failed: " << result;
149     instance_->PostMessage(status.str());
150     return;
151   }
152
153   status << "server: Wrote " << result << " bytes";
154   instance_->PostMessage(status.str());
155
156   // Try and read more bytes from the client
157   TryRead();
158 }
159
160 void EchoServer::TryRead() {
161   pp::CompletionCallback callback =
162       callback_factory_.NewCallback(&EchoServer::OnReadCompletion);
163   incoming_socket_.Read(receive_buffer_, kBufferSize, callback);
164 }
165
166 void EchoServer::TryAccept() {
167   pp::CompletionCallbackWithOutput<pp::TCPSocket> callback =
168       callback_factory_.NewCallbackWithOutput(
169           &EchoServer::OnAcceptCompletion);
170   listening_socket_.Accept(callback);
171 }