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.
39
#include "safedelete.h"
40
#include <libidn/idna.h>
45
#include "httpconnect.h"
48
#include "srvresolver.h"
54
//----------------------------------------------------------------------------
56
//----------------------------------------------------------------------------
57
Connector::Connector(QObject *parent)
64
Connector::~Connector()
68
bool Connector::useSSL() const
73
bool Connector::havePeerAddress() const
78
QHostAddress Connector::peerAddress() const
83
quint16 Connector::peerPort() const
88
void Connector::setUseSSL(bool b)
93
void Connector::setPeerAddressNone()
96
addr = QHostAddress();
100
void Connector::setPeerAddress(const QHostAddress &_addr, quint16 _port)
107
QString Connector::host() const
113
//----------------------------------------------------------------------------
114
// AdvancedConnector::Proxy
115
//----------------------------------------------------------------------------
116
AdvancedConnector::Proxy::Proxy()
122
AdvancedConnector::Proxy::~Proxy()
126
int AdvancedConnector::Proxy::type() const
131
QString AdvancedConnector::Proxy::host() const
136
quint16 AdvancedConnector::Proxy::port() const
141
QString AdvancedConnector::Proxy::url() const
146
QString AdvancedConnector::Proxy::user() const
151
QString AdvancedConnector::Proxy::pass() const
156
int AdvancedConnector::Proxy::pollInterval() const
161
void AdvancedConnector::Proxy::setHttpConnect(const QString &host, quint16 port)
168
void AdvancedConnector::Proxy::setHttpPoll(const QString &host, quint16 port, const QString &url)
176
void AdvancedConnector::Proxy::setSocks(const QString &host, quint16 port)
183
void AdvancedConnector::Proxy::setUserPass(const QString &user, const QString &pass)
189
void AdvancedConnector::Proxy::setPollInterval(int secs)
195
//----------------------------------------------------------------------------
197
//----------------------------------------------------------------------------
198
enum { Idle, Connecting, Connected };
199
class AdvancedConnector::Private
208
QStringList opt_hosts;
210
bool opt_probe, opt_ssl;
213
QStringList hostsToTry;
216
QList<Q3Dns::Server> servers;
220
bool multi, using_srv;
227
QTimer connectTimeout;
230
AdvancedConnector::AdvancedConnector(QObject *parent)
235
connect(&d->dns, SIGNAL(resultsReady()), SLOT(dns_done()));
236
connect(&d->srv, SIGNAL(resultsReady()), SLOT(srv_done()));
237
connect(&d->connectTimeout, SIGNAL(timeout()), SLOT(t_timeout()));
238
d->connectTimeout.setSingleShot(true);
239
d->opt_probe = false;
245
AdvancedConnector::~AdvancedConnector()
251
void AdvancedConnector::cleanup()
261
// destroy the bytestream, if there is one
266
d->using_srv = false;
267
d->will_be_ssl = false;
271
setPeerAddressNone();
274
void AdvancedConnector::setProxy(const Proxy &proxy)
281
void AdvancedConnector::setOptHostPort(const QString &host, quint16 _port)
285
// empty host means disable explicit host support
287
d->opt_hosts.clear();
290
d->opt_hosts = QStringList() << host;
294
void AdvancedConnector::setOptHostsPort(const QStringList &_hosts, quint16 _port)
298
d->opt_hosts = _hosts;
302
void AdvancedConnector::setOptProbe(bool b)
309
void AdvancedConnector::setOptSSL(bool b)
316
void AdvancedConnector::connectToServer(const QString &server)
323
d->hostsToTry.clear();
325
d->mode = Connecting;
327
d->connectHost.clear();
329
// Encode the servername
330
d->server = QUrl::toAce(server);
331
//char* server_encoded;
332
//if (!idna_to_ascii_8z(server.utf8().data(), &server_encoded, 0)) {
333
// d->server = QString(server_encoded);
334
// free(server_encoded);
337
// d->server = server;
340
if(d->proxy.type() == Proxy::HttpPoll) {
342
//if(!QCA::isSupported(QCA::CAP_SHA1))
343
// QCA::insertProvider(createProviderHash());
345
HttpPoll *s = new HttpPoll;
347
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
348
connect(s, SIGNAL(syncStarted()), SLOT(http_syncStarted()));
349
connect(s, SIGNAL(syncFinished()), SLOT(http_syncFinished()));
350
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
351
if(!d->proxy.user().isEmpty())
352
s->setAuth(d->proxy.user(), d->proxy.pass());
353
s->setPollInterval(d->proxy.pollInterval());
355
if(d->proxy.host().isEmpty())
356
s->connectToUrl(d->proxy.url());
358
s->connectToHost(d->proxy.host(), d->proxy.port(), d->proxy.url());
360
else if (d->proxy.type() == Proxy::HttpConnect) {
361
if(!d->opt_hosts.isEmpty()) {
362
d->hostsToTry = d->opt_hosts;
363
d->host = d->hostsToTry.takeFirst();
364
d->port = d->opt_port;
373
if(!d->opt_hosts.isEmpty()) {
374
d->hostsToTry = d->opt_hosts;
375
d->host = d->hostsToTry.takeFirst();
376
d->port = d->opt_port;
382
QPointer<QObject> self = this;
383
srvLookup(d->server);
387
d->srv.resolveSrvOnly(d->server, "xmpp-client", "tcp");
392
void AdvancedConnector::changePollInterval(int secs)
394
if(d->bs && (d->bs->inherits("XMPP::HttpPoll") || d->bs->inherits("HttpPoll"))) {
395
HttpPoll *s = static_cast<HttpPoll*>(d->bs);
396
s->setPollInterval(secs);
400
ByteStream *AdvancedConnector::stream() const
402
if(d->mode == Connected)
408
void AdvancedConnector::done()
413
int AdvancedConnector::errorCode() const
418
void AdvancedConnector::do_resolve()
420
d->dns.resolve(d->host);
423
void AdvancedConnector::dns_done()
428
if(d->dns.result().isNull ())
431
addr = QHostAddress(d->dns.result());
437
// using proxy? then try the unresolved host through the proxy
438
if(d->proxy.type() != Proxy::None) {
444
else if(d->using_srv) {
448
if(d->servers.isEmpty()) {
450
printf("dns1.2.1\n");
453
d->errorCode = ErrConnectionRefused;
458
printf("dns1.2.2\n");
468
if(!d->hostsToTry.isEmpty())
471
d->host = d->hostsToTry.takeFirst();
477
d->errorCode = ErrHostNotFound;
485
d->connectHost = d->host;
486
d->host = addr.toString();
491
void AdvancedConnector::do_connect()
493
// 5 seconds to connect
494
d->connectTimeout.start(5000);
497
printf("trying %s:%d\n", d->host.latin1(), d->port);
499
int t = d->proxy.type();
500
if(t == Proxy::None) {
502
printf("do_connect1\n");
504
BSocket *s = new BSocket;
506
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
507
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
508
s->connectToHost(d->host, d->port);
510
else if(t == Proxy::HttpConnect) {
512
printf("do_connect2\n");
514
HttpConnect *s = new HttpConnect;
516
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
517
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
518
if(!d->proxy.user().isEmpty())
519
s->setAuth(d->proxy.user(), d->proxy.pass());
520
s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port);
522
else if(t == Proxy::Socks) {
524
printf("do_connect3\n");
526
SocksClient *s = new SocksClient;
528
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
529
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
530
if(!d->proxy.user().isEmpty())
531
s->setAuth(d->proxy.user(), d->proxy.pass());
532
s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port);
536
void AdvancedConnector::tryNextSrv()
539
printf("trying next srv\n");
541
Q_ASSERT(!d->servers.isEmpty());
542
d->host = d->servers.first().name;
543
d->port = d->servers.first().port;
544
d->servers.takeFirst();
548
void AdvancedConnector::srv_done()
550
QPointer<QObject> self = this;
552
printf("srv_done1\n");
554
d->servers = d->srv.servers();
555
if(d->servers.isEmpty()) {
561
printf("srv_done1.1\n");
563
// fall back to A record
564
d->using_srv = false;
568
printf("srv_done1.1.1\n");
572
d->will_be_ssl = true;
576
printf("srv_done1.1.2\n");
593
void AdvancedConnector::bs_connected()
595
d->connectTimeout.stop();
597
if(d->proxy.type() == Proxy::None) {
598
QHostAddress h = (static_cast<BSocket*>(d->bs))->peerAddress();
599
int p = (static_cast<BSocket*>(d->bs))->peerPort();
600
setPeerAddress(h, p);
603
// only allow ssl override if proxy==poll or host:port
604
if((d->proxy.type() == Proxy::HttpPoll || !d->opt_hosts.isEmpty()) && d->opt_ssl)
606
else if(d->will_be_ssl)
613
void AdvancedConnector::bs_error(int x)
615
if(d->mode == Connected) {
616
d->errorCode = ErrStream;
621
bool proxyError = false;
622
int err = ErrConnectionRefused;
623
int t = d->proxy.type();
629
// figure out the error
630
if(t == Proxy::None) {
631
if(x == BSocket::ErrHostNotFound)
632
err = ErrHostNotFound;
634
err = ErrConnectionRefused;
636
else if(t == Proxy::HttpConnect) {
637
if(x == HttpConnect::ErrConnectionRefused)
638
err = ErrConnectionRefused;
639
else if(x == HttpConnect::ErrHostNotFound)
640
err = ErrHostNotFound;
643
if(x == HttpConnect::ErrProxyAuth)
645
else if(x == HttpConnect::ErrProxyNeg)
648
err = ErrProxyConnect;
651
else if(t == Proxy::HttpPoll) {
652
if(x == HttpPoll::ErrConnectionRefused)
653
err = ErrConnectionRefused;
654
else if(x == HttpPoll::ErrHostNotFound)
655
err = ErrHostNotFound;
658
if(x == HttpPoll::ErrProxyAuth)
660
else if(x == HttpPoll::ErrProxyNeg)
663
err = ErrProxyConnect;
666
else if(t == Proxy::Socks) {
667
if(x == SocksClient::ErrConnectionRefused)
668
err = ErrConnectionRefused;
669
else if(x == SocksClient::ErrHostNotFound)
670
err = ErrHostNotFound;
673
if(x == SocksClient::ErrProxyAuth)
675
else if(x == SocksClient::ErrProxyNeg)
678
err = ErrProxyConnect;
682
// try next host, if any
683
if(!d->hostsToTry.isEmpty())
686
d->host = d->hostsToTry.takeFirst();
691
// no-multi or proxy error means we quit
692
if(!d->multi || proxyError) {
699
if(d->using_srv && !d->servers.isEmpty()) {
705
else if(!d->using_srv && d->opt_probe && d->probe_mode == 0) {
711
d->will_be_ssl = false;
719
d->errorCode = ErrConnectionRefused;
724
void AdvancedConnector::http_syncStarted()
729
void AdvancedConnector::http_syncFinished()
734
void AdvancedConnector::t_timeout()
736
// skip to next host, if there is one
737
if(!d->hostsToTry.isEmpty())
743
d->host = d->hostsToTry.takeFirst();
748
QString AdvancedConnector::host() const
750
return d->connectHost;