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 31 namespace buzz { 32 33 XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL), 34 tls_(tls) { 35 state_ = buzz::AsyncSocket::STATE_CLOSED; 36 } 37 38 void 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 68 XmppSocket::~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 78 void XmppSocket::OnReadEvent(rtc::AsyncSocket * socket) { 79 SignalRead(); 80 } 81 82 void 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 96 void 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 109 void XmppSocket::OnCloseEvent(rtc::AsyncSocket * socket, int error) { 110 SignalCloseEvent(error); 111 } 112 113 #else // USE_SSLSTREAM 114 115 void 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 156 buzz::AsyncSocket::State XmppSocket::state() { 157 return state_; 158 } 159 160 buzz::AsyncSocket::Error XmppSocket::error() { 161 return buzz::AsyncSocket::ERROR_NONE; 162 } 163 164 int XmppSocket::GetError() { 165 return 0; 166 } 167 168 bool 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 178 bool 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 193 bool 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 203 bool 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 221 bool 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