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 "talk/base/basicdefs.h" 36 #include "talk/base/logging.h" 37 #include "talk/base/thread.h" 38 #ifdef FEATURE_ENABLE_SSL 39 #include "talk/base/ssladapter.h" 40 #endif 41 42 #ifdef USE_SSLSTREAM 43 #include "talk/base/socketstream.h" 44 #ifdef FEATURE_ENABLE_SSL 45 #include "talk/base/sslstreamadapter.h" 46 #endif // FEATURE_ENABLE_SSL 47 #endif // USE_SSLSTREAM 48 49 namespace buzz { 50 51 XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL), 52 tls_(tls) { 53 state_ = buzz::AsyncSocket::STATE_CLOSED; 54 } 55 56 void XmppSocket::CreateCricketSocket(int family) { 57 talk_base::Thread* pth = talk_base::Thread::Current(); 58 if (family == AF_UNSPEC) { 59 family = AF_INET; 60 } 61 talk_base::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 = talk_base::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 talk_base::SocketStream(cricket_socket_); 78 #ifdef FEATURE_ENABLE_SSL 79 if (tls_ != buzz::TLS_DISABLED) 80 stream_ = talk_base::SSLStreamAdapter::Create(stream_); 81 #endif // FEATURE_ENABLE_SSL 82 stream_->SignalEvent.connect(this, &XmppSocket::OnEvent); 83 #endif // USE_SSLSTREAM 84 } 85 86 XmppSocket::~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 96 void XmppSocket::OnReadEvent(talk_base::AsyncSocket * socket) { 97 SignalRead(); 98 } 99 100 void XmppSocket::OnWriteEvent(talk_base::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 114 void XmppSocket::OnConnectEvent(talk_base::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 127 void XmppSocket::OnCloseEvent(talk_base::AsyncSocket * socket, int error) { 128 SignalCloseEvent(error); 129 } 130 131 #else // USE_SSLSTREAM 132 133 void XmppSocket::OnEvent(talk_base::StreamInterface* stream, 134 int events, int err) { 135 if ((events & talk_base::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 |= talk_base::SE_WRITE; 141 } else 142 #endif 143 { 144 state_ = buzz::AsyncSocket::STATE_OPEN; 145 SignalConnected(); 146 } 147 } 148 if ((events & talk_base::SE_READ)) 149 SignalRead(); 150 if ((events & talk_base::SE_WRITE)) { 151 // Write bytes if there are any 152 while (buffer_.Length() != 0) { 153 talk_base::StreamResult result; 154 size_t written; 155 int error; 156 result = stream_->Write(buffer_.Data(), buffer_.Length(), 157 &written, &error); 158 if (result == talk_base::SR_ERROR) { 159 LOG(LS_ERROR) << "Send error: " << error; 160 return; 161 } 162 if (result == talk_base::SR_BLOCK) 163 return; 164 ASSERT(result == talk_base::SR_SUCCESS); 165 ASSERT(written > 0); 166 buffer_.Shift(written); 167 } 168 } 169 if ((events & talk_base::SE_CLOSE)) 170 SignalCloseEvent(err); 171 } 172 #endif // USE_SSLSTREAM 173 174 buzz::AsyncSocket::State XmppSocket::state() { 175 return state_; 176 } 177 178 buzz::AsyncSocket::Error XmppSocket::error() { 179 return buzz::AsyncSocket::ERROR_NONE; 180 } 181 182 int XmppSocket::GetError() { 183 return 0; 184 } 185 186 bool XmppSocket::Connect(const talk_base::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 196 bool 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 talk_base::StreamResult result = stream_->Read(data, len, len_read, NULL); 205 if (result == talk_base::SR_SUCCESS) 206 return true; 207 #endif // USE_SSLSTREAM 208 return false; 209 } 210 211 bool 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_, talk_base::SE_WRITE, 0); 217 #endif // USE_SSLSTREAM 218 return true; 219 } 220 221 bool 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 239 bool 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 talk_base::SSLAdapter* ssl_adapter = 245 static_cast<talk_base::SSLAdapter *>(cricket_socket_); 246 if (ssl_adapter->StartSSL(domainname.c_str(), false) != 0) 247 return false; 248 #else // USE_SSLSTREAM 249 talk_base::SSLStreamAdapter* ssl_stream = 250 static_cast<talk_base::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