| 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 "chrome/browser/sync/notifier/communicator/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 notifier { | |
| 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 io_callback_(this, &SSLSocketAdapter::OnIO)), | |
| 67 ssl_connected_(false), | |
| 68 state_(STATE_NONE) { | |
| 69 transport_socket_ = new TransportSocket(socket, this); | |
| 70 } | |
| 71 | |
| 72 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { | |
| 73 DCHECK(!restartable); | |
| 74 hostname_ = hostname; | |
| 75 | |
| 76 if (socket_->GetState() != Socket::CS_CONNECTED) { | |
| 77 state_ = STATE_SSL_WAIT; | |
| 78 return 0; | |
| 79 } else { | |
| 80 return BeginSSL(); | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 int SSLSocketAdapter::BeginSSL() { | |
| 85 if (!MessageLoop::current()) { | |
| 86 // Certificate verification is done via the Chrome message loop. | |
| 87 // Without this check, if we don't have a chrome message loop the | |
| 88 // SSL connection just hangs silently. | |
| 89 LOG(DFATAL) << "Chrome message loop (needed by SSL certificate " | |
| 90 << "verification) does not exist"; | |
| 91 return net::ERR_UNEXPECTED; | |
| 92 } | |
| 93 | |
| 94 // SSLConfigService is not thread-safe, and the default values for SSLConfig | |
| 95 // are correct for us, so we don't use the config service to initialize this | |
| 96 // object. | |
| 97 net::SSLConfig ssl_config; | |
| 98 transport_socket_->set_addr(talk_base::SocketAddress(hostname_.c_str())); | |
| 99 ssl_socket_.reset( | |
| 100 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( | |
| 101 transport_socket_, hostname_.c_str(), ssl_config)); | |
| 102 | |
| 103 int result = ssl_socket_->Connect(&connected_callback_); | |
| 104 | |
| 105 if (result == net::ERR_IO_PENDING || result == net::OK) { | |
| 106 return 0; | |
| 107 } else { | |
| 108 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result); | |
| 109 return result; | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 int SSLSocketAdapter::Send(const void* buf, size_t len) { | |
| 114 if (!ssl_connected_) { | |
| 115 return AsyncSocketAdapter::Send(buf, len); | |
| 116 } else { | |
| 117 scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len); | |
| 118 memcpy(transport_buf->data(), buf, len); | |
| 119 | |
| 120 int result = ssl_socket_->Write(transport_buf, len, NULL); | |
| 121 if (result == net::ERR_IO_PENDING) { | |
| 122 SetError(EWOULDBLOCK); | |
| 123 } | |
| 124 transport_buf = NULL; | |
| 125 return result; | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 int SSLSocketAdapter::Recv(void* buf, size_t len) { | |
| 130 if (!ssl_connected_) { | |
| 131 return AsyncSocketAdapter::Recv(buf, len); | |
| 132 } | |
| 133 | |
| 134 switch (state_) { | |
| 135 case STATE_NONE: { | |
| 136 transport_buf_ = new net::IOBuffer(len); | |
| 137 int result = ssl_socket_->Read(transport_buf_, len, &io_callback_); | |
| 138 if (result >= 0) { | |
| 139 memcpy(buf, transport_buf_->data(), len); | |
| 140 } | |
| 141 | |
| 142 if (result == net::ERR_IO_PENDING) { | |
| 143 state_ = STATE_READ; | |
| 144 SetError(EWOULDBLOCK); | |
| 145 } else { | |
| 146 if (result < 0) { | |
| 147 SetError(result); | |
| 148 LOG(INFO) << "Socket error " << result; | |
| 149 } | |
| 150 transport_buf_ = NULL; | |
| 151 } | |
| 152 return result; | |
| 153 } | |
| 154 case STATE_READ_COMPLETE: | |
| 155 memcpy(buf, transport_buf_->data(), len); | |
| 156 transport_buf_ = NULL; | |
| 157 state_ = STATE_NONE; | |
| 158 return data_transferred_; | |
| 159 | |
| 160 case STATE_READ: | |
| 161 case STATE_WRITE: | |
| 162 case STATE_WRITE_COMPLETE: | |
| 163 case STATE_SSL_WAIT: | |
| 164 SetError(EWOULDBLOCK); | |
| 165 return -1; | |
| 166 | |
| 167 default: | |
| 168 NOTREACHED(); | |
| 169 break; | |
| 170 } | |
| 171 return -1; | |
| 172 } | |
| 173 | |
| 174 void SSLSocketAdapter::OnConnected(int result) { | |
| 175 if (result == net::OK) { | |
| 176 ssl_connected_ = true; | |
| 177 OnConnectEvent(this); | |
| 178 } else { | |
| 179 LOG(WARNING) << "OnConnected failed with error " << result; | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 void SSLSocketAdapter::OnIO(int result) { | |
| 184 switch (state_) { | |
| 185 case STATE_READ: | |
| 186 state_ = STATE_READ_COMPLETE; | |
| 187 data_transferred_ = result; | |
| 188 AsyncSocketAdapter::OnReadEvent(this); | |
| 189 break; | |
| 190 case STATE_WRITE: | |
| 191 state_ = STATE_WRITE_COMPLETE; | |
| 192 data_transferred_ = result; | |
| 193 AsyncSocketAdapter::OnWriteEvent(this); | |
| 194 break; | |
| 195 case STATE_NONE: | |
| 196 case STATE_READ_COMPLETE: | |
| 197 case STATE_WRITE_COMPLETE: | |
| 198 case STATE_SSL_WAIT: | |
| 199 default: | |
| 200 NOTREACHED(); | |
| 201 break; | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void SSLSocketAdapter::OnReadEvent(talk_base::AsyncSocket* socket) { | |
| 206 if (!transport_socket_->OnReadEvent(socket)) | |
| 207 AsyncSocketAdapter::OnReadEvent(socket); | |
| 208 } | |
| 209 | |
| 210 void SSLSocketAdapter::OnWriteEvent(talk_base::AsyncSocket* socket) { | |
| 211 if (!transport_socket_->OnWriteEvent(socket)) | |
| 212 AsyncSocketAdapter::OnWriteEvent(socket); | |
| 213 } | |
| 214 | |
| 215 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) { | |
| 216 if (state_ != STATE_SSL_WAIT) { | |
| 217 AsyncSocketAdapter::OnConnectEvent(socket); | |
| 218 } else { | |
| 219 state_ = STATE_NONE; | |
| 220 int result = BeginSSL(); | |
| 221 if (0 != result) { | |
| 222 // TODO(zork): Handle this case gracefully. | |
| 223 LOG(WARNING) << "BeginSSL() failed with " << result; | |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 TransportSocket::TransportSocket(talk_base::AsyncSocket* socket, | |
| 229 SSLSocketAdapter *ssl_adapter) | |
| 230 : connect_callback_(NULL), | |
| 231 read_callback_(NULL), | |
| 232 write_callback_(NULL), | |
| 233 read_buffer_len_(0), | |
| 234 write_buffer_len_(0), | |
| 235 socket_(socket) { | |
| 236 socket_->SignalConnectEvent.connect(this, &TransportSocket::OnConnectEvent); | |
| 237 } | |
| 238 | |
| 239 int TransportSocket::Connect(net::CompletionCallback* callback) { | |
| 240 connect_callback_ = callback; | |
| 241 return socket_->Connect(addr_); | |
| 242 } | |
| 243 | |
| 244 void TransportSocket::Disconnect() { | |
| 245 socket_->Close(); | |
| 246 } | |
| 247 | |
| 248 bool TransportSocket::IsConnected() const { | |
| 249 return (socket_->GetState() == talk_base::Socket::CS_CONNECTED); | |
| 250 } | |
| 251 | |
| 252 bool TransportSocket::IsConnectedAndIdle() const { | |
| 253 // Not implemented. | |
| 254 NOTREACHED(); | |
| 255 return false; | |
| 256 } | |
| 257 | |
| 258 int TransportSocket::GetPeerAddress(net::AddressList* address) const { | |
| 259 talk_base::SocketAddress socket_address = socket_->GetRemoteAddress(); | |
| 260 | |
| 261 // libjingle supports only IPv4 addresses. | |
| 262 sockaddr_in ipv4addr; | |
| 263 socket_address.ToSockAddr(&ipv4addr); | |
| 264 | |
| 265 struct addrinfo ai; | |
| 266 memset(&ai, 0, sizeof(ai)); | |
| 267 ai.ai_family = ipv4addr.sin_family; | |
| 268 ai.ai_socktype = SOCK_STREAM; | |
| 269 ai.ai_protocol = IPPROTO_TCP; | |
| 270 ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr); | |
| 271 ai.ai_addrlen = sizeof(ipv4addr); | |
| 272 | |
| 273 address->Copy(&ai, false); | |
| 274 return net::OK; | |
| 275 } | |
| 276 | |
| 277 int TransportSocket::Read(net::IOBuffer* buf, int buf_len, | |
| 278 net::CompletionCallback* callback) { | |
| 279 DCHECK(buf); | |
| 280 DCHECK(!read_callback_); | |
| 281 DCHECK(!read_buffer_.get()); | |
| 282 int result = socket_->Recv(buf->data(), buf_len); | |
| 283 if (result < 0) { | |
| 284 result = MapPosixError(socket_->GetError()); | |
| 285 if (result == net::ERR_IO_PENDING) { | |
| 286 read_callback_ = callback; | |
| 287 read_buffer_ = buf; | |
| 288 read_buffer_len_ = buf_len; | |
| 289 } | |
| 290 } | |
| 291 return result; | |
| 292 } | |
| 293 | |
| 294 int TransportSocket::Write(net::IOBuffer* buf, int buf_len, | |
| 295 net::CompletionCallback* callback) { | |
| 296 DCHECK(buf); | |
| 297 DCHECK(!write_callback_); | |
| 298 DCHECK(!write_buffer_.get()); | |
| 299 int result = socket_->Send(buf->data(), buf_len); | |
| 300 if (result < 0) { | |
| 301 result = MapPosixError(socket_->GetError()); | |
| 302 if (result == net::ERR_IO_PENDING) { | |
| 303 write_callback_ = callback; | |
| 304 write_buffer_ = buf; | |
| 305 write_buffer_len_ = buf_len; | |
| 306 } | |
| 307 } | |
| 308 return result; | |
| 309 } | |
| 310 | |
| 311 bool TransportSocket::SetReceiveBufferSize(int32 size) { | |
| 312 // Not implemented. | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 bool TransportSocket::SetSendBufferSize(int32 size) { | |
| 317 // Not implemented. | |
| 318 return false; | |
| 319 } | |
| 320 | |
| 321 void TransportSocket::OnConnectEvent(talk_base::AsyncSocket * socket) { | |
| 322 if (connect_callback_) { | |
| 323 net::CompletionCallback *callback = connect_callback_; | |
| 324 connect_callback_ = NULL; | |
| 325 callback->RunWithParams(Tuple1<int>(MapPosixError(socket_->GetError()))); | |
| 326 } else { | |
| 327 LOG(WARNING) << "OnConnectEvent called with no callback."; | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 bool TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) { | |
| 332 if (read_callback_) { | |
| 333 DCHECK(read_buffer_.get()); | |
| 334 net::CompletionCallback* callback = read_callback_; | |
| 335 scoped_refptr<net::IOBuffer> buffer = read_buffer_; | |
| 336 int buffer_len = read_buffer_len_; | |
| 337 | |
| 338 read_callback_ = NULL; | |
| 339 read_buffer_ = NULL; | |
| 340 read_buffer_len_ = 0; | |
| 341 | |
| 342 int result = socket_->Recv(buffer->data(), buffer_len); | |
| 343 if (result < 0) { | |
| 344 result = MapPosixError(socket_->GetError()); | |
| 345 if (result == net::ERR_IO_PENDING) { | |
| 346 read_callback_ = callback; | |
| 347 read_buffer_ = buffer; | |
| 348 read_buffer_len_ = buffer_len; | |
| 349 return true; | |
| 350 } | |
| 351 } | |
| 352 callback->RunWithParams(Tuple1<int>(result)); | |
| 353 return true; | |
| 354 } else { | |
| 355 LOG(WARNING) << "OnReadEvent called with no callback."; | |
| 356 return false; | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 bool TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) { | |
| 361 if (write_callback_) { | |
| 362 DCHECK(write_buffer_.get()); | |
| 363 net::CompletionCallback* callback = write_callback_; | |
| 364 scoped_refptr<net::IOBuffer> buffer = write_buffer_; | |
| 365 int buffer_len = write_buffer_len_; | |
| 366 | |
| 367 write_callback_ = NULL; | |
| 368 write_buffer_ = NULL; | |
| 369 write_buffer_len_ = 0; | |
| 370 | |
| 371 int result = socket_->Send(buffer->data(), buffer_len); | |
| 372 if (result < 0) { | |
| 373 result = MapPosixError(socket_->GetError()); | |
| 374 if (result == net::ERR_IO_PENDING) { | |
| 375 write_callback_ = callback; | |
| 376 write_buffer_ = buffer; | |
| 377 write_buffer_len_ = buffer_len; | |
| 378 return true; | |
| 379 } | |
| 380 } | |
| 381 callback->RunWithParams(Tuple1<int>(result)); | |
| 382 return true; | |
| 383 } else { | |
| 384 LOG(WARNING) << "OnWriteEvent called with no callback."; | |
| 385 return false; | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 } // namespace notifier | |
| OLD | NEW |