195
201
//----------------------------------------------------------------------------
196
202
// AdvancedConnector
197
203
//----------------------------------------------------------------------------
198
enum { Idle, Connecting, Connected };
204
typedef enum { Idle, Connecting, Connected } Mode;
205
typedef enum { Force, Probe, Never } LegacySSL;
199
207
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;
210
ByteStream *bs; //!< Socket to use
212
/* configuration values / "options" */
213
QString opt_host; //!< explicit host from config
214
quint16 opt_port; //!< explicit port from config
215
LegacySSL opt_ssl; //!< Whether to use legacy SSL support
216
Proxy proxy; //!< Proxy configuration
218
/* State tracking values */
219
Mode mode; //!< Idle, Connecting, Connected
220
QString host; //!< Host we currently try to connect to, set from connectToServer()
221
int port; //!< Port we currently try to connect to, set from connectToServer() and bs_error()
222
int errorCode; //!< Current error, if any
230
225
AdvancedConnector::AdvancedConnector(QObject *parent)
278
257
d->proxy = proxy;
281
void AdvancedConnector::setOptHostPort(const QString &host, quint16 _port)
260
void AdvancedConnector::setOptHostPort(const QString &_host, quint16 _port)
263
XDEBUG << "h:" << _host << "p:" << _port;
283
266
if(d->mode != Idle)
285
269
// empty host means disable explicit host support
287
d->opt_hosts.clear();
270
if(_host.isEmpty()) {
290
d->opt_hosts = QStringList() << host;
294
void AdvancedConnector::setOptHostsPort(const QStringList &_hosts, quint16 _port)
298
d->opt_hosts = _hosts;
299
275
d->opt_port = _port;
302
278
void AdvancedConnector::setOptProbe(bool b)
304
284
if(d->mode != Idle)
286
d->opt_ssl = (b ? Probe : Never);
309
289
void AdvancedConnector::setOptSSL(bool b)
311
295
if(d->mode != Idle)
297
d->opt_ssl = (b ? Force : Never);
316
300
void AdvancedConnector::connectToServer(const QString &server)
303
XDEBUG << "s:" << server;
318
306
if(d->mode != Idle)
320
308
if(server.isEmpty())
323
d->hostsToTry.clear();
324
311
d->errorCode = 0;
325
312
d->mode = Connecting;
327
d->connectHost.clear();
329
314
// 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;
315
d->host = QUrl::toAce(server);
316
if (d->host == QByteArray()) {
317
/* server contains invalid characters for DNS name, but maybe valid characters for connecting, like "::1" */
320
d->port = XMPP_DEFAULT_PORT;
340
322
if(d->proxy.type() == Proxy::HttpPoll) {
342
//if(!QCA::isSupported(QCA::CAP_SHA1))
343
// QCA::insertProvider(createProviderHash());
345
323
HttpPoll *s = new HttpPoll;
347
326
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
348
327
connect(s, SIGNAL(syncStarted()), SLOT(http_syncStarted()));
349
328
connect(s, SIGNAL(syncFinished()), SLOT(http_syncFinished()));
350
329
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
351
331
if(!d->proxy.user().isEmpty())
352
332
s->setAuth(d->proxy.user(), d->proxy.pass());
353
333
s->setPollInterval(d->proxy.pollInterval());
358
338
s->connectToHost(d->proxy.host(), d->proxy.port(), d->proxy.url());
360
340
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;
341
HttpConnect *s = new HttpConnect;
344
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
345
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
347
if(!d->opt_host.isEmpty()) {
348
d->host = d->opt_host;
349
d->port = d->opt_port;
352
if(!d->proxy.user().isEmpty())
353
s->setAuth(d->proxy.user(), d->proxy.pass());
355
s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port);
357
else if (d->proxy.type() == Proxy::Socks) {
358
SocksClient *s = new SocksClient;
361
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
362
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
364
if(!d->opt_host.isEmpty()) {
365
d->host = d->opt_host;
366
d->port = d->opt_port;
369
if(!d->proxy.user().isEmpty())
370
s->setAuth(d->proxy.user(), d->proxy.pass());
372
s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port);
373
if(!d->opt_hosts.isEmpty()) {
374
d->hostsToTry = d->opt_hosts;
375
d->host = d->hostsToTry.takeFirst();
375
BSocket *s = new BSocket;
378
XDEBUG << "Adding socket:" << s;
381
connect(s, SIGNAL(connected()), SLOT(bs_connected()));
382
connect(s, SIGNAL(error(int)), SLOT(bs_error(int)));
384
if(!d->opt_host.isEmpty()) {
385
d->host = d->opt_host;
376
386
d->port = d->opt_port;
382
QPointer<QObject> self = this;
383
srvLookup(d->server);
387
d->srv.resolveSrvOnly(d->server, "xmpp-client", "tcp");
387
s->connectToHost(d->host, d->port);
389
} else if (d->opt_ssl != Never) {
390
d->port = XMPP_LEGACY_PORT;
393
s->connectToHost(XMPP_CLIENT_SRV, XMPP_CLIENT_TRANSPORT, d->host, d->port);
415
420
return d->errorCode;
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
423
void AdvancedConnector::bs_connected()
595
d->connectTimeout.stop();
597
428
if(d->proxy.type() == Proxy::None) {
598
429
QHostAddress h = (static_cast<BSocket*>(d->bs))->peerAddress();
599
430
int p = (static_cast<BSocket*>(d->bs))->peerPort();
600
431
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)
434
bool ssl_disabled = d->proxy.type() == Proxy::None &&
435
(static_cast<BSocket*>(d->bs)->isPeerFromSrv() || d->port == XMPP_DEFAULT_PORT);
436
// only allow ssl override if proxy==poll or host:port or when probing legacy ssl port
437
if(d->proxy.type() != Proxy::HttpPoll && d->opt_ssl != Never && !ssl_disabled)
609
440
d->mode = Connected;
613
444
void AdvancedConnector::bs_error(int x)
615
450
if(d->mode == Connected) {
616
451
d->errorCode = ErrStream;
682
// try next host, if any
683
if(!d->hostsToTry.isEmpty())
686
d->host = d->hostsToTry.takeFirst();
691
517
// no-multi or proxy error means we quit
692
if(!d->multi || proxyError) {
694
520
d->errorCode = err;
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;
526
if we shall probe the ssl legacy port, and we just did that (port=legacy),
527
then try to connect to the normal port instead
529
if(d->opt_ssl == Probe && d->port == XMPP_LEGACY_PORT) {
533
BSocket *s = static_cast<BSocket*>(d->bs);
534
d->port = XMPP_DEFAULT_PORT;
535
s->connectToHost(XMPP_CLIENT_SRV, XMPP_CLIENT_TRANSPORT, d->host, d->port);
537
/* otherwise we have no fallbacks and must have failed to connect */
715
539
#ifdef XMPP_DEBUG
719
543
d->errorCode = ErrConnectionRefused;