static int dump_domains(int argc, char** argv) { DomainList::Iterator iterator = sDomains.GetIterator(); while (net_domain_private* domain = iterator.Next()) { kprintf("domain: %p, %s, %d\n", domain, domain->name, domain->family); kprintf(" module: %p\n", domain->module); kprintf(" address_module: %p\n", domain->address_module); if (!domain->routes.IsEmpty()) kprintf(" routes:\n"); RouteList::Iterator routeIterator = domain->routes.GetIterator(); while (net_route_private* route = routeIterator.Next()) { kprintf(" %p: dest %s, mask %s, gw %s, flags %" B_PRIx32 ", " "address %p\n", route, AddressString(domain, route->destination ? route->destination : NULL).Data(), AddressString(domain, route->mask ? route->mask : NULL).Data(), AddressString(domain, route->gateway ? route->gateway : NULL).Data(), route->flags, route->interface_address); } if (!domain->route_infos.IsEmpty()) kprintf(" route infos:\n"); RouteInfoList::Iterator infoIterator = domain->route_infos.GetIterator(); while (net_route_info* info = infoIterator.Next()) { kprintf(" %p\n", info); } } return 0; }
status_t remove_route(struct net_domain* _domain, const struct net_route* removeRoute) { struct net_domain_private* domain = (net_domain_private*)_domain; TRACE("remove route from domain %s: dest %s, mask %s, gw %s, flags %lx\n", domain->name, AddressString(domain, removeRoute->destination ? removeRoute->destination : NULL).Data(), AddressString(domain, removeRoute->mask ? removeRoute->mask : NULL).Data(), AddressString(domain, removeRoute->gateway ? removeRoute->gateway : NULL).Data(), removeRoute->flags); RecursiveLocker locker(domain->lock); net_route_private* route = find_route(domain, removeRoute); if (route == NULL) return B_ENTRY_NOT_FOUND; domain->routes.Remove(route); put_route_internal(domain, route); update_route_infos(domain); return B_OK; }
UsageEnvironment& operator<<(UsageEnvironment& s, const Groupsock& g) { UsageEnvironment& s1 = s << timestampString() << " Groupsock(" << g.socketNum() << ": " << AddressString(g.groupAddress()).val() << ", " << g.port() << ", "; if (g.isSSM()) { return s1 << "SSM source: " << AddressString(g.sourceFilterAddress()).val() << ")"; } else { return s1 << (unsigned)(g.ttl()) << ")"; } }
static net_route_private* find_route(net_domain* _domain, const sockaddr* address) { net_domain_private* domain = (net_domain_private*)_domain; // find last matching route RouteList::Iterator iterator = domain->routes.GetIterator(); net_route_private* candidate = NULL; TRACE("test address %s for routes...\n", AddressString(domain, address).Data()); // TODO: alternate equal default routes while (iterator.HasNext()) { net_route_private* route = iterator.Next(); if (route->mask) { sockaddr maskedAddress; domain->address_module->mask_address(address, route->mask, &maskedAddress); if (!domain->address_module->equal_addresses(&maskedAddress, route->destination)) continue; } else if (!domain->address_module->equal_addresses(address, route->destination)) continue; // neglect routes that point to devices that have no link if ((route->interface_address->interface->device->flags & IFF_LINK) == 0) { if (candidate == NULL) { TRACE(" found candidate: %s, flags %lx\n", AddressString( domain, route->destination).Data(), route->flags); candidate = route; } continue; } TRACE(" found route: %s, flags %lx\n", AddressString(domain, route->destination).Data(), route->flags); return route; } return candidate; }
int main(int argc, char** argv) { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler); // Create a 'groupsock' for the input multicast group,port: char const* sessionAddressStr = "224.2.127.254"; struct in_addr sessionAddress; sessionAddress.s_addr = our_inet_addr(sessionAddressStr); const Port port(9875); const unsigned char ttl = 0; // we're only reading from this mcast group Groupsock inputGroupsock(*env, sessionAddress, port, ttl); // Start reading and printing incoming packets // (Because this is the only thing we do, we can just do this // synchronously, in a loop, so we don't need to set up an asynchronous // event handler like we do in most of the other test programs.) unsigned packetSize; struct sockaddr_in fromAddress; while (inputGroupsock.handleRead(packet, maxPacketSize, packetSize, fromAddress)) { printf("\n[packet from %s (%d bytes)]\n", AddressString(fromAddress).val(), packetSize); // Ignore the first 8 bytes (SAP header). if (packetSize < 8) { *env << "Ignoring short packet from " << AddressString(fromAddress).val() << "%s!\n"; continue; } // convert "application/sdp\0" -> "application/sdp\0x20" // or all other nonprintable characters to blank, except new line unsigned idx = 8; while (idx < packetSize) { if (packet[idx] < 0x20 && packet[idx] != '\n') packet[idx] = 0x20; idx++; } packet[packetSize] = '\0'; // just in case printf("%s", (char*)(packet+8)); } return 0; // only to prevent compiler warning }
Boolean Groupsock::handleRead(unsigned char* buffer, unsigned bufferMaxSize, unsigned& bytesRead, struct sockaddr_in& fromAddressAndPort) { // Read data from the socket, and relay it across any attached tunnels //##### later make this code more general - independent of tunnels bytesRead = 0; int maxBytesToRead = bufferMaxSize - TunnelEncapsulationTrailerMaxSize; int numBytes = readSocket(env(), socketNum(), buffer, maxBytesToRead, fromAddressAndPort); if (numBytes < 0) { if (DebugLevel >= 0) { // this is a fatal error UsageEnvironment::MsgString msg = strDup(env().getResultMsg()); env().setResultMsg("Groupsock read failed: ", msg); delete[] (char*)msg; } return False; } // If we're a SSM group, make sure the source address matches: if (isSSM() && fromAddressAndPort.sin_addr.s_addr != sourceFilterAddress().s_addr) { return True; } // We'll handle this data. // Also write it (with the encapsulation trailer) to each member, // unless the packet was originally sent by us to begin with. bytesRead = numBytes; int numMembers = 0; if (!wasLoopedBackFromUs(env(), fromAddressAndPort)) { statsIncoming.countPacket(numBytes); statsGroupIncoming.countPacket(numBytes); numMembers = outputToAllMembersExcept(NULL, ttl(), buffer, bytesRead, fromAddressAndPort.sin_addr.s_addr); if (numMembers > 0) { statsRelayedIncoming.countPacket(numBytes); statsGroupRelayedIncoming.countPacket(numBytes); } } if (DebugLevel >= 3) { env() << *this << ": read " << bytesRead << " bytes from " << AddressString(fromAddressAndPort).val() << ", port " << ntohs(fromAddressAndPort.sin_port); if (numMembers > 0) { env() << "; relayed to " << numMembers << " members"; } env() << "\n"; } return True; }
void invalidate_routes(InterfaceAddress* address) { net_domain_private* domain = (net_domain_private*)address->domain; TRACE("invalidate_routes(%s)\n", AddressString(domain, address->local).Data()); RecursiveLocker locker(domain->lock); RouteList::Iterator iterator = domain->routes.GetIterator(); while (iterator.HasNext()) { net_route* route = iterator.Next(); if (route->interface_address == address) remove_route(domain, route); } }
void GenericMediaServer::incomingConnectionHandlerOnSocket(int serverSocket) { struct sockaddr_in clientAddr; SOCKLEN_T clientAddrLen = sizeof clientAddr; int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen); if (clientSocket < 0) { int err = envir().getErrno(); if (err != EWOULDBLOCK) { envir().setResultErrMsg("accept() failed: "); } return; } ignoreSigPipeOnSocket(clientSocket); // so that clients on the same host that are killed don't also kill us makeSocketNonBlocking(clientSocket); increaseSendBufferTo(envir(), clientSocket, 50*1024); #ifdef DEBUG envir() << "accept()ed connection from " << AddressString(clientAddr).val() << "\n"; #endif // Create a new object for handling this connection: (void)createNewClientConnection(clientSocket, clientAddr); }
status_t update_interface_address(InterfaceAddress* interfaceAddress, int32 option, const sockaddr* oldAddress, const sockaddr* newAddress) { TRACE("%s(address %p, option %" B_PRId32 ", oldAddress %s, newAddress " "%s)\n", __FUNCTION__, interfaceAddress, option, AddressString(interfaceAddress->domain, oldAddress).Data(), AddressString(interfaceAddress->domain, newAddress).Data()); MutexLocker locker(sHashLock); // set logical interface address sockaddr** _address = interfaceAddress->AddressFor(option); if (_address == NULL) return B_BAD_VALUE; Interface* interface = (Interface*)interfaceAddress->interface; interfaceAddress->RemoveDefaultRoutes(option); if (option == SIOCDIFADDR) { // Remove address, and release its reference (causing our caller to // delete it) locker.Unlock(); invalidate_routes(interfaceAddress); interface->RemoveAddress(interfaceAddress); interfaceAddress->ReleaseReference(); return B_OK; } if (interfaceAddress->LocalIsDefined()) sAddressTable.Remove(interfaceAddress); // Copy new address over status_t status = InterfaceAddress::Set(_address, newAddress); if (status == B_OK) { sockaddr* address = *_address; if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) { // Reset netmask and broadcast addresses to defaults net_domain* domain = interfaceAddress->domain; sockaddr* defaultNetmask = NULL; const sockaddr* netmask = NULL; if (option == SIOCSIFADDR) { defaultNetmask = InterfaceAddress::Prepare( &interfaceAddress->mask, address->sa_len); } else netmask = newAddress; // Reset the broadcast address if the address family has // such sockaddr* defaultBroadcast = NULL; if ((domain->address_module->flags & NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) { defaultBroadcast = InterfaceAddress::Prepare( &interfaceAddress->destination, address->sa_len); } else InterfaceAddress::Set(&interfaceAddress->destination, NULL); domain->address_module->set_to_defaults(defaultNetmask, defaultBroadcast, interfaceAddress->local, netmask); } interfaceAddress->AddDefaultRoutes(option); notify_interface_changed(interface); } if (interfaceAddress->LocalIsDefined()) sAddressTable.Insert(interfaceAddress); return status; }
status_t add_route(struct net_domain* _domain, const struct net_route* newRoute) { struct net_domain_private* domain = (net_domain_private*)_domain; TRACE("add route to domain %s: dest %s, mask %s, gw %s, flags %lx\n", domain->name, AddressString(domain, newRoute->destination ? newRoute->destination : NULL).Data(), AddressString(domain, newRoute->mask ? newRoute->mask : NULL).Data(), AddressString(domain, newRoute->gateway ? newRoute->gateway : NULL).Data(), newRoute->flags); if (domain == NULL || newRoute == NULL || newRoute->interface_address == NULL || ((newRoute->flags & RTF_HOST) != 0 && newRoute->mask != NULL) || ((newRoute->flags & RTF_DEFAULT) == 0 && newRoute->destination == NULL) || ((newRoute->flags & RTF_GATEWAY) != 0 && newRoute->gateway == NULL) || !domain->address_module->check_mask(newRoute->mask)) return B_BAD_VALUE; RecursiveLocker _(domain->lock); net_route_private* route = find_route(domain, newRoute); if (route != NULL) return B_FILE_EXISTS; route = new (std::nothrow) net_route_private; if (route == NULL) return B_NO_MEMORY; if (domain->address_module->copy_address(newRoute->destination, &route->destination, (newRoute->flags & RTF_DEFAULT) != 0, newRoute->mask) != B_OK || domain->address_module->copy_address(newRoute->mask, &route->mask, (newRoute->flags & RTF_DEFAULT) != 0, NULL) != B_OK || domain->address_module->copy_address(newRoute->gateway, &route->gateway, false, NULL) != B_OK) { delete route; return B_NO_MEMORY; } route->flags = newRoute->flags; route->interface_address = newRoute->interface_address; ((InterfaceAddress*)route->interface_address)->AcquireReference(); route->mtu = 0; route->ref_count = 1; // Insert the route sorted by completeness of its mask RouteList::Iterator iterator = domain->routes.GetIterator(); net_route_private* before = NULL; while ((before = iterator.Next()) != NULL) { // if the before mask is less specific than the one of the route, // we can insert it before that route. if (domain->address_module->first_mask_bit(before->mask) > domain->address_module->first_mask_bit(route->mask)) break; if ((route->flags & RTF_DEFAULT) != 0 && (before->flags & RTF_DEFAULT) != 0) { // both routes are equal - let the link speed decide the // order if (before->interface_address->interface->device->link_speed < route->interface_address->interface->device->link_speed) break; } } domain->routes.Insert(before, route); update_route_infos(domain); return B_OK; }
SIPClient::SIPClient(UsageEnvironment& env, unsigned char desiredAudioRTPPayloadFormat, char const* mimeSubtype, int verbosityLevel, char const* applicationName) : Medium(env), fT1(500000 /* 500 ms */), fDesiredAudioRTPPayloadFormat(desiredAudioRTPPayloadFormat), fVerbosityLevel(verbosityLevel), fCSeq(0), fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0), fURL(NULL), fURLSize(0), fToTagStr(NULL), fToTagStrSize(0), fUserName(NULL), fUserNameSize(0), fInviteSDPDescription(NULL), fInviteSDPDescriptionReturned(NULL), fInviteCmd(NULL), fInviteCmdSize(0) { if (mimeSubtype == NULL) mimeSubtype = ""; fMIMESubtype = strDup(mimeSubtype); fMIMESubtypeSize = strlen(fMIMESubtype); if (applicationName == NULL) applicationName = ""; fApplicationName = strDup(applicationName); fApplicationNameSize = strlen(fApplicationName); struct in_addr ourAddress; ourAddress.s_addr = ourIPAddress(env); // hack fOurAddressStr = strDup(AddressString(ourAddress).val()); fOurAddressStrSize = strlen(fOurAddressStr); fOurSocket = new Groupsock(env, ourAddress, 0, 255); if (fOurSocket == NULL) { env << "ERROR: Failed to create socket for addr " << fOurAddressStr << ": " << env.getResultMsg() << "\n"; } // Now, find out our source port number. Hack: Do this by first trying to // send a 0-length packet, so that the "getSourcePort()" call will work. fOurSocket->output(envir(), (unsigned char*)"", 0); Port srcPort(0); getSourcePort(env, fOurSocket->socketNum(), srcPort); if (srcPort.num() != 0) { fOurPortNum = ntohs(srcPort.num()); } else { // No luck. Try again using a default port number: fOurPortNum = 5060; delete fOurSocket; fOurSocket = new Groupsock(env, ourAddress, fOurPortNum, 255); if (fOurSocket == NULL) { env << "ERROR: Failed to create socket for addr " << fOurAddressStr << ", port " << fOurPortNum << ": " << env.getResultMsg() << "\n"; } } // Set the "User-Agent:" header to use in each request: char const* const libName = "LIVE555 Streaming Media v"; char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; char const* libPrefix; char const* libSuffix; if (applicationName == NULL || applicationName[0] == '\0') { applicationName = libPrefix = libSuffix = ""; } else { libPrefix = " ("; libSuffix = ")"; } unsigned userAgentNameSize = fApplicationNameSize + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1; char* userAgentName = new char[userAgentNameSize]; sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix); setUserAgentString(userAgentName); delete[] userAgentName; reset(); }
void RTCPInstance ::processIncomingReport(unsigned packetSize, struct sockaddr_in const& fromAddress, int tcpSocketNum, unsigned char tcpStreamChannelId) { do { Boolean callByeHandler = False; unsigned char* pkt = fInBuf; #ifdef DEBUG fprintf(stderr, "[%p]saw incoming RTCP packet (from ", this); if (tcpSocketNum < 0) { // Note that "fromAddress" is valid only if we're receiving over UDP (not over TCP): fprintf(stderr, "address %s, port %d", AddressString(fromAddress).val(), ntohs(fromAddress.sin_port)); } else { fprintf(stderr, "TCP socket #%d, stream channel id %d", tcpSocketNum, tcpStreamChannelId); } fprintf(stderr, ")\n"); 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 (tcpSocketNum < 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 = tcpSocketNum; fromPortNum = tcpStreamChannelId; } 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, arrange for it to be called at the end of this routine. // (Note: We don't call it immediately, in case it happens to cause "this" to be deleted.) if (fByeHandlerTask != NULL && (!fByeHandleActiveParticipantsOnly || (fSource != NULL && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL) || (fSink != NULL && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) { callByeHandler = True; } // We should really check for & handle >1 SSRCs being present ##### subPacketOK = True; typeOfPacket = PACKET_BYE; break; } // Other RTCP packet types that we don't yet handle: case RTCP_PT_SDES: { #ifdef DEBUG // 'Handle' SDES packets only in debugging code, by printing out the 'SDES items': fprintf(stderr, "SDES\n"); // Process each 'chunk': Boolean chunkOK = False; ADVANCE(-4); length += 4; // hack so that we see the first SSRC/CSRC again while (length >= 8) { // A valid chunk must be at least 8 bytes long chunkOK = False; // until we learn otherwise u_int32_t SSRC_CSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4); length -= 4; fprintf(stderr, "\tSSRC/CSRC: 0x%08x\n", SSRC_CSRC); // Process each 'SDES item' in the chunk: u_int8_t itemType = *pkt; ADVANCE(1); --length; while (itemType != 0) { unsigned itemLen = *pkt; ADVANCE(1); --length; // Make sure "itemLen" allows for at least 1 zero byte at the end of the chunk: if (itemLen + 1 > length || pkt[itemLen] != 0) break; fprintf(stderr, "\t\t%s:%s\n", itemType == 1 ? "CNAME" : itemType == 2 ? "NAME" : itemType == 3 ? "EMAIL" : itemType == 4 ? "PHONE" : itemType == 5 ? "LOC" : itemType == 6 ? "TOOL" : itemType == 7 ? "NOTE" : itemType == 8 ? "PRIV" : "(unknown)", itemType < 8 ? (char*)pkt // hack, because we know it's '\0'-terminated : "???"/* don't try to print out PRIV or unknown items */); ADVANCE(itemLen); length -= itemLen; itemType = *pkt; ADVANCE(1); --length; } if (itemType != 0) break; // bad 'SDES item' // Thus, itemType == 0. This zero 'type' marks the end of the list of SDES items. // Skip over remaining zero padding bytes, so that this chunk ends on a 4-byte boundary: while (length%4 > 0 && *pkt == 0) { ADVANCE(1); --length; } if (length%4 > 0) break; // Bad (non-zero) padding byte chunkOK = True; } if (!chunkOK || length > 0) break; // bad chunk, or not enough bytes for the last chunk #endif subPacketOK = True; break; } case RTCP_PT_APP: { #ifdef DEBUG fprintf(stderr, "APP(unhandled)\n"); #endif subPacketOK = True; break; } case RTCP_PT_RTPFB: { #ifdef DEBUG fprintf(stderr, "RTPFB(unhandled)\n"); #endif subPacketOK = True; break; } case RTCP_PT_PSFB: { #ifdef DEBUG fprintf(stderr, "PSFB(unhandled)\n"); // Temporary code to show "Receiver Estimated Maximum Bitrate" (REMB) feedback reports: //##### if (length >= 12 && pkt[4] == 'R' && pkt[5] == 'E' && pkt[6] == 'M' && pkt[7] == 'B') { u_int8_t exp = pkt[9]>>2; u_int32_t mantissa = ((pkt[9]&0x03)<<16)|(pkt[10]<<8)|pkt[11]; double remb = (double)mantissa; while (exp > 0) { remb *= 2.0; exp /= 2; } fprintf(stderr, "\tReceiver Estimated Max Bitrate (REMB): %g bps\n", remb); } #endif subPacketOK = True; break; } case RTCP_PT_XR: { #ifdef DEBUG fprintf(stderr, "XR(unhandled)\n"); #endif subPacketOK = True; break; } case RTCP_PT_AVB: { #ifdef DEBUG fprintf(stderr, "AVB(unhandled)\n"); #endif subPacketOK = True; break; } case RTCP_PT_RSI: { #ifdef DEBUG fprintf(stderr, "RSI(unhandled)\n"); #endif subPacketOK = True; break; } case RTCP_PT_TOKEN: { #ifdef DEBUG fprintf(stderr, "TOKEN(unhandled)\n"); #endif subPacketOK = True; break; } case RTCP_PT_IDMS: { #ifdef DEBUG fprintf(stderr, "IDMS(unhandled)\n"); #endif subPacketOK = True; break; } default: { #ifdef DEBUG fprintf(stderr, "UNKNOWN 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: rc:%d, pt:%d, bytes remaining:%d, report sender SSRC:0x%08x\n", 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); // Finally, if we need to call a "BYE" handler, do so now (in case it causes "this" to get deleted): if (callByeHandler && fByeHandlerTask != NULL/*sanity check*/) { TaskFunc* byeHandler = fByeHandlerTask; fByeHandlerTask = NULL; // because we call the handler only once, by default (*byeHandler)(fByeHandlerClientData); } } while (0);
void RTCPInstance ::processIncomingReport(unsigned packetSize, struct sockaddr_in const& fromAddress) { do { Boolean callByeHandler = False; int tcpReadStreamSocketNum = fRTCPInterface.nextTCPReadStreamSocketNum(); unsigned char tcpReadStreamChannelId = fRTCPInterface.nextTCPReadStreamChannelId(); unsigned char* pkt = fInBuf; #ifdef DEBUG fprintf(stderr, "[%p]saw incoming RTCP packet", this); if (tcpReadStreamSocketNum < 0) { // Note that "fromAddress" is valid only if we're receiving over UDP (not over TCP): fprintf(stderr, " (from address %s, port %d)", AddressString(fromAddress).val(), ntohs(fromAddress.sin_port)); } fprintf(stderr, "\n"); 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, arrange for it to be called at the end of this routine. // (Note: We don't call it immediately, in case it happens to cause "this" to be deleted.) if (fByeHandlerTask != NULL && (!fByeHandleActiveParticipantsOnly || (fSource != NULL && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL) || (fSink != NULL && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) { callByeHandler = True; } // 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); // Finally, if we need to call a "BYE" handler, do so now (in case it causes "this" to get deleted): if (callByeHandler && fByeHandlerTask != NULL/*sanity check*/) { TaskFunc* byeHandler = fByeHandlerTask; fByeHandlerTask = NULL; // because we call the handler only once, by default (*byeHandler)(fByeHandlerClientData); } } while (0); }
netAddressBits ourIPAddress(UsageEnvironment& env) { static netAddressBits ourAddress = 0; int sock = -1; struct in_addr testAddr; if (ReceivingInterfaceAddr != INADDR_ANY) { // Hack: If we were told to receive on a specific interface address, then // define this to be our ip address: ourAddress = ReceivingInterfaceAddr; } if (ourAddress == 0) { // We need to find our source address struct sockaddr_in fromAddr; fromAddr.sin_addr.s_addr = 0; // Get our address by sending a (0-TTL) multicast packet, // receiving it, and looking at the source address used. // (This is kinda bogus, but it provides the best guarantee // that other nodes will think our address is the same as we do.) do { loopbackWorks = 0; // until we learn otherwise testAddr.s_addr = our_inet_addr("228.67.43.91"); // arbitrary Port testPort(15947); // ditto sock = setupDatagramSocket(env, testPort); if (sock < 0) break; if (!socketJoinGroup(env, sock, testAddr.s_addr)) break; unsigned char testString[] = "hostIdTest"; unsigned testStringLength = sizeof testString; if (!writeSocket(env, sock, testAddr, testPort.num(), 0, testString, testStringLength)) break; // Block until the socket is readable (with a 5-second timeout): fd_set rd_set; FD_ZERO(&rd_set); FD_SET((unsigned)sock, &rd_set); const unsigned numFds = sock+1; struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; int result = select(numFds, &rd_set, NULL, NULL, &timeout); if (result <= 0) break; unsigned char readBuffer[20]; int bytesRead = readSocket(env, sock, readBuffer, sizeof readBuffer, fromAddr); if (bytesRead != (int)testStringLength || strncmp((char*)readBuffer, (char*)testString, testStringLength) != 0) { break; } // We use this packet's source address, if it's good: loopbackWorks = !badAddressForUs(fromAddr.sin_addr.s_addr); } while (0); if (sock >= 0) { socketLeaveGroup(env, sock, testAddr.s_addr); closeSocket(sock); } if (!loopbackWorks) do { // We couldn't find our address using multicast loopback, // so try instead to look it up directly - by first getting our host name, and then resolving this host name char hostname[100]; hostname[0] = '\0'; int result = gethostname(hostname, sizeof hostname); if (result != 0 || hostname[0] == '\0') { env.setResultErrMsg("initial gethostname() failed"); break; } // Try to resolve "hostname" to an IP address: NetAddressList addresses(hostname); NetAddressList::Iterator iter(addresses); NetAddress const* address; // Take the first address that's not bad: netAddressBits addr = 0; while ((address = iter.nextAddress()) != NULL) { netAddressBits a = *(netAddressBits*)(address->data()); if (!badAddressForUs(a)) { addr = a; break; } } // Assign the address that we found to "fromAddr" (as if the 'loopback' method had worked), to simplify the code below: fromAddr.sin_addr.s_addr = addr; } while (0); // Make sure we have a good address: netAddressBits from = fromAddr.sin_addr.s_addr; if (badAddressForUs(from)) { char tmp[100]; sprintf(tmp, "This computer has an invalid IP address: %s", AddressString(from).val()); env.setResultMsg(tmp); from = 0; } ourAddress = from; // Use our newly-discovered IP address, and the current time, // to initialize the random number generator's seed: struct timeval timeNow; gettimeofday(&timeNow, NULL); unsigned seed = ourAddress^timeNow.tv_sec^timeNow.tv_usec; our_srandom(seed); } return ourAddress; }
status_t tcp_receive_data(net_buffer* buffer) { TRACE(("TCP: Received buffer %p\n", buffer)); if (buffer->interface_address == NULL || buffer->interface_address->domain == NULL) return B_ERROR; net_domain* domain = buffer->interface_address->domain; net_address_module_info* addressModule = domain->address_module; NetBufferHeaderReader<tcp_header> bufferHeader(buffer); if (bufferHeader.Status() < B_OK) return bufferHeader.Status(); tcp_header& header = bufferHeader.Data(); uint16 headerLength = header.HeaderLength(); if (headerLength < sizeof(tcp_header)) return B_BAD_DATA; if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer, IPPROTO_TCP) != 0) return B_BAD_DATA; addressModule->set_port(buffer->source, header.source_port); addressModule->set_port(buffer->destination, header.destination_port); TRACE((" Looking for: peer %s, local %s\n", AddressString(domain, buffer->source, true).Data(), AddressString(domain, buffer->destination, true).Data())); //dump_tcp_header(header); //gBufferModule->dump(buffer); tcp_segment_header segment(header.flags); segment.sequence = header.Sequence(); segment.acknowledge = header.Acknowledge(); segment.advertised_window = header.AdvertisedWindow(); segment.urgent_offset = header.UrgentOffset(); process_options(segment, buffer, headerLength - sizeof(tcp_header)); bufferHeader.Remove(headerLength); // we no longer need to keep the header around EndpointManager* endpointManager = endpoint_manager_for(domain); if (endpointManager == NULL) { TRACE((" No endpoint manager!\n")); return B_ERROR; } int32 segmentAction = DROP; TCPEndpoint* endpoint = endpointManager->FindConnection( buffer->destination, buffer->source); if (endpoint != NULL) { segmentAction = endpoint->SegmentReceived(segment, buffer); gSocketModule->release_socket(endpoint->socket); } else if ((segment.flags & TCP_FLAG_RESET) == 0) segmentAction = DROP | RESET; if ((segmentAction & RESET) != 0) { // send reset endpointManager->ReplyWithReset(segment, buffer); } if ((segmentAction & DROP) != 0) gBufferModule->free(buffer); return B_OK; }
void RTCPInstance::incomingReportHandler1() { do { Boolean callByeHandler = False; int tcpReadStreamSocketNum = fRTCPInterface.nextTCPReadStreamSocketNum(); unsigned char tcpReadStreamChannelId = fRTCPInterface.nextTCPReadStreamChannelId(); unsigned packetSize = 0; unsigned numBytesRead; struct sockaddr_in fromAddress; Boolean packetReadWasIncomplete; if (fNumBytesAlreadyRead >= maxRTCPPacketSize) { envir() << "RTCPInstance error: Hit limit when reading incoming packet over TCP. Increase \"maxRTCPPacketSize\"\n"; break; } Boolean readResult = fRTCPInterface.handleRead(&fInBuf[fNumBytesAlreadyRead], maxRTCPPacketSize - 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) 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", this); if (tcpReadStreamSocketNum < 0) { // Note that "fromAddress" is valid only if we're receiving over UDP (not over TCP): fprintf(stderr, " (from address %s, port %d)", AddressString(fromAddress).val(), ntohs(fromAddress.sin_port)); } fprintf(stderr, "\n"); 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, arrange for it to be called at the end of this routine. // (Note: We don't call it immediately, in case it happens to cause "this" to be deleted.) if (fByeHandlerTask != NULL && (!fByeHandleActiveParticipantsOnly || (fSource != NULL && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL) || (fSink != NULL && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) { callByeHandler = True; } // 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); // Finally, if we need to call a "BYE" handler, do so now (in case it causes "this" to get deleted): if (callByeHandler && fByeHandlerTask != NULL/*sanity check*/) { TaskFunc* byeHandler = fByeHandlerTask; fByeHandlerTask = NULL; // because we call the handler only once, by default (*byeHandler)(fByeHandlerClientData); } } while (0); }