| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "remoting/client/plugin/pepper_port_allocator.h" | 5 #include "remoting/client/plugin/pepper_port_allocator.h" |
| 6 | 6 |
| 7 #include "base/string_number_conversions.h" | 7 #include "base/string_number_conversions.h" |
| 8 #include "net/base/net_util.h" |
| 8 #include "ppapi/c/pp_errors.h" | 9 #include "ppapi/c/pp_errors.h" |
| 9 #include "ppapi/cpp/completion_callback.h" | 10 #include "ppapi/cpp/completion_callback.h" |
| 11 #include "ppapi/cpp/private/host_resolver_private.h" |
| 10 #include "ppapi/cpp/url_loader.h" | 12 #include "ppapi/cpp/url_loader.h" |
| 11 #include "ppapi/cpp/url_request_info.h" | 13 #include "ppapi/cpp/url_request_info.h" |
| 12 #include "ppapi/cpp/url_response_info.h" | 14 #include "ppapi/cpp/url_response_info.h" |
| 13 #include "remoting/client/plugin/pepper_network_manager.h" | 15 #include "remoting/client/plugin/pepper_network_manager.h" |
| 14 #include "remoting/client/plugin/pepper_packet_socket_factory.h" | 16 #include "remoting/client/plugin/pepper_packet_socket_factory.h" |
| 17 #include "remoting/client/plugin/pepper_util.h" |
| 15 | 18 |
| 16 namespace remoting { | 19 namespace remoting { |
| 17 | 20 |
| 18 namespace { | 21 namespace { |
| 19 | 22 |
| 23 // URL used to create a relay session. |
| 24 const char kCreateRelaySessionURL[] = "/create_session"; |
| 25 |
| 20 // Read buffer we allocate per read when reading response from | 26 // Read buffer we allocate per read when reading response from |
| 21 // URLLoader. Normally the response from URL loader is smaller than 1kB. | 27 // URLLoader. Normally the response from URL loader is smaller than 1kB. |
| 22 const int kReadSize = 1024; | 28 const int kReadSize = 1024; |
| 23 | 29 |
| 24 class PepperPortAllocatorSession | 30 class PepperPortAllocatorSession |
| 25 : public cricket::HttpPortAllocatorSessionBase { | 31 : public cricket::HttpPortAllocatorSessionBase { |
| 26 public: | 32 public: |
| 27 PepperPortAllocatorSession( | 33 PepperPortAllocatorSession( |
| 28 cricket::HttpPortAllocatorBase* allocator, | 34 cricket::HttpPortAllocatorBase* allocator, |
| 29 const std::string& channel_name, | 35 const std::string& channel_name, |
| 30 int component, | 36 int component, |
| 31 const std::vector<talk_base::SocketAddress>& stun_hosts, | 37 const std::vector<talk_base::SocketAddress>& stun_hosts, |
| 32 const std::vector<std::string>& relay_hosts, | 38 const std::vector<std::string>& relay_hosts, |
| 33 const std::string& relay, | 39 const std::string& relay_token, |
| 34 const pp::InstanceHandle& instance); | 40 const pp::InstanceHandle& instance); |
| 35 virtual ~PepperPortAllocatorSession(); | 41 virtual ~PepperPortAllocatorSession(); |
| 36 | 42 |
| 37 // cricket::HttpPortAllocatorBase overrides. | 43 // cricket::HttpPortAllocatorBase overrides. |
| 38 virtual void ConfigReady(cricket::PortConfiguration* config) OVERRIDE; | 44 virtual void ConfigReady(cricket::PortConfiguration* config) OVERRIDE; |
| 45 virtual void GetPortConfigurations() OVERRIDE; |
| 39 virtual void SendSessionRequest(const std::string& host, int port) OVERRIDE; | 46 virtual void SendSessionRequest(const std::string& host, int port) OVERRIDE; |
| 40 | 47 |
| 41 private: | 48 private: |
| 42 // Callback handlers for pp::URLLoader. | 49 // Callback handlers for Pepper APIs. |
| 50 static void HostResolverCallback(void* user_data, int32_t result); |
| 43 static void UrlLoaderOpenCallback(void* user_data, int32_t result); | 51 static void UrlLoaderOpenCallback(void* user_data, int32_t result); |
| 44 static void UrlLoaderReadCallback(void* user_data, int32_t result); | 52 static void UrlLoaderReadCallback(void* user_data, int32_t result); |
| 45 | 53 |
| 54 void ResolveStunServerAddress(); |
| 55 void OnStunAddressResolved(int32_t result); |
| 56 |
| 46 void OnUrlOpened(int32_t result); | 57 void OnUrlOpened(int32_t result); |
| 47 void ReadResponseBody(); | 58 void ReadResponseBody(); |
| 48 void OnResponseBodyRead(int32_t result); | 59 void OnResponseBodyRead(int32_t result); |
| 49 | 60 |
| 50 pp::InstanceHandle instance_; | 61 pp::InstanceHandle instance_; |
| 51 | 62 |
| 52 scoped_ptr<pp::URLLoader> url_loader_; | 63 pp::HostResolverPrivate stun_address_resolver_; |
| 53 std::vector<char> body_; | 64 talk_base::SocketAddress stun_address_; |
| 65 int stun_port_; |
| 66 |
| 67 scoped_ptr<pp::URLLoader> relay_url_loader_; |
| 68 std::vector<char> relay_response_body_; |
| 69 bool relay_response_received_; |
| 54 | 70 |
| 55 DISALLOW_COPY_AND_ASSIGN(PepperPortAllocatorSession); | 71 DISALLOW_COPY_AND_ASSIGN(PepperPortAllocatorSession); |
| 56 }; | 72 }; |
| 57 | 73 |
| 58 PepperPortAllocatorSession::PepperPortAllocatorSession( | 74 PepperPortAllocatorSession::PepperPortAllocatorSession( |
| 59 cricket::HttpPortAllocatorBase* allocator, | 75 cricket::HttpPortAllocatorBase* allocator, |
| 60 const std::string& channel_name, | 76 const std::string& channel_name, |
| 61 int component, | 77 int component, |
| 62 const std::vector<talk_base::SocketAddress>& stun_hosts, | 78 const std::vector<talk_base::SocketAddress>& stun_hosts, |
| 63 const std::vector<std::string>& relay_hosts, | 79 const std::vector<std::string>& relay_hosts, |
| 64 const std::string& relay, | 80 const std::string& relay_token, |
| 65 const pp::InstanceHandle& instance) | 81 const pp::InstanceHandle& instance) |
| 66 : HttpPortAllocatorSessionBase( | 82 : cricket::HttpPortAllocatorSessionBase( |
| 67 allocator, channel_name, component, stun_hosts, relay_hosts, relay, ""), | 83 allocator, channel_name, component, stun_hosts, |
| 68 instance_(instance) { | 84 relay_hosts, relay_token, ""), |
| 85 instance_(instance), |
| 86 stun_address_resolver_(instance_), |
| 87 stun_port_(0), |
| 88 relay_response_received_(false) { |
| 89 set_flags(cricket::PORTALLOCATOR_DISABLE_TCP); |
| 90 if (stun_hosts.size() > 0) { |
| 91 stun_address_ = stun_hosts[0]; |
| 92 } |
| 69 } | 93 } |
| 70 | 94 |
| 71 PepperPortAllocatorSession::~PepperPortAllocatorSession() { | 95 PepperPortAllocatorSession::~PepperPortAllocatorSession() { |
| 72 } | 96 } |
| 73 | 97 |
| 74 void PepperPortAllocatorSession::ConfigReady( | 98 void PepperPortAllocatorSession::ConfigReady( |
| 75 cricket::PortConfiguration* config) { | 99 cricket::PortConfiguration* config) { |
| 100 if (config->stun_address.IsUnresolved()) { |
| 101 // Make sure that the address that we pass to ConfigReady() is |
| 102 // always resolved. |
| 103 if (stun_address_.IsUnresolved()) { |
| 104 config->stun_address.Clear(); |
| 105 } else { |
| 106 config->stun_address = stun_address_; |
| 107 } |
| 108 } |
| 109 |
| 76 // Filter out non-UDP relay ports, so that we don't try using TCP. | 110 // Filter out non-UDP relay ports, so that we don't try using TCP. |
| 77 for (cricket::PortConfiguration::RelayList::iterator relay = | 111 for (cricket::PortConfiguration::RelayList::iterator relay = |
| 78 config->relays.begin(); relay != config->relays.end(); ++relay) { | 112 config->relays.begin(); relay != config->relays.end(); ++relay) { |
| 79 cricket::PortConfiguration::PortList filtered_ports; | 113 cricket::PortConfiguration::PortList filtered_ports; |
| 80 for (cricket::PortConfiguration::PortList::iterator port = | 114 for (cricket::PortConfiguration::PortList::iterator port = |
| 81 relay->ports.begin(); port != relay->ports.end(); ++port) { | 115 relay->ports.begin(); port != relay->ports.end(); ++port) { |
| 82 if (port->proto == cricket::PROTO_UDP) { | 116 if (port->proto == cricket::PROTO_UDP) { |
| 83 filtered_ports.push_back(*port); | 117 filtered_ports.push_back(*port); |
| 84 } | 118 } |
| 85 } | 119 } |
| 86 relay->ports = filtered_ports; | 120 relay->ports = filtered_ports; |
| 87 } | 121 } |
| 88 cricket::BasicPortAllocatorSession::ConfigReady(config); | 122 cricket::BasicPortAllocatorSession::ConfigReady(config); |
| 89 } | 123 } |
| 90 | 124 |
| 125 void PepperPortAllocatorSession::GetPortConfigurations() { |
| 126 // Add an empty configuration synchronously, so a local connection |
| 127 // can be started immediately. |
| 128 ConfigReady(new cricket::PortConfiguration(talk_base::SocketAddress())); |
| 129 |
| 130 ResolveStunServerAddress(); |
| 131 TryCreateRelaySession(); |
| 132 } |
| 133 |
| 134 void PepperPortAllocatorSession::ResolveStunServerAddress() { |
| 135 if (stun_address_.IsNil()) { |
| 136 return; |
| 137 } |
| 138 |
| 139 if (!stun_address_.IsUnresolved()) { |
| 140 return; |
| 141 } |
| 142 |
| 143 std::string hostname = stun_address_.hostname(); |
| 144 uint16 port = stun_address_.port(); |
| 145 |
| 146 PP_HostResolver_Private_Hint hint; |
| 147 hint.flags = 0; |
| 148 hint.family = PP_NETADDRESSFAMILY_IPV4; |
| 149 int result = stun_address_resolver_.Resolve( |
| 150 hostname, port, hint, pp::CompletionCallback( |
| 151 &PepperPortAllocatorSession::HostResolverCallback, this)); |
| 152 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 153 } |
| 154 |
| 155 void PepperPortAllocatorSession::OnStunAddressResolved(int32_t result) { |
| 156 if (result < 0) { |
| 157 LOG(ERROR) << "Failed to resolve stun address " |
| 158 << stun_address_.hostname() << ": " << result; |
| 159 return; |
| 160 } |
| 161 |
| 162 if (!stun_address_resolver_.GetSize()) { |
| 163 LOG(WARNING) << "Received 0 addresses for stun server " |
| 164 << stun_address_.hostname(); |
| 165 return; |
| 166 } |
| 167 |
| 168 PP_NetAddress_Private address; |
| 169 if (!stun_address_resolver_.GetNetAddress(0, &address) || |
| 170 !PpAddressToSocketAddress(address, &stun_address_)) { |
| 171 LOG(ERROR) << "Failed to get address for STUN server " |
| 172 << stun_address_.hostname(); |
| 173 return; |
| 174 } |
| 175 |
| 176 DCHECK(!stun_address_.IsUnresolved()); |
| 177 |
| 178 if (relay_response_received_) { |
| 179 // If we've finished reading the response, then resubmit it to |
| 180 // HttpPortAllocatorSessionBase. This is necessary because STUN |
| 181 // and Relay parameters are stored together in PortConfiguration |
| 182 // and ReceiveSessionResponse() doesn't save relay session |
| 183 // configuration for the case we resolve STUN address later. This |
| 184 // method invokes overriden ConfigReady() which then submits |
| 185 // resolved |stun_address_|. |
| 186 // |
| 187 // TODO(sergeyu): Refactor HttpPortAllocatorSessionBase to fix this. |
| 188 ReceiveSessionResponse(std::string(relay_response_body_.begin(), |
| 189 relay_response_body_.end())); |
| 190 } else { |
| 191 ConfigReady(new cricket::PortConfiguration(stun_address_)); |
| 192 } |
| 193 } |
| 194 |
| 91 void PepperPortAllocatorSession::SendSessionRequest( | 195 void PepperPortAllocatorSession::SendSessionRequest( |
| 92 const std::string& host, | 196 const std::string& host, |
| 93 int port) { | 197 int port) { |
| 94 url_loader_.reset(new pp::URLLoader(instance_)); | 198 relay_url_loader_.reset(new pp::URLLoader(instance_)); |
| 95 pp::URLRequestInfo request_info(instance_); | 199 pp::URLRequestInfo request_info(instance_); |
| 96 std::string url = "https://" + host + ":" + base::IntToString(port) + | 200 std::string url = "https://" + host + ":" + base::IntToString(port) + |
| 97 GetSessionRequestUrl() + "&sn=1"; | 201 GetSessionRequestUrl() + "&sn=1"; |
| 98 request_info.SetURL(url); | 202 request_info.SetURL(url); |
| 99 request_info.SetMethod("GET"); | 203 request_info.SetMethod("GET"); |
| 100 std::stringstream headers; | 204 std::stringstream headers; |
| 101 headers << "X-Talk-Google-Relay-Auth: " << relay_token() << "\n\r"; | 205 headers << "X-Talk-Google-Relay-Auth: " << relay_token() << "\n\r"; |
| 102 headers << "X-Google-Relay-Auth: " << relay_token() << "\n\r"; | 206 headers << "X-Google-Relay-Auth: " << relay_token() << "\n\r"; |
| 103 headers << "X-StreamType: " << channel_name() << "\n\r"; | 207 headers << "X-StreamType: " << channel_name() << "\n\r"; |
| 104 request_info.SetHeaders(headers.str()); | 208 request_info.SetHeaders(headers.str()); |
| 105 | 209 |
| 106 int result = url_loader_->Open(request_info, pp::CompletionCallback( | 210 int result = relay_url_loader_->Open(request_info, pp::CompletionCallback( |
| 107 &PepperPortAllocatorSession::UrlLoaderOpenCallback, this)); | 211 &PepperPortAllocatorSession::UrlLoaderOpenCallback, this)); |
| 108 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | 212 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 109 } | 213 } |
| 110 | 214 |
| 111 void PepperPortAllocatorSession::OnUrlOpened(int32_t result) { | 215 void PepperPortAllocatorSession::OnUrlOpened(int32_t result) { |
| 112 if (result == PP_ERROR_ABORTED) | 216 if (result == PP_ERROR_ABORTED) { |
| 113 return; | 217 return; |
| 218 } |
| 114 | 219 |
| 115 if (result < 0) { | 220 if (result < 0) { |
| 116 LOG(WARNING) << "URLLoader failed: " << result; | 221 LOG(WARNING) << "URLLoader failed: " << result; |
| 117 // Retry creating session. | 222 // Retry creating session. |
| 118 TryCreateRelaySession(); | 223 TryCreateRelaySession(); |
| 119 return; | 224 return; |
| 120 } | 225 } |
| 121 | 226 |
| 122 pp::URLResponseInfo response = url_loader_->GetResponseInfo(); | 227 pp::URLResponseInfo response = relay_url_loader_->GetResponseInfo(); |
| 123 DCHECK(!response.is_null()); | 228 DCHECK(!response.is_null()); |
| 124 if (response.GetStatusCode() != 200) { | 229 if (response.GetStatusCode() != 200) { |
| 125 LOG(WARNING) << "Received HTTP status code " << response.GetStatusCode(); | 230 LOG(WARNING) << "Received HTTP status code " << response.GetStatusCode(); |
| 126 // Retry creating session. | 231 // Retry creating session. |
| 127 TryCreateRelaySession(); | 232 TryCreateRelaySession(); |
| 128 return; | 233 return; |
| 129 } | 234 } |
| 130 | 235 |
| 131 body_.clear(); | 236 relay_response_body_.clear(); |
| 132 ReadResponseBody(); | 237 ReadResponseBody(); |
| 133 } | 238 } |
| 134 | 239 |
| 135 void PepperPortAllocatorSession::ReadResponseBody() { | 240 void PepperPortAllocatorSession::ReadResponseBody() { |
| 136 int pos = body_.size(); | 241 int pos = relay_response_body_.size(); |
| 137 body_.resize(pos + kReadSize); | 242 relay_response_body_.resize(pos + kReadSize); |
| 138 int result = url_loader_->ReadResponseBody( | 243 int result = relay_url_loader_->ReadResponseBody( |
| 139 &body_[pos], kReadSize, pp::CompletionCallback( | 244 &relay_response_body_[pos], kReadSize, pp::CompletionCallback( |
| 140 &PepperPortAllocatorSession::UrlLoaderReadCallback, this)); | 245 &PepperPortAllocatorSession::UrlLoaderReadCallback, this)); |
| 141 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | 246 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 142 } | 247 } |
| 143 | 248 |
| 144 void PepperPortAllocatorSession::OnResponseBodyRead(int32_t result) { | 249 void PepperPortAllocatorSession::OnResponseBodyRead(int32_t result) { |
| 145 if (result == PP_ERROR_ABORTED) | 250 if (result == PP_ERROR_ABORTED) { |
| 146 return; | 251 return; |
| 252 } |
| 147 | 253 |
| 148 if (result < 0) { | 254 if (result < 0) { |
| 149 LOG(WARNING) << "Failed to read HTTP response body when " | 255 LOG(WARNING) << "Failed to read HTTP response body when " |
| 150 "creating relay session: " << result; | 256 "creating relay session: " << result; |
| 151 // Retry creating session. | 257 // Retry creating session. |
| 152 TryCreateRelaySession(); | 258 TryCreateRelaySession(); |
| 153 return; | 259 return; |
| 154 } | 260 } |
| 155 | 261 |
| 156 // Resize the buffer in case we've read less than was requested. | 262 // Resize the buffer in case we've read less than was requested. |
| 157 CHECK_LE(result, kReadSize); | 263 CHECK_LE(result, kReadSize); |
| 158 CHECK_GE(static_cast<int>(body_.size()), kReadSize); | 264 CHECK_GE(static_cast<int>(relay_response_body_.size()), kReadSize); |
| 159 body_.resize(body_.size() - kReadSize + result); | 265 relay_response_body_.resize(relay_response_body_.size() - kReadSize + result); |
| 160 | 266 |
| 161 if (result == 0) { | 267 if (result == 0) { |
| 162 // Finished reading the response. | 268 relay_response_received_ = true; |
| 163 ReceiveSessionResponse(std::string(body_.begin(), body_.end())); | 269 ReceiveSessionResponse(std::string(relay_response_body_.begin(), |
| 270 relay_response_body_.end())); |
| 164 return; | 271 return; |
| 165 } | 272 } |
| 166 | 273 |
| 167 ReadResponseBody(); | 274 ReadResponseBody(); |
| 168 } | 275 } |
| 169 | 276 |
| 170 // static | 277 // static |
| 278 void PepperPortAllocatorSession::HostResolverCallback( |
| 279 void* user_data, |
| 280 int32_t result) { |
| 281 PepperPortAllocatorSession* object = |
| 282 static_cast<PepperPortAllocatorSession*>(user_data); |
| 283 object->OnStunAddressResolved(result); |
| 284 } |
| 285 |
| 286 // static |
| 171 void PepperPortAllocatorSession::UrlLoaderOpenCallback( | 287 void PepperPortAllocatorSession::UrlLoaderOpenCallback( |
| 172 void* user_data, | 288 void* user_data, |
| 173 int32_t result) { | 289 int32_t result) { |
| 174 PepperPortAllocatorSession* object = | 290 PepperPortAllocatorSession* object = |
| 175 static_cast<PepperPortAllocatorSession*>(user_data); | 291 static_cast<PepperPortAllocatorSession*>(user_data); |
| 176 object->OnUrlOpened(result); | 292 object->OnUrlOpened(result); |
| 177 } | 293 } |
| 178 | 294 |
| 179 // static | 295 // static |
| 180 void PepperPortAllocatorSession::UrlLoaderReadCallback( | 296 void PepperPortAllocatorSession::UrlLoaderReadCallback( |
| (...skipping 27 matching lines...) Expand all Loading... |
| 208 network_manager_(network_manager.Pass()), | 324 network_manager_(network_manager.Pass()), |
| 209 socket_factory_(socket_factory.Pass()) { | 325 socket_factory_(socket_factory.Pass()) { |
| 210 } | 326 } |
| 211 | 327 |
| 212 PepperPortAllocator::~PepperPortAllocator() { | 328 PepperPortAllocator::~PepperPortAllocator() { |
| 213 } | 329 } |
| 214 | 330 |
| 215 cricket::PortAllocatorSession* PepperPortAllocator::CreateSession( | 331 cricket::PortAllocatorSession* PepperPortAllocator::CreateSession( |
| 216 const std::string& channel_name, | 332 const std::string& channel_name, |
| 217 int component) { | 333 int component) { |
| 218 return new PepperPortAllocatorSession( | 334 return new PepperPortAllocatorSession( |
| 219 this, channel_name, component, stun_hosts(), | 335 this, channel_name, component, stun_hosts(), |
| 220 relay_hosts(), relay_token(), instance_); | 336 relay_hosts(), relay_token(), instance_); |
| 221 } | 337 } |
| 222 | 338 |
| 223 } // namespace remoting | 339 } // namespace remoting |
| OLD | NEW |