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