2
* connector.cpp - establish a connection to an XMPP server
3
* Copyright (C) 2003 Justin Karneges
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
- Test and analyze all possible branches
26
XMPP::AdvancedConnector is "good for now." The only real issue is that
27
most of what it provides is just to work around the old Jabber/XMPP 0.9
28
connection behavior. When XMPP 1.0 has taken over the world, we can
29
greatly simplify this class. - Sep 3rd, 2003.
34
#include<qguardedptr.h>
36
#include"safedelete.h"
44
#include"srvresolver.h"
46
#include"httpconnect.h"
55
//----------------------------------------------------------------------------
57
//----------------------------------------------------------------------------
58
Connector::Connector(QObject *parent)
65
Connector::~Connector()
69
bool Connector::useSSL() const
74
bool Connector::havePeerAddress() const
79
QHostAddress Connector::peerAddress() const
84
Q_UINT16 Connector::peerPort() const
89
void Connector::setUseSSL(bool b)
94
void Connector::setPeerAddressNone()
97
addr = QHostAddress();
101
void Connector::setPeerAddress(const QHostAddress &_addr, Q_UINT16 _port)
109
//----------------------------------------------------------------------------
110
// AdvancedConnector::Proxy
111
//----------------------------------------------------------------------------
112
AdvancedConnector::Proxy::Proxy()
118
AdvancedConnector::Proxy::~Proxy()
122
int AdvancedConnector::Proxy::type() const
127
QString AdvancedConnector::Proxy::host() const
132
Q_UINT16 AdvancedConnector::Proxy::port() const
137
QString AdvancedConnector::Proxy::url() const
142
QString AdvancedConnector::Proxy::user() const
147
QString AdvancedConnector::Proxy::pass() const
152
int AdvancedConnector::Proxy::pollInterval() const
157
void AdvancedConnector::Proxy::setHttpConnect(const QString &host, Q_UINT16 port)
164
void AdvancedConnector::Proxy::setHttpPoll(const QString &host, Q_UINT16 port, const QString &url)
172
void AdvancedConnector::Proxy::setSocks(const QString &host, Q_UINT16 port)
179
void AdvancedConnector::Proxy::setUserPass(const QString &user, const QString &pass)
185
void AdvancedConnector::Proxy::setPollInterval(int secs)
191
//----------------------------------------------------------------------------
193
//----------------------------------------------------------------------------
194
enum { Idle, Connecting, Connected };
195
class AdvancedConnector::Private
210
bool opt_probe, opt_ssl;
215
QValueList<QDns::Server> servers;
218
bool multi, using_srv;
226
AdvancedConnector::AdvancedConnector(QObject *parent)
234
connect(&d->dns, SIGNAL(resultsReady()), SLOT(dns_done()));
236
connect(&d->srv, SIGNAL(resultsReady()), SLOT(srv_done()));
237
d->opt_probe = false;
243
AdvancedConnector::~AdvancedConnector()
249
void AdvancedConnector::cleanup()
256
d->qdns->disconnect(this);
257
d->qdns->deleteLater();
258
//d->sd.deleteLater(d->qdns);
268
// destroy the bytestream, if there is one
273
d->using_srv = false;
274
d->will_be_ssl = false;
278
setPeerAddressNone();
281
void AdvancedConnector::setProxy(const Proxy &proxy)
288
void AdvancedConnector::setOptHostPort(const QString &host, Q_UINT16 _port)
296
void AdvancedConnector::setOptProbe(bool b)
303
void AdvancedConnector::setOptSSL(bool b)
310
void AdvancedConnector::connectToServer(const QString &server)
319
d->mode = Connecting;
322
if(d->proxy.type() == Proxy::HttpPoll) {
324
if(!QCA::isSupported(QCA::CAP_SHA1))
325
QCA::insertProvider(createProviderHash());
327
HttpPoll *s = new HttpPoll;
329
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
330
connect(s, SIGNAL(syncStarted()), SLOT(http_syncStarted()));
331
connect(s, SIGNAL(syncFinished()), SLOT(http_syncFinished()));
332
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
333
if(!d->proxy.user().isEmpty())
334
s->setAuth(d->proxy.user(), d->proxy.pass());
335
s->setPollInterval(d->proxy.pollInterval());
337
if(d->proxy.host().isEmpty())
338
s->connectToUrl(d->proxy.url());
340
s->connectToHost(d->proxy.host(), d->proxy.port(), d->proxy.url());
343
if(!d->opt_host.isEmpty()) {
344
d->host = d->opt_host;
345
d->port = d->opt_port;
351
QGuardedPtr<QObject> self = this;
352
srvLookup(d->server);
356
d->srv.resolveSrvOnly(d->server, "xmpp-client", "tcp");
361
void AdvancedConnector::changePollInterval(int secs)
363
if(d->bs && (d->bs->inherits("XMPP::HttpPoll") || d->bs->inherits("HttpPoll"))) {
364
HttpPoll *s = static_cast<HttpPoll*>(d->bs);
365
s->setPollInterval(secs);
369
ByteStream *AdvancedConnector::stream() const
371
if(d->mode == Connected)
377
void AdvancedConnector::done()
382
int AdvancedConnector::errorCode() const
387
void AdvancedConnector::do_resolve()
390
printf("resolving (aaaa=%d)\n", d->aaaa);
392
connect(d->qdns, SIGNAL(resultsReady()), SLOT(dns_done()));
394
d->qdns->setRecordType(QDns::Aaaa); // IPv6
396
d->qdns->setRecordType(QDns::A); // IPv4
397
d->qdns->setLabel(d->host);
399
d->dns.resolve(d->host);
403
void AdvancedConnector::dns_done()
412
// apparently we sometimes get this signal even though the results aren' t ready
413
//if(d->qdns->isWorking())
416
//SafeDeleteLock s(&d->sd);
418
// grab the address list and destroy the qdns object
419
QValueList<QHostAddress> list = d->qdns->addresses();
420
d->qdns->disconnect(this);
421
d->qdns->deleteLater();
422
//d->sd.deleteLater(d->qdns);
438
if(d->dns.result() == 0)
441
addr = QHostAddress(d->dns.result());
448
// using proxy? then try the unresolved host through the proxy
449
if(d->proxy.type() != Proxy::None) {
455
else if(d->using_srv) {
459
if(d->servers.isEmpty()) {
461
printf("dns1.2.1\n");
464
d->errorCode = ErrConnectionRefused;
469
printf("dns1.2.2\n");
480
d->errorCode = ErrHostNotFound;
488
d->host = addr.toString();
493
void AdvancedConnector::do_connect()
496
printf("trying %s:%d\n", d->host.latin1(), d->port);
498
int t = d->proxy.type();
499
if(t == Proxy::None) {
501
printf("do_connect1\n");
503
BSocket *s = new BSocket;
505
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
506
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
507
s->connectToHost(d->host, d->port);
509
else if(t == Proxy::HttpConnect) {
511
printf("do_connect2\n");
513
HttpConnect *s = new HttpConnect;
515
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
516
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
517
if(!d->proxy.user().isEmpty())
518
s->setAuth(d->proxy.user(), d->proxy.pass());
519
s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port);
521
else if(t == Proxy::Socks) {
523
printf("do_connect3\n");
525
SocksClient *s = new SocksClient;
527
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
528
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
529
if(!d->proxy.user().isEmpty())
530
s->setAuth(d->proxy.user(), d->proxy.pass());
531
s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port);
535
void AdvancedConnector::tryNextSrv()
538
printf("trying next srv\n");
540
d->host = d->servers.first().name;
541
d->port = d->servers.first().port;
542
d->servers.remove(d->servers.begin());
546
void AdvancedConnector::srv_done()
548
QGuardedPtr<QObject> self = this;
550
printf("srv_done1\n");
552
d->servers = d->srv.servers();
553
if(d->servers.isEmpty()) {
559
printf("srv_done1.1\n");
561
// fall back to A record
562
d->using_srv = false;
566
printf("srv_done1.1.1\n");
570
d->will_be_ssl = true;
574
printf("srv_done1.1.2\n");
591
void AdvancedConnector::bs_connected()
593
if(d->proxy.type() == Proxy::None) {
594
QHostAddress h = (static_cast<BSocket*>(d->bs))->peerAddress();
595
int p = (static_cast<BSocket*>(d->bs))->peerPort();
596
setPeerAddress(h, p);
599
// only allow ssl override if proxy==poll or host:port
600
if((d->proxy.type() == Proxy::HttpPoll || !d->opt_host.isEmpty()) && d->opt_ssl)
602
else if(d->will_be_ssl)
609
void AdvancedConnector::bs_error(int x)
611
if(d->mode == Connected) {
612
d->errorCode = ErrStream;
617
bool proxyError = false;
618
int err = ErrConnectionRefused;
619
int t = d->proxy.type();
625
// figure out the error
626
if(t == Proxy::None) {
627
if(x == BSocket::ErrHostNotFound)
628
err = ErrHostNotFound;
630
err = ErrConnectionRefused;
632
else if(t == Proxy::HttpConnect) {
633
if(x == HttpConnect::ErrConnectionRefused)
634
err = ErrConnectionRefused;
635
else if(x == HttpConnect::ErrHostNotFound)
636
err = ErrHostNotFound;
639
if(x == HttpConnect::ErrProxyAuth)
641
else if(x == HttpConnect::ErrProxyNeg)
644
err = ErrProxyConnect;
647
else if(t == Proxy::HttpPoll) {
648
if(x == HttpPoll::ErrConnectionRefused)
649
err = ErrConnectionRefused;
650
else if(x == HttpPoll::ErrHostNotFound)
651
err = ErrHostNotFound;
654
if(x == HttpPoll::ErrProxyAuth)
656
else if(x == HttpPoll::ErrProxyNeg)
659
err = ErrProxyConnect;
662
else if(t == Proxy::Socks) {
663
if(x == SocksClient::ErrConnectionRefused)
664
err = ErrConnectionRefused;
665
else if(x == SocksClient::ErrHostNotFound)
666
err = ErrHostNotFound;
669
if(x == SocksClient::ErrProxyAuth)
671
else if(x == SocksClient::ErrProxyNeg)
674
err = ErrProxyConnect;
678
// no-multi or proxy error means we quit
679
if(!d->multi || proxyError) {
686
if(d->using_srv && !d->servers.isEmpty()) {
692
else if(!d->using_srv && d->opt_probe && d->probe_mode == 0) {
698
d->will_be_ssl = false;
706
d->errorCode = ErrConnectionRefused;
711
void AdvancedConnector::http_syncStarted()
716
void AdvancedConnector::http_syncFinished()