当前位置: 首页 > news >正文

发现live555中一个小bug(2)

在《发现live555中一个小bug》一文中所修改的代码并不起作用。

经测试,RTPSource的Socket检测不到网络出错的情况。而RTCPInstance中的socket可以检测到,所以可以利用RTCPInstance通知RTPSource应停止流传输了。修改如下(//---------------------包含的代码为修改处):

void RTCPInstance::incomingReportHandler1() { do { int tcpReadStreamSocketNum = fRTCPInterface.nextTCPReadStreamSocketNum(); unsigned char tcpReadStreamChannelId = fRTCPInterface.nextTCPReadStreamChannelId(); unsigned packetSize = 0; unsigned numBytesRead; struct sockaddr_in fromAddress; Boolean packetReadWasIncomplete; Boolean readResult = fRTCPInterface.handleRead( &fInBuf[fNumBytesAlreadyRead], maxPacketSize - fNumBytesAlreadyRead, numBytesRead, fromAddress, packetReadWasIncomplete); if (packetReadWasIncomplete) { fNumBytesAlreadyRead += numBytesRead; return; // more reads are needed to get the entire packet } else { // normal case: We've read the entire packet packetSize = fNumBytesAlreadyRead + numBytesRead; fNumBytesAlreadyRead = 0; // for next time } if (!readResult){ //-------------------------------- //出错了,停止网络读 fRTCPInterface.stopNetworkReading(); //通知RTPSource和RTPSink,网络出错了,应该停止了 if(fSink) fSink->stopPlaying(); if(fSource) fSource->handleClosure((void*)fSource); //--------------------------------- break; } // Ignore the packet if it was looped-back from ourself: Boolean packetWasFromOurHost = False; if (RTCPgs()->wasLoopedBackFromUs(envir(), fromAddress)) { packetWasFromOurHost = True; // However, we still want to handle incoming RTCP packets from // *other processes* on the same machine. To distinguish this // case from a true loop-back, check whether we've just sent a // packet of the same size. (This check isn't perfect, but it seems // to be the best we can do.) if (fHaveJustSentPacket && fLastPacketSentSize == packetSize) { // This is a true loop-back: fHaveJustSentPacket = False; break; // ignore this packet } } unsigned char* pkt = fInBuf; if (fIsSSMSource && !packetWasFromOurHost) { // This packet is assumed to have been received via unicast (because we're a SSM source, and SSM receivers send back RTCP "RR" // packets via unicast). 'Reflect' the packet by resending it to the multicast group, so that any other receivers can also // get to see it. // NOTE: Denial-of-service attacks are possible here. // Users of this software may wish to add their own, // application-specific mechanism for 'authenticating' the // validity of this packet before reflecting it. // NOTE: The test for "!packetWasFromOurHost" means that we won't reflect RTCP packets that come from other processes on // the same host as us. The reason for this is that the 'packet size' test above is not 100% reliable; some packets // that were truly looped back from us might not be detected as such, and this might lead to infinite forwarding/receiving // of some packets. To avoid this possibility, we only reflect RTCP packets that we know for sure originated elsewhere. // (Note, though, that if we ever re-enable the code in "Groupsock::multicastSendOnly()", then we could remove the test for // "!packetWasFromOurHost".) fRTCPInterface.sendPacket(pkt, packetSize); fHaveJustSentPacket = True; fLastPacketSentSize = packetSize; } #ifdef DEBUG fprintf(stderr, "[%p]saw incoming RTCP packet (from address %s, port %d)\n", this, our_inet_ntoa(fromAddress.sin_addr), ntohs(fromAddress.sin_port)); for (unsigned i = 0; i < packetSize; ++i) { if (i%4 == 0) fprintf(stderr, " "); fprintf(stderr, "%02x", pkt[i]); } fprintf(stderr, "\n"); #endif int totPacketSize = IP_UDP_HDR_SIZE + packetSize; // Check the RTCP packet for validity: // It must at least contain a header (4 bytes), and this header // must be version=2, with no padding bit, and a payload type of // SR (200) or RR (201): if (packetSize < 4) break; unsigned rtcpHdr = ntohl(*(u_int32_t*) pkt); if ((rtcpHdr & 0xE0FE0000) != (0x80000000 | (RTCP_PT_SR << 16))) { #ifdef DEBUG fprintf(stderr, "rejected bad RTCP packet: header 0x%08x\n", rtcpHdr); #endif break; } // Process each of the individual RTCP 'subpackets' in (what may be) // a compound RTCP packet. int typeOfPacket = PACKET_UNKNOWN_TYPE; unsigned reportSenderSSRC = 0; Boolean packetOK = False; while (1) { unsigned rc = (rtcpHdr >> 24) & 0x1F; unsigned pt = (rtcpHdr >> 16) & 0xFF; unsigned length = 4 * (rtcpHdr & 0xFFFF); // doesn't count hdr ADVANCE(4); // skip over the header if (length > packetSize) break; // Assume that each RTCP subpacket begins with a 4-byte SSRC: if (length < 4) break; length -= 4; reportSenderSSRC = ntohl(*(u_int32_t*) pkt); ADVANCE(4); Boolean subPacketOK = False; switch (pt) { case RTCP_PT_SR: { #ifdef DEBUG fprintf(stderr, "SR\n"); #endif if (length < 20) break; length -= 20; // Extract the NTP timestamp, and note this: unsigned NTPmsw = ntohl(*(u_int32_t*) pkt); ADVANCE(4); unsigned NTPlsw = ntohl(*(u_int32_t*) pkt); ADVANCE(4); unsigned rtpTimestamp = ntohl(*(u_int32_t*) pkt); ADVANCE(4); if (fSource != NULL) { RTPReceptionStatsDB& receptionStats = fSource->receptionStatsDB(); receptionStats.noteIncomingSR(reportSenderSSRC, NTPmsw, NTPlsw, rtpTimestamp); }ADVANCE(8); // skip over packet count, octet count // If a 'SR handler' was set, call it now: if (fSRHandlerTask != NULL) (*fSRHandlerTask)(fSRHandlerClientData); // The rest of the SR is handled like a RR (so, no "break;" here) } case RTCP_PT_RR: { #ifdef DEBUG fprintf(stderr, "RR\n"); #endif unsigned reportBlocksSize = rc * (6 * 4); if (length < reportBlocksSize) break; length -= reportBlocksSize; if (fSink != NULL) { // Use this information to update stats about our transmissions: RTPTransmissionStatsDB& transmissionStats = fSink->transmissionStatsDB(); for (unsigned i = 0; i < rc; ++i) { unsigned senderSSRC = ntohl(*(u_int32_t*) pkt); ADVANCE(4); // We care only about reports about our own transmission, not others' if (senderSSRC == fSink->SSRC()) { unsigned lossStats = ntohl(*(u_int32_t*) pkt); ADVANCE(4); unsigned highestReceived = ntohl(*(u_int32_t*) pkt); ADVANCE(4); unsigned jitter = ntohl(*(u_int32_t*) pkt); ADVANCE(4); unsigned timeLastSR = ntohl(*(u_int32_t*) pkt); ADVANCE(4); unsigned timeSinceLastSR = ntohl(*(u_int32_t*) pkt); ADVANCE(4); transmissionStats.noteIncomingRR(reportSenderSSRC, fromAddress, lossStats, highestReceived, jitter, timeLastSR, timeSinceLastSR); } else { ADVANCE(4*5); } } } else { ADVANCE(reportBlocksSize); } if (pt == RTCP_PT_RR) { // i.e., we didn't fall through from 'SR' // If a 'RR handler' was set, call it now: // Specific RR handler: if (fSpecificRRHandlerTable != NULL) { netAddressBits fromAddr; portNumBits fromPortNum; if (tcpReadStreamSocketNum < 0) { // Normal case: We read the RTCP packet over UDP fromAddr = fromAddress.sin_addr.s_addr; fromPortNum = ntohs(fromAddress.sin_port); } else { // Special case: We read the RTCP packet over TCP (interleaved) // Hack: Use the TCP socket and channel id to look up the handler fromAddr = tcpReadStreamSocketNum; fromPortNum = tcpReadStreamChannelId; } Port fromPort(fromPortNum); RRHandlerRecord* rrHandler = (RRHandlerRecord*) (fSpecificRRHandlerTable->Lookup( fromAddr, (~0), fromPort)); if (rrHandler != NULL) { if (rrHandler->rrHandlerTask != NULL) { (*(rrHandler->rrHandlerTask))( rrHandler->rrHandlerClientData); } } } // General RR handler: if (fRRHandlerTask != NULL) (*fRRHandlerTask)(fRRHandlerClientData); } subPacketOK = True; typeOfPacket = PACKET_RTCP_REPORT; break; } case RTCP_PT_BYE: { #ifdef DEBUG fprintf(stderr, "BYE\n"); #endif // If a 'BYE handler' was set, call it now: TaskFunc* byeHandler = fByeHandlerTask; if (byeHandler != NULL && (!fByeHandleActiveParticipantsOnly || (fSource != NULL && fSource->receptionStatsDB().lookup( reportSenderSSRC) != NULL) || (fSink != NULL && fSink->transmissionStatsDB().lookup( reportSenderSSRC) != NULL))) { fByeHandlerTask = NULL; // we call this only once by default (*byeHandler)(fByeHandlerClientData); } // We should really check for & handle >1 SSRCs being present ##### subPacketOK = True; typeOfPacket = PACKET_BYE; break; } // Later handle SDES, APP, and compound RTCP packets ##### default: #ifdef DEBUG fprintf(stderr, "UNSUPPORTED TYPE(0x%x)\n", pt); #endif subPacketOK = True; break; } if (!subPacketOK) break; // need to check for (& handle) SSRC collision! ##### #ifdef DEBUG fprintf(stderr, "validated RTCP subpacket (type %d): %d, %d, %d, 0x%08x\n", typeOfPacket, rc, pt, length, reportSenderSSRC); #endif // Skip over any remaining bytes in this subpacket: ADVANCE(length); // Check whether another RTCP 'subpacket' follows: if (packetSize == 0) { packetOK = True; break; } else if (packetSize < 4) { #ifdef DEBUG fprintf(stderr, "extraneous %d bytes at end of RTCP packet!\n", packetSize); #endif break; } rtcpHdr = ntohl(*(u_int32_t*) pkt); if ((rtcpHdr & 0xC0000000) != 0x80000000) { #ifdef DEBUG fprintf(stderr, "bad RTCP subpacket: header 0x%08x\n", rtcpHdr); #endif break; } } if (!packetOK) { #ifdef DEBUG fprintf(stderr, "rejected bad RTCP subpacket: header 0x%08x\n", rtcpHdr); #endif break; } else { #ifdef DEBUG fprintf(stderr, "validated entire RTCP packet\n"); #endif } onReceive(typeOfPacket, totPacketSize, reportSenderSSRC); } while (0); } 注意,fSource为 const*型的,设计者的原意是不能这样用的,但找不到更好的办法,而且测试没有问题,但是不能保证在以后的版本中不会出问题哦。

相关文章:

  • 转载:APP的上线和推广——线上推广渠道
  • 关于HashMap的建值取向
  • 【软件】Eclipse 下载
  • web service 开源项目比较
  • SOSO发布通用搜索引擎优化指南
  • 超越死亡:恩宠与勇气节选
  • linux进程与它的文件描述符2
  • 操作笔记:catalina.out膨胀太快,分割tomcat 7日志
  • [转载]GSview注册码
  • ******IT公司面试题汇总+优秀技术博客汇总
  • iphone 如何设置按钮透明,文字不透明
  • 问题-提示“adodataset.command”
  • 【转载】Nginx负载均衡之后碰到的问题
  • 关于NoSQL与SQL的区别
  • 听?
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 【Leetcode】104. 二叉树的最大深度
  • 2018一半小结一波
  • Angularjs之国际化
  • PHP的类修饰符与访问修饰符
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • vue中实现单选
  • 浮现式设计
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 我的zsh配置, 2019最新方案
  • 由插件封装引出的一丢丢思考
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • Nginx实现动静分离
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (离散数学)逻辑连接词
  • (十六)串口UART
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (转载)CentOS查看系统信息|CentOS查看命令
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .net 受管制代码
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .Net小白的大学四年,内含面经
  • @EnableAsync和@Async开始异步任务支持
  • @reference注解_Dubbo配置参考手册之dubbo:reference
  • [BZOJ4016][FJOI2014]最短路径树问题
  • [C# WPF] 如何给控件添加边框(Border)?
  • [C++][基础]1_变量、常量和基本类型
  • [C语言]编译和链接
  • [FFmpeg学习]从视频中获取图片
  • [Godot] 3D拾取
  • [HeMIM]Cl,[AeMIM]Br,[CeEIM]Cl,([HO-PECH-MIM]Cl,[HOOC-PECH-MIM]Cl改性酚醛树脂
  • [hihocoder1395] 最大权闭合子图
  • [Leetcode] Permutations II
  • [LeetCode][LCR178]训练计划 VI——使用位运算寻找数组中不同的数字