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
46 {
47 // segment data in packets of no more than 65536 octets.
49 }
50
52 destList(), destinationLock()
53 {}
54
56 {
59 for (std::list<TransportAddress*>::iterator i =
destList.begin();
61 tmp = *i;
62 #ifdef CCXX_EXCEPTIONS
63 try {
64 #endif
65 delete tmp;
66 #ifdef CCXX_EXCEPTIONS
67 } catch (...) {}
68 #endif
69 }
71 }
72
73 bool
75 tpport_t data, tpport_t control)
76 {
81 return true;
82 }
83
84 bool
86 tpport_t dataPort, tpport_t controlPort)
87 {
88 bool result = false;
91 for (std::list<TransportAddress*>::iterator i =
destList.begin();
93 tmp = *i;
97 // matches. -> remove it.
98 result = true;
100 delete tmp;
101 } else{
102 i++;
103 }
104 }
106 return result;
107 }
108
109 #ifdef CCXX_IPV6
110
111 DestinationListHandlerIPV6::DestinationListHandlerIPV6() :
112 destListIPV6(), destinationLock()
113 {}
114
115 DestinationListHandlerIPV6::~DestinationListHandlerIPV6()
116 {
117 TransportAddressIPV6* tmp = NULL;
118 writeLockDestinationListIPV6();
119 for (std::list<TransportAddressIPV6*>::iterator i = destListIPV6.begin();
120 destListIPV6.end() != i; i++) {
121 tmp = *i;
122 #ifdef CCXX_EXCEPTIONS
123 try {
124 #endif
125 delete tmp;
126 #ifdef CCXX_EXCEPTIONS
127 } catch (...) {}
128 #endif
129 }
130 unlockDestinationListIPV6();
131 }
132
133 bool
134 DestinationListHandlerIPV6::addDestinationToListIPV6(const IPV6Address& ia,
135 tpport_t data, tpport_t control)
136 {
137 TransportAddressIPV6* addr = new TransportAddressIPV6(ia,data,control);
138 writeLockDestinationListIPV6();
139 destListIPV6.push_back(addr);
140 unlockDestinationListIPV6();
141 return true;
142 }
143
144 bool
145 DestinationListHandlerIPV6::removeDestinationFromListIPV6(const IPV6Address& ia,
146 tpport_t dataPort, tpport_t controlPort)
147 {
148 bool result = false;
149 writeLockDestinationListIPV6();
150 TransportAddressIPV6* tmp;
151 for (std::list<TransportAddressIPV6*>::iterator i = destListIPV6.begin();
152 destListIPV6.end() != i && !result; ) {
153 tmp = *i;
154 if ( ia == tmp->getNetworkAddress() &&
155 dataPort == tmp->getDataTransportPort() &&
156 controlPort == tmp->getControlTransportPort() ) {
157 // matches. -> remove it.
158 result = true;
159 destListIPV6.erase(i);
160 delete tmp;
161 } else {
162 i++;
163 }
164 }
165 unlockDestinationListIPV6();
166 return result;
167 }
168
169
170 #endif
171
176
179 #ifdef CCXX_IPV6
180 DestinationListHandlerIPV6(),
181 #endif
183 {
187
191 sendInfo.sendCC = 0;
// initially, 0 CSRC identifiers follow the fixed heade
192 sendInfo.paddinglen = 0;
// do not add padding bits.
195 // the local source is the first contributing source
197 // this will be an accumulator for the successive cycles of timestamp
200 }
201
202 void
204 {
206 // flush the sending queue (delete outgoing packets
207 // unsent so far)
213 }
216 }
217
218 bool
220 tpport_t dataPort, tpport_t controlPort)
221 {
222 if ( 0 == controlPort )
223 controlPort = dataPort + 1;
228 }
229 return result;
230 }
231
232 bool
234 tpport_t dataPort, tpport_t controlPort)
235 {
236 if ( 0 == controlPort )
237 controlPort = dataPort + 1;
242 }
243 return result;
244 }
245
246 bool
248 tpport_t dataPort, tpport_t controlPort)
249 {
250 if ( 0 == controlPort )
251 controlPort = dataPort + 1;
254 }
255
256 bool
258 tpport_t dataPort, tpport_t controlPort)
259 {
260 if ( 0 == controlPort )
261 controlPort = dataPort + 1;
264 }
265
266 #ifdef CCXX_IPV6
267 bool
269 tpport_t dataPort, tpport_t controlPort)
270 {
271 if ( 0 == controlPort )
272 controlPort = dataPort + 1;
273 bool result = addDestinationToListIPV6(ia,dataPort,controlPort);
274 if ( result && isSingleDestinationIPV6() ) {
275 setDataPeerIPV6(ia,dataPort);
276 setControlPeerIPV6(ia,controlPort);
277 }
278 return result;
279 }
280
281 bool
283 tpport_t dataPort, tpport_t controlPort)
284 {
285 if ( 0 == controlPort )
286 controlPort = dataPort + 1;
287 return DestinationListHandlerIPV6::
288 removeDestinationFromListIPV6(ia,dataPort,controlPort);
289 }
290
291 #endif
292
293 bool
295 {
297 return true;
298
299 return false;
300 }
301
304 {
305 struct timeval send, now;
306 uint32 rate;
307 uint32 rem;
308
309 for(;;) {
310 // if there is no packet to send, use the default scheduling
311 // timeout
314
318
319 // now we want to get in <code>send</code> _when_ the
320 // packet is scheduled to be sent.
321
322 // translate timestamp to timeval
323 send.tv_sec = stamp / rate;
324 rem = stamp % rate;
325 send.tv_usec = (1000ul*rem) / (rate/1000ul); // 10^6 * rem/rate
326
327 // add timevals. Overflow holds the inital time
328 // plus the time accumulated through successive
329 // overflows of timestamp. See below.
330 timeradd(&send,&(
sendInfo.overflowTime),&send);
331 SysTime::gettimeofday(&now, NULL);
332
333 // Problem: when timestamp overflows, time goes back.
334 // We MUST ensure that _send_ is not too lower than
335 // _now_, otherwise, we MUST keep how many time was
336 // lost because of overflow. We assume that _send_
337 // 5000 seconds lower than now suggests timestamp
338 // overflow. (Remember than the 32 bits of the
339 // timestamp field are 47722 seconds under a sampling
340 // clock of 90000 hz.) This is not a perfect
341 // solution. Disorderedly timestamped packets coming
342 // after an overflowed one will be wrongly
343 // corrected. Nevertheless, this may only corrupt a
344 // handful of those packets every more than 13 hours
345 // (if timestamp started from 0).
346 if ( now.tv_sec - send.tv_sec > 5000) {
347 timeval overflow;
348 overflow.tv_sec =(~static_cast<uint32>(0)) / rate;
349 overflow.tv_usec = (~static_cast<uint32>(0)) % rate *
350 1000000ul / rate;
351 do {
352 timeradd(&send,&overflow,&send);
353 timeradd(&(
sendInfo.overflowTime),&overflow,
355 } while ( now.tv_sec - send.tv_sec > 5000 );
356 }
357
358 // This tries to solve the aforementioned problem
359 // about disordered packets coming after an overflowed
360 // one. Now we apply the reverse idea.
361 if ( send.tv_sec - now.tv_sec > 20000 ) {
362 timeval overflow;
363 overflow.tv_sec = (~static_cast<uint32>(0)) / rate;
364 overflow.tv_usec = (~static_cast<uint32>(0)) % rate *
365 1000000ul / rate;
366 timersub(&send,&overflow,&send);
367 }
368
369 // A: This sets a maximum timeout of 1 hour.
370 if ( send.tv_sec - now.tv_sec > 3600 ) {
371 return 3600000000ul;
372 }
373 int32 diff =
374 ((send.tv_sec - now.tv_sec) * 1000000ul) +
375 send.tv_usec - now.tv_usec;
376 // B: wait <code>diff</code> usecs more before sending
377 if ( diff >= 0 ) {
379 }
380
381 // C: the packet must be sent right now
382 if ( (diff < 0) &&
384 return 0;
385 }
386
387 // D: the packet has expired -> delete it.
392 delete packet;
395 else
398 }
400 return 0;
401 }
402
403 void
405 {
406 if ( !data || !datalen )
407 return;
408
409 size_t step = 0, offset = 0;
410 while ( offset < datalen ) {
411 // remainder and step take care of segmentation
412 // according to getMaxSendSegmentSize()
413 size_t remainder = datalen - offset;
416
418 if (pcc == NULL) {
420 if (pcc != NULL) {
422 if (pcc != NULL) {
425 }
426 }
427 }
431 else
433
437
439 if ( (0 == offset) &&
getMark() ) {
442 } else {
444 }
445 if (pcc != NULL) {
447 }
448 // insert the packet into the "tail" of the sending queue
454 else
458
459 offset += step;
460 }
461 }
462
463 void
465 {
466 if ( !data || !datalen )
467 return;
468
469 size_t step = 0, offset = 0;
470 while ( offset < datalen ) {
471 // remainder and step take care of segmentation
472 // according to getMaxSendSegmentSize()
473 size_t remainder = datalen - offset;
476
478
482 else
484
489
490 if ( (0 == offset) &&
getMark() ) {
493 } else {
495 }
496 if (pcc != NULL) {
498 }
500 delete packet;
501 offset += step;
502 }
503 }
504
506 {
510 // if going from multi destinations to single destinations.
512
514 } else {
515 // when no destination has been added, NULL == dest.
516 for (std::list<TransportAddress*>::iterator i =
destList.begin();
destList.end() != i; i++) {
520 }
521 }
523
524 #ifdef CCXX_IPV6
525 lockDestinationListIPV6();
526 if ( isSingleDestinationIPV6() ) {
527 TransportAddressIPV6* tmp6 = destListIPV6.front();
528 // if going from multi destinations to single destinations.
529 setDataPeerIPV6(tmp6->getNetworkAddress(),
530 tmp6->getDataTransportPort());
531
534 } else {
535 // when no destination has been added, NULL == dest.
536 for (std::list<TransportAddressIPV6*>::iterator i6 = destListIPV6.begin(); destListIPV6.end() != i6; i6++) {
537 TransportAddressIPV6* dest6 = *i6;
538 setDataPeerIPV6(dest6->getNetworkAddress(),
539 dest6->getDataTransportPort());
542 }
543 }
544 unlockDestinationListIPV6();
545 #endif
546 }
547
548 size_t
550 {
553
554 if ( !packetLink ){
556 return 0;
557 }
558
562
563 // unlink the sent packet from the queue and destroy it. Also
564 // record the sending.
568 } else {
570 }
571 // for general accounting and RTCP SR statistics
574 delete packetLink;
575
577 return rtn;
578 }
579
580 size_t
582 size_t offset, size_t max)
583 {
586 while ( packetLink )
587 {
589 if ( pstamp > stamp ) {
590 packetLink = NULL;
591 break;
592 } else if ( pstamp == stamp ) {
593 break;
594 }
595
596 packetLink = packetLink->
getNext();
597 }
598 if ( !packetLink ) {
600 return 0;
601 }
602
605 return 0;
606
609
610 memcpy((
unsigned char*)(packet->
getPayload()) + offset,
611 data, max);
613 return max;
614 }
615
616 void
618 {
619 std::list<CryptoContext *>::iterator i;
620
622 // check if a CryptoContext for a SSRC already exists. If yes
623 // remove it from list before inserting the new one.
625 if( (*i)->getSsrc() == cc->
getSsrc() ) {
628 delete tmp;
629 break;
630 }
631 }
633 }
634
635 void
637 {
638 std::list<CryptoContext *>::iterator i;
639
641 if (cc == NULL) { // Remove any incoming crypto contexts
645 delete tmp;
646 }
647 }
648 else {
650 if( (*i)->getSsrc() == cc->
getSsrc() ) {
653 delete tmp;
654 return;
655 }
656 }
657 }
658 }
659
662 {
663 std::list<CryptoContext *>::iterator i;
664
667 if( (*i)->getSsrc() == ssrc) {
668 return (*i);
669 }
670 }
671 return NULL;
672 }
673
674 END_NAMESPACE
675
void setPrev(OutgoingRTPPktLink *p)
microtimeout_t getSchedulingTimeout()
This computes the timeout period for scheduling transmission of the next packet at the "head" of the ...
void setMarker(bool mark)
Specify the value of the marker bit.
void setMark(bool mark)
Set marker bit for the packet in which the next data provided will be send.
CryptoContext * getOutQueueCryptoContext(uint32 ssrc)
Get an output queue CryptoContext identified by SSRC.
virtual size_t sendData(const unsigned char *const buffer, size_t len)
This function performs the physical I/O for writing a packet to the destination.
void setSchedulingTimeout(microtimeout_t to)
Set the default scheduling timeout to use when no data packets are waiting to be sent.
void setNext(OutgoingRTPPktLink *n)
bool getMark() const
Get wheter the mark bit will be set in the next packet.
The implementation for a SRTP cryptographic context.
void writeLockDestinationList() const
uint32 microtimeout_t
Time interval expressed in microseconds.
void setOutQueueCryptoContext(CryptoContext *cc)
Set ouput queue CryptoContext.
std::list< TransportAddress * > destList
size_t getDefaultMaxSendSegmentSize()
OutgoingRTPPkt * getPacket()
void putData(uint32 stamp, const unsigned char *data=NULL, size_t len=0)
This is used to create a data packet in the send queue.
This class handles a list of destination addresses.
PayloadType getCurrentPayloadType() const
timeval getInitialTime() const
void lockDestinationList() const
void setSeqNum(uint16 seq)
Sets the sequence number in the header.
size_t setPartial(uint32 timestamp, unsigned char *data, size_t offset, size_t max)
Set partial data for an already queued packet.
Declaration of ccRTP internal stuff.
size_t dispatchDataPacket()
This function is used by the service thread to process the next outgoing packet pending in the sendin...
microtimeout_t getDefaultExpireTimeout() const
void dispatchImmediate(OutgoingRTPPkt *packet)
This is used to write the RTP data packet to one or more destinations.
void setSSRCNetwork(uint32 ssrc) const
Set synchronization source numeric identifier.
std::list< CryptoContext * > cryptoContexts
bool isSending() const
Determine if outgoing packets are waiting to send.
uint32 getInitialTimestamp()
virtual void onExpireSend(OutgoingRTPPkt &)
A hook to filter packets being sent that have been expired.
uint32 getTimestamp() const
bool addDestinationToList(const InetAddress &ia, tpport_t data, tpport_t control)
Locks the object before modifying it.
const uint8 *const getPayload() const
bool removeDestinationFromList(const InetAddress &ia, tpport_t dataPort, tpport_t controlPort)
Locks the object before modifying it.
bool forgetDestination(const InetHostAddress &ia, tpport_t dataPort=DefaultRTPDataPort, tpport_t controlPort=0)
Generic RTP output queues.
CryptoContext * newCryptoContextForSSRC(uint32 ssrc, int roc, int64 keyDerivRate)
Derive a new Crypto Context for use with a new SSRC.
OutgoingRTPPktLink * sendLast
~DestinationListHandler()
void purgeOutgoingQueue()
struct OutgoingDataQueue::@4 sendInfo
microtimeout_t getDefaultSchedulingTimeout() const
void setMaxSendSegmentSize(size_t size)
Set maximum payload segment size before fragmenting sends.
virtual void setControlPeer(const InetAddress &host, tpport_t port)
static const microtimeout_t defaultSchedulingTimeout
Schedule at 8 ms.
const unsigned char *const getRawPacket() const
Get the raw packet as it will be sent through the network.
size_t getMaxSendSegmentSize()
microtimeout_t schedulingTimeout
void setInitialTimestamp(uint32 ts)
uint32 getLocalSSRCNetwork() const
tpport_t getControlTransportPort() const
const InetAddress & getNetworkAddress() const
void removeOutQueueCryptoContext(CryptoContext *cc)
Remove output queue CryptoContext.
tpport_t getDataTransportPort() const
uint32 getPayloadSize() const
bool addDestination(const InetHostAddress &ia, tpport_t dataPort=DefaultRTPDataPort, tpport_t controlPort=0)
uint32 getLocalSSRC() const
void setTimestamp(uint32 pts)
void setPayloadType(PayloadType pt)
void deriveSrtpKeys(uint64 index)
Perform key derivation according to SRTP specification.
uint32 getSsrc() const
Get the SSRC of this SRTP Cryptograhic context.
OutgoingRTPPktLink * sendFirst
static const microtimeout_t defaultExpireTimeout
Packets unsent will expire after 40 ms.
uint32 getRawPacketSizeSrtp() const
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).
void sendImmediate(uint32 stamp, const unsigned char *data=NULL, size_t len=0)
This is used to create a data packet and send it immediately.
void setExpireTimeout(microtimeout_t to)
Set the "expired" timer for expiring packets pending in the send queue which have gone unsent and are...
void protect(uint32 ssrc, CryptoContext *pcc)
Called packet is setup.
virtual void setDataPeer(const InetAddress &host, tpport_t port)
bool isSingleDestination() const
Get whether there is only a destination in the list.
static const size_t defaultMaxSendSegmentSize
OutgoingRTPPktLink * getNext()
microtimeout_t getExpireTimeout() const
void unlockDestinationList() const