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