1 // Copyright (C) 2001-2015 Federico Montesino Pouzols <fedemp@altern.org>
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 //
17 // As a special exception, you may use this file as part of a free software
18 // library without restriction. Specifically, if other files instantiate
19 // templates or use macros or inline functions from this file, or you compile
20 // this file and link it with other files to produce an executable, this
21 // file does not by itself cause the resulting executable to be covered by
22 // the GNU General Public License. This exception does not however
23 // invalidate any other reasons why the executable file might be covered by
24 // the GNU General Public License.
25 //
26 // This exception applies only to the code released under the name GNU
27 // ccRTP. If you copy code from other releases into a copy of GNU
28 // ccRTP, as the General Public License permits, the exception does
29 // not apply to the code that you add in this way. To avoid misleading
30 // anyone as to the status of such modified files, you must delete
31 // this exception notice from them.
32 //
33 // If you write modifications of your own for GNU ccRTP, it is your choice
34 // whether to permit this exception to apply to your modifications.
35 // If you do not wish that, delete this exception notice.
36 //
37
40
41 NAMESPACE_COMMONCPP
42
44
47 networkAddress(na), dataTransportPort(dtp),
48 controlTransportPort(ctp), next(NULL)
49 {
51 }
52
55 {
59 result = result->
next;
60 return result;
61 }
62
65 {
67 while ( result &&
70 result = result->
next;
71 return result;
72 }
73
74 void
76 {
79
83 } else {
85 }
86 }
87
93
96 {
102 }
103
104 void
106 {
108 // flush the reception queue (incoming packets not yet
109 // retrieved)
112 {
114
115 // nullify source specific packet list
119
123 }
125 }
126
127 void
129 {
130 const uint32 MAXTRIES = 20;
131 uint32 newssrc;
132 uint16 tries = 0;
133 do {
135 tries++;
136 }
while ( (tries < MAXTRIES) &&
isRegistered(newssrc) );
137
138 if ( MAXTRIES == tries ) {
139 // TODO we are in real trouble.
140 }
141 }
142
143 bool
145 {
146 bool w;
148 if ( NULL == src )
150 else
152
154 return w;
155 }
156
157 uint32
159 {
161
162 // get the first packet
164 if ( NULL == src )
166 else
168
169 // get the timestamp of the first packet
170 uint32 ts;
171 if ( packetLink )
173 else
174 ts = 0l;
175
177 return ts;
178 }
179
180 size_t
182 {
183 InetHostAddress network_address;
184 tpport_t transport_port;
185
187 unsigned char* buffer = new unsigned char[nextSize];
188 int32 rtn = (int32)
recvData(buffer,nextSize,network_address,transport_port);
190 delete [] buffer;
191 return 0;
192 }
193
194 // get time of arrival
195 struct timeval recvtime;
196 SysTime::gettimeofday(&recvtime,NULL);
197
198 // Special handling of padding to take care of encrypted content.
199 // In case of SRTP the padding length field is also encrypted, thus
200 // it gives a wrong length. Check and clear padding bit before
201 // creating the RTPPacket. Will be set and re-computed after a possible
202 // SRTP decryption.
203 uint8 padSet = (*buffer & 0x20);
204 if (padSet) {
205 *buffer = *buffer & ~0x20; // clear padding bit
206 }
207 // build a packet. It will link itself to its source
210
211 // Generic header validity check.
213 delete packet;
214 return 0;
215 }
216
218 if (pcc == NULL) {
220 if (pcc != NULL) {
222 if (pcc != NULL) {
225 }
226 }
227 }
228 if (pcc != NULL) {
230 if (ret < 0) {
232 delete packet;
233 return 0;
234 }
235 }
236 }
237 if (padSet) {
239 }
240 // virtual for profile-specific validation and processing.
242 delete packet;
243 return 0;
244 }
245
246 bool source_created;
250 if ( source_created ) {
251 // Set data transport address.
253 // Network address is assumed to be the same as the control one
256 // Keep first sequence number for stats
258 // First packet arrival time.
263 } else if ( 0 == s->getDataTransportPort() ) {
264 // Test if RTCP packets had been received but this is the
265 // first data packet from this source.
267 }
268
269 // Before inserting in the queue,
270 // 1) check for collisions and loops. If the packet cannot be
271 // assigned to a source, it will be rejected.
272 // 2) check the source is a sufficiently well known source
273 // TODO: also check CSRC identifiers.
275 network_address,transport_port) &&
277 // now the packet link is linked in the queues
280 sourceLink,
281 recvtime,
284 NULL,NULL,NULL,NULL);
286 } else {
287 // must be discarded due to collision or loop or
288 // invalid source
289 delete packet;
290 }
291
292 // ccRTP keeps packets from the new source, but avoids
293 // flip-flopping. This allows losing less packets and for
294 // mobile telephony applications or other apps that may change
295 // the source transport address during the session.
296 return rtn;
297 }
298
300 bool is_new, InetAddress& network_address, tpport_t transport_port)
301 {
302 bool result = true;
303
304 // Test if the source is new and it is not the local one.
305 if ( is_new &&
307 return result;
308
310
313 // SSRC collision or a loop has happened
315 // TODO: Optional error counter.
316
317 // Note this differs from the default in the RFC.
318 // Discard packet only when the collision is
319 // repeating (to avoid flip-flopping)
321 (
322 (network_address ==
324 &&
325 (transport_port ==
327 ) ) {
328 // discard packet and do not flip-flop
329 result = false;
330 } else {
331 // Record who has collided so that in
332 // the future we can how if the
333 // collision repeats.
335 transport_port,0);
336 // Change sync source transport address
339 }
340
341 } else {
342 // Collision or loop of own packets.
345 transport_port);
346 if ( conflicting ) {
347 // Optional error counter.
349 result = false;
350 } else {
351 // New collision
355 dispatchBYE(
"SSRC collision detected when receiving data packet.");
362 }
363 }
364 }
365 return result;
366 }
367
368 bool
370 {
375 if ( plink && (seq < plink->getPacket()->getSeqNum()) ) {
376 // a disordered packet, so look for its place
377 while ( plink && (seq < plink->getPacket()->getSeqNum()) ){
378 // the packet is a duplicate
381 VDL((
"Duplicated disordered packet: seqnum %d, SSRC:",
384 delete packetLink;
385 return false;
386 }
388 }
389 if ( !plink ) {
390 // we have scanned the whole (and non empty)
391 // list, so this must be the older (first)
392 // packet from this source.
393
394 // insert into the source specific queue
398 // insert into the global queue
400 if ( prevFirst ){
401 prevFirst->
setNext(packetLink);
402 packetLink->
setPrev(prevFirst);
403 }
407 } else {
408 // (we are in the middle of the source list)
409 // insert into the source specific queue
412 // -- insert into the global queue, with the
413 // minimum priority compared to packets from
414 // other sources
419 // ------
422 // insert into the global queue (giving
423 // priority compared to packets from other sources)
424 //list->getNext->setPrev(packetLink);
425 //packetLink->setNext(list->getNext);
426 //list->setNext(packet);
427 //packet->setPrev(list);
428 }
429 } else {
430 // An ordered packet
431 if ( !plink ) {
432 // the only packet in the source specific queue
435 // the last packet in the global queue
439 }
443 } else {
444 // there are already more packets from this source.
445 // this ignores duplicate packets
447 VDL((
"Duplicated packet: seqnum %d, SSRC:",
451 delete packetLink;
452 return false;
453 }
454 // the last packet in the source specific queue
458 // the last packet in the global queue
462 }
463 }
464 // account the insertion of this packet into the queue
467 // packet successfully inserted
468 return true;
469 }
470
473 {
475 // unsigned count = 0;
477
480 // size_t len = packet->getPayloadSize();
481
484
485 // delete the packet link, but not the packet
486 delete pl;
487 // count += len;
488 } else {
489 result = NULL;
490 }
491 return result;
492 }
493
494 // FIX: try to merge and organize
497 {
498 if ( src && !
isMine(*src) )
499 return NULL;
500
503 if ( src != NULL ) {
504 // process source specific queries:
505 // we will modify the queue of this source
507
508 // first, delete all older packets. The while loop
509 // down here counts how many older packets are there;
510 // then the for loop deletes them and advances l till
511 // the first non older packet.
512 int nold = 0;
514 if ( !l ) {
515 result = NULL;
517 return result;
518 }
521 nold++;
523 }
524 // to know whether the global queue gets empty
525 bool nonempty = false;
526 for ( int i = 0; i < nold; i++) {
529 // unlink from the global queue
530 nonempty = false;
532 nonempty = true;
535 nonempty = true;
537 }
538 // now, delete it
541 delete l;
542 }
543 // return the packet, if found
545 // threre are no more packets from this source
547 if ( !nonempty )
549 result = NULL;
551 // threre are only newer packets from this source
553 result = NULL;
554 } else {
555 // (src->getFirst()->getTimestamp() == stamp) is true
557 // unlink the selected packet from the global queue
560 else
564 else
566 // unlink the selected packet from the source queue
570 else
572 }
573 } else {
574 // process source unspecific queries
575 int nold = 0;
579 nold++;
581 }
582 for (int i = 0; i < nold; i++) {
585 // unlink the packet from the queue of its source
590 else
592 // now, delete it
595 delete l;
596 }
597
598 // return the packet, if found
600 // there are no more packets in the queue
602 result = NULL;
604 // there are only newer packets in the queue
605 if (l)
607 result = NULL;
608 } else {
609 // (recvFirst->getTimestamp() == stamp) is true
611 // unlink the selected packet from the global queue
615 else
617 // unlink the selected packet from the queue
618 // of its source
623 else
625 }
626 }
628 return result;
629 }
630
631 bool
634 {
635 bool result = true;
636
637 // Source validation.
640 // source is not yet valid.
642 // packet in sequence.
645 // source has become valid.
646 // TODO: avoid this the first time.
648 } else {
649 result = false;
650 }
651 } else {
652 // packet not in sequence.
654 result = false;
655 }
657 } else {
658 // source was already valid.
661 // Ordered, with not too high step.
663 // sequene number wrapped.
665 }
668 // too high step of the sequence number.
671 } else {
674 //This additional check avoids that
675 //the very first packet from a source
676 //be discarded.
678 result = false;
679 } else {
681 }
682 }
683 } else {
684 // duplicate or reordered packet
685 }
686 }
687
688 if ( result ) {
689 // the packet is considered valid.
694 // ooops, it's the first packet from this source
697 }
698 // we record the last time a packet from this source
699 // was received, this has statistical interest and is
700 // needed to time out old senders that are no sending
701 // any longer.
702
703 // compute the interarrival jitter estimation.
704 timeval tarrival;
707 timersub(&lastT,&initial,&tarrival);
711 int32 delta = transitTime -
714 if ( delta < 0 )
715 delta = -delta;
717 (1.0f / 16.0f) *
718 (static_cast<float>(delta) -
720 }
721 return result;
722 }
723
724 void
726 {}
727
728 void
730 {
731 std::list<CryptoContext *>::iterator i;
732
734 // check if a CryptoContext for a SSRC already exists. If yes
735 // remove it from list before inserting the new one.
737 if( (*i)->getSsrc() == cc->
getSsrc() ) {
740 delete tmp;
741 break;
742 }
743 }
745 }
746
747 void
749 {
750 std::list<CryptoContext *>::iterator i;
751
753 if (cc == NULL) { // Remove any incoming crypto contexts
757 delete tmp;
758 }
759 }
760 else {
762 if( (*i)->getSsrc() == cc->
getSsrc() ) {
765 delete tmp;
766 return;
767 }
768 }
769 }
770 }
771
774 {
775 std::list<CryptoContext *>::iterator i;
776
779 if( (*i)->getSsrc() == ssrc) {
780 return (*i);
781 }
782 }
783 return NULL;
784 }
785
786 END_NAMESPACE
787
void setFirst(IncomingRTPPktLink *fp)
virtual bool onRTPPacketRecv(IncomingRTPPkt &)
A virtual function to support parsing of arriving packets to determine if they should be kept in the ...
ConflictingTransportAddress * next
static const uint16 defaultMaxPacketDropout
IncomingDataQueue::IncomingRTPPktLink * getWaiting(uint32 timestamp, const SyncSource *src=NULL)
This is used to fetch a packet in the receive queue and to expire packets older than the current time...
static const uint32 SEQNUMMOD
void setBaseSeqNum(uint16 seqnum)
ConflictingTransportAddress * searchDataConflict(InetAddress na, tpport_t dtp)
virtual size_t dispatchBYE(const std::string &)
A plugin point for posting of BYE messages.
tpport_t getDataTransportPort() const
Synchronization source in an RTP session.
void incObservedPacketCount()
IncomingRTPPkt * getPacket() const
Interface (envelope) to data received over RTP packets.
The implementation for a SRTP cryptographic context.
void setSender(SyncSource &source, bool active)
ConflictingTransportAddress * getPrevConflict() const
void setPrevConflict(InetAddress &addr, tpport_t dataPort, tpport_t controlPort)
Get conflicting address.
void reComputePayLength(bool padding)
Re-compute payload length.
void setProbation(uint8 p)
RTP packets received from other participants.
void recordExtraction(const IncomingRTPPkt &pkt)
Log extraction of a packet from this source from the scheduled reception queue.
uint32 getInitialDataTimestamp() const
static const size_t defaultMembersSize
virtual bool end2EndDelayed(IncomingRTPPktLink &)
bool isRegistered(uint32 ssrc)
Returns whether there is already a synchronizacion source with "ssrc" SSRC identifier.
void setNext(IncomingRTPPktLink *nl)
microtimeout_t timeval2microtimeout(const timeval &t)
Convert a time interval, expressed as a timeval value into a microseconds counter.
virtual size_t recvData(unsigned char *buffer, size_t length, InetHostAddress &host, tpport_t &port)=0
This function performs the physical I/O for reading a packet from the source.
bool checkSSRCInIncomingRTPPkt(SyncSourceLink &sourceLink, bool is_new, InetAddress &na, tpport_t tp)
Apply collision and loop detection and correction algorithm when receiving RTP data packets...
virtual void onNewSyncSource(const SyncSource &)
Virtual called when a new synchronization source has joined the session.
uint8 minValidPacketSequence
size_t getMaxRecvPacketSize() const
uint8 getMinValidPacketSequence() const
Get the minimun number of consecutive packets that must be received from a source before accepting it...
uint32 getSSRC() const
Get synchronization source numeric identifier.
tpport_t controlTransportPort
uint32 getObservedPacketCount() const
Get the total number of RTP packets received from this source.
void incObservedOctetCount(uint32 n)
Declaration of ccRTP internal stuff.
IncomingRTPPktLink * getLast()
Get last RTP (data) packet in the queue of packets received from this socket.
uint16 getMaxPacketMisorder() const
int32 unprotect(CryptoContext *pcc)
Unprotect a received packet.
static const uint16 defaultMaxPacketMisorder
Synchronization Source internal handler within the incoming packets queue.
uint16 getDefaultMaxPacketMisorder() const
IncomingRTPPktLink * getPrev() const
SyncSource * getSource()
Get the synchronization source object this link objet holds information for.
IncomingRTPPktLink * getNext() const
uint32 getTimestamp() const
bool isHeaderValid()
Get validity of this packet.
uint8 sourceExpirationPeriod
uint32 getLastPacketTransitTime()
IncomingRTPPktLink * getSrcNext() const
void setNext(ConflictingTransportAddress *nc)
IncomingDataQueue(uint32 size)
static const size_t defaultMaxRecvPacketSize
Generic RTP input queues.
void setNetworkAddress(SyncSource &source, InetAddress addr)
CryptoContext * newCryptoContextForSSRC(uint32 ssrc, int roc, int64 keyDerivRate)
Derive a new Crypto Context for use with a new SSRC.
bool isWaiting(const SyncSource *src=NULL) const
Determine if packets are waiting in the reception queue.
IncomingRTPPktLink * getFirst()
Get first RTP (data) packet in the queue of packets received from this socket.
bool isMine(const SyncSource &source) const
Get whether a synchronization source is recorded in this membership controller.
bool recordReception(SyncSourceLink &srcLink, const IncomingRTPPkt &pkt, const timeval recvtime)
Log reception of a new RTP packet from this source.
static const size_t defaultMembersHashSize
CryptoContext * getInQueueCryptoContext(uint32 ssrc)
Get an input queue CryptoContext identified by SSRC.
void setDataTransportPort(SyncSource &source, tpport_t p)
bool insertRecvPacket(IncomingRTPPktLink *packetLink)
Insert a just received packet in the queue (both general and source specific queues).
IncomingRTPPktLink * getSrcPrev() const
const AppDataUnit * getData(uint32 stamp, const SyncSource *src=NULL)
Retreive data from a specific timestamped packet if such a packet is currently available in the recei...
void recordInsertion(const IncomingRTPPktLink &pl)
Record the insertion of an RTP packet from this source into the scheduled reception queue...
const InetAddress & getNetworkAddress() const
SyncSourceLink * getSourceLink() const
IncomingRTPPktLink * recvFirst
void setInitialDataTimestamp(uint32 ts)
tpport_t getControlTransportPort() const
SyncSourceLink * getSourceBySSRC(uint32 ssrc, bool &created)
Get the description of a source by its ssrc identifier.
timeval getInitialDataTime() const
uint32 getBadSeqNum() const
InetAddress networkAddress
virtual size_t takeInDataPacket()
This function is used by the service thread to process the next incoming packet and place it in the r...
void purgeIncomingQueue()
static const uint8 defaultMinValidPacketSequence
uint32 getPayloadSize() const
uint32 getLocalSSRC() const
uint16 getMaxPacketDropout() const
void setBadSeqNum(uint32 seq)
void setSrcPrev(IncomingRTPPktLink *sp)
uint16 getDefaultMaxPacketDropout() const
void deriveSrtpKeys(uint64 index)
Perform key derivation according to SRTP specification.
uint32 getSsrc() const
Get the SSRC of this SRTP Cryptograhic context.
Controls the group membership in the current session.
void setSrcNext(IncomingRTPPktLink *sn)
IncomingRTPPktLink * recvLast
ConflictingTransportAddress * lastConflict
uint32 getCurrentRTPClockRate() const
Get the clock rate in RTP clock units (for instance, 8000 units per second for PCMU, or 90000 units per second for MP2T).
tpport_t dataTransportPort
ConflictingTransportAddress(InetAddress na, tpport_t dtp, tpport_t ctp)
uint32 getFirstTimestamp(const SyncSource *src=NULL) const
Get timestamp of first packet waiting in the queue.
virtual void onExpireRecv(IncomingRTPPkt &)
A hook to filter packets in the receive queue that are being expired.
void addConflict(const InetAddress &na, tpport_t dtp, tpport_t ctp)
uint16 getMaxSeqNum() const
Get the highest valid sequence number received.
void setMaxSeqNum(uint16 max)
Set the highest valid sequence number recived.
SyncSourceLink * getLink(const SyncSource &source) const
void initSequence(uint16 seqnum)
Start a new sequence of received packets.
void setPrev(IncomingRTPPktLink *pl)
Incoming RTP data packets control structure within the incoming packet queue class.
virtual bool onSRTPPacketError(IncomingRTPPkt &pkt, int32 errorCode)
A hook that gets called if the decoding of an incoming SRTP was erroneous.
timeval getLastPacketTime() const
void updateConflict(ConflictingTransportAddress &ca)
uint8 getDefaultMinValidPacketSequence() const
void setLast(IncomingRTPPktLink *lp)
void removeInQueueCryptoContext(CryptoContext *cc)
Remove input queue CryptoContext.
virtual size_t getNextDataPacketSize() const =0
uint32 getTimestamp() const
Get timestamp of this packet.
std::list< CryptoContext * > cryptoContexts
void setLastPacketTransitTime(uint32 time)
ConflictingTransportAddress * firstConflict
ConflictingTransportAddress * searchControlConflict(InetAddress na, tpport_t ctp)
bool getHello()
Mark this source as having sent some packet.
void setInQueueCryptoContext(CryptoContext *cc)
Set input queue CryptoContext.
void setInitialDataTime(timeval it)
void setControlTransportPort(SyncSource &source, tpport_t p)