1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
3 // Copyright (C) 2015 Cherokees of Idaho.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 // As a special exception, you may use this file as part of a free software
20 // library without restriction. Specifically, if other files instantiate
21 // templates or use macros or inline functions from this file, or you compile
22 // this file and link it with other files to produce an executable, this
23 // file does not by itself cause the resulting executable to be covered by
24 // the GNU General Public License. This exception does not however
25 // invalidate any other reasons why the executable file might be covered by
26 // the GNU General Public License.
27 //
28 // This exception applies only to the code released under the name GNU
29 // ccRTP. If you copy code from other releases into a copy of GNU
30 // ccRTP, as the General Public License permits, the exception does
31 // not apply to the code that you add in this way. To avoid misleading
32 // anyone as to the status of such modified files, you must delete
33 // this exception notice from them.
34 //
35 // If you write modifications of your own for GNU ccRTP, it is your choice
36 // whether to permit this exception to apply to your modifications.
37 // If you do not wish that, delete this exception notice.
38 //
39
40 /**
41 * @file control.cpp
42 *
43 * @short QueueRTCPManager classes implementation.
44 **/
45
46 #include "private.h"
47 #include <cstdlib>
48 #include <ccrtp/cqueue.h>
49 #include <cstdlib>
50 #include <climits>
51
52 NAMESPACE_COMMONCPP
53
54 const uint16 QueueRTCPManager::TIMEOUT_MULTIPLIER = 5;
55 const double QueueRTCPManager::RECONSIDERATION_COMPENSATION = 2.718281828 - 1.5;
56 const SDESItemType QueueRTCPManager::firstSchedulable = SDESItemTypeNAME;
57 const SDESItemType QueueRTCPManager::lastSchedulable = SDESItemTypePRIV;
58 /// maximum end to end delay: unlimited
59 const microtimeout_t QueueRTCPManager::defaultEnd2EndDelay = 0;
60
QueueRTCPManager(uint32 size,RTPApplication & app)61 QueueRTCPManager::QueueRTCPManager(uint32 size, RTPApplication& app):
62 RTPDataQueue(size), RTCPCompoundHandler(RTCPCompoundHandler::defaultPathMTU),
63 queueApplication(app), srtcpIndex(0)
64 {
65 controlServiceActive = false;
66 controlBwFract = 0.05f;
67 sendControlBwFract = 0.25;
68 recvControlBwFract = 1-sendControlBwFract;
69 ctrlSendCount = 0;
70
71 lowerHeadersSize = networkHeaderSize() + transportHeaderSize();
72
73 nextScheduledSDESItem = SDESItemTypeNAME;
74
75 // initialize RTCP timing
76 reconsInfo.rtcpTp.tv_sec = reconsInfo.rtcpTc.tv_sec =
77 reconsInfo.rtcpTn.tv_sec = 0;
78 reconsInfo.rtcpTp.tv_usec = reconsInfo.rtcpTc.tv_usec =
79 reconsInfo.rtcpTn.tv_usec = 0;
80 reconsInfo.rtcpPMembers = 1;
81
82 rtcpWeSent = false;
83 rtcpAvgSize = sizeof(RTCPFixedHeader) + sizeof(uint32) +
84 sizeof(SenderInfo);
85 rtcpInitial = true;
86 // force an initial check for incoming RTCP packets
87 SysTime::gettimeofday(&rtcpNextCheck,NULL);
88 // check for incoming RTCP packets every 1/4 seconds.
89 rtcpCheckInterval.tv_sec = 0;
90 rtcpCheckInterval.tv_usec = 250000;
91 timersub(&rtcpNextCheck,&rtcpCheckInterval,&rtcpLastCheck);
92
93 lastSendPacketCount = 0;
94
95 rtcpMinInterval = 5000000; // 5 seconds.
96
97 leavingDelay = 1000000; // 1 second
98 end2EndDelay = getDefaultEnd2EndDelay();
99
100 // Fill in fixed fields that will never change
101 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer);
102 pkt->fh.version = CCRTP_VERSION;
103 // (SSRCCollision will have to take this into account)
104 pkt->info.SR.ssrc = getLocalSSRCNetwork();
105
106 // allow to start RTCP service once everything is set up
107 controlServiceActive = true;
108 }
109
110 // TODO Streamline this code (same as above, put into a separate method)
QueueRTCPManager(uint32 ssrc,uint32 size,RTPApplication & app)111 QueueRTCPManager::QueueRTCPManager(uint32 ssrc, uint32 size, RTPApplication& app):
112 RTPDataQueue(&ssrc, size),
113 RTCPCompoundHandler(RTCPCompoundHandler::defaultPathMTU),
114 queueApplication(app), srtcpIndex(0)
115 {
116 controlServiceActive = false;
117 controlBwFract = 0.05f;
118 sendControlBwFract = 0.25;
119 recvControlBwFract = 1-sendControlBwFract;
120 ctrlSendCount = 0;
121
122 lowerHeadersSize = networkHeaderSize() + transportHeaderSize();
123
124 nextScheduledSDESItem = SDESItemTypeNAME;
125
126 // initialize RTCP timing
127 reconsInfo.rtcpTp.tv_sec = reconsInfo.rtcpTc.tv_sec =
128 reconsInfo.rtcpTn.tv_sec = 0;
129
130 reconsInfo.rtcpTp.tv_usec = reconsInfo.rtcpTc.tv_usec =
131 reconsInfo.rtcpTn.tv_usec = 0;
132
133 reconsInfo.rtcpPMembers = 1;
134
135 rtcpWeSent = false;
136 rtcpAvgSize = sizeof(RTCPFixedHeader) + sizeof(uint32) + sizeof(SenderInfo);
137 rtcpInitial = true;
138 // force an initial check for incoming RTCP packets
139 SysTime::gettimeofday(&rtcpNextCheck,NULL);
140 // check for incoming RTCP packets every 1/4 seconds.
141 rtcpCheckInterval.tv_sec = 0;
142 rtcpCheckInterval.tv_usec = 250000;
143 timersub(&rtcpNextCheck,&rtcpCheckInterval,&rtcpLastCheck);
144
145 lastSendPacketCount = 0;
146
147 rtcpMinInterval = 5000000; // 5 seconds.
148
149 leavingDelay = 1000000; // 1 second
150 end2EndDelay = getDefaultEnd2EndDelay();
151
152 // Fill in fixed fields that will never change
153 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer);
154 pkt->fh.version = CCRTP_VERSION;
155 // (SSRCCollision will have to take this into account)
156 pkt->info.SR.ssrc = getLocalSSRCNetwork();
157
158 // allow to start RTCP service once everything is set up
159 controlServiceActive = true;
160 }
161
~QueueRTCPManager()162 QueueRTCPManager::~QueueRTCPManager()
163 {
164 endQueueRTCPManager();
165 }
166
endQueueRTCPManager()167 void QueueRTCPManager::endQueueRTCPManager()
168 {
169 controlServiceActive = false;
170 controlBwFract = sendControlBwFract = 0;
171 removeOutQueueCryptoContextCtrl(NULL); // remove the outgoing crypto context
172 removeInQueueCryptoContextCtrl(NULL); // Remove any incoming crypto contexts
173
174 }
175
checkSSRCInRTCPPkt(SyncSourceLink & sourceLink,bool is_new,InetAddress & network_address,tpport_t transport_port)176 bool QueueRTCPManager::checkSSRCInRTCPPkt(SyncSourceLink& sourceLink,
177 bool is_new, InetAddress& network_address, tpport_t transport_port)
178 {
179 bool result = true;
180
181 // Test if the source is new and it is not the local one.
182 if ( is_new && sourceLink.getSource()->getID() != getLocalSSRC() )
183 return result;
184
185 SyncSource *s = sourceLink.getSource();
186 if ( s->getControlTransportPort() != transport_port ||
187 s->getNetworkAddress() != network_address ) {
188 // SSRC collision or a loop has happened
189 if ( s->getID() != getLocalSSRC() ) {
190 // TODO: Optional error counter.
191
192 // Note this differs from the default in the RFC.
193 // Discard packet only when the collision is
194 // repeating (to avoid flip-flopping)
195 if ( sourceLink.getPrevConflict() &&
196 (
197 (network_address ==
198 sourceLink.getPrevConflict()->networkAddress)
199 &&
200 (transport_port ==
201 sourceLink.getPrevConflict()->controlTransportPort)
202 ) ) {
203 // discard packet and do not flip-flop
204 result = false;
205 } else {
206 // Record who has collided so that in
207 // the future we can how if the
208 // collision repeats.
209 sourceLink.setPrevConflict(network_address,
210 0,transport_port);
211 // Change sync source transport address
212 setControlTransportPort(*s,transport_port);
213 setNetworkAddress(*s,network_address);
214 }
215
216 } else {
217 // Collision or loop of own packets.
218 ConflictingTransportAddress* conflicting =
219 searchControlConflict(network_address,
220 transport_port);
221 if ( conflicting ) {
222 // Optional error counter.
223 updateConflict(*conflicting);
224 result = false;
225 } else {
226 // New collision
227 addConflict(s->getNetworkAddress(),
228 s->getDataTransportPort(),
229 s->getControlTransportPort());
230 dispatchBYE("SSRC collision detected when receiving RTCP packet");
231 renewLocalSSRC();
232 setNetworkAddress(*s,network_address);
233 setControlTransportPort(*s,transport_port);
234 setControlTransportPort(*s,0);
235 sourceLink.initStats();
236 }
237 }
238 }
239 return result;
240 }
241
controlReceptionService()242 void QueueRTCPManager::controlReceptionService()
243 {
244 if ( !controlServiceActive )
245 return;
246
247 // A) see if there are incoming RTCP packets
248 SysTime::gettimeofday(&(reconsInfo.rtcpTc),NULL);
249 if ( timercmp(&(reconsInfo.rtcpTc),&rtcpNextCheck,>=) ) {
250 while ( isPendingControl(0) )
251 takeInControlPacket();
252 // If this do loops more than once, then we have not
253 // been in time. So it skips until the next future
254 // instant.
255 do {
256 timeval tmp = rtcpNextCheck;
257 timeradd(&rtcpLastCheck,&rtcpCheckInterval,
258 &rtcpNextCheck);
259 rtcpLastCheck = tmp;
260 } while ( timercmp(&(reconsInfo.rtcpTc), &(rtcpNextCheck), >=) );
261 }
262 }
263
controlTransmissionService()264 void QueueRTCPManager::controlTransmissionService()
265 {
266 if ( !controlServiceActive )
267 return;
268
269 // B) send RTCP packets
270 SysTime::gettimeofday(&(reconsInfo.rtcpTc),NULL);
271 if ( timercmp(&(reconsInfo.rtcpTc),&(reconsInfo.rtcpTn),>=) ) {
272 if ( timerReconsideration() ) {
273 // this would update to last received RTCP packets
274 //while ( isPendingControl(0) )
275 // takeInControlPacket();
276 rtcpLastCheck = reconsInfo.rtcpTc;
277 dispatchControlPacket();
278 if (rtcpInitial)
279 rtcpInitial = false;
280 expireSSRCs();
281 reconsInfo.rtcpTp = reconsInfo.rtcpTc;
282 // we have updated tp and sent a report, so we
283 // have to recalculate the sending interval
284 timeval T = computeRTCPInterval();
285 timeradd(&(reconsInfo.rtcpTc),&T,&(reconsInfo.rtcpTn));
286
287 // record current number of members for the
288 // next check.
289 reconsInfo.rtcpPMembers = getMembersCount();
290 }
291 }
292 }
293
timerReconsideration()294 bool QueueRTCPManager::timerReconsideration()
295 {
296 bool result = false;
297 // compute again the interval to confirm it under current
298 // circumstances
299 timeval T = computeRTCPInterval();
300 timeradd(&(reconsInfo.rtcpTp),&T,&(reconsInfo.rtcpTn));
301 SysTime::gettimeofday(&(reconsInfo.rtcpTc),NULL);
302 if ( timercmp(&(reconsInfo.rtcpTc),&(reconsInfo.rtcpTn),>=) ) {
303 reconsInfo.rtcpTp = reconsInfo.rtcpTc;
304 result = true;
305 }
306 return result;
307 }
308
309 void
expireSSRCs()310 QueueRTCPManager::expireSSRCs()
311 {}
312
313 void
takeInControlPacket()314 QueueRTCPManager::takeInControlPacket()
315 {
316 size_t len = 0;
317 InetHostAddress network_address;
318 tpport_t transport_port;
319 len = recvControl(rtcpRecvBuffer,getPathMTU(),network_address, transport_port);
320
321 // get time of arrival
322 struct timeval recvtime;
323 SysTime::gettimeofday(&recvtime,NULL);
324
325 // process a 'len' octets long RTCP compound packet
326
327 RTCPPacket *pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer);
328
329 CryptoContextCtrl* pcc = getInQueueCryptoContextCtrl(pkt->getSSRC());
330 if (pcc == NULL) {
331 pcc = getInQueueCryptoContextCtrl(0);
332 if (pcc != NULL) {
333 pcc = pcc->newCryptoContextForSSRC(pkt->getSSRC());
334 if (pcc != NULL) {
335 pcc->deriveSrtcpKeys();
336 setInQueueCryptoContextCtrl(pcc);
337 }
338 }
339 }
340 // If no crypto context: then SRTP/SRTCP is off
341 // If crypto context is available then unprotect data here. If an error
342 // occurs report the error and discard the packet.
343 if (pcc != NULL) {
344 int32 ret;
345 if ((ret = unprotect(rtcpRecvBuffer, len, pcc)) < 0) {
346 // TODO: do more error handling?
347 return;
348 }
349 len = ret; // adjust length after unprotecting the packet
350 }
351 // Check validity of the header fields of the compound packet
352 if ( !RTCPCompoundHandler::checkCompoundRTCPHeader(len) )
353 return;
354
355
356 // TODO: for now, we do nothing with the padding bit
357 // in the header.
358
359 bool source_created;
360 SyncSourceLink* sourceLink = getSourceBySSRC(pkt->getSSRC(),source_created);
361 SyncSource* s = sourceLink->getSource();
362
363 if ( source_created ) {
364 // Set control transport address.
365 setControlTransportPort(*s,transport_port);
366 // Network address is assumed to be the same as the control one
367 setNetworkAddress(*s,network_address);
368 sourceLink->initStats();
369 sourceLink->setProbation(getMinValidPacketSequence());
370 if ( sourceLink->getHello() )
371 onNewSyncSource(*s);
372 } else if ( s->getControlTransportPort() == 0 ) {
373 // Test if RTP data packets had been received but this
374 // is the first control packet from this source.
375 setControlTransportPort(*s,transport_port);
376 }
377 // record reception time
378 sourceLink->lastRTCPPacketTime = recvtime;
379 sourceLink->lastRTCPSRTime = recvtime;
380
381 size_t pointer = 0;
382 // Check the first packet is a report and do special
383 // processing for SR reports.
384 if ( RTCPPacket::tRR == pkt->fh.type ) {
385 // no special initialization is required for
386 // RR reports, all reports will be processed
387 // in the do-while down here.
388 } else if ( RTCPPacket::tSR == pkt->fh.type ){
389 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
390 network_address,
391 transport_port) )
392 sourceLink->lastRTCPSRTime = recvtime;
393 onGotSR(*s,pkt->info.SR,pkt->fh.block_count);
394 // Advance to the next packet in the compound.
395 pointer += pkt->getLength();
396 pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer +pointer);
397 } else if ( RTCPPacket::tXR == pkt->fh.type ) {
398 // TODO: handle XR reports.
399 } else {
400 // Ignore RTCP types unknown.
401 }
402
403 // Process all RR reports.
404 while ( (pointer < len) && (RTCPPacket::tRR == pkt->fh.type) ) {
405 sourceLink = getSourceBySSRC(pkt->getSSRC(),
406 source_created);
407 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
408 network_address,transport_port) )
409 onGotRR(*s,pkt->info.RR,pkt->fh.block_count);
410 // Advance to the next packet in the compound
411 pointer += pkt->getLength();
412 pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer +pointer);
413 }
414
415 // SDES, APP and BYE. process first everything but the
416 // BYE packets.
417 bool cname_found = false;
418 while ( (pointer < len ) &&
419 (pkt->fh.type == RTCPPacket::tSDES ||
420 pkt->fh.type == RTCPPacket::tAPP) ) {
421 I ( cname_found || !pkt->fh.padding );
422 sourceLink = getSourceBySSRC(pkt->getSSRC(),
423 source_created);
424 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
425 network_address,
426 transport_port) ) {
427 if ( pkt->fh.type == RTCPPacket::tSDES ) {
428 bool cname = onGotSDES(*s,*pkt);
429 cname_found = cname_found? cname_found : cname;
430 } else if ( pkt->fh.type == RTCPPacket::tAPP ) {
431 onGotAPP(*s,pkt->info.APP,pkt->getLength());
432 // pointer += pkt->getLength();
433 } else {
434 // error?
435 }
436 }
437 // Get the next packet in the compound.
438 pointer += pkt->getLength();
439 pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer +pointer);
440 }
441
442 // TODO: error? if !cname_found
443
444 // process BYE packets
445 while ( pointer < len ) {
446 if ( pkt->fh.type == RTCPPacket::tBYE ) {
447 sourceLink = getSourceBySSRC(pkt->getSSRC(),
448 source_created);
449 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
450 network_address,
451 transport_port) )
452 getBYE(*pkt,pointer,len);
453 } else if ( pkt->fh.type != RTCPPacket::tBYE ) {
454 break; // TODO: check non-BYE out of place.
455 } else {
456 break;
457 }
458 }
459
460 // Call plug-in in case there are profile extensions
461 // at the end of the SR/RR.
462 if ( pointer != len ) {
463 onGotRRSRExtension(rtcpRecvBuffer + pointer,
464 len - pointer);
465 }
466
467 // Everything went right, update the RTCP average size
468 updateAvgRTCPSize(len);
469 }
470
end2EndDelayed(IncomingRTPPktLink & pl)471 bool QueueRTCPManager::end2EndDelayed(IncomingRTPPktLink& pl)
472 {
473 bool result = false;
474
475 if ( 0 != getEnd2EndDelay() ) {
476 SyncSourceLink* sl = pl.getSourceLink();
477 void* si = sl->getSenderInfo();
478 if ( NULL != si ) {
479 RTCPSenderInfo rsi(si);
480 uint32 tsInc = pl.getPacket()->getTimestamp() -
481 rsi.getRTPTimestamp();
482 // approx.
483 microtimeout_t Inc = tsInc * 1000 /
484 (getCurrentRTPClockRate() / 1000);
485 timeval timevalInc = microtimeout2Timeval(Inc);
486
487 timeval tNTP = NTP2Timeval(rsi.getNTPTimestampInt(),
488 rsi.getNTPTimestampFrac());
489 timeval packetTime;
490 timeradd(&tNTP,&timevalInc,&packetTime);
491 timeval now, diff;
492 SysTime::gettimeofday(&now,NULL);
493 timersub(&now,&packetTime,&diff);
494
495 if ( timeval2microtimeout(diff) > getEnd2EndDelay() )
496 result = true;
497 }
498 }
499 return result;
500 }
501
onGotSR(SyncSource & source,SendReport & SR,uint8)502 void QueueRTCPManager::onGotSR(SyncSource& source, SendReport& SR, uint8)
503 {
504 // We ignore the receiver blocks and just get the sender info
505 // at the beginning of the SR.
506 getLink(source)->setSenderInfo(reinterpret_cast<unsigned char*>(&(SR.sinfo)));
507 }
508
onGotRR(SyncSource & source,RecvReport & RR,uint8 blocks)509 void QueueRTCPManager::onGotRR(SyncSource& source, RecvReport& RR, uint8 blocks)
510 {
511 for ( uint8 i = 0; i < blocks; i++) {
512 // this generic RTCP manager ignores reports about
513 // other sources than the local one
514 if ( getLocalSSRCNetwork() == RR.ssrc ) {
515 getLink(source)->
516 setReceiverInfo
517 (reinterpret_cast<unsigned char*>(&(RR.blocks[i].rinfo)));
518 }
519 }
520 }
521
updateAvgRTCPSize(size_t len)522 void QueueRTCPManager::updateAvgRTCPSize(size_t len)
523 {
524 size_t newlen = len;
525 newlen += lowerHeadersSize;
526 rtcpAvgSize = (uint16)(( (15 * rtcpAvgSize) >> 4 ) + ( newlen >> 4));
527 }
528
getBYE(RTCPPacket & pkt,size_t & pointer,size_t)529 bool QueueRTCPManager::getBYE(RTCPPacket& pkt, size_t& pointer, size_t)
530 {
531 if ( 0 == pkt.fh.block_count )
532 return false;
533
534 char *reason = NULL;
535
536 if ( (sizeof(RTCPFixedHeader) + pkt.fh.block_count * sizeof(uint32))
537 < pkt.getLength() ) {
538 uint16 endpointer = (uint16)(pointer + sizeof(RTCPFixedHeader) +
539 pkt.fh.block_count * sizeof(uint32));
540 uint16 len = rtcpRecvBuffer[endpointer];
541 reason = new char[len + 1];
542 memcpy(reason,rtcpRecvBuffer + endpointer + 1,len);
543 reason[len] = '\0';
544 } else { // avoid dangerous conversion of NULL to a C++ string.
545 reason = new char[1];
546 reason[0] = '\0';
547 }
548
549 int i = 0;
550 while ( i < pkt.fh.block_count ) {
551 bool created;
552 SyncSourceLink* srcLink =
553 getSourceBySSRC(pkt.getSSRC(),created);
554 i++;
555 if( srcLink->getGoodbye() )
556 onGotGoodbye(*(srcLink->getSource()),reason);
557 BYESource(pkt.getSSRC());
558 setState(*(srcLink->getSource()),SyncSource::stateLeaving);
559
560 reverseReconsideration();
561 }
562
563 delete [] reason;
564 pointer += pkt.getLength();
565 return true;
566 }
567
reverseReconsideration()568 void QueueRTCPManager::reverseReconsideration()
569 {
570 if ( getMembersCount() < reconsInfo.rtcpPMembers ) {
571 timeval inc;
572
573 // reconsider reconsInfo.rtcpTn (time for next RTCP packet)
574 microtimeout_t t =
575 (reconsInfo.rtcpTn.tv_sec - reconsInfo.rtcpTc.tv_sec) *
576 1000000 +
577 (reconsInfo.rtcpTn.tv_usec - reconsInfo.rtcpTc.tv_usec);
578 t *= getMembersCount();
579 t /= reconsInfo.rtcpPMembers;
580 inc.tv_usec = t % 1000000;
581 inc.tv_sec = t / 1000000;
582 timeradd(&(reconsInfo.rtcpTc),&inc,&(reconsInfo.rtcpTn));
583
584 // reconsider tp (time for previous RTCP packet)
585 t = (reconsInfo.rtcpTc.tv_sec - reconsInfo.rtcpTp.tv_sec) *
586 1000000 +
587 (reconsInfo.rtcpTc.tv_usec - reconsInfo.rtcpTp.tv_usec);
588 t *= getMembersCount();
589 t /= reconsInfo.rtcpPMembers;
590 inc.tv_usec = t % 1000000;
591 inc.tv_sec = t / 1000000;
592 timeradd(&(reconsInfo.rtcpTc),&inc,&(reconsInfo.rtcpTp));
593 }
594 reconsInfo.rtcpPMembers = getMembersCount();
595 }
596
onGotSDES(SyncSource & source,RTCPPacket & pkt)597 bool QueueRTCPManager::onGotSDES(SyncSource& source, RTCPPacket& pkt)
598 {
599 // Take into account that length fields in SDES items are
600 // 8-bit long, so no ntoh[s|l] is required
601 bool cname_found = false;
602
603 std::ptrdiff_t pointer = reinterpret_cast<unsigned char*>(&pkt) - rtcpRecvBuffer;
604 uint16 i = 0;
605 do {
606 size_t len = pkt.getLength();
607 pointer += sizeof(RTCPFixedHeader);
608 SDESChunk* chunk = (SDESChunk*)(rtcpRecvBuffer + pointer);
609
610 bool source_created = false;
611 // TODO: avoid searching again the source of the first chunk.
612 SyncSourceLink* sourceLink =
613 getSourceBySSRC(chunk->getSSRC(),
614 source_created);
615 // TODO: check that there are no two chunks with the
616 // same SSRC but different CNAME
617 SyncSource& src = *( sourceLink->getSource() );
618
619 if ( onGotSDESChunk(source,*chunk,len) )
620 cname_found = true;
621 pointer +=len;
622 if( sourceLink->getHello() )
623 onNewSyncSource(src);
624 i++;
625 } while ( i < pkt.fh.block_count );
626 return cname_found;
627 }
628
onGotSDESChunk(SyncSource & source,SDESChunk & chunk,size_t len)629 bool QueueRTCPManager::onGotSDESChunk(SyncSource& source, SDESChunk& chunk, size_t len)
630 {
631 bool cname_found = false;
632 bool end = false;
633
634 SyncSourceLink* srcLink = getLink(source);
635 Participant* part = source.getParticipant();
636
637 size_t pointer = sizeof(chunk.ssrc);
638
639 // process chunk items
640 while ( (pointer < len) && !end ) {
641 SDESItem* item =
642 reinterpret_cast<SDESItem*>(size_t(&(chunk)) + pointer);
643 if ( item->type > SDESItemTypeEND && item->type <= SDESItemTypeLast) {
644 pointer += sizeof(item->type) + sizeof(item->len) +
645 item->len;
646 if ( NULL == part && SDESItemTypeCNAME == item->type ) {
647 const RTPApplication& app = getApplication();
648 std::string cname = std::string(item->data,item->len);
649 const Participant* p = app.getParticipant(cname);
650 if ( p ) {
651 part = const_cast<Participant*>(p);
652 setParticipant(*(srcLink->getSource()),*part);
653 } else {
654 part = new Participant("-");
655 addParticipant(const_cast<RTPApplication&>(getApplication()),*part);
656 }
657 setParticipant(*(srcLink->getSource()),*part);
658 }
659
660 // support for CNAME updates
661 if ( part )
662 setSDESItem(part,(SDESItemType)item->type, item->data,item->len);
663
664 if ( item->type == SDESItemTypeCNAME) {
665 cname_found = true;
666 // note that CNAME must be send in
667 // every RTCP compound, so we only
668 // trust sources that include it.
669 setState(*(srcLink->getSource()),
670 SyncSource::stateActive);
671 }
672 } else if ( item->type == SDESItemTypeEND) {
673 end = true;
674 pointer++;
675 pointer += (pointer & 0x03); // padding
676 } else if ( item->type == SDESItemTypePRIV ) {
677 std::ptrdiff_t prevpointer = pointer;
678 uint8 plength = *( &(item->len) + 1 );
679 pointer += sizeof(item->type) + sizeof(item->len) + 1;
680
681 if ( part )
682 setSDESItem(part,SDESItemTypePRIV,
683 reinterpret_cast<char*>(item + pointer),plength);
684 pointer += plength;
685 setPRIVPrefix(part,
686 reinterpret_cast<char*>(item + pointer),
687 (item->len - 1 - plength));
688 pointer = prevpointer + item->len;
689 } else {
690 pointer++;
691 // TODO: error: SDES unknown
692 I( false );
693 }
694 }
695 return cname_found;
696 }
697
computeRTCPInterval()698 timeval QueueRTCPManager::computeRTCPInterval()
699 {
700 float bwfract = controlBwFract * getSessionBandwidth();
701 uint32 participants = getMembersCount();
702 if ( getSendersCount() > 0 &&
703 ( getSendersCount() < (getMembersCount() * sendControlBwFract) )) {
704 // reserve "sendControlBwFract" fraction of the total
705 // RTCP bandwith for senders.
706 if (rtcpWeSent) {
707 // we take the side of active senders
708 bwfract *= sendControlBwFract;
709 participants = getSendersCount();
710 } else {
711 // we take the side of passive receivers
712 bwfract *= recvControlBwFract;
713 participants = getMembersCount() - getSendersCount();
714 }
715 }
716
717 microtimeout_t min_interval = rtcpMinInterval;
718 // be a bit quicker at first
719 if ( rtcpInitial )
720 min_interval /= 2;
721 // this is the real computation:
722 microtimeout_t interval = 0;
723 if ( bwfract != 0 ) {
724 interval = static_cast<microtimeout_t>
725 ((participants * rtcpAvgSize / bwfract) * 1000000);
726
727 if ( interval < rtcpMinInterval )
728 interval = rtcpMinInterval;
729 } else {
730 // 100 seconds instead of infinite
731 interval = 100000000;
732 }
733
734 interval = static_cast<microtimeout_t>(interval * ( 0.5 +
735 (rand() / (RAND_MAX + 1.0))));
736
737 timeval result;
738 result.tv_sec = interval / 1000000;
739 result.tv_usec = interval % 1000000;
740 return result;
741 }
742
743 #define BYE_BUFFER_LENGTH 500
744
dispatchBYE(const std::string & reason)745 size_t QueueRTCPManager::dispatchBYE(const std::string& reason)
746 {
747 // for this method, see section 6.3.7 in RFC 3550
748 // never send a BYE packet if never sent an RTP or RTCP packet
749 // before
750 if ( !(getSendPacketCount() || getSendRTCPPacketCount()) )
751 return 0;
752
753 if ( getMembersCount() > 50) {
754 // Usurp the scheduler role and apply a back-off
755 // algorithm to avoid BYE floods.
756 SysTime::gettimeofday(&(reconsInfo.rtcpTc),NULL);
757 reconsInfo.rtcpTp = reconsInfo.rtcpTc;
758 setMembersCount(1);
759 setPrevMembersNum(1);
760 rtcpInitial = true;
761 rtcpWeSent = false;
762 rtcpAvgSize = (uint16)(sizeof(RTCPFixedHeader) + sizeof(uint32) +
763 strlen(reason.c_str()) +
764 (4 - (strlen(reason.c_str()) & 0x03)));
765 SysTime::gettimeofday(&(reconsInfo.rtcpTc),NULL);
766 timeval T = computeRTCPInterval();
767 timeradd(&(reconsInfo.rtcpTp),&T,&(reconsInfo.rtcpTn));
768 while ( timercmp(&(reconsInfo.rtcpTc),&(reconsInfo.rtcpTn),<) ) {
769 getOnlyBye();
770 if ( timerReconsideration() )
771 break;
772 SysTime::gettimeofday(&(reconsInfo.rtcpTc),NULL);
773 }
774 }
775
776
777 unsigned char buffer[BYE_BUFFER_LENGTH] = {0};
778 // Build an empty RR as first packet in the compound.
779 // TODO: provide more information if available. Not really
780 // important, since this is the last packet being sent.
781 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(buffer);
782 pkt->fh.version = CCRTP_VERSION;
783 pkt->fh.padding = 0;
784 pkt->fh.block_count = 0;
785 pkt->fh.type = RTCPPacket::tRR;
786 pkt->info.RR.ssrc= getLocalSSRCNetwork();
787 uint16 len1 = sizeof(RTCPFixedHeader) + sizeof(uint32); // 1st pkt len.
788 pkt->fh.length = htons((len1 >> 2) - 1);
789 uint16 len = len1; // whole compound len.
790 // build a BYE packet
791 uint16 padlen = 0;
792 pkt = reinterpret_cast<RTCPPacket*>(buffer + len1);
793 pkt->fh.version = CCRTP_VERSION;
794 pkt->fh.block_count = 1;
795 pkt->fh.type = RTCPPacket::tBYE;
796 // add the SSRC identifier
797 pkt->info.BYE.ssrc = getLocalSSRCNetwork();
798 len += sizeof(RTCPFixedHeader) + sizeof(BYEPacket);
799 // add the optional reason
800 if ( reason.c_str() != NULL ){
801 pkt->info.BYE.length = (uint8)strlen(reason.c_str());
802 memcpy(buffer + len,reason.c_str(),pkt->info.BYE.length);
803 len += pkt->info.BYE.length;
804 padlen = 4 - ((len - len1) & 0x03);
805 if ( padlen ) {
806 memset(buffer + len,0,padlen);
807 len += padlen;
808 pkt->info.BYE.length += padlen;
809 }
810 }
811 pkt->fh.length = htons(((len - len1) >> 2) - 1);
812
813 return sendControlToDestinations(buffer,len);
814 }
815
getOnlyBye()816 void QueueRTCPManager::getOnlyBye()
817 {
818 // This method is kind of simplified recvControl
819 timeval wait;
820 timersub(&(reconsInfo.rtcpTn),&(reconsInfo.rtcpTc),&wait);
821 microtimeout_t timer = wait.tv_usec/1000 + wait.tv_sec * 1000;
822 // wait up to reconsInfo.rtcpTn
823 if ( !isPendingControl(timer) )
824 return;
825
826 size_t len = 0;
827 InetHostAddress network_address;
828 tpport_t transport_port;
829 while ( (len = recvControl(rtcpRecvBuffer,getPathMTU(),
830 network_address,transport_port)) ) {
831 // Process a <code>len<code> octets long RTCP compound packet
832 // Check validity of the header fields of the compound packet
833 if ( !RTCPCompoundHandler::checkCompoundRTCPHeader(len) )
834 return;
835
836 // TODO: For now, we do nothing with the padding bit
837 // in the header.
838 uint32 pointer = 0;
839 RTCPPacket* pkt;
840 while ( pointer < len) {
841 pkt = reinterpret_cast<RTCPPacket*>
842 (rtcpRecvBuffer + pointer);
843
844 if (pkt->fh.type == RTCPPacket::tBYE ) {
845 bool created;
846 SyncSourceLink* srcLink =
847 getSourceBySSRC(pkt->getSSRC(),
848 created);
849 if( srcLink->getGoodbye() )
850 onGotGoodbye(*(srcLink->getSource()), "");
851 BYESource(pkt->getSSRC());
852 }
853 pointer += pkt->getLength();
854 }
855 }
856 }
857
dispatchControlPacket(void)858 size_t QueueRTCPManager::dispatchControlPacket(void)
859 {
860 rtcpInitial = false;
861 // Keep in mind: always include a report (in SR or RR) and at
862 // least a SDES with the local CNAME. It is mandatory.
863
864 // (A) SR or RR, depending on whether we sent.
865 // pkt will point to the packets of the compound
866
867 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer);
868 // Fixed header of the first report
869 pkt->fh.padding = 0;
870 pkt->fh.version = CCRTP_VERSION;
871 // length of the RTCP compound packet. It will increase till
872 // the end of this routine. Both sender and receiver report
873 // carry the general 32-bit long fixed header and a 32-bit
874 // long SSRC identifier.
875 uint16 len = sizeof(RTCPFixedHeader) + sizeof(uint32);
876
877 // the fields block_count and length will be filled in later
878 // now decide whether to send a SR or a SR
879 if ( lastSendPacketCount != getSendPacketCount() ) {
880 // we have sent rtp packets since last RTCP -> send SR
881 lastSendPacketCount = getSendPacketCount();
882 pkt->fh.type = RTCPPacket::tSR;
883 pkt->info.SR.ssrc = getLocalSSRCNetwork();
884
885 // Fill in sender info block. It would be more
886 // accurate if this were done as late as possible.
887 timeval now;
888 SysTime::gettimeofday(&now,NULL);
889 // NTP MSB and MSB: dependent on current payload type.
890 pkt->info.SR.sinfo.NTPMSW = htonl(now.tv_sec + NTP_EPOCH_OFFSET);
891 pkt->info.SR.sinfo.NTPLSW = htonl((uint32)(((double)(now.tv_usec)*(uint32)(~0))/1000000.0));
892 // RTP timestamp
893 int32 tstamp = now.tv_usec - getInitialTime().tv_usec;
894 tstamp *= (getCurrentRTPClockRate()/1000);
895 tstamp /= 1000;
896 tstamp += (now.tv_sec - getInitialTime().tv_sec) *
897 getCurrentRTPClockRate();
898 tstamp += getInitialTimestamp();
899 pkt->info.SR.sinfo.RTPTimestamp = htonl(tstamp);
900 // sender's packet and octet count
901 pkt->info.SR.sinfo.packetCount = htonl(getSendPacketCount());
902 pkt->info.SR.sinfo.octetCount = htonl(getSendOctetCount());
903 len += sizeof(SenderInfo);
904 } else {
905 // RR
906 pkt->fh.type = RTCPPacket::tRR;
907 pkt->info.RR.ssrc = getLocalSSRCNetwork();
908 }
909
910 // (B) put report blocks
911 // After adding report blocks, we have to leave room for at
912 // least a CNAME SDES item
913 uint16 available = (uint16)(getPathMTU()
914 - lowerHeadersSize
915 - len
916 - (sizeof(RTCPFixedHeader) +
917 2*sizeof(uint8) +
918 getApplication().getSDESItem(SDESItemTypeCNAME).length())
919 - 100);
920
921 // if we have to go to a new RR packet
922 bool another = false;
923 uint16 prevlen = 0;
924 RRBlock* reports;
925 if ( RTCPPacket::tRR == pkt->fh.type )
926 reports = pkt->info.RR.blocks;
927 else // ( RTCPPacket::tSR == pkt->fh.type )
928 reports = pkt->info.SR.blocks;
929 do {
930 uint8 blocks = 0;
931 pkt->fh.block_count = blocks = packReportBlocks(reports,len,available);
932 // the length field specifies 32-bit words
933 pkt->fh.length = htons( ((len - prevlen) >> 2) - 1);
934 prevlen = len;
935 if ( 31 == blocks ) {
936 // we would need room for a new RR packet and
937 // a CNAME SDES
938 if ( len < (available -
939 ( sizeof(RTCPFixedHeader) + sizeof(uint32) +
940 sizeof(RRBlock))) ) {
941 another = true;
942 // Header for this new packet in the compound
943 pkt = reinterpret_cast<RTCPPacket*>
944 (rtcpSendBuffer + len);
945 pkt->fh.version = CCRTP_VERSION;
946 pkt->fh.padding = 0;
947 pkt->fh.type = RTCPPacket::tRR;
948 pkt->info.RR.ssrc = getLocalSSRCNetwork();
949 // appended a new Header and a report block
950
951 len += sizeof(RTCPFixedHeader)+ sizeof(uint32);
952 reports = pkt->info.RR.blocks;
953 } else {
954 another = false;
955 }
956 } else {
957 another = false;
958 }
959 } while ( (len < available) && another );
960
961 // (C) SDES (CNAME)
962 // each SDES chunk must be 32-bit multiple long
963 // fill the padding with 0s
964 packSDES(len);
965
966 // TODO: virtual for sending APP RTCP packets?
967
968 // actually send the packet.
969 size_t count = sendControlToDestinations(rtcpSendBuffer,len);
970 ctrlSendCount++;
971 // Everything went right, update the RTCP average size
972 updateAvgRTCPSize(len);
973
974 return count;
975 }
976
packSDES(uint16 & len)977 void QueueRTCPManager::packSDES(uint16 &len)
978 {
979 uint16 prevlen = len;
980 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer + len);
981 // Fill RTCP fixed header. Note fh.length is not set till the
982 // end of this routine.
983 pkt->fh.version = CCRTP_VERSION;
984 pkt->fh.padding = 0;
985 pkt->fh.block_count = 1;
986 pkt->fh.type = RTCPPacket::tSDES;
987 pkt->info.SDES.ssrc = getLocalSSRCNetwork();
988 pkt->info.SDES.item.type = SDESItemTypeCNAME;
989 // put CNAME
990 size_t cnameLen =
991 getApplication().getSDESItem(SDESItemTypeCNAME).length();
992 const char* cname =
993 getApplication().getSDESItem(SDESItemTypeCNAME).c_str();
994 pkt->info.SDES.item.len = (uint8)cnameLen;
995 len += sizeof(RTCPFixedHeader) + sizeof(pkt->info.SDES.ssrc) +
996 sizeof(pkt->info.SDES.item.type) +
997 sizeof(pkt->info.SDES.item.len);
998
999 memcpy((rtcpSendBuffer + len),cname,cnameLen);
1000 len += (uint16)cnameLen;
1001 // pack items other than CNAME (following priorities
1002 // stablished inside scheduleSDESItem()).
1003 SDESItemType nexttype = scheduleSDESItem();
1004 if ( (nexttype > SDESItemTypeCNAME) &&
1005 (nexttype <= SDESItemTypeLast ) ) {
1006 SDESItem *item = reinterpret_cast<SDESItem *>(rtcpSendBuffer + len);
1007 item->type = nexttype;
1008 const char *content =
1009 getApplication().getSDESItem(nexttype).c_str();
1010 item->len = (uint8)strlen(content);
1011 len += 2;
1012 memcpy(reinterpret_cast<char *>(rtcpSendBuffer + len),
1013 content,item->len);
1014 len += item->len;
1015 }
1016
1017 // pack END item (terminate list of items in this chunk)
1018 rtcpSendBuffer[len] = SDESItemTypeEND;
1019 len++;
1020
1021 uint8 padding = len & 0x03;
1022 if ( padding ) {
1023 padding = 4 - padding;
1024 memset((rtcpSendBuffer + len),SDESItemTypeEND,padding);
1025 len += padding;
1026 }
1027 pkt->fh.length = htons((len - prevlen - 1) >>2);
1028 }
1029
packReportBlocks(RRBlock * blocks,uint16 & len,uint16 & available)1030 uint8 QueueRTCPManager::packReportBlocks(RRBlock* blocks, uint16 &len, uint16& available)
1031 {
1032 uint8 j = 0;
1033 // pack as many report blocks as we can
1034 SyncSourceLink* i = getFirst();
1035 for ( ;
1036 ( ( i != NULL ) &&
1037 ( len < (available - sizeof(RTCPCompoundHandler::RRBlock)) ) &&
1038 ( j < 31 ) );
1039 i = i->getNext() ) {
1040 SyncSourceLink& srcLink = *i;
1041 // update stats.
1042 srcLink.computeStats();
1043 blocks[j].ssrc = htonl(srcLink.getSource()->getID());
1044 blocks[j].rinfo.fractionLost = srcLink.getFractionLost();
1045 blocks[j].rinfo.lostMSB =
1046 (srcLink.getCumulativePacketLost() & 0xFF0000) >> 16;
1047 blocks[j].rinfo.lostLSW =
1048 htons(srcLink.getCumulativePacketLost() & 0xFFFF);
1049 blocks[j].rinfo.highestSeqNum =
1050 htonl(srcLink.getExtendedMaxSeqNum());
1051 blocks[j].rinfo.jitter =
1052 htonl(static_cast<uint32>(srcLink.getJitter()));
1053 RTCPCompoundHandler::SenderInfo* si =
1054 reinterpret_cast<RTCPCompoundHandler::SenderInfo*>(srcLink.getSenderInfo());
1055 if ( NULL == si ) {
1056 blocks[j].rinfo.lsr = 0;
1057 blocks[j].rinfo.dlsr = 0;
1058 } else {
1059 blocks[j].rinfo.lsr =
1060 htonl( ((ntohl(si->NTPMSW) & 0x0FFFF) << 16 )+
1061 ((ntohl(si->NTPLSW) & 0xFFFF0000) >> 16)
1062 );
1063 timeval now, diff;
1064 SysTime::gettimeofday(&now,NULL);
1065 timeval last = srcLink.getLastRTCPSRTime();
1066 timersub(&now,&last,&diff);
1067 blocks[j].rinfo.dlsr =
1068 htonl(timevalIntervalTo65536(diff));
1069 }
1070 len += sizeof(RTCPCompoundHandler::RRBlock);
1071 j++;
1072 }
1073 return j;
1074 }
1075
setSDESItem(Participant * part,SDESItemType type,const char * const value,size_t len)1076 void QueueRTCPManager::setSDESItem(Participant* part, SDESItemType type,
1077 const char* const value, size_t len)
1078 {
1079 char* buf = new char[len + 1];
1080 memcpy(buf,value,len);
1081 buf[len] = '\0';
1082 ParticipantHandler::setSDESItem(part,type,buf);
1083 delete [] buf;
1084 }
1085
setPRIVPrefix(Participant * part,const char * const value,size_t len)1086 void QueueRTCPManager::setPRIVPrefix(Participant* part, const char* const value, size_t len)
1087 {
1088 char *buf = new char[len + 1];
1089 memcpy(buf,value,len);
1090 buf[len] = '\0';
1091 ParticipantHandler::setPRIVPrefix(part,buf);
1092 delete [] buf;
1093 }
1094
scheduleSDESItem()1095 SDESItemType QueueRTCPManager::scheduleSDESItem()
1096 {
1097 uint8 i = 0;
1098 // TODO: follow, at least, standard priorities
1099 SDESItemType type = nextScheduledSDESItem;
1100
1101 while ( (queueApplication.getSDESItem(type).length() <= 0) &&
1102 i < (lastSchedulable - firstSchedulable) ) {
1103 i++;
1104 type = nextSDESType(type);
1105 }
1106 bool empty = true;
1107 if ( queueApplication.getSDESItem(type).length() > 0 )
1108 empty = false;
1109 nextScheduledSDESItem = nextSDESType(type);
1110 if ( empty )
1111 return SDESItemTypeEND;
1112 else
1113 return type;
1114 }
1115
nextSDESType(SDESItemType t)1116 SDESItemType QueueRTCPManager::nextSDESType(SDESItemType t)
1117 {
1118 t = static_cast<SDESItemType>( static_cast<int>(t) + 1 );
1119 if ( t > lastSchedulable )
1120 t = firstSchedulable;
1121 return t;
1122 }
1123
sendControlToDestinations(unsigned char * buffer,size_t len)1124 size_t QueueRTCPManager::sendControlToDestinations(unsigned char* buffer, size_t len)
1125 {
1126 size_t count = 0;
1127 lockDestinationList();
1128
1129 // Cast to have easy access to ssrc et al
1130 RTCPPacket *pkt = reinterpret_cast<RTCPPacket *>(buffer);
1131
1132 CryptoContextCtrl* pcc = getOutQueueCryptoContextCtrl(pkt->getSSRC());
1133 if (pcc == NULL) {
1134 pcc = getOutQueueCryptoContextCtrl(0);
1135 if (pcc != NULL) {
1136 pcc = pcc->newCryptoContextForSSRC(pkt->getSSRC());
1137 if (pcc != NULL) {
1138 pcc->deriveSrtcpKeys();
1139 setOutQueueCryptoContextCtrl(pcc);
1140 }
1141 }
1142 }
1143 // If no crypto context: then SRTP/SRTCP is off
1144 // If crypto context is available then unprotect data here. If an error
1145 // occurs report the error and discard the packet.
1146 if (pcc != NULL) {
1147 len = protect(buffer, len, pcc);
1148 }
1149
1150 if ( isSingleDestination() ) {
1151 count = sendControl(buffer,len);
1152 } else {
1153 // when no destination has been added, NULL == dest.
1154 for (std::list<TransportAddress*>::iterator i =
1155 destList.begin(); destList.end() != i; i++) {
1156 TransportAddress* dest = *i;
1157 setControlPeer(dest->getNetworkAddress(),
1158 dest->getControlTransportPort());
1159 count += sendControl(buffer,len);
1160 }
1161 }
1162 unlockDestinationList();
1163
1164 return count;
1165 }
1166
1167 int32
protect(uint8 * pkt,size_t len,CryptoContextCtrl * pcc)1168 QueueRTCPManager::protect(uint8* pkt, size_t len, CryptoContextCtrl* pcc) {
1169 /* Encrypt the packet */
1170
1171 uint32 ssrc = *(reinterpret_cast<uint32*>(pkt + 4)); // always SSRC of sender
1172 ssrc =ntohl(ssrc);
1173
1174 pcc->srtcpEncrypt(pkt + 8, len - 8, srtcpIndex, ssrc);
1175
1176 uint32 encIndex = srtcpIndex | 0x80000000; // set the E flag
1177
1178 uint32* ip = reinterpret_cast<uint32*>(pkt+len);
1179 *ip = htonl(encIndex);
1180
1181 // NO MKI support yet - here we assume MKI is zero. To build in MKI
1182 // take MKI length into account when storing the authentication tag.
1183
1184 // Compute MAC and store in packet after the SRTCP index field
1185 pcc->srtcpAuthenticate(pkt, len, encIndex, pkt + len + sizeof(uint32));
1186
1187 srtcpIndex++;
1188 srtcpIndex &= ~0x80000000; // clear possible overflow
1189
1190 return len + pcc->getTagLength() + sizeof(uint32);
1191 }
1192
1193 int32
unprotect(uint8 * pkt,size_t len,CryptoContextCtrl * pcc)1194 QueueRTCPManager::unprotect(uint8* pkt, size_t len, CryptoContextCtrl* pcc) {
1195 if (pcc == NULL) {
1196 return true;
1197 }
1198
1199 // Compute the total length of the payload
1200 uint32 payloadLen = len - (pcc->getTagLength() + pcc->getMkiLength() + 4);
1201
1202 // point to the SRTCP index field just after the real payload
1203 const uint32* index = reinterpret_cast<uint32*>(pkt + payloadLen);
1204 uint32 ssrc = *(reinterpret_cast<uint32*>(pkt + 4)); // always SSRC of sender
1205 ssrc =ntohl(ssrc);
1206
1207 uint32 encIndex = ntohl(*index);
1208 uint32 remoteIndex = encIndex & ~0x80000000; // index without Encryption flag
1209
1210 if (!pcc->checkReplay(remoteIndex)) {
1211 return -2;
1212 }
1213
1214 uint8 mac[20];
1215
1216 // Now get a pointer to the authentication tag field
1217 const uint8* tag = pkt + (len - pcc->getTagLength());
1218
1219 // Authenticate includes the index, but not MKI and not (obviously) the tag itself
1220 pcc->srtcpAuthenticate(pkt, payloadLen, encIndex, mac);
1221 if (memcmp(tag, mac, pcc->getTagLength()) != 0) {
1222 return -1;
1223 }
1224
1225 // Decrypt the content, exclude the very first SRTCP header (fixed, 8 bytes)
1226 if (encIndex & 0x80000000)
1227 pcc->srtcpEncrypt(pkt + 8, payloadLen - 8, remoteIndex, ssrc);
1228
1229 // Update the Crypto-context
1230 pcc->update(remoteIndex);
1231
1232 return payloadLen;
1233 }
1234
1235
1236 void
setOutQueueCryptoContextCtrl(CryptoContextCtrl * cc)1237 QueueRTCPManager::setOutQueueCryptoContextCtrl(CryptoContextCtrl* cc)
1238 {
1239 std::list<CryptoContextCtrl *>::iterator i;
1240
1241 MutexLock lock(outCryptoMutex);
1242 // check if a CryptoContext for a SSRC already exists. If yes
1243 // remove it from list before inserting the new one.
1244 for( i = outCryptoContexts.begin(); i!= outCryptoContexts.end(); i++ ) {
1245 if( (*i)->getSsrc() == cc->getSsrc() ) {
1246 CryptoContextCtrl* tmp = *i;
1247 outCryptoContexts.erase(i);
1248 delete tmp;
1249 break;
1250 }
1251 }
1252 outCryptoContexts.push_back(cc);
1253 }
1254
1255 void
removeOutQueueCryptoContextCtrl(CryptoContextCtrl * cc)1256 QueueRTCPManager::removeOutQueueCryptoContextCtrl(CryptoContextCtrl* cc)
1257 {
1258 std::list<CryptoContextCtrl *>::iterator i;
1259
1260 MutexLock lock(outCryptoMutex);
1261 if (cc == NULL) { // Remove any incoming crypto contexts
1262 for (i = outCryptoContexts.begin(); i != outCryptoContexts.end(); ) {
1263 CryptoContextCtrl* tmp = *i;
1264 i = outCryptoContexts.erase(i);
1265 delete tmp;
1266 }
1267 }
1268 else {
1269 for( i = outCryptoContexts.begin(); i != outCryptoContexts.end(); i++ ) {
1270 if( (*i)->getSsrc() == cc->getSsrc() ) {
1271 CryptoContextCtrl* tmp = *i;
1272 outCryptoContexts.erase(i);
1273 delete tmp;
1274 return;
1275 }
1276 }
1277 }
1278 }
1279
1280 CryptoContextCtrl*
getOutQueueCryptoContextCtrl(uint32 ssrc)1281 QueueRTCPManager::getOutQueueCryptoContextCtrl(uint32 ssrc)
1282 {
1283 std::list<CryptoContextCtrl *>::iterator i;
1284
1285 MutexLock lock(outCryptoMutex);
1286 for( i = outCryptoContexts.begin(); i != outCryptoContexts.end(); i++ ){
1287 if( (*i)->getSsrc() == ssrc) {
1288 return (*i);
1289 }
1290 }
1291 return NULL;
1292 }
1293
1294 void
setInQueueCryptoContextCtrl(CryptoContextCtrl * cc)1295 QueueRTCPManager::setInQueueCryptoContextCtrl(CryptoContextCtrl* cc)
1296 {
1297 std::list<CryptoContextCtrl *>::iterator i;
1298
1299 MutexLock lock(inCryptoMutex);
1300 // check if a CryptoContext for a SSRC already exists. If yes
1301 // remove it from list before inserting the new one.
1302 for( i = inCryptoContexts.begin(); i!= inCryptoContexts.end(); i++ ) {
1303 if( (*i)->getSsrc() == cc->getSsrc() ) {
1304 CryptoContextCtrl* tmp = *i;
1305 inCryptoContexts.erase(i);
1306 delete tmp;
1307 break;
1308 }
1309 }
1310 inCryptoContexts.push_back(cc);
1311 }
1312
1313 void
removeInQueueCryptoContextCtrl(CryptoContextCtrl * cc)1314 QueueRTCPManager::removeInQueueCryptoContextCtrl(CryptoContextCtrl* cc)
1315 {
1316 std::list<CryptoContextCtrl *>::iterator i;
1317
1318 MutexLock lock(inCryptoMutex);
1319 if (cc == NULL) { // Remove any incoming crypto contexts
1320 for (i = inCryptoContexts.begin(); i != inCryptoContexts.end(); ) {
1321 CryptoContextCtrl* tmp = *i;
1322 i = inCryptoContexts.erase(i);
1323 delete tmp;
1324 }
1325 }
1326 else {
1327 for( i = inCryptoContexts.begin(); i!= inCryptoContexts.end(); i++ ){
1328 if( (*i)->getSsrc() == cc->getSsrc() ) {
1329 CryptoContextCtrl* tmp = *i;
1330 inCryptoContexts.erase(i);
1331 delete tmp;
1332 return;
1333 }
1334 }
1335 }
1336 }
1337
1338 CryptoContextCtrl*
getInQueueCryptoContextCtrl(uint32 ssrc)1339 QueueRTCPManager::getInQueueCryptoContextCtrl(uint32 ssrc)
1340 {
1341 std::list<CryptoContextCtrl *>::iterator i;
1342
1343 MutexLock lock(inCryptoMutex);
1344 for( i = inCryptoContexts.begin(); i!= inCryptoContexts.end(); i++ ){
1345 if( (*i)->getSsrc() == ssrc) {
1346 return (*i);
1347 }
1348 }
1349 return NULL;
1350 }
1351
1352 END_NAMESPACE
1353
1354 /** EMACS **
1355 * Local variables:
1356 * mode: c++
1357 * c-basic-offset: 4
1358 * End:
1359 */
1360