发现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*型的,设计者的原意是不能这样用的,但找不到更好的办法,而且测试没有问题,但是不能保证在以后的版本中不会出问题哦。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值