| // Copyright (c) 2012 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. |
| // |
| // An implementation of buzz::AsyncSocket that uses Chrome sockets. |
| |
| #ifndef JINGLE_GLUE_CHROME_ASYNC_SOCKET_H_ |
| #define JINGLE_GLUE_CHROME_ASYNC_SOCKET_H_ |
| |
| #if !defined(FEATURE_ENABLE_SSL) |
| #error ChromeAsyncSocket expects FEATURE_ENABLE_SSL to be defined |
| #endif |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/basictypes.h" |
| #include "base/compiler_specific.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "net/base/completion_callback.h" |
| #include "net/base/net_errors.h" |
| #include "third_party/webrtc/libjingle/xmpp/asyncsocket.h" |
| |
| namespace net { |
| class IOBufferWithSize; |
| class StreamSocket; |
| } // namespace net |
| |
| namespace jingle_glue { |
| |
| class ResolvingClientSocketFactory; |
| |
| class ChromeAsyncSocket : public buzz::AsyncSocket { |
| public: |
| // Takes ownership of |resolving_client_socket_factory|. |
| ChromeAsyncSocket( |
| ResolvingClientSocketFactory* resolving_client_socket_factory, |
| size_t read_buf_size, |
| size_t write_buf_size); |
| |
| // Does not raise any signals. |
| ~ChromeAsyncSocket() override; |
| |
| // buzz::AsyncSocket implementation. |
| |
| // The current state (see buzz::AsyncSocket::State; all but |
| // STATE_CLOSING is used). |
| State state() override; |
| |
| // The last generated error. Errors are generated when the main |
| // functions below return false or when SignalClosed is raised due |
| // to an asynchronous error. |
| Error error() override; |
| |
| // GetError() (which is of type net::Error) != net::OK only when |
| // error() == ERROR_WINSOCK. |
| int GetError() override; |
| |
| // Tries to connect to the given address. |
| // |
| // If state() is not STATE_CLOSED, sets error to ERROR_WRONGSTATE |
| // and returns false. |
| // |
| // If |address| has an empty hostname or a zero port, sets error to |
| // ERROR_DNS and returns false. (We don't use the IP address even |
| // if it's present, as DNS resolution is done by |
| // |resolving_client_socket_factory_|. But it's perfectly fine if |
| // the hostname is a stringified IP address.) |
| // |
| // Otherwise, starts the connection process and returns true. |
| // SignalConnected will be raised when the connection is successful; |
| // otherwise, SignalClosed will be raised with a net error set. |
| bool Connect(const rtc::SocketAddress& address) override; |
| |
| // Tries to read at most |len| bytes into |data|. |
| // |
| // If state() is not STATE_TLS_CONNECTING, STATE_OPEN, or |
| // STATE_TLS_OPEN, sets error to ERROR_WRONGSTATE and returns false. |
| // |
| // Otherwise, fills in |len_read| with the number of bytes read and |
| // returns true. If this is called when state() is |
| // STATE_TLS_CONNECTING, reads 0 bytes. (We have to handle this |
| // case because StartTls() is called during a slot connected to |
| // SignalRead after parsing the final non-TLS reply from the server |
| // [see XmppClient::Private::OnSocketRead()].) |
| bool Read(char* data, size_t len, size_t* len_read) override; |
| |
| // Queues up |len| bytes of |data| for writing. |
| // |
| // If state() is not STATE_TLS_CONNECTING, STATE_OPEN, or |
| // STATE_TLS_OPEN, sets error to ERROR_WRONGSTATE and returns false. |
| // |
| // If the given data is too big for the internal write buffer, sets |
| // error to ERROR_WINSOCK/net::ERR_INSUFFICIENT_RESOURCES and |
| // returns false. |
| // |
| // Otherwise, queues up the data and returns true. If this is |
| // called when state() == STATE_TLS_CONNECTING, the data is will be |
| // sent only after the TLS connection succeeds. (See StartTls() |
| // below for why this happens.) |
| // |
| // Note that there's no guarantee that the data will actually be |
| // sent; however, it is guaranteed that the any data sent will be |
| // sent in FIFO order. |
| bool Write(const char* data, size_t len) override; |
| |
| // If the socket is not already closed, closes the socket and raises |
| // SignalClosed. Always returns true. |
| bool Close() override; |
| |
| // Tries to change to a TLS connection with the given domain name. |
| // |
| // If state() is not STATE_OPEN or there are pending reads or |
| // writes, sets error to ERROR_WRONGSTATE and returns false. (In |
| // practice, this means that StartTls() can only be called from a |
| // slot connected to SignalRead.) |
| // |
| // Otherwise, starts the TLS connection process and returns true. |
| // SignalSSLConnected will be raised when the connection is |
| // successful; otherwise, SignalClosed will be raised with a net |
| // error set. |
| bool StartTls(const std::string& domain_name) override; |
| |
| // Signal behavior: |
| // |
| // SignalConnected: raised whenever the connect initiated by a call |
| // to Connect() is complete. |
| // |
| // SignalSSLConnected: raised whenever the connect initiated by a |
| // call to StartTls() is complete. Not actually used by |
| // XmppClient. (It just assumes that if SignalRead is raised after a |
| // call to StartTls(), the connection has been successfully |
| // upgraded.) |
| // |
| // SignalClosed: raised whenever the socket is closed, either due to |
| // an asynchronous error, the other side closing the connection, or |
| // when Close() is called. |
| // |
| // SignalRead: raised whenever the next call to Read() will succeed |
| // with a non-zero |len_read| (assuming nothing else happens in the |
| // meantime). |
| // |
| // SignalError: not used. |
| |
| private: |
| enum AsyncIOState { |
| // An I/O op is not in progress. |
| IDLE, |
| // A function has been posted to do the I/O. |
| POSTED, |
| // An async I/O operation is pending. |
| PENDING, |
| }; |
| |
| bool IsOpen() const; |
| |
| // Error functions. |
| void DoNonNetError(Error error); |
| void DoNetError(net::Error net_error); |
| void DoNetErrorFromStatus(int status); |
| |
| // Connection functions. |
| void ProcessConnectDone(int status); |
| |
| // Read loop functions. |
| void PostDoRead(); |
| void DoRead(); |
| void ProcessReadDone(int status); |
| |
| // Write loop functions. |
| void PostDoWrite(); |
| void DoWrite(); |
| void ProcessWriteDone(int status); |
| |
| // SSL/TLS connection functions. |
| void ProcessSSLConnectDone(int status); |
| |
| // Close functions. |
| void DoClose(); |
| |
| scoped_ptr<ResolvingClientSocketFactory> resolving_client_socket_factory_; |
| |
| // buzz::AsyncSocket state. |
| buzz::AsyncSocket::State state_; |
| buzz::AsyncSocket::Error error_; |
| net::Error net_error_; |
| |
| // NULL iff state() == STATE_CLOSED. |
| scoped_ptr<net::StreamSocket> transport_socket_; |
| |
| // State for the read loop. |read_start_| <= |read_end_| <= |
| // |read_buf_->size()|. There's a read in flight (i.e., |
| // |read_state_| != IDLE) iff |read_end_| == 0. |
| AsyncIOState read_state_; |
| scoped_refptr<net::IOBufferWithSize> read_buf_; |
| size_t read_start_, read_end_; |
| |
| // State for the write loop. |write_end_| <= |write_buf_->size()|. |
| // There's a write in flight (i.e., |write_state_| != IDLE) iff |
| // |write_end_| > 0. |
| AsyncIOState write_state_; |
| scoped_refptr<net::IOBufferWithSize> write_buf_; |
| size_t write_end_; |
| |
| base::WeakPtrFactory<ChromeAsyncSocket> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ChromeAsyncSocket); |
| }; |
| |
| } // namespace jingle_glue |
| |
| #endif // JINGLE_GLUE_CHROME_ASYNC_SOCKET_H_ |