2
* rtspproxy.cpp - proxy for RTSP allowing direct and/or virtual endpoints
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
21
#include "rtspproxy.h"
29
#define SERVER_ALLOC_BASE 16000
30
#define SERVER_ALLOC_MAX 65535
32
static bool try_serve(RTSP::Server *s)
34
for(int n = SERVER_ALLOC_BASE; n <= SERVER_ALLOC_MAX; ++n)
42
//----------------------------------------------------------------------------
44
//----------------------------------------------------------------------------
45
static PortRangeList create_virtual_ranges(const PortRangeList &in)
49
for(PortRangeList::ConstIterator it = in.begin(); it != in.end(); ++it)
53
r.count = (*it).count;
68
PortRangeList realPortRanges, altPortRanges;
80
host = QHostAddress();
85
class PortMapper : public QObject
95
bool reserveDirectClient(const PortRangeList &clientRanges, bool virtServer=false);
96
bool reserveVirtualClient(const PortRangeList &clientRanges);
97
bool finalize(const QHostAddress &clientHost, const PortRange &clientPorts, const QHostAddress &serverHost, const PortRange &serverPorts);
99
PortRangeList clientAlternatePorts() const;
100
PortRangeList serverAlternatePorts() const;
102
void writeAsClient(int source, int dest, const QByteArray &buf);
103
void writeAsServer(int source, int dest, const QByteArray &buf);
106
void packetFromClient(int source, int dest, const QByteArray &buf);
107
void packetFromServer(int source, int dest, const QByteArray &buf);
110
void client_packetReady(int index, const QHostAddress &addr, int sourcePort, const QByteArray &buf);
111
void server_packetReady(int index, const QHostAddress &addr, int sourcePort, const QByteArray &buf);
114
MapItem client, server;
118
PortMapper::PortMapper()
120
connect(&client.altPorts, SIGNAL(packetReady(int, const QHostAddress &, int, const QByteArray &)), SLOT(client_packetReady(int, const QHostAddress &, int, const QByteArray &)));
121
connect(&server.altPorts, SIGNAL(packetReady(int, const QHostAddress &, int, const QByteArray &)), SLOT(server_packetReady(int, const QHostAddress &, int, const QByteArray &)));
125
PortMapper::~PortMapper()
129
void PortMapper::reset()
136
bool PortMapper::reserveDirectClient(const PortRangeList &clientRanges, bool virtServer)
141
client.realPortRanges = clientRanges;
144
client.virt = true; // virtual server means virtual client ports
145
client.altPortRanges = create_virtual_ranges(clientRanges);
149
if(!client.altPorts.reserve(clientRanges, &client.altPortRanges))
152
client.active = true;
157
bool PortMapper::reserveVirtualClient(const PortRangeList &clientRanges)
162
server.virt = true; // virtual client means virtual server ports
163
client.realPortRanges = clientRanges;
164
client.altPorts.reserve(clientRanges, &client.altPortRanges);
165
client.active = true;
170
bool PortMapper::finalize(const QHostAddress &clientHost, const PortRange &clientPorts, const QHostAddress &serverHost, const PortRange &serverPorts)
175
int n = client.altPortRanges.findByBase(clientPorts.base);
179
client.host = clientHost;
180
client.realPorts = client.realPortRanges[n];
181
client.realPorts.count = clientPorts.count;
185
PortRange virtPorts = client.altPortRanges[n];
186
virtPorts.count = clientPorts.count;
187
client.altPortRanges.clear();
188
client.altPortRanges.append(virtPorts);
192
client.altPorts.keep(client.realPorts);
193
client.altPortRanges.clear();
194
client.altPortRanges.append(client.altPorts.range());
197
server.host = serverHost;
198
server.realPorts = serverPorts;
203
in.append(server.realPorts);
204
server.altPortRanges = create_virtual_ranges(in);
209
if(!server.altPorts.allocate(server.realPorts, &r))
211
server.altPortRanges.clear();
212
server.altPortRanges.append(r);
214
server.active = true;
220
PortRangeList PortMapper::clientAlternatePorts() const
222
return client.altPortRanges;
225
PortRangeList PortMapper::serverAlternatePorts() const
227
return server.altPortRanges;
230
void PortMapper::writeAsClient(int source, int, const QByteArray &buf)
232
if(source < client.realPorts.base || source >= client.realPorts.base + client.realPorts.count)
234
int index = source - client.realPorts.base;
235
client.altPorts.send(index, server.host, server.realPorts.base + index, buf);
238
void PortMapper::writeAsServer(int source, int, const QByteArray &buf)
240
if(source < server.realPorts.base || source >= server.realPorts.base + server.realPorts.count)
242
int index = source - server.realPorts.base;
243
server.altPorts.send(index, client.host, client.realPorts.base + index, buf);
246
void PortMapper::client_packetReady(int index, const QHostAddress &, int, const QByteArray &buf)
249
emit packetFromServer(server.altPortRanges.first().base + index, client.realPorts.base + index, buf);
251
server.altPorts.send(index, client.host, client.realPorts.base + index, buf);
254
void PortMapper::server_packetReady(int index, const QHostAddress &, int, const QByteArray &buf)
257
emit packetFromClient(client.altPortRanges.first().base + index, server.realPorts.base + index, buf);
259
client.altPorts.send(index, server.host, server.realPorts.base + index, buf);
262
//----------------------------------------------------------------------------
264
//----------------------------------------------------------------------------
265
using namespace RTSP;
267
static PortRangeList transport_get_ports(const TransportList &list, const QString &type)
270
for(TransportList::ConstIterator it = list.begin(); it != list.end(); ++it)
273
if(!r.fromString((*it).argument(type)))
280
static TransportList transport_set_ports(const TransportList &_list, const QString &type, const PortRangeList &newpl)
282
TransportList list = _list;
283
PortRangeList oldpl = transport_get_ports(_list, type);
284
for(TransportList::Iterator it = list.begin(); it != list.end(); ++it)
288
if(!r.fromString(t.argument(type)))
290
int n = oldpl.findByBase(r.base);
293
r.base = newpl[n].base;
294
t.setArgument(type, r.toString());
299
static PortRangeList transport_get_client_ports(const TransportList &list)
301
return transport_get_ports(list, "client_port");
304
static TransportList transport_set_client_ports(const TransportList &_list, const PortRangeList &newpl)
306
return transport_set_ports(_list, "client_port", newpl);
309
static PortRangeList transport_get_server_ports(const TransportList &list)
311
return transport_get_ports(list, "server_port");
314
static TransportList transport_set_server_ports(const TransportList &_list, const PortRangeList &newpl)
316
return transport_set_ports(_list, "server_port", newpl);
319
static void showPacket(const RTSP::Packet &p)
321
if(p.type() == RTSP::Packet::Request)
323
printf("--- RTSP Request ---\n");
324
printf("Command: [%s]\n", p.command().latin1());
325
printf("Resource: [%s]\n", p.resource().latin1());
326
printf("Version: [%s]\n", p.version().latin1());
327
printf("Headers:\n");
328
HeaderList headers = p.headers();
329
for(HeaderList::ConstIterator it = headers.begin(); it != headers.end(); ++it)
330
printf(" [%s] = [%s]\n", (*it).name.latin1(), (*it).value.latin1());
331
QByteArray data = p.data();
333
printf("[%d bytes of attached content]\n", data.size());
334
printf("------------------------\n");
336
else if(p.type() == RTSP::Packet::Response)
338
printf("--- RTSP Response ---\n");
339
printf("Code: [%d]\n", p.responseCode());
340
printf("String: [%s]\n", p.responseString().latin1());
341
printf("Version: [%s]\n", p.version().latin1());
342
printf("Headers:\n");
343
HeaderList headers = p.headers();
344
for(HeaderList::ConstIterator it = headers.begin(); it != headers.end(); ++it)
345
printf(" [%s] = [%s]\n", (*it).name.latin1(), (*it).value.latin1());
346
QByteArray data = p.data();
348
printf("[%d bytes of attached content]\n", data.size());
349
printf("------------------------\n");
351
else if(p.type() == RTSP::Packet::Data)
353
printf("--- RTSP Interleaved ---\n");
354
printf("Channel: [%d]\n", p.channel());
355
QByteArray data = p.data();
357
printf("[%d bytes of RTP content]\n", data.size());
358
printf("------------------------\n");
362
class Session : public QObject
371
connect(&local, SIGNAL(incomingReady()), SLOT(local_incomingReady()));
372
connect(&mapper, SIGNAL(packetFromClient(int, int, const QByteArray &)), SLOT(map_packetFromClient(int, int, const QByteArray &)));
373
connect(&mapper, SIGNAL(packetFromServer(int, int, const QByteArray &)), SLOT(map_packetFromServer(int, int, const QByteArray &)));
389
bool startIncoming(const QValueList<QUrl> &_urls, ByteStream *_server, int *incomingPort)
392
server = new RTSP::Client;
393
server->setByteStream(_server, RTSP::Client::MServer);
395
if(!try_serve(&local))
400
*incomingPort = local.port();
404
bool startIncoming(const QValueList<QUrl> &_urls, const QString &serverHost, int serverPort, int *incomingPort)
413
if(!try_serve(&local))
418
*incomingPort = local.port();
422
bool startExisting(const QValueList<QUrl> &_urls, ByteStream *_client, const QString &serverHost, int serverPort)
425
client = new RTSP::Client;
426
client->setByteStream(_client, RTSP::Client::MClient);
435
void writeAsClient(int source, int dest, const QByteArray &buf)
437
mapper.writeAsClient(source, dest, buf);
440
void writeAsServer(int source, int dest, const QByteArray &buf)
442
mapper.writeAsServer(source, dest, buf);
446
void packetFromClient(int source, int dest, const QByteArray &buf);
447
void packetFromServer(int source, int dest, const QByteArray &buf);
450
void local_incomingReady()
452
Client *c = local.takeIncoming();
459
connect(client, SIGNAL(connectionClosed()), SLOT(client_connectionClosed()));
460
connect(client, SIGNAL(packetReady(const Packet &)), SLOT(client_packetReady(const Packet &)));
461
connect(client, SIGNAL(packetWritten()), SLOT(client_packetWritten()));
462
connect(client, SIGNAL(error(int)), SLOT(client_error(int)));
465
void client_connectionClosed()
467
printf("Session: Client: connectionClosed\n");
472
void client_packetReady(const Packet &p)
477
lastWasSetup = false;
482
QUrl u = urls.first();
483
int u_port = u.hasPort() ? u.port() : 554;
485
QUrl pu(m.resource());
486
pu.setHost(u.host());
487
pu.setPort(u_port == 554 ? -1 : u_port);
489
m.setResource(pu.toString());
492
QString cmd = m.command();
495
TransportList list = m.transports();
496
PortRangeList pl = transport_get_client_ports(list);
498
/*printf("SETUP ports [%d]:\n", pl.count());
499
for(PortRangeList::ConstIterator it = pl.begin(); it != pl.end(); ++it)
500
printf("[%d-%d] ", (*it).base, (*it).count);
504
mapper.reserveVirtualClient(pl);
506
mapper.reserveDirectClient(pl, virtServer);
507
PortRangeList altPorts = mapper.clientAlternatePorts();
509
/*printf("Alternate ports [%d]:\n", altPorts.count());
510
for(PortRangeList::ConstIterator it = altPorts.begin(); it != altPorts.end(); ++it)
511
printf("[%d-%d] ", (*it).base, (*it).count);
514
m.setTransports(transport_set_client_ports(list, altPorts));
520
// on receipt of first packet, connect to server if necessary
524
connect(server, SIGNAL(connected()), SLOT(server_connected()));
525
connect(server, SIGNAL(connectionClosed()), SLOT(server_connectionClosed()));
526
connect(server, SIGNAL(packetReady(const Packet &)), SLOT(server_packetReady(const Packet &)));
527
connect(server, SIGNAL(packetWritten()), SLOT(server_packetWritten()));
528
connect(server, SIGNAL(error(int)), SLOT(server_error(int)));
529
printf("Session: Server: connecting to server\n");
530
server->connectToHost(shost, sport);
537
void client_packetWritten()
539
//printf("Session: Client: packetWritten\n");
542
void client_error(int x)
544
printf("Session: Client: error %d\n", x);
549
void server_connected()
551
printf("Session: Server: connected\n");
555
void server_connectionClosed()
557
printf("Session: Server: connectionClosed\n");
561
void server_packetReady(const Packet &p)
569
TransportList list = m.transports();
570
PortRangeList cpl = transport_get_client_ports(list);
571
PortRangeList spl = transport_get_server_ports(list);
573
/*printf("SETUP ports [%d]:\n", cpl.count());
574
for(PortRangeList::ConstIterator it = cpl.begin(); it != cpl.end(); ++it)
575
printf("[%d-%d] ", (*it).base, (*it).count);
577
printf("Server SETUP ports [%d]:\n", spl.count());
578
for(PortRangeList::ConstIterator it = spl.begin(); it != spl.end(); ++it)
579
printf("[%d-%d] ", (*it).base, (*it).count);
582
mapper.finalize(client->peerAddress(), cpl.first(), server->peerAddress(), spl.first());
583
PortRangeList altPorts = mapper.serverAlternatePorts();
585
/*printf("Alternate ports [%d]:\n", altPorts.count());
586
for(PortRangeList::ConstIterator it = altPorts.begin(); it != altPorts.end(); ++it)
587
printf("[%d-%d] ", (*it).base, (*it).count);
590
m.setTransports(transport_set_server_ports(list, altPorts));
597
void server_packetWritten()
599
//printf("Session: Server: packetWritten\n");
602
void server_error(int x)
604
printf("Session: Server: error %d\n", x);
608
void map_packetFromClient(int source, int dest, const QByteArray &buf)
610
packetFromClient(source, dest, buf);
613
void map_packetFromServer(int source, int dest, const QByteArray &buf)
615
packetFromServer(source, dest, buf);
621
for(QValueList<Packet>::Iterator it = cpackets.begin(); it != cpackets.end();)
625
it = cpackets.remove(it);
629
bool virtClient, virtServer;
630
QValueList<Packet> cpackets;
631
Client *client, *server;
633
QValueList<QUrl> urls;
640
//----------------------------------------------------------------------------
642
//----------------------------------------------------------------------------
643
class RTSPProxy::Private : public QObject
649
Private(RTSPProxy *_par) : par(_par)
654
RTSPProxy::RTSPProxy(QObject *parent)
657
d = new Private(this);
660
RTSPProxy::~RTSPProxy()
665
int RTSPProxy::startIncoming(const QStringList &urls, ByteStream *server, int *incomingPort)
669
int RTSPProxy::startIncoming(const QStringList &urls, const QString &serverHost, int serverPort, int *incomingPort)
671
QValueList<QUrl> list;
672
for(QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it)
673
list.append(QUrl(*it));
674
Session *s = new Session;
675
if(!s->startIncoming(list, serverHost, serverPort, incomingPort))
680
// TODO: add session to a list or something
683
int RTSPProxy::startExisting(const QStringList &urls, ByteStream *client, const QString &serverHost, int serverPort)
687
void RTSPProxy::stop(int id)
691
void RTSPProxy::writeAsClient(int id, int source, int dest, const QByteArray &buf)
695
void RTSPProxy::writeAsServer(int id, int source, int dest, const QByteArray &buf)
699
QString RTSPProxy::mangle(const QString &url, const QString &host, int port)
703
u.setPort(port == 554 ? -1 : port);
707
#include "rtspproxy.moc"