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 
XmppSocket(buzz::TlsOptions tls)33 XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL),
34                                                tls_(tls) {
35   state_ = buzz::AsyncSocket::STATE_CLOSED;
36 }
37 
CreateCricketSocket(int family)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 
~XmppSocket()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
OnReadEvent(rtc::AsyncSocket * socket)78 void XmppSocket::OnReadEvent(rtc::AsyncSocket * socket) {
79   SignalRead();
80 }
81 
OnWriteEvent(rtc::AsyncSocket * socket)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 
OnConnectEvent(rtc::AsyncSocket * socket)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 
OnCloseEvent(rtc::AsyncSocket * socket,int error)109 void XmppSocket::OnCloseEvent(rtc::AsyncSocket * socket, int error) {
110   SignalCloseEvent(error);
111 }
112 
113 #else  // USE_SSLSTREAM
114 
OnEvent(rtc::StreamInterface * stream,int events,int err)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 
state()156 buzz::AsyncSocket::State XmppSocket::state() {
157   return state_;
158 }
159 
error()160 buzz::AsyncSocket::Error XmppSocket::error() {
161   return buzz::AsyncSocket::ERROR_NONE;
162 }
163 
GetError()164 int XmppSocket::GetError() {
165   return 0;
166 }
167 
Connect(const rtc::SocketAddress & addr)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 
Read(char * data,size_t len,size_t * len_read)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 
Write(const char * data,size_t len)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 
Close()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 
StartTls(const std::string & domainname)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