~ubuntu-branches/ubuntu/wily/psi/wily-proposed

« back to all changes in this revision

Viewing changes to iris/src/irisnet/noncore/stuntransaction.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2009  Barracuda Networks, Inc.
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2.1 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
17
 * 02110-1301  USA
 
18
 *
 
19
 */
 
20
 
 
21
#include "stuntransaction.h"
 
22
 
 
23
#include <QHash>
 
24
#include <QMetaType>
 
25
#include <QTime>
 
26
#include <QTimer>
 
27
#include <QtCrypto>
 
28
#include "stunmessage.h"
 
29
 
 
30
Q_DECLARE_METATYPE(XMPP::StunTransaction::Error)
 
31
 
 
32
namespace XMPP {
 
33
 
 
34
//----------------------------------------------------------------------------
 
35
// StunTransaction
 
36
//----------------------------------------------------------------------------
 
37
class StunTransaction::Private : public QObject
 
38
{
 
39
        Q_OBJECT
 
40
 
 
41
public:
 
42
        StunTransaction *q;
 
43
        bool active;
 
44
        StunTransaction::Mode mode;
 
45
        QByteArray id;
 
46
        QByteArray packet;
 
47
        int rto, rc, rm, ti;
 
48
        int tries;
 
49
        int last_interval;
 
50
        QTimer *t;
 
51
        //QTime time;
 
52
        QString stuser;
 
53
        QByteArray key;
 
54
 
 
55
        Private(StunTransaction *_q) :
 
56
                QObject(_q),
 
57
                q(_q)
 
58
        {
 
59
                qRegisterMetaType<StunTransaction::Error>();
 
60
 
 
61
                active = false;
 
62
 
 
63
                t = new QTimer(this);
 
64
                connect(t, SIGNAL(timeout()), SLOT(t_timeout()));
 
65
                t->setSingleShot(true);
 
66
 
 
67
                // defaults from RFC 5389
 
68
                rto = 500;
 
69
                rc = 7;
 
70
                rm = 16;
 
71
                ti = 39500;
 
72
        }
 
73
 
 
74
        ~Private()
 
75
        {
 
76
                t->disconnect(this);
 
77
                t->setParent(0);
 
78
                t->deleteLater();
 
79
        }
 
80
 
 
81
        void start(StunTransaction::Mode _mode, const StunMessage &msg, const QString &_stuser, const QString &stpass)
 
82
        {
 
83
                mode = _mode;
 
84
                stuser = _stuser;
 
85
                StunMessage out = msg;
 
86
 
 
87
                id = QByteArray((const char *)msg.id(), 12);
 
88
 
 
89
                // HACK HACK HACK
 
90
                if(!stuser.isEmpty())
 
91
                {
 
92
                        QList<StunMessage::Attribute> list = out.attributes();
 
93
                        StunMessage::Attribute attr;
 
94
                        attr.type = 0x0006; // USERNAME
 
95
                        attr.value = stuser.toUtf8();
 
96
                        list += attr;
 
97
                        out.setAttributes(list);
 
98
 
 
99
                        key = stpass.toUtf8();
 
100
                        // FIXME: why also fingerprint?  this is such a mess
 
101
                        packet = out.toBinary(StunMessage::MessageIntegrity | StunMessage::Fingerprint, key);
 
102
                }
 
103
                else
 
104
                        packet = out.toBinary();
 
105
                if(packet.isEmpty())
 
106
                {
 
107
                        // since a transaction is not cancelable nor reusable,
 
108
                        //   there's no DOR-SR issue here
 
109
                        QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection,
 
110
                                Q_ARG(XMPP::StunTransaction::Error, ErrorGeneric));
 
111
                        return;
 
112
                }
 
113
 
 
114
                active = true;
 
115
                tries = 1; // assume the user does its job
 
116
 
 
117
                if(mode == StunTransaction::Udp)
 
118
                {
 
119
                        last_interval = rm * rto;
 
120
                        t->start(rto);
 
121
                        rto *= 2;
 
122
                }
 
123
                else if(mode == StunTransaction::Tcp)
 
124
                {
 
125
                        t->start(ti);
 
126
                }
 
127
                else
 
128
                        Q_ASSERT(0);
 
129
 
 
130
                //time.start();
 
131
                //printf("send: %d\n", time.elapsed());
 
132
        }
 
133
 
 
134
private slots:
 
135
        void t_timeout()
 
136
        {
 
137
                if(mode == StunTransaction::Tcp || tries == rc)
 
138
                {
 
139
                        emit q->error(StunTransaction::ErrorTimeout);
 
140
                        return;
 
141
                }
 
142
 
 
143
                ++tries;
 
144
                if(tries == rc)
 
145
                {
 
146
                        t->start(last_interval);
 
147
                }
 
148
                else
 
149
                {
 
150
                        t->start(rto);
 
151
                        rto *= 2;
 
152
                }
 
153
 
 
154
                //printf("send: %d\n", time.elapsed());
 
155
                emit q->retransmit();
 
156
        }
 
157
 
 
158
public:
 
159
        bool processIncoming(const StunMessage &msg)
 
160
        {
 
161
                if(!active)
 
162
                        return false;
 
163
 
 
164
                if(msg.mclass() != StunMessage::SuccessResponse && msg.mclass() != StunMessage::ErrorResponse)
 
165
                        return false;
 
166
 
 
167
                if(memcmp(msg.id(), id.data(), 12) != 0)
 
168
                        return false;
 
169
 
 
170
                active = false;
 
171
                t->stop();
 
172
                emit q->finished(msg);
 
173
                return true;
 
174
        }
 
175
};
 
176
 
 
177
StunTransaction::StunTransaction(QObject *parent) :
 
178
        QObject(parent)
 
179
{
 
180
        d = new Private(this);
 
181
}
 
182
 
 
183
StunTransaction::~StunTransaction()
 
184
{
 
185
        delete d;
 
186
}
 
187
 
 
188
void StunTransaction::start(Mode mode, const StunMessage &msg, const QString &stuser, const QString &stpass)
 
189
{
 
190
        Q_ASSERT(!d->active);
 
191
        d->start(mode, msg, stuser, stpass);
 
192
}
 
193
 
 
194
QByteArray StunTransaction::transactionId() const
 
195
{
 
196
        return d->id;
 
197
}
 
198
 
 
199
QByteArray StunTransaction::packet() const
 
200
{
 
201
        return d->packet;
 
202
}
 
203
 
 
204
void StunTransaction::setRTO(int i)
 
205
{
 
206
        Q_ASSERT(!d->active);
 
207
        d->rto = i;
 
208
}
 
209
 
 
210
void StunTransaction::setRc(int i)
 
211
{
 
212
        Q_ASSERT(!d->active);
 
213
        d->rc = i;
 
214
}
 
215
 
 
216
void StunTransaction::setRm(int i)
 
217
{
 
218
        Q_ASSERT(!d->active);
 
219
        d->rm = i;
 
220
}
 
221
 
 
222
void StunTransaction::setTi(int i)
 
223
{
 
224
        Q_ASSERT(!d->active);
 
225
        d->ti = i;
 
226
}
 
227
 
 
228
bool StunTransaction::writeIncomingMessage(const StunMessage &msg)
 
229
{
 
230
        return d->processIncoming(msg);
 
231
}
 
232
 
 
233
//----------------------------------------------------------------------------
 
234
// StunTransactionPool
 
235
//----------------------------------------------------------------------------
 
236
class StunTransactionPool::Private : public QObject
 
237
{
 
238
        Q_OBJECT
 
239
 
 
240
public:
 
241
        StunTransactionPool *q;
 
242
        StunTransaction::Mode mode;
 
243
        QHash<StunTransaction*,QByteArray> transToId;
 
244
        QHash<QByteArray,StunTransaction*> idToTrans;
 
245
        bool shortTermCredentials;
 
246
        QString username, password;
 
247
 
 
248
        Private(StunTransactionPool *_q) :
 
249
                QObject(_q),
 
250
                q(_q),
 
251
                shortTermCredentials(false)
 
252
        {
 
253
        }
 
254
 
 
255
        void insert(StunTransaction *trans)
 
256
        {
 
257
                connect(trans, SIGNAL(retransmit()), this, SLOT(trans_retransmit()));
 
258
 
 
259
                QByteArray id = trans->transactionId();
 
260
                transToId.insert(trans, id);
 
261
                idToTrans.insert(id, trans);
 
262
 
 
263
                // send the first transmit attempt
 
264
                emit q->retransmit(trans);
 
265
        }
 
266
 
 
267
        void remove(StunTransaction *trans)
 
268
        {
 
269
                disconnect(trans, SIGNAL(retransmit()), this, SLOT(trans_retransmit()));
 
270
 
 
271
                QByteArray id = transToId.value(trans);
 
272
                transToId.remove(trans);
 
273
                idToTrans.remove(id);
 
274
        }
 
275
 
 
276
private slots:
 
277
        void trans_retransmit()
 
278
        {
 
279
                StunTransaction *trans = (StunTransaction *)sender();
 
280
                emit q->retransmit(trans);
 
281
        }
 
282
};
 
283
 
 
284
StunTransactionPool::StunTransactionPool(StunTransaction::Mode mode, QObject *parent) :
 
285
        QObject(parent)
 
286
{
 
287
        d = new Private(this);
 
288
        d->mode = mode;
 
289
}
 
290
 
 
291
StunTransactionPool::~StunTransactionPool()
 
292
{
 
293
        delete d;
 
294
}
 
295
 
 
296
StunTransaction::Mode StunTransactionPool::mode() const
 
297
{
 
298
        return d->mode;
 
299
}
 
300
 
 
301
QByteArray StunTransactionPool::generateId() const
 
302
{
 
303
        QByteArray id;
 
304
 
 
305
        do
 
306
        {
 
307
                id = QCA::Random::randomArray(12).toByteArray();
 
308
        } while(d->idToTrans.contains(id));
 
309
 
 
310
        return id;
 
311
}
 
312
 
 
313
void StunTransactionPool::insert(StunTransaction *trans)
 
314
{
 
315
        Q_ASSERT(!trans->transactionId().isEmpty());
 
316
        d->insert(trans);
 
317
}
 
318
 
 
319
void StunTransactionPool::remove(StunTransaction *trans)
 
320
{
 
321
        d->remove(trans);
 
322
}
 
323
 
 
324
bool StunTransactionPool::writeIncomingMessage(const StunMessage &msg)
 
325
{
 
326
        if(msg.mclass() != StunMessage::SuccessResponse && msg.mclass() != StunMessage::ErrorResponse)
 
327
                return false;
 
328
 
 
329
        StunTransaction *trans = d->idToTrans.value(QByteArray::fromRawData((const char *)msg.id(), 12));
 
330
        if(!trans)
 
331
                return false;
 
332
 
 
333
        return trans->writeIncomingMessage(msg);
 
334
}
 
335
 
 
336
QString StunTransactionPool::realm() const
 
337
{
 
338
        // TODO
 
339
        return QString();
 
340
}
 
341
 
 
342
void StunTransactionPool::setUsername(const QString &username)
 
343
{
 
344
        d->username = username;
 
345
}
 
346
 
 
347
void StunTransactionPool::setPassword(const QCA::SecureArray &password)
 
348
{
 
349
        // HACK HACK HACK
 
350
        d->password = QString::fromUtf8(password.toByteArray());
 
351
}
 
352
 
 
353
void StunTransactionPool::setRealm(const QString &realm)
 
354
{
 
355
        // TODO
 
356
        Q_UNUSED(realm);
 
357
}
 
358
 
 
359
void StunTransactionPool::setShortTermCredentialsEnabled(bool enabled)
 
360
{
 
361
        d->shortTermCredentials = enabled;
 
362
}
 
363
 
 
364
void StunTransactionPool::continueAfterParams()
 
365
{
 
366
        // TODO
 
367
}
 
368
 
 
369
QString StunTransactionPool::username() const
 
370
{
 
371
        return d->username;
 
372
}
 
373
 
 
374
QString StunTransactionPool::password() const
 
375
{
 
376
        return d->password;
 
377
}
 
378
 
 
379
}
 
380
 
 
381
#include "stuntransaction.moc"