| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/jingle_glue/ssl_socket_adapter.h" | |
| 6 | |
| 7 #include "base/compiler_specific.h" | |
| 8 #include "base/message_loop.h" | |
| 9 #include "net/base/address_list.h" | |
| 10 #include "net/base/net_errors.h" | |
| 11 #include "net/base/ssl_config_service.h" | |
| 12 #include "net/base/sys_addrinfo.h" | |
| 13 #include "net/socket/client_socket_factory.h" | |
| 14 #include "net/url_request/url_request_context.h" | |
| 15 | |
| 16 namespace remoting { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Convert values from <errno.h> to values from "net/base/net_errors.h" | |
| 21 int MapPosixError(int err) { | |
| 22 // There are numerous posix error codes, but these are the ones we thus far | |
| 23 // find interesting. | |
| 24 switch (err) { | |
| 25 case EAGAIN: | |
| 26 #if EWOULDBLOCK != EAGAIN | |
| 27 case EWOULDBLOCK: | |
| 28 #endif | |
| 29 return net::ERR_IO_PENDING; | |
| 30 case ENETDOWN: | |
| 31 return net::ERR_INTERNET_DISCONNECTED; | |
| 32 case ETIMEDOUT: | |
| 33 return net::ERR_TIMED_OUT; | |
| 34 case ECONNRESET: | |
| 35 case ENETRESET: // Related to keep-alive | |
| 36 return net::ERR_CONNECTION_RESET; | |
| 37 case ECONNABORTED: | |
| 38 return net::ERR_CONNECTION_ABORTED; | |
| 39 case ECONNREFUSED: | |
| 40 return net::ERR_CONNECTION_REFUSED; | |
| 41 case EHOSTUNREACH: | |
| 42 case ENETUNREACH: | |
| 43 return net::ERR_ADDRESS_UNREACHABLE; | |
| 44 case EADDRNOTAVAIL: | |
| 45 return net::ERR_ADDRESS_INVALID; | |
| 46 case 0: | |
| 47 return net::OK; | |
| 48 default: | |
| 49 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | |
| 50 return net::ERR_FAILED; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) { | |
| 57 return new SSLSocketAdapter(socket); | |
| 58 } | |
| 59 | |
| 60 SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket) | |
| 61 : SSLAdapter(socket), | |
| 62 ignore_bad_cert_(false), | |
| 63 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 64 connected_callback_(this, &SSLSocketAdapter::OnConnected)), | |
| 65 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 66 read_callback_(this, &SSLSocketAdapter::OnRead)), | |
| 67 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 68 write_callback_(this, &SSLSocketAdapter::OnWrite)), | |
| 69 ssl_state_(SSLSTATE_NONE), | |
| 70 read_state_(IOSTATE_NONE), | |
| 71 write_state_(IOSTATE_NONE) { | |
| 72 transport_socket_ = new TransportSocket(socket, this); | |
| 73 } | |
| 74 | |
| 75 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { | |
| 76 DCHECK(!restartable); | |
| 77 hostname_ = hostname; | |
| 78 | |
| 79 if (socket_->GetState() != Socket::CS_CONNECTED) { | |
| 80 ssl_state_ = SSLSTATE_WAIT; | |
| 81 return 0; | |
| 82 } else { | |
| 83 return BeginSSL(); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 int SSLSocketAdapter::BeginSSL() { | |
| 88 if (!MessageLoop::current()) { | |
| 89 // Certificate verification is done via the Chrome message loop. | |
| 90 // Without this check, if we don't have a chrome message loop the | |
| 91 // SSL connection just hangs silently. | |
| 92 LOG(DFATAL) << "Chrome message loop (needed by SSL certificate " | |
| 93 << "verification) does not exist"; | |
| 94 return net::ERR_UNEXPECTED; | |
| 95 } | |
| 96 | |
| 97 // SSLConfigService is not thread-safe, and the default values for SSLConfig | |
| 98 // are correct for us, so we don't use the config service to initialize this | |
| 99 // object. | |
| 100 net::SSLConfig ssl_config; | |
| 101 transport_socket_->set_addr(talk_base::SocketAddress(hostname_, 0)); | |
| 102 ssl_socket_.reset( | |
| 103 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( | |
| 104 transport_socket_, hostname_.c_str(), ssl_config)); | |
| 105 | |
| 106 int result = ssl_socket_->Connect(&connected_callback_); | |
| 107 | |
| 108 if (result == net::ERR_IO_PENDING || result == net::OK) { | |
| 109 return 0; | |
| 110 } else { | |
| 111 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result); | |
| 112 return result; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 int SSLSocketAdapter::Send(const void* buf, size_t len) { | |
| 117 if (ssl_state_ != SSLSTATE_CONNECTED) { | |
| 118 return AsyncSocketAdapter::Send(buf, len); | |
| 119 } else { | |
| 120 scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len); | |
| 121 memcpy(transport_buf->data(), buf, len); | |
| 122 | |
| 123 int result = ssl_socket_->Write(transport_buf, len, NULL); | |
| 124 if (result == net::ERR_IO_PENDING) { | |
| 125 SetError(EWOULDBLOCK); | |
| 126 } | |
| 127 transport_buf = NULL; | |
| 128 return result; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 int SSLSocketAdapter::Recv(void* buf, size_t len) { | |
| 133 switch (ssl_state_) { | |
| 134 case SSLSTATE_NONE: | |
| 135 return AsyncSocketAdapter::Recv(buf, len); | |
| 136 | |
| 137 case SSLSTATE_WAIT: | |
| 138 SetError(EWOULDBLOCK); | |
| 139 return -1; | |
| 140 | |
| 141 case SSLSTATE_CONNECTED: | |
| 142 switch (read_state_) { | |
| 143 case IOSTATE_NONE: { | |
| 144 transport_buf_ = new net::IOBuffer(len); | |
| 145 int result = ssl_socket_->Read(transport_buf_, len, &read_callback_); | |
| 146 if (result >= 0) { | |
| 147 memcpy(buf, transport_buf_->data(), len); | |
| 148 } | |
| 149 | |
| 150 if (result == net::ERR_IO_PENDING) { | |
| 151 read_state_ = IOSTATE_PENDING; | |
| 152 SetError(EWOULDBLOCK); | |
| 153 } else { | |
| 154 if (result < 0) { | |
| 155 SetError(result); | |
| 156 LOG(INFO) << "Socket error " << result; | |
| 157 } | |
| 158 transport_buf_ = NULL; | |
| 159 } | |
| 160 return result; | |
| 161 } | |
| 162 case IOSTATE_PENDING: | |
| 163 SetError(EWOULDBLOCK); | |
| 164 return -1; | |
| 165 | |
| 166 case IOSTATE_COMPLETE: | |
| 167 memcpy(buf, transport_buf_->data(), len); | |
| 168 transport_buf_ = NULL; | |
| 169 read_state_ = IOSTATE_NONE; | |
| 170 return data_transferred_; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 NOTREACHED(); | |
| 175 return -1; | |
| 176 } | |
| 177 | |
| 178 void SSLSocketAdapter::OnConnected(int result) { | |
| 179 if (result == net::OK) { | |
| 180 ssl_state_ = SSLSTATE_CONNECTED; | |
| 181 OnConnectEvent(this); | |
| 182 } else { | |
| 183 LOG(WARNING) << "OnConnected failed with error " << result; | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 void SSLSocketAdapter::OnRead(int result) { | |
| 188 DCHECK(read_state_ == IOSTATE_PENDING); | |
| 189 read_state_ = IOSTATE_COMPLETE; | |
| 190 data_transferred_ = result; | |
| 191 AsyncSocketAdapter::OnReadEvent(this); | |
| 192 } | |
| 193 | |
| 194 void SSLSocketAdapter::OnWrite(int result) { | |
| 195 DCHECK(write_state_ == IOSTATE_PENDING); | |
| 196 write_state_ = IOSTATE_COMPLETE; | |
| 197 data_transferred_ = result; | |
| 198 AsyncSocketAdapter::OnWriteEvent(this); | |
| 199 } | |
| 200 | |
| 201 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) { | |
| 202 if (ssl_state_ != SSLSTATE_WAIT) { | |
| 203 AsyncSocketAdapter::OnConnectEvent(socket); | |
| 204 } else { | |
| 205 ssl_state_ = SSLSTATE_NONE; | |
| 206 int result = BeginSSL(); | |
| 207 if (0 != result) { | |
| 208 // TODO(zork): Handle this case gracefully. | |
| 209 LOG(WARNING) << "BeginSSL() failed with " << result; | |
| 210 } | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 TransportSocket::TransportSocket(talk_base::AsyncSocket* socket, | |
| 215 SSLSocketAdapter *ssl_adapter) | |
| 216 : read_callback_(NULL), | |
| 217 write_callback_(NULL), | |
| 218 read_buffer_len_(0), | |
| 219 write_buffer_len_(0), | |
| 220 socket_(socket) { | |
| 221 socket_->SignalReadEvent.connect(this, &TransportSocket::OnReadEvent); | |
| 222 socket_->SignalWriteEvent.connect(this, &TransportSocket::OnWriteEvent); | |
| 223 } | |
| 224 | |
| 225 int TransportSocket::Connect(net::CompletionCallback* callback) { | |
| 226 // Connect is never called by SSLClientSocket, instead SSLSocketAdapter | |
| 227 // calls Connect() on socket_ directly. | |
| 228 NOTREACHED(); | |
| 229 return false; | |
| 230 } | |
| 231 | |
| 232 void TransportSocket::Disconnect() { | |
| 233 socket_->Close(); | |
| 234 } | |
| 235 | |
| 236 bool TransportSocket::IsConnected() const { | |
| 237 return (socket_->GetState() == talk_base::Socket::CS_CONNECTED); | |
| 238 } | |
| 239 | |
| 240 bool TransportSocket::IsConnectedAndIdle() const { | |
| 241 // Not implemented. | |
| 242 NOTREACHED(); | |
| 243 return false; | |
| 244 } | |
| 245 | |
| 246 int TransportSocket::GetPeerAddress(net::AddressList* address) const { | |
| 247 talk_base::SocketAddress socket_address = socket_->GetRemoteAddress(); | |
| 248 | |
| 249 // libjingle supports only IPv4 addresses. | |
| 250 sockaddr_in ipv4addr; | |
| 251 socket_address.ToSockAddr(&ipv4addr); | |
| 252 | |
| 253 struct addrinfo ai; | |
| 254 memset(&ai, 0, sizeof(ai)); | |
| 255 ai.ai_family = ipv4addr.sin_family; | |
| 256 ai.ai_socktype = SOCK_STREAM; | |
| 257 ai.ai_protocol = IPPROTO_TCP; | |
| 258 ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr); | |
| 259 ai.ai_addrlen = sizeof(ipv4addr); | |
| 260 | |
| 261 address->Copy(&ai, false); | |
| 262 return net::OK; | |
| 263 } | |
| 264 | |
| 265 int TransportSocket::Read(net::IOBuffer* buf, int buf_len, | |
| 266 net::CompletionCallback* callback) { | |
| 267 DCHECK(buf); | |
| 268 DCHECK(!read_callback_); | |
| 269 DCHECK(!read_buffer_.get()); | |
| 270 int result = socket_->Recv(buf->data(), buf_len); | |
| 271 if (result < 0) { | |
| 272 result = MapPosixError(socket_->GetError()); | |
| 273 if (result == net::ERR_IO_PENDING) { | |
| 274 read_callback_ = callback; | |
| 275 read_buffer_ = buf; | |
| 276 read_buffer_len_ = buf_len; | |
| 277 } | |
| 278 } | |
| 279 return result; | |
| 280 } | |
| 281 | |
| 282 int TransportSocket::Write(net::IOBuffer* buf, int buf_len, | |
| 283 net::CompletionCallback* callback) { | |
| 284 DCHECK(buf); | |
| 285 DCHECK(!write_callback_); | |
| 286 DCHECK(!write_buffer_.get()); | |
| 287 int result = socket_->Send(buf->data(), buf_len); | |
| 288 if (result < 0) { | |
| 289 result = MapPosixError(socket_->GetError()); | |
| 290 if (result == net::ERR_IO_PENDING) { | |
| 291 write_callback_ = callback; | |
| 292 write_buffer_ = buf; | |
| 293 write_buffer_len_ = buf_len; | |
| 294 } | |
| 295 } | |
| 296 return result; | |
| 297 } | |
| 298 | |
| 299 bool TransportSocket::SetReceiveBufferSize(int32 size) { | |
| 300 // Not implemented. | |
| 301 return false; | |
| 302 } | |
| 303 | |
| 304 bool TransportSocket::SetSendBufferSize(int32 size) { | |
| 305 // Not implemented. | |
| 306 return false; | |
| 307 } | |
| 308 | |
| 309 void TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) { | |
| 310 if (read_callback_) { | |
| 311 DCHECK(read_buffer_.get()); | |
| 312 net::CompletionCallback* callback = read_callback_; | |
| 313 scoped_refptr<net::IOBuffer> buffer = read_buffer_; | |
| 314 int buffer_len = read_buffer_len_; | |
| 315 | |
| 316 read_callback_ = NULL; | |
| 317 read_buffer_ = NULL; | |
| 318 read_buffer_len_ = 0; | |
| 319 | |
| 320 int result = socket_->Recv(buffer->data(), buffer_len); | |
| 321 if (result < 0) { | |
| 322 result = MapPosixError(socket_->GetError()); | |
| 323 if (result == net::ERR_IO_PENDING) { | |
| 324 read_callback_ = callback; | |
| 325 read_buffer_ = buffer; | |
| 326 read_buffer_len_ = buffer_len; | |
| 327 return; | |
| 328 } | |
| 329 } | |
| 330 callback->RunWithParams(Tuple1<int>(result)); | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) { | |
| 335 if (write_callback_) { | |
| 336 DCHECK(write_buffer_.get()); | |
| 337 net::CompletionCallback* callback = write_callback_; | |
| 338 scoped_refptr<net::IOBuffer> buffer = write_buffer_; | |
| 339 int buffer_len = write_buffer_len_; | |
| 340 | |
| 341 write_callback_ = NULL; | |
| 342 write_buffer_ = NULL; | |
| 343 write_buffer_len_ = 0; | |
| 344 | |
| 345 int result = socket_->Send(buffer->data(), buffer_len); | |
| 346 if (result < 0) { | |
| 347 result = MapPosixError(socket_->GetError()); | |
| 348 if (result == net::ERR_IO_PENDING) { | |
| 349 write_callback_ = callback; | |
| 350 write_buffer_ = buffer; | |
| 351 write_buffer_len_ = buffer_len; | |
| 352 return; | |
| 353 } | |
| 354 } | |
| 355 callback->RunWithParams(Tuple1<int>(result)); | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 } // namespace remoting | |
| OLD | NEW |