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 |