summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/notifier
diff options
context:
space:
mode:
authorzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-26 23:38:24 +0000
committerzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-26 23:38:24 +0000
commit7afe339b8b7906587ce4cfd218df4cffae89e18f (patch)
tree51184ce93deb6a5950d95d7ac17f2070b9f6da8d /chrome/browser/sync/notifier
parent5fcc3f7533d627cfe55dc44349b0e7f6d242f133 (diff)
downloadchromium_src-7afe339b8b7906587ce4cfd218df4cffae89e18f.zip
chromium_src-7afe339b8b7906587ce4cfd218df4cffae89e18f.tar.gz
chromium_src-7afe339b8b7906587ce4cfd218df4cffae89e18f.tar.bz2
Add SSL wrapper for linux and mac. This allows notifier to use chrome's SSL layer instead of OpenSSL.
BUG=none TEST=none Review URL: http://codereview.chromium.org/270074 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30123 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync/notifier')
-rwxr-xr-xchrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc348
-rwxr-xr-xchrome/browser/sync/notifier/communicator/ssl_socket_adapter.h127
-rw-r--r--chrome/browser/sync/notifier/communicator/xmpp_socket_adapter.cc16
3 files changed, 490 insertions, 1 deletions
diff --git a/chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc b/chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc
new file mode 100755
index 0000000..28acf08
--- /dev/null
+++ b/chrome/browser/sync/notifier/communicator/ssl_socket_adapter.cc
@@ -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
diff --git a/chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h b/chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h
new file mode 100755
index 0000000..f121e1b
--- /dev/null
+++ b/chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h
@@ -0,0 +1,127 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_COMMUNICATOR_SSL_SOCKET_ADAPTER_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_COMMUNICATOR_SSL_SOCKET_ADAPTER_H_
+
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/socket/client_socket.h"
+#include "net/socket/ssl_client_socket.h"
+#include "talk/base/asyncsocket.h"
+
+namespace notifier {
+
+class SSLSocketAdapter;
+
+// This class provides a wrapper to libjingle's talk_base::AsyncSocket that
+// implements Chromium's net::ClientSocket interface. It's used by
+// SSLSocketAdapter to enable Chromium's SSL implementation to work over
+// libjingle's socket class.
+class TransportSocket : public net::ClientSocket, public sigslot::has_slots<> {
+ public:
+ TransportSocket(talk_base::AsyncSocket* socket,
+ SSLSocketAdapter *ssl_adapter);
+
+ void set_addr(const talk_base::SocketAddress& addr) {
+ addr_ = addr;
+ }
+
+ // net::ClientSocket implementation
+
+ virtual int Connect(net::CompletionCallback* callback);
+ virtual void Disconnect();
+ virtual bool IsConnected() const;
+ virtual bool IsConnectedAndIdle() const;
+
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+ virtual int GetPeerName(struct sockaddr *name, socklen_t *namelen);
+#endif
+
+ // net::Socket implementation
+
+ virtual int Read(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback);
+ virtual int Write(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback);
+ virtual bool SetReceiveBufferSize(int32 size);
+ virtual bool SetSendBufferSize(int32 size);
+
+ private:
+ void OnConnectEvent(talk_base::AsyncSocket * socket);
+ void OnReadEvent(talk_base::AsyncSocket * socket);
+ void OnWriteEvent(talk_base::AsyncSocket * socket);
+ void OnCloseEvent(talk_base::AsyncSocket * socket, int err);
+
+ net::CompletionCallback* connect_callback_;
+ net::CompletionCallback* read_callback_;
+ net::CompletionCallback* write_callback_;
+
+ scoped_refptr<net::IOBuffer> read_buffer_;
+ int read_buffer_len_;
+ scoped_refptr<net::IOBuffer> write_buffer_;
+ int write_buffer_len_;
+
+ talk_base::AsyncSocket *socket_;
+ talk_base::SocketAddress addr_;
+ SSLSocketAdapter *ssl_adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransportSocket);
+};
+
+// This provides a talk_base::AsyncSocketAdapter interface around Chromium's
+// net::SSLClientSocket class. This allows notifier to use Chromium's SSL
+// implementation instead of OpenSSL.
+class SSLSocketAdapter : public talk_base::AsyncSocketAdapter {
+ public:
+ explicit SSLSocketAdapter(talk_base::AsyncSocket* socket);
+
+ bool ignore_bad_cert() const { return ignore_bad_cert_; }
+ void set_ignore_bad_cert(bool ignore) { ignore_bad_cert_ = ignore; }
+
+ // StartSSL returns 0 if successful, or non-zero on failure.
+ // If StartSSL is called while the socket is closed or connecting, the SSL
+ // negotiation will begin as soon as the socket connects.
+ //
+ // restartable is not implemented, and must be set to false.
+ virtual int StartSSL(const char* hostname, bool restartable);
+
+ // Create the default SSL adapter for this platform.
+ static SSLSocketAdapter* Create(AsyncSocket* socket);
+
+ virtual int Send(const void* pv, size_t cb);
+ virtual int Recv(void* pv, size_t cb);
+
+ private:
+ friend class TransportSocket;
+
+ enum State {
+ STATE_NONE,
+ STATE_READ,
+ STATE_READ_COMPLETE,
+ STATE_WRITE,
+ STATE_WRITE_COMPLETE
+ };
+
+ void OnConnected(int result);
+ void OnIO(int result);
+
+ bool ignore_bad_cert_;
+ scoped_ptr<TransportSocket> socket_;
+ scoped_ptr<net::SSLClientSocket> ssl_socket_;
+ net::CompletionCallbackImpl<SSLSocketAdapter> connected_callback_;
+ net::CompletionCallbackImpl<SSLSocketAdapter> io_callback_;
+ bool ssl_connected_;
+ State state_;
+ scoped_refptr<net::IOBuffer> transport_buf_;
+ int data_transferred_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLSocketAdapter);
+};
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_COMMUNICATOR_SSL_SOCKET_ADAPTER_H_
diff --git a/chrome/browser/sync/notifier/communicator/xmpp_socket_adapter.cc b/chrome/browser/sync/notifier/communicator/xmpp_socket_adapter.cc
index 03c1977..b7a3602 100644
--- a/chrome/browser/sync/notifier/communicator/xmpp_socket_adapter.cc
+++ b/chrome/browser/sync/notifier/communicator/xmpp_socket_adapter.cc
@@ -9,12 +9,17 @@
#include "base/logging.h"
#include "chrome/browser/sync/notifier/communicator/product_info.h"
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+#include "chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h"
+#endif
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
#include "talk/base/firewallsocketserver.h"
#include "talk/base/logging.h"
#include "talk/base/socketadapters.h"
+#if defined(OS_WIN)
#include "talk/base/ssladapter.h"
+#endif
#include "talk/xmpp/xmppengine.h"
namespace notifier {
@@ -132,7 +137,11 @@ bool XmppSocketAdapter::Connect(const talk_base::SocketAddress& addr) {
}
#if defined(FEATURE_ENABLE_SSL)
+#if defined(OS_WIN)
talk_base::SSLAdapter* ssl = talk_base::SSLAdapter::Create(socket);
+#else
+ notifier::SSLSocketAdapter* ssl = notifier::SSLSocketAdapter::Create(socket);
+#endif
socket = ssl;
#endif
@@ -320,8 +329,13 @@ bool XmppSocketAdapter::StartTls(const std::string& verify_host_name) {
ASSERT(write_buffer_length_ == 0);
+#if defined(OS_WIN)
talk_base::SSLAdapter* ssl_adapter =
- static_cast<talk_base::SSLAdapter*>(socket_);
+ static_cast<talk_base::SSLAdapter*>(socket_);
+#else
+ notifier::SSLSocketAdapter* ssl_adapter =
+ static_cast<notifier::SSLSocketAdapter*>(socket_);
+#endif
if (allow_unverified_certs_) {
ssl_adapter->set_ignore_bad_cert(true);