Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package live555 for openSUSE:Factory checked in at 2026-10-28 17:45:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/live555 (Old) and /work/SRC/openSUSE:Factory/.live555.new.2252680 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "live555" Wed Oct 28 17:45:53 2026 rev:52 rq:1393140 version:2026.10.24 Changes: -------- --- /work/SRC/openSUSE:Factory/live555/live555.changes 2026-10-24 22:05:16.687236292 +0200 +++ /work/SRC/openSUSE:Factory/.live555.new.2252680/live555.changes 2026-10-28 17:45:57.062565705 +0100 @@ -1,0 +2,12 @@ +Sun Oct 25 20:39:50 UTC 2026 - Bjørn Lie <[email protected]> + +- Update to version 2026.10.24: + * In "RTPInterface::handleRead()", if we're reading from a TCP socket, call + "getpeername()" to set our "fromAddress", because the "recvfrom()" call + won't set it. + * Added a check to "AC3AudioStreamParser" for a buffer overflow that probably + won't happen, but to be safe... + * Began replacing some calls to "sprintf()" (that were perfectly safe, but + caused some compilers to emit warning messages) with calls to "snprintf()". + +------------------------------------------------------------------- Old: ---- live.2026.10.23.tar.gz New: ---- live.2026.10.24.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ live555.spec ++++++ --- /var/tmp/diff_new_pack.FslyjD/_old 2026-10-28 17:45:57.976603963 +0100 +++ /var/tmp/diff_new_pack.FslyjD/_new 2026-10-28 17:45:57.978604046 +0100 @@ -19,7 +19,7 @@ %define lmdmaj 122 Name: live555 -Version: 2026.10.23 +Version: 2026.10.24 Release: 0 Summary: LIVE555 Streaming Media License: LGPL-2.1-only ++++++ live.2026.10.23.tar.gz -> live.2026.10.24.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh new/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh --- old/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh 2026-10-23 02:04:27.000000000 +0200 +++ new/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh 2026-10-24 05:04:52.000000000 +0200 @@ -19,8 +19,8 @@ #ifndef _BASICUSAGEENVIRONMENT_VERSION_HH #define _BASICUSAGEENVIRONMENT_VERSION_HH -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.10.23" -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1792713600 +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.10.24" +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1792800000 extern char const* const BasicUsageEnvironmentLibraryVersionStr; extern int const BasicUsageEnvironmentLibraryVersionInt; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/UsageEnvironment/include/UsageEnvironment_version.hh new/live/UsageEnvironment/include/UsageEnvironment_version.hh --- old/live/UsageEnvironment/include/UsageEnvironment_version.hh 2026-10-23 02:04:27.000000000 +0200 +++ new/live/UsageEnvironment/include/UsageEnvironment_version.hh 2026-10-24 05:04:52.000000000 +0200 @@ -19,8 +19,8 @@ #ifndef _USAGEENVIRONMENT_VERSION_HH #define _USAGEENVIRONMENT_VERSION_HH -#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.10.23" -#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1792713600 +#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.10.24" +#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1792800000 extern char const* const UsageEnvironmentLibraryVersionStr; extern int const UsageEnvironmentLibraryVersionInt; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/config.linux-with-shared-libraries new/live/config.linux-with-shared-libraries --- old/live/config.linux-with-shared-libraries 2026-10-23 02:04:48.000000000 +0200 +++ new/live/config.linux-with-shared-libraries 2026-10-24 05:05:53.000000000 +0200 @@ -4,7 +4,7 @@ # One or more interfaces were added, but no existing interfaces were changed or removed => CURRENT += 1; REVISION = 0; AGE += 1 libliveMedia_VERSION_CURRENT=122 -libliveMedia_VERSION_REVISION=0 +libliveMedia_VERSION_REVISION=1 libliveMedia_VERSION_AGE=0 libliveMedia_LIB_SUFFIX=so.$(shell expr $(libliveMedia_VERSION_CURRENT) - $(libliveMedia_VERSION_AGE)).$(libliveMedia_VERSION_AGE).$(libliveMedia_VERSION_REVISION) @@ -19,7 +19,7 @@ libUsageEnvironment_LIB_SUFFIX=so.$(shell expr $(libUsageEnvironment_VERSION_CURRENT) - $(libUsageEnvironment_VERSION_AGE)).$(libUsageEnvironment_VERSION_AGE).$(libUsageEnvironment_VERSION_REVISION) libgroupsock_VERSION_CURRENT=33 -libgroupsock_VERSION_REVISION=1 +libgroupsock_VERSION_REVISION=2 libgroupsock_VERSION_AGE=0 libgroupsock_LIB_SUFFIX=so.$(shell expr $(libgroupsock_VERSION_CURRENT) - $(libgroupsock_VERSION_AGE)).$(libgroupsock_VERSION_AGE).$(libgroupsock_VERSION_REVISION) ##### diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/groupsock/Groupsock.cpp new/live/groupsock/Groupsock.cpp --- old/live/groupsock/Groupsock.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/groupsock/Groupsock.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -425,7 +425,7 @@ // Make sure the "sock" parameter is in bounds: if (sock < 0) { char buf[100]; - sprintf(buf, "trying to use bad socket (%d)", sock); + snprintf(buf, sizeof buf, "trying to use bad socket (%d)", sock); env.setResultMsg(buf); break; } @@ -437,7 +437,7 @@ = (sockets->Lookup((char*)(long)sock) != 0); if (alreadyExists) { char buf[100]; - sprintf(buf, "Attempting to replace an existing socket (%d)", sock); + snprintf(buf, sizeof buf, "Attempting to replace an existing socket (%d)", sock); env.setResultMsg(buf); break; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/groupsock/GroupsockHelper.cpp new/live/groupsock/GroupsockHelper.cpp --- old/live/groupsock/GroupsockHelper.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/groupsock/GroupsockHelper.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -180,7 +180,7 @@ MAKE_SOCKADDR_IN(name, addr, port.num()); if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { char tmpBuffer[100]; - sprintf(tmpBuffer, "IPv4 bind() error (port number: %d): ", ntohs(port.num())); + snprintf(tmpBuffer, sizeof tmpBuffer, "IPv4 bind() error (port number: %d): ", ntohs(port.num())); socketErr(env, tmpBuffer); closeSocket(newSocket); return -1; @@ -200,7 +200,7 @@ MAKE_SOCKADDR_IN6(name, addr, port.num()); if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { char tmpBuffer[100]; - sprintf(tmpBuffer, "IPv6 bind() error (port number: %d): ", ntohs(port.num())); + snprintf(tmpBuffer, sizeof tmpBuffer, "IPv6 bind() error (port number: %d): ", ntohs(port.num())); socketErr(env, tmpBuffer); closeSocket(newSocket); return -1; @@ -362,7 +362,7 @@ MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num()); if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { char tmpBuffer[100]; - sprintf(tmpBuffer, "IPv4 bind() error (port number: %d): ", ntohs(port.num())); + snprintf(tmpBuffer, sizeof tmpBuffer, "IPv4 bind() error (port number: %d): ", ntohs(port.num())); socketErr(env, tmpBuffer); closeSocket(newSocket); return -1; @@ -381,7 +381,7 @@ MAKE_SOCKADDR_IN6(name, ReceivingInterfaceAddr6, port.num()); if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { char tmpBuffer[100]; - sprintf(tmpBuffer, "IPv6 bind() error (port number: %d): ", ntohs(port.num())); + snprintf(tmpBuffer, sizeof tmpBuffer, "IPv6 bind() error (port number: %d): ", ntohs(port.num())); socketErr(env, tmpBuffer); closeSocket(newSocket); return -1; @@ -475,9 +475,9 @@ int bytesSent = sendto(socket, (char*)buffer, bufferSize, MSG_NOSIGNAL, (struct sockaddr const*)&addressAndPort, dest_len); if (bytesSent != (int)bufferSize) { - char tmpBuf[100]; - sprintf(tmpBuf, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize); - socketErr(env, tmpBuf); + char tmpBuffer[100]; + snprintf(tmpBuffer, sizeof tmpBuffer, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize); + socketErr(env, tmpBuffer); break; } @@ -1013,7 +1013,7 @@ time_t tvNow_t = tvNow.tv_sec; char const* ctimeResult = ctime(&tvNow_t); if (ctimeResult == NULL) { - sprintf(timeString, "??:??:??"); + snprintf(timeString, sizeof timeString, "??:??:??"); } else { char const* from = &ctimeResult[11]; int i; @@ -1027,7 +1027,7 @@ // a timestamp string just using the integer and fractional parts // of "tvNow": static char timeString[50]; - sprintf(timeString, "%lu.%06ld", tvNow.tv_sec, tvNow.tv_usec); + snprintf(timeString, sizeof timeString, "%lu.%06ld", tvNow.tv_sec, tvNow.tv_usec); #endif return (char const*)&timeString; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/groupsock/NetAddress.cpp new/live/groupsock/NetAddress.cpp --- old/live/groupsock/NetAddress.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/groupsock/NetAddress.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -475,8 +475,9 @@ break; } default: { - fVal = new char[200]; // more than enough for this error message - sprintf(fVal, "(unknown address family %d)", addr.ss_family); + size_t const msgMaxSize = 200; // more than enough for this error message + fVal = new char[msgMaxSize]; // more than enough for this error message + snprintf(fVal, msgMaxSize, "(unknown address family %d)", addr.ss_family); break; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/groupsock/include/groupsock_version.hh new/live/groupsock/include/groupsock_version.hh --- old/live/groupsock/include/groupsock_version.hh 2026-10-23 02:04:27.000000000 +0200 +++ new/live/groupsock/include/groupsock_version.hh 2026-10-24 05:04:52.000000000 +0200 @@ -19,8 +19,8 @@ #ifndef _GROUPSOCK_VERSION_HH #define _GROUPSOCK_VERSION_HH -#define GROUPSOCK_LIBRARY_VERSION_STRING "2026.10.23" -#define GROUPSOCK_LIBRARY_VERSION_INT 1792713600 +#define GROUPSOCK_LIBRARY_VERSION_STRING "2026.10.24" +#define GROUPSOCK_LIBRARY_VERSION_INT 1792800000 extern char const* const groupsockLibraryVersionStr; extern int const groupsockLibraryVersionInt; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/hlsProxy/live555HLSProxy.cpp new/live/hlsProxy/live555HLSProxy.cpp --- old/live/hlsProxy/live555HLSProxy.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/hlsProxy/live555HLSProxy.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -462,9 +462,10 @@ // Then, rewrite our ".m3u8" file with the new list of segments: if (ourM3U8FileName == NULL) { - ourM3U8FileName = new char[strlen(hlsPrefix) + 5/*strlen(".m3u8")*/ + 1]; + size_t fileNameSize = strlen(hlsPrefix) + 5/*strlen(".m3u8")*/ + 1; + ourM3U8FileName = new char[fileNameSize]; if (ourM3U8FileName == NULL) exit(1); - sprintf(ourM3U8FileName, "%s.m3u8", hlsPrefix); + snprintf(ourM3U8FileName, fileNameSize, "%s.m3u8", hlsPrefix); } // Open our ".m3u8" file for output, and write the prefix: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/#RTPInterface.cpp# new/live/liveMedia/#RTPInterface.cpp# --- old/live/liveMedia/#RTPInterface.cpp# 1970-01-01 01:00:00.000000000 +0100 +++ new/live/liveMedia/#RTPInterface.cpp# 2026-10-24 05:04:52.000000000 +0200 @@ -0,0 +1,371 @@ +@ RTPInterface::handleRead(socket %d): getpeername() returned %d: %s:0x%04x\n", tcpSocketNum, gpnResult, AddressString(fromAddress).val(), portNum(fromAddress)); + + while ((curBytesRead = (fNextTCPReadTLSState != NULL && fNextTCPReadTLSState->isNeeded) + ? fNextTCPReadTLSState->read(&buffer[bytesRead], curBytesToRead) + : readSocket(envir(), fNextTCPReadStreamSocketNum, + &buffer[bytesRead], curBytesToRead, + fromAddress)) > 0) { + bytesRead += curBytesRead; + if (bytesRead >= totBytesToRead) break; + curBytesToRead -= curBytesRead; + } + fNextTCPReadSize -= bytesRead; + if (fNextTCPReadSize == 0) { + // We've read all of the data that we asked for + readSuccess = True; + } else if (curBytesRead < 0) { + // There was an error reading the socket + bytesRead = 0; + readSuccess = False; + } else { + // We need to read more bytes, and there was not an error reading the socket + packetReadWasIncomplete = True; + return True; + } + fNextTCPReadStreamSocketNum = -1; // default, for next time + } + + if (readSuccess && fAuxReadHandlerFunc != NULL) { + // Also pass the newly-read packet data to our auxilliary handler: + (*fAuxReadHandlerFunc)(fAuxReadHandlerClientData, buffer, bytesRead); + } + return readSuccess; +} + +void RTPInterface::stopNetworkReading() { + // Normal case + if (fGS != NULL) envir().taskScheduler().turnOffBackgroundReadHandling(fGS->socketNum()); + + // Also turn off read handling on each of our TCP connections: + for (tcpStreamRecord* streams = fTCPStreams; streams != NULL; streams = streams->fNext) { + deregisterSocket(envir(), streams->fStreamSocketNum, streams->fStreamChannelId); + } +} + + +////////// Helper Functions - Implementation ///////// + +Boolean RTPInterface::sendRTPorRTCPPacketOverTCP(u_int8_t* packet, unsigned packetSize, + int socketNum, unsigned char streamChannelId, + TLSState* tlsState) { +#ifdef DEBUG_SEND + fprintf(stderr, "sendRTPorRTCPPacketOverTCP: %d bytes over channel %d (socket %d)\n", + packetSize, streamChannelId, socketNum); fflush(stderr); +#endif + // Send a RTP/RTCP packet over TCP, using the encoding defined in RFC 2326, section 10.12: + // $<streamChannelId><packetSize><packet> + // (If the initial "send()" of '$<streamChannelId><packetSize>' succeeds, then we force + // the subsequent "send()" for the <packet> data to succeed, even if we have to do so with + // a blocking "send()".) + do { + u_int8_t framingHeader[4]; + framingHeader[0] = '$'; + framingHeader[1] = streamChannelId; + framingHeader[2] = (u_int8_t) ((packetSize&0xFF00)>>8); + framingHeader[3] = (u_int8_t) (packetSize&0xFF); + if (!sendDataOverTCP(socketNum, tlsState, framingHeader, 4, False)) break; + + if (!sendDataOverTCP(socketNum, tlsState, packet, packetSize, True)) break; +#ifdef DEBUG_SEND + fprintf(stderr, "sendRTPorRTCPPacketOverTCP: completed\n"); fflush(stderr); +#endif + + return True; + } while (0); + +#ifdef DEBUG_SEND + fprintf(stderr, "sendRTPorRTCPPacketOverTCP: failed! (errno %d)\n", envir().getErrno()); fflush(stderr); +#endif + return False; +} + +#ifndef RTPINTERFACE_BLOCKING_WRITE_TIMEOUT_MS +#define RTPINTERFACE_BLOCKING_WRITE_TIMEOUT_MS 500 +#endif + +Boolean RTPInterface::sendDataOverTCP(int socketNum, TLSState* tlsState, + u_int8_t const* data, unsigned dataSize, + Boolean forceSendToSucceed) { + int sendResult = (tlsState != NULL && tlsState->isNeeded) + ? tlsState->write((char const*)data, dataSize) + : send(socketNum, (char const*)data, dataSize, MSG_NOSIGNAL/*flags*/); + if (sendResult < (int)dataSize) { + // The TCP send() failed - at least partially. + + unsigned numBytesSentSoFar = sendResult < 0 ? 0 : (unsigned)sendResult; + if (numBytesSentSoFar > 0 || (forceSendToSucceed && envir().getErrno() == EAGAIN)) { + // The OS's TCP send buffer has filled up (because the stream's bitrate has exceeded + // the capacity of the TCP connection!). + // Force this data write to succeed, by blocking if necessary until it does: + unsigned numBytesRemainingToSend = dataSize - numBytesSentSoFar; +#ifdef DEBUG_SEND + fprintf(stderr, "sendDataOverTCP: resending %d-byte send (blocking)\n", numBytesRemainingToSend); fflush(stderr); +#endif + makeSocketBlocking(socketNum, RTPINTERFACE_BLOCKING_WRITE_TIMEOUT_MS); + sendResult = (tlsState != NULL && tlsState->isNeeded) + ? tlsState->write((char const*)(&data[numBytesSentSoFar]), numBytesRemainingToSend) + : send(socketNum, (char const*)(&data[numBytesSentSoFar]), numBytesRemainingToSend, MSG_NOSIGNAL/*flags*/); + makeSocketNonBlocking(socketNum); + if ((unsigned)sendResult != numBytesRemainingToSend) { + // The blocking "send()" failed, or timed out. In either case, we assume that the + // TCP connection has failed (or is 'hanging' indefinitely), and we stop using it + // (for both RTP and RTP). + // (If we kept using the socket here, the RTP or RTCP packet write would be in an + // incomplete, inconsistent state.) +#ifdef DEBUG_SEND + fprintf(stderr, "sendDataOverTCP: blocking send() failed (delivering %d bytes out of %d); closing socket %d\n", sendResult, numBytesRemainingToSend, socketNum); fflush(stderr); +#endif + removeStreamSocket(socketNum, 0xFF); + return False; + } + + return True; + } else if (sendResult < 0 && envir().getErrno() != EAGAIN) { + // Because the "send()" call failed, assume that the socket is now unusable, so stop + // using it (for both RTP and RTCP): + removeStreamSocket(socketNum, 0xFF); + } + + return False; + } + + return True; +} + +SocketDescriptor::SocketDescriptor(UsageEnvironment& env, int socketNum, TLSState* tlsState) + : fEnv(env), fOurSocketNum(socketNum), fTLSState(tlsState), + fSubChannelHashTable(HashTable::create(ONE_WORD_HASH_KEYS)), + fServerRequestAlternativeByteHandler(NULL), fServerRequestAlternativeByteHandlerClientData(NULL), + fReadErrorOccurred(False), fDeleteMyselfNext(False), fAreInReadHandlerLoop(False), fTCPReadingState(AWAITING_DOLLAR) { +} + +SocketDescriptor::~SocketDescriptor() { + fDeleteMyselfNext = False; + fEnv.taskScheduler().turnOffBackgroundReadHandling(fOurSocketNum); + removeSocketDescription(fEnv, fOurSocketNum); + + if (fSubChannelHashTable != NULL) { + // Remove knowledge of this socket from any "RTPInterface"s that are using it: + HashTable::Iterator* iter = HashTable::Iterator::create(*fSubChannelHashTable); + RTPInterface* rtpInterface; + char const* key; + + while ((rtpInterface = (RTPInterface*)(iter->next(key))) != NULL) { + u_int64_t streamChannelIdLong = (u_int64_t)key; + unsigned char streamChannelId = (unsigned char)streamChannelIdLong; + + rtpInterface->removeStreamSocket(fOurSocketNum, streamChannelId); + } + delete iter; + + // Then remove the hash table entries themselves, and then remove the hash table: + while (fSubChannelHashTable->RemoveNext() != NULL) {} + delete fSubChannelHashTable; + } + + // Finally: + if (fServerRequestAlternativeByteHandler != NULL) { + // Hack: Pass a special character to our alternative byte handler, to tell it that either + // - an error occurred when reading the TCP socket, or + // - no error occurred, but it needs to take over control of the TCP socket once again. + u_int8_t specialChar = fReadErrorOccurred ? 0xFF : 0xFE; + (*fServerRequestAlternativeByteHandler)(fServerRequestAlternativeByteHandlerClientData, specialChar); + } +} + +void SocketDescriptor::registerRTPInterface(unsigned char streamChannelId, + RTPInterface* rtpInterface) { + Boolean isFirstRegistration = fSubChannelHashTable->IsEmpty(); +#if defined(DEBUG_SEND)||defined(DEBUG_RECEIVE) + fprintf(stderr, "SocketDescriptor(socket %d)::registerRTPInterface(channel %d): isFirstRegistration %d\n", fOurSocketNum, streamChannelId, isFirstRegistration); +#endif + fSubChannelHashTable->Add((char const*)(long)streamChannelId, + rtpInterface); + + if (isFirstRegistration) { + // Arrange to handle reads on this TCP socket: + TaskScheduler::BackgroundHandlerProc* handler + = (TaskScheduler::BackgroundHandlerProc*)&tcpReadHandler; + fEnv.taskScheduler(). + setBackgroundHandling(fOurSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION, handler, this); + } +} + +RTPInterface* SocketDescriptor +::lookupRTPInterface(unsigned char streamChannelId) { + char const* lookupArg = (char const*)(long)streamChannelId; + return (RTPInterface*)(fSubChannelHashTable->Lookup(lookupArg)); +} + +void SocketDescriptor +::deregisterRTPInterface(unsigned char streamChannelId) { +#if defined(DEBUG_SEND)||defined(DEBUG_RECEIVE) + fprintf(stderr, "SocketDescriptor(socket %d)::deregisterRTPInterface(channel %d)\n", fOurSocketNum, streamChannelId); +#endif + fSubChannelHashTable->Remove((char const*)(long)streamChannelId); + + if (fSubChannelHashTable->IsEmpty()) { + // No more interfaces are using us, so it's curtains for us now: + if (fAreInReadHandlerLoop) { + fDeleteMyselfNext = True; // we can't delete ourself yet, but we'll do so from "tcpReadHandler()" below + } else { + delete this; + } + } +} + +void SocketDescriptor::tcpReadHandler(SocketDescriptor* socketDescriptor, int mask) { + // Call the read handler until it returns false, with a limit to avoid starving other sockets + unsigned count = 2000; + Boolean areInRecursiveCall = socketDescriptor->fAreInReadHandlerLoop; + + socketDescriptor->fAreInReadHandlerLoop = True; + while (!socketDescriptor->fDeleteMyselfNext && socketDescriptor->tcpReadHandler1(mask) && --count > 0) {} + if (!areInRecursiveCall) { + socketDescriptor->fAreInReadHandlerLoop = False; + if (socketDescriptor->fDeleteMyselfNext) delete socketDescriptor; + } +} + +Boolean SocketDescriptor::tcpReadHandler1(int mask) { + // We expect the following data over the TCP channel: + // optional RTSP command or response bytes (before the first '$' character) + // a '$' character + // a 1-byte channel id + // a 2-byte packet size (in network byte order) + // the packet data. + // However, because the socket is being read asynchronously, this data might arrive in pieces. + + u_int8_t c; + struct sockaddr_storage dummy; // not used + if (fTCPReadingState != AWAITING_PACKET_DATA) { + int result = (fTLSState != NULL && fTLSState->isNeeded) + ? fTLSState->read(&c, 1) + : readSocket(fEnv, fOurSocketNum, &c, 1, dummy); + if (result == 0) { // There was no more data to read + return False; + } else if (result != 1) { // error reading TCP socket, so we will no longer handle it +#ifdef DEBUG_RECEIVE + fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): readSocket(1 byte) returned %d (error)\n", fOurSocketNum, result); +#endif + fReadErrorOccurred = True; + fDeleteMyselfNext = True; + return False; + } + } + + Boolean callAgain = True; + switch (fTCPReadingState) { + case AWAITING_DOLLAR: { + if (c == '$') { +#ifdef DEBUG_RECEIVE + fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): Saw '$'\n", fOurSocketNum); +#endif + fTCPReadingState = AWAITING_STREAM_CHANNEL_ID; + } else { + // This character is part of a RTSP request or command, which is handled separately: + if (fServerRequestAlternativeByteHandler != NULL && c != 0xFF && c != 0xFE) { + // Hack: 0xFF and 0xFE are used as special signaling characters, so don't send them + (*fServerRequestAlternativeByteHandler)(fServerRequestAlternativeByteHandlerClientData, c); + } + } + break; + } + case AWAITING_STREAM_CHANNEL_ID: { + // The byte that we read is the stream channel id. + if (lookupRTPInterface(c) != NULL) { // sanity check + fStreamChannelId = c; + fTCPReadingState = AWAITING_SIZE1; + } else { + // This wasn't a stream channel id that we expected. We're (somehow) in a strange state. Try to recover: +#ifdef DEBUG_RECEIVE + fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): Saw nonexistent stream channel id: 0x%02x\n", fOurSocketNum, c); +#endif + fTCPReadingState = AWAITING_DOLLAR; + } + break; + } + case AWAITING_SIZE1: { + // The byte that we read is the first (high) byte of the 16-bit RTP or RTCP packet 'size'. + fSizeByte1 = c; + fTCPReadingState = AWAITING_SIZE2; + break; + } + case AWAITING_SIZE2: { + // The byte that we read is the second (low) byte of the 16-bit RTP or RTCP packet 'size'. + unsigned short size = (fSizeByte1<<8)|c; + + // Record the information about the packet data that will be read next: + RTPInterface* rtpInterface = lookupRTPInterface(fStreamChannelId); + if (rtpInterface != NULL) { + rtpInterface->fNextTCPReadSize = size; + rtpInterface->fNextTCPReadStreamSocketNum = fOurSocketNum; + rtpInterface->fNextTCPReadStreamChannelId = fStreamChannelId; + rtpInterface->fNextTCPReadTLSState = fTLSState; + } + fTCPReadingState = AWAITING_PACKET_DATA; + break; + } + case AWAITING_PACKET_DATA: { + callAgain = False; + fTCPReadingState = AWAITING_DOLLAR; // the next state, unless we end up having to read more data in the current state + // Call the appropriate read handler to get the packet data from the TCP stream: + RTPInterface* rtpInterface = lookupRTPInterface(fStreamChannelId); + if (rtpInterface != NULL) { + if (rtpInterface->fNextTCPReadSize == 0) { + // We've already read all the data for this packet. + break; + } + if (rtpInterface->fReadHandlerProc != NULL) { +#ifdef DEBUG_RECEIVE + fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): reading %d bytes on channel %d\n", fOurSocketNum, rtpInterface->fNextTCPReadSize, rtpInterface->fNextTCPReadStreamChannelId); +#endif + fTCPReadingState = AWAITING_PACKET_DATA; + rtpInterface->fReadHandlerProc(rtpInterface->fOwner, mask); + } else { +#ifdef DEBUG_RECEIVE + fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): No handler proc for \"rtpInterface\" for channel %d; need to skip %d remaining bytes\n", fOurSocketNum, fStreamChannelId, rtpInterface->fNextTCPReadSize); +#endif + int result = (fTLSState != NULL && fTLSState->isNeeded) + ? fTLSState->read(&c, 1) + : readSocket(fEnv, fOurSocketNum, &c, 1, dummy); + if (result < 0) { // error reading TCP socket, so we will no longer handle it +#ifdef DEBUG_RECEIVE + fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): readSocket(1 byte) returned %d (error)\n", fOurSocketNum, result); +#endif + fReadErrorOccurred = True; + fDeleteMyselfNext = True; + return False; + } else { + fTCPReadingState = AWAITING_PACKET_DATA; + if (result == 1) { + --rtpInterface->fNextTCPReadSize; + callAgain = True; + } + } + } + } +#ifdef DEBUG_RECEIVE + else fprintf(stderr, "SocketDescriptor(socket %d)::tcpReadHandler(): No \"rtpInterface\" for channel %d\n", fOurSocketNum, fStreamChannelId); +#endif + } + } + + return callAgain; +} + + +////////// tcpStreamRecord implementation ////////// + +tcpStreamRecord +::tcpStreamRecord(int streamSocketNum, unsigned char streamChannelId, + TLSState* tlsState, + tcpStreamRecord* next) + : fNext(next), + fStreamSocketNum(streamSocketNum), fStreamChannelId(streamChannelId), + fTLSState(tlsState) { +} + +tcpStreamRecord::~tcpStreamRecord() { + delete fNext; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/AC3AudioStreamFramer.cpp new/live/liveMedia/AC3AudioStreamFramer.cpp --- old/live/liveMedia/AC3AudioStreamFramer.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/liveMedia/AC3AudioStreamFramer.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -227,8 +227,7 @@ delete[] fSavedFrame; } -void AC3AudioStreamParser::registerReadInterest(unsigned char* to, - unsigned maxSize) { +void AC3AudioStreamParser::registerReadInterest(unsigned char* to, unsigned maxSize) { fTo = to; fMaxSize = maxSize; } @@ -254,6 +253,13 @@ unsigned AC3AudioStreamParser::parseFrame(unsigned& numTruncatedBytes) { if (fSavedFrameSize > 0) { // We've already read and parsed a frame. Use it instead: + if (fSavedFrameSize > fMaxSize) { + numTruncatedBytes = fSavedFrameSize - fMaxSize; + fSavedFrameSize = fMaxSize; + } else { + numTruncatedBytes = 0; + } + memmove(fTo, fSavedFrame, fSavedFrameSize); delete[] fSavedFrame; fSavedFrame = NULL; unsigned frameSize = fSavedFrameSize; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MediaSession.cpp new/live/liveMedia/MediaSession.cpp --- old/live/liveMedia/MediaSession.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/liveMedia/MediaSession.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -303,7 +303,7 @@ static Boolean parseTwoStringValues(char const* sdpLine, char const* searchFormat, char*& result1, char*& result2) { Boolean parseSuccess = False; - size_t sdpLineSize = strlen(sdpLine) + 1; + size_t const sdpLineSize = strlen(sdpLine) + 1; char* buffer1 = new char[sdpLineSize]; char* buffer2 = new char[sdpLineSize]; @@ -385,7 +385,7 @@ } static Boolean parseRangeAttribute(char const* sdpLine, char*& absStartTime, char*& absEndTime) { - size_t len = strlen(sdpLine) + 1; + size_t const len = strlen(sdpLine) + 1; char* as = new char[len]; char* ae = new char[len]; int sscanfResult = sscanf(sdpLine, "a=range: clock = %[^-\r\n]-%[^\r\n]", as, ae); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/QuickTimeFileSink.cpp new/live/liveMedia/QuickTimeFileSink.cpp --- old/live/liveMedia/QuickTimeFileSink.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/liveMedia/QuickTimeFileSink.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -1902,7 +1902,7 @@ if (psets == NULL) return 0; char const* spsBase64 = psets; - size_t comma_pos = strcspn(psets, ","); + size_t const comma_pos = strcspn(psets, ","); psets[comma_pos] = '\0'; char const* ppsBase64 = &psets[comma_pos+1]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTPInterface.cpp new/live/liveMedia/RTPInterface.cpp --- old/live/liveMedia/RTPInterface.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/liveMedia/RTPInterface.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -288,15 +288,14 @@ if (totBytesToRead > bufferMaxSize) totBytesToRead = bufferMaxSize; unsigned curBytesToRead = totBytesToRead; int curBytesRead; - // Because we're calling "readSocket()" on a stream socket, we don't expect "fromAddress" - // to be filled in, so set it to a 'dummy' value instead: - fromAddress.ss_family = AF_INET; - ((sockaddr_in&)fromAddress).sin_addr.s_addr = 0; - ((sockaddr_in&)fromAddress).sin_port = 0; + // Because we're reading from a stream socket, we don't expect "fromAddress" + // to be filled in, so call getpeername() instead to try to get this: + SOCKLEN_T namelen = sizeof (struct sockaddr_storage); + (void)getpeername(tcpSocketNum, (struct sockaddr*)&fromAddress, &namelen); while ((curBytesRead = (fNextTCPReadTLSState != NULL && fNextTCPReadTLSState->isNeeded) ? fNextTCPReadTLSState->read(&buffer[bytesRead], curBytesToRead) - : readSocket(envir(), fNextTCPReadStreamSocketNum, + : readSocket(envir(), tcpSocketNum, &buffer[bytesRead], curBytesToRead, fromAddress)) > 0) { bytesRead += curBytesRead; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTSPCommon.cpp new/live/liveMedia/RTSPCommon.cpp --- old/live/liveMedia/RTSPCommon.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/liveMedia/RTSPCommon.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -258,7 +258,7 @@ rangeStart = rangeEnd = 0.0; char const* utcTimes = ¶mStr[numCharsMatched3]; - size_t len = strlen(utcTimes) + 1; + size_t const len = strlen(utcTimes) + 1; char* as = new char[len]; char* ae = new char[len]; int sscanfResult = sscanf(utcTimes, "%[^-]-%[^\r\n]", as, ae); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/liveMedia_version.hh new/live/liveMedia/include/liveMedia_version.hh --- old/live/liveMedia/include/liveMedia_version.hh 2026-10-23 02:04:27.000000000 +0200 +++ new/live/liveMedia/include/liveMedia_version.hh 2026-10-24 05:04:52.000000000 +0200 @@ -19,8 +19,8 @@ #ifndef _LIVEMEDIA_VERSION_HH #define _LIVEMEDIA_VERSION_HH -#define LIVEMEDIA_LIBRARY_VERSION_STRING "2026.10.23" -#define LIVEMEDIA_LIBRARY_VERSION_INT 1792713600 +#define LIVEMEDIA_LIBRARY_VERSION_STRING "2026.10.24" +#define LIVEMEDIA_LIBRARY_VERSION_INT 1792800000 extern char const* const liveMediaLibraryVersionStr; extern int const liveMediaLibraryVersionInt; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/mediaServer/DynamicRTSPServer.cpp new/live/mediaServer/DynamicRTSPServer.cpp --- old/live/mediaServer/DynamicRTSPServer.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/mediaServer/DynamicRTSPServer.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -190,9 +190,9 @@ } else if (strcmp(extension, ".ts") == 0) { // Assumed to be a MPEG Transport Stream file: // Use an index file name that's the same as the TS file name, except with ".tsx": - unsigned indexFileNameLen = strlen(fileName) + 2; // allow for trailing "x\0" + size_t indexFileNameLen = strlen(fileName) + 2; // allow for trailing "x\0" char* indexFileName = new char[indexFileNameLen]; - sprintf(indexFileName, "%sx", fileName); + snprintf(indexFileName, indexFileNameLen, "%sx", fileName); NEW_SMS("MPEG Transport Stream"); sms->addSubsession(MPEG2TransportFileServerMediaSubsession::createNew(env, fileName, indexFileName, reuseSource)); delete[] indexFileName; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/mediaServer/version.hh new/live/mediaServer/version.hh --- old/live/mediaServer/version.hh 2026-10-23 02:04:27.000000000 +0200 +++ new/live/mediaServer/version.hh 2026-10-24 05:04:52.000000000 +0200 @@ -20,6 +20,6 @@ #ifndef _MEDIA_SERVER_VERSION_HH #define _MEDIA_SERVER_VERSION_HH -#define MEDIA_SERVER_VERSION_STRING "1.15" +#define MEDIA_SERVER_VERSION_STRING "1.16" #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/proxyServer/live555ProxyServer.cpp new/live/proxyServer/live555ProxyServer.cpp --- old/live/proxyServer/live555ProxyServer.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/proxyServer/live555ProxyServer.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -214,9 +214,9 @@ char const* proxiedStreamURL = argv[i]; char streamName[30]; if (argc == 2) { - sprintf(streamName, "%s", "proxyStream"); // there's just one stream; give it this name + snprintf(streamName, sizeof streamName, "%s", "proxyStream"); // there's just one stream; give it this name } else { - sprintf(streamName, "proxyStream-%d", i); // there's more than one stream; distinguish them by name + snprintf(streamName, sizeof streamName, "proxyStream-%d", i); // there's more than one stream; distinguish them by name } ServerMediaSession* sms = ProxyServerMediaSession::createNew(*env, rtspServer, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/testProgs/MPEG2TransportStreamIndexer.cpp new/live/testProgs/MPEG2TransportStreamIndexer.cpp --- old/live/testProgs/MPEG2TransportStreamIndexer.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/testProgs/MPEG2TransportStreamIndexer.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -65,18 +65,22 @@ = MPEG2IFrameIndexFromTransportStream::createNew(*env, input); // The output file name is the same as the input file name, except with suffix ".tsx": - char* outputFileName = new char[len+2]; // allow for trailing x\0 - sprintf(outputFileName, "%sx", inputFileName); + size_t const outputFileNameLen = len+2; // allow for trailing x\0 + char* outputFileName = new char[outputFileNameLen]; + snprintf(outputFileName, outputFileNameLen, "%sx", inputFileName); // Open the output file (for writing), as a 'file sink': MediaSink* output = FileSink::createNew(*env, outputFileName); if (output == NULL) { *env << "Failed to open output file \"" << outputFileName << "\"\n"; + delete[] outputFileName; exit(1); } // Start playing, to generate the output index file: *env << "Writing index file \"" << outputFileName << "\"..."; + delete[] outputFileName; + output->startPlaying(*indexer, afterPlaying, NULL); env->taskScheduler().doEventLoop(); // does not return diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/testProgs/playCommon.cpp new/live/testProgs/playCommon.cpp --- old/live/testProgs/playCommon.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/testProgs/playCommon.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -838,7 +838,7 @@ if (outputQuickTimeFile || outputAVIFile) { if (periodicFilenameSuffix[0] == '\0') { // Normally (unless the '-P <interval-in-seconds>' option was given) we output to 'stdout': - sprintf(outFileName, "stdout"); + snprintf(outFileName, sizeof outFileName, "stdout"); } else { // Otherwise output to a type-specific file name, containing "periodicFilenameSuffix": char const* prefix = fileNamePrefix[0] == '\0' ? "output" : fileNamePrefix; @@ -898,7 +898,7 @@ } else { // When outputting a single medium only, we output to 'stdout // (unless the '-P <interval-in-seconds>' option was given): - sprintf(outFileName, "stdout"); + snprintf(outFileName, sizeof outFileName, "stdout"); } FileSink* fileSink = NULL; @@ -1513,7 +1513,8 @@ struct timeval timeNow; gettimeofday(&timeNow, NULL); char timestampStr[100]; - sprintf(timestampStr, "%ld%03ld", timeNow.tv_sec, (long)(timeNow.tv_usec/1000)); + snprintf(timestampStr, sizeof timestampStr, + "%ld%03ld", timeNow.tv_sec, (long)(timeNow.tv_usec/1000)); *env << (syncStreams ? "Synchronized d" : "D") << "ata packets have begun arriving [" << timestampStr << "]\007\n"; return; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/testProgs/testH264VideoToHLSSegments.cpp new/live/testProgs/testH264VideoToHLSSegments.cpp --- old/live/testProgs/testH264VideoToHLSSegments.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/testProgs/testH264VideoToHLSSegments.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -14,7 +14,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // Copyright (c) 1996-2026, Live Networks, Inc. All rights reserved -// A program that converts a H.264 (Elementary Stream) video file into sequence of +// A program that converts a H.264 (Elementary Stream) video file into a sequence of // HLS (HTTP Live Streaming) segments, plus a ".m3u8" file that can be accessed via a web browser. // main program @@ -72,8 +72,9 @@ char const* segmentFileName, double segmentDuration) { if (ourM3U8Fid == NULL) { // Open our ".m3u8" file for output, and write the prefix: - char* ourM3U8FileName = new char[strlen(OUR_HLS_FILENAME_PREFIX) + 5/*strlen(".m3u8")*/ + 1]; - sprintf(ourM3U8FileName, "%s.m3u8", OUR_HLS_FILENAME_PREFIX); + size_t const ourM3U8FileNameLen = strlen(OUR_HLS_FILENAME_PREFIX) + 5/*strlen(".m3u8")*/ + 1; + char* ourM3U8FileName = new char[ourM3U8FileNameLen]; + snprintf(ourM3U8FileName, ourM3U8FileNameLen, "%s.m3u8", OUR_HLS_FILENAME_PREFIX); ourM3U8Fid = fopen(ourM3U8FileName, "wb"); fprintf(ourM3U8Fid, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/testProgs/testMKVSplitter.cpp new/live/testProgs/testMKVSplitter.cpp --- old/live/testProgs/testMKVSplitter.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/testProgs/testMKVSplitter.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -80,8 +80,9 @@ // Create the file name from "mimeType" by replacing "/" with "-", and adding the // track number at the end: - char* fileName = new char[strlen(mimeType) + 100/*more than enough space*/]; - sprintf(fileName, "%s-%d", mimeType, trackNumber); + size_t const fileNameLen = strlen(mimeType) + 100/*more than enough space*/; + char* fileName = new char[fileNameLen]; + snprintf(fileName, fileNameLen, "%s-%d", mimeType, trackNumber); for (unsigned j = 0; fileName[j] != '\0'; ++j) { if (fileName[j] == '/') { fileName[j] = '-'; @@ -95,6 +96,7 @@ ++numActiveTracks; fprintf(stderr, "Created output file \"%s\" for track %d\n", fileName, trackNumber); } + delete[] fileName; } if (numActiveTracks == 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/testProgs/testMPEG2TransportStreamTrickPlay.cpp new/live/testProgs/testMPEG2TransportStreamTrickPlay.cpp --- old/live/testProgs/testMPEG2TransportStreamTrickPlay.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/testProgs/testMPEG2TransportStreamTrickPlay.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -73,14 +73,17 @@ // Check whether the corresponding index file exists. // The index file name is the same as the input file name, except with suffix ".tsx": - char* indexFileName = new char[len+2]; // allow for trailing x\0 - sprintf(indexFileName, "%sx", inputFileName); + size_t const indexFileNameLen = len+2; // allow for trailing x\0 + char* indexFileName = new char[indexFileNameLen]; // allow for trailing x\0 + snprintf(indexFileName, indexFileNameLen, "%sx", inputFileName); MPEG2TransportStreamIndexFile* indexFile = MPEG2TransportStreamIndexFile::createNew(*env, indexFileName); if (indexFile == NULL) { *env << "Failed to open index file \"" << indexFileName << "\" (does it exist?)\n"; + delete[] indexFileName; exit(1); } + delete[] indexFileName; // Create a filter that generates trick mode data from the input and index files: MPEG2TransportStreamTrickModeFilter* trickModeFilter diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/testProgs/testRTSPClient.cpp new/live/testProgs/testRTSPClient.cpp --- old/live/testProgs/testRTSPClient.cpp 2026-10-23 02:04:27.000000000 +0200 +++ new/live/testProgs/testRTSPClient.cpp 2026-10-24 05:04:52.000000000 +0200 @@ -511,7 +511,7 @@ envir() << fSubsession.mediumName() << "/" << fSubsession.codecName() << ":\tReceived " << frameSize << " bytes"; if (numTruncatedBytes > 0) envir() << " (with " << numTruncatedBytes << " bytes truncated)"; char uSecsStr[6+1]; // used to output the 'microseconds' part of the presentation time - sprintf(uSecsStr, "%06u", (unsigned)presentationTime.tv_usec); + snprintf(uSecsStr, sizeof uSecsStr, "%06u", (unsigned)presentationTime.tv_usec); envir() << ".\tPresentation time: " << (int)presentationTime.tv_sec << "." << uSecsStr; if (fSubsession.rtpSource() != NULL && !fSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) { envir() << "!"; // mark the debugging output to indicate that this presentation time is not RTCP-synchronized
