2
* altports.cpp - manage alternative UDP port ranges
3
* Copyright (C) 2004 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
23
#include <qsocketdevice.h>
24
#include <qsocketnotifier.h>
27
//----------------------------------------------------------------------------
29
//----------------------------------------------------------------------------
30
PortRange::PortRange()
36
QString PortRange::toString() const
41
s += QString::number(base);
45
s += QString::number(base + count - 1);
51
bool PortRange::fromString(const QString &s)
66
int first = s.mid(0, n).toInt();
67
int last = s.mid(n + 1).toInt();
68
if(first < 1 || first > 65535 || last < first || last > 65535)
72
count = last - first + 1;
77
//----------------------------------------------------------------------------
79
//----------------------------------------------------------------------------
80
void PortRangeList::merge(const PortRange &r)
82
// see if we have this base already
83
for(Iterator it = begin(); it != end(); ++it)
88
pr.count = QMAX(pr.count, r.count);
93
// else, just append it
97
int PortRangeList::findByBase(int base) const
100
for(ConstIterator it = begin(); it != end(); ++it)
102
if((*it).base == base)
109
//----------------------------------------------------------------------------
111
//----------------------------------------------------------------------------
112
class UDPItem : public QObject
116
static UDPItem *create(const QHostAddress &addr, int port)
118
QSocketDevice *sd = new QSocketDevice(QSocketDevice::Datagram);
119
sd->setBlocking(false);
120
if(!sd->bind(addr, port))
122
UDPItem *i = new UDPItem;
124
i->sn = new QSocketNotifier(i->sd->socket(), QSocketNotifier::Read);
125
i->connect(i->sn, SIGNAL(activated(int)), SLOT(sn_activated(int)));
127
//printf("UDP BIND: [%d]\n", port);
135
//printf("UDP UNBIND: [%d]\n", _port);
143
void write(const QByteArray &buf, const QHostAddress &addr, int port)
145
sd->setBlocking(true);
146
sd->writeBlock(buf.data(), buf.size(), addr, port);
147
sd->setBlocking(false);
151
void packetReady(const QByteArray &buf, const QHostAddress &addr, int port);
154
void sn_activated(int)
156
QByteArray buf(8192);
157
int actual = sd->readBlock(buf.data(), buf.size());
159
QHostAddress pa = sd->peerAddress();
160
int pp = sd->peerPort();
161
packetReady(buf, pa, pp);
174
//----------------------------------------------------------------------------
176
//----------------------------------------------------------------------------
177
#define PORT_ALLOC_BASE 16000
178
#define PORT_ALLOC_MAX 65535
180
class PortSequence : public QObject
186
list.setAutoDelete(true);
194
bool allocate(const QHostAddress &address, int count, int base=-1)
196
return try_allocate(address, count, base);
199
bool resize(int count)
201
// don't allow growing
202
if(count > (int)list.count())
205
QPtrListIterator<UDPItem> it(list);
207
int del = list.count() - count;
208
for(int n = 0; n < del; ++n)
209
list.removeRef(it.current());
213
void send(int index, const QHostAddress &addr, int destPort, const QByteArray &buf)
215
if(index >= 0 && index < (int)list.count())
216
list.at(index)->write(buf, addr, destPort);
219
QHostAddress address() const
227
return list.getFirst()->port();
238
void packetReady(int index, const QHostAddress &addr, int port, const QByteArray &buf);
241
void udp_packetReady(const QByteArray &buf, const QHostAddress &addr, int port)
243
UDPItem *su = (UDPItem *)sender();
246
QPtrListIterator<UDPItem> it(list);
247
for(UDPItem *u; (u = it.current()); ++it)
259
packetReady(index, addr, port, buf);
264
QPtrList<UDPItem> list;
266
bool try_allocate(const QHostAddress &address, int count, int base)
272
int start = base != -1 ? base : PORT_ALLOC_BASE;
273
while(start + (count - 1) <= PORT_ALLOC_MAX)
275
QPtrList<UDPItem> udplist;
277
for(int n = 0; n < count; ++n)
279
UDPItem *i = UDPItem::create(address, start + n);
292
udplist.setAutoDelete(true);
294
// if using 'start', we only get one chance
298
start += udplist.count() + 1;
306
QPtrListIterator<UDPItem> it(list);
307
for(UDPItem *u; (u = it.current()); ++it)
308
connect(u, SIGNAL(packetReady(const QByteArray &, const QHostAddress &, int)), SLOT(udp_packetReady(const QByteArray &, const QHostAddress &, int)));
314
//----------------------------------------------------------------------------
316
//----------------------------------------------------------------------------
317
class AltPorts::Private : public QObject
322
QPtrList<PortSequence> list;
326
Private(AltPorts *_par)
333
void range_packetReady(int index, const QHostAddress &addr, int port, const QByteArray &buf)
335
par->packetReady(index, addr, port, buf);
341
d = new Private(this);
344
AltPorts::~AltPorts()
349
void AltPorts::reset()
357
bool AltPorts::isEmpty() const
359
if(!d->ports && d->list.isEmpty())
364
bool AltPorts::allocate(const PortRange &real, PortRange *alt)
369
PortRangeList in, out;
371
if(!reserve(in, &out))
378
bool AltPorts::reserve(const PortRangeList &real, PortRangeList *alt)
384
QPtrList<PortSequence> list;
385
for(PortRangeList::ConstIterator it = real.begin(); it != real.end(); ++it)
387
PortSequence *s = new PortSequence;
388
if(!s->allocate(QHostAddress(), (*it).count))
391
list.setAutoDelete(true);
396
r.count = s->count();
407
void AltPorts::keep(const PortRange &r)
412
int n = d->orig.findByBase(r.base);
416
PortSequence *s = d->list.at(n);
419
d->list.removeRef(s);
420
d->list.setAutoDelete(true);
422
d->list.setAutoDelete(false);
423
connect(d->ports, SIGNAL(packetReady(int, const QHostAddress &, int, const QByteArray &)), d, SLOT(range_packetReady(int, const QHostAddress &, int, const QByteArray &)));
426
PortRange AltPorts::range() const
431
r.base = d->ports->base();
432
r.count = d->ports->count();
437
void AltPorts::send(int index, const QHostAddress &addr, int destPort, const QByteArray &buf)
440
d->ports->send(index, addr, destPort, buf);
443
#include "altports.moc"