1/* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "xmppsocket.h" 29 30#ifdef HAVE_CONFIG_H 31#include <config.h> 32#endif 33 34#include <errno.h> 35#include "webrtc/base/basicdefs.h" 36#include "webrtc/base/logging.h" 37#include "webrtc/base/thread.h" 38#ifdef FEATURE_ENABLE_SSL 39#include "webrtc/base/ssladapter.h" 40#endif 41 42#ifdef USE_SSLSTREAM 43#include "webrtc/base/socketstream.h" 44#ifdef FEATURE_ENABLE_SSL 45#include "webrtc/base/sslstreamadapter.h" 46#endif // FEATURE_ENABLE_SSL 47#endif // USE_SSLSTREAM 48 49namespace buzz { 50 51XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL), 52 tls_(tls) { 53 state_ = buzz::AsyncSocket::STATE_CLOSED; 54} 55 56void XmppSocket::CreateCricketSocket(int family) { 57 rtc::Thread* pth = rtc::Thread::Current(); 58 if (family == AF_UNSPEC) { 59 family = AF_INET; 60 } 61 rtc::AsyncSocket* socket = 62 pth->socketserver()->CreateAsyncSocket(family, SOCK_STREAM); 63#ifndef USE_SSLSTREAM 64#ifdef FEATURE_ENABLE_SSL 65 if (tls_ != buzz::TLS_DISABLED) { 66 socket = rtc::SSLAdapter::Create(socket); 67 } 68#endif // FEATURE_ENABLE_SSL 69 cricket_socket_ = socket; 70 cricket_socket_->SignalReadEvent.connect(this, &XmppSocket::OnReadEvent); 71 cricket_socket_->SignalWriteEvent.connect(this, &XmppSocket::OnWriteEvent); 72 cricket_socket_->SignalConnectEvent.connect(this, 73 &XmppSocket::OnConnectEvent); 74 cricket_socket_->SignalCloseEvent.connect(this, &XmppSocket::OnCloseEvent); 75#else // USE_SSLSTREAM 76 cricket_socket_ = socket; 77 stream_ = new rtc::SocketStream(cricket_socket_); 78#ifdef FEATURE_ENABLE_SSL 79 if (tls_ != buzz::TLS_DISABLED) 80 stream_ = rtc::SSLStreamAdapter::Create(stream_); 81#endif // FEATURE_ENABLE_SSL 82 stream_->SignalEvent.connect(this, &XmppSocket::OnEvent); 83#endif // USE_SSLSTREAM 84} 85 86XmppSocket::~XmppSocket() { 87 Close(); 88#ifndef USE_SSLSTREAM 89 delete cricket_socket_; 90#else // USE_SSLSTREAM 91 delete stream_; 92#endif // USE_SSLSTREAM 93} 94 95#ifndef USE_SSLSTREAM 96void XmppSocket::OnReadEvent(rtc::AsyncSocket * socket) { 97 SignalRead(); 98} 99 100void XmppSocket::OnWriteEvent(rtc::AsyncSocket * socket) { 101 // Write bytes if there are any 102 while (buffer_.Length() != 0) { 103 int written = cricket_socket_->Send(buffer_.Data(), buffer_.Length()); 104 if (written > 0) { 105 buffer_.Consume(written); 106 continue; 107 } 108 if (!cricket_socket_->IsBlocking()) 109 LOG(LS_ERROR) << "Send error: " << cricket_socket_->GetError(); 110 return; 111 } 112} 113 114void XmppSocket::OnConnectEvent(rtc::AsyncSocket * socket) { 115#if defined(FEATURE_ENABLE_SSL) 116 if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) { 117 state_ = buzz::AsyncSocket::STATE_TLS_OPEN; 118 SignalSSLConnected(); 119 OnWriteEvent(cricket_socket_); 120 return; 121 } 122#endif // !defined(FEATURE_ENABLE_SSL) 123 state_ = buzz::AsyncSocket::STATE_OPEN; 124 SignalConnected(); 125} 126 127void XmppSocket::OnCloseEvent(rtc::AsyncSocket * socket, int error) { 128 SignalCloseEvent(error); 129} 130 131#else // USE_SSLSTREAM 132 133void XmppSocket::OnEvent(rtc::StreamInterface* stream, 134 int events, int err) { 135 if ((events & rtc::SE_OPEN)) { 136#if defined(FEATURE_ENABLE_SSL) 137 if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) { 138 state_ = buzz::AsyncSocket::STATE_TLS_OPEN; 139 SignalSSLConnected(); 140 events |= rtc::SE_WRITE; 141 } else 142#endif 143 { 144 state_ = buzz::AsyncSocket::STATE_OPEN; 145 SignalConnected(); 146 } 147 } 148 if ((events & rtc::SE_READ)) 149 SignalRead(); 150 if ((events & rtc::SE_WRITE)) { 151 // Write bytes if there are any 152 while (buffer_.Length() != 0) { 153 rtc::StreamResult result; 154 size_t written; 155 int error; 156 result = stream_->Write(buffer_.Data(), buffer_.Length(), 157 &written, &error); 158 if (result == rtc::SR_ERROR) { 159 LOG(LS_ERROR) << "Send error: " << error; 160 return; 161 } 162 if (result == rtc::SR_BLOCK) 163 return; 164 ASSERT(result == rtc::SR_SUCCESS); 165 ASSERT(written > 0); 166 buffer_.Shift(written); 167 } 168 } 169 if ((events & rtc::SE_CLOSE)) 170 SignalCloseEvent(err); 171} 172#endif // USE_SSLSTREAM 173 174buzz::AsyncSocket::State XmppSocket::state() { 175 return state_; 176} 177 178buzz::AsyncSocket::Error XmppSocket::error() { 179 return buzz::AsyncSocket::ERROR_NONE; 180} 181 182int XmppSocket::GetError() { 183 return 0; 184} 185 186bool XmppSocket::Connect(const rtc::SocketAddress& addr) { 187 if (cricket_socket_ == NULL) { 188 CreateCricketSocket(addr.family()); 189 } 190 if (cricket_socket_->Connect(addr) < 0) { 191 return cricket_socket_->IsBlocking(); 192 } 193 return true; 194} 195 196bool XmppSocket::Read(char * data, size_t len, size_t* len_read) { 197#ifndef USE_SSLSTREAM 198 int read = cricket_socket_->Recv(data, len); 199 if (read > 0) { 200 *len_read = (size_t)read; 201 return true; 202 } 203#else // USE_SSLSTREAM 204 rtc::StreamResult result = stream_->Read(data, len, len_read, NULL); 205 if (result == rtc::SR_SUCCESS) 206 return true; 207#endif // USE_SSLSTREAM 208 return false; 209} 210 211bool XmppSocket::Write(const char * data, size_t len) { 212 buffer_.WriteBytes(data, len); 213#ifndef USE_SSLSTREAM 214 OnWriteEvent(cricket_socket_); 215#else // USE_SSLSTREAM 216 OnEvent(stream_, rtc::SE_WRITE, 0); 217#endif // USE_SSLSTREAM 218 return true; 219} 220 221bool XmppSocket::Close() { 222 if (state_ != buzz::AsyncSocket::STATE_OPEN) 223 return false; 224#ifndef USE_SSLSTREAM 225 if (cricket_socket_->Close() == 0) { 226 state_ = buzz::AsyncSocket::STATE_CLOSED; 227 SignalClosed(); 228 return true; 229 } 230 return false; 231#else // USE_SSLSTREAM 232 state_ = buzz::AsyncSocket::STATE_CLOSED; 233 stream_->Close(); 234 SignalClosed(); 235 return true; 236#endif // USE_SSLSTREAM 237} 238 239bool XmppSocket::StartTls(const std::string & domainname) { 240#if defined(FEATURE_ENABLE_SSL) 241 if (tls_ == buzz::TLS_DISABLED) 242 return false; 243#ifndef USE_SSLSTREAM 244 rtc::SSLAdapter* ssl_adapter = 245 static_cast<rtc::SSLAdapter *>(cricket_socket_); 246 if (ssl_adapter->StartSSL(domainname.c_str(), false) != 0) 247 return false; 248#else // USE_SSLSTREAM 249 rtc::SSLStreamAdapter* ssl_stream = 250 static_cast<rtc::SSLStreamAdapter *>(stream_); 251 if (ssl_stream->StartSSLWithServer(domainname.c_str()) != 0) 252 return false; 253#endif // USE_SSLSTREAM 254 state_ = buzz::AsyncSocket::STATE_TLS_CONNECTING; 255 return true; 256#else // !defined(FEATURE_ENABLE_SSL) 257 return false; 258#endif // !defined(FEATURE_ENABLE_SSL) 259} 260 261} // namespace buzz 262 263