source: psi/trunk/cutestuff/rtsp/rtspproxy.cpp@ 189

Last change on this file since 189 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 17.7 KB
Line 
1/*
2 * rtspproxy.cpp - proxy for RTSP allowing direct and/or virtual endpoints
3 * Copyright (C) 2004 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 "rtspproxy.h"
22
23#include <qurl.h>
24#include "servsock.h"
25#include "bsocket.h"
26#include "rtspbase.h"
27#include "altports.h"
28
29#define SERVER_ALLOC_BASE 16000
30#define SERVER_ALLOC_MAX 65535
31
32static bool try_serve(RTSP::Server *s)
33{
34 for(int n = SERVER_ALLOC_BASE; n <= SERVER_ALLOC_MAX; ++n)
35 {
36 if(s->start(n))
37 return true;
38 }
39 return false;
40}
41
42//----------------------------------------------------------------------------
43// PortMapper
44//----------------------------------------------------------------------------
45static PortRangeList create_virtual_ranges(const PortRangeList &in)
46{
47 PortRangeList out;
48 int base = 1;
49 for(PortRangeList::ConstIterator it = in.begin(); it != in.end(); ++it)
50 {
51 PortRange r;
52 r.base = base;
53 r.count = (*it).count;
54 base += r.count;
55 out.append(r);
56 }
57 return out;
58}
59
60class MapItem
61{
62public:
63 bool active;
64 bool virt;
65 QHostAddress host;
66 PortRange realPorts;
67 AltPorts altPorts;
68 PortRangeList realPortRanges, altPortRanges;
69
70 MapItem()
71 {
72 active = false;
73 virt = false;
74 }
75
76 void reset()
77 {
78 active = false;
79 virt = false;
80 host = QHostAddress();
81 altPorts.reset();
82 }
83};
84
85class PortMapper : public QObject
86{
87 Q_OBJECT
88public:
89 PortMapper();
90 ~PortMapper();
91
92 void reset();
93
94 // setup
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);
98
99 PortRangeList clientAlternatePorts() const;
100 PortRangeList serverAlternatePorts() const;
101
102 void writeAsClient(int source, int dest, const QByteArray &buf);
103 void writeAsServer(int source, int dest, const QByteArray &buf);
104
105signals:
106 void packetFromClient(int source, int dest, const QByteArray &buf);
107 void packetFromServer(int source, int dest, const QByteArray &buf);
108
109private slots:
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);
112
113private:
114 MapItem client, server;
115 bool ready;
116};
117
118PortMapper::PortMapper()
119{
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 &)));
122 ready = false;
123}
124
125PortMapper::~PortMapper()
126{
127}
128
129void PortMapper::reset()
130{
131 client.reset();
132 server.reset();
133 ready = false;
134}
135
136bool PortMapper::reserveDirectClient(const PortRangeList &clientRanges, bool virtServer)
137{
138 if(client.active)
139 return true;
140
141 client.realPortRanges = clientRanges;
142 if(virtServer)
143 {
144 client.virt = true; // virtual server means virtual client ports
145 client.altPortRanges = create_virtual_ranges(clientRanges);
146 }
147 else
148 {
149 if(!client.altPorts.reserve(clientRanges, &client.altPortRanges))
150 return false;
151 }
152 client.active = true;
153
154 return true;
155}
156
157bool PortMapper::reserveVirtualClient(const PortRangeList &clientRanges)
158{
159 if(client.active)
160 return false;
161
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;
166
167 return true;
168}
169
170bool PortMapper::finalize(const QHostAddress &clientHost, const PortRange &clientPorts, const QHostAddress &serverHost, const PortRange &serverPorts)
171{
172 if(ready)
173 return true;
174
175 int n = client.altPortRanges.findByBase(clientPorts.base);
176 if(n == -1)
177 return false;
178
179 client.host = clientHost;
180 client.realPorts = client.realPortRanges[n];
181 client.realPorts.count = clientPorts.count;
182
183 if(client.virt)
184 {
185 PortRange virtPorts = client.altPortRanges[n];
186 virtPorts.count = clientPorts.count;
187 client.altPortRanges.clear();
188 client.altPortRanges.append(virtPorts);
189 }
190 else
191 {
192 client.altPorts.keep(client.realPorts);
193 client.altPortRanges.clear();
194 client.altPortRanges.append(client.altPorts.range());
195 }
196
197 server.host = serverHost;
198 server.realPorts = serverPorts;
199
200 if(server.virt)
201 {
202 PortRangeList in;
203 in.append(server.realPorts);
204 server.altPortRanges = create_virtual_ranges(in);
205 }
206 else
207 {
208 PortRange r;
209 if(!server.altPorts.allocate(server.realPorts, &r))
210 return false;
211 server.altPortRanges.clear();
212 server.altPortRanges.append(r);
213 }
214 server.active = true;
215
216 ready = true;
217 return true;
218}
219
220PortRangeList PortMapper::clientAlternatePorts() const
221{
222 return client.altPortRanges;
223}
224
225PortRangeList PortMapper::serverAlternatePorts() const
226{
227 return server.altPortRanges;
228}
229
230void PortMapper::writeAsClient(int source, int, const QByteArray &buf)
231{
232 if(source < client.realPorts.base || source >= client.realPorts.base + client.realPorts.count)
233 return;
234 int index = source - client.realPorts.base;
235 client.altPorts.send(index, server.host, server.realPorts.base + index, buf);
236}
237
238void PortMapper::writeAsServer(int source, int, const QByteArray &buf)
239{
240 if(source < server.realPorts.base || source >= server.realPorts.base + server.realPorts.count)
241 return;
242 int index = source - server.realPorts.base;
243 server.altPorts.send(index, client.host, client.realPorts.base + index, buf);
244}
245
246void PortMapper::client_packetReady(int index, const QHostAddress &, int, const QByteArray &buf)
247{
248 if(server.virt)
249 emit packetFromServer(server.altPortRanges.first().base + index, client.realPorts.base + index, buf);
250 else
251 server.altPorts.send(index, client.host, client.realPorts.base + index, buf);
252}
253
254void PortMapper::server_packetReady(int index, const QHostAddress &, int, const QByteArray &buf)
255{
256 if(client.virt)
257 emit packetFromClient(client.altPortRanges.first().base + index, server.realPorts.base + index, buf);
258 else
259 client.altPorts.send(index, server.host, server.realPorts.base + index, buf);
260}
261
262//----------------------------------------------------------------------------
263// Session
264//----------------------------------------------------------------------------
265using namespace RTSP;
266
267static PortRangeList transport_get_ports(const TransportList &list, const QString &type)
268{
269 PortRangeList out;
270 for(TransportList::ConstIterator it = list.begin(); it != list.end(); ++it)
271 {
272 PortRange r;
273 if(!r.fromString((*it).argument(type)))
274 continue;
275 out.merge(r);
276 }
277 return out;
278}
279
280static TransportList transport_set_ports(const TransportList &_list, const QString &type, const PortRangeList &newpl)
281{
282 TransportList list = _list;
283 PortRangeList oldpl = transport_get_ports(_list, type);
284 for(TransportList::Iterator it = list.begin(); it != list.end(); ++it)
285 {
286 Transport &t = *it;
287 PortRange r;
288 if(!r.fromString(t.argument(type)))
289 continue;
290 int n = oldpl.findByBase(r.base);
291 if(n == -1)
292 continue;
293 r.base = newpl[n].base;
294 t.setArgument(type, r.toString());
295 }
296 return list;
297}
298
299static PortRangeList transport_get_client_ports(const TransportList &list)
300{
301 return transport_get_ports(list, "client_port");
302}
303
304static TransportList transport_set_client_ports(const TransportList &_list, const PortRangeList &newpl)
305{
306 return transport_set_ports(_list, "client_port", newpl);
307}
308
309static PortRangeList transport_get_server_ports(const TransportList &list)
310{
311 return transport_get_ports(list, "server_port");
312}
313
314static TransportList transport_set_server_ports(const TransportList &_list, const PortRangeList &newpl)
315{
316 return transport_set_ports(_list, "server_port", newpl);
317}
318
319static void showPacket(const RTSP::Packet &p)
320{
321 if(p.type() == RTSP::Packet::Request)
322 {
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();
332 if(!data.isEmpty())
333 printf("[%d bytes of attached content]\n", data.size());
334 printf("------------------------\n");
335 }
336 else if(p.type() == RTSP::Packet::Response)
337 {
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();
347 if(!data.isEmpty())
348 printf("[%d bytes of attached content]\n", data.size());
349 printf("------------------------\n");
350 }
351 else if(p.type() == RTSP::Packet::Data)
352 {
353 printf("--- RTSP Interleaved ---\n");
354 printf("Channel: [%d]\n", p.channel());
355 QByteArray data = p.data();
356 if(!data.isEmpty())
357 printf("[%d bytes of RTP content]\n", data.size());
358 printf("------------------------\n");
359 }
360}
361
362class Session : public QObject
363{
364 Q_OBJECT
365public:
366 Session()
367 {
368 client = 0;
369 server = 0;
370
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 &)));
374 }
375
376 ~Session()
377 {
378 reset();
379 }
380
381 void reset()
382 {
383 delete client;
384 client = 0;
385 delete server;
386 server = 0;
387 }
388
389 bool startIncoming(const QValueList<QUrl> &_urls, ByteStream *_server, int *incomingPort)
390 {
391 urls = _urls;
392 server = new RTSP::Client;
393 server->setByteStream(_server, RTSP::Client::MServer);
394
395 if(!try_serve(&local))
396 return false;
397
398 virtClient = false;
399 virtServer = true;
400 *incomingPort = local.port();
401 return true;
402 }
403
404 bool startIncoming(const QValueList<QUrl> &_urls, const QString &serverHost, int serverPort, int *incomingPort)
405 {
406 if(_urls.isEmpty())
407 return false;
408
409 urls = _urls;
410 shost = serverHost;
411 sport = serverPort;
412
413 if(!try_serve(&local))
414 return false;
415
416 virtClient = false;
417 virtServer = false;
418 *incomingPort = local.port();
419 return true;
420 }
421
422 bool startExisting(const QValueList<QUrl> &_urls, ByteStream *_client, const QString &serverHost, int serverPort)
423 {
424 urls = _urls;
425 client = new RTSP::Client;
426 client->setByteStream(_client, RTSP::Client::MClient);
427 shost = serverHost;
428 sport = serverPort;
429
430 virtClient = true;
431 virtServer = false;
432 return true;
433 }
434
435 void writeAsClient(int source, int dest, const QByteArray &buf)
436 {
437 mapper.writeAsClient(source, dest, buf);
438 }
439
440 void writeAsServer(int source, int dest, const QByteArray &buf)
441 {
442 mapper.writeAsServer(source, dest, buf);
443 }
444
445signals:
446 void packetFromClient(int source, int dest, const QByteArray &buf);
447 void packetFromServer(int source, int dest, const QByteArray &buf);
448
449private slots:
450 void local_incomingReady()
451 {
452 Client *c = local.takeIncoming();
453 if(!c)
454 return;
455
456 local.stop();
457
458 client = c;
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)));
463 }
464
465 void client_connectionClosed()
466 {
467 printf("Session: Client: connectionClosed\n");
468 delete client;
469 client = 0;
470 }
471
472 void client_packetReady(const Packet &p)
473 {
474 showPacket(p);
475
476 Packet m = p;
477 lastWasSetup = false;
478
479 // unmangle the url?
480 if(!virtClient)
481 {
482 QUrl u = urls.first();
483 int u_port = u.hasPort() ? u.port() : 554;
484
485 QUrl pu(m.resource());
486 pu.setHost(u.host());
487 pu.setPort(u_port == 554 ? -1 : u_port);
488
489 m.setResource(pu.toString());
490 }
491
492 QString cmd = m.command();
493 if(cmd == "SETUP")
494 {
495 TransportList list = m.transports();
496 PortRangeList pl = transport_get_client_ports(list);
497
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);
501 printf("\n");*/
502
503 if(virtClient)
504 mapper.reserveVirtualClient(pl);
505 else
506 mapper.reserveDirectClient(pl, virtServer);
507 PortRangeList altPorts = mapper.clientAlternatePorts();
508
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);
512 printf("\n");*/
513
514 m.setTransports(transport_set_client_ports(list, altPorts));
515 lastWasSetup = true;
516 }
517
518 cpackets.append(m);
519
520 // on receipt of first packet, connect to server if necessary
521 if(!server)
522 {
523 server = new Client;
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);
531 return;
532 }
533
534 sendPackets();
535 }
536
537 void client_packetWritten()
538 {
539 //printf("Session: Client: packetWritten\n");
540 }
541
542 void client_error(int x)
543 {
544 printf("Session: Client: error %d\n", x);
545 delete client;
546 client = 0;
547 }
548
549 void server_connected()
550 {
551 printf("Session: Server: connected\n");
552 sendPackets();
553 }
554
555 void server_connectionClosed()
556 {
557 printf("Session: Server: connectionClosed\n");
558 reset();
559 }
560
561 void server_packetReady(const Packet &p)
562 {
563 showPacket(p);
564 if(client)
565 {
566 Packet m = p;
567 if(lastWasSetup)
568 {
569 TransportList list = m.transports();
570 PortRangeList cpl = transport_get_client_ports(list);
571 PortRangeList spl = transport_get_server_ports(list);
572
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);
576 printf("\n");
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);
580 printf("\n");*/
581
582 mapper.finalize(client->peerAddress(), cpl.first(), server->peerAddress(), spl.first());
583 PortRangeList altPorts = mapper.serverAlternatePorts();
584
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);
588 printf("\n");*/
589
590 m.setTransports(transport_set_server_ports(list, altPorts));
591 }
592 showPacket(m);
593 client->write(m);
594 }
595 }
596
597 void server_packetWritten()
598 {
599 //printf("Session: Server: packetWritten\n");
600 }
601
602 void server_error(int x)
603 {
604 printf("Session: Server: error %d\n", x);
605 reset();
606 }
607
608 void map_packetFromClient(int source, int dest, const QByteArray &buf)
609 {
610 packetFromClient(source, dest, buf);
611 }
612
613 void map_packetFromServer(int source, int dest, const QByteArray &buf)
614 {
615 packetFromServer(source, dest, buf);
616 }
617
618private:
619 void sendPackets()
620 {
621 for(QValueList<Packet>::Iterator it = cpackets.begin(); it != cpackets.end();)
622 {
623 showPacket(*it);
624 server->write(*it);
625 it = cpackets.remove(it);
626 }
627 }
628
629 bool virtClient, virtServer;
630 QValueList<Packet> cpackets;
631 Client *client, *server;
632 Server local;
633 QValueList<QUrl> urls;
634 QString shost;
635 int sport;
636 PortMapper mapper;
637 bool lastWasSetup;
638};
639
640//----------------------------------------------------------------------------
641// RTSPProxy
642//----------------------------------------------------------------------------
643class RTSPProxy::Private : public QObject
644{
645 Q_OBJECT
646public:
647 RTSPProxy *par;
648
649 Private(RTSPProxy *_par) : par(_par)
650 {
651 }
652};
653
654RTSPProxy::RTSPProxy(QObject *parent)
655:QObject(parent)
656{
657 d = new Private(this);
658}
659
660RTSPProxy::~RTSPProxy()
661{
662 delete d;
663}
664
665int RTSPProxy::startIncoming(const QStringList &urls, ByteStream *server, int *incomingPort)
666{
667}
668
669int RTSPProxy::startIncoming(const QStringList &urls, const QString &serverHost, int serverPort, int *incomingPort)
670{
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))
676 {
677 delete s;
678 return -1;
679 }
680 // TODO: add session to a list or something
681}
682
683int RTSPProxy::startExisting(const QStringList &urls, ByteStream *client, const QString &serverHost, int serverPort)
684{
685}
686
687void RTSPProxy::stop(int id)
688{
689}
690
691void RTSPProxy::writeAsClient(int id, int source, int dest, const QByteArray &buf)
692{
693}
694
695void RTSPProxy::writeAsServer(int id, int source, int dest, const QByteArray &buf)
696{
697}
698
699QString RTSPProxy::mangle(const QString &url, const QString &host, int port)
700{
701 QUrl u(url);
702 u.setHost(host);
703 u.setPort(port == 554 ? -1 : port);
704 return u.toString();
705}
706
707#include "rtspproxy.moc"
Note: See TracBrowser for help on using the repository browser.