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