Index: chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc |
=================================================================== |
--- chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc (revision 0) |
+++ chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc (revision 0) |
@@ -0,0 +1,348 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h" |
+ |
+#include "base/compiler_specific.h" |
+#include "chrome/browser/net/url_request_context_getter.h" |
+#include "chrome/browser/profile.h" |
+#include "net/base/ssl_config_service.h" |
+#include "net/socket/client_socket_factory.h" |
+#include "net/url_request/url_request_context.h" |
+ |
+namespace notifier { |
+ |
+namespace { |
+ |
+// Convert values from <errno.h> to values from "net/base/net_errors.h" |
+int MapPosixError(int err) { |
+ // There are numerous posix error codes, but these are the ones we thus far |
+ // find interesting. |
+ switch (err) { |
+ case EAGAIN: |
+#if EWOULDBLOCK != EAGAIN |
+ case EWOULDBLOCK: |
+#endif |
+ return net::ERR_IO_PENDING; |
+ case ENETDOWN: |
+ return net::ERR_INTERNET_DISCONNECTED; |
+ case ETIMEDOUT: |
+ return net::ERR_TIMED_OUT; |
+ case ECONNRESET: |
+ case ENETRESET: // Related to keep-alive |
+ return net::ERR_CONNECTION_RESET; |
+ case ECONNABORTED: |
+ return net::ERR_CONNECTION_ABORTED; |
+ case ECONNREFUSED: |
+ return net::ERR_CONNECTION_REFUSED; |
+ case EHOSTUNREACH: |
+ case ENETUNREACH: |
+ return net::ERR_ADDRESS_UNREACHABLE; |
+ case EADDRNOTAVAIL: |
+ return net::ERR_ADDRESS_INVALID; |
+ case 0: |
+ return net::OK; |
+ default: |
+ LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; |
+ return net::ERR_FAILED; |
+ } |
+} |
+ |
+} |
+ |
+SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) { |
+ return new SSLSocketAdapter(socket); |
+} |
+ |
+SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket) |
+ : AsyncSocketAdapter(socket), |
+ ignore_bad_cert_(false), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ connected_callback_(this, &SSLSocketAdapter::OnConnected)), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ io_callback_(this, &SSLSocketAdapter::OnIO)), |
+ ssl_connected_(false), |
+ state_(STATE_NONE) { |
+ socket_.reset(new TransportSocket(socket, this)); |
+} |
+ |
+int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { |
+ DCHECK(!restartable); |
+ |
+ // SSLConfigService is not thread-safe, and the default values for SSLConfig |
+ // are correct for us, so we don't use the config service to initialize this |
+ // object. |
+ net::SSLConfig ssl_config; |
+ socket_->set_addr(talk_base::SocketAddress(hostname)); |
+ ssl_socket_.reset( |
+ net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( |
+ socket_.release(), hostname, ssl_config)); |
+ |
+ int result = ssl_socket_->Connect(&connected_callback_); |
+ |
+ if (result == net::ERR_IO_PENDING || result == net::OK) { |
+ return 0; |
+ } else { |
+ return result; |
+ } |
+} |
+ |
+int SSLSocketAdapter::Send(const void* buf, size_t len) { |
+ if (!ssl_connected_) { |
+ return AsyncSocketAdapter::Send(buf, len); |
+ } |
+ |
+ switch (state_) { |
+ case STATE_NONE: { |
+ transport_buf_ = new net::IOBuffer(len); |
+ memcpy(transport_buf_->data(), buf, len); |
+ |
+ int result = ssl_socket_->Write(transport_buf_, len, &io_callback_); |
+ if (result == net::ERR_IO_PENDING) { |
+ state_ = STATE_WRITE; |
+ SetError(EWOULDBLOCK); |
+ } else { |
+ transport_buf_ = NULL; |
+ } |
+ return result; |
+ } |
+ case STATE_WRITE_COMPLETE: |
+ transport_buf_ = NULL; |
+ state_ = STATE_NONE; |
+ return data_transferred_; |
+ |
+ case STATE_READ: |
+ case STATE_READ_COMPLETE: |
+ case STATE_WRITE: |
+ SetError(EWOULDBLOCK); |
+ return -1; |
+ |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return -1; |
+} |
+ |
+int SSLSocketAdapter::Recv(void* buf, size_t len) { |
+ if (!ssl_connected_) { |
+ return AsyncSocketAdapter::Recv(buf, len); |
+ } |
+ |
+ switch (state_) { |
+ case STATE_NONE: { |
+ transport_buf_ = new net::IOBuffer(len); |
+ int result = ssl_socket_->Read(transport_buf_, len, &io_callback_); |
+ if (result >= 0) { |
+ memcpy(buf, transport_buf_->data(), len); |
+ } |
+ |
+ if (result == net::ERR_IO_PENDING) { |
+ state_ = STATE_READ; |
+ SetError(EWOULDBLOCK); |
+ } else { |
+ transport_buf_ = NULL; |
+ } |
+ return result; |
+ } |
+ case STATE_READ_COMPLETE: |
+ memcpy(buf, transport_buf_->data(), len); |
+ transport_buf_ = NULL; |
+ state_ = STATE_NONE; |
+ return data_transferred_; |
+ |
+ case STATE_READ: |
+ case STATE_WRITE: |
+ case STATE_WRITE_COMPLETE: |
+ SetError(EWOULDBLOCK); |
+ return -1; |
+ |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return -1; |
+} |
+ |
+void SSLSocketAdapter::OnConnected(int result) { |
+ if (result == net::OK) { |
+ ssl_connected_ = true; |
+ OnConnectEvent(this); |
+ } |
+} |
+ |
+void SSLSocketAdapter::OnIO(int result) { |
+ switch (state_) { |
+ case STATE_READ: |
+ state_ = STATE_READ_COMPLETE; |
+ data_transferred_ = result; |
+ break; |
+ case STATE_WRITE: |
+ state_ = STATE_WRITE_COMPLETE; |
+ data_transferred_ = result; |
+ break; |
+ case STATE_NONE: |
+ case STATE_READ_COMPLETE: |
+ case STATE_WRITE_COMPLETE: |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
+TransportSocket::TransportSocket(talk_base::AsyncSocket* socket, |
+ SSLSocketAdapter *ssl_adapter) |
+ : connect_callback_(NULL), |
+ read_callback_(NULL), |
+ write_callback_(NULL), |
+ read_buffer_len_(0), |
+ write_buffer_len_(0), |
+ socket_(socket), |
+ ssl_adapter_(ssl_adapter) { |
+ socket_->SignalConnectEvent.connect(this, &TransportSocket::OnConnectEvent); |
+ socket_->SignalReadEvent.connect(this, &TransportSocket::OnReadEvent); |
+ socket_->SignalWriteEvent.connect(this, &TransportSocket::OnWriteEvent); |
+ socket_->SignalCloseEvent.connect(this, &TransportSocket::OnCloseEvent); |
+} |
+ |
+int TransportSocket::Connect(net::CompletionCallback* callback) { |
+ connect_callback_ = callback; |
+ return socket_->Connect(addr_); |
+} |
+ |
+void TransportSocket::Disconnect() { |
+ socket_->Close(); |
+} |
+ |
+bool TransportSocket::IsConnected() const { |
+ return (socket_->GetState() == talk_base::Socket::CS_CONNECTED); |
+} |
+ |
+bool TransportSocket::IsConnectedAndIdle() const { |
+ // Not implemented. |
+ NOTREACHED(); |
+ return false; |
+} |
+ |
+#if defined(OS_LINUX) || defined(OS_MACOSX) |
+int TransportSocket::GetPeerName(struct sockaddr *name, socklen_t *namelen) { |
+ talk_base::SocketAddress address = socket_->GetRemoteAddress(); |
+ address.ToSockAddr(reinterpret_cast<sockaddr_in *>(name)); |
+ return 0; |
+} |
+#endif |
+ |
+int TransportSocket::Read(net::IOBuffer* buf, int buf_len, |
+ net::CompletionCallback* callback) { |
+ DCHECK(buf); |
+ DCHECK(!read_callback_); |
+ DCHECK(!read_buffer_.get()); |
+ int result = socket_->Recv(buf->data(), buf_len); |
+ if (result < 0) { |
+ result = MapPosixError(socket_->GetError()); |
+ if (result == net::ERR_IO_PENDING) { |
+ read_callback_ = callback; |
+ read_buffer_ = buf; |
+ read_buffer_len_ = buf_len; |
+ } |
+ } |
+ return result; |
+} |
+ |
+int TransportSocket::Write(net::IOBuffer* buf, int buf_len, |
+ net::CompletionCallback* callback) { |
+ DCHECK(buf); |
+ DCHECK(!write_callback_); |
+ DCHECK(!write_buffer_.get()); |
+ int result = socket_->Send(buf->data(), buf_len); |
+ if (result < 0) { |
+ result = MapPosixError(socket_->GetError()); |
+ if (result == net::ERR_IO_PENDING) { |
+ write_callback_ = callback; |
+ write_buffer_ = buf; |
+ write_buffer_len_ = buf_len; |
+ } |
+ } |
+ return result; |
+} |
+ |
+bool TransportSocket::SetReceiveBufferSize(int32 size) { |
+ // Not implemented. |
+ return false; |
+} |
+ |
+bool TransportSocket::SetSendBufferSize(int32 size) { |
+ // Not implemented. |
+ return false; |
+} |
+ |
+void TransportSocket::OnConnectEvent(talk_base::AsyncSocket * socket) { |
+ if (connect_callback_) { |
+ net::CompletionCallback *callback = connect_callback_; |
+ connect_callback_ = NULL; |
+ callback->RunWithParams(Tuple1<int>(MapPosixError(socket_->GetError()))); |
+ } else { |
+ ssl_adapter_->OnConnectEvent(socket); |
+ } |
+} |
+ |
+void TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) { |
+ if (read_callback_) { |
+ DCHECK(read_buffer_.get()); |
+ net::CompletionCallback* callback = read_callback_; |
+ scoped_refptr<net::IOBuffer> buffer = read_buffer_; |
+ int buffer_len = read_buffer_len_; |
+ |
+ read_callback_ = NULL; |
+ read_buffer_ = NULL; |
+ read_buffer_len_ = 0; |
+ |
+ int result = socket_->Recv(buffer->data(), buffer_len); |
+ if (result < 0) { |
+ result = MapPosixError(socket_->GetError()); |
+ if (result == net::ERR_IO_PENDING) { |
+ read_callback_ = callback; |
+ read_buffer_ = buffer; |
+ read_buffer_len_ = buffer_len; |
+ return; |
+ } |
+ } |
+ callback->RunWithParams(Tuple1<int>(result)); |
+ } else { |
+ ssl_adapter_->OnReadEvent(socket); |
+ } |
+} |
+ |
+void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) { |
+ if (write_callback_) { |
+ DCHECK(write_buffer_.get()); |
+ net::CompletionCallback* callback = write_callback_; |
+ scoped_refptr<net::IOBuffer> buffer = write_buffer_; |
+ int buffer_len = write_buffer_len_; |
+ |
+ write_callback_ = NULL; |
+ write_buffer_ = NULL; |
+ write_buffer_len_ = 0; |
+ |
+ int result = socket_->Send(buffer->data(), buffer_len); |
+ if (result < 0) { |
+ result = MapPosixError(socket_->GetError()); |
+ if (result == net::ERR_IO_PENDING) { |
+ write_callback_ = callback; |
+ write_buffer_ = buffer; |
+ write_buffer_len_ = buffer_len; |
+ return; |
+ } |
+ } |
+ callback->RunWithParams(Tuple1<int>(result)); |
+ } else { |
+ ssl_adapter_->OnWriteEvent(socket); |
+ } |
+} |
+ |
+void TransportSocket::OnCloseEvent(talk_base::AsyncSocket* socket, int err) { |
+ ssl_adapter_->OnCloseEvent(socket, err); |
+} |
+ |
+} // namespace notifier |
Property changes on: chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc |
___________________________________________________________________ |
Added: svn:executable |
+ * |
Added: svn:eol-style |
+ LF |