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