~ubuntu-branches/ubuntu/oneiric/psi/oneiric

« back to all changes in this revision

Viewing changes to iris/jabber/s5b.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * s5b.cpp - direct connection protocol via tcp
 
3
 * Copyright (C) 2003  Justin Karneges
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 *
 
19
 */
 
20
 
 
21
#include"s5b.h"
 
22
 
 
23
#include<qtimer.h>
 
24
#include<qguardedptr.h>
 
25
#include<stdlib.h>
 
26
#include<qca.h>
 
27
#include"xmpp_xmlcommon.h"
 
28
#include"socks.h"
 
29
#include"safedelete.h"
 
30
 
 
31
#ifdef Q_OS_WIN
 
32
# include <windows.h>
 
33
#else
 
34
# include <netinet/in.h>
 
35
#endif
 
36
 
 
37
#define MAXSTREAMHOSTS 5
 
38
 
 
39
//#define S5B_DEBUG
 
40
 
 
41
namespace XMPP {
 
42
 
 
43
static QString makeKey(const QString &sid, const Jid &initiator, const Jid &target)
 
44
{
 
45
        QString str = sid + initiator.full() + target.full();
 
46
        return QCA::SHA1::hashToString(str.utf8());
 
47
}
 
48
 
 
49
static bool haveHost(const StreamHostList &list, const Jid &j)
 
50
{
 
51
        for(StreamHostList::ConstIterator it = list.begin(); it != list.end(); ++it) {
 
52
                if((*it).jid().compare(j))
 
53
                        return true;
 
54
        }
 
55
        return false;
 
56
}
 
57
 
 
58
class S5BManager::Item : public QObject
 
59
{
 
60
        Q_OBJECT
 
61
public:
 
62
        enum { Idle, Initiator, Target, Active };
 
63
        enum { ErrRefused, ErrConnect, ErrWrongHost, ErrProxy };
 
64
        enum { Unknown, Fast, NotFast };
 
65
        S5BManager *m;
 
66
        int state;
 
67
        QString sid, key, out_key, out_id, in_id;
 
68
        Jid self, peer;
 
69
        StreamHostList in_hosts;
 
70
        JT_S5B *task, *proxy_task;
 
71
        SocksClient *client, *client_out;
 
72
        SocksUDP *client_udp, *client_out_udp;
 
73
        S5BConnector *conn, *proxy_conn;
 
74
        bool wantFast;
 
75
        StreamHost proxy;
 
76
        int targetMode; // initiator sets this once it figures it out
 
77
        bool fast; // target sets this
 
78
        bool activated;
 
79
        bool lateProxy;
 
80
        bool connSuccess;
 
81
        bool localFailed, remoteFailed;
 
82
        bool allowIncoming;
 
83
        bool udp;
 
84
        int statusCode;
 
85
        Jid activatedStream;
 
86
 
 
87
        Item(S5BManager *manager);
 
88
        ~Item();
 
89
 
 
90
        void reset();
 
91
        void startInitiator(const QString &_sid, const Jid &_self, const Jid &_peer, bool fast, bool udp);
 
92
        void startTarget(const QString &_sid, const Jid &_self, const Jid &_peer, const StreamHostList &hosts, const QString &iq_id, bool fast, bool udp);
 
93
        void handleFast(const StreamHostList &hosts, const QString &iq_id);
 
94
 
 
95
        void doOutgoing();
 
96
        void doIncoming();
 
97
        void setIncomingClient(SocksClient *sc);
 
98
        void incomingActivate(const Jid &streamHost);
 
99
 
 
100
signals:
 
101
        void accepted();
 
102
        void tryingHosts(const StreamHostList &list);
 
103
        void proxyConnect();
 
104
        void waitingForActivation();
 
105
        void connected();
 
106
        void error(int);
 
107
 
 
108
private slots:
 
109
        void jt_finished();
 
110
        void conn_result(bool b);
 
111
        void proxy_result(bool b);
 
112
        void proxy_finished();
 
113
        void sc_readyRead();
 
114
        void sc_bytesWritten(int);
 
115
        void sc_error(int);
 
116
 
 
117
private:
 
118
        void doConnectError();
 
119
        void tryActivation();
 
120
        void checkForActivation();
 
121
        void checkFailure();
 
122
        void finished();
 
123
};
 
124
 
 
125
//----------------------------------------------------------------------------
 
126
// S5BDatagram
 
127
//----------------------------------------------------------------------------
 
128
S5BDatagram::S5BDatagram()
 
129
{
 
130
        _source = 0;
 
131
        _dest = 0;
 
132
}
 
133
 
 
134
S5BDatagram::S5BDatagram(int source, int dest, const QByteArray &data)
 
135
{
 
136
        _source = source;
 
137
        _dest = dest;
 
138
        _buf = data;
 
139
}
 
140
 
 
141
int S5BDatagram::sourcePort() const
 
142
{
 
143
        return _source;
 
144
}
 
145
 
 
146
int S5BDatagram::destPort() const
 
147
{
 
148
        return _dest;
 
149
}
 
150
 
 
151
QByteArray S5BDatagram::data() const
 
152
{
 
153
        return _buf;
 
154
}
 
155
 
 
156
//----------------------------------------------------------------------------
 
157
// S5BConnection
 
158
//----------------------------------------------------------------------------
 
159
class S5BConnection::Private
 
160
{
 
161
public:
 
162
        S5BManager *m;
 
163
        SocksClient *sc;
 
164
        SocksUDP *su;
 
165
        int state;
 
166
        Jid peer;
 
167
        QString sid;
 
168
        bool remote;
 
169
        bool switched;
 
170
        bool notifyRead, notifyClose;
 
171
        int id;
 
172
        S5BRequest req;
 
173
        Jid proxy;
 
174
        Mode mode;
 
175
        QPtrList<S5BDatagram> dglist;
 
176
};
 
177
 
 
178
static int id_conn = 0;
 
179
static int num_conn = 0;
 
180
 
 
181
S5BConnection::S5BConnection(S5BManager *m, QObject *parent)
 
182
:ByteStream(parent)
 
183
{
 
184
        d = new Private;
 
185
        d->m = m;
 
186
        d->sc = 0;
 
187
        d->su = 0;
 
188
 
 
189
        ++num_conn;
 
190
        d->id = id_conn++;
 
191
#ifdef S5B_DEBUG
 
192
        printf("S5BConnection[%d]: constructing, count=%d, %p\n", d->id, num_conn, this);
 
193
#endif
 
194
 
 
195
        reset();
 
196
}
 
197
 
 
198
S5BConnection::~S5BConnection()
 
199
{
 
200
        reset(true);
 
201
 
 
202
        --num_conn;
 
203
#ifdef S5B_DEBUG
 
204
        printf("S5BConnection[%d]: destructing, count=%d\n", d->id, num_conn);
 
205
#endif
 
206
 
 
207
        delete d;
 
208
}
 
209
 
 
210
void S5BConnection::reset(bool clear)
 
211
{
 
212
        d->m->con_unlink(this);
 
213
        if(clear && d->sc) {
 
214
                delete d->sc;
 
215
                d->sc = 0;
 
216
        }
 
217
        delete d->su;
 
218
        d->su = 0;
 
219
        if(clear) {
 
220
                d->dglist.setAutoDelete(true);
 
221
                d->dglist.clear();
 
222
                d->dglist.setAutoDelete(false);
 
223
        }
 
224
        d->state = Idle;
 
225
        d->peer = Jid();
 
226
        d->sid = QString();
 
227
        d->remote = false;
 
228
        d->switched = false;
 
229
        d->notifyRead = false;
 
230
        d->notifyClose = false;
 
231
}
 
232
 
 
233
Jid S5BConnection::proxy() const
 
234
{
 
235
        return d->proxy;
 
236
}
 
237
 
 
238
void S5BConnection::setProxy(const Jid &proxy)
 
239
{
 
240
        d->proxy = proxy;
 
241
}
 
242
 
 
243
void S5BConnection::connectToJid(const Jid &peer, const QString &sid, Mode m)
 
244
{
 
245
        reset(true);
 
246
        if(!d->m->isAcceptableSID(peer, sid))
 
247
                return;
 
248
 
 
249
        d->peer = peer;
 
250
        d->sid = sid;
 
251
        d->state = Requesting;
 
252
        d->mode = m;
 
253
#ifdef S5B_DEBUG
 
254
        printf("S5BConnection[%d]: connecting %s [%s]\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
255
#endif
 
256
        d->m->con_connect(this);
 
257
}
 
258
 
 
259
void S5BConnection::accept()
 
260
{
 
261
        if(d->state != WaitingForAccept)
 
262
                return;
 
263
 
 
264
        d->state = Connecting;
 
265
#ifdef S5B_DEBUG
 
266
        printf("S5BConnection[%d]: accepting %s [%s]\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
267
#endif
 
268
        d->m->con_accept(this);
 
269
}
 
270
 
 
271
void S5BConnection::close()
 
272
{
 
273
        if(d->state == Idle)
 
274
                return;
 
275
 
 
276
        if(d->state == WaitingForAccept)
 
277
                d->m->con_reject(this);
 
278
        else if(d->state == Active)
 
279
                d->sc->close();
 
280
#ifdef S5B_DEBUG
 
281
        printf("S5BConnection[%d]: closing %s [%s]\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
282
#endif
 
283
        reset();
 
284
}
 
285
 
 
286
Jid S5BConnection::peer() const
 
287
{
 
288
        return d->peer;
 
289
}
 
290
 
 
291
QString S5BConnection::sid() const
 
292
{
 
293
        return d->sid;
 
294
}
 
295
 
 
296
bool S5BConnection::isRemote() const
 
297
{
 
298
        return d->remote;
 
299
}
 
300
 
 
301
S5BConnection::Mode S5BConnection::mode() const
 
302
{
 
303
        return d->mode;
 
304
}
 
305
 
 
306
int S5BConnection::state() const
 
307
{
 
308
        return d->state;
 
309
}
 
310
 
 
311
bool S5BConnection::isOpen() const
 
312
{
 
313
        if(d->state == Active)
 
314
                return true;
 
315
        else
 
316
                return false;
 
317
}
 
318
 
 
319
void S5BConnection::write(const QByteArray &buf)
 
320
{
 
321
        if(d->state == Active && d->mode == Stream)
 
322
                d->sc->write(buf);
 
323
}
 
324
 
 
325
QByteArray S5BConnection::read(int bytes)
 
326
{
 
327
        if(d->sc)
 
328
                return d->sc->read(bytes);
 
329
        else
 
330
                return QByteArray();
 
331
}
 
332
 
 
333
int S5BConnection::bytesAvailable() const
 
334
{
 
335
        if(d->sc)
 
336
                return d->sc->bytesAvailable();
 
337
        else
 
338
                return 0;
 
339
}
 
340
 
 
341
int S5BConnection::bytesToWrite() const
 
342
{
 
343
        if(d->state == Active)
 
344
                return d->sc->bytesToWrite();
 
345
        else
 
346
                return 0;
 
347
}
 
348
 
 
349
void S5BConnection::writeDatagram(const S5BDatagram &i)
 
350
{
 
351
        QByteArray buf(i.data().size() + 4);
 
352
        ushort ssp = htons(i.sourcePort());
 
353
        ushort sdp = htons(i.destPort());
 
354
        QByteArray data = i.data();
 
355
        memcpy(buf.data(), &ssp, 2);
 
356
        memcpy(buf.data() + 2, &sdp, 2);
 
357
        memcpy(buf.data() + 4, data.data(), data.size());
 
358
        sendUDP(buf);
 
359
}
 
360
 
 
361
S5BDatagram S5BConnection::readDatagram()
 
362
{
 
363
        if(d->dglist.isEmpty())
 
364
                return S5BDatagram();
 
365
        S5BDatagram *i = d->dglist.getFirst();
 
366
        d->dglist.removeRef(i);
 
367
        S5BDatagram val = *i;
 
368
        delete i;
 
369
        return val;
 
370
}
 
371
 
 
372
int S5BConnection::datagramsAvailable() const
 
373
{
 
374
        return d->dglist.count();
 
375
}
 
376
 
 
377
void S5BConnection::man_waitForAccept(const S5BRequest &r)
 
378
{
 
379
        d->state = WaitingForAccept;
 
380
        d->remote = true;
 
381
        d->req = r;
 
382
        d->peer = r.from;
 
383
        d->sid = r.sid;
 
384
        d->mode = r.udp ? Datagram : Stream;
 
385
}
 
386
 
 
387
void S5BConnection::man_clientReady(SocksClient *sc, SocksUDP *sc_udp)
 
388
{
 
389
        d->sc = sc;
 
390
        connect(d->sc, SIGNAL(connectionClosed()), SLOT(sc_connectionClosed()));
 
391
        connect(d->sc, SIGNAL(delayedCloseFinished()), SLOT(sc_delayedCloseFinished()));
 
392
        connect(d->sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
393
        connect(d->sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
394
        connect(d->sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
395
 
 
396
        if(sc_udp) {
 
397
                d->su = sc_udp;
 
398
                connect(d->su, SIGNAL(packetReady(const QByteArray &)), SLOT(su_packetReady(const QByteArray &)));
 
399
        }
 
400
 
 
401
        d->state = Active;
 
402
#ifdef S5B_DEBUG
 
403
        printf("S5BConnection[%d]: %s [%s] <<< success >>>\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
404
#endif
 
405
 
 
406
        // bytes already in the stream?
 
407
        if(d->sc->bytesAvailable()) {
 
408
#ifdef S5B_DEBUG
 
409
                printf("Stream has %d bytes in it.\n", d->sc->bytesAvailable());
 
410
#endif
 
411
                d->notifyRead = true;
 
412
        }
 
413
        // closed before it got here?
 
414
        if(!d->sc->isOpen()) {
 
415
#ifdef S5B_DEBUG
 
416
                printf("Stream was closed before S5B request finished?\n");
 
417
#endif
 
418
                d->notifyClose = true;
 
419
        }
 
420
        if(d->notifyRead || d->notifyClose)
 
421
                QTimer::singleShot(0, this, SLOT(doPending()));
 
422
        connected();
 
423
}
 
424
 
 
425
void S5BConnection::doPending()
 
426
{
 
427
        if(d->notifyRead) {
 
428
                if(d->notifyClose)
 
429
                        QTimer::singleShot(0, this, SLOT(doPending()));
 
430
                sc_readyRead();
 
431
        }
 
432
        else if(d->notifyClose)
 
433
                sc_connectionClosed();
 
434
}
 
435
 
 
436
void S5BConnection::man_udpReady(const QByteArray &buf)
 
437
{
 
438
        handleUDP(buf);
 
439
}
 
440
 
 
441
void S5BConnection::man_failed(int x)
 
442
{
 
443
        reset(true);
 
444
        if(x == S5BManager::Item::ErrRefused)
 
445
                error(ErrRefused);
 
446
        if(x == S5BManager::Item::ErrConnect)
 
447
                error(ErrConnect);
 
448
        if(x == S5BManager::Item::ErrWrongHost)
 
449
                error(ErrConnect);
 
450
        if(x == S5BManager::Item::ErrProxy)
 
451
                error(ErrProxy);
 
452
}
 
453
 
 
454
void S5BConnection::sc_connectionClosed()
 
455
{
 
456
        // if we have a pending read notification, postpone close
 
457
        if(d->notifyRead) {
 
458
#ifdef S5B_DEBUG
 
459
                printf("closed while pending read\n");
 
460
#endif
 
461
                d->notifyClose = true;
 
462
                return;
 
463
        }
 
464
        d->notifyClose = false;
 
465
        reset();
 
466
        connectionClosed();
 
467
}
 
468
 
 
469
void S5BConnection::sc_delayedCloseFinished()
 
470
{
 
471
        // echo
 
472
        delayedCloseFinished();
 
473
}
 
474
 
 
475
void S5BConnection::sc_readyRead()
 
476
{
 
477
        if(d->mode == Datagram) {
 
478
                // throw the data away
 
479
                d->sc->read();
 
480
                return;
 
481
        }
 
482
 
 
483
        d->notifyRead = false;
 
484
        // echo
 
485
        readyRead();
 
486
}
 
487
 
 
488
void S5BConnection::sc_bytesWritten(int x)
 
489
{
 
490
        // echo
 
491
        bytesWritten(x);
 
492
}
 
493
 
 
494
void S5BConnection::sc_error(int)
 
495
{
 
496
        reset();
 
497
        error(ErrSocket);
 
498
}
 
499
 
 
500
void S5BConnection::su_packetReady(const QByteArray &buf)
 
501
{
 
502
        handleUDP(buf);
 
503
}
 
504
 
 
505
void S5BConnection::handleUDP(const QByteArray &buf)
 
506
{
 
507
        // must be at least 4 bytes, to accomodate virtual ports
 
508
        if(buf.size() < 4)
 
509
                return; // drop
 
510
 
 
511
        ushort ssp, sdp;
 
512
        memcpy(&ssp, buf.data(), 2);
 
513
        memcpy(&sdp, buf.data() + 2, 2);
 
514
        int source = ntohs(ssp);
 
515
        int dest = ntohs(sdp);
 
516
        QByteArray data(buf.size() - 4);
 
517
        memcpy(data.data(), buf.data() + 4, data.size());
 
518
        d->dglist.append(new S5BDatagram(source, dest, data));
 
519
 
 
520
        datagramReady();
 
521
}
 
522
 
 
523
void S5BConnection::sendUDP(const QByteArray &buf)
 
524
{
 
525
        if(d->su)
 
526
                d->su->write(buf);
 
527
        else
 
528
                d->m->con_sendUDP(this, buf);
 
529
}
 
530
 
 
531
//----------------------------------------------------------------------------
 
532
// S5BManager
 
533
//----------------------------------------------------------------------------
 
534
class S5BManager::Entry
 
535
{
 
536
public:
 
537
        Entry()
 
538
        {
 
539
                i = 0;
 
540
                query = 0;
 
541
                udp_init = false;
 
542
        }
 
543
 
 
544
        ~Entry()
 
545
        {
 
546
                delete query;
 
547
        }
 
548
 
 
549
        S5BConnection *c;
 
550
        Item *i;
 
551
        QString sid;
 
552
        JT_S5B *query;
 
553
        StreamHost proxyInfo;
 
554
        QGuardedPtr<S5BServer> relatedServer;
 
555
 
 
556
        bool udp_init;
 
557
        QHostAddress udp_addr;
 
558
        int udp_port;
 
559
};
 
560
 
 
561
class S5BManager::Private
 
562
{
 
563
public:
 
564
        Client *client;
 
565
        S5BServer *serv;
 
566
        QPtrList<Entry> activeList;
 
567
        S5BConnectionList incomingConns;
 
568
        JT_PushS5B *ps;
 
569
};
 
570
 
 
571
S5BManager::S5BManager(Client *parent)
 
572
:QObject(parent)
 
573
{
 
574
        d = new Private;
 
575
        d->client = parent;
 
576
        d->serv = 0;
 
577
        d->activeList.setAutoDelete(true);
 
578
 
 
579
        d->ps = new JT_PushS5B(d->client->rootTask());
 
580
        connect(d->ps, SIGNAL(incoming(const S5BRequest &)), SLOT(ps_incoming(const S5BRequest &)));
 
581
        connect(d->ps, SIGNAL(incomingUDPSuccess(const Jid &, const QString &)), SLOT(ps_incomingUDPSuccess(const Jid &, const QString &)));
 
582
        connect(d->ps, SIGNAL(incomingActivate(const Jid &, const QString &, const Jid &)), SLOT(ps_incomingActivate(const Jid &, const QString &, const Jid &)));
 
583
}
 
584
 
 
585
S5BManager::~S5BManager()
 
586
{
 
587
        setServer(0);
 
588
        d->incomingConns.setAutoDelete(true);
 
589
        d->incomingConns.clear();
 
590
        delete d->ps;
 
591
        delete d;
 
592
}
 
593
 
 
594
Client *S5BManager::client() const
 
595
{
 
596
        return d->client;
 
597
}
 
598
 
 
599
S5BServer *S5BManager::server() const
 
600
{
 
601
        return d->serv;
 
602
}
 
603
 
 
604
void S5BManager::setServer(S5BServer *serv)
 
605
{
 
606
        if(d->serv) {
 
607
                d->serv->unlink(this);
 
608
                d->serv = 0;
 
609
        }
 
610
 
 
611
        if(serv) {
 
612
                d->serv = serv;
 
613
                d->serv->link(this);
 
614
        }
 
615
}
 
616
 
 
617
S5BConnection *S5BManager::createConnection()
 
618
{
 
619
        S5BConnection *c = new S5BConnection(this);
 
620
        return c;
 
621
}
 
622
 
 
623
S5BConnection *S5BManager::takeIncoming()
 
624
{
 
625
        if(d->incomingConns.isEmpty())
 
626
                return 0;
 
627
 
 
628
        S5BConnection *c = d->incomingConns.getFirst();
 
629
        d->incomingConns.removeRef(c);
 
630
 
 
631
        // move to activeList
 
632
        Entry *e = new Entry;
 
633
        e->c = c;
 
634
        e->sid = c->d->sid;
 
635
        d->activeList.append(e);
 
636
 
 
637
        return c;
 
638
}
 
639
 
 
640
void S5BManager::ps_incoming(const S5BRequest &req)
 
641
{
 
642
#ifdef S5B_DEBUG
 
643
        printf("S5BManager: incoming from %s\n", req.from.full().latin1());
 
644
#endif
 
645
 
 
646
        bool ok = false;
 
647
        // ensure we don't already have an incoming connection from this peer+sid
 
648
        S5BConnection *c = findIncoming(req.from, req.sid);
 
649
        if(!c) {
 
650
                // do we have an active entry with this sid already?
 
651
                Entry *e = findEntryBySID(req.from, req.sid);
 
652
                if(e) {
 
653
                        if(e->i) {
 
654
                                // loopback
 
655
                                if(req.from.compare(d->client->jid()) && (req.id == e->i->out_id)) {
 
656
#ifdef S5B_DEBUG
 
657
                                        printf("ALLOWED: loopback\n");
 
658
#endif
 
659
                                        ok = true;
 
660
                                }
 
661
                                // allowed by 'fast mode'
 
662
                                else if(e->i->state == Item::Initiator && e->i->targetMode == Item::Unknown) {
 
663
#ifdef S5B_DEBUG
 
664
                                        printf("ALLOWED: fast-mode\n");
 
665
#endif
 
666
                                        e->i->handleFast(req.hosts, req.id);
 
667
                                        return;
 
668
                                }
 
669
                        }
 
670
                }
 
671
                else {
 
672
#ifdef S5B_DEBUG
 
673
                        printf("ALLOWED: we don't have it\n");
 
674
#endif
 
675
                        ok = true;
 
676
                }
 
677
        }
 
678
        if(!ok) {
 
679
                d->ps->respondError(req.from, req.id, 406, "SID in use");
 
680
                return;
 
681
        }
 
682
 
 
683
        // create an incoming connection
 
684
        c = new S5BConnection(this);
 
685
        c->man_waitForAccept(req);
 
686
        d->incomingConns.append(c);
 
687
        incomingReady();
 
688
}
 
689
 
 
690
void S5BManager::ps_incomingUDPSuccess(const Jid &from, const QString &key)
 
691
{
 
692
        Entry *e = findEntryByHash(key);
 
693
        if(e && e->i) {
 
694
                if(e->i->conn)
 
695
                        e->i->conn->man_udpSuccess(from);
 
696
                else if(e->i->proxy_conn)
 
697
                        e->i->proxy_conn->man_udpSuccess(from);
 
698
        }
 
699
}
 
700
 
 
701
void S5BManager::ps_incomingActivate(const Jid &from, const QString &sid, const Jid &streamHost)
 
702
{
 
703
        Entry *e = findEntryBySID(from, sid);
 
704
        if(e && e->i)
 
705
                e->i->incomingActivate(streamHost);
 
706
}
 
707
 
 
708
void S5BManager::doSuccess(const Jid &peer, const QString &id, const Jid &streamHost)
 
709
{
 
710
        d->ps->respondSuccess(peer, id, streamHost);
 
711
}
 
712
 
 
713
void S5BManager::doError(const Jid &peer, const QString &id, int code, const QString &str)
 
714
{
 
715
        d->ps->respondError(peer, id, code, str);
 
716
}
 
717
 
 
718
void S5BManager::doActivate(const Jid &peer, const QString &sid, const Jid &streamHost)
 
719
{
 
720
        d->ps->sendActivate(peer, sid, streamHost);
 
721
}
 
722
 
 
723
QString S5BManager::genUniqueSID(const Jid &peer) const
 
724
{
 
725
        // get unused key
 
726
        QString sid;
 
727
        do {
 
728
                sid = "s5b_";
 
729
                for(int i = 0; i < 4; ++i) {
 
730
                        int word = rand() & 0xffff;
 
731
                        for(int n = 0; n < 4; ++n) {
 
732
                                QString s;
 
733
                                s.sprintf("%x", (word >> (n * 4)) & 0xf);
 
734
                                sid.append(s);
 
735
                        }
 
736
                }
 
737
        } while(!isAcceptableSID(peer, sid));
 
738
        return sid;
 
739
}
 
740
 
 
741
bool S5BManager::isAcceptableSID(const Jid &peer, const QString &sid) const
 
742
{
 
743
        QString key = makeKey(sid, d->client->jid(), peer);
 
744
        QString key_out = makeKey(sid, peer, d->client->jid());
 
745
 
 
746
        // if we have a server, then check through it
 
747
        if(d->serv) {
 
748
                if(findServerEntryByHash(key) || findServerEntryByHash(key_out))
 
749
                        return false;
 
750
        }
 
751
        else {
 
752
                if(findEntryByHash(key) || findEntryByHash(key_out))
 
753
                        return false;
 
754
        }
 
755
        return true;
 
756
}
 
757
 
 
758
S5BConnection *S5BManager::findIncoming(const Jid &from, const QString &sid) const
 
759
{
 
760
        QPtrListIterator<S5BConnection> it(d->incomingConns);
 
761
        for(S5BConnection *c; (c = it.current()); ++it) {
 
762
                if(c->d->peer.compare(from) && c->d->sid == sid)
 
763
                        return c;
 
764
        }
 
765
        return 0;
 
766
}
 
767
 
 
768
S5BManager::Entry *S5BManager::findEntry(S5BConnection *c) const
 
769
{
 
770
        QPtrListIterator<Entry> it(d->activeList);
 
771
        for(Entry *e; (e = it.current()); ++it) {
 
772
                if(e->c == c)
 
773
                        return e;
 
774
        }
 
775
        return 0;
 
776
}
 
777
 
 
778
S5BManager::Entry *S5BManager::findEntry(Item *i) const
 
779
{
 
780
        QPtrListIterator<Entry> it(d->activeList);
 
781
        for(Entry *e; (e = it.current()); ++it) {
 
782
                if(e->i == i)
 
783
                        return e;
 
784
        }
 
785
        return 0;
 
786
}
 
787
 
 
788
S5BManager::Entry *S5BManager::findEntryByHash(const QString &key) const
 
789
{
 
790
        QPtrListIterator<Entry> it(d->activeList);
 
791
        for(Entry *e; (e = it.current()); ++it) {
 
792
                if(e->i && e->i->key == key)
 
793
                        return e;
 
794
        }
 
795
        return 0;
 
796
}
 
797
 
 
798
S5BManager::Entry *S5BManager::findEntryBySID(const Jid &peer, const QString &sid) const
 
799
{
 
800
        QPtrListIterator<Entry> it(d->activeList);
 
801
        for(Entry *e; (e = it.current()); ++it) {
 
802
                if(e->i && e->i->peer.compare(peer) && e->sid == sid)
 
803
                        return e;
 
804
        }
 
805
        return 0;
 
806
}
 
807
 
 
808
S5BManager::Entry *S5BManager::findServerEntryByHash(const QString &key) const
 
809
{
 
810
        const QPtrList<S5BManager> &manList = d->serv->managerList();
 
811
        QPtrListIterator<S5BManager> it(manList);
 
812
        for(S5BManager *m; (m = it.current()); ++it) {
 
813
                Entry *e = m->findEntryByHash(key);
 
814
                if(e)
 
815
                        return e;
 
816
        }
 
817
        return 0;
 
818
}
 
819
 
 
820
bool S5BManager::srv_ownsHash(const QString &key) const
 
821
{
 
822
        if(findEntryByHash(key))
 
823
                return true;
 
824
        return false;
 
825
}
 
826
 
 
827
void S5BManager::srv_incomingReady(SocksClient *sc, const QString &key)
 
828
{
 
829
        Entry *e = findEntryByHash(key);
 
830
        if(!e->i->allowIncoming) {
 
831
                sc->requestDeny();
 
832
                SafeDelete::deleteSingle(sc);
 
833
                return;
 
834
        }
 
835
        if(e->c->d->mode == S5BConnection::Datagram)
 
836
                sc->grantUDPAssociate("", 0);
 
837
        else
 
838
                sc->grantConnect();
 
839
        e->relatedServer = (S5BServer *)sender();
 
840
        e->i->setIncomingClient(sc);
 
841
}
 
842
 
 
843
void S5BManager::srv_incomingUDP(bool init, const QHostAddress &addr, int port, const QString &key, const QByteArray &data)
 
844
{
 
845
        Entry *e = findEntryByHash(key);
 
846
        if(!e->c->d->mode != S5BConnection::Datagram)
 
847
                return; // this key isn't in udp mode?  drop!
 
848
 
 
849
        if(init) {
 
850
                if(e->udp_init)
 
851
                        return; // only init once
 
852
 
 
853
                // lock on to this sender
 
854
                e->udp_addr = addr;
 
855
                e->udp_port = port;
 
856
                e->udp_init = true;
 
857
 
 
858
                // reply that initialization was successful
 
859
                d->ps->sendUDPSuccess(e->c->d->peer, key);
 
860
                return;
 
861
        }
 
862
 
 
863
        // not initialized yet?  something went wrong
 
864
        if(!e->udp_init)
 
865
                return;
 
866
 
 
867
        // must come from same source as when initialized
 
868
        if(addr.toString() != e->udp_addr.toString() || port != e->udp_port)
 
869
                return;
 
870
 
 
871
        e->c->man_udpReady(data);
 
872
}
 
873
 
 
874
void S5BManager::srv_unlink()
 
875
{
 
876
        d->serv = 0;
 
877
}
 
878
 
 
879
void S5BManager::con_connect(S5BConnection *c)
 
880
{
 
881
        if(findEntry(c))
 
882
                return;
 
883
        Entry *e = new Entry;
 
884
        e->c = c;
 
885
        e->sid = c->d->sid;
 
886
        d->activeList.append(e);
 
887
 
 
888
        if(c->d->proxy.isValid()) {
 
889
                queryProxy(e);
 
890
                return;
 
891
        }
 
892
        entryContinue(e);
 
893
}
 
894
 
 
895
void S5BManager::con_accept(S5BConnection *c)
 
896
{
 
897
        Entry *e = findEntry(c);
 
898
        if(!e)
 
899
                return;
 
900
 
 
901
        if(e->c->d->req.fast) {
 
902
                if(targetShouldOfferProxy(e)) {
 
903
                        queryProxy(e);
 
904
                        return;
 
905
                }
 
906
        }
 
907
        entryContinue(e);
 
908
}
 
909
 
 
910
void S5BManager::con_reject(S5BConnection *c)
 
911
{
 
912
        d->ps->respondError(c->d->peer, c->d->req.id, 406, "Not acceptable");
 
913
}
 
914
 
 
915
void S5BManager::con_unlink(S5BConnection *c)
 
916
{
 
917
        Entry *e = findEntry(c);
 
918
        if(!e)
 
919
                return;
 
920
 
 
921
        // active incoming request?  cancel it
 
922
        if(e->i && e->i->conn)
 
923
                d->ps->respondError(e->i->peer, e->i->out_id, 406, "Not acceptable");
 
924
        delete e->i;
 
925
        d->activeList.removeRef(e);
 
926
}
 
927
 
 
928
void S5BManager::con_sendUDP(S5BConnection *c, const QByteArray &buf)
 
929
{
 
930
        Entry *e = findEntry(c);
 
931
        if(!e)
 
932
                return;
 
933
        if(!e->udp_init)
 
934
                return;
 
935
 
 
936
        if(e->relatedServer)
 
937
                e->relatedServer->writeUDP(e->udp_addr, e->udp_port, buf);
 
938
}
 
939
 
 
940
void S5BManager::item_accepted()
 
941
{
 
942
        Item *i = (Item *)sender();
 
943
        Entry *e = findEntry(i);
 
944
 
 
945
        e->c->accepted(); // signal
 
946
}
 
947
 
 
948
void S5BManager::item_tryingHosts(const StreamHostList &list)
 
949
{
 
950
        Item *i = (Item *)sender();
 
951
        Entry *e = findEntry(i);
 
952
 
 
953
        e->c->tryingHosts(list); // signal
 
954
}
 
955
 
 
956
void S5BManager::item_proxyConnect()
 
957
{
 
958
        Item *i = (Item *)sender();
 
959
        Entry *e = findEntry(i);
 
960
 
 
961
        e->c->proxyConnect(); // signal
 
962
}
 
963
 
 
964
void S5BManager::item_waitingForActivation()
 
965
{
 
966
        Item *i = (Item *)sender();
 
967
        Entry *e = findEntry(i);
 
968
 
 
969
        e->c->waitingForActivation(); // signal
 
970
}
 
971
 
 
972
void S5BManager::item_connected()
 
973
{
 
974
        Item *i = (Item *)sender();
 
975
        Entry *e = findEntry(i);
 
976
 
 
977
        // grab the client
 
978
        SocksClient *client = i->client;
 
979
        i->client = 0;
 
980
        SocksUDP *client_udp = i->client_udp;
 
981
        i->client_udp = 0;
 
982
 
 
983
        // give it to the connection
 
984
        e->c->man_clientReady(client, client_udp);
 
985
}
 
986
 
 
987
void S5BManager::item_error(int x)
 
988
{
 
989
        Item *i = (Item *)sender();
 
990
        Entry *e = findEntry(i);
 
991
 
 
992
        e->c->man_failed(x);
 
993
}
 
994
 
 
995
void S5BManager::entryContinue(Entry *e)
 
996
{
 
997
        e->i = new Item(this);
 
998
        e->i->proxy = e->proxyInfo;
 
999
 
 
1000
        connect(e->i, SIGNAL(accepted()), SLOT(item_accepted()));
 
1001
        connect(e->i, SIGNAL(tryingHosts(const StreamHostList &)), SLOT(item_tryingHosts(const StreamHostList &)));
 
1002
        connect(e->i, SIGNAL(proxyConnect()), SLOT(item_proxyConnect()));
 
1003
        connect(e->i, SIGNAL(waitingForActivation()), SLOT(item_waitingForActivation()));
 
1004
        connect(e->i, SIGNAL(connected()), SLOT(item_connected()));
 
1005
        connect(e->i, SIGNAL(error(int)), SLOT(item_error(int)));
 
1006
 
 
1007
        if(e->c->isRemote()) {
 
1008
                const S5BRequest &req = e->c->d->req;
 
1009
                e->i->startTarget(e->sid, d->client->jid(), e->c->d->peer, req.hosts, req.id, req.fast, req.udp);
 
1010
        }
 
1011
        else {
 
1012
                e->i->startInitiator(e->sid, d->client->jid(), e->c->d->peer, true, e->c->d->mode == S5BConnection::Datagram ? true: false);
 
1013
                e->c->requesting(); // signal
 
1014
        }
 
1015
}
 
1016
 
 
1017
void S5BManager::queryProxy(Entry *e)
 
1018
{
 
1019
        QGuardedPtr<QObject> self = this;
 
1020
        e->c->proxyQuery(); // signal
 
1021
        if(!self)
 
1022
                return;
 
1023
 
 
1024
#ifdef S5B_DEBUG
 
1025
        printf("querying proxy: [%s]\n", e->c->d->proxy.full().latin1());
 
1026
#endif
 
1027
        e->query = new JT_S5B(d->client->rootTask());
 
1028
        connect(e->query, SIGNAL(finished()), SLOT(query_finished()));
 
1029
        e->query->requestProxyInfo(e->c->d->proxy);
 
1030
        e->query->go(true);
 
1031
}
 
1032
 
 
1033
void S5BManager::query_finished()
 
1034
{
 
1035
        JT_S5B *query = (JT_S5B *)sender();
 
1036
        Entry *e;
 
1037
        bool found = false;
 
1038
        QPtrListIterator<Entry> it(d->activeList);
 
1039
        for(; (e = it.current()); ++it) {
 
1040
                if(e->query == query) {
 
1041
                        found = true;
 
1042
                        break;
 
1043
                }
 
1044
        }
 
1045
        if(!found)
 
1046
                return;
 
1047
        e->query = 0;
 
1048
 
 
1049
#ifdef S5B_DEBUG
 
1050
        printf("query finished: ");
 
1051
#endif
 
1052
        if(query->success()) {
 
1053
                e->proxyInfo = query->proxyInfo();
 
1054
#ifdef S5B_DEBUG
 
1055
                printf("host/ip=[%s] port=[%d]\n", e->proxyInfo.host().latin1(), e->proxyInfo.port());
 
1056
#endif
 
1057
        }
 
1058
        else {
 
1059
#ifdef S5B_DEBUG
 
1060
                printf("fail\n");
 
1061
#endif
 
1062
        }
 
1063
 
 
1064
        QGuardedPtr<QObject> self = this;
 
1065
        e->c->proxyResult(query->success()); // signal
 
1066
        if(!self)
 
1067
                return;
 
1068
 
 
1069
        entryContinue(e);
 
1070
}
 
1071
 
 
1072
bool S5BManager::targetShouldOfferProxy(Entry *e)
 
1073
{
 
1074
        if(!e->c->d->proxy.isValid())
 
1075
                return false;
 
1076
 
 
1077
        // if target, don't offer any proxy if the initiator already did
 
1078
        const StreamHostList &hosts = e->c->d->req.hosts;
 
1079
        for(StreamHostList::ConstIterator it = hosts.begin(); it != hosts.end(); ++it) {
 
1080
                if((*it).isProxy())
 
1081
                        return false;
 
1082
        }
 
1083
 
 
1084
        // ensure we don't offer the same proxy as the initiator
 
1085
        if(haveHost(hosts, e->c->d->proxy))
 
1086
                return false;
 
1087
 
 
1088
        return true;
 
1089
}
 
1090
 
 
1091
//----------------------------------------------------------------------------
 
1092
// S5BManager::Item
 
1093
//----------------------------------------------------------------------------
 
1094
S5BManager::Item::Item(S5BManager *manager) : QObject(0)
 
1095
{
 
1096
        m = manager;
 
1097
        task = 0;
 
1098
        proxy_task = 0;
 
1099
        conn = 0;
 
1100
        proxy_conn = 0;
 
1101
        client_udp = 0;
 
1102
        client = 0;
 
1103
        client_out_udp = 0;
 
1104
        client_out = 0;
 
1105
        reset();
 
1106
}
 
1107
 
 
1108
S5BManager::Item::~Item()
 
1109
{
 
1110
        reset();
 
1111
}
 
1112
 
 
1113
void S5BManager::Item::reset()
 
1114
{
 
1115
        delete task;
 
1116
        task = 0;
 
1117
 
 
1118
        delete proxy_task;
 
1119
        proxy_task = 0;
 
1120
 
 
1121
        delete conn;
 
1122
        conn = 0;
 
1123
 
 
1124
        delete proxy_conn;
 
1125
        proxy_conn = 0;
 
1126
 
 
1127
        delete client_udp;
 
1128
        client_udp = 0;
 
1129
 
 
1130
        delete client;
 
1131
        client = 0;
 
1132
 
 
1133
        delete client_out_udp;
 
1134
        client_out_udp = 0;
 
1135
 
 
1136
        delete client_out;
 
1137
        client_out = 0;
 
1138
 
 
1139
        state = Idle;
 
1140
        wantFast = false;
 
1141
        targetMode = Unknown;
 
1142
        fast = false;
 
1143
        activated = false;
 
1144
        lateProxy = false;
 
1145
        connSuccess = false;
 
1146
        localFailed = false;
 
1147
        remoteFailed = false;
 
1148
        allowIncoming = false;
 
1149
        udp = false;
 
1150
}
 
1151
 
 
1152
void S5BManager::Item::startInitiator(const QString &_sid, const Jid &_self, const Jid &_peer, bool fast, bool _udp)
 
1153
{
 
1154
        sid = _sid;
 
1155
        self = _self;
 
1156
        peer = _peer;
 
1157
        key = makeKey(sid, self, peer);
 
1158
        out_key = makeKey(sid, peer, self);
 
1159
        wantFast = fast;
 
1160
        udp = _udp;
 
1161
 
 
1162
#ifdef S5B_DEBUG
 
1163
        printf("S5BManager::Item initiating request %s [%s]\n", peer.full().latin1(), sid.latin1());
 
1164
#endif
 
1165
        state = Initiator;
 
1166
        doOutgoing();
 
1167
}
 
1168
 
 
1169
void S5BManager::Item::startTarget(const QString &_sid, const Jid &_self, const Jid &_peer, const StreamHostList &hosts, const QString &iq_id, bool _fast, bool _udp)
 
1170
{
 
1171
        sid = _sid;
 
1172
        peer = _peer;
 
1173
        self = _self;
 
1174
        in_hosts = hosts;
 
1175
        in_id = iq_id;
 
1176
        fast = _fast;
 
1177
        key = makeKey(sid, self, peer);
 
1178
        out_key = makeKey(sid, peer, self);
 
1179
        udp = _udp;
 
1180
 
 
1181
#ifdef S5B_DEBUG
 
1182
        printf("S5BManager::Item incoming request %s [%s]\n", peer.full().latin1(), sid.latin1());
 
1183
#endif
 
1184
        state = Target;
 
1185
        if(fast)
 
1186
                doOutgoing();
 
1187
        doIncoming();
 
1188
}
 
1189
 
 
1190
void S5BManager::Item::handleFast(const StreamHostList &hosts, const QString &iq_id)
 
1191
{
 
1192
        targetMode = Fast;
 
1193
 
 
1194
        QGuardedPtr<QObject> self = this;
 
1195
        accepted();
 
1196
        if(!self)
 
1197
                return;
 
1198
 
 
1199
        // if we already have a stream, then bounce this request
 
1200
        if(client) {
 
1201
                m->doError(peer, iq_id, 406, "Not acceptable");
 
1202
        }
 
1203
        else {
 
1204
                in_hosts = hosts;
 
1205
                in_id = iq_id;
 
1206
                doIncoming();
 
1207
        }
 
1208
}
 
1209
 
 
1210
void S5BManager::Item::doOutgoing()
 
1211
{
 
1212
        StreamHostList hosts;
 
1213
        S5BServer *serv = m->server();
 
1214
        if(serv && serv->isActive() && !haveHost(in_hosts, m->client()->jid())) {
 
1215
                QStringList hostList = serv->hostList();
 
1216
                for(QStringList::ConstIterator it = hostList.begin(); it != hostList.end(); ++it) {
 
1217
                        StreamHost h;
 
1218
                        h.setJid(m->client()->jid());
 
1219
                        h.setHost(*it);
 
1220
                        h.setPort(serv->port());
 
1221
                        hosts += h;
 
1222
                }
 
1223
        }
 
1224
 
 
1225
        // if the proxy is valid, then it's ok to add (the manager already ensured that it doesn't conflict)
 
1226
        if(proxy.jid().isValid())
 
1227
                hosts += proxy;
 
1228
 
 
1229
        // if we're the target and we have no streamhosts of our own, then don't even bother with fast-mode
 
1230
        if(state == Target && hosts.isEmpty()) {
 
1231
                fast = false;
 
1232
                return;
 
1233
        }
 
1234
 
 
1235
        allowIncoming = true;
 
1236
 
 
1237
        task = new JT_S5B(m->client()->rootTask());
 
1238
        connect(task, SIGNAL(finished()), SLOT(jt_finished()));
 
1239
        task->request(peer, sid, hosts, state == Initiator ? wantFast : false, udp);
 
1240
        out_id = task->id();
 
1241
        task->go(true);
 
1242
}
 
1243
 
 
1244
void S5BManager::Item::doIncoming()
 
1245
{
 
1246
        if(in_hosts.isEmpty()) {
 
1247
                doConnectError();
 
1248
                return;
 
1249
        }
 
1250
 
 
1251
        StreamHostList list;
 
1252
        if(lateProxy) {
 
1253
                // take just the proxy streamhosts
 
1254
                for(StreamHostList::ConstIterator it = in_hosts.begin(); it != in_hosts.end(); ++it) {
 
1255
                        if((*it).isProxy())
 
1256
                                list += *it;
 
1257
                }
 
1258
                lateProxy = false;
 
1259
        }
 
1260
        else {
 
1261
                // only try doing the late proxy trick if using fast mode AND we did not offer a proxy
 
1262
                if((state == Initiator || (state == Target && fast)) && !proxy.jid().isValid()) {
 
1263
                        // take just the non-proxy streamhosts
 
1264
                        bool hasProxies = false;
 
1265
                        for(StreamHostList::ConstIterator it = in_hosts.begin(); it != in_hosts.end(); ++it) {
 
1266
                                if((*it).isProxy())
 
1267
                                        hasProxies = true;
 
1268
                                else
 
1269
                                        list += *it;
 
1270
                        }
 
1271
                        if(hasProxies) {
 
1272
                                lateProxy = true;
 
1273
 
 
1274
                                // no regular streamhosts?  wait for remote error
 
1275
                                if(list.isEmpty())
 
1276
                                        return;
 
1277
                        }
 
1278
                }
 
1279
                else
 
1280
                        list = in_hosts;
 
1281
        }
 
1282
 
 
1283
        conn = new S5BConnector;
 
1284
        connect(conn, SIGNAL(result(bool)), SLOT(conn_result(bool)));
 
1285
 
 
1286
        QGuardedPtr<QObject> self = this;
 
1287
        tryingHosts(list);
 
1288
        if(!self)
 
1289
                return;
 
1290
 
 
1291
        conn->start(m->client()->jid(), list, out_key, udp, lateProxy ? 10 : 30);
 
1292
}
 
1293
 
 
1294
void S5BManager::Item::setIncomingClient(SocksClient *sc)
 
1295
{
 
1296
#ifdef S5B_DEBUG
 
1297
        printf("S5BManager::Item: %s [%s] successful incoming connection\n", peer.full().latin1(), sid.latin1());
 
1298
#endif
 
1299
 
 
1300
        connect(sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
1301
        connect(sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
1302
        connect(sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1303
 
 
1304
        client = sc;
 
1305
        allowIncoming = false;
 
1306
}
 
1307
 
 
1308
void S5BManager::Item::incomingActivate(const Jid &streamHost)
 
1309
{
 
1310
        if(!activated) {
 
1311
                activatedStream = streamHost;
 
1312
                checkForActivation();
 
1313
        }
 
1314
}
 
1315
 
 
1316
void S5BManager::Item::jt_finished()
 
1317
{
 
1318
        JT_S5B *j = task;
 
1319
        task = 0;
 
1320
 
 
1321
#ifdef S5B_DEBUG
 
1322
        printf("jt_finished: state=%s, %s\n", state == Initiator ? "initiator" : "target", j->success() ? "ok" : "fail");
 
1323
#endif
 
1324
 
 
1325
        if(state == Initiator) {
 
1326
                if(targetMode == Unknown) {
 
1327
                        targetMode = NotFast;
 
1328
                        QGuardedPtr<QObject> self = this;
 
1329
                        accepted();
 
1330
                        if(!self)
 
1331
                                return;
 
1332
                }
 
1333
        }
 
1334
 
 
1335
        // if we've already reported successfully connecting to them, then this response doesn't matter
 
1336
        if(state == Initiator && connSuccess) {
 
1337
                tryActivation();
 
1338
                return;
 
1339
        }
 
1340
 
 
1341
        if(j->success()) {
 
1342
                // stop connecting out
 
1343
                if(conn || lateProxy) {
 
1344
                        delete conn;
 
1345
                        conn = 0;
 
1346
                        doConnectError();
 
1347
                }
 
1348
 
 
1349
                Jid streamHost = j->streamHostUsed();
 
1350
 
 
1351
                // they connected to us?
 
1352
                if(streamHost.compare(self)) {
 
1353
                        if(client) {
 
1354
                                if(state == Initiator) {
 
1355
                                        activatedStream = streamHost;
 
1356
                                        tryActivation();
 
1357
                                }
 
1358
                                else
 
1359
                                        checkForActivation();
 
1360
                        }
 
1361
                        else {
 
1362
#ifdef S5B_DEBUG
 
1363
                                printf("S5BManager::Item %s claims to have connected to us, but we don't see this\n", peer.full().latin1());
 
1364
#endif
 
1365
                                reset();
 
1366
                                error(ErrWrongHost);
 
1367
                        }
 
1368
                }
 
1369
                else if(streamHost.compare(proxy.jid())) {
 
1370
                        // toss out any direct incoming, since it won't be used
 
1371
                        delete client;
 
1372
                        client = 0;
 
1373
                        allowIncoming = false;
 
1374
 
 
1375
#ifdef S5B_DEBUG
 
1376
                        printf("attempting to connect to proxy\n");
 
1377
#endif
 
1378
                        // connect to the proxy
 
1379
                        proxy_conn = new S5BConnector;
 
1380
                        connect(proxy_conn, SIGNAL(result(bool)), SLOT(proxy_result(bool)));
 
1381
                        StreamHostList list;
 
1382
                        list += proxy;
 
1383
 
 
1384
                        QGuardedPtr<QObject> self = this;
 
1385
                        proxyConnect();
 
1386
                        if(!self)
 
1387
                                return;
 
1388
 
 
1389
                        proxy_conn->start(m->client()->jid(), list, key, udp, 30);
 
1390
                }
 
1391
                else {
 
1392
#ifdef S5B_DEBUG
 
1393
                        printf("S5BManager::Item %s claims to have connected to a streamhost we never offered\n", peer.full().latin1());
 
1394
#endif
 
1395
                        reset();
 
1396
                        error(ErrWrongHost);
 
1397
                }
 
1398
        }
 
1399
        else {
 
1400
#ifdef S5B_DEBUG
 
1401
                printf("S5BManager::Item %s [%s] error\n", peer.full().latin1(), sid.latin1());
 
1402
#endif
 
1403
                remoteFailed = true;
 
1404
                statusCode = j->statusCode();
 
1405
 
 
1406
                if(lateProxy) {
 
1407
                        if(!conn)
 
1408
                                doIncoming();
 
1409
                }
 
1410
                else {
 
1411
                        // if connSuccess is true at this point, then we're a Target
 
1412
                        if(connSuccess)
 
1413
                                checkForActivation();
 
1414
                        else
 
1415
                                checkFailure();
 
1416
                }
 
1417
        }
 
1418
}
 
1419
 
 
1420
void S5BManager::Item::conn_result(bool b)
 
1421
{
 
1422
        if(b) {
 
1423
                SocksClient *sc = conn->takeClient();
 
1424
                SocksUDP *sc_udp = conn->takeUDP();
 
1425
                StreamHost h = conn->streamHostUsed();
 
1426
                delete conn;
 
1427
                conn = 0;
 
1428
                connSuccess = true;
 
1429
 
 
1430
#ifdef S5B_DEBUG
 
1431
                printf("S5BManager::Item: %s [%s] successful outgoing connection\n", peer.full().latin1(), sid.latin1());
 
1432
#endif
 
1433
 
 
1434
                connect(sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
1435
                connect(sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
1436
                connect(sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1437
 
 
1438
                m->doSuccess(peer, in_id, h.jid());
 
1439
 
 
1440
                // if the first batch works, don't try proxy
 
1441
                lateProxy = false;
 
1442
 
 
1443
                // if initiator, run with this one
 
1444
                if(state == Initiator) {
 
1445
                        // if we had an incoming one, toss it
 
1446
                        delete client_udp;
 
1447
                        client_udp = sc_udp;
 
1448
                        delete client;
 
1449
                        client = sc;
 
1450
                        allowIncoming = false;
 
1451
                        activatedStream = peer;
 
1452
                        tryActivation();
 
1453
                }
 
1454
                else {
 
1455
                        client_out_udp = sc_udp;
 
1456
                        client_out = sc;
 
1457
                        checkForActivation();
 
1458
                }
 
1459
        }
 
1460
        else {
 
1461
                delete conn;
 
1462
                conn = 0;
 
1463
 
 
1464
                // if we delayed the proxies for later, try now
 
1465
                if(lateProxy) {
 
1466
                        if(remoteFailed)
 
1467
                                doIncoming();
 
1468
                }
 
1469
                else
 
1470
                        doConnectError();
 
1471
        }
 
1472
}
 
1473
 
 
1474
void S5BManager::Item::proxy_result(bool b)
 
1475
{
 
1476
#ifdef S5B_DEBUG
 
1477
        printf("proxy_result: %s\n", b ? "ok" : "fail");
 
1478
#endif
 
1479
        if(b) {
 
1480
                SocksClient *sc = proxy_conn->takeClient();
 
1481
                SocksUDP *sc_udp = proxy_conn->takeUDP();
 
1482
                delete proxy_conn;
 
1483
                proxy_conn = 0;
 
1484
 
 
1485
                connect(sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
1486
                connect(sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
1487
                connect(sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1488
 
 
1489
                client = sc;
 
1490
                client_udp = sc_udp;
 
1491
 
 
1492
                // activate
 
1493
#ifdef S5B_DEBUG
 
1494
                printf("activating proxy stream\n");
 
1495
#endif
 
1496
                proxy_task = new JT_S5B(m->client()->rootTask());
 
1497
                connect(proxy_task, SIGNAL(finished()), SLOT(proxy_finished()));
 
1498
                proxy_task->requestActivation(proxy.jid(), sid, peer);
 
1499
                proxy_task->go(true);
 
1500
        }
 
1501
        else {
 
1502
                delete proxy_conn;
 
1503
                proxy_conn = 0;
 
1504
                reset();
 
1505
                error(ErrProxy);
 
1506
        }
 
1507
}
 
1508
 
 
1509
void S5BManager::Item::proxy_finished()
 
1510
{
 
1511
        JT_S5B *j = proxy_task;
 
1512
        proxy_task = 0;
 
1513
 
 
1514
        if(j->success()) {
 
1515
#ifdef S5B_DEBUG
 
1516
                printf("proxy stream activated\n");
 
1517
#endif
 
1518
                if(state == Initiator) {
 
1519
                        activatedStream = proxy.jid();
 
1520
                        tryActivation();
 
1521
                }
 
1522
                else
 
1523
                        checkForActivation();
 
1524
        }
 
1525
        else {
 
1526
                reset();
 
1527
                error(ErrProxy);
 
1528
        }
 
1529
}
 
1530
 
 
1531
void S5BManager::Item::sc_readyRead()
 
1532
{
 
1533
#ifdef S5B_DEBUG
 
1534
        printf("sc_readyRead\n");
 
1535
#endif
 
1536
        // only targets check for activation, and only should do it if there is no pending outgoing iq-set
 
1537
        if(state == Target && !task && !proxy_task)
 
1538
                checkForActivation();
 
1539
}
 
1540
 
 
1541
void S5BManager::Item::sc_bytesWritten(int)
 
1542
{
 
1543
#ifdef S5B_DEBUG
 
1544
        printf("sc_bytesWritten\n");
 
1545
#endif
 
1546
        // this should only happen to the initiator, and should always be 1 byte (the '\r' sent earlier)
 
1547
        finished();
 
1548
}
 
1549
 
 
1550
void S5BManager::Item::sc_error(int)
 
1551
{
 
1552
#ifdef S5B_DEBUG
 
1553
        printf("sc_error\n");
 
1554
#endif
 
1555
        reset();
 
1556
        error(ErrConnect);
 
1557
}
 
1558
 
 
1559
void S5BManager::Item::doConnectError()
 
1560
{
 
1561
        localFailed = true;
 
1562
        m->doError(peer, in_id, 404, "Could not connect to given hosts");
 
1563
        checkFailure();
 
1564
}
 
1565
 
 
1566
void S5BManager::Item::tryActivation()
 
1567
{
 
1568
#ifdef S5B_DEBUG
 
1569
        printf("tryActivation\n");
 
1570
#endif
 
1571
        if(activated) {
 
1572
#ifdef S5B_DEBUG
 
1573
                printf("already activated !?\n");
 
1574
#endif
 
1575
                return;
 
1576
        }
 
1577
 
 
1578
        if(targetMode == NotFast) {
 
1579
#ifdef S5B_DEBUG
 
1580
                printf("tryActivation: NotFast\n");
 
1581
#endif
 
1582
                // nothing to activate, we're done
 
1583
                finished();
 
1584
        }
 
1585
        else if(targetMode == Fast) {
 
1586
                // with fast mode, we don't wait for the iq reply, so delete the task (if any)
 
1587
                delete task;
 
1588
                task = 0;
 
1589
 
 
1590
                activated = true;
 
1591
 
 
1592
                // if udp, activate using special stanza
 
1593
                if(udp) {
 
1594
                        m->doActivate(peer, sid, activatedStream);
 
1595
                }
 
1596
                else {
 
1597
#ifdef S5B_DEBUG
 
1598
                        printf("sending extra CR\n");
 
1599
#endif
 
1600
                        // must send [CR] to activate target streamhost
 
1601
                        QByteArray a(1);
 
1602
                        a[0] = '\r';
 
1603
                        client->write(a);
 
1604
                }
 
1605
        }
 
1606
}
 
1607
 
 
1608
void S5BManager::Item::checkForActivation()
 
1609
{
 
1610
        QPtrList<SocksClient> clientList;
 
1611
        if(client)
 
1612
                clientList.append(client);
 
1613
        if(client_out)
 
1614
                clientList.append(client_out);
 
1615
        QPtrListIterator<SocksClient> it(clientList);
 
1616
        for(SocksClient *sc; (sc = it.current()); ++it) {
 
1617
#ifdef S5B_DEBUG
 
1618
                printf("checking for activation\n");
 
1619
#endif
 
1620
                if(fast) {
 
1621
                        bool ok = false;
 
1622
                        if(udp) {
 
1623
                                if((sc == client_out && activatedStream.compare(self)) || (sc == client && !activatedStream.compare(self))) {
 
1624
                                        clientList.removeRef(sc);
 
1625
                                        ok = true;
 
1626
                                }
 
1627
                        }
 
1628
                        else {
 
1629
#ifdef S5B_DEBUG
 
1630
                                printf("need CR\n");
 
1631
#endif
 
1632
                                if(sc->bytesAvailable() >= 1) {
 
1633
                                        clientList.removeRef(sc);
 
1634
                                        QByteArray a = sc->read(1);
 
1635
                                        if(a[0] != '\r') {
 
1636
                                                delete sc;
 
1637
                                                return;
 
1638
                                        }
 
1639
                                        ok = true;
 
1640
                                }
 
1641
                        }
 
1642
 
 
1643
                        if(ok) {
 
1644
                                SocksUDP *sc_udp = 0;
 
1645
                                if(sc == client) {
 
1646
                                        delete client_out_udp;
 
1647
                                        client_out_udp = 0;
 
1648
                                        sc_udp = client_udp;
 
1649
                                }
 
1650
                                else if(sc == client_out) {
 
1651
                                        delete client_udp;
 
1652
                                        client_udp = 0;
 
1653
                                        sc_udp = client_out_udp;
 
1654
                                }
 
1655
 
 
1656
                                sc->disconnect(this);
 
1657
                                clientList.setAutoDelete(true);
 
1658
                                clientList.clear();
 
1659
                                client = sc;
 
1660
                                client_out = 0;
 
1661
                                client_udp = sc_udp;
 
1662
                                activated = true;
 
1663
#ifdef S5B_DEBUG
 
1664
                                printf("activation success\n");
 
1665
#endif
 
1666
                                break;
 
1667
                        }
 
1668
                }
 
1669
                else {
 
1670
#ifdef S5B_DEBUG
 
1671
                        printf("not fast mode, no need to wait for anything\n");
 
1672
#endif
 
1673
                        clientList.removeRef(sc);
 
1674
                        sc->disconnect(this);
 
1675
                        clientList.setAutoDelete(true);
 
1676
                        clientList.clear();
 
1677
                        client = sc;
 
1678
                        client_out = 0;
 
1679
                        activated = true;
 
1680
                        break;
 
1681
                }
 
1682
        }
 
1683
 
 
1684
        if(activated) {
 
1685
                finished();
 
1686
        }
 
1687
        else {
 
1688
                // only emit waitingForActivation if there is nothing left to do
 
1689
                if((connSuccess || localFailed) && !proxy_task && !proxy_conn)
 
1690
                        waitingForActivation();
 
1691
        }
 
1692
}
 
1693
 
 
1694
void S5BManager::Item::checkFailure()
 
1695
{
 
1696
        bool failed = false;
 
1697
        if(state == Initiator) {
 
1698
                if(remoteFailed) {
 
1699
                        if((localFailed && targetMode == Fast) || targetMode == NotFast)
 
1700
                                failed = true;
 
1701
                }
 
1702
        }
 
1703
        else {
 
1704
                if(localFailed) {
 
1705
                        if((remoteFailed && fast) || !fast)
 
1706
                                failed = true;
 
1707
                }
 
1708
        }
 
1709
 
 
1710
        if(failed) {
 
1711
                if(state == Initiator) {
 
1712
                        reset();
 
1713
                        if(statusCode == 404)
 
1714
                                error(ErrConnect);
 
1715
                        else
 
1716
                                error(ErrRefused);
 
1717
                }
 
1718
                else {
 
1719
                        reset();
 
1720
                        error(ErrConnect);
 
1721
                }
 
1722
        }
 
1723
}
 
1724
 
 
1725
void S5BManager::Item::finished()
 
1726
{
 
1727
        client->disconnect(this);
 
1728
        state = Active;
 
1729
#ifdef S5B_DEBUG
 
1730
        printf("S5BManager::Item %s [%s] linked successfully\n", peer.full().latin1(), sid.latin1());
 
1731
#endif
 
1732
        connected();
 
1733
}
 
1734
 
 
1735
//----------------------------------------------------------------------------
 
1736
// S5BConnector
 
1737
//----------------------------------------------------------------------------
 
1738
class S5BConnector::Item : public QObject
 
1739
{
 
1740
        Q_OBJECT
 
1741
public:
 
1742
        SocksClient *client;
 
1743
        SocksUDP *client_udp;
 
1744
        StreamHost host;
 
1745
        QString key;
 
1746
        bool udp;
 
1747
        int udp_tries;
 
1748
        QTimer t;
 
1749
        Jid jid;
 
1750
 
 
1751
        Item(const Jid &self, const StreamHost &_host, const QString &_key, bool _udp) : QObject(0)
 
1752
        {
 
1753
                jid = self;
 
1754
                host = _host;
 
1755
                key = _key;
 
1756
                udp = _udp;
 
1757
                client = new SocksClient;
 
1758
                client_udp = 0;
 
1759
                connect(client, SIGNAL(connected()), SLOT(sc_connected()));
 
1760
                connect(client, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1761
                connect(&t, SIGNAL(timeout()), SLOT(trySendUDP()));
 
1762
        }
 
1763
 
 
1764
        ~Item()
 
1765
        {
 
1766
                cleanup();
 
1767
        }
 
1768
 
 
1769
        void start()
 
1770
        {
 
1771
                client->connectToHost(host.host(), host.port(), key, 0, udp);
 
1772
        }
 
1773
 
 
1774
        void udpSuccess()
 
1775
        {
 
1776
                t.stop();
 
1777
                client_udp->change(key, 0); // flip over to the data port
 
1778
                success();
 
1779
        }
 
1780
 
 
1781
signals:
 
1782
        void result(bool);
 
1783
 
 
1784
private slots:
 
1785
        void sc_connected()
 
1786
        {
 
1787
                // if udp, need to send init packet before we are good
 
1788
                if(udp) {
 
1789
                        // port 1 is init
 
1790
                        client_udp = client->createUDP(key, 1, client->peerAddress(), client->peerPort());
 
1791
                        udp_tries = 0;
 
1792
                        t.start(5000);
 
1793
                        trySendUDP();
 
1794
                        return;
 
1795
                }
 
1796
 
 
1797
                success();
 
1798
        }
 
1799
 
 
1800
        void sc_error(int)
 
1801
        {
 
1802
#ifdef S5B_DEBUG
 
1803
                printf("S5BConnector[%s]: error\n", host.host().latin1());
 
1804
#endif
 
1805
                cleanup();
 
1806
                result(false);
 
1807
        }
 
1808
 
 
1809
        void trySendUDP()
 
1810
        {
 
1811
                if(udp_tries == 5) {
 
1812
                        t.stop();
 
1813
                        cleanup();
 
1814
                        result(false);
 
1815
                        return;
 
1816
                }
 
1817
 
 
1818
                // send initialization with our JID
 
1819
                QCString cs = jid.full().utf8();
 
1820
                QByteArray a(cs.length());
 
1821
                memcpy(a.data(), cs.data(), a.size());
 
1822
                client_udp->write(a);
 
1823
                ++udp_tries;
 
1824
        }
 
1825
 
 
1826
private:
 
1827
        void cleanup()
 
1828
        {
 
1829
                delete client_udp;
 
1830
                client_udp = 0;
 
1831
                delete client;
 
1832
                client = 0;
 
1833
        }
 
1834
 
 
1835
        void success()
 
1836
        {
 
1837
#ifdef S5B_DEBUG
 
1838
                printf("S5BConnector[%s]: success\n", host.host().latin1());
 
1839
#endif
 
1840
                client->disconnect(this);
 
1841
                result(true);
 
1842
        }
 
1843
};
 
1844
 
 
1845
class S5BConnector::Private
 
1846
{
 
1847
public:
 
1848
        SocksClient *active;
 
1849
        SocksUDP *active_udp;
 
1850
        QPtrList<Item> itemList;
 
1851
        QString key;
 
1852
        StreamHost activeHost;
 
1853
        QTimer t;
 
1854
};
 
1855
 
 
1856
S5BConnector::S5BConnector(QObject *parent)
 
1857
:QObject(parent)
 
1858
{
 
1859
        d = new Private;
 
1860
        d->active = 0;
 
1861
        d->active_udp = 0;
 
1862
        d->itemList.setAutoDelete(true);
 
1863
        connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout()));
 
1864
}
 
1865
 
 
1866
S5BConnector::~S5BConnector()
 
1867
{
 
1868
        reset();
 
1869
        delete d;
 
1870
}
 
1871
 
 
1872
void S5BConnector::reset()
 
1873
{
 
1874
        d->t.stop();
 
1875
        delete d->active_udp;
 
1876
        d->active_udp = 0;
 
1877
        delete d->active;
 
1878
        d->active = 0;
 
1879
        d->itemList.clear();
 
1880
}
 
1881
 
 
1882
void S5BConnector::start(const Jid &self, const StreamHostList &hosts, const QString &key, bool udp, int timeout)
 
1883
{
 
1884
        reset();
 
1885
 
 
1886
#ifdef S5B_DEBUG
 
1887
        printf("S5BConnector: starting [%p]!\n", this);
 
1888
#endif
 
1889
        for(StreamHostList::ConstIterator it = hosts.begin(); it != hosts.end(); ++it) {
 
1890
                Item *i = new Item(self, *it, key, udp);
 
1891
                connect(i, SIGNAL(result(bool)), SLOT(item_result(bool)));
 
1892
                d->itemList.append(i);
 
1893
                i->start();
 
1894
        }
 
1895
        d->t.start(timeout * 1000);
 
1896
}
 
1897
 
 
1898
SocksClient *S5BConnector::takeClient()
 
1899
{
 
1900
        SocksClient *c = d->active;
 
1901
        d->active = 0;
 
1902
        return c;
 
1903
}
 
1904
 
 
1905
SocksUDP *S5BConnector::takeUDP()
 
1906
{
 
1907
        SocksUDP *c = d->active_udp;
 
1908
        d->active_udp = 0;
 
1909
        return c;
 
1910
}
 
1911
 
 
1912
StreamHost S5BConnector::streamHostUsed() const
 
1913
{
 
1914
        return d->activeHost;
 
1915
}
 
1916
 
 
1917
void S5BConnector::item_result(bool b)
 
1918
{
 
1919
        Item *i = (Item *)sender();
 
1920
        if(b) {
 
1921
                d->active = i->client;
 
1922
                i->client = 0;
 
1923
                d->active_udp = i->client_udp;
 
1924
                i->client_udp = 0;
 
1925
                d->activeHost = i->host;
 
1926
                d->itemList.clear();
 
1927
                d->t.stop();
 
1928
#ifdef S5B_DEBUG
 
1929
                printf("S5BConnector: complete! [%p]\n", this);
 
1930
#endif
 
1931
                result(true);
 
1932
        }
 
1933
        else {
 
1934
                d->itemList.removeRef(i);
 
1935
                if(d->itemList.isEmpty()) {
 
1936
                        d->t.stop();
 
1937
#ifdef S5B_DEBUG
 
1938
                        printf("S5BConnector: failed! [%p]\n", this);
 
1939
#endif
 
1940
                        result(false);
 
1941
                }
 
1942
        }
 
1943
}
 
1944
 
 
1945
void S5BConnector::t_timeout()
 
1946
{
 
1947
        reset();
 
1948
#ifdef S5B_DEBUG
 
1949
        printf("S5BConnector: failed! (timeout)\n");
 
1950
#endif
 
1951
        result(false);
 
1952
}
 
1953
 
 
1954
void S5BConnector::man_udpSuccess(const Jid &streamHost)
 
1955
{
 
1956
        // was anyone sending to this streamhost?
 
1957
        QPtrListIterator<Item> it(d->itemList);
 
1958
        for(Item *i; (i = it.current()); ++it) {
 
1959
                if(i->host.jid().compare(streamHost) && i->client_udp) {
 
1960
                        i->udpSuccess();
 
1961
                        return;
 
1962
                }
 
1963
        }
 
1964
}
 
1965
 
 
1966
//----------------------------------------------------------------------------
 
1967
// S5BServer
 
1968
//----------------------------------------------------------------------------
 
1969
class S5BServer::Item : public QObject
 
1970
{
 
1971
        Q_OBJECT
 
1972
public:
 
1973
        SocksClient *client;
 
1974
        QString host;
 
1975
        QTimer expire;
 
1976
 
 
1977
        Item(SocksClient *c) : QObject(0)
 
1978
        {
 
1979
                client = c;
 
1980
                connect(client, SIGNAL(incomingMethods(int)), SLOT(sc_incomingMethods(int)));
 
1981
                connect(client, SIGNAL(incomingConnectRequest(const QString &, int)), SLOT(sc_incomingConnectRequest(const QString &, int)));
 
1982
                connect(client, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1983
 
 
1984
                connect(&expire, SIGNAL(timeout()), SLOT(doError()));
 
1985
                resetExpiration();
 
1986
        }
 
1987
 
 
1988
        ~Item()
 
1989
        {
 
1990
                delete client;
 
1991
        }
 
1992
 
 
1993
        void resetExpiration()
 
1994
        {
 
1995
                expire.start(30000);
 
1996
        }
 
1997
 
 
1998
signals:
 
1999
        void result(bool);
 
2000
 
 
2001
private slots:
 
2002
        void doError()
 
2003
        {
 
2004
                expire.stop();
 
2005
                delete client;
 
2006
                client = 0;
 
2007
                result(false);
 
2008
        }
 
2009
 
 
2010
        void sc_incomingMethods(int m)
 
2011
        {
 
2012
                if(m & SocksClient::AuthNone)
 
2013
                        client->chooseMethod(SocksClient::AuthNone);
 
2014
                else
 
2015
                        doError();
 
2016
        }
 
2017
 
 
2018
        void sc_incomingConnectRequest(const QString &_host, int port)
 
2019
        {
 
2020
                if(port == 0) {
 
2021
                        host = _host;
 
2022
                        client->disconnect(this);
 
2023
                        result(true);
 
2024
                }
 
2025
                else
 
2026
                        doError();
 
2027
        }
 
2028
 
 
2029
        void sc_error(int)
 
2030
        {
 
2031
                doError();
 
2032
        }
 
2033
};
 
2034
 
 
2035
class S5BServer::Private
 
2036
{
 
2037
public:
 
2038
        SocksServer serv;
 
2039
        QStringList hostList;
 
2040
        QPtrList<S5BManager> manList;
 
2041
        QPtrList<Item> itemList;
 
2042
};
 
2043
 
 
2044
S5BServer::S5BServer(QObject *parent)
 
2045
:QObject(parent)
 
2046
{
 
2047
        d = new Private;
 
2048
        d->itemList.setAutoDelete(true);
 
2049
        connect(&d->serv, SIGNAL(incomingReady()), SLOT(ss_incomingReady()));
 
2050
        connect(&d->serv, SIGNAL(incomingUDP(const QString &, int, const QHostAddress &, int, const QByteArray &)), SLOT(ss_incomingUDP(const QString &, int, const QHostAddress &, int, const QByteArray &)));
 
2051
}
 
2052
 
 
2053
S5BServer::~S5BServer()
 
2054
{
 
2055
        unlinkAll();
 
2056
        delete d;
 
2057
}
 
2058
 
 
2059
bool S5BServer::isActive() const
 
2060
{
 
2061
        return d->serv.isActive();
 
2062
}
 
2063
 
 
2064
bool S5BServer::start(int port)
 
2065
{
 
2066
        d->serv.stop();
 
2067
        return d->serv.listen(port, true);
 
2068
}
 
2069
 
 
2070
void S5BServer::stop()
 
2071
{
 
2072
        d->serv.stop();
 
2073
}
 
2074
 
 
2075
void S5BServer::setHostList(const QStringList &list)
 
2076
{
 
2077
        d->hostList = list;
 
2078
}
 
2079
 
 
2080
QStringList S5BServer::hostList() const
 
2081
{
 
2082
        return d->hostList;
 
2083
}
 
2084
 
 
2085
int S5BServer::port() const
 
2086
{
 
2087
        return d->serv.port();
 
2088
}
 
2089
 
 
2090
void S5BServer::ss_incomingReady()
 
2091
{
 
2092
        Item *i = new Item(d->serv.takeIncoming());
 
2093
#ifdef S5B_DEBUG
 
2094
        printf("S5BServer: incoming connection from %s:%d\n", i->client->peerAddress().toString().latin1(), i->client->peerPort());
 
2095
#endif
 
2096
        connect(i, SIGNAL(result(bool)), SLOT(item_result(bool)));
 
2097
        d->itemList.append(i);
 
2098
}
 
2099
 
 
2100
void S5BServer::ss_incomingUDP(const QString &host, int port, const QHostAddress &addr, int sourcePort, const QByteArray &data)
 
2101
{
 
2102
        if(port != 0 || port != 1)
 
2103
                return;
 
2104
 
 
2105
        QPtrListIterator<S5BManager> it(d->manList);
 
2106
        for(S5BManager *m; (m = it.current()); ++it) {
 
2107
                if(m->srv_ownsHash(host)) {
 
2108
                        m->srv_incomingUDP(port == 1 ? true : false, addr, sourcePort, host, data);
 
2109
                        return;
 
2110
                }
 
2111
        }
 
2112
}
 
2113
 
 
2114
void S5BServer::item_result(bool b)
 
2115
{
 
2116
        Item *i = (Item *)sender();
 
2117
#ifdef S5B_DEBUG
 
2118
        printf("S5BServer item result: %d\n", b);
 
2119
#endif
 
2120
        if(!b) {
 
2121
                d->itemList.removeRef(i);
 
2122
                return;
 
2123
        }
 
2124
 
 
2125
        SocksClient *c = i->client;
 
2126
        i->client = 0;
 
2127
        QString key = i->host;
 
2128
        d->itemList.removeRef(i);
 
2129
 
 
2130
        // find the appropriate manager for this incoming connection
 
2131
        QPtrListIterator<S5BManager> it(d->manList);
 
2132
        for(S5BManager *m; (m = it.current()); ++it) {
 
2133
                if(m->srv_ownsHash(key)) {
 
2134
                        m->srv_incomingReady(c, key);
 
2135
                        return;
 
2136
                }
 
2137
        }
 
2138
 
 
2139
        // throw it away
 
2140
        delete c;
 
2141
}
 
2142
 
 
2143
void S5BServer::link(S5BManager *m)
 
2144
{
 
2145
        d->manList.append(m);
 
2146
}
 
2147
 
 
2148
void S5BServer::unlink(S5BManager *m)
 
2149
{
 
2150
        d->manList.removeRef(m);
 
2151
}
 
2152
 
 
2153
void S5BServer::unlinkAll()
 
2154
{
 
2155
        QPtrListIterator<S5BManager> it(d->manList);
 
2156
        for(S5BManager *m; (m = it.current()); ++it)
 
2157
                m->srv_unlink();
 
2158
        d->manList.clear();
 
2159
}
 
2160
 
 
2161
const QPtrList<S5BManager> & S5BServer::managerList() const
 
2162
{
 
2163
        return d->manList;
 
2164
}
 
2165
 
 
2166
void S5BServer::writeUDP(const QHostAddress &addr, int port, const QByteArray &data)
 
2167
{
 
2168
        d->serv.writeUDP(addr, port, data);
 
2169
}
 
2170
 
 
2171
//----------------------------------------------------------------------------
 
2172
// JT_S5B
 
2173
//----------------------------------------------------------------------------
 
2174
class JT_S5B::Private
 
2175
{
 
2176
public:
 
2177
        QDomElement iq;
 
2178
        Jid to;
 
2179
        Jid streamHost;
 
2180
        StreamHost proxyInfo;
 
2181
        int mode;
 
2182
        QTimer t;
 
2183
};
 
2184
 
 
2185
JT_S5B::JT_S5B(Task *parent)
 
2186
:Task(parent)
 
2187
{
 
2188
        d = new Private;
 
2189
        d->mode = -1;
 
2190
        connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout()));
 
2191
}
 
2192
 
 
2193
JT_S5B::~JT_S5B()
 
2194
{
 
2195
        delete d;
 
2196
}
 
2197
 
 
2198
void JT_S5B::request(const Jid &to, const QString &sid, const StreamHostList &hosts, bool fast, bool udp)
 
2199
{
 
2200
        d->mode = 0;
 
2201
 
 
2202
        QDomElement iq;
 
2203
        d->to = to;
 
2204
        iq = createIQ(doc(), "set", to.full(), id());
 
2205
        QDomElement query = doc()->createElement("query");
 
2206
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
2207
        query.setAttribute("sid", sid);
 
2208
        query.setAttribute("mode", udp ? "udp" : "tcp" );
 
2209
        iq.appendChild(query);
 
2210
        for(StreamHostList::ConstIterator it = hosts.begin(); it != hosts.end(); ++it) {
 
2211
                QDomElement shost = doc()->createElement("streamhost");
 
2212
                shost.setAttribute("jid", (*it).jid().full());
 
2213
                shost.setAttribute("host", (*it).host());
 
2214
                shost.setAttribute("port", QString::number((*it).port()));
 
2215
                if((*it).isProxy()) {
 
2216
                        QDomElement p = doc()->createElement("proxy");
 
2217
                        p.setAttribute("xmlns", "http://affinix.com/jabber/stream");
 
2218
                        shost.appendChild(p);
 
2219
                }
 
2220
                query.appendChild(shost);
 
2221
        }
 
2222
        if(fast) {
 
2223
                QDomElement e = doc()->createElement("fast");
 
2224
                e.setAttribute("xmlns", "http://affinix.com/jabber/stream");
 
2225
                query.appendChild(e);
 
2226
        }
 
2227
        d->iq = iq;
 
2228
}
 
2229
 
 
2230
void JT_S5B::requestProxyInfo(const Jid &to)
 
2231
{
 
2232
        d->mode = 1;
 
2233
 
 
2234
        QDomElement iq;
 
2235
        d->to = to;
 
2236
        iq = createIQ(doc(), "get", to.full(), id());
 
2237
        QDomElement query = doc()->createElement("query");
 
2238
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
2239
        iq.appendChild(query);
 
2240
        d->iq = iq;
 
2241
}
 
2242
 
 
2243
void JT_S5B::requestActivation(const Jid &to, const QString &sid, const Jid &target)
 
2244
{
 
2245
        d->mode = 2;
 
2246
 
 
2247
        QDomElement iq;
 
2248
        d->to = to;
 
2249
        iq = createIQ(doc(), "set", to.full(), id());
 
2250
        QDomElement query = doc()->createElement("query");
 
2251
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
2252
        query.setAttribute("sid", sid);
 
2253
        iq.appendChild(query);
 
2254
        QDomElement act = doc()->createElement("activate");
 
2255
        act.appendChild(doc()->createTextNode(target.full()));
 
2256
        query.appendChild(act);
 
2257
        d->iq = iq;
 
2258
}
 
2259
 
 
2260
void JT_S5B::onGo()
 
2261
{
 
2262
        if(d->mode == 1)
 
2263
                d->t.start(15000, true);
 
2264
        send(d->iq);
 
2265
}
 
2266
 
 
2267
void JT_S5B::onDisconnect()
 
2268
{
 
2269
        d->t.stop();
 
2270
}
 
2271
 
 
2272
bool JT_S5B::take(const QDomElement &x)
 
2273
{
 
2274
        if(d->mode == -1)
 
2275
                return false;
 
2276
 
 
2277
        if(!iqVerify(x, d->to, id()))
 
2278
                return false;
 
2279
 
 
2280
        d->t.stop();
 
2281
 
 
2282
        if(x.attribute("type") == "result") {
 
2283
                QDomElement q = queryTag(x);
 
2284
                if(d->mode == 0) {
 
2285
                        d->streamHost = "";
 
2286
                        if(!q.isNull()) {
 
2287
                                QDomElement shost = q.elementsByTagName("streamhost-used").item(0).toElement();
 
2288
                                if(!shost.isNull())
 
2289
                                        d->streamHost = shost.attribute("jid");
 
2290
                        }
 
2291
 
 
2292
                        setSuccess();
 
2293
                }
 
2294
                else if(d->mode == 1) {
 
2295
                        if(!q.isNull()) {
 
2296
                                QDomElement shost = q.elementsByTagName("streamhost").item(0).toElement();
 
2297
                                if(!shost.isNull()) {
 
2298
                                        Jid j = shost.attribute("jid");
 
2299
                                        if(j.isValid()) {
 
2300
                                                QString host = shost.attribute("host");
 
2301
                                                if(!host.isEmpty()) {
 
2302
                                                        int port = shost.attribute("port").toInt();
 
2303
                                                        StreamHost h;
 
2304
                                                        h.setJid(j);
 
2305
                                                        h.setHost(host);
 
2306
                                                        h.setPort(port);
 
2307
                                                        h.setIsProxy(true);
 
2308
                                                        d->proxyInfo = h;
 
2309
                                                }
 
2310
                                        }
 
2311
                                }
 
2312
                        }
 
2313
 
 
2314
                        setSuccess();
 
2315
                }
 
2316
                else {
 
2317
                        setSuccess();
 
2318
                }
 
2319
        }
 
2320
        else {
 
2321
                setError(x);
 
2322
        }
 
2323
 
 
2324
        return true;
 
2325
}
 
2326
 
 
2327
void JT_S5B::t_timeout()
 
2328
{
 
2329
        d->mode = -1;
 
2330
        setError(500, "Timed out");
 
2331
}
 
2332
 
 
2333
Jid JT_S5B::streamHostUsed() const
 
2334
{
 
2335
        return d->streamHost;
 
2336
}
 
2337
 
 
2338
StreamHost JT_S5B::proxyInfo() const
 
2339
{
 
2340
        return d->proxyInfo;
 
2341
}
 
2342
 
 
2343
//----------------------------------------------------------------------------
 
2344
// JT_PushS5B
 
2345
//----------------------------------------------------------------------------
 
2346
JT_PushS5B::JT_PushS5B(Task *parent)
 
2347
:Task(parent)
 
2348
{
 
2349
}
 
2350
 
 
2351
JT_PushS5B::~JT_PushS5B()
 
2352
{
 
2353
}
 
2354
 
 
2355
int JT_PushS5B::priority() const
 
2356
{
 
2357
        return 1;
 
2358
}
 
2359
 
 
2360
bool JT_PushS5B::take(const QDomElement &e)
 
2361
{
 
2362
        // look for udpsuccess
 
2363
        if(e.tagName() == "message") {
 
2364
                QDomElement x = e.elementsByTagName("udpsuccess").item(0).toElement();
 
2365
                if(!x.isNull() && x.attribute("xmlns") == "http://jabber.org/protocol/bytestreams") {
 
2366
                        incomingUDPSuccess(Jid(x.attribute("from")), x.attribute("dstaddr"));
 
2367
                        return true;
 
2368
                }
 
2369
                x = e.elementsByTagName("activate").item(0).toElement();
 
2370
                if(!x.isNull() && x.attribute("xmlns") == "http://affinix.com/jabber/stream") {
 
2371
                        incomingActivate(Jid(x.attribute("from")), x.attribute("sid"), Jid(x.attribute("jid")));
 
2372
                        return true;
 
2373
                }
 
2374
                return false;
 
2375
        }
 
2376
 
 
2377
        // must be an iq-set tag
 
2378
        if(e.tagName() != "iq")
 
2379
                return false;
 
2380
        if(e.attribute("type") != "set")
 
2381
                return false;
 
2382
        if(queryNS(e) != "http://jabber.org/protocol/bytestreams")
 
2383
                return false;
 
2384
 
 
2385
        Jid from(e.attribute("from"));
 
2386
        QDomElement q = queryTag(e);
 
2387
        QString sid = q.attribute("sid");
 
2388
 
 
2389
        StreamHostList hosts;
 
2390
        QDomNodeList nl = q.elementsByTagName("streamhost");
 
2391
        for(uint n = 0; n < nl.count(); ++n) {
 
2392
                QDomElement shost = nl.item(n).toElement();
 
2393
                if(hosts.count() < MAXSTREAMHOSTS) {
 
2394
                        Jid j = shost.attribute("jid");
 
2395
                        if(!j.isValid())
 
2396
                                continue;
 
2397
                        QString host = shost.attribute("host");
 
2398
                        if(host.isEmpty())
 
2399
                                continue;
 
2400
                        int port = shost.attribute("port").toInt();
 
2401
                        QDomElement p = shost.elementsByTagName("proxy").item(0).toElement();
 
2402
                        bool isProxy = false;
 
2403
                        if(!p.isNull() && p.attribute("xmlns") == "http://affinix.com/jabber/stream")
 
2404
                                isProxy = true;
 
2405
 
 
2406
                        StreamHost h;
 
2407
                        h.setJid(j);
 
2408
                        h.setHost(host);
 
2409
                        h.setPort(port);
 
2410
                        h.setIsProxy(isProxy);
 
2411
                        hosts += h;
 
2412
                }
 
2413
        }
 
2414
 
 
2415
        bool fast = false;
 
2416
        QDomElement t;
 
2417
        t = q.elementsByTagName("fast").item(0).toElement();
 
2418
        if(!t.isNull() && t.attribute("xmlns") == "http://affinix.com/jabber/stream")
 
2419
                fast = true;
 
2420
 
 
2421
        S5BRequest r;
 
2422
        r.from = from;
 
2423
        r.id = e.attribute("id");
 
2424
        r.sid = sid;
 
2425
        r.hosts = hosts;
 
2426
        r.fast = fast;
 
2427
        r.udp = q.attribute("mode") == "udp" ? true: false;
 
2428
 
 
2429
        incoming(r);
 
2430
        return true;
 
2431
}
 
2432
 
 
2433
void JT_PushS5B::respondSuccess(const Jid &to, const QString &id, const Jid &streamHost)
 
2434
{
 
2435
        QDomElement iq = createIQ(doc(), "result", to.full(), id);
 
2436
        QDomElement query = doc()->createElement("query");
 
2437
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
2438
        iq.appendChild(query);
 
2439
        QDomElement shost = doc()->createElement("streamhost-used");
 
2440
        shost.setAttribute("jid", streamHost.full());
 
2441
        query.appendChild(shost);
 
2442
        send(iq);
 
2443
}
 
2444
 
 
2445
void JT_PushS5B::respondError(const Jid &to, const QString &id, int code, const QString &str)
 
2446
{
 
2447
        QDomElement iq = createIQ(doc(), "error", to.full(), id);
 
2448
        QDomElement err = textTag(doc(), "error", str);
 
2449
        err.setAttribute("code", QString::number(code));
 
2450
        iq.appendChild(err);
 
2451
        send(iq);
 
2452
}
 
2453
 
 
2454
void JT_PushS5B::sendUDPSuccess(const Jid &to, const QString &dstaddr)
 
2455
{
 
2456
        QDomElement m = doc()->createElement("message");
 
2457
        m.setAttribute("to", to.full());
 
2458
        QDomElement u = doc()->createElement("udpsuccess");
 
2459
        u.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
2460
        u.setAttribute("dstaddr", dstaddr);
 
2461
        m.appendChild(u);
 
2462
        send(m);
 
2463
}
 
2464
 
 
2465
void JT_PushS5B::sendActivate(const Jid &to, const QString &sid, const Jid &streamHost)
 
2466
{
 
2467
        QDomElement m = doc()->createElement("message");
 
2468
        m.setAttribute("to", to.full());
 
2469
        QDomElement act = doc()->createElement("activate");
 
2470
        act.setAttribute("xmlns", "http://affinix.com/jabber/stream");
 
2471
        act.setAttribute("sid", sid);
 
2472
        act.setAttribute("jid", streamHost.full());
 
2473
        m.appendChild(act);
 
2474
        send(m);
 
2475
}
 
2476
 
 
2477
//----------------------------------------------------------------------------
 
2478
// StreamHost
 
2479
//----------------------------------------------------------------------------
 
2480
StreamHost::StreamHost()
 
2481
{
 
2482
        v_port = -1;
 
2483
        proxy = false;
 
2484
}
 
2485
 
 
2486
const Jid & StreamHost::jid() const
 
2487
{
 
2488
        return j;
 
2489
}
 
2490
 
 
2491
const QString & StreamHost::host() const
 
2492
{
 
2493
        return v_host;
 
2494
}
 
2495
 
 
2496
int StreamHost::port() const
 
2497
{
 
2498
        return v_port;
 
2499
}
 
2500
 
 
2501
bool StreamHost::isProxy() const
 
2502
{
 
2503
        return proxy;
 
2504
}
 
2505
 
 
2506
void StreamHost::setJid(const Jid &_j)
 
2507
{
 
2508
        j = _j;
 
2509
}
 
2510
 
 
2511
void StreamHost::setHost(const QString &host)
 
2512
{
 
2513
        v_host = host;
 
2514
}
 
2515
 
 
2516
void StreamHost::setPort(int port)
 
2517
{
 
2518
        v_port = port;
 
2519
}
 
2520
 
 
2521
void StreamHost::setIsProxy(bool b)
 
2522
{
 
2523
        proxy = b;
 
2524
}
 
2525
 
 
2526
}
 
2527
 
 
2528
#include"s5b.moc"