您的位置:首页 > 其它

[置顶]发现live555中一个小bug(2)

2012-01-05 09:46 323 查看
在《发现live555中一个小bug》一文中所修改的代码并不起作用。

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

view
plain

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

转载http://blog.csdn.net/nkmnkm/article/details/7004764
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: