Home | History | Annotate | Download | only in xmpp
      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