OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdio.h> | 5 #include <stdio.h> |
| 6 #include <arpa/inet.h> |
6 | 7 |
7 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/memory/weak_ptr.h" |
| 10 #include "mojo/common/handle_watcher.h" |
8 #include "mojo/public/c/system/main.h" | 11 #include "mojo/public/c/system/main.h" |
9 #include "mojo/public/cpp/application/application_delegate.h" | 12 #include "mojo/public/cpp/application/application_delegate.h" |
10 #include "mojo/public/cpp/application/application_impl.h" | 13 #include "mojo/public/cpp/application/application_impl.h" |
11 #include "mojo/public/cpp/application/application_runner.h" | 14 #include "mojo/public/cpp/application/application_runner.h" |
| 15 #include "mojo/public/cpp/system/data_pipe.h" |
12 #include "mojo/services/public/interfaces/network/network_service.mojom.h" | 16 #include "mojo/services/public/interfaces/network/network_service.mojom.h" |
13 | 17 |
14 namespace mojo { | 18 namespace mojo { |
15 namespace examples { | 19 namespace examples { |
16 | 20 |
| 21 // The canned response that this server replies to each request with. |
| 22 const char kResponse[] = |
| 23 "HTTP/1.0 200 OK\n" |
| 24 "Content-Type: text/html; charset=utf-8\n" |
| 25 "\n" |
| 26 "Hello, world\n"; |
| 27 |
| 28 // Represents one connection to a client. This connection will manage its own |
| 29 // lifetime and will delete itself when the connection is closed. |
| 30 class Connection { |
| 31 public: |
| 32 Connection(TCPConnectedSocketPtr conn, |
| 33 ScopedDataPipeProducerHandle sender, |
| 34 ScopedDataPipeConsumerHandle receiver) |
| 35 : connection_(conn.Pass()), |
| 36 sender_(sender.Pass()), |
| 37 receiver_(receiver.Pass()), |
| 38 weak_ptr_factory_(this), |
| 39 response_(kResponse), |
| 40 response_offset_(0) { |
| 41 WriteMore(); |
| 42 } |
| 43 |
| 44 ~Connection() { |
| 45 } |
| 46 |
| 47 private: |
| 48 void OnSenderReady(MojoResult result) { |
| 49 WriteMore(); |
| 50 } |
| 51 |
| 52 void WriteMore() { |
| 53 uint32_t num_bytes = |
| 54 static_cast<uint32_t>(response_.size() - response_offset_); |
| 55 // TODO(brettw) write chunks (ideally capped at some small size to |
| 56 // illustrate how it works even in the presence of our relatively small |
| 57 // reply) rather than specifying ALL_OR_NONE. See below. |
| 58 MojoResult result = WriteDataRaw( |
| 59 sender_.get(), &response_[response_offset_], &num_bytes, |
| 60 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); |
| 61 if (result == MOJO_RESULT_SHOULD_WAIT) { |
| 62 num_bytes = 0; |
| 63 } else if (result != MOJO_RESULT_OK) { |
| 64 printf("Error writing to pipe.\n"); |
| 65 delete this; |
| 66 return; |
| 67 } |
| 68 |
| 69 response_offset_ += num_bytes; |
| 70 |
| 71 if (response_offset_ == response_.size()) { |
| 72 // Connection complete. |
| 73 delete this; |
| 74 return; |
| 75 } |
| 76 |
| 77 // Wait for sender to be writable. |
| 78 // TODO(brettw) we won't actually get here since we ALL_OR_NONE was |
| 79 // specified above. This call won't work because the message loop is not a |
| 80 // Chromium message loop. Instead, we probably need to use |
| 81 // Environment::GetDefaultAsyncWaiter to wait on the handles and remove the |
| 82 // ALL_OR_NONE flag. |
| 83 sender_watcher_.Start( |
| 84 sender_.get(), |
| 85 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE, |
| 86 base::Bind(&Connection::OnSenderReady, weak_ptr_factory_.GetWeakPtr())); |
| 87 } |
| 88 |
| 89 TCPConnectedSocketPtr connection_; |
| 90 ScopedDataPipeProducerHandle sender_; |
| 91 ScopedDataPipeConsumerHandle receiver_; |
| 92 |
| 93 base::WeakPtrFactory<Connection> weak_ptr_factory_; |
| 94 common::HandleWatcher sender_watcher_; |
| 95 |
| 96 std::string response_; |
| 97 size_t response_offset_; |
| 98 }; |
| 99 |
17 class HttpServerApp : public ApplicationDelegate { | 100 class HttpServerApp : public ApplicationDelegate { |
18 public: | 101 public: |
19 virtual void Initialize(ApplicationImpl* app) override { | 102 virtual void Initialize(ApplicationImpl* app) override { |
20 app->ConnectToService("mojo:mojo_network_service", &network_service_); | 103 app->ConnectToService("mojo:mojo_network_service", &network_service_); |
21 Start(); | 104 Start(); |
22 } | 105 } |
23 | 106 |
24 private: | 107 private: |
25 void OnListeningStarted(NetworkErrorPtr err) { | |
26 } | |
27 | |
28 void OnSocketBound(NetworkErrorPtr err, NetAddressPtr bound_address) { | 108 void OnSocketBound(NetworkErrorPtr err, NetAddressPtr bound_address) { |
29 if (err->code != 0) { | 109 if (err->code != 0) { |
30 printf("Bound err = %d\n", err->code); | 110 printf("Bound err = %d\n", err->code); |
31 return; | 111 return; |
32 } | 112 } |
33 | 113 |
34 printf("Got address = %d.%d.%d.%d:%d\n", | 114 printf("Got address %d.%d.%d.%d:%d\n", |
35 (int)bound_address->ipv4->addr[0], | 115 (int)bound_address->ipv4->addr[0], |
36 (int)bound_address->ipv4->addr[1], | 116 (int)bound_address->ipv4->addr[1], |
37 (int)bound_address->ipv4->addr[2], | 117 (int)bound_address->ipv4->addr[2], |
38 (int)bound_address->ipv4->addr[3], | 118 (int)bound_address->ipv4->addr[3], |
39 (int)bound_address->ipv4->port); | 119 (int)bound_address->ipv4->port); |
| 120 } |
40 | 121 |
41 bound_socket_->StartListening( | 122 void OnSocketListening(NetworkErrorPtr err) { |
42 GetProxy(&server_socket_), | 123 if (err->code != 0) { |
43 base::Bind(&HttpServerApp::OnListeningStarted, | 124 printf("Listen err = %d\n", err->code); |
44 base::Unretained(this))); | 125 return; |
| 126 } |
| 127 printf("Waiting for incoming connections...\n"); |
| 128 } |
| 129 |
| 130 void OnConnectionAccepted(NetworkErrorPtr err, NetAddressPtr remote_address) { |
| 131 if (err->code != 0) { |
| 132 printf("Accepted socket error = %d\n", err->code); |
| 133 return; |
| 134 } |
| 135 |
| 136 new Connection(pending_connected_socket_.Pass(), |
| 137 pending_send_handle_.Pass(), |
| 138 pending_receive_handle_.Pass()); |
| 139 |
| 140 // Ready for another connection. |
| 141 WaitForNextConnection(); |
| 142 } |
| 143 |
| 144 void WaitForNextConnection() { |
| 145 // Need two pipes (one for each direction). |
| 146 ScopedDataPipeConsumerHandle send_consumer_handle; |
| 147 MojoResult result = CreateDataPipe( |
| 148 nullptr, &pending_send_handle_, &send_consumer_handle); |
| 149 assert(result == MOJO_RESULT_OK); |
| 150 |
| 151 ScopedDataPipeProducerHandle receive_producer_handle; |
| 152 result = CreateDataPipe( |
| 153 nullptr, &receive_producer_handle, &pending_receive_handle_); |
| 154 assert(result == MOJO_RESULT_OK); |
| 155 |
| 156 server_socket_->Accept(send_consumer_handle.Pass(), |
| 157 receive_producer_handle.Pass(), |
| 158 GetProxy(&pending_connected_socket_), |
| 159 base::Bind(&HttpServerApp::OnConnectionAccepted, |
| 160 base::Unretained(this))); |
45 } | 161 } |
46 | 162 |
47 void Start() { | 163 void Start() { |
48 NetAddressPtr net_address(NetAddress::New()); | 164 NetAddressPtr net_address(NetAddress::New()); |
49 net_address->family = NET_ADDRESS_FAMILY_IPV4; | 165 net_address->family = NET_ADDRESS_FAMILY_IPV4; |
50 net_address->ipv4 = NetAddressIPv4::New(); | 166 net_address->ipv4 = NetAddressIPv4::New(); |
51 net_address->ipv4->addr.resize(4); | 167 net_address->ipv4->addr.resize(4); |
52 net_address->ipv4->addr[0] = 0; | 168 net_address->ipv4->addr[0] = 127; |
53 net_address->ipv4->addr[1] = 0; | 169 net_address->ipv4->addr[1] = 0; |
54 net_address->ipv4->addr[2] = 0; | 170 net_address->ipv4->addr[2] = 0; |
55 net_address->ipv4->addr[3] = 0; | 171 net_address->ipv4->addr[3] = 1; |
| 172 net_address->ipv4->port = 0; |
56 | 173 |
| 174 // Note that we can start using the proxies right away even thought the |
| 175 // callbacks have not been called yet. If a previous step fails, they'll |
| 176 // all fail. |
57 network_service_->CreateTCPBoundSocket( | 177 network_service_->CreateTCPBoundSocket( |
58 net_address.Pass(), | 178 net_address.Pass(), |
59 GetProxy(&bound_socket_), | 179 GetProxy(&bound_socket_), |
60 base::Bind(&HttpServerApp::OnSocketBound, base::Unretained(this))); | 180 base::Bind(&HttpServerApp::OnSocketBound, base::Unretained(this))); |
| 181 bound_socket_->StartListening(GetProxy( |
| 182 &server_socket_), |
| 183 base::Bind(&HttpServerApp::OnSocketListening, base::Unretained(this))); |
| 184 WaitForNextConnection(); |
61 } | 185 } |
62 | 186 |
63 NetworkServicePtr network_service_; | 187 NetworkServicePtr network_service_; |
64 TCPBoundSocketPtr bound_socket_; | 188 TCPBoundSocketPtr bound_socket_; |
65 TCPServerSocketPtr server_socket_; | 189 TCPServerSocketPtr server_socket_; |
| 190 |
| 191 ScopedDataPipeProducerHandle pending_send_handle_; |
| 192 ScopedDataPipeConsumerHandle pending_receive_handle_; |
| 193 TCPConnectedSocketPtr pending_connected_socket_; |
66 }; | 194 }; |
67 | 195 |
68 } // namespace examples | 196 } // namespace examples |
69 } // namespace mojo | 197 } // namespace mojo |
70 | 198 |
71 MojoResult MojoMain(MojoHandle shell_handle) { | 199 MojoResult MojoMain(MojoHandle shell_handle) { |
72 mojo::ApplicationRunner runner(new mojo::examples::HttpServerApp); | 200 mojo::ApplicationRunner runner(new mojo::examples::HttpServerApp); |
73 return runner.Run(shell_handle); | 201 return runner.Run(shell_handle); |
74 } | 202 } |
OLD | NEW |