1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/jingle_glue/xmpp_socket_adapter.h"
10 #include "base/logging.h"
11 #include "remoting/jingle_glue/ssl_adapter.h"
12 #include "third_party/libjingle/source/talk/base/byteorder.h"
13 #include "third_party/libjingle/source/talk/base/common.h"
14 #include "third_party/libjingle/source/talk/base/firewallsocketserver.h"
15 #include "third_party/libjingle/source/talk/base/logging.h"
16 #include "third_party/libjingle/source/talk/base/socketadapters.h"
17 #include "third_party/libjingle/source/talk/base/ssladapter.h"
18 #include "third_party/libjingle/source/talk/base/thread.h"
19 #include "third_party/libjingle/source/talk/xmpp/xmppengine.h"
23 XmppSocketAdapter::XmppSocketAdapter(const buzz::XmppClientSettings
& xcs
,
24 bool allow_unverified_certs
)
25 : state_(STATE_CLOSED
),
29 protocol_(xcs
.protocol()),
32 write_buffer_length_(0),
33 write_buffer_capacity_(0),
34 allow_unverified_certs_(allow_unverified_certs
) {
35 proxy_
.type
= xcs
.proxy();
36 proxy_
.address
.SetIP(xcs
.proxy_host());
37 proxy_
.address
.SetPort(xcs
.proxy_port());
38 proxy_
.username
= xcs
.proxy_user();
39 proxy_
.password
= xcs
.proxy_pass();
42 XmppSocketAdapter::~XmppSocketAdapter() {
45 // Clean up any previous socket - cannot delete socket on close because close
46 // happens during the child socket's stack callback.
53 buzz::AsyncSocket::State
XmppSocketAdapter::state() {
57 buzz::AsyncSocket::Error
XmppSocketAdapter::error() {
61 int XmppSocketAdapter::GetError() {
65 bool XmppSocketAdapter::FreeState() {
68 // Clean up the socket.
69 if (socket_
&& !(state_
== STATE_CLOSED
|| state_
== STATE_CLOSING
)) {
70 code
= socket_
->Close();
73 delete[] write_buffer_
;
75 write_buffer_length_
= 0;
76 write_buffer_capacity_
= 0;
85 bool XmppSocketAdapter::Connect(const talk_base::SocketAddress
& addr
) {
86 if (state_
!= STATE_CLOSED
) {
87 SetError(ERROR_WRONGSTATE
);
91 VLOG(1) << "XmppSocketAdapter::Connect(" << addr
.ToString() << ")";
93 // Clean up any previous socket - cannot delete socket on close because close
94 // happens during the child socket's stack callback.
100 talk_base::AsyncSocket
* socket
=
101 talk_base::Thread::Current()->socketserver()->CreateAsyncSocket(
104 SetWSAError(WSA_NOT_ENOUGH_MEMORY
);
109 // TODO(sync): Change this to make WSAAsyncSockets support current thread
111 talk_base::FirewallSocketServer
* fw
=
112 static_cast<talk_base::FirewallSocketServer
*>(
113 talk_base::Thread::Current()->socketserver());
114 socket
= fw
->WrapSocket(socket
, SOCK_STREAM
);
118 talk_base::AsyncSocket
* proxy_socket
= 0;
119 if (proxy_
.type
== talk_base::PROXY_SOCKS5
) {
120 proxy_socket
= new talk_base::AsyncSocksProxySocket(
121 socket
, proxy_
.address
, proxy_
.username
, proxy_
.password
);
123 // Note: we are trying unknown proxies as HTTPS currently.
124 proxy_socket
= new talk_base::AsyncHttpsProxySocket(socket
,
125 "chromoting", proxy_
.address
, proxy_
.username
,
129 SetWSAError(WSA_NOT_ENOUGH_MEMORY
);
133 socket
= proxy_socket
; // For our purposes the proxy is now the socket.
136 if (protocol_
== cricket::PROTO_SSLTCP
) {
137 talk_base::AsyncSocket
*fake_ssl_socket
=
138 new talk_base::AsyncSSLSocket(socket
);
139 if (!fake_ssl_socket
) {
140 SetWSAError(WSA_NOT_ENOUGH_MEMORY
);
144 socket
= fake_ssl_socket
; // For our purposes the SSL socket is the socket.
147 #if defined(FEATURE_ENABLE_SSL)
148 talk_base::SSLAdapter
* ssl_adapter
= remoting::CreateSSLAdapter(socket
);
149 socket
= ssl_adapter
; // For our purposes the SSL adapter is the socket.
152 socket
->SignalReadEvent
.connect(this, &XmppSocketAdapter::OnReadEvent
);
153 socket
->SignalWriteEvent
.connect(this, &XmppSocketAdapter::OnWriteEvent
);
154 socket
->SignalConnectEvent
.connect(this, &XmppSocketAdapter::OnConnectEvent
);
155 socket
->SignalCloseEvent
.connect(this, &XmppSocketAdapter::OnCloseEvent
);
157 // The linux implementation of socket::Connect returns an error when the
158 // connect didn't complete yet. This can be distinguished from a failure
159 // because socket::IsBlocking is true. Perhaps, the linux implementation
160 // should be made to behave like the windows version which doesn't do this,
161 // but it seems to be a pattern with these methods that they return an error
162 // if the operation didn't complete in a sync fashion and one has to check
163 // IsBlocking to tell if was a "real" error.
164 if (socket
->Connect(addr
) == SOCKET_ERROR
&& !socket
->IsBlocking()) {
165 SetWSAError(socket
->GetError());
171 state_
= STATE_CONNECTING
;
175 bool XmppSocketAdapter::Read(char* data
, size_t len
, size_t* len_read
) {
179 if (state_
<= STATE_CLOSING
) {
180 SetError(ERROR_WRONGSTATE
);
187 int result
= socket_
->Recv(data
, len
);
189 if (!socket_
->IsBlocking()) {
190 SetWSAError(socket_
->GetError());
204 bool XmppSocketAdapter::Write(const char* data
, size_t len
) {
205 if (state_
<= STATE_CLOSING
) {
206 // There may be data in a buffer that gets lost. Too bad!
207 SetError(ERROR_WRONGSTATE
);
215 // Try an immediate write when there is no buffer and we aren't in SSL mode
216 // or opening the connection.
217 if (write_buffer_length_
== 0 && IsOpen()) {
218 int result
= socket_
->Send(data
, len
);
220 if (!socket_
->IsBlocking()) {
221 SetWSAError(socket_
->GetError());
227 sent
= static_cast<size_t>(result
);
230 // Buffer what we didn't send.
232 QueueWriteData(data
+ sent
, len
- sent
);
235 // Service the socket right away to push the written data out in SSL mode.
236 return HandleWritable();
239 bool XmppSocketAdapter::Close() {
240 if (state_
== STATE_CLOSING
) {
241 return false; // Avoid recursion, but not unexpected.
243 if (state_
== STATE_CLOSED
) {
244 // In theory should not be trying to re-InternalClose.
245 SetError(ERROR_WRONGSTATE
);
249 // TODO(sync): deal with flushing close (flush, don't do reads, clean ssl).
251 // If we've gotten to the point where we really do have a socket underneath
252 // then close it. It should call us back to tell us it is closed, and
253 // NotifyClose will be called. We indicate "closing" state so that we
254 // do not recusively try to keep closing the socket.
256 state_
= STATE_CLOSING
;
260 // If we didn't get the callback, then we better make sure we signal
262 if (state_
!= STATE_CLOSED
) {
263 // The socket was closed manually, not directly due to error.
264 if (error_
!= ERROR_NONE
) {
265 VLOG(1) << "XmppSocketAdapter::Close - previous Error: " << error_
266 << " WSAError: " << wsa_error_
;
275 void XmppSocketAdapter::NotifyClose() {
276 if (state_
== STATE_CLOSED
) {
277 SetError(ERROR_WRONGSTATE
);
279 VLOG(1) << "XmppSocketAdapter::NotifyClose - Error: " << error_
280 << " WSAError: " << wsa_error_
;
281 state_
= STATE_CLOSED
;
287 void XmppSocketAdapter::OnConnectEvent(talk_base::AsyncSocket
*socket
) {
288 if (state_
== STATE_CONNECTING
) {
290 VLOG(1) << "XmppSocketAdapter::OnConnectEvent - STATE_OPEN";
292 #if defined(FEATURE_ENABLE_SSL)
293 } else if (state_
== STATE_TLS_CONNECTING
) {
294 state_
= STATE_TLS_OPEN
;
295 VLOG(1) << "XmppSocketAdapter::OnConnectEvent - STATE_TLS_OPEN";
296 SignalSSLConnected();
297 if (write_buffer_length_
> 0) {
300 #endif // defined(FEATURE_ENABLE_SSL)
302 LOG(DFATAL
) << "unexpected XmppSocketAdapter::OnConnectEvent state: "
307 void XmppSocketAdapter::OnReadEvent(talk_base::AsyncSocket
*socket
) {
311 void XmppSocketAdapter::OnWriteEvent(talk_base::AsyncSocket
*socket
) {
315 void XmppSocketAdapter::OnCloseEvent(talk_base::AsyncSocket
*socket
,
317 VLOG(1) << "XmppSocketAdapter::OnCloseEvent(" << error
<< ")";
319 if (error
== SOCKET_EACCES
) {
320 SignalAuthenticationError(); // Proxy needs authentication.
325 #if defined(FEATURE_ENABLE_SSL)
326 bool XmppSocketAdapter::StartTls(const std::string
& verify_host_name
) {
327 if (state_
!= STATE_OPEN
) {
328 SetError(ERROR_WRONGSTATE
);
332 state_
= STATE_TLS_CONNECTING
;
334 DCHECK_EQ(write_buffer_length_
, 0U);
336 talk_base::SSLAdapter
* ssl_adapter
=
337 static_cast<talk_base::SSLAdapter
*>(socket_
);
339 if (allow_unverified_certs_
) {
340 ssl_adapter
->set_ignore_bad_cert(true);
343 if (ssl_adapter
->StartSSL(verify_host_name
.c_str(), false) != 0) {
351 #endif // defined(FEATURE_ENABLE_SSL)
353 void XmppSocketAdapter::QueueWriteData(const char* data
, size_t len
) {
354 // Expand buffer if needed.
355 if (write_buffer_length_
+ len
> write_buffer_capacity_
) {
356 size_t new_capacity
= 1024;
357 while (new_capacity
< write_buffer_length_
+ len
) {
358 new_capacity
= new_capacity
* 2;
360 char* new_buffer
= new char[new_capacity
];
361 DCHECK_LE(write_buffer_length_
, 64000U);
362 memcpy(new_buffer
, write_buffer_
, write_buffer_length_
);
363 delete[] write_buffer_
;
364 write_buffer_
= new_buffer
;
365 write_buffer_capacity_
= new_capacity
;
368 // Copy data into the end of buffer.
369 memcpy(write_buffer_
+ write_buffer_length_
, data
, len
);
370 write_buffer_length_
+= len
;
373 void XmppSocketAdapter::FlushWriteQueue(Error
* error
, int* wsa_error
) {
378 while (flushed
< write_buffer_length_
) {
379 int sent
= socket_
->Send(write_buffer_
+ flushed
,
380 static_cast<int>(write_buffer_length_
- flushed
));
382 if (!socket_
->IsBlocking()) {
383 *error
= ERROR_WINSOCK
;
384 *wsa_error
= socket_
->GetError();
388 flushed
+= static_cast<size_t>(sent
);
391 // Remove flushed memory.
392 write_buffer_length_
-= flushed
;
393 memmove(write_buffer_
, write_buffer_
+ flushed
, write_buffer_length_
);
395 // When everything is flushed, deallocate the buffer if it's gotten big.
396 if (write_buffer_length_
== 0) {
397 if (write_buffer_capacity_
> 8192) {
398 delete[] write_buffer_
;
399 write_buffer_
= NULL
;
400 write_buffer_capacity_
= 0;
405 void XmppSocketAdapter::SetError(Error error
) {
406 if (error_
== ERROR_NONE
) {
411 void XmppSocketAdapter::SetWSAError(int error
) {
412 if (error_
== ERROR_NONE
&& error
!= 0) {
413 error_
= ERROR_WINSOCK
;
418 bool XmppSocketAdapter::HandleReadable() {
426 bool XmppSocketAdapter::HandleWritable() {
430 Error error
= ERROR_NONE
;
432 FlushWriteQueue(&error
, &wsa_error
);
433 if (error
!= ERROR_NONE
) {
440 } // namespace remoting