source: psi/trunk/cutestuff/rtsp/rtspbase.cpp

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

Imported original Psi 0.10 sources from Affinix

File size: 17.8 KB
Line 
1/*
2 * rtspbase.cpp - very basic RTSP client/server
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 "rtspbase.h"
22
23#include <qtimer.h>
24#include <qguardedptr.h>
25#include "bsocket.h"
26#include "servsock.h"
27
28#ifdef Q_OS_WIN
29# include <windows.h>
30#else
31# include <netinet/in.h>
32#endif
33
34#define MAX_CONTENT_LENGTH 32767
35
36namespace RTSP {
37
38//----------------------------------------------------------------------------
39// HeaderList
40//----------------------------------------------------------------------------
41HeaderList::HeaderList()
42:QValueList<Var>()
43{
44}
45
46bool HeaderList::has(const QString &var) const
47{
48 QString low = var.lower();
49 for(ConstIterator it = begin(); it != end(); ++it)
50 {
51 if((*it).name.lower() == low)
52 return true;
53 }
54 return false;
55}
56
57QString HeaderList::get(const QString &var) const
58{
59 QString low = var.lower();
60 for(ConstIterator it = begin(); it != end(); ++it)
61 {
62 if((*it).name.lower() == low)
63 return (*it).value;
64 }
65 return QString::null;
66}
67
68void HeaderList::set(const QString &var, const QString &val)
69{
70 QString low = var.lower();
71 for(Iterator it = begin(); it != end(); ++it)
72 {
73 if((*it).name.lower() == low)
74 {
75 (*it).value = val;
76 return;
77 }
78 }
79 Var v;
80 v.name = var;
81 v.value = val;
82 append(v);
83}
84
85void HeaderList::remove(const QString &var)
86{
87 QString low = var.lower();
88 for(Iterator it = begin(); it != end(); ++it)
89 {
90 if((*it).name.lower() == low)
91 {
92 QValueList<Var>::remove(it);
93 return;
94 }
95 }
96}
97
98//----------------------------------------------------------------------------
99// Transport
100//----------------------------------------------------------------------------
101static int findOneOf(const QString &s, const QString &list, int i, QChar *found)
102{
103 for(int n = i; n < (int)s.length(); ++n)
104 {
105 for(int k = 0; k < (int)list.length(); ++k)
106 {
107 if(s[n] == list[k])
108 {
109 if(found)
110 *found = list[k];
111 return n;
112 }
113 }
114 }
115 return -1;
116}
117
118Transport::Transport()
119{
120}
121
122QString Transport::name() const
123{
124 return _name;
125}
126
127TransportArgs Transport::arguments() const
128{
129 return _args;
130}
131
132QString Transport::argument(const QString &name) const
133{
134 for(TransportArgs::ConstIterator it = _args.begin(); it != _args.end(); ++it)
135 {
136 const Var &v = *it;
137 if(v.name == name)
138 return v.value;
139 }
140 return QString::null;
141}
142
143void Transport::setArguments(const TransportArgs &list)
144{
145 _args = list;
146}
147
148void Transport::setArgument(const QString &name, const QString &value)
149{
150 for(TransportArgs::Iterator it = _args.begin(); it != _args.end(); ++it)
151 {
152 Var &v = *it;
153 if(v.name == name)
154 {
155 v.value = value;
156 return;
157 }
158 }
159}
160
161QString Transport::toString() const
162{
163 QString s;
164 s += _name;
165 if(!_args.isEmpty())
166 {
167 for(TransportArgs::ConstIterator it = _args.begin(); it != _args.end(); ++it)
168 {
169 s += ';';
170 s += (*it).name;
171 if(!(*it).value.isNull())
172 {
173 s += '=';
174 s += (*it).value;
175 }
176 }
177 }
178 return s;
179}
180
181Transport::ReadStatus Transport::readFromString(QString *sp)
182{
183 const QString &s = *sp;
184 QString tname;
185 QValueList<Var> targs;
186
187 // first read the name
188 int at = 0;
189 QChar c;
190 int n = findOneOf(s, ",;", at, &c);
191 if(n == -1)
192 {
193 tname = s.mid(at);
194 // empty at end means nothing left
195 if(tname.isEmpty())
196 return Done;
197
198 at = s.length();
199 }
200 else if(c == ',')
201 {
202 tname = s.mid(at, n - at);
203 // empty with separator is bad
204 if(tname.isEmpty())
205 return Error;
206
207 at = n + 1;
208 }
209 else if(c == ';')
210 {
211 tname = s.mid(at, n - at);
212 // empty with separator is bad
213 if(tname.isEmpty())
214 return Error;
215
216 at = n + 1;
217
218 // read args
219 QString targ, tval;
220 bool last = false;
221 while(!last)
222 {
223 // get arg
224 n = findOneOf(s, ",;=", at, &c);
225 if(n == -1)
226 {
227 targ = s.mid(at);
228 // empty at end means nothing left
229 if(targ.isEmpty())
230 break;
231
232 at = s.length();
233 last = true;
234 }
235 else if(c == ',')
236 {
237 targ = s.mid(at, n - at);
238 // empty with separator is bad
239 if(targ.isEmpty())
240 return Error;
241
242 at = n + 1;
243 last = true;
244 }
245 else if(c == ';')
246 {
247 targ = s.mid(at, n - at);
248 // empty with separator is bad
249 if(targ.isEmpty())
250 return Error;
251
252 at = n + 1;
253 }
254 else if(c == '=')
255 {
256 // this arg has a value
257 targ = s.mid(at, n - at);
258 // empty with value is bad
259 if(targ.isEmpty())
260 return Error;
261
262 at = n + 1;
263
264 // is next char a quote?
265 if(at < (int)s.length() && s[at] == '\"')
266 {
267 n = s.find('\"', at + 1);
268 if(n == -1)
269 return Error;
270 tval = s.mid(at, n - at + 1);
271 at = n + 1;
272
273 if(at < (int)s.length())
274 {
275 // if not at end, the next char better be a separator
276 if(s[at] != ',' && s[at] != ';')
277 return Error;
278
279 if(s[at] == ',')
280 last = true;
281
282 // skip over it
283 ++at;
284 }
285 else
286 last = true;
287 }
288 else
289 {
290 // find next separator
291 n = findOneOf(s, ",;", at, &c);
292 if(n == -1)
293 {
294 tval = s.mid(at);
295 at = s.length();
296 last = true;
297 }
298 else if(c == ',')
299 {
300 tval = s.mid(at, n - at);
301 at = n + 1;
302 last = true;
303 }
304 else if(c == ';')
305 {
306 tval = s.mid(at, n - at);
307 at = n + 1;
308 }
309 }
310 }
311
312 Var v;
313 v.name = targ;
314 v.value = tval;
315 targs.append(v);
316 }
317 }
318
319 _name = tname;
320 _args = targs;
321
322 // remove what we just parsed
323 (*sp) = sp->mid(at);
324 return Ok;
325}
326
327//----------------------------------------------------------------------------
328// TransportList
329//----------------------------------------------------------------------------
330TransportList::TransportList()
331:QValueList<Transport>()
332{
333}
334
335QString TransportList::toString() const
336{
337 QStringList list;
338 for(ConstIterator it = begin(); it != end(); ++it)
339 list.append((*it).toString());
340 return list.join(",");
341}
342
343bool TransportList::fromString(const QString &s)
344{
345 QString tmp = s;
346 clear();
347
348 while(1)
349 {
350 Transport t;
351 Transport::ReadStatus r = t.readFromString(&tmp);
352 if(r == Transport::Error)
353 return false;
354 if(r == Transport::Done)
355 break;
356 append(t);
357 }
358
359 return true;
360}
361
362//----------------------------------------------------------------------------
363// Packet
364//----------------------------------------------------------------------------
365Packet::Packet()
366{
367 t = Empty;
368}
369
370Packet::Packet(const QString &command, const QString &resource, const HeaderList &headers)
371{
372 cmd = command;
373 res = resource;
374 _headers = headers;
375 ver = "1.0";
376}
377
378Packet::Packet(int responseCode, const QString &responseString, const HeaderList &headers)
379{
380 rcode = responseCode;
381 rstr = responseString;
382 _headers = headers;
383 ver = "1.0";
384}
385
386Packet::~Packet()
387{
388}
389
390bool Packet::isNull() const
391{
392 return (t == Empty);
393}
394
395Packet::Type Packet::type() const
396{
397 return t;
398}
399
400QString Packet::version() const
401{
402 return ver;
403}
404
405QString Packet::command() const
406{
407 return cmd;
408}
409
410QString Packet::resource() const
411{
412 return res;
413}
414
415int Packet::responseCode() const
416{
417 return rcode;
418}
419
420QString Packet::responseString() const
421{
422 return rstr;
423}
424
425int Packet::channel() const
426{
427 return chan;
428}
429
430QByteArray Packet::data() const
431{
432 return _data;
433}
434
435HeaderList & Packet::headers()
436{
437 return _headers;
438}
439
440const HeaderList & Packet::headers() const
441{
442 return _headers;
443}
444
445TransportList Packet::transports() const
446{
447 TransportList list;
448 list.fromString(_headers.get("Transport"));
449 return list;
450}
451
452void Packet::setTransports(const TransportList &list)
453{
454 _headers.set("Transport", list.toString());
455}
456
457void Packet::setResource(const QString &s)
458{
459 res = s;
460}
461
462QByteArray Packet::toArray() const
463{
464 QByteArray buf;
465
466 if(t == Data)
467 {
468 buf.resize(4 + _data.size());
469
470 buf[0] = '$';
471 buf[1] = chan;
472 ushort ssa = _data.size();
473 ushort ssb = htons(ssa);
474 memcpy(buf.data() + 2, &ssb, 2);
475 memcpy(buf.data() + 4, _data.data(), _data.size());
476 }
477 else
478 {
479 QString str;
480
481 if(t == Request)
482 {
483 str += cmd + ' ' + res + " RTSP/" + ver + '\n';
484 for(HeaderList::ConstIterator it = _headers.begin(); it != _headers.end(); ++it)
485 str += (*it).name + ": " + (*it).value + '\n';
486 str += '\n';
487 }
488 else if(t == Response)
489 {
490 str += "RTSP/" + ver + ' ' + QString::number(rcode) + ' ' + rstr + '\n';
491 for(HeaderList::ConstIterator it = _headers.begin(); it != _headers.end(); ++it)
492 str += (*it).name + ": " + (*it).value + '\n';
493 str += '\n';
494 }
495
496 QCString cs = str.utf8();
497 buf.resize(cs.length());
498 memcpy(buf.data(), cs.data(), buf.size());
499 ByteStream::appendArray(&buf, _data);
500 }
501
502 return buf;
503}
504
505//----------------------------------------------------------------------------
506// Parser
507//----------------------------------------------------------------------------
508Parser::Parser()
509{
510}
511
512void Parser::reset(Mode _mode)
513{
514 mode = _mode;
515 in.resize(0);
516 cur.clear();
517 tmp = Packet();
518 list.clear();
519}
520
521void Parser::appendData(const QByteArray &a)
522{
523 ByteStream::appendArray(&in, a);
524}
525
526Packet Parser::read(bool *ok)
527{
528 if(ok)
529 *ok = true;
530
531 if(list.isEmpty())
532 {
533 if(!readPacket())
534 {
535 if(ok)
536 *ok = false;
537 }
538 }
539
540 Packet p;
541 if(!list.isEmpty())
542 {
543 p = list.first();
544 list.remove(list.begin());
545 }
546 return p;
547}
548
549bool Parser::readPacket()
550{
551 bool interleaved = false;
552 bool done = false;
553
554 // don't know what it is yet? let's have a look
555 if(tmp.t == Packet::Empty)
556 {
557 // need at least 1 byte
558 if(in.isEmpty())
559 return true;
560
561 if(in[0] == '$')
562 {
563 // interleaved data
564 if(in.size() < 4)
565 return true;
566 ushort ss;
567 memcpy(&ss, in.data() + 2, 2);
568 int size = ntohs(ss);
569 if((int)in.size() < 4 + size)
570 return true;
571
572 QByteArray buf = ByteStream::takeArray(&in, 4 + size);
573 tmp.t = Packet::Data;
574 tmp.chan = buf[1];
575 tmp._data.resize(size);
576 memcpy(tmp._data.data(), buf.data() + 4, size);
577
578 interleaved = true;
579 done = true;
580 }
581 else
582 {
583 // regular request/response
584 if(mode == Client)
585 tmp.t = Packet::Request;
586 else
587 tmp.t = Packet::Response;
588 readingContent = false;
589 }
590 }
591
592 if(!interleaved)
593 {
594 if(!readingContent)
595 {
596 // read the lines
597 QStringList lines = readPacketLines();
598 if(lines.isEmpty())
599 return true;
600 if(!packetFromLines(lines))
601 return false;
602 if(tmp._headers.has("Content-length"))
603 {
604 clen = tmp._headers.get("Content-length").toInt();
605 if(clen > MAX_CONTENT_LENGTH)
606 return false;
607 }
608 else
609 clen = 0;
610 readingContent = true;
611 }
612
613 if(readingContent)
614 {
615 if(clen > 0)
616 {
617 int need = clen - tmp._data.size();
618 QByteArray a;
619 if((int)in.size() >= need)
620 a = ByteStream::takeArray(&in, need);
621 else
622 a = ByteStream::takeArray(&in);
623 ByteStream::appendArray(&tmp._data, a);
624 }
625
626 if(clen == 0 || (int)tmp._data.size() == clen)
627 done = true;
628 }
629 }
630
631 if(done)
632 {
633 list.append(tmp);
634 tmp = Packet();
635 }
636
637 return true;
638}
639
640bool Parser::packetFromLines(const QStringList &lines)
641{
642 if(mode == Client)
643 {
644 if(lines.isEmpty())
645 return false;
646 QString str = lines[0];
647 int n = str.find(' ');
648 if(n == -1)
649 return false;
650 QString c = str.mid(0, n);
651 int at = n + 1;
652 n = str.find(' ', at);
653 if(n == -1)
654 return false;
655 QString r = str.mid(at, n - at);
656 QString v = str.mid(n + 1);
657
658 if(v.left(5) != "RTSP/")
659 return false;
660
661 HeaderList headers;
662 if(!readHeaders(lines, &headers))
663 return false;
664
665 tmp.cmd = c;
666 tmp.res = r;
667 tmp.ver = v.mid(5);
668 tmp._headers = headers;
669 return true;
670 }
671 else
672 {
673 if(lines.isEmpty())
674 return false;
675 QString str = lines[0];
676 int n = str.find(' ');
677 if(n == -1)
678 return false;
679 QString v = str.mid(0, n);
680 int at = n + 1;
681 n = str.find(' ', at);
682 if(n == -1)
683 return false;
684 QString c = str.mid(at, n - at);
685 QString s = str.mid(n + 1);
686 if(v.left(5) != "RTSP/")
687 return false;
688
689 HeaderList headers;
690 if(!readHeaders(lines, &headers))
691 return false;
692
693 tmp.ver = v.mid(5);
694 tmp.rcode = c.toInt();
695 tmp.rstr = s;
696 tmp._headers = headers;
697 return true;
698 }
699}
700
701bool Parser::readHeaders(const QStringList &lines, HeaderList *headers)
702{
703 // skip the first line
704 QStringList::ConstIterator it = lines.begin();
705 ++it;
706
707 headers->clear();
708 for(; it != lines.end(); ++it)
709 {
710 const QString &s = *it;
711 int n = s.find(':');
712 if(n == -1)
713 return false;
714 Var v;
715 v.name = s.mid(0, n).stripWhiteSpace();
716 v.value = s.mid(n + 1).stripWhiteSpace();
717 headers->append(v);
718 }
719 return true;
720}
721
722QStringList Parser::readPacketLines()
723{
724 QStringList lines;
725 while(1)
726 {
727 QString str = tryReadLine();
728 if(str.isNull())
729 break;
730
731 if(str.isEmpty())
732 {
733 lines = cur;
734 cur.clear();
735 break;
736 }
737
738 cur.append(str);
739 }
740 return lines;
741}
742
743QString Parser::tryReadLine()
744{
745 for(int n = 0; n < (int)in.size(); ++n)
746 {
747 if(in[n] == '\n')
748 {
749 int eat = n + 1;
750 if(n > 0 && in[n-1] == '\r')
751 --n;
752 QByteArray buf = ByteStream::takeArray(&in, eat);
753 QCString cs;
754 cs.resize(n + 1);
755 memcpy(cs.data(), buf.data(), n);
756 return QString::fromUtf8(cs);
757 }
758 }
759 return QString::null;
760}
761
762//----------------------------------------------------------------------------
763// Client
764//----------------------------------------------------------------------------
765class Client::Private
766{
767public:
768 Private()
769 {
770 bs = 0;
771 using_sock = false;
772 conn = false;
773 active = false;
774 }
775
776 ByteStream *bs;
777 bool using_sock;
778 bool conn;
779 bool active;
780 Parser parser;
781 QValueList<int> trackQueue;
782};
783
784Client::Client(QObject *parent)
785:QObject(parent)
786{
787 d = new Private;
788}
789
790Client::Client(int socket)
791{
792 d = new Private;
793 d->using_sock = true;
794 BSocket *sock = new BSocket;
795 d->bs = sock;
796 d->conn = false;
797 hook();
798 d->parser.reset(Parser::Client); // as a server, we want to parse client requests
799 sock->setSocket(socket);
800}
801
802Client::~Client()
803{
804 delete d->bs;
805 delete d;
806}
807
808void Client::hook()
809{
810 connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed()));
811 connect(d->bs, SIGNAL(readyRead()), SLOT(bs_readyRead()));
812 connect(d->bs, SIGNAL(bytesWritten(int)), SLOT(bs_bytesWritten(int)));
813 connect(d->bs, SIGNAL(error(int)), SLOT(bs_error(int)));
814}
815
816void Client::processPackets()
817{
818 QGuardedPtr<QObject> self = this;
819 while(1)
820 {
821 bool ok;
822 Packet p = d->parser.read(&ok);
823 if(!ok)
824 {
825 delete d->bs;
826 d->bs = 0;
827 error(ErrParse);
828 return;
829 }
830
831 if(p.isNull())
832 break;
833
834 packetReady(p);
835 if(!self)
836 return;
837 }
838}
839
840void Client::connectToHost(const QString &host, int port)
841{
842 BSocket *sock = new BSocket;
843 connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
844 d->bs = sock;
845 d->conn = true;
846 hook();
847 sock->connectToHost(host, port);
848}
849
850void Client::setByteStream(ByteStream *bs, Mode mode)
851{
852 d->bs = bs;
853 d->conn = false;
854 hook();
855 d->parser.reset(mode == MClient ? Parser::Server : Parser::Client);
856}
857
858void Client::close()
859{
860 if(d->bs)
861 d->bs->close();
862}
863
864void Client::write(const Packet &p)
865{
866 QByteArray buf = p.toArray();
867 d->trackQueue.append(buf.size());
868 d->bs->write(buf);
869}
870
871QHostAddress Client::peerAddress() const
872{
873 QHostAddress addr;
874 if(d->using_sock)
875 addr = ((BSocket *)d->bs)->peerAddress();
876 return addr;
877}
878
879void Client::sock_connected()
880{
881 d->using_sock = true;
882 d->active = true;
883 d->parser.reset(Parser::Server); // as a client, we want to parse server responses
884 connected();
885}
886
887void Client::bs_connectionClosed()
888{
889 connectionClosed();
890}
891
892void Client::bs_readyRead()
893{
894 QByteArray buf = d->bs->read();
895 d->parser.appendData(buf);
896 if(d->active)
897 processPackets();
898}
899
900void Client::bs_bytesWritten(int bytes)
901{
902 int written = 0;
903 for(QValueList<int>::Iterator it = d->trackQueue.begin(); it != d->trackQueue.end();)
904 {
905 int &i = *it;
906
907 // enough bytes?
908 if(bytes < i) {
909 i -= bytes;
910 break;
911 }
912 bytes -= i;
913 it = d->trackQueue.remove(it);
914 ++written;
915 }
916
917 for(int n = 0; n < written; ++n)
918 packetWritten();
919}
920
921void Client::bs_error(int x)
922{
923 delete d->bs;
924 d->bs = 0;
925
926 if(d->conn)
927 {
928 if(x == BSocket::ErrConnectionRefused || x == BSocket::ErrHostNotFound)
929 {
930 error(ErrConnect);
931 return;
932 }
933 }
934
935 error(ErrStream);
936 return;
937}
938
939void Client::serve()
940{
941 d->active = true;
942 processPackets();
943}
944
945//----------------------------------------------------------------------------
946// Server
947//----------------------------------------------------------------------------
948class Server::Private
949{
950public:
951 Private() {}
952
953 ServSock serv;
954 QPtrList<Client> incomingConns;
955};
956
957Server::Server(QObject *parent)
958:QObject(parent)
959{
960 d = new Private;
961 connect(&d->serv, SIGNAL(connectionReady(int)), SLOT(connectionReady(int)));
962}
963
964Server::~Server()
965{
966 d->incomingConns.setAutoDelete(true);
967 d->incomingConns.clear();
968 delete d;
969}
970
971bool Server::isActive() const
972{
973 return d->serv.isActive();
974}
975
976bool Server::start(int port)
977{
978 return d->serv.listen(port);
979}
980
981void Server::stop()
982{
983 d->serv.stop();
984}
985
986int Server::port() const
987{
988 return d->serv.port();
989}
990
991QHostAddress Server::address() const
992{
993 return d->serv.address();
994}
995
996Client *Server::takeIncoming()
997{
998 if(d->incomingConns.isEmpty())
999 return 0;
1000
1001 Client *c = d->incomingConns.getFirst();
1002 d->incomingConns.removeRef(c);
1003
1004 // we don't care about errors anymore
1005 disconnect(c, SIGNAL(error(int)), this, SLOT(connectionError()));
1006
1007 // don't serve the connection until the event loop, to give the caller a chance to map signals
1008 QTimer::singleShot(0, c, SLOT(serve()));
1009
1010 return c;
1011}
1012
1013void Server::connectionReady(int s)
1014{
1015 Client *c = new Client(s);
1016 connect(c, SIGNAL(error(int)), this, SLOT(connectionError()));
1017 d->incomingConns.append(c);
1018 incomingReady();
1019}
1020
1021void Server::connectionError()
1022{
1023 Client *c = (Client *)sender();
1024 d->incomingConns.removeRef(c);
1025 c->deleteLater();
1026}
1027
1028}
Note: See TracBrowser for help on using the repository browser.