1/* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "xmppsocket.h" 12 13#ifdef HAVE_CONFIG_H 14#include <config.h> 15#endif 16 17#include <errno.h> 18#include "webrtc/base/logging.h" 19#include "webrtc/base/thread.h" 20#ifdef FEATURE_ENABLE_SSL 21#include "webrtc/base/ssladapter.h" 22#endif 23 24#ifdef USE_SSLSTREAM 25#include "webrtc/base/socketstream.h" 26#ifdef FEATURE_ENABLE_SSL 27#include "webrtc/base/sslstreamadapter.h" 28#endif // FEATURE_ENABLE_SSL 29#endif // USE_SSLSTREAM 30 31namespace buzz { 32 33XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL), 34 tls_(tls) { 35 state_ = buzz::AsyncSocket::STATE_CLOSED; 36} 37 38void XmppSocket::CreateCricketSocket(int family) { 39 rtc::Thread* pth = rtc::Thread::Current(); 40 if (family == AF_UNSPEC) { 41 family = AF_INET; 42 } 43 rtc::AsyncSocket* socket = 44 pth->socketserver()->CreateAsyncSocket(family, SOCK_STREAM); 45#ifndef USE_SSLSTREAM 46#ifdef FEATURE_ENABLE_SSL 47 if (tls_ != buzz::TLS_DISABLED) { 48 socket = rtc::SSLAdapter::Create(socket); 49 } 50#endif // FEATURE_ENABLE_SSL 51 cricket_socket_ = socket; 52 cricket_socket_->SignalReadEvent.connect(this, &XmppSocket::OnReadEvent); 53 cricket_socket_->SignalWriteEvent.connect(this, &XmppSocket::OnWriteEvent); 54 cricket_socket_->SignalConnectEvent.connect(this, 55 &XmppSocket::OnConnectEvent); 56 cricket_socket_->SignalCloseEvent.connect(this, &XmppSocket::OnCloseEvent); 57#else // USE_SSLSTREAM 58 cricket_socket_ = socket; 59 stream_ = new rtc::SocketStream(cricket_socket_); 60#ifdef FEATURE_ENABLE_SSL 61 if (tls_ != buzz::TLS_DISABLED) 62 stream_ = rtc::SSLStreamAdapter::Create(stream_); 63#endif // FEATURE_ENABLE_SSL 64 stream_->SignalEvent.connect(this, &XmppSocket::OnEvent); 65#endif // USE_SSLSTREAM 66} 67 68XmppSocket::~XmppSocket() { 69 Close(); 70#ifndef USE_SSLSTREAM 71 delete cricket_socket_; 72#else // USE_SSLSTREAM 73 delete stream_; 74#endif // USE_SSLSTREAM 75} 76 77#ifndef USE_SSLSTREAM 78void XmppSocket::OnReadEvent(rtc::AsyncSocket * socket) { 79 SignalRead(); 80} 81 82void XmppSocket::OnWriteEvent(rtc::AsyncSocket * socket) { 83 // Write bytes if there are any 84 while (buffer_.Length() != 0) { 85 int written = cricket_socket_->Send(buffer_.Data(), buffer_.Length()); 86 if (written > 0) { 87 buffer_.Consume(written); 88 continue; 89 } 90 if (!cricket_socket_->IsBlocking()) 91 LOG(LS_ERROR) << "Send error: " << cricket_socket_->GetError(); 92 return; 93 } 94} 95 96void XmppSocket::OnConnectEvent(rtc::AsyncSocket * socket) { 97#if defined(FEATURE_ENABLE_SSL) 98 if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) { 99 state_ = buzz::AsyncSocket::STATE_TLS_OPEN; 100 SignalSSLConnected(); 101 OnWriteEvent(cricket_socket_); 102 return; 103 } 104#endif // !defined(FEATURE_ENABLE_SSL) 105 state_ = buzz::AsyncSocket::STATE_OPEN; 106 SignalConnected(); 107} 108 109void XmppSocket::OnCloseEvent(rtc::AsyncSocket * socket, int error) { 110 SignalCloseEvent(error); 111} 112 113#else // USE_SSLSTREAM 114 115void XmppSocket::OnEvent(rtc::StreamInterface* stream, 116 int events, int err) { 117 if ((events & rtc::SE_OPEN)) { 118#if defined(FEATURE_ENABLE_SSL) 119 if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) { 120 state_ = buzz::AsyncSocket::STATE_TLS_OPEN; 121 SignalSSLConnected(); 122 events |= rtc::SE_WRITE; 123 } else 124#endif 125 { 126 state_ = buzz::AsyncSocket::STATE_OPEN; 127 SignalConnected(); 128 } 129 } 130 if ((events & rtc::SE_READ)) 131 SignalRead(); 132 if ((events & rtc::SE_WRITE)) { 133 // Write bytes if there are any 134 while (buffer_.Length() != 0) { 135 rtc::StreamResult result; 136 size_t written; 137 int error; 138 result = stream_->Write(buffer_.Data(), buffer_.Length(), 139 &written, &error); 140 if (result == rtc::SR_ERROR) { 141 LOG(LS_ERROR) << "Send error: " << error; 142 return; 143 } 144 if (result == rtc::SR_BLOCK) 145 return; 146 ASSERT(result == rtc::SR_SUCCESS); 147 ASSERT(written > 0); 148 buffer_.Shift(written); 149 } 150 } 151 if ((events & rtc::SE_CLOSE)) 152 SignalCloseEvent(err); 153} 154#endif // USE_SSLSTREAM 155 156buzz::AsyncSocket::State XmppSocket::state() { 157 return state_; 158} 159 160buzz::AsyncSocket::Error XmppSocket::error() { 161 return buzz::AsyncSocket::ERROR_NONE; 162} 163 164int XmppSocket::GetError() { 165 return 0; 166} 167 168bool XmppSocket::Connect(const rtc::SocketAddress& addr) { 169 if (cricket_socket_ == NULL) { 170 CreateCricketSocket(addr.family()); 171 } 172 if (cricket_socket_->Connect(addr) < 0) { 173 return cricket_socket_->IsBlocking(); 174 } 175 return true; 176} 177 178bool XmppSocket::Read(char * data, size_t len, size_t* len_read) { 179#ifndef USE_SSLSTREAM 180 int read = cricket_socket_->Recv(data, len); 181 if (read > 0) { 182 *len_read = (size_t)read; 183 return true; 184 } 185#else // USE_SSLSTREAM 186 rtc::StreamResult result = stream_->Read(data, len, len_read, NULL); 187 if (result == rtc::SR_SUCCESS) 188 return true; 189#endif // USE_SSLSTREAM 190 return false; 191} 192 193bool XmppSocket::Write(const char * data, size_t len) { 194 buffer_.WriteBytes(data, len); 195#ifndef USE_SSLSTREAM 196 OnWriteEvent(cricket_socket_); 197#else // USE_SSLSTREAM 198 OnEvent(stream_, rtc::SE_WRITE, 0); 199#endif // USE_SSLSTREAM 200 return true; 201} 202 203bool XmppSocket::Close() { 204 if (state_ != buzz::AsyncSocket::STATE_OPEN) 205 return false; 206#ifndef USE_SSLSTREAM 207 if (cricket_socket_->Close() == 0) { 208 state_ = buzz::AsyncSocket::STATE_CLOSED; 209 SignalClosed(); 210 return true; 211 } 212 return false; 213#else // USE_SSLSTREAM 214 state_ = buzz::AsyncSocket::STATE_CLOSED; 215 stream_->Close(); 216 SignalClosed(); 217 return true; 218#endif // USE_SSLSTREAM 219} 220 221bool XmppSocket::StartTls(const std::string & domainname) { 222#if defined(FEATURE_ENABLE_SSL) 223 if (tls_ == buzz::TLS_DISABLED) 224 return false; 225#ifndef USE_SSLSTREAM 226 rtc::SSLAdapter* ssl_adapter = 227 static_cast<rtc::SSLAdapter *>(cricket_socket_); 228 if (ssl_adapter->StartSSL(domainname.c_str(), false) != 0) 229 return false; 230#else // USE_SSLSTREAM 231 rtc::SSLStreamAdapter* ssl_stream = 232 static_cast<rtc::SSLStreamAdapter *>(stream_); 233 if (ssl_stream->StartSSLWithServer(domainname.c_str()) != 0) 234 return false; 235#endif // USE_SSLSTREAM 236 state_ = buzz::AsyncSocket::STATE_TLS_CONNECTING; 237 return true; 238#else // !defined(FEATURE_ENABLE_SSL) 239 return false; 240#endif // !defined(FEATURE_ENABLE_SSL) 241} 242 243} // namespace buzz 244 245