| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // "liveMedia" |
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| 18 | // RTCP |
| 19 | // Implementation |
| 20 | |
| 21 | #include "RTCP.hh" |
| 22 | #include "GroupsockHelper.hh" |
| 23 | #include "rtcp_from_spec.h" |
| 24 | #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) |
| 25 | #define snprintf _snprintf |
| 26 | #endif |
| 27 | |
| 28 | ////////// RTCPMemberDatabase ////////// |
| 29 | |
| 30 | class RTCPMemberDatabase { |
| 31 | public: |
| 32 | RTCPMemberDatabase(RTCPInstance& ourRTCPInstance) |
| 33 | : fOurRTCPInstance(ourRTCPInstance), fNumMembers(1 /*ourself*/), |
| 34 | fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { |
| 35 | } |
| 36 | |
| 37 | virtual ~RTCPMemberDatabase() { |
| 38 | delete fTable; |
| 39 | } |
| 40 | |
| 41 | Boolean isMember(u_int32_t ssrc) const { |
| 42 | return fTable->Lookup((char*)(long)ssrc) != NULL; |
| 43 | } |
| 44 | |
| 45 | Boolean noteMembership(u_int32_t ssrc, unsigned curTimeCount) { |
| 46 | Boolean isNew = !isMember(ssrc); |
| 47 | |
| 48 | if (isNew) { |
| 49 | ++fNumMembers; |
| 50 | } |
| 51 | |
| 52 | // Record the current time, so we can age stale members |
| 53 | fTable->Add((char*)(long)ssrc, (void*)(long)curTimeCount); |
| 54 | |
| 55 | return isNew; |
| 56 | } |
| 57 | |
| 58 | Boolean remove(u_int32_t ssrc) { |
| 59 | Boolean wasPresent = fTable->Remove((char*)(long)ssrc); |
| 60 | if (wasPresent) { |
| 61 | --fNumMembers; |
| 62 | } |
| 63 | return wasPresent; |
| 64 | } |
| 65 | |
| 66 | unsigned numMembers() const { |
| 67 | return fNumMembers; |
| 68 | } |
| 69 | |
| 70 | void reapOldMembers(unsigned threshold); |
| 71 | |
| 72 | private: |
| 73 | RTCPInstance& fOurRTCPInstance; |
| 74 | unsigned fNumMembers; |
| 75 | HashTable* fTable; |
| 76 | }; |
| 77 | |
| 78 | void RTCPMemberDatabase::reapOldMembers(unsigned threshold) { |
| 79 | Boolean foundOldMember; |
| 80 | u_int32_t oldSSRC = 0; |
| 81 | |
| 82 | do { |
| 83 | foundOldMember = False; |
| 84 | |
| 85 | HashTable::Iterator* iter |
| 86 | = HashTable::Iterator::create(*fTable); |
| 87 | uintptr_t timeCount; |
| 88 | char const* key; |
| 89 | while ((timeCount = (uintptr_t)(iter->next(key))) != 0) { |
| 90 | #ifdef DEBUG |
| 91 | fprintf(stderr, "reap: checking SSRC 0x%lx: %ld (threshold %d)\n" , (unsigned long)key, timeCount, threshold); |
| 92 | #endif |
| 93 | if (timeCount < (uintptr_t)threshold) { // this SSRC is old |
| 94 | uintptr_t ssrc = (uintptr_t)key; |
| 95 | oldSSRC = (u_int32_t)ssrc; |
| 96 | foundOldMember = True; |
| 97 | } |
| 98 | } |
| 99 | delete iter; |
| 100 | |
| 101 | if (foundOldMember) { |
| 102 | #ifdef DEBUG |
| 103 | fprintf(stderr, "reap: removing SSRC 0x%x\n" , oldSSRC); |
| 104 | #endif |
| 105 | fOurRTCPInstance.removeSSRC(oldSSRC, True); |
| 106 | } |
| 107 | } while (foundOldMember); |
| 108 | } |
| 109 | |
| 110 | |
| 111 | ////////// RTCPInstance ////////// |
| 112 | |
| 113 | static double dTimeNow() { |
| 114 | struct timeval timeNow; |
| 115 | gettimeofday(&timeNow, NULL); |
| 116 | return (double) (timeNow.tv_sec + timeNow.tv_usec/1000000.0); |
| 117 | } |
| 118 | |
| 119 | static unsigned const maxRTCPPacketSize = 1456; |
| 120 | // bytes (1500, minus some allowance for IP, UDP, UMTP headers) |
| 121 | static unsigned const preferredRTCPPacketSize = 1000; // bytes |
| 122 | |
| 123 | RTCPInstance::RTCPInstance(UsageEnvironment& env, Groupsock* RTCPgs, |
| 124 | unsigned totSessionBW, |
| 125 | unsigned char const* cname, |
| 126 | RTPSink* sink, RTPSource* source, |
| 127 | Boolean isSSMSource) |
| 128 | : Medium(env), fRTCPInterface(this, RTCPgs), fTotSessionBW(totSessionBW), |
| 129 | fSink(sink), fSource(source), fIsSSMSource(isSSMSource), |
| 130 | fCNAME(RTCP_SDES_CNAME, cname), fOutgoingReportCount(1), |
| 131 | fAveRTCPSize(0), fIsInitial(1), fPrevNumMembers(0), |
| 132 | fLastSentSize(0), fLastReceivedSize(0), fLastReceivedSSRC(0), |
| 133 | fTypeOfEvent(EVENT_UNKNOWN), fTypeOfPacket(PACKET_UNKNOWN_TYPE), |
| 134 | fHaveJustSentPacket(False), fLastPacketSentSize(0), |
| 135 | fByeHandlerTask(NULL), fByeWithReasonHandlerTask(NULL), fByeHandlerClientData(NULL), |
| 136 | fSRHandlerTask(NULL), fSRHandlerClientData(NULL), |
| 137 | fRRHandlerTask(NULL), fRRHandlerClientData(NULL), |
| 138 | fSpecificRRHandlerTable(NULL), |
| 139 | fAppHandlerTask(NULL), fAppHandlerClientData(NULL) { |
| 140 | #ifdef DEBUG |
| 141 | fprintf(stderr, "RTCPInstance[%p]::RTCPInstance()\n" , this); |
| 142 | #endif |
| 143 | if (fTotSessionBW == 0) { // not allowed! |
| 144 | env << "RTCPInstance::RTCPInstance error: totSessionBW parameter should not be zero!\n" ; |
| 145 | fTotSessionBW = 1; |
| 146 | } |
| 147 | |
| 148 | if (isSSMSource) RTCPgs->multicastSendOnly(); // don't receive multicast |
| 149 | |
| 150 | double timeNow = dTimeNow(); |
| 151 | fPrevReportTime = fNextReportTime = timeNow; |
| 152 | |
| 153 | fKnownMembers = new RTCPMemberDatabase(*this); |
| 154 | fInBuf = new unsigned char[maxRTCPPacketSize]; |
| 155 | if (fKnownMembers == NULL || fInBuf == NULL) return; |
| 156 | fNumBytesAlreadyRead = 0; |
| 157 | |
| 158 | fOutBuf = new OutPacketBuffer(preferredRTCPPacketSize, maxRTCPPacketSize, maxRTCPPacketSize); |
| 159 | if (fOutBuf == NULL) return; |
| 160 | |
| 161 | if (fSource != NULL && fSource->RTPgs() == RTCPgs) { |
| 162 | // We're receiving RTCP reports that are multiplexed with RTP, so ask the RTP source |
| 163 | // to give them to us: |
| 164 | fSource->registerForMultiplexedRTCPPackets(this); |
| 165 | } else { |
| 166 | // Arrange to handle incoming reports from the network: |
| 167 | TaskScheduler::BackgroundHandlerProc* handler |
| 168 | = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; |
| 169 | fRTCPInterface.startNetworkReading(handler); |
| 170 | } |
| 171 | |
| 172 | // Send our first report. |
| 173 | fTypeOfEvent = EVENT_REPORT; |
| 174 | onExpire(this); |
| 175 | } |
| 176 | |
| 177 | struct RRHandlerRecord { |
| 178 | TaskFunc* rrHandlerTask; |
| 179 | void* rrHandlerClientData; |
| 180 | }; |
| 181 | |
| 182 | RTCPInstance::~RTCPInstance() { |
| 183 | #ifdef DEBUG |
| 184 | fprintf(stderr, "RTCPInstance[%p]::~RTCPInstance()\n" , this); |
| 185 | #endif |
| 186 | // Begin by sending a BYE. We have to do this immediately, without |
| 187 | // 'reconsideration', because "this" is going away. |
| 188 | fTypeOfEvent = EVENT_BYE; // not used, but... |
| 189 | sendBYE(); |
| 190 | |
| 191 | if (fSource != NULL && fSource->RTPgs() == fRTCPInterface.gs()) { |
| 192 | // We were receiving RTCP reports that were multiplexed with RTP, so tell the RTP source |
| 193 | // to stop giving them to us: |
| 194 | fSource->deregisterForMultiplexedRTCPPackets(); |
| 195 | fRTCPInterface.forgetOurGroupsock(); |
| 196 | // so that the "fRTCPInterface" destructor doesn't turn off background read handling |
| 197 | } |
| 198 | |
| 199 | if (fSpecificRRHandlerTable != NULL) { |
| 200 | AddressPortLookupTable::Iterator iter(*fSpecificRRHandlerTable); |
| 201 | RRHandlerRecord* rrHandler; |
| 202 | while ((rrHandler = (RRHandlerRecord*)iter.next()) != NULL) { |
| 203 | delete rrHandler; |
| 204 | } |
| 205 | delete fSpecificRRHandlerTable; |
| 206 | } |
| 207 | |
| 208 | delete fKnownMembers; |
| 209 | delete fOutBuf; |
| 210 | delete[] fInBuf; |
| 211 | } |
| 212 | |
| 213 | void RTCPInstance::noteArrivingRR(struct sockaddr_in const& fromAddressAndPort, |
| 214 | int tcpSocketNum, unsigned char tcpStreamChannelId) { |
| 215 | // If a 'RR handler' was set, call it now: |
| 216 | |
| 217 | // Specific RR handler: |
| 218 | if (fSpecificRRHandlerTable != NULL) { |
| 219 | netAddressBits fromAddr; |
| 220 | portNumBits fromPortNum; |
| 221 | if (tcpSocketNum < 0) { |
| 222 | // Normal case: We read the RTCP packet over UDP |
| 223 | fromAddr = fromAddressAndPort.sin_addr.s_addr; |
| 224 | fromPortNum = ntohs(fromAddressAndPort.sin_port); |
| 225 | } else { |
| 226 | // Special case: We read the RTCP packet over TCP (interleaved) |
| 227 | // Hack: Use the TCP socket and channel id to look up the handler |
| 228 | fromAddr = tcpSocketNum; |
| 229 | fromPortNum = tcpStreamChannelId; |
| 230 | } |
| 231 | Port fromPort(fromPortNum); |
| 232 | RRHandlerRecord* rrHandler |
| 233 | = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddr, (~0), fromPort)); |
| 234 | if (rrHandler != NULL) { |
| 235 | if (rrHandler->rrHandlerTask != NULL) { |
| 236 | (*(rrHandler->rrHandlerTask))(rrHandler->rrHandlerClientData); |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | // General RR handler: |
| 242 | if (fRRHandlerTask != NULL) (*fRRHandlerTask)(fRRHandlerClientData); |
| 243 | } |
| 244 | |
| 245 | RTCPInstance* RTCPInstance::createNew(UsageEnvironment& env, Groupsock* RTCPgs, |
| 246 | unsigned totSessionBW, |
| 247 | unsigned char const* cname, |
| 248 | RTPSink* sink, RTPSource* source, |
| 249 | Boolean isSSMSource) { |
| 250 | return new RTCPInstance(env, RTCPgs, totSessionBW, cname, sink, source, |
| 251 | isSSMSource); |
| 252 | } |
| 253 | |
| 254 | Boolean RTCPInstance::lookupByName(UsageEnvironment& env, |
| 255 | char const* instanceName, |
| 256 | RTCPInstance*& resultInstance) { |
| 257 | resultInstance = NULL; // unless we succeed |
| 258 | |
| 259 | Medium* medium; |
| 260 | if (!Medium::lookupByName(env, instanceName, medium)) return False; |
| 261 | |
| 262 | if (!medium->isRTCPInstance()) { |
| 263 | env.setResultMsg(instanceName, " is not a RTCP instance" ); |
| 264 | return False; |
| 265 | } |
| 266 | |
| 267 | resultInstance = (RTCPInstance*)medium; |
| 268 | return True; |
| 269 | } |
| 270 | |
| 271 | Boolean RTCPInstance::isRTCPInstance() const { |
| 272 | return True; |
| 273 | } |
| 274 | |
| 275 | unsigned RTCPInstance::numMembers() const { |
| 276 | if (fKnownMembers == NULL) return 0; |
| 277 | |
| 278 | return fKnownMembers->numMembers(); |
| 279 | } |
| 280 | |
| 281 | void RTCPInstance::setByeHandler(TaskFunc* handlerTask, void* clientData, |
| 282 | Boolean handleActiveParticipantsOnly) { |
| 283 | fByeHandlerTask = handlerTask; |
| 284 | fByeWithReasonHandlerTask = NULL; |
| 285 | fByeHandlerClientData = clientData; |
| 286 | fByeHandleActiveParticipantsOnly = handleActiveParticipantsOnly; |
| 287 | } |
| 288 | |
| 289 | void RTCPInstance::setByeWithReasonHandler(ByeWithReasonHandlerFunc* handlerTask, void* clientData, |
| 290 | Boolean handleActiveParticipantsOnly) { |
| 291 | fByeHandlerTask = NULL; |
| 292 | fByeWithReasonHandlerTask = handlerTask; |
| 293 | fByeHandlerClientData = clientData; |
| 294 | fByeHandleActiveParticipantsOnly = handleActiveParticipantsOnly; |
| 295 | } |
| 296 | |
| 297 | void RTCPInstance::setSRHandler(TaskFunc* handlerTask, void* clientData) { |
| 298 | fSRHandlerTask = handlerTask; |
| 299 | fSRHandlerClientData = clientData; |
| 300 | } |
| 301 | |
| 302 | void RTCPInstance::setRRHandler(TaskFunc* handlerTask, void* clientData) { |
| 303 | fRRHandlerTask = handlerTask; |
| 304 | fRRHandlerClientData = clientData; |
| 305 | } |
| 306 | |
| 307 | void RTCPInstance |
| 308 | ::setSpecificRRHandler(netAddressBits fromAddress, Port fromPort, |
| 309 | TaskFunc* handlerTask, void* clientData) { |
| 310 | if (handlerTask == NULL && clientData == NULL) { |
| 311 | unsetSpecificRRHandler(fromAddress, fromPort); |
| 312 | return; |
| 313 | } |
| 314 | |
| 315 | RRHandlerRecord* rrHandler = new RRHandlerRecord; |
| 316 | rrHandler->rrHandlerTask = handlerTask; |
| 317 | rrHandler->rrHandlerClientData = clientData; |
| 318 | if (fSpecificRRHandlerTable == NULL) { |
| 319 | fSpecificRRHandlerTable = new AddressPortLookupTable; |
| 320 | } |
| 321 | RRHandlerRecord* existingRecord = (RRHandlerRecord*)fSpecificRRHandlerTable->Add(fromAddress, (~0), fromPort, rrHandler); |
| 322 | delete existingRecord; // if any |
| 323 | |
| 324 | } |
| 325 | |
| 326 | void RTCPInstance |
| 327 | ::unsetSpecificRRHandler(netAddressBits fromAddress, Port fromPort) { |
| 328 | if (fSpecificRRHandlerTable == NULL) return; |
| 329 | |
| 330 | RRHandlerRecord* rrHandler |
| 331 | = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddress, (~0), fromPort)); |
| 332 | if (rrHandler != NULL) { |
| 333 | fSpecificRRHandlerTable->Remove(fromAddress, (~0), fromPort); |
| 334 | delete rrHandler; |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | void RTCPInstance::setAppHandler(RTCPAppHandlerFunc* handlerTask, void* clientData) { |
| 339 | fAppHandlerTask = handlerTask; |
| 340 | fAppHandlerClientData = clientData; |
| 341 | } |
| 342 | |
| 343 | void RTCPInstance::sendAppPacket(u_int8_t subtype, char const* name, |
| 344 | u_int8_t* appDependentData, unsigned appDependentDataSize) { |
| 345 | // Set up the first 4 bytes: V,PT,subtype,PT,length: |
| 346 | u_int32_t rtcpHdr = 0x80000000; // version 2, no padding |
| 347 | rtcpHdr |= (subtype&0x1F)<<24; |
| 348 | rtcpHdr |= (RTCP_PT_APP<<16); |
| 349 | unsigned length = 2 + (appDependentDataSize+3)/4; |
| 350 | rtcpHdr |= (length&0xFFFF); |
| 351 | fOutBuf->enqueueWord(rtcpHdr); |
| 352 | |
| 353 | // Set up the next 4 bytes: SSRC: |
| 354 | fOutBuf->enqueueWord(fSource != NULL ? fSource->SSRC() : fSink != NULL ? fSink->SSRC() : 0); |
| 355 | |
| 356 | // Set up the next 4 bytes: name: |
| 357 | char nameBytes[4]; |
| 358 | nameBytes[0] = nameBytes[1] = nameBytes[2] = nameBytes[3] = '\0'; // by default |
| 359 | if (name != NULL) { |
| 360 | snprintf(nameBytes, 4, "%s" , name); |
| 361 | } |
| 362 | fOutBuf->enqueue((u_int8_t*)nameBytes, 4); |
| 363 | |
| 364 | // Set up the remaining bytes (if any): application-dependent data (+ padding): |
| 365 | if (appDependentData != NULL && appDependentDataSize > 0) { |
| 366 | fOutBuf->enqueue(appDependentData, appDependentDataSize); |
| 367 | |
| 368 | unsigned modulo = appDependentDataSize%4; |
| 369 | unsigned paddingSize = modulo == 0 ? 0 : 4-modulo; |
| 370 | u_int8_t const paddingByte = 0x00; |
| 371 | for (unsigned i = 0; i < paddingSize; ++i) fOutBuf->enqueue(&paddingByte, 1); |
| 372 | } |
| 373 | |
| 374 | // Finally, send the packet: |
| 375 | sendBuiltPacket(); |
| 376 | } |
| 377 | |
| 378 | void RTCPInstance::setStreamSocket(int sockNum, |
| 379 | unsigned char streamChannelId) { |
| 380 | // Turn off background read handling: |
| 381 | fRTCPInterface.stopNetworkReading(); |
| 382 | |
| 383 | // Switch to RTCP-over-TCP: |
| 384 | fRTCPInterface.setStreamSocket(sockNum, streamChannelId); |
| 385 | |
| 386 | // Turn background reading back on: |
| 387 | TaskScheduler::BackgroundHandlerProc* handler |
| 388 | = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; |
| 389 | fRTCPInterface.startNetworkReading(handler); |
| 390 | } |
| 391 | |
| 392 | void RTCPInstance::addStreamSocket(int sockNum, |
| 393 | unsigned char streamChannelId) { |
| 394 | // First, turn off background read handling for the default (UDP) socket: |
| 395 | envir().taskScheduler().turnOffBackgroundReadHandling(fRTCPInterface.gs()->socketNum()); |
| 396 | |
| 397 | // Add the RTCP-over-TCP interface: |
| 398 | fRTCPInterface.addStreamSocket(sockNum, streamChannelId); |
| 399 | |
| 400 | // Turn on background reading for this socket (in case it's not on already): |
| 401 | TaskScheduler::BackgroundHandlerProc* handler |
| 402 | = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; |
| 403 | fRTCPInterface.startNetworkReading(handler); |
| 404 | } |
| 405 | |
| 406 | void RTCPInstance |
| 407 | ::injectReport(u_int8_t const* packet, unsigned packetSize, struct sockaddr_in const& fromAddress) { |
| 408 | if (packetSize > maxRTCPPacketSize) packetSize = maxRTCPPacketSize; |
| 409 | memmove(fInBuf, packet, packetSize); |
| 410 | |
| 411 | processIncomingReport(packetSize, fromAddress, -1, 0xFF); // assume report received over UDP |
| 412 | } |
| 413 | |
| 414 | static unsigned const IP_UDP_HDR_SIZE = 28; |
| 415 | // overhead (bytes) of IP and UDP hdrs |
| 416 | |
| 417 | #define ADVANCE(n) pkt += (n); packetSize -= (n) |
| 418 | |
| 419 | void RTCPInstance::incomingReportHandler(RTCPInstance* instance, |
| 420 | int /*mask*/) { |
| 421 | instance->incomingReportHandler1(); |
| 422 | } |
| 423 | |
| 424 | void RTCPInstance::incomingReportHandler1() { |
| 425 | do { |
| 426 | if (fNumBytesAlreadyRead >= maxRTCPPacketSize) { |
| 427 | envir() << "RTCPInstance error: Hit limit when reading incoming packet over TCP. (fNumBytesAlreadyRead (" |
| 428 | << fNumBytesAlreadyRead << ") >= maxRTCPPacketSize (" << maxRTCPPacketSize |
| 429 | << ")). The remote endpoint is using a buggy implementation of RTP/RTCP-over-TCP. Please upgrade it!\n" ; |
| 430 | break; |
| 431 | } |
| 432 | |
| 433 | unsigned numBytesRead; |
| 434 | struct sockaddr_in fromAddress; |
| 435 | int tcpSocketNum; |
| 436 | unsigned char tcpStreamChannelId; |
| 437 | Boolean packetReadWasIncomplete; |
| 438 | Boolean readResult |
| 439 | = fRTCPInterface.handleRead(&fInBuf[fNumBytesAlreadyRead], maxRTCPPacketSize - fNumBytesAlreadyRead, |
| 440 | numBytesRead, fromAddress, |
| 441 | tcpSocketNum, tcpStreamChannelId, |
| 442 | packetReadWasIncomplete); |
| 443 | |
| 444 | unsigned packetSize = 0; |
| 445 | if (packetReadWasIncomplete) { |
| 446 | fNumBytesAlreadyRead += numBytesRead; |
| 447 | return; // more reads are needed to get the entire packet |
| 448 | } else { // normal case: We've read the entire packet |
| 449 | packetSize = fNumBytesAlreadyRead + numBytesRead; |
| 450 | fNumBytesAlreadyRead = 0; // for next time |
| 451 | } |
| 452 | if (!readResult) break; |
| 453 | |
| 454 | // Ignore the packet if it was looped-back from ourself: |
| 455 | Boolean packetWasFromOurHost = False; |
| 456 | if (RTCPgs()->wasLoopedBackFromUs(envir(), fromAddress)) { |
| 457 | packetWasFromOurHost = True; |
| 458 | // However, we still want to handle incoming RTCP packets from |
| 459 | // *other processes* on the same machine. To distinguish this |
| 460 | // case from a true loop-back, check whether we've just sent a |
| 461 | // packet of the same size. (This check isn't perfect, but it seems |
| 462 | // to be the best we can do.) |
| 463 | if (fHaveJustSentPacket && fLastPacketSentSize == packetSize) { |
| 464 | // This is a true loop-back: |
| 465 | fHaveJustSentPacket = False; |
| 466 | break; // ignore this packet |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | if (fIsSSMSource && !packetWasFromOurHost) { |
| 471 | // This packet is assumed to have been received via unicast (because we're a SSM source, |
| 472 | // and SSM receivers send back RTCP "RR" packets via unicast). |
| 473 | // 'Reflect' the packet by resending it to the multicast group, so that any other receivers |
| 474 | // can also get to see it. |
| 475 | |
| 476 | // NOTE: Denial-of-service attacks are possible here. |
| 477 | // Users of this software may wish to add their own, |
| 478 | // application-specific mechanism for 'authenticating' the |
| 479 | // validity of this packet before reflecting it. |
| 480 | |
| 481 | // NOTE: The test for "!packetWasFromOurHost" means that we won't reflect RTCP packets |
| 482 | // that come from other processes on the same host as us. The reason for this is that the |
| 483 | // 'packet size' test above is not 100% reliable; some packets that were truly looped back |
| 484 | // from us might not be detected as such, and this might lead to infinite |
| 485 | // forwarding/receiving of some packets. To avoid this possibility, we reflect only |
| 486 | // RTCP packets that we know for sure originated elsewhere. |
| 487 | // (Note, though, that if we ever re-enable the code in "Groupsock::multicastSendOnly()", |
| 488 | // then we could remove the test for "!packetWasFromOurHost".) |
| 489 | fRTCPInterface.sendPacket(fInBuf, packetSize); |
| 490 | fHaveJustSentPacket = True; |
| 491 | fLastPacketSentSize = packetSize; |
| 492 | } |
| 493 | |
| 494 | processIncomingReport(packetSize, fromAddress, tcpSocketNum, tcpStreamChannelId); |
| 495 | } while (0); |
| 496 | } |
| 497 | |
| 498 | void RTCPInstance |
| 499 | ::processIncomingReport(unsigned packetSize, struct sockaddr_in const& fromAddressAndPort, |
| 500 | int tcpSocketNum, unsigned char tcpStreamChannelId) { |
| 501 | do { |
| 502 | Boolean callByeHandler = False; |
| 503 | char* reason = NULL; // by default, unless/until a BYE packet with a 'reason' arrives |
| 504 | unsigned char* pkt = fInBuf; |
| 505 | |
| 506 | #ifdef DEBUG |
| 507 | fprintf(stderr, "[%p]saw incoming RTCP packet (from " , this); |
| 508 | if (tcpSocketNum < 0) { |
| 509 | // Note that "fromAddressAndPort" is valid only if we're receiving over UDP (not over TCP): |
| 510 | fprintf(stderr, "address %s, port %d" , AddressString(fromAddressAndPort).val(), ntohs(fromAddressAndPort.sin_port)); |
| 511 | } else { |
| 512 | fprintf(stderr, "TCP socket #%d, stream channel id %d" , tcpSocketNum, tcpStreamChannelId); |
| 513 | } |
| 514 | fprintf(stderr, ")\n" ); |
| 515 | for (unsigned i = 0; i < packetSize; ++i) { |
| 516 | if (i%4 == 0) fprintf(stderr, " " ); |
| 517 | fprintf(stderr, "%02x" , pkt[i]); |
| 518 | } |
| 519 | fprintf(stderr, "\n" ); |
| 520 | #endif |
| 521 | int totPacketSize = IP_UDP_HDR_SIZE + packetSize; |
| 522 | |
| 523 | // Check the RTCP packet for validity: |
| 524 | // It must at least contain a header (4 bytes), and this header |
| 525 | // must be version=2, with no padding bit, and a payload type of |
| 526 | // SR (200), RR (201), or APP (204): |
| 527 | if (packetSize < 4) break; |
| 528 | unsigned rtcpHdr = ntohl(*(u_int32_t*)pkt); |
| 529 | if ((rtcpHdr & 0xE0FE0000) != (0x80000000 | (RTCP_PT_SR<<16)) && |
| 530 | (rtcpHdr & 0xE0FF0000) != (0x80000000 | (RTCP_PT_APP<<16))) { |
| 531 | #ifdef DEBUG |
| 532 | fprintf(stderr, "rejected bad RTCP packet: header 0x%08x\n" , rtcpHdr); |
| 533 | #endif |
| 534 | break; |
| 535 | } |
| 536 | |
| 537 | // Process each of the individual RTCP 'subpackets' in (what may be) |
| 538 | // a compound RTCP packet. |
| 539 | int typeOfPacket = PACKET_UNKNOWN_TYPE; |
| 540 | unsigned = 0; |
| 541 | Boolean packetOK = False; |
| 542 | while (1) { |
| 543 | u_int8_t rc = (rtcpHdr>>24)&0x1F; |
| 544 | u_int8_t pt = (rtcpHdr>>16)&0xFF; |
| 545 | unsigned length = 4*(rtcpHdr&0xFFFF); // doesn't count hdr |
| 546 | ADVANCE(4); // skip over the header |
| 547 | if (length > packetSize) break; |
| 548 | |
| 549 | // Assume that each RTCP subpacket begins with a 4-byte SSRC: |
| 550 | if (length < 4) break; length -= 4; |
| 551 | reportSenderSSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 552 | #ifdef HACK_FOR_CHROME_WEBRTC_BUG |
| 553 | if (reportSenderSSRC == 0x00000001 && pt == RTCP_PT_RR) { |
| 554 | // Chrome (and Opera) WebRTC receivers have a bug that causes them to always send |
| 555 | // SSRC 1 in their "RR"s. To work around this (to help us distinguish between different |
| 556 | // receivers), we use a fake SSRC in this case consisting of the IP address, XORed with |
| 557 | // the port number: |
| 558 | reportSenderSSRC = fromAddressAndPort.sin_addr.s_addr^fromAddressAndPort.sin_port; |
| 559 | } |
| 560 | #endif |
| 561 | |
| 562 | Boolean subPacketOK = False; |
| 563 | switch (pt) { |
| 564 | case RTCP_PT_SR: { |
| 565 | #ifdef DEBUG |
| 566 | fprintf(stderr, "SR\n" ); |
| 567 | #endif |
| 568 | if (length < 20) break; length -= 20; |
| 569 | |
| 570 | // Extract the NTP timestamp, and note this: |
| 571 | unsigned NTPmsw = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 572 | unsigned NTPlsw = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 573 | unsigned rtpTimestamp = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 574 | if (fSource != NULL) { |
| 575 | RTPReceptionStatsDB& receptionStats |
| 576 | = fSource->receptionStatsDB(); |
| 577 | receptionStats.noteIncomingSR(reportSenderSSRC, |
| 578 | NTPmsw, NTPlsw, rtpTimestamp); |
| 579 | } |
| 580 | ADVANCE(8); // skip over packet count, octet count |
| 581 | |
| 582 | // If a 'SR handler' was set, call it now: |
| 583 | if (fSRHandlerTask != NULL) (*fSRHandlerTask)(fSRHandlerClientData); |
| 584 | |
| 585 | // The rest of the SR is handled like a RR (so, no "break;" here) |
| 586 | } |
| 587 | case RTCP_PT_RR: { |
| 588 | #ifdef DEBUG |
| 589 | fprintf(stderr, "RR\n" ); |
| 590 | #endif |
| 591 | unsigned reportBlocksSize = rc*(6*4); |
| 592 | if (length < reportBlocksSize) break; |
| 593 | length -= reportBlocksSize; |
| 594 | |
| 595 | if (fSink != NULL) { |
| 596 | // Use this information to update stats about our transmissions: |
| 597 | RTPTransmissionStatsDB& transmissionStats = fSink->transmissionStatsDB(); |
| 598 | for (unsigned i = 0; i < rc; ++i) { |
| 599 | unsigned = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 600 | // We care only about reports about our own transmission, not others' |
| 601 | if (senderSSRC == fSink->SSRC()) { |
| 602 | unsigned lossStats = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 603 | unsigned highestReceived = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 604 | unsigned jitter = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 605 | unsigned timeLastSR = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 606 | unsigned timeSinceLastSR = ntohl(*(u_int32_t*)pkt); ADVANCE(4); |
| 607 | transmissionStats.noteIncomingRR(reportSenderSSRC, fromAddressAndPort, |
| 608 | lossStats, |
| 609 | highestReceived, jitter, |
| 610 | timeLastSR, timeSinceLastSR); |
| 611 | } else { |
| 612 | ADVANCE(4*5); |
| 613 | } |
| 614 | } |
| 615 | } else { |
| 616 | ADVANCE(reportBlocksSize); |
| 617 | } |
| 618 | |
| 619 | if (pt == RTCP_PT_RR) { // i.e., we didn't fall through from 'SR' |
| 620 | noteArrivingRR(fromAddressAndPort, tcpSocketNum, tcpStreamChannelId); |
| 621 | } |
| 622 | |
| 623 | subPacketOK = True; |
| 624 | typeOfPacket = PACKET_RTCP_REPORT; |
| 625 | break; |
| 626 | } |
| 627 | case RTCP_PT_BYE: { |
| 628 | #ifdef DEBUG |
| 629 | fprintf(stderr, "BYE" ); |
| 630 | #endif |
| 631 | // Check whether there was a 'reason for leaving': |
| 632 | if (length > 0) { |
| 633 | u_int8_t reasonLength = *pkt; |
| 634 | if (reasonLength > length-1) { |
| 635 | // The 'reason' length field is too large! |
| 636 | #ifdef DEBUG |
| 637 | fprintf(stderr, "\nError: The 'reason' length %d is too large (it should be <= %d)\n" , |
| 638 | reasonLength, length-1); |
| 639 | #endif |
| 640 | reasonLength = length-1; |
| 641 | } |
| 642 | reason = new char[reasonLength + 1]; |
| 643 | for (unsigned i = 0; i < reasonLength; ++i) { |
| 644 | reason[i] = pkt[1+i]; |
| 645 | } |
| 646 | reason[reasonLength] = '\0'; |
| 647 | #ifdef DEBUG |
| 648 | fprintf(stderr, " (reason:%s)" , reason); |
| 649 | #endif |
| 650 | } |
| 651 | #ifdef DEBUG |
| 652 | fprintf(stderr, "\n" ); |
| 653 | #endif |
| 654 | // If a 'BYE handler' was set, arrange for it to be called at the end of this routine. |
| 655 | // (Note: We don't call it immediately, in case it happens to cause "this" to be deleted.) |
| 656 | if ((fByeHandlerTask != NULL || fByeWithReasonHandlerTask != NULL) |
| 657 | && (!fByeHandleActiveParticipantsOnly |
| 658 | || (fSource != NULL |
| 659 | && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL) |
| 660 | || (fSink != NULL |
| 661 | && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) { |
| 662 | callByeHandler = True; |
| 663 | } |
| 664 | |
| 665 | // We should really check for & handle >1 SSRCs being present ##### |
| 666 | |
| 667 | subPacketOK = True; |
| 668 | typeOfPacket = PACKET_BYE; |
| 669 | break; |
| 670 | } |
| 671 | case RTCP_PT_APP: { |
| 672 | u_int8_t& subtype = rc; // In "APP" packets, the "rc" field gets used as "subtype" |
| 673 | #ifdef DEBUG |
| 674 | fprintf(stderr, "APP (subtype 0x%02x)\n" , subtype); |
| 675 | #endif |
| 676 | if (length < 4) { |
| 677 | #ifdef DEBUG |
| 678 | fprintf(stderr, "\tError: No \"name\" field!\n" ); |
| 679 | #endif |
| 680 | break; |
| 681 | } |
| 682 | length -= 4; |
| 683 | #ifdef DEBUG |
| 684 | fprintf(stderr, "\tname:%c%c%c%c\n" , pkt[0], pkt[1], pkt[2], pkt[3]); |
| 685 | #endif |
| 686 | u_int32_t nameBytes = (pkt[0]<<24)|(pkt[1]<<16)|(pkt[2]<<8)|(pkt[3]); |
| 687 | ADVANCE(4); // skip over "name", to the 'application-dependent data' |
| 688 | #ifdef DEBUG |
| 689 | fprintf(stderr, "\tapplication-dependent data size: %d bytes\n" , length); |
| 690 | #endif |
| 691 | |
| 692 | // If an 'APP' packet handler was set, call it now: |
| 693 | if (fAppHandlerTask != NULL) { |
| 694 | (*fAppHandlerTask)(fAppHandlerClientData, subtype, nameBytes, pkt, length); |
| 695 | } |
| 696 | subPacketOK = True; |
| 697 | typeOfPacket = PACKET_RTCP_APP; |
| 698 | break; |
| 699 | } |
| 700 | // Other RTCP packet types that we don't yet handle: |
| 701 | case RTCP_PT_SDES: { |
| 702 | #ifdef DEBUG |
| 703 | // 'Handle' SDES packets only in debugging code, by printing out the 'SDES items': |
| 704 | fprintf(stderr, "SDES\n" ); |
| 705 | |
| 706 | // Process each 'chunk': |
| 707 | Boolean chunkOK = False; |
| 708 | ADVANCE(-4); length += 4; // hack so that we see the first SSRC/CSRC again |
| 709 | while (length >= 8) { // A valid chunk must be at least 8 bytes long |
| 710 | chunkOK = False; // until we learn otherwise |
| 711 | |
| 712 | u_int32_t SSRC_CSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4); length -= 4; |
| 713 | fprintf(stderr, "\tSSRC/CSRC: 0x%08x\n" , SSRC_CSRC); |
| 714 | |
| 715 | // Process each 'SDES item' in the chunk: |
| 716 | u_int8_t itemType = *pkt; ADVANCE(1); --length; |
| 717 | while (itemType != 0) { |
| 718 | unsigned itemLen = *pkt; ADVANCE(1); --length; |
| 719 | // Make sure "itemLen" allows for at least 1 zero byte at the end of the chunk: |
| 720 | if (itemLen + 1 > length || pkt[itemLen] != 0) break; |
| 721 | |
| 722 | fprintf(stderr, "\t\t%s:%s\n" , |
| 723 | itemType == 1 ? "CNAME" : |
| 724 | itemType == 2 ? "NAME" : |
| 725 | itemType == 3 ? "EMAIL" : |
| 726 | itemType == 4 ? "PHONE" : |
| 727 | itemType == 5 ? "LOC" : |
| 728 | itemType == 6 ? "TOOL" : |
| 729 | itemType == 7 ? "NOTE" : |
| 730 | itemType == 8 ? "PRIV" : |
| 731 | "(unknown)" , |
| 732 | itemType < 8 ? (char*)pkt // hack, because we know it's '\0'-terminated |
| 733 | : "???" /* don't try to print out PRIV or unknown items */); |
| 734 | ADVANCE(itemLen); length -= itemLen; |
| 735 | |
| 736 | itemType = *pkt; ADVANCE(1); --length; |
| 737 | } |
| 738 | if (itemType != 0) break; // bad 'SDES item' |
| 739 | |
| 740 | // Thus, itemType == 0. This zero 'type' marks the end of the list of SDES items. |
| 741 | // Skip over remaining zero padding bytes, so that this chunk ends on a 4-byte boundary: |
| 742 | while (length%4 > 0 && *pkt == 0) { ADVANCE(1); --length; } |
| 743 | if (length%4 > 0) break; // Bad (non-zero) padding byte |
| 744 | |
| 745 | chunkOK = True; |
| 746 | } |
| 747 | if (!chunkOK || length > 0) break; // bad chunk, or not enough bytes for the last chunk |
| 748 | #endif |
| 749 | subPacketOK = True; |
| 750 | break; |
| 751 | } |
| 752 | case RTCP_PT_RTPFB: { |
| 753 | #ifdef DEBUG |
| 754 | fprintf(stderr, "RTPFB(unhandled)\n" ); |
| 755 | #endif |
| 756 | subPacketOK = True; |
| 757 | break; |
| 758 | } |
| 759 | case RTCP_PT_PSFB: { |
| 760 | #ifdef DEBUG |
| 761 | fprintf(stderr, "PSFB(unhandled)\n" ); |
| 762 | // Temporary code to show "Receiver Estimated Maximum Bitrate" (REMB) feedback reports: |
| 763 | //##### |
| 764 | if (length >= 12 && pkt[4] == 'R' && pkt[5] == 'E' && pkt[6] == 'M' && pkt[7] == 'B') { |
| 765 | u_int8_t exp = pkt[9]>>2; |
| 766 | u_int32_t mantissa = ((pkt[9]&0x03)<<16)|(pkt[10]<<8)|pkt[11]; |
| 767 | double remb = (double)mantissa; |
| 768 | while (exp > 0) { |
| 769 | remb *= 2.0; |
| 770 | exp /= 2; |
| 771 | } |
| 772 | fprintf(stderr, "\tReceiver Estimated Max Bitrate (REMB): %g bps\n" , remb); |
| 773 | } |
| 774 | #endif |
| 775 | subPacketOK = True; |
| 776 | break; |
| 777 | } |
| 778 | case RTCP_PT_XR: { |
| 779 | #ifdef DEBUG |
| 780 | fprintf(stderr, "XR(unhandled)\n" ); |
| 781 | #endif |
| 782 | subPacketOK = True; |
| 783 | break; |
| 784 | } |
| 785 | case RTCP_PT_AVB: { |
| 786 | #ifdef DEBUG |
| 787 | fprintf(stderr, "AVB(unhandled)\n" ); |
| 788 | #endif |
| 789 | subPacketOK = True; |
| 790 | break; |
| 791 | } |
| 792 | case RTCP_PT_RSI: { |
| 793 | #ifdef DEBUG |
| 794 | fprintf(stderr, "RSI(unhandled)\n" ); |
| 795 | #endif |
| 796 | subPacketOK = True; |
| 797 | break; |
| 798 | } |
| 799 | case RTCP_PT_TOKEN: { |
| 800 | #ifdef DEBUG |
| 801 | fprintf(stderr, "TOKEN(unhandled)\n" ); |
| 802 | #endif |
| 803 | subPacketOK = True; |
| 804 | break; |
| 805 | } |
| 806 | case RTCP_PT_IDMS: { |
| 807 | #ifdef DEBUG |
| 808 | fprintf(stderr, "IDMS(unhandled)\n" ); |
| 809 | #endif |
| 810 | subPacketOK = True; |
| 811 | break; |
| 812 | } |
| 813 | default: { |
| 814 | #ifdef DEBUG |
| 815 | fprintf(stderr, "UNKNOWN TYPE(0x%x)\n" , pt); |
| 816 | #endif |
| 817 | subPacketOK = True; |
| 818 | break; |
| 819 | } |
| 820 | } |
| 821 | if (!subPacketOK) break; |
| 822 | |
| 823 | // need to check for (& handle) SSRC collision! ##### |
| 824 | |
| 825 | #ifdef DEBUG |
| 826 | fprintf(stderr, "validated RTCP subpacket: rc:%d, pt:%d, bytes remaining:%d, report sender SSRC:0x%08x\n" , rc, pt, length, reportSenderSSRC); |
| 827 | #endif |
| 828 | |
| 829 | // Skip over any remaining bytes in this subpacket: |
| 830 | ADVANCE(length); |
| 831 | |
| 832 | // Check whether another RTCP 'subpacket' follows: |
| 833 | if (packetSize == 0) { |
| 834 | packetOK = True; |
| 835 | break; |
| 836 | } else if (packetSize < 4) { |
| 837 | #ifdef DEBUG |
| 838 | fprintf(stderr, "extraneous %d bytes at end of RTCP packet!\n" , packetSize); |
| 839 | #endif |
| 840 | break; |
| 841 | } |
| 842 | rtcpHdr = ntohl(*(u_int32_t*)pkt); |
| 843 | if ((rtcpHdr & 0xC0000000) != 0x80000000) { |
| 844 | #ifdef DEBUG |
| 845 | fprintf(stderr, "bad RTCP subpacket: header 0x%08x\n" , rtcpHdr); |
| 846 | #endif |
| 847 | break; |
| 848 | } |
| 849 | } |
| 850 | |
| 851 | if (!packetOK) { |
| 852 | #ifdef DEBUG |
| 853 | fprintf(stderr, "rejected bad RTCP subpacket: header 0x%08x\n" , rtcpHdr); |
| 854 | #endif |
| 855 | break; |
| 856 | } else { |
| 857 | #ifdef DEBUG |
| 858 | fprintf(stderr, "validated entire RTCP packet\n" ); |
| 859 | #endif |
| 860 | } |
| 861 | |
| 862 | onReceive(typeOfPacket, totPacketSize, reportSenderSSRC); |
| 863 | |
| 864 | // Finally, if we need to call a "BYE" handler, do so now (in case it causes "this" to get deleted): |
| 865 | if (callByeHandler) { |
| 866 | if (fByeHandlerTask != NULL) { // call a BYE handler without including a 'reason' |
| 867 | TaskFunc* byeHandler = fByeHandlerTask; |
| 868 | fByeHandlerTask = NULL; // because we call the handler only once, by default |
| 869 | (*byeHandler)(fByeHandlerClientData); |
| 870 | } else if (fByeWithReasonHandlerTask != NULL) { // call a BYE handler that includes a 'reason' |
| 871 | ByeWithReasonHandlerFunc* byeHandler = fByeWithReasonHandlerTask; |
| 872 | fByeWithReasonHandlerTask = NULL; // because we call the handler only once, by default |
| 873 | (*byeHandler)(fByeHandlerClientData, reason); |
| 874 | // Note that the handler function is responsible for delete[]ing "reason" |
| 875 | } |
| 876 | } |
| 877 | } while (0); |
| 878 | } |
| 879 | |
| 880 | void RTCPInstance::onReceive(int typeOfPacket, int totPacketSize, u_int32_t ssrc) { |
| 881 | fTypeOfPacket = typeOfPacket; |
| 882 | fLastReceivedSize = totPacketSize; |
| 883 | fLastReceivedSSRC = ssrc; |
| 884 | |
| 885 | int members = (int)numMembers(); |
| 886 | int senders = (fSink != NULL) ? 1 : 0; |
| 887 | |
| 888 | OnReceive(this, // p |
| 889 | this, // e |
| 890 | &members, // members |
| 891 | &fPrevNumMembers, // pmembers |
| 892 | &senders, // senders |
| 893 | &fAveRTCPSize, // avg_rtcp_size |
| 894 | &fPrevReportTime, // tp |
| 895 | dTimeNow(), // tc |
| 896 | fNextReportTime); |
| 897 | } |
| 898 | |
| 899 | void RTCPInstance::sendReport() { |
| 900 | #ifdef DEBUG |
| 901 | fprintf(stderr, "sending REPORT\n" ); |
| 902 | #endif |
| 903 | // Begin by including a SR and/or RR report: |
| 904 | if (!addReport()) return; |
| 905 | |
| 906 | // Then, include a SDES: |
| 907 | addSDES(); |
| 908 | |
| 909 | // Send the report: |
| 910 | sendBuiltPacket(); |
| 911 | |
| 912 | // Periodically clean out old members from our SSRC membership database: |
| 913 | const unsigned membershipReapPeriod = 5; |
| 914 | if ((++fOutgoingReportCount) % membershipReapPeriod == 0) { |
| 915 | unsigned threshold = fOutgoingReportCount - membershipReapPeriod; |
| 916 | fKnownMembers->reapOldMembers(threshold); |
| 917 | } |
| 918 | } |
| 919 | |
| 920 | void RTCPInstance::sendBYE(char const* reason) { |
| 921 | #ifdef DEBUG |
| 922 | if (reason != NULL) { |
| 923 | fprintf(stderr, "sending BYE (reason:%s)\n" , reason); |
| 924 | } else { |
| 925 | fprintf(stderr, "sending BYE\n" ); |
| 926 | } |
| 927 | #endif |
| 928 | // The packet must begin with a SR and/or RR report: |
| 929 | (void)addReport(True); |
| 930 | |
| 931 | addBYE(reason); |
| 932 | sendBuiltPacket(); |
| 933 | } |
| 934 | |
| 935 | void RTCPInstance::sendBuiltPacket() { |
| 936 | #ifdef DEBUG |
| 937 | fprintf(stderr, "sending RTCP packet\n" ); |
| 938 | unsigned char* p = fOutBuf->packet(); |
| 939 | for (unsigned i = 0; i < fOutBuf->curPacketSize(); ++i) { |
| 940 | if (i%4 == 0) fprintf(stderr," " ); |
| 941 | fprintf(stderr, "%02x" , p[i]); |
| 942 | } |
| 943 | fprintf(stderr, "\n" ); |
| 944 | #endif |
| 945 | unsigned reportSize = fOutBuf->curPacketSize(); |
| 946 | fRTCPInterface.sendPacket(fOutBuf->packet(), reportSize); |
| 947 | fOutBuf->resetOffset(); |
| 948 | |
| 949 | fLastSentSize = IP_UDP_HDR_SIZE + reportSize; |
| 950 | fHaveJustSentPacket = True; |
| 951 | fLastPacketSentSize = reportSize; |
| 952 | } |
| 953 | |
| 954 | int RTCPInstance::checkNewSSRC() { |
| 955 | return fKnownMembers->noteMembership(fLastReceivedSSRC, |
| 956 | fOutgoingReportCount); |
| 957 | } |
| 958 | |
| 959 | void RTCPInstance::removeLastReceivedSSRC() { |
| 960 | removeSSRC(fLastReceivedSSRC, False/*keep stats around*/); |
| 961 | } |
| 962 | |
| 963 | void RTCPInstance::removeSSRC(u_int32_t ssrc, Boolean alsoRemoveStats) { |
| 964 | fKnownMembers->remove(ssrc); |
| 965 | |
| 966 | if (alsoRemoveStats) { |
| 967 | // Also, remove records of this SSRC from any reception or transmission stats |
| 968 | if (fSource != NULL) fSource->receptionStatsDB().removeRecord(ssrc); |
| 969 | if (fSink != NULL) fSink->transmissionStatsDB().removeRecord(ssrc); |
| 970 | } |
| 971 | } |
| 972 | |
| 973 | void RTCPInstance::onExpire(RTCPInstance* instance) { |
| 974 | instance->onExpire1(); |
| 975 | } |
| 976 | |
| 977 | // Member functions to build specific kinds of report: |
| 978 | |
| 979 | Boolean RTCPInstance::addReport(Boolean alwaysAdd) { |
| 980 | // Include a SR or a RR, depending on whether we have an associated sink or source: |
| 981 | if (fSink != NULL) { |
| 982 | if (!alwaysAdd) { |
| 983 | if (!fSink->enableRTCPReports()) return False; |
| 984 | |
| 985 | // Hack: Don't send a SR during those (brief) times when the timestamp of the |
| 986 | // next outgoing RTP packet has been preset, to ensure that that timestamp gets |
| 987 | // used for that outgoing packet. (David Bertrand, 2006.07.18) |
| 988 | if (fSink->nextTimestampHasBeenPreset()) return False; |
| 989 | } |
| 990 | |
| 991 | addSR(); |
| 992 | } |
| 993 | if (fSource != NULL) { |
| 994 | if (!alwaysAdd) { |
| 995 | if (!fSource->enableRTCPReports()) return False; |
| 996 | } |
| 997 | |
| 998 | addRR(); |
| 999 | } |
| 1000 | |
| 1001 | return True; |
| 1002 | } |
| 1003 | |
| 1004 | void RTCPInstance::addSR() { |
| 1005 | // ASSERT: fSink != NULL |
| 1006 | |
| 1007 | enqueueCommonReportPrefix(RTCP_PT_SR, fSink->SSRC(), |
| 1008 | 5 /* extra words in a SR */); |
| 1009 | |
| 1010 | // Now, add the 'sender info' for our sink |
| 1011 | |
| 1012 | // Insert the NTP and RTP timestamps for the 'wallclock time': |
| 1013 | struct timeval timeNow; |
| 1014 | gettimeofday(&timeNow, NULL); |
| 1015 | fOutBuf->enqueueWord(timeNow.tv_sec + 0x83AA7E80); |
| 1016 | // NTP timestamp most-significant word (1970 epoch -> 1900 epoch) |
| 1017 | double fractionalPart = (timeNow.tv_usec/15625.0)*0x04000000; // 2^32/10^6 |
| 1018 | fOutBuf->enqueueWord((unsigned)(fractionalPart+0.5)); |
| 1019 | // NTP timestamp least-significant word |
| 1020 | unsigned rtpTimestamp = fSink->convertToRTPTimestamp(timeNow); |
| 1021 | fOutBuf->enqueueWord(rtpTimestamp); // RTP ts |
| 1022 | |
| 1023 | // Insert the packet and byte counts: |
| 1024 | fOutBuf->enqueueWord(fSink->packetCount()); |
| 1025 | fOutBuf->enqueueWord(fSink->octetCount()); |
| 1026 | |
| 1027 | enqueueCommonReportSuffix(); |
| 1028 | } |
| 1029 | |
| 1030 | void RTCPInstance::addRR() { |
| 1031 | // ASSERT: fSource != NULL |
| 1032 | |
| 1033 | enqueueCommonReportPrefix(RTCP_PT_RR, fSource->SSRC()); |
| 1034 | enqueueCommonReportSuffix(); |
| 1035 | } |
| 1036 | |
| 1037 | void RTCPInstance::enqueueCommonReportPrefix(unsigned char packetType, |
| 1038 | u_int32_t SSRC, |
| 1039 | unsigned ) { |
| 1040 | unsigned numReportingSources; |
| 1041 | if (fSource == NULL) { |
| 1042 | numReportingSources = 0; // we don't receive anything |
| 1043 | } else { |
| 1044 | RTPReceptionStatsDB& allReceptionStats |
| 1045 | = fSource->receptionStatsDB(); |
| 1046 | numReportingSources = allReceptionStats.numActiveSourcesSinceLastReset(); |
| 1047 | // This must be <32, to fit in 5 bits: |
| 1048 | if (numReportingSources >= 32) { numReportingSources = 32; } |
| 1049 | // Later: support adding more reports to handle >32 sources (unlikely)##### |
| 1050 | } |
| 1051 | |
| 1052 | unsigned rtcpHdr = 0x80000000; // version 2, no padding |
| 1053 | rtcpHdr |= (numReportingSources<<24); |
| 1054 | rtcpHdr |= (packetType<<16); |
| 1055 | rtcpHdr |= (1 + numExtraWords + 6*numReportingSources); |
| 1056 | // each report block is 6 32-bit words long |
| 1057 | fOutBuf->enqueueWord(rtcpHdr); |
| 1058 | |
| 1059 | fOutBuf->enqueueWord(SSRC); |
| 1060 | } |
| 1061 | |
| 1062 | void RTCPInstance::enqueueCommonReportSuffix() { |
| 1063 | // Output the report blocks for each source: |
| 1064 | if (fSource != NULL) { |
| 1065 | RTPReceptionStatsDB& allReceptionStats |
| 1066 | = fSource->receptionStatsDB(); |
| 1067 | |
| 1068 | RTPReceptionStatsDB::Iterator iterator(allReceptionStats); |
| 1069 | while (1) { |
| 1070 | RTPReceptionStats* receptionStats = iterator.next(); |
| 1071 | if (receptionStats == NULL) break; |
| 1072 | enqueueReportBlock(receptionStats); |
| 1073 | } |
| 1074 | |
| 1075 | allReceptionStats.reset(); // because we have just generated a report |
| 1076 | } |
| 1077 | } |
| 1078 | |
| 1079 | void |
| 1080 | RTCPInstance::enqueueReportBlock(RTPReceptionStats* stats) { |
| 1081 | fOutBuf->enqueueWord(stats->SSRC()); |
| 1082 | |
| 1083 | unsigned highestExtSeqNumReceived = stats->highestExtSeqNumReceived(); |
| 1084 | |
| 1085 | unsigned totNumExpected |
| 1086 | = highestExtSeqNumReceived - stats->baseExtSeqNumReceived(); |
| 1087 | int totNumLost = totNumExpected - stats->totNumPacketsReceived(); |
| 1088 | // 'Clamp' this loss number to a 24-bit signed value: |
| 1089 | if (totNumLost > 0x007FFFFF) { |
| 1090 | totNumLost = 0x007FFFFF; |
| 1091 | } else if (totNumLost < 0) { |
| 1092 | if (totNumLost < -0x00800000) totNumLost = 0x00800000; // unlikely, but... |
| 1093 | totNumLost &= 0x00FFFFFF; |
| 1094 | } |
| 1095 | |
| 1096 | unsigned numExpectedSinceLastReset |
| 1097 | = highestExtSeqNumReceived - stats->lastResetExtSeqNumReceived(); |
| 1098 | int numLostSinceLastReset |
| 1099 | = numExpectedSinceLastReset - stats->numPacketsReceivedSinceLastReset(); |
| 1100 | unsigned char lossFraction; |
| 1101 | if (numExpectedSinceLastReset == 0 || numLostSinceLastReset < 0) { |
| 1102 | lossFraction = 0; |
| 1103 | } else { |
| 1104 | lossFraction = (unsigned char) |
| 1105 | ((numLostSinceLastReset << 8) / numExpectedSinceLastReset); |
| 1106 | } |
| 1107 | |
| 1108 | fOutBuf->enqueueWord((lossFraction<<24) | totNumLost); |
| 1109 | fOutBuf->enqueueWord(highestExtSeqNumReceived); |
| 1110 | |
| 1111 | fOutBuf->enqueueWord(stats->jitter()); |
| 1112 | |
| 1113 | unsigned NTPmsw = stats->lastReceivedSR_NTPmsw(); |
| 1114 | unsigned NTPlsw = stats->lastReceivedSR_NTPlsw(); |
| 1115 | unsigned LSR = ((NTPmsw&0xFFFF)<<16)|(NTPlsw>>16); // middle 32 bits |
| 1116 | fOutBuf->enqueueWord(LSR); |
| 1117 | |
| 1118 | // Figure out how long has elapsed since the last SR rcvd from this src: |
| 1119 | struct timeval const& LSRtime = stats->lastReceivedSR_time(); // "last SR" |
| 1120 | struct timeval timeNow, timeSinceLSR; |
| 1121 | gettimeofday(&timeNow, NULL); |
| 1122 | if (timeNow.tv_usec < LSRtime.tv_usec) { |
| 1123 | timeNow.tv_usec += 1000000; |
| 1124 | timeNow.tv_sec -= 1; |
| 1125 | } |
| 1126 | timeSinceLSR.tv_sec = timeNow.tv_sec - LSRtime.tv_sec; |
| 1127 | timeSinceLSR.tv_usec = timeNow.tv_usec - LSRtime.tv_usec; |
| 1128 | // The enqueued time is in units of 1/65536 seconds. |
| 1129 | // (Note that 65536/1000000 == 1024/15625) |
| 1130 | unsigned DLSR; |
| 1131 | if (LSR == 0) { |
| 1132 | DLSR = 0; |
| 1133 | } else { |
| 1134 | DLSR = (timeSinceLSR.tv_sec<<16) |
| 1135 | | ( (((timeSinceLSR.tv_usec<<11)+15625)/31250) & 0xFFFF); |
| 1136 | } |
| 1137 | fOutBuf->enqueueWord(DLSR); |
| 1138 | } |
| 1139 | |
| 1140 | void RTCPInstance::addSDES() { |
| 1141 | // For now we support only the CNAME item; later support more ##### |
| 1142 | |
| 1143 | // Begin by figuring out the size of the entire SDES report: |
| 1144 | unsigned numBytes = 4; |
| 1145 | // counts the SSRC, but not the header; it'll get subtracted out |
| 1146 | numBytes += fCNAME.totalSize(); // includes id and length |
| 1147 | numBytes += 1; // the special END item |
| 1148 | |
| 1149 | unsigned num4ByteWords = (numBytes + 3)/4; |
| 1150 | |
| 1151 | unsigned rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC chunk |
| 1152 | rtcpHdr |= (RTCP_PT_SDES<<16); |
| 1153 | rtcpHdr |= num4ByteWords; |
| 1154 | fOutBuf->enqueueWord(rtcpHdr); |
| 1155 | |
| 1156 | if (fSource != NULL) { |
| 1157 | fOutBuf->enqueueWord(fSource->SSRC()); |
| 1158 | } else if (fSink != NULL) { |
| 1159 | fOutBuf->enqueueWord(fSink->SSRC()); |
| 1160 | } |
| 1161 | |
| 1162 | // Add the CNAME: |
| 1163 | fOutBuf->enqueue(fCNAME.data(), fCNAME.totalSize()); |
| 1164 | |
| 1165 | // Add the 'END' item (i.e., a zero byte), plus any more needed to pad: |
| 1166 | unsigned numPaddingBytesNeeded = 4 - (fOutBuf->curPacketSize() % 4); |
| 1167 | unsigned char const zero = '\0'; |
| 1168 | while (numPaddingBytesNeeded-- > 0) fOutBuf->enqueue(&zero, 1); |
| 1169 | } |
| 1170 | |
| 1171 | void RTCPInstance::addBYE(char const* reason) { |
| 1172 | u_int32_t rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC |
| 1173 | rtcpHdr |= (RTCP_PT_BYE<<16); |
| 1174 | u_int16_t num32BitWords = 2; // by default, two 32-bit words total (i.e., with 1 SSRC) |
| 1175 | u_int8_t reasonLength8Bits = 0; // by default |
| 1176 | if (reason != NULL) { |
| 1177 | // We need to add more 32-bit words for the 'length+reason': |
| 1178 | unsigned const reasonLength = strlen(reason); |
| 1179 | reasonLength8Bits = reasonLength < 0xFF ? (u_int8_t)reasonLength : 0xFF; |
| 1180 | unsigned = ((1/*reason length field*/+reasonLength8Bits)+3)/4; |
| 1181 | |
| 1182 | num32BitWords += numExtraWords; |
| 1183 | } |
| 1184 | rtcpHdr |= (num32BitWords-1); // length field |
| 1185 | fOutBuf->enqueueWord(rtcpHdr); |
| 1186 | |
| 1187 | if (fSource != NULL) { |
| 1188 | fOutBuf->enqueueWord(fSource->SSRC()); |
| 1189 | } else if (fSink != NULL) { |
| 1190 | fOutBuf->enqueueWord(fSink->SSRC()); |
| 1191 | } |
| 1192 | |
| 1193 | num32BitWords -= 2; // ASSERT: num32BitWords >= 0 |
| 1194 | if (num32BitWords > 0) { |
| 1195 | // Add a length+'reason for leaving': |
| 1196 | // First word: |
| 1197 | u_int32_t lengthPlusFirst3ReasonBytes = reasonLength8Bits<<24; |
| 1198 | unsigned index = 0; |
| 1199 | if (reasonLength8Bits > index) lengthPlusFirst3ReasonBytes |= ((u_int8_t)reason[index++])<<16; |
| 1200 | if (reasonLength8Bits > index) lengthPlusFirst3ReasonBytes |= ((u_int8_t)reason[index++])<<8; |
| 1201 | if (reasonLength8Bits > index) lengthPlusFirst3ReasonBytes |= (u_int8_t)reason[index++]; |
| 1202 | fOutBuf->enqueueWord(lengthPlusFirst3ReasonBytes); |
| 1203 | |
| 1204 | // Any subsequent words: |
| 1205 | if (reasonLength8Bits > 3) { |
| 1206 | // ASSERT: num32BitWords > 1 |
| 1207 | while (--num32BitWords > 0) { |
| 1208 | u_int32_t fourMoreReasonBytes = 0; |
| 1209 | if (reasonLength8Bits > index) fourMoreReasonBytes |= ((u_int8_t)reason[index++])<<24; |
| 1210 | if (reasonLength8Bits > index) fourMoreReasonBytes |= ((u_int8_t)reason[index++])<<16; |
| 1211 | if (reasonLength8Bits > index) fourMoreReasonBytes |= ((u_int8_t)reason[index++])<<8; |
| 1212 | if (reasonLength8Bits > index) fourMoreReasonBytes |= (u_int8_t)reason[index++]; |
| 1213 | fOutBuf->enqueueWord(fourMoreReasonBytes); |
| 1214 | } |
| 1215 | } |
| 1216 | } |
| 1217 | } |
| 1218 | |
| 1219 | void RTCPInstance::schedule(double nextTime) { |
| 1220 | fNextReportTime = nextTime; |
| 1221 | |
| 1222 | double secondsToDelay = nextTime - dTimeNow(); |
| 1223 | if (secondsToDelay < 0) secondsToDelay = 0; |
| 1224 | #ifdef DEBUG |
| 1225 | fprintf(stderr, "schedule(%f->%f)\n" , secondsToDelay, nextTime); |
| 1226 | #endif |
| 1227 | int64_t usToGo = (int64_t)(secondsToDelay * 1000000); |
| 1228 | nextTask() = envir().taskScheduler().scheduleDelayedTask(usToGo, |
| 1229 | (TaskFunc*)RTCPInstance::onExpire, this); |
| 1230 | } |
| 1231 | |
| 1232 | void RTCPInstance::reschedule(double nextTime) { |
| 1233 | envir().taskScheduler().unscheduleDelayedTask(nextTask()); |
| 1234 | schedule(nextTime); |
| 1235 | } |
| 1236 | |
| 1237 | void RTCPInstance::onExpire1() { |
| 1238 | nextTask() = NULL; |
| 1239 | |
| 1240 | // Note: fTotSessionBW is kbits per second |
| 1241 | double rtcpBW = 0.05*fTotSessionBW*1024/8; // -> bytes per second |
| 1242 | |
| 1243 | OnExpire(this, // event |
| 1244 | numMembers(), // members |
| 1245 | (fSink != NULL) ? 1 : 0, // senders |
| 1246 | rtcpBW, // rtcp_bw |
| 1247 | (fSink != NULL) ? 1 : 0, // we_sent |
| 1248 | &fAveRTCPSize, // ave_rtcp_size |
| 1249 | &fIsInitial, // initial |
| 1250 | dTimeNow(), // tc |
| 1251 | &fPrevReportTime, // tp |
| 1252 | &fPrevNumMembers // pmembers |
| 1253 | ); |
| 1254 | } |
| 1255 | |
| 1256 | ////////// SDESItem ////////// |
| 1257 | |
| 1258 | SDESItem::SDESItem(unsigned char tag, unsigned char const* value) { |
| 1259 | unsigned length = strlen((char const*)value); |
| 1260 | if (length > 0xFF) length = 0xFF; // maximum data length for a SDES item |
| 1261 | |
| 1262 | fData[0] = tag; |
| 1263 | fData[1] = (unsigned char)length; |
| 1264 | memmove(&fData[2], value, length); |
| 1265 | } |
| 1266 | |
| 1267 | unsigned SDESItem::totalSize() const { |
| 1268 | return 2 + (unsigned)fData[1]; |
| 1269 | } |
| 1270 | |
| 1271 | |
| 1272 | ////////// Implementation of routines imported by the "rtcp_from_spec" C code |
| 1273 | |
| 1274 | extern "C" void Schedule(double nextTime, event e) { |
| 1275 | RTCPInstance* instance = (RTCPInstance*)e; |
| 1276 | if (instance == NULL) return; |
| 1277 | |
| 1278 | instance->schedule(nextTime); |
| 1279 | } |
| 1280 | |
| 1281 | extern "C" void Reschedule(double nextTime, event e) { |
| 1282 | RTCPInstance* instance = (RTCPInstance*)e; |
| 1283 | if (instance == NULL) return; |
| 1284 | |
| 1285 | instance->reschedule(nextTime); |
| 1286 | } |
| 1287 | |
| 1288 | extern "C" void SendRTCPReport(event e) { |
| 1289 | RTCPInstance* instance = (RTCPInstance*)e; |
| 1290 | if (instance == NULL) return; |
| 1291 | |
| 1292 | instance->sendReport(); |
| 1293 | } |
| 1294 | |
| 1295 | extern "C" void SendBYEPacket(event e) { |
| 1296 | RTCPInstance* instance = (RTCPInstance*)e; |
| 1297 | if (instance == NULL) return; |
| 1298 | |
| 1299 | instance->sendBYE(); |
| 1300 | } |
| 1301 | |
| 1302 | extern "C" int TypeOfEvent(event e) { |
| 1303 | RTCPInstance* instance = (RTCPInstance*)e; |
| 1304 | if (instance == NULL) return EVENT_UNKNOWN; |
| 1305 | |
| 1306 | return instance->typeOfEvent(); |
| 1307 | } |
| 1308 | |
| 1309 | extern "C" int SentPacketSize(event e) { |
| 1310 | RTCPInstance* instance = (RTCPInstance*)e; |
| 1311 | if (instance == NULL) return 0; |
| 1312 | |
| 1313 | return instance->sentPacketSize(); |
| 1314 | } |
| 1315 | |
| 1316 | extern "C" int PacketType(packet p) { |
| 1317 | RTCPInstance* instance = (RTCPInstance*)p; |
| 1318 | if (instance == NULL) return PACKET_UNKNOWN_TYPE; |
| 1319 | |
| 1320 | return instance->packetType(); |
| 1321 | } |
| 1322 | |
| 1323 | extern "C" int ReceivedPacketSize(packet p) { |
| 1324 | RTCPInstance* instance = (RTCPInstance*)p; |
| 1325 | if (instance == NULL) return 0; |
| 1326 | |
| 1327 | return instance->receivedPacketSize(); |
| 1328 | } |
| 1329 | |
| 1330 | extern "C" int NewMember(packet p) { |
| 1331 | RTCPInstance* instance = (RTCPInstance*)p; |
| 1332 | if (instance == NULL) return 0; |
| 1333 | |
| 1334 | return instance->checkNewSSRC(); |
| 1335 | } |
| 1336 | |
| 1337 | extern "C" int NewSender(packet /*p*/) { |
| 1338 | return 0; // we don't yet recognize senders other than ourselves ##### |
| 1339 | } |
| 1340 | |
| 1341 | extern "C" void AddMember(packet /*p*/) { |
| 1342 | // Do nothing; all of the real work was done when NewMember() was called |
| 1343 | } |
| 1344 | |
| 1345 | extern "C" void AddSender(packet /*p*/) { |
| 1346 | // we don't yet recognize senders other than ourselves ##### |
| 1347 | } |
| 1348 | |
| 1349 | extern "C" void RemoveMember(packet p) { |
| 1350 | RTCPInstance* instance = (RTCPInstance*)p; |
| 1351 | if (instance == NULL) return; |
| 1352 | |
| 1353 | instance->removeLastReceivedSSRC(); |
| 1354 | } |
| 1355 | |
| 1356 | extern "C" void RemoveSender(packet /*p*/) { |
| 1357 | // we don't yet recognize senders other than ourselves ##### |
| 1358 | } |
| 1359 | |
| 1360 | extern "C" double drand30() { |
| 1361 | unsigned tmp = our_random()&0x3FFFFFFF; // a random 30-bit integer |
| 1362 | return tmp/(double)(1024*1024*1024); |
| 1363 | } |
| 1364 | |