2 * s5b.cpp - direct connection protocol via tcp
3 * Copyright (C) 2003 Justin Karneges
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "xmpp_xmlcommon.h"
31 #include "safedelete.h"
36 # include <netinet/in.h>
39 #define MAXSTREAMHOSTS 5
41 static const char *S5B_NS
= "http://jabber.org/protocol/bytestreams";
47 static QString
makeKey(const QString
&sid
, const Jid
&initiator
, const Jid
&target
)
50 qDebug("makeKey: sid=%s initiator=%s target=%s", qPrintable(sid
),
51 qPrintable(initiator
.full()), qPrintable(target
.full()));
53 QString str
= sid
+ initiator
.full() + target
.full();
54 return QCA::Hash("sha1").hashToString(str
.toUtf8());
57 static bool haveHost(const StreamHostList
&list
, const Jid
&j
)
59 for(StreamHostList::ConstIterator it
= list
.begin(); it
!= list
.end(); ++it
) {
60 if((*it
).jid().compare(j
))
66 class S5BManager::Item
: public QObject
70 enum { Idle
, Initiator
, Target
, Active
};
71 enum { ErrRefused
, ErrConnect
, ErrWrongHost
, ErrProxy
};
72 enum { Unknown
, Fast
, NotFast
};
75 QString sid
, key
, out_key
, out_id
, in_id
;
77 StreamHostList in_hosts
;
78 JT_S5B
*task
, *proxy_task
;
79 SocksClient
*client
, *client_out
;
80 SocksUDP
*client_udp
, *client_out_udp
;
81 S5BConnector
*conn
, *proxy_conn
;
84 int targetMode
; // initiator sets this once it figures it out
85 bool fast
; // target sets this
89 bool localFailed
, remoteFailed
;
95 Item(S5BManager
*manager
);
99 void startInitiator(const QString
&_sid
, const Jid
&_self
, const Jid
&_peer
, bool fast
, bool udp
);
100 void startTarget(const QString
&_sid
, const Jid
&_self
, const Jid
&_peer
, const StreamHostList
&hosts
, const QString
&iq_id
, bool fast
, bool udp
);
101 void handleFast(const StreamHostList
&hosts
, const QString
&iq_id
);
105 void setIncomingClient(SocksClient
*sc
);
106 void incomingActivate(const Jid
&streamHost
);
110 void tryingHosts(const StreamHostList
&list
);
112 void waitingForActivation();
118 void conn_result(bool b
);
119 void proxy_result(bool b
);
120 void proxy_finished();
122 void sc_bytesWritten(int);
126 void doConnectError();
127 void tryActivation();
128 void checkForActivation();
133 //----------------------------------------------------------------------------
135 //----------------------------------------------------------------------------
136 S5BDatagram::S5BDatagram()
142 S5BDatagram::S5BDatagram(int source
, int dest
, const QByteArray
&data
)
149 int S5BDatagram::sourcePort() const
154 int S5BDatagram::destPort() const
159 QByteArray
S5BDatagram::data() const
164 //----------------------------------------------------------------------------
166 //----------------------------------------------------------------------------
167 class S5BConnection::Private
178 bool notifyRead
, notifyClose
;
183 QList
<S5BDatagram
*> dglist
;
186 static int id_conn
= 0;
187 static int num_conn
= 0;
189 S5BConnection::S5BConnection(S5BManager
*m
, QObject
*parent
)
190 : BSConnection(parent
)
200 qDebug("S5BConnection[%d]: constructing, count=%d, %p\n", d
->id
, num_conn
, this);
206 S5BConnection::~S5BConnection()
212 qDebug("S5BConnection[%d]: destructing, count=%d\n", d
->id
, num_conn
);
218 void S5BConnection::reset(bool clear
)
220 d
->m
->con_unlink(this);
228 while (!d
->dglist
.isEmpty()) {
229 delete d
->dglist
.takeFirst();
237 d
->notifyRead
= false;
238 d
->notifyClose
= false;
241 Jid
S5BConnection::proxy() const
246 void S5BConnection::setProxy(const Jid
&proxy
)
251 void S5BConnection::connectToJid(const Jid
&peer
, const QString
&sid
, Mode m
)
254 if(!d
->m
->isAcceptableSID(peer
, sid
))
259 d
->state
= Requesting
;
262 qDebug("S5BConnection[%d]: connecting %s [%s]\n", d
->id
, qPrintable(d
->peer
.full()), qPrintable(d
->sid
));
264 d
->m
->con_connect(this);
267 void S5BConnection::accept()
269 if(d
->state
!= WaitingForAccept
)
272 d
->state
= Connecting
;
274 qDebug("S5BConnection[%d]: accepting %s [%s]\n", d
->id
, qPrintable(d
->peer
.full()), qPrintable(d
->sid
));
276 d
->m
->con_accept(this);
279 void S5BConnection::close()
284 if(d
->state
== WaitingForAccept
)
285 d
->m
->con_reject(this);
286 else if(d
->state
== Active
)
289 qDebug("S5BConnection[%d]: closing %s [%s]\n", d
->id
, qPrintable(d
->peer
.full()), qPrintable(d
->sid
));
294 Jid
S5BConnection::peer() const
299 QString
S5BConnection::sid() const
304 BytestreamManager
* S5BConnection::manager() const
309 bool S5BConnection::isRemote() const
314 S5BConnection::Mode
S5BConnection::mode() const
319 int S5BConnection::state() const
324 bool S5BConnection::isOpen() const
326 if(d
->state
== Active
)
332 void S5BConnection::write(const QByteArray
&buf
)
334 if(d
->state
== Active
&& d
->mode
== Stream
)
338 QByteArray
S5BConnection::read(int bytes
)
341 return d
->sc
->read(bytes
);
346 int S5BConnection::bytesAvailable() const
349 return d
->sc
->bytesAvailable();
354 int S5BConnection::bytesToWrite() const
356 if(d
->state
== Active
)
357 return d
->sc
->bytesToWrite();
362 void S5BConnection::writeDatagram(const S5BDatagram
&i
)
365 buf
.resize(i
.data().size() + 4);
366 ushort ssp
= htons(i
.sourcePort());
367 ushort sdp
= htons(i
.destPort());
368 QByteArray data
= i
.data();
369 memcpy(buf
.data(), &ssp
, 2);
370 memcpy(buf
.data() + 2, &sdp
, 2);
371 memcpy(buf
.data() + 4, data
.data(), data
.size());
375 S5BDatagram
S5BConnection::readDatagram()
377 if(d
->dglist
.isEmpty())
378 return S5BDatagram();
379 S5BDatagram
*i
= d
->dglist
.takeFirst();
380 S5BDatagram val
= *i
;
385 int S5BConnection::datagramsAvailable() const
387 return d
->dglist
.count();
390 void S5BConnection::man_waitForAccept(const S5BRequest
&r
)
392 d
->state
= WaitingForAccept
;
397 d
->mode
= r
.udp
? Datagram
: Stream
;
400 void S5BConnection::man_clientReady(SocksClient
*sc
, SocksUDP
*sc_udp
)
403 connect(d
->sc
, SIGNAL(connectionClosed()), SLOT(sc_connectionClosed()));
404 connect(d
->sc
, SIGNAL(delayedCloseFinished()), SLOT(sc_delayedCloseFinished()));
405 connect(d
->sc
, SIGNAL(readyRead()), SLOT(sc_readyRead()));
406 connect(d
->sc
, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
407 connect(d
->sc
, SIGNAL(error(int)), SLOT(sc_error(int)));
411 connect(d
->su
, SIGNAL(packetReady(const QByteArray
&)), SLOT(su_packetReady(const QByteArray
&)));
416 qDebug("S5BConnection[%d]: %s [%s] <<< success >>>\n", d
->id
, qPrintable(d
->peer
.full()), qPrintable(d
->sid
));
419 // bytes already in the stream?
420 if(d
->sc
->bytesAvailable()) {
422 qDebug("Stream has %d bytes in it.\n", d
->sc
->bytesAvailable());
424 d
->notifyRead
= true;
426 // closed before it got here?
427 if(!d
->sc
->isOpen()) {
429 qDebug("Stream was closed before S5B request finished?\n");
431 d
->notifyClose
= true;
433 if(d
->notifyRead
|| d
->notifyClose
)
434 QTimer::singleShot(0, this, SLOT(doPending()));
438 void S5BConnection::doPending()
442 QTimer::singleShot(0, this, SLOT(doPending()));
445 else if(d
->notifyClose
)
446 sc_connectionClosed();
449 void S5BConnection::man_udpReady(const QByteArray
&buf
)
454 void S5BConnection::man_failed(int x
)
457 if(x
== S5BManager::Item::ErrRefused
)
459 if(x
== S5BManager::Item::ErrConnect
)
461 if(x
== S5BManager::Item::ErrWrongHost
)
463 if(x
== S5BManager::Item::ErrProxy
)
467 void S5BConnection::sc_connectionClosed()
469 // if we have a pending read notification, postpone close
472 qDebug("closed while pending read\n");
474 d
->notifyClose
= true;
477 d
->notifyClose
= false;
482 void S5BConnection::sc_delayedCloseFinished()
485 delayedCloseFinished();
488 void S5BConnection::sc_readyRead()
490 if(d
->mode
== Datagram
) {
491 // throw the data away
496 d
->notifyRead
= false;
501 void S5BConnection::sc_bytesWritten(int x
)
507 void S5BConnection::sc_error(int)
513 void S5BConnection::su_packetReady(const QByteArray
&buf
)
518 void S5BConnection::handleUDP(const QByteArray
&buf
)
520 // must be at least 4 bytes, to accomodate virtual ports
525 memcpy(&ssp
, buf
.data(), 2);
526 memcpy(&sdp
, buf
.data() + 2, 2);
527 int source
= ntohs(ssp
);
528 int dest
= ntohs(sdp
);
530 data
.resize(buf
.size() - 4);
531 memcpy(data
.data(), buf
.data() + 4, data
.size());
532 d
->dglist
.append(new S5BDatagram(source
, dest
, data
));
537 void S5BConnection::sendUDP(const QByteArray
&buf
)
542 d
->m
->con_sendUDP(this, buf
);
545 //----------------------------------------------------------------------------
547 //----------------------------------------------------------------------------
548 class S5BManager::Entry
567 StreamHost proxyInfo
;
568 QPointer
<S5BServer
> relatedServer
;
571 QHostAddress udp_addr
;
575 class S5BManager::Private
580 QList
<Entry
*> activeList
;
581 S5BConnectionList incomingConns
;
585 S5BManager::S5BManager(Client
*parent
)
586 : BytestreamManager(parent
)
589 //if(!QCA::isSupported(QCA::CAP_SHA1))
590 // QCA::insertProvider(createProviderHash());
596 d
->ps
= new JT_PushS5B(d
->client
->rootTask());
597 connect(d
->ps
, SIGNAL(incoming(const S5BRequest
&)), SLOT(ps_incoming(const S5BRequest
&)));
598 connect(d
->ps
, SIGNAL(incomingUDPSuccess(const Jid
&, const QString
&)), SLOT(ps_incomingUDPSuccess(const Jid
&, const QString
&)));
599 connect(d
->ps
, SIGNAL(incomingActivate(const Jid
&, const QString
&, const Jid
&)), SLOT(ps_incomingActivate(const Jid
&, const QString
&, const Jid
&)));
602 S5BManager::~S5BManager()
605 while (!d
->incomingConns
.isEmpty()) {
606 delete d
->incomingConns
.takeFirst();
612 const char* S5BManager::ns()
617 Client
*S5BManager::client() const
622 S5BServer
*S5BManager::server() const
627 void S5BManager::setServer(S5BServer
*serv
)
630 d
->serv
->unlink(this);
640 S5BConnection
*S5BManager::createConnection()
642 return new S5BConnection(this);
645 S5BConnection
*S5BManager::takeIncoming()
647 if(d
->incomingConns
.isEmpty())
650 S5BConnection
*c
= d
->incomingConns
.takeFirst();
652 // move to activeList
653 Entry
*e
= new Entry
;
656 d
->activeList
.append(e
);
661 void S5BManager::ps_incoming(const S5BRequest
&req
)
664 qDebug("S5BManager: incoming from %s\n", qPrintable(req
.from
.full()));
668 // ensure we don't already have an incoming connection from this peer+sid
669 S5BConnection
*c
= findIncoming(req
.from
, req
.sid
);
671 // do we have an active entry with this sid already?
672 Entry
*e
= findEntryBySID(req
.from
, req
.sid
);
676 if(req
.from
.compare(localPeer(req
.from
)) && (req
.id
== e
->i
->out_id
)) {
678 qDebug("ALLOWED: loopback\n");
682 // allowed by 'fast mode'
683 else if(e
->i
->state
== Item::Initiator
&& e
->i
->targetMode
== Item::Unknown
) {
685 qDebug("ALLOWED: fast-mode\n");
687 e
->i
->handleFast(req
.hosts
, req
.id
);
694 qDebug("ALLOWED: we don't have it\n");
700 d
->ps
->respondError(req
.from
, req
.id
, Stanza::Error::NotAcceptable
, "SID in use");
704 // create an incoming connection
705 c
= new S5BConnection(this);
706 c
->man_waitForAccept(req
);
707 d
->incomingConns
.append(c
);
711 void S5BManager::ps_incomingUDPSuccess(const Jid
&from
, const QString
&key
)
713 Entry
*e
= findEntryByHash(key
);
716 e
->i
->conn
->man_udpSuccess(from
);
717 else if(e
->i
->proxy_conn
)
718 e
->i
->proxy_conn
->man_udpSuccess(from
);
722 void S5BManager::ps_incomingActivate(const Jid
&from
, const QString
&sid
, const Jid
&streamHost
)
724 Entry
*e
= findEntryBySID(from
, sid
);
726 e
->i
->incomingActivate(streamHost
);
729 void S5BManager::doSuccess(const Jid
&peer
, const QString
&id
, const Jid
&streamHost
)
731 d
->ps
->respondSuccess(peer
, id
, streamHost
);
734 void S5BManager::doError(const Jid
&peer
, const QString
&id
,
735 Stanza::Error::ErrorCond cond
, const QString
&str
)
737 d
->ps
->respondError(peer
, id
, cond
, str
);
740 void S5BManager::doActivate(const Jid
&peer
, const QString
&sid
, const Jid
&streamHost
)
742 d
->ps
->sendActivate(peer
, sid
, streamHost
);
745 Jid
S5BManager::localPeer(const Jid
&peer
) const
747 QString gcNick
= d
->client
->groupChatNick(peer
.domain(), peer
.node());
748 return gcNick
.isEmpty() ? d
->client
->jid() : peer
.withResource(gcNick
);
751 bool S5BManager::isAcceptableSID(const Jid
&peer
, const QString
&sid
) const
753 Jid lp
= localPeer(peer
);
754 QString key
= makeKey(sid
, lp
, peer
);
755 QString key_out
= makeKey(sid
, peer
, lp
);
757 // if we have a server, then check through it
759 if(findServerEntryByHash(key
) || findServerEntryByHash(key_out
))
763 if(findEntryByHash(key
) || findEntryByHash(key_out
))
769 const char* S5BManager::sidPrefix() const
774 S5BConnection
*S5BManager::findIncoming(const Jid
&from
, const QString
&sid
) const
776 foreach(S5BConnection
*c
, d
->incomingConns
) {
777 if(c
->d
->peer
.compare(from
) && c
->d
->sid
== sid
)
783 S5BManager::Entry
*S5BManager::findEntry(S5BConnection
*c
) const
785 foreach(Entry
*e
, d
->activeList
) {
792 S5BManager::Entry
*S5BManager::findEntry(Item
*i
) const
794 foreach(Entry
*e
, d
->activeList
) {
801 S5BManager::Entry
*S5BManager::findEntryByHash(const QString
&key
) const
803 foreach(Entry
*e
, d
->activeList
) {
804 if(e
->i
&& e
->i
->key
== key
)
810 S5BManager::Entry
*S5BManager::findEntryBySID(const Jid
&peer
, const QString
&sid
) const
812 foreach(Entry
*e
, d
->activeList
) {
813 if(e
->i
&& e
->i
->peer
.compare(peer
) && e
->sid
== sid
)
819 S5BManager::Entry
*S5BManager::findServerEntryByHash(const QString
&key
) const
821 const QList
<S5BManager
*> &manList
= d
->serv
->managerList();
822 foreach(S5BManager
*m
, manList
) {
823 Entry
*e
= m
->findEntryByHash(key
);
830 bool S5BManager::srv_ownsHash(const QString
&key
) const
832 if(findEntryByHash(key
))
837 void S5BManager::srv_incomingReady(SocksClient
*sc
, const QString
&key
)
839 Entry
*e
= findEntryByHash(key
);
840 if(!e
->i
->allowIncoming
) {
842 SafeDelete::deleteSingle(sc
);
845 if(e
->c
->d
->mode
== S5BConnection::Datagram
)
846 sc
->grantUDPAssociate("", 0);
849 e
->relatedServer
= (S5BServer
*)sender();
850 e
->i
->setIncomingClient(sc
);
853 void S5BManager::srv_incomingUDP(bool init
, const QHostAddress
&addr
, int port
, const QString
&key
, const QByteArray
&data
)
855 Entry
*e
= findEntryByHash(key
);
856 if(!e
->c
->d
->mode
!= S5BConnection::Datagram
)
857 return; // this key isn't in udp mode? drop!
861 return; // only init once
863 // lock on to this sender
868 // reply that initialization was successful
869 d
->ps
->sendUDPSuccess(e
->c
->d
->peer
, key
);
873 // not initialized yet? something went wrong
877 // must come from same source as when initialized
878 if(addr
.toString() != e
->udp_addr
.toString() || port
!= e
->udp_port
)
881 e
->c
->man_udpReady(data
);
884 void S5BManager::srv_unlink()
889 void S5BManager::con_connect(S5BConnection
*c
)
893 Entry
*e
= new Entry
;
896 d
->activeList
.append(e
);
898 if(c
->d
->proxy
.isValid()) {
905 void S5BManager::con_accept(S5BConnection
*c
)
907 Entry
*e
= findEntry(c
);
911 if(e
->c
->d
->req
.fast
) {
912 if(targetShouldOfferProxy(e
)) {
920 void S5BManager::con_reject(S5BConnection
*c
)
922 d
->ps
->respondError(c
->d
->peer
, c
->d
->req
.id
, Stanza::Error::NotAcceptable
,
926 void S5BManager::con_unlink(S5BConnection
*c
)
928 Entry
*e
= findEntry(c
);
932 // active incoming request? cancel it
933 if(e
->i
&& e
->i
->conn
)
934 d
->ps
->respondError(e
->i
->peer
, e
->i
->out_id
,
935 Stanza::Error::NotAcceptable
, "Not acceptable");
937 d
->activeList
.removeAll(e
);
941 void S5BManager::con_sendUDP(S5BConnection
*c
, const QByteArray
&buf
)
943 Entry
*e
= findEntry(c
);
950 e
->relatedServer
->writeUDP(e
->udp_addr
, e
->udp_port
, buf
);
953 void S5BManager::item_accepted()
955 Item
*i
= (Item
*)sender();
956 Entry
*e
= findEntry(i
);
958 emit e
->c
->accepted(); // signal
961 void S5BManager::item_tryingHosts(const StreamHostList
&list
)
963 Item
*i
= (Item
*)sender();
964 Entry
*e
= findEntry(i
);
966 e
->c
->tryingHosts(list
); // signal
969 void S5BManager::item_proxyConnect()
971 Item
*i
= (Item
*)sender();
972 Entry
*e
= findEntry(i
);
974 e
->c
->proxyConnect(); // signal
977 void S5BManager::item_waitingForActivation()
979 Item
*i
= (Item
*)sender();
980 Entry
*e
= findEntry(i
);
982 e
->c
->waitingForActivation(); // signal
985 void S5BManager::item_connected()
987 Item
*i
= (Item
*)sender();
988 Entry
*e
= findEntry(i
);
991 SocksClient
*client
= i
->client
;
993 SocksUDP
*client_udp
= i
->client_udp
;
996 // give it to the connection
997 e
->c
->man_clientReady(client
, client_udp
);
1000 void S5BManager::item_error(int x
)
1002 Item
*i
= (Item
*)sender();
1003 Entry
*e
= findEntry(i
);
1005 e
->c
->man_failed(x
);
1008 void S5BManager::entryContinue(Entry
*e
)
1010 e
->i
= new Item(this);
1011 e
->i
->proxy
= e
->proxyInfo
;
1013 connect(e
->i
, SIGNAL(accepted()), SLOT(item_accepted()));
1014 connect(e
->i
, SIGNAL(tryingHosts(const StreamHostList
&)), SLOT(item_tryingHosts(const StreamHostList
&)));
1015 connect(e
->i
, SIGNAL(proxyConnect()), SLOT(item_proxyConnect()));
1016 connect(e
->i
, SIGNAL(waitingForActivation()), SLOT(item_waitingForActivation()));
1017 connect(e
->i
, SIGNAL(connected()), SLOT(item_connected()));
1018 connect(e
->i
, SIGNAL(error(int)), SLOT(item_error(int)));
1020 if(e
->c
->isRemote()) {
1021 const S5BRequest
&req
= e
->c
->d
->req
;
1022 e
->i
->startTarget(e
->sid
, localPeer(e
->c
->d
->peer
), e
->c
->d
->peer
, req
.hosts
, req
.id
, req
.fast
, req
.udp
);
1025 e
->i
->startInitiator(e
->sid
, localPeer(e
->c
->d
->peer
), e
->c
->d
->peer
, true, e
->c
->d
->mode
== S5BConnection::Datagram
? true: false);
1026 e
->c
->requesting(); // signal
1030 void S5BManager::queryProxy(Entry
*e
)
1032 QPointer
<QObject
> self
= this;
1033 e
->c
->proxyQuery(); // signal
1038 qDebug("querying proxy: [%s]\n", qPrintable(e
->c
->d
->proxy
.full()));
1040 e
->query
= new JT_S5B(d
->client
->rootTask());
1041 connect(e
->query
, SIGNAL(finished()), SLOT(query_finished()));
1042 e
->query
->requestProxyInfo(e
->c
->d
->proxy
);
1046 void S5BManager::query_finished()
1048 JT_S5B
*query
= (JT_S5B
*)sender();
1050 foreach(Entry
* i
, d
->activeList
) {
1051 if(i
->query
== query
) {
1061 qDebug("query finished: ");
1063 if(query
->success()) {
1064 e
->proxyInfo
= query
->proxyInfo();
1066 qDebug("host/ip=[%s] port=[%d]\n", qPrintable(e
->proxyInfo
.host()), e
->proxyInfo
.port());
1075 QPointer
<QObject
> self
= this;
1076 e
->c
->proxyResult(query
->success()); // signal
1083 bool S5BManager::targetShouldOfferProxy(Entry
*e
)
1085 if(!e
->c
->d
->proxy
.isValid())
1088 // if target, don't offer any proxy if the initiator already did
1089 const StreamHostList
&hosts
= e
->c
->d
->req
.hosts
;
1090 for(StreamHostList::ConstIterator it
= hosts
.begin(); it
!= hosts
.end(); ++it
) {
1095 // ensure we don't offer the same proxy as the initiator
1096 if(haveHost(hosts
, e
->c
->d
->proxy
))
1102 //----------------------------------------------------------------------------
1104 //----------------------------------------------------------------------------
1105 S5BManager::Item::Item(S5BManager
*manager
) : QObject(0)
1119 S5BManager::Item::~Item()
1124 void S5BManager::Item::reset()
1144 delete client_out_udp
;
1152 targetMode
= Unknown
;
1156 connSuccess
= false;
1157 localFailed
= false;
1158 remoteFailed
= false;
1159 allowIncoming
= false;
1163 void S5BManager::Item::startInitiator(const QString
&_sid
, const Jid
&_self
, const Jid
&_peer
, bool fast
, bool _udp
)
1168 key
= makeKey(sid
, self
, peer
);
1169 out_key
= makeKey(sid
, peer
, self
);
1174 qDebug("S5BManager::Item initiating request %s [%s] (inhash=%s)\n", qPrintable(peer
.full()), qPrintable(sid
), qPrintable(key
));
1180 void S5BManager::Item::startTarget(const QString
&_sid
, const Jid
&_self
, const Jid
&_peer
, const StreamHostList
&hosts
, const QString
&iq_id
, bool _fast
, bool _udp
)
1188 key
= makeKey(sid
, self
, peer
);
1189 out_key
= makeKey(sid
, peer
, self
);
1193 qDebug("S5BManager::Item incoming request %s [%s] (inhash=%s)\n", qPrintable(peer
.full()), qPrintable(sid
), qPrintable(key
));
1201 void S5BManager::Item::handleFast(const StreamHostList
&hosts
, const QString
&iq_id
)
1205 QPointer
<QObject
> self
= this;
1210 // if we already have a stream, then bounce this request
1212 m
->doError(peer
, iq_id
, Stanza::Error::NotAcceptable
, "Not acceptable");
1221 void S5BManager::Item::doOutgoing()
1223 StreamHostList hosts
;
1224 S5BServer
*serv
= m
->server();
1225 if(serv
&& serv
->isActive() && !haveHost(in_hosts
, self
)) {
1226 QStringList hostList
= serv
->hostList();
1227 for(QStringList::ConstIterator it
= hostList
.begin(); it
!= hostList
.end(); ++it
) {
1231 h
.setPort(serv
->port());
1236 // if the proxy is valid, then it's ok to add (the manager already ensured that it doesn't conflict)
1237 if(proxy
.jid().isValid())
1240 // if we're the target and we have no streamhosts of our own, then don't even bother with fast-mode
1241 if(state
== Target
&& hosts
.isEmpty()) {
1246 allowIncoming
= true;
1248 task
= new JT_S5B(m
->client()->rootTask());
1249 connect(task
, SIGNAL(finished()), SLOT(jt_finished()));
1250 task
->request(peer
, sid
, hosts
, state
== Initiator
? wantFast
: false, udp
);
1251 out_id
= task
->id();
1255 void S5BManager::Item::doIncoming()
1257 if(in_hosts
.isEmpty()) {
1262 StreamHostList list
;
1264 // take just the proxy streamhosts
1265 for(StreamHostList::ConstIterator it
= in_hosts
.begin(); it
!= in_hosts
.end(); ++it
) {
1272 // only try doing the late proxy trick if using fast mode AND we did not offer a proxy
1273 if((state
== Initiator
|| (state
== Target
&& fast
)) && !proxy
.jid().isValid()) {
1274 // take just the non-proxy streamhosts
1275 bool hasProxies
= false;
1276 for(StreamHostList::ConstIterator it
= in_hosts
.begin(); it
!= in_hosts
.end(); ++it
) {
1285 // no regular streamhosts? wait for remote error
1294 conn
= new S5BConnector
;
1295 connect(conn
, SIGNAL(result(bool)), SLOT(conn_result(bool)));
1297 QPointer
<QObject
> self
= this;
1302 conn
->start(this->self
, list
, out_key
, udp
, lateProxy
? 10 : 30);
1305 void S5BManager::Item::setIncomingClient(SocksClient
*sc
)
1308 qDebug("S5BManager::Item: %s [%s] successful incoming connection\n", qPrintable(peer
.full()), qPrintable(sid
));
1311 connect(sc
, SIGNAL(readyRead()), SLOT(sc_readyRead()));
1312 connect(sc
, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
1313 connect(sc
, SIGNAL(error(int)), SLOT(sc_error(int)));
1316 allowIncoming
= false;
1319 void S5BManager::Item::incomingActivate(const Jid
&streamHost
)
1322 activatedStream
= streamHost
;
1323 checkForActivation();
1327 void S5BManager::Item::jt_finished()
1333 qDebug("jt_finished: state=%s, %s\n", state
== Initiator
? "initiator" : "target", j
->success() ? "ok" : "fail");
1336 if(state
== Initiator
) {
1337 if(targetMode
== Unknown
) {
1338 targetMode
= NotFast
;
1339 QPointer
<QObject
> self
= this;
1346 // if we've already reported successfully connecting to them, then this response doesn't matter
1347 if(state
== Initiator
&& connSuccess
) {
1353 // stop connecting out
1354 if(conn
|| lateProxy
) {
1360 Jid streamHost
= j
->streamHostUsed();
1362 // they connected to us?
1363 if(streamHost
.compare(self
)) {
1365 if(state
== Initiator
) {
1366 activatedStream
= streamHost
;
1370 checkForActivation();
1374 qDebug("S5BManager::Item %s claims to have connected to us, but we don't see this\n", qPrintable(peer
.full()));
1377 error(ErrWrongHost
);
1380 else if(streamHost
.compare(proxy
.jid())) {
1381 // toss out any direct incoming, since it won't be used
1384 allowIncoming
= false;
1387 qDebug("attempting to connect to proxy\n");
1389 // connect to the proxy
1390 proxy_conn
= new S5BConnector
;
1391 connect(proxy_conn
, SIGNAL(result(bool)), SLOT(proxy_result(bool)));
1392 StreamHostList list
;
1395 QPointer
<QObject
> self
= this;
1400 proxy_conn
->start(this->self
, list
, key
, udp
, 30);
1404 qDebug("S5BManager::Item %s claims to have connected to a streamhost we never offered\n", qPrintable(peer
.full()));
1407 error(ErrWrongHost
);
1412 qDebug("S5BManager::Item %s [%s] error\n", qPrintable(peer
.full()), qPrintable(sid
));
1414 remoteFailed
= true;
1415 statusCode
= j
->statusCode();
1422 // if connSuccess is true at this point, then we're a Target
1424 checkForActivation();
1431 void S5BManager::Item::conn_result(bool b
)
1434 SocksClient
*sc
= conn
->takeClient();
1435 SocksUDP
*sc_udp
= conn
->takeUDP();
1436 StreamHost h
= conn
->streamHostUsed();
1442 qDebug("S5BManager::Item: %s [%s] successful outgoing connection\n",
1443 qPrintable(peer
.full()), qPrintable(sid
));
1446 connect(sc
, SIGNAL(readyRead()), SLOT(sc_readyRead()));
1447 connect(sc
, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
1448 connect(sc
, SIGNAL(error(int)), SLOT(sc_error(int)));
1450 m
->doSuccess(peer
, in_id
, h
.jid());
1452 // if the first batch works, don't try proxy
1455 // if initiator, run with this one
1456 if(state
== Initiator
) {
1457 // if we had an incoming one, toss it
1459 client_udp
= sc_udp
;
1462 allowIncoming
= false;
1463 activatedStream
= peer
;
1467 client_out_udp
= sc_udp
;
1469 checkForActivation();
1476 // if we delayed the proxies for later, try now
1486 void S5BManager::Item::proxy_result(bool b
)
1489 qDebug("proxy_result: %s\n", b
? "ok" : "fail");
1492 SocksClient
*sc
= proxy_conn
->takeClient();
1493 SocksUDP
*sc_udp
= proxy_conn
->takeUDP();
1497 connect(sc
, SIGNAL(readyRead()), SLOT(sc_readyRead()));
1498 connect(sc
, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
1499 connect(sc
, SIGNAL(error(int)), SLOT(sc_error(int)));
1502 client_udp
= sc_udp
;
1506 qDebug("activating proxy stream\n");
1508 proxy_task
= new JT_S5B(m
->client()->rootTask());
1509 connect(proxy_task
, SIGNAL(finished()), SLOT(proxy_finished()));
1510 proxy_task
->requestActivation(proxy
.jid(), sid
, peer
);
1511 proxy_task
->go(true);
1521 void S5BManager::Item::proxy_finished()
1523 JT_S5B
*j
= proxy_task
;
1528 qDebug("proxy stream activated\n");
1530 if(state
== Initiator
) {
1531 activatedStream
= proxy
.jid();
1535 checkForActivation();
1543 void S5BManager::Item::sc_readyRead()
1546 qDebug("sc_readyRead\n");
1548 // only targets check for activation, and only should do it if there is no pending outgoing iq-set
1549 if(state
== Target
&& !task
&& !proxy_task
)
1550 checkForActivation();
1553 void S5BManager::Item::sc_bytesWritten(int)
1556 qDebug("sc_bytesWritten\n");
1558 // this should only happen to the initiator, and should always be 1 byte (the '\r' sent earlier)
1562 void S5BManager::Item::sc_error(int)
1565 qDebug("sc_error\n");
1571 void S5BManager::Item::doConnectError()
1574 m
->doError(peer
, in_id
, Stanza::Error::RemoteServerNotFound
,
1575 "Could not connect to given hosts");
1579 void S5BManager::Item::tryActivation()
1582 qDebug("tryActivation\n");
1586 qDebug("already activated !?\n");
1591 if(targetMode
== NotFast
) {
1593 qDebug("tryActivation: NotFast\n");
1595 // nothing to activate, we're done
1598 else if(targetMode
== Fast
) {
1599 // with fast mode, we don't wait for the iq reply, so delete the task (if any)
1605 // if udp, activate using special stanza
1607 m
->doActivate(peer
, sid
, activatedStream
);
1611 qDebug("sending extra CR\n");
1613 // must send [CR] to activate target streamhost
1622 void S5BManager::Item::checkForActivation()
1624 QList
<SocksClient
*> clientList
;
1626 clientList
.append(client
);
1628 clientList
.append(client_out
);
1629 foreach(SocksClient
*sc
, clientList
) {
1631 qDebug("checking for activation\n");
1636 if((sc
== client_out
&& activatedStream
.compare(self
)) || (sc
== client
&& !activatedStream
.compare(self
))) {
1637 clientList
.removeAll(sc
);
1643 qDebug("need CR\n");
1645 if(sc
->bytesAvailable() >= 1) {
1646 clientList
.removeAll(sc
);
1647 QByteArray a
= sc
->read(1);
1657 SocksUDP
*sc_udp
= 0;
1659 delete client_out_udp
;
1661 sc_udp
= client_udp
;
1663 else if(sc
== client_out
) {
1666 sc_udp
= client_out_udp
;
1669 sc
->disconnect(this);
1670 while (!clientList
.isEmpty()) {
1671 delete clientList
.takeFirst();
1675 client_udp
= sc_udp
;
1678 qDebug("activation success\n");
1685 qDebug("not fast mode, no need to wait for anything\n");
1687 clientList
.removeAll(sc
);
1688 sc
->disconnect(this);
1689 while (!clientList
.isEmpty()) {
1690 delete clientList
.takeFirst();
1703 // only emit waitingForActivation if there is nothing left to do
1704 if((connSuccess
|| localFailed
) && !proxy_task
&& !proxy_conn
)
1705 waitingForActivation();
1709 void S5BManager::Item::checkFailure()
1711 bool failed
= false;
1712 if(state
== Initiator
) {
1714 if((localFailed
&& targetMode
== Fast
) || targetMode
== NotFast
)
1720 if((remoteFailed
&& fast
) || !fast
)
1726 if(state
== Initiator
) {
1728 if(statusCode
== 404)
1740 void S5BManager::Item::finished()
1742 client
->disconnect(this);
1745 qDebug("S5BManager::Item %s [%s] linked successfully\n", qPrintable(peer
.full()), qPrintable(sid
));
1750 //----------------------------------------------------------------------------
1752 //----------------------------------------------------------------------------
1753 class S5BConnector::Item
: public QObject
1757 SocksClient
*client
;
1758 SocksUDP
*client_udp
;
1766 Item(const Jid
&self
, const StreamHost
&_host
, const QString
&_key
, bool _udp
) : QObject(0)
1772 client
= new SocksClient
;
1774 connect(client
, SIGNAL(connected()), SLOT(sc_connected()));
1775 connect(client
, SIGNAL(error(int)), SLOT(sc_error(int)));
1776 connect(&t
, SIGNAL(timeout()), SLOT(trySendUDP()));
1786 client
->connectToHost(host
.host(), host
.port(), key
, 0, udp
);
1792 client_udp
->change(key
, 0); // flip over to the data port
1802 // if udp, need to send init packet before we are good
1805 client_udp
= client
->createUDP(key
, 1, client
->peerAddress(), client
->peerPort());
1818 qDebug("S5BConnector[%s]: error\n", qPrintable(host
.host()));
1826 if(udp_tries
== 5) {
1833 // send initialization with our JID
1834 QByteArray
a(jid
.full().toUtf8());
1835 client_udp
->write(a
);
1851 qDebug("S5BConnector[%s]: success\n", qPrintable(host
.host()));
1853 client
->disconnect(this);
1858 class S5BConnector::Private
1861 SocksClient
*active
;
1862 SocksUDP
*active_udp
;
1863 QList
<Item
*> itemList
;
1865 StreamHost activeHost
;
1869 S5BConnector::S5BConnector(QObject
*parent
)
1875 connect(&d
->t
, SIGNAL(timeout()), SLOT(t_timeout()));
1878 S5BConnector::~S5BConnector()
1884 void S5BConnector::reset()
1887 delete d
->active_udp
;
1891 while (!d
->itemList
.empty()) {
1892 delete d
->itemList
.takeFirst();
1896 void S5BConnector::start(const Jid
&self
, const StreamHostList
&hosts
, const QString
&key
, bool udp
, int timeout
)
1901 qDebug("S5BConnector: starting [%p]!\n", this);
1903 for(StreamHostList::ConstIterator it
= hosts
.begin(); it
!= hosts
.end(); ++it
) {
1904 Item
*i
= new Item(self
, *it
, key
, udp
);
1905 connect(i
, SIGNAL(result(bool)), SLOT(item_result(bool)));
1906 d
->itemList
.append(i
);
1909 d
->t
.start(timeout
* 1000);
1912 SocksClient
*S5BConnector::takeClient()
1914 SocksClient
*c
= d
->active
;
1919 SocksUDP
*S5BConnector::takeUDP()
1921 SocksUDP
*c
= d
->active_udp
;
1926 StreamHost
S5BConnector::streamHostUsed() const
1928 return d
->activeHost
;
1931 void S5BConnector::item_result(bool b
)
1933 Item
*i
= (Item
*)sender();
1935 d
->active
= i
->client
;
1937 d
->active_udp
= i
->client_udp
;
1939 d
->activeHost
= i
->host
;
1940 while (!d
->itemList
.isEmpty()) {
1941 delete d
->itemList
.takeFirst();
1945 qDebug("S5BConnector: complete! [%p]\n", this);
1950 d
->itemList
.removeAll(i
);
1952 if(d
->itemList
.isEmpty()) {
1955 qDebug("S5BConnector: failed! [%p]\n", this);
1962 void S5BConnector::t_timeout()
1966 qDebug("S5BConnector: failed! (timeout)\n");
1971 void S5BConnector::man_udpSuccess(const Jid
&streamHost
)
1973 // was anyone sending to this streamhost?
1974 foreach(Item
*i
, d
->itemList
) {
1975 if(i
->host
.jid().compare(streamHost
) && i
->client_udp
) {
1982 //----------------------------------------------------------------------------
1984 //----------------------------------------------------------------------------
1985 class S5BServer::Item
: public QObject
1989 SocksClient
*client
;
1993 Item(SocksClient
*c
) : QObject(0)
1996 connect(client
, SIGNAL(incomingMethods(int)), SLOT(sc_incomingMethods(int)));
1997 connect(client
, SIGNAL(incomingConnectRequest(const QString
&, int)), SLOT(sc_incomingConnectRequest(const QString
&, int)));
1998 connect(client
, SIGNAL(error(int)), SLOT(sc_error(int)));
2000 connect(&expire
, SIGNAL(timeout()), SLOT(doError()));
2009 void resetExpiration()
2011 expire
.start(30000);
2026 void sc_incomingMethods(int m
)
2028 if(m
& SocksClient::AuthNone
)
2029 client
->chooseMethod(SocksClient::AuthNone
);
2034 void sc_incomingConnectRequest(const QString
&_host
, int port
)
2038 client
->disconnect(this);
2051 class S5BServer::Private
2055 QStringList hostList
;
2056 QList
<S5BManager
*> manList
;
2057 QList
<Item
*> itemList
;
2060 S5BServer::S5BServer(QObject
*parent
)
2064 connect(&d
->serv
, SIGNAL(incomingReady()), SLOT(ss_incomingReady()));
2065 connect(&d
->serv
, SIGNAL(incomingUDP(const QString
&, int, const QHostAddress
&, int, const QByteArray
&)), SLOT(ss_incomingUDP(const QString
&, int, const QHostAddress
&, int, const QByteArray
&)));
2068 S5BServer::~S5BServer()
2074 bool S5BServer::isActive() const
2076 return d
->serv
.isActive();
2079 bool S5BServer::start(int port
)
2082 //return d->serv.listen(port, true);
2083 return d
->serv
.listen(port
);
2086 void S5BServer::stop()
2091 void S5BServer::setHostList(const QStringList
&list
)
2096 QStringList
S5BServer::hostList() const
2101 int S5BServer::port() const
2103 return d
->serv
.port();
2106 void S5BServer::ss_incomingReady()
2108 Item
*i
= new Item(d
->serv
.takeIncoming());
2110 qDebug("S5BServer: incoming connection from %s:%d\n", qPrintable(i
->client
->peerAddress().toString()), i
->client
->peerPort());
2112 connect(i
, SIGNAL(result(bool)), SLOT(item_result(bool)));
2113 d
->itemList
.append(i
);
2116 void S5BServer::ss_incomingUDP(const QString
&host
, int port
, const QHostAddress
&addr
, int sourcePort
, const QByteArray
&data
)
2118 if(port
!= 0 || port
!= 1)
2121 foreach(S5BManager
* m
, d
->manList
) {
2122 if(m
->srv_ownsHash(host
)) {
2123 m
->srv_incomingUDP(port
== 1 ? true : false, addr
, sourcePort
, host
, data
);
2129 void S5BServer::item_result(bool b
)
2131 Item
*i
= (Item
*)sender();
2133 qDebug("S5BServer item result: %d\n", b
);
2136 d
->itemList
.removeAll(i
);
2141 SocksClient
*c
= i
->client
;
2143 QString key
= i
->host
;
2144 d
->itemList
.removeAll(i
);
2147 // find the appropriate manager for this incoming connection
2148 foreach(S5BManager
*m
, d
->manList
) {
2149 if(m
->srv_ownsHash(key
)) {
2150 m
->srv_incomingReady(c
, key
);
2156 qDebug("S5BServer item result: unknown hash [%s]\n", qPrintable(key
));
2163 void S5BServer::link(S5BManager
*m
)
2165 d
->manList
.append(m
);
2168 void S5BServer::unlink(S5BManager
*m
)
2170 d
->manList
.removeAll(m
);
2173 void S5BServer::unlinkAll()
2175 foreach(S5BManager
*m
, d
->manList
) {
2181 const QList
<S5BManager
*> & S5BServer::managerList() const
2186 void S5BServer::writeUDP(const QHostAddress
&addr
, int port
, const QByteArray
&data
)
2188 d
->serv
.writeUDP(addr
, port
, data
);
2191 //----------------------------------------------------------------------------
2193 //----------------------------------------------------------------------------
2194 class JT_S5B::Private
2200 StreamHost proxyInfo
;
2205 JT_S5B::JT_S5B(Task
*parent
)
2210 connect(&d
->t
, SIGNAL(timeout()), SLOT(t_timeout()));
2218 void JT_S5B::request(const Jid
&to
, const QString
&sid
, const StreamHostList
&hosts
, bool fast
, bool udp
)
2224 iq
= createIQ(doc(), "set", to
.full(), id());
2225 QDomElement query
= doc()->createElement("query");
2226 query
.setAttribute("xmlns", S5B_NS
);
2227 query
.setAttribute("sid", sid
);
2228 query
.setAttribute("mode", udp
? "udp" : "tcp" );
2229 iq
.appendChild(query
);
2230 for(StreamHostList::ConstIterator it
= hosts
.begin(); it
!= hosts
.end(); ++it
) {
2231 QDomElement shost
= doc()->createElement("streamhost");
2232 shost
.setAttribute("jid", (*it
).jid().full());
2233 shost
.setAttribute("host", (*it
).host());
2234 shost
.setAttribute("port", QString::number((*it
).port()));
2235 if((*it
).isProxy()) {
2236 QDomElement p
= doc()->createElement("proxy");
2237 p
.setAttribute("xmlns", "http://affinix.com/jabber/stream");
2238 shost
.appendChild(p
);
2240 query
.appendChild(shost
);
2243 QDomElement e
= doc()->createElement("fast");
2244 e
.setAttribute("xmlns", "http://affinix.com/jabber/stream");
2245 query
.appendChild(e
);
2250 void JT_S5B::requestProxyInfo(const Jid
&to
)
2256 iq
= createIQ(doc(), "get", to
.full(), id());
2257 QDomElement query
= doc()->createElement("query");
2258 query
.setAttribute("xmlns", S5B_NS
);
2259 iq
.appendChild(query
);
2263 void JT_S5B::requestActivation(const Jid
&to
, const QString
&sid
, const Jid
&target
)
2269 iq
= createIQ(doc(), "set", to
.full(), id());
2270 QDomElement query
= doc()->createElement("query");
2271 query
.setAttribute("xmlns", S5B_NS
);
2272 query
.setAttribute("sid", sid
);
2273 iq
.appendChild(query
);
2274 QDomElement act
= doc()->createElement("activate");
2275 act
.appendChild(doc()->createTextNode(target
.full()));
2276 query
.appendChild(act
);
2283 d
->t
.setSingleShot(true);
2289 void JT_S5B::onDisconnect()
2294 bool JT_S5B::take(const QDomElement
&x
)
2299 if(!iqVerify(x
, d
->to
, id()))
2304 if(x
.attribute("type") == "result") {
2305 QDomElement q
= queryTag(x
);
2309 QDomElement shost
= q
.elementsByTagName("streamhost-used").item(0).toElement();
2311 d
->streamHost
= shost
.attribute("jid");
2316 else if(d
->mode
== 1) {
2318 QDomElement shost
= q
.elementsByTagName("streamhost").item(0).toElement();
2319 if(!shost
.isNull()) {
2320 Jid j
= shost
.attribute("jid");
2322 QString host
= shost
.attribute("host");
2323 if(!host
.isEmpty()) {
2324 int port
= shost
.attribute("port").toInt();
2349 void JT_S5B::t_timeout()
2352 setError(500, "Timed out");
2355 Jid
JT_S5B::streamHostUsed() const
2357 return d
->streamHost
;
2360 StreamHost
JT_S5B::proxyInfo() const
2362 return d
->proxyInfo
;
2365 //----------------------------------------------------------------------------
2367 //----------------------------------------------------------------------------
2368 JT_PushS5B::JT_PushS5B(Task
*parent
)
2373 JT_PushS5B::~JT_PushS5B()
2377 int JT_PushS5B::priority() const
2382 bool JT_PushS5B::take(const QDomElement
&e
)
2384 // look for udpsuccess
2385 if(e
.tagName() == "message") {
2386 QDomElement x
= e
.elementsByTagName("udpsuccess").item(0).toElement();
2387 if(!x
.isNull() && x
.attribute("xmlns") == S5B_NS
) {
2388 incomingUDPSuccess(Jid(x
.attribute("from")), x
.attribute("dstaddr"));
2391 x
= e
.elementsByTagName("activate").item(0).toElement();
2392 if(!x
.isNull() && x
.attribute("xmlns") == "http://affinix.com/jabber/stream") {
2393 incomingActivate(Jid(x
.attribute("from")), x
.attribute("sid"), Jid(x
.attribute("jid")));
2399 // must be an iq-set tag
2400 if(e
.tagName() != "iq")
2402 if(e
.attribute("type") != "set")
2404 if(queryNS(e
) != S5B_NS
)
2407 Jid
from(e
.attribute("from"));
2408 QDomElement q
= queryTag(e
);
2409 QString sid
= q
.attribute("sid");
2411 StreamHostList hosts
;
2412 QDomNodeList nl
= q
.elementsByTagName("streamhost");
2413 for(int n
= 0; n
< nl
.count(); ++n
) {
2414 QDomElement shost
= nl
.item(n
).toElement();
2415 if(hosts
.count() < MAXSTREAMHOSTS
) {
2416 Jid j
= shost
.attribute("jid");
2419 QString host
= shost
.attribute("host");
2422 int port
= shost
.attribute("port").toInt();
2423 QDomElement p
= shost
.elementsByTagName("proxy").item(0).toElement();
2424 bool isProxy
= false;
2425 if(!p
.isNull() && p
.attribute("xmlns") == "http://affinix.com/jabber/stream")
2432 h
.setIsProxy(isProxy
);
2439 t
= q
.elementsByTagName("fast").item(0).toElement();
2440 if(!t
.isNull() && t
.attribute("xmlns") == "http://affinix.com/jabber/stream")
2445 r
.id
= e
.attribute("id");
2449 r
.udp
= q
.attribute("mode") == "udp" ? true: false;
2455 void JT_PushS5B::respondSuccess(const Jid
&to
, const QString
&id
, const Jid
&streamHost
)
2457 QDomElement iq
= createIQ(doc(), "result", to
.full(), id
);
2458 QDomElement query
= doc()->createElement("query");
2459 query
.setAttribute("xmlns", S5B_NS
);
2460 iq
.appendChild(query
);
2461 QDomElement shost
= doc()->createElement("streamhost-used");
2462 shost
.setAttribute("jid", streamHost
.full());
2463 query
.appendChild(shost
);
2467 void JT_PushS5B::respondError(const Jid
&to
, const QString
&id
,
2468 Stanza::Error::ErrorCond cond
, const QString
&str
)
2470 QDomElement iq
= createIQ(doc(), "error", to
.full(), id
);
2471 Stanza::Error
error(Stanza::Error::Cancel
, cond
, str
);
2472 iq
.appendChild(error
.toXml(*client()->doc(), client()->stream().baseNS()));
2476 void JT_PushS5B::sendUDPSuccess(const Jid
&to
, const QString
&dstaddr
)
2478 QDomElement m
= doc()->createElement("message");
2479 m
.setAttribute("to", to
.full());
2480 QDomElement u
= doc()->createElement("udpsuccess");
2481 u
.setAttribute("xmlns", S5B_NS
);
2482 u
.setAttribute("dstaddr", dstaddr
);
2487 void JT_PushS5B::sendActivate(const Jid
&to
, const QString
&sid
, const Jid
&streamHost
)
2489 QDomElement m
= doc()->createElement("message");
2490 m
.setAttribute("to", to
.full());
2491 QDomElement act
= doc()->createElement("activate");
2492 act
.setAttribute("xmlns", "http://affinix.com/jabber/stream");
2493 act
.setAttribute("sid", sid
);
2494 act
.setAttribute("jid", streamHost
.full());
2499 //----------------------------------------------------------------------------
2501 //----------------------------------------------------------------------------
2502 StreamHost::StreamHost()
2508 const Jid
& StreamHost::jid() const
2513 const QString
& StreamHost::host() const
2518 int StreamHost::port() const
2523 bool StreamHost::isProxy() const
2528 void StreamHost::setJid(const Jid
&_j
)
2533 void StreamHost::setHost(const QString
&host
)
2538 void StreamHost::setPort(int port
)
2543 void StreamHost::setIsProxy(bool b
)