| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 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 "remoting/protocol/pepper_stream_channel.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "crypto/hmac.h" |
| 9 #include "jingle/glue/utils.h" |
| 10 #include "net/base/cert_status_flags.h" |
| 11 #include "net/base/cert_verifier.h" |
| 12 #include "net/base/host_port_pair.h" |
| 13 #include "net/base/ssl_config_service.h" |
| 14 #include "net/socket/ssl_client_socket.h" |
| 15 #include "net/socket/client_socket_factory.h" |
| 16 #include "ppapi/c/pp_errors.h" |
| 17 #include "ppapi/cpp/dev/transport_dev.h" |
| 18 #include "ppapi/cpp/var.h" |
| 19 #include "remoting/protocol/channel_authenticator.h" |
| 20 #include "remoting/protocol/pepper_session.h" |
| 21 #include "remoting/protocol/transport_config.h" |
| 22 #include "third_party/libjingle/source/talk/p2p/base/candidate.h" |
| 23 |
| 24 namespace remoting { |
| 25 namespace protocol { |
| 26 |
| 27 namespace { |
| 28 |
| 29 // Value is choosen to balance the extra latency against the reduced |
| 30 // load due to ACK traffic. |
| 31 const int kTcpAckDelayMilliseconds = 10; |
| 32 |
| 33 // Values for the TCP send and receive buffer size. This should be tuned to |
| 34 // accomodate high latency network but not backlog the decoding pipeline. |
| 35 const int kTcpReceiveBufferSize = 256 * 1024; |
| 36 const int kTcpSendBufferSize = kTcpReceiveBufferSize + 30 * 1024; |
| 37 |
| 38 // Helper method to create a SSL client socket. |
| 39 net::SSLClientSocket* CreateSSLClientSocket( |
| 40 net::StreamSocket* socket, const std::string& der_cert, |
| 41 net::CertVerifier* cert_verifier) { |
| 42 net::SSLConfig ssl_config; |
| 43 |
| 44 // Certificate provided by the host doesn't need authority. |
| 45 net::SSLConfig::CertAndStatus cert_and_status; |
| 46 cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID; |
| 47 cert_and_status.der_cert = der_cert; |
| 48 ssl_config.allowed_bad_certs.push_back(cert_and_status); |
| 49 |
| 50 // Revocation checking is not needed because we use self-signed |
| 51 // certs. Disable it so that SSL layer doesn't try to initialize |
| 52 // OCSP (OCSP works only on IO thread). |
| 53 ssl_config.rev_checking_enabled = false; |
| 54 |
| 55 // SSLClientSocket takes ownership of the |socket|. |
| 56 net::HostPortPair host_and_port("chromoting", 0); |
| 57 net::SSLClientSocketContext context; |
| 58 context.cert_verifier = cert_verifier; |
| 59 net::SSLClientSocket* ssl_socket = |
| 60 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( |
| 61 socket, host_and_port, ssl_config, NULL, context); |
| 62 return ssl_socket; |
| 63 } |
| 64 |
| 65 } // namespace |
| 66 |
| 67 PepperStreamChannel::PepperStreamChannel( |
| 68 PepperSession* session, |
| 69 const std::string& name, |
| 70 const Session::StreamChannelCallback& callback) |
| 71 : session_(session), |
| 72 name_(name), |
| 73 callback_(callback), |
| 74 channel_(NULL), |
| 75 connected_(false), |
| 76 ssl_client_socket_(NULL), |
| 77 ALLOW_THIS_IN_INITIALIZER_LIST(p2p_connect_callback_( |
| 78 this, &PepperStreamChannel::OnP2PConnect)), |
| 79 ALLOW_THIS_IN_INITIALIZER_LIST(ssl_connect_callback_( |
| 80 this, &PepperStreamChannel::OnSSLConnect)) { |
| 81 } |
| 82 |
| 83 PepperStreamChannel::~PepperStreamChannel() { |
| 84 // Verify that the |channel_| is ether destroyed or we own it. |
| 85 DCHECK_EQ(channel_, owned_channel_.get()); |
| 86 // Channel should be already destroyed if we were connected. |
| 87 DCHECK(!connected_ || channel_ == NULL); |
| 88 } |
| 89 |
| 90 void PepperStreamChannel::Connect(pp::Instance* pp_instance, |
| 91 const TransportConfig& transport_config, |
| 92 const std::string& remote_cert) { |
| 93 DCHECK(CalledOnValidThread()); |
| 94 |
| 95 remote_cert_ = remote_cert; |
| 96 |
| 97 pp::Transport_Dev* transport = |
| 98 new pp::Transport_Dev(pp_instance, name_.c_str(), "tcp"); |
| 99 |
| 100 if (transport->SetProperty(PP_TRANSPORTPROPERTY_TCP_RECEIVE_WINDOW, |
| 101 pp::Var(kTcpReceiveBufferSize)) != PP_OK) { |
| 102 LOG(ERROR) << "Failed to set TCP receive window"; |
| 103 } |
| 104 if (transport->SetProperty(PP_TRANSPORTPROPERTY_TCP_SEND_WINDOW, |
| 105 pp::Var(kTcpSendBufferSize)) != PP_OK) { |
| 106 LOG(ERROR) << "Failed to set TCP send window"; |
| 107 } |
| 108 |
| 109 if (transport->SetProperty(PP_TRANSPORTPROPERTY_TCP_NO_DELAY, |
| 110 pp::Var(true)) != PP_OK) { |
| 111 LOG(ERROR) << "Failed to set TCP_NODELAY"; |
| 112 } |
| 113 |
| 114 if (transport->SetProperty(PP_TRANSPORTPROPERTY_TCP_ACK_DELAY, |
| 115 pp::Var(kTcpAckDelayMilliseconds)) != PP_OK) { |
| 116 LOG(ERROR) << "Failed to set TCP ACK delay."; |
| 117 } |
| 118 |
| 119 if (transport_config.nat_traversal) { |
| 120 if (transport->SetProperty( |
| 121 PP_TRANSPORTPROPERTY_STUN_SERVER, |
| 122 pp::Var(transport_config.stun_server)) != PP_OK) { |
| 123 LOG(ERROR) << "Failed to set STUN server."; |
| 124 } |
| 125 |
| 126 if (transport->SetProperty( |
| 127 PP_TRANSPORTPROPERTY_RELAY_SERVER, |
| 128 pp::Var(transport_config.relay_server)) != PP_OK) { |
| 129 LOG(ERROR) << "Failed to set Relay server."; |
| 130 } |
| 131 |
| 132 if (transport->SetProperty( |
| 133 PP_TRANSPORTPROPERTY_RELAY_TOKEN, |
| 134 pp::Var(transport_config.relay_token)) != PP_OK) { |
| 135 LOG(ERROR) << "Failed to set Relay token."; |
| 136 } |
| 137 } |
| 138 |
| 139 channel_ = new PepperTransportSocketAdapter(transport, name_, this); |
| 140 owned_channel_.reset(channel_); |
| 141 |
| 142 int result = channel_->Connect(&p2p_connect_callback_); |
| 143 if (result != net::ERR_IO_PENDING) |
| 144 OnP2PConnect(result); |
| 145 } |
| 146 |
| 147 void PepperStreamChannel::AddRemoveCandidate( |
| 148 const cricket::Candidate& candidate) { |
| 149 DCHECK(CalledOnValidThread()); |
| 150 if (channel_) |
| 151 channel_->AddRemoteCandidate(jingle_glue::SerializeP2PCandidate(candidate)); |
| 152 } |
| 153 |
| 154 const std::string& PepperStreamChannel::name() { |
| 155 DCHECK(CalledOnValidThread()); |
| 156 return name_; |
| 157 } |
| 158 |
| 159 void PepperStreamChannel::OnChannelDeleted() { |
| 160 if (connected_) { |
| 161 channel_ = NULL; |
| 162 // The PepperTransportSocketAdapter is being deleted, so delete the |
| 163 // channel too. |
| 164 session_->OnDeleteChannel(this); |
| 165 delete this; |
| 166 } |
| 167 } |
| 168 |
| 169 void PepperStreamChannel::OnChannelNewLocalCandidate( |
| 170 const std::string& candidate) { |
| 171 DCHECK(CalledOnValidThread()); |
| 172 |
| 173 cricket::Candidate candidate_value; |
| 174 if (!jingle_glue::DeserializeP2PCandidate(candidate, &candidate_value)) { |
| 175 LOG(ERROR) << "Failed to parse candidate " << candidate; |
| 176 } |
| 177 session_->AddLocalCandidate(candidate_value); |
| 178 } |
| 179 |
| 180 void PepperStreamChannel::OnP2PConnect(int result) { |
| 181 DCHECK(CalledOnValidThread()); |
| 182 |
| 183 if (result != net::OK || !EstablishSSLConnection()) |
| 184 NotifyConnectFailed(); |
| 185 } |
| 186 |
| 187 bool PepperStreamChannel::EstablishSSLConnection() { |
| 188 DCHECK(CalledOnValidThread()); |
| 189 |
| 190 cert_verifier_.reset(new net::CertVerifier()); |
| 191 |
| 192 // Create client SSL socket. |
| 193 ssl_client_socket_ = CreateSSLClientSocket( |
| 194 owned_channel_.release(), remote_cert_, cert_verifier_.get()); |
| 195 socket_.reset(ssl_client_socket_); |
| 196 |
| 197 int result = ssl_client_socket_->Connect(&ssl_connect_callback_); |
| 198 |
| 199 if (result == net::ERR_IO_PENDING) { |
| 200 return true; |
| 201 } else if (result != net::OK) { |
| 202 LOG(ERROR) << "Failed to establish SSL connection"; |
| 203 return false; |
| 204 } |
| 205 |
| 206 // Reach here if net::OK is received. |
| 207 ssl_connect_callback_.Run(net::OK); |
| 208 return true; |
| 209 } |
| 210 |
| 211 void PepperStreamChannel::OnSSLConnect(int result) { |
| 212 DCHECK(CalledOnValidThread()); |
| 213 |
| 214 if (result != net::OK) { |
| 215 LOG(ERROR) << "Error during SSL connection: " << result; |
| 216 NotifyConnectFailed(); |
| 217 return; |
| 218 } |
| 219 |
| 220 DCHECK(socket_->IsConnected()); |
| 221 AuthenticateChannel(); |
| 222 } |
| 223 |
| 224 void PepperStreamChannel::AuthenticateChannel() { |
| 225 DCHECK(CalledOnValidThread()); |
| 226 |
| 227 authenticator_.reset(new ClientChannelAuthenticator(ssl_client_socket_)); |
| 228 authenticator_->Authenticate( |
| 229 session_->shared_secret(), |
| 230 base::Bind(&PepperStreamChannel::OnAuthenticationDone, |
| 231 base::Unretained(this))); |
| 232 } |
| 233 |
| 234 void PepperStreamChannel::OnAuthenticationDone( |
| 235 ChannelAuthenticator::Result result) { |
| 236 DCHECK(CalledOnValidThread()); |
| 237 |
| 238 switch (result) { |
| 239 case ChannelAuthenticator::SUCCESS: |
| 240 NotifyConnected(socket_.release()); |
| 241 break; |
| 242 |
| 243 case ChannelAuthenticator::FAILURE: |
| 244 NotifyConnectFailed(); |
| 245 break; |
| 246 } |
| 247 } |
| 248 |
| 249 void PepperStreamChannel::NotifyConnected(net::StreamSocket* socket) { |
| 250 DCHECK(!connected_); |
| 251 callback_.Run(socket); |
| 252 connected_ = true; |
| 253 } |
| 254 |
| 255 void PepperStreamChannel::NotifyConnectFailed() { |
| 256 channel_ = NULL; |
| 257 owned_channel_.reset(); |
| 258 socket_.reset(); |
| 259 |
| 260 NotifyConnected(NULL); |
| 261 } |
| 262 |
| 263 } // namespace protocol |
| 264 } // namespace remoting |
| OLD | NEW |