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-11-10 14:38:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/live555 (Old) and /work/SRC/openSUSE:Factory/.live555.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "live555" Tue Nov 10 14:38:37 2026 rev:54 rq:1396219 version:2026.11.08 Changes: -------- --- /work/SRC/openSUSE:Factory/live555/live555.changes 2026-11-01 22:23:46.009862928 +0100 +++ /work/SRC/openSUSE:Factory/.live555.new.3759290/live555.changes 2026-11-10 14:38:44.224338311 +0100 @@ -1,0 +2,17 @@ +Mon Nov 9 04:50:17 UTC 2026 - Bjørn Lie <[email protected]> + +- Update to version 2026.11.08: + * In "MultiFramedRTPSource" (for handling RTP reception), handle the case + where a malformed RTP special header could cause no data to get delivered, + and get us into an infinite loop. We now reject (the rest of) the packet in + this case. +- Changes from version 2026.11.05: + * Updated the 'authentication' fix that we made in version 2026.09.23: We no + longer "reset()" the "Authenticator" if we get a "303" (REDIRECT) response, + because the new server might still want to do Digest authentication (with + the same username+password as the original server). + Instead, once we receive a request for Digest authentication, we no longer + allow Basic authentication (for this "RTSPClient") - either for the same + server, or for any server that we get redirected to. + +------------------------------------------------------------------- Old: ---- live.2026.10.24.tar.gz live.2026.10.29.tar.gz New: ---- live.2026.11.08.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ live555.spec ++++++ --- /var/tmp/diff_new_pack.IkWZGu/_old 2026-11-10 14:38:45.169377863 +0100 +++ /var/tmp/diff_new_pack.IkWZGu/_new 2026-11-10 14:38:45.170377905 +0100 @@ -19,7 +19,7 @@ %define lmdmaj 122 Name: live555 -Version: 2026.10.29 +Version: 2026.11.08 Release: 0 Summary: LIVE555 Streaming Media License: LGPL-2.1-only ++++++ live.2026.10.24.tar.gz -> live.2026.11.08.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/BasicUsageEnvironment/BasicTaskScheduler.cpp new/live/BasicUsageEnvironment/BasicTaskScheduler.cpp --- old/live/BasicUsageEnvironment/BasicTaskScheduler.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/BasicUsageEnvironment/BasicTaskScheduler.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -17,6 +17,10 @@ // Basic Usage Environment: for a simple, non-scripted, console application // Implementation +// REMINDER: You should not make major changes to this code. This code is intended to +// implement just a basic, simple task scheduler. If you want a more complex task scheduler, +// then you should use subclassing, with separate source code files. +// See: http://live555.com/liveMedia/faq.html#modifying-and-extending #include "BasicUsageEnvironment.hh" #include "HandlerSet.hh" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp new/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp --- old/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -17,6 +17,11 @@ // Basic Usage Environment: for a simple, non-scripted, console application // Implementation +// REMINDER: You should not make major changes to this code. This code is intended to +// implement just a basic, simple "UsageEnvironment". If you want a more complex implementation, +// then you should use subclassing, with separate source code files. +// See: http://live555.com/liveMedia/faq.html#modifying-and-extending + #include "BasicUsageEnvironment.hh" #include <stdio.h> 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-24 05:04:52.000000000 +0200 +++ new/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh 2026-11-08 17:12:02.000000000 +0100 @@ -19,8 +19,8 @@ #ifndef _BASICUSAGEENVIRONMENT_VERSION_HH #define _BASICUSAGEENVIRONMENT_VERSION_HH -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.10.24" -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1792800000 +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.11.08" +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1794096000 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-24 05:04:52.000000000 +0200 +++ new/live/UsageEnvironment/include/UsageEnvironment_version.hh 2026-11-08 17:12:02.000000000 +0100 @@ -19,8 +19,8 @@ #ifndef _USAGEENVIRONMENT_VERSION_HH #define _USAGEENVIRONMENT_VERSION_HH -#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.10.24" -#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1792800000 +#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2026.11.08" +#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1794096000 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-24 05:05:53.000000000 +0200 +++ new/live/config.linux-with-shared-libraries 2026-11-08 17:12:18.000000000 +0100 @@ -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=1 +libliveMedia_VERSION_REVISION=5 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=2 +libgroupsock_VERSION_REVISION=3 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-24 05:04:52.000000000 +0200 +++ new/live/groupsock/Groupsock.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -248,12 +248,12 @@ } void Groupsock::multicastSendOnly() { - // We disable this code for now, because - on some systems - leaving the multicast group seems to cause sent packets - // to not be received by other applications (at least, on the same host). + // We disable this code for now, because - on some systems - leaving the multicast group seems + // to cause sent packets to not be received by other applications (at least, on the same host). #if 0 - socketLeaveGroup(env(), socketNum(), groupAddress(r); + socketLeaveGroup(env(), socketNum(), groupAddress()); for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { - socketLeaveGroup(env(), socketNum(), dests->fGroupEId.groupAddress(r); + socketLeaveGroup(env(), socketNum(), dests->fGroupEId.groupAddress()); } #endif } 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-24 05:04:52.000000000 +0200 +++ new/live/groupsock/include/groupsock_version.hh 2026-11-08 17:12:02.000000000 +0100 @@ -19,8 +19,8 @@ #ifndef _GROUPSOCK_VERSION_HH #define _GROUPSOCK_VERSION_HH -#define GROUPSOCK_LIBRARY_VERSION_STRING "2026.10.24" -#define GROUPSOCK_LIBRARY_VERSION_INT 1792800000 +#define GROUPSOCK_LIBRARY_VERSION_STRING "2026.11.08" +#define GROUPSOCK_LIBRARY_VERSION_INT 1794096000 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-24 05:04:52.000000000 +0200 +++ new/live/hlsProxy/live555HLSProxy.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -462,7 +462,7 @@ // Then, rewrite our ".m3u8" file with the new list of segments: if (ourM3U8FileName == NULL) { - size_t fileNameSize = strlen(hlsPrefix) + 5/*strlen(".m3u8")*/ + 1; + size_t const fileNameSize = strlen(hlsPrefix) + 5/*strlen(".m3u8")*/ + 1; ourM3U8FileName = new char[fileNameSize]; if (ourM3U8FileName == NULL) exit(1); snprintf(ourM3U8FileName, fileNameSize, "%s.m3u8", hlsPrefix); 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-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/#RTPInterface.cpp# 1970-01-01 01:00:00.000000000 +0100 @@ -1,371 +0,0 @@ -@ 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/Media.cpp new/live/liveMedia/Media.cpp --- old/live/liveMedia/Media.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/Media.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -153,10 +153,8 @@ } } -void MediaLookupTable::generateNewName(char* mediumName, - unsigned /*maxLen*/) { - // We should really use snprintf() here, but not all systems have it - sprintf(mediumName, "liveMedia%d", fNameGenerator++); +void MediaLookupTable::generateNewName(char* mediumName, unsigned maxLen) { + snprintf(mediumName, maxLen, "liveMedia%d", fNameGenerator++); } MediaLookupTable::MediaLookupTable(UsageEnvironment& env) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MultiFramedRTPSink.cpp new/live/liveMedia/MultiFramedRTPSink.cpp --- old/live/liveMedia/MultiFramedRTPSink.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/MultiFramedRTPSink.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -430,7 +430,7 @@ // sending the next packet. struct timeval timeNow; gettimeofday(&timeNow, NULL); - int secsDiff = fNextSendTime.tv_sec - timeNow.tv_sec; + int64_t secsDiff = fNextSendTime.tv_sec - timeNow.tv_sec; int64_t uSecondsToGo = secsDiff*1000000 + (fNextSendTime.tv_usec - timeNow.tv_usec); if (uSecondsToGo < 0 || secsDiff < 0) { // sanity check: Make sure that the time-to-delay is non-negative: uSecondsToGo = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MultiFramedRTPSource.cpp new/live/liveMedia/MultiFramedRTPSource.cpp --- old/live/liveMedia/MultiFramedRTPSource.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/MultiFramedRTPSource.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -181,6 +181,13 @@ fCurPacketRTPSeqNum, fCurPacketRTPTimestamp, fPresentationTime, fCurPacketHasBeenSynchronizedUsingRTCP, fCurPacketMarkerBit); + if (frameSize == 0) { + // A "frameSize" of zero means that no data was delivered, perhaps due to a malformed + // header. Reject the rest of the packet, so that we continue to make progress: + fReorderingBuffer->releaseUsedPacket(nextPacket); + fNeedDelivery = True; + continue; + } fFrameSize += frameSize; if (!nextPacket->hasUsableData()) { @@ -188,7 +195,7 @@ fReorderingBuffer->releaseUsedPacket(nextPacket); } - if (fCurrentPacketCompletesFrame && fFrameSize > 0) { + if (fCurrentPacketCompletesFrame) { // We have all the data that the client wants. if (fNumTruncatedBytes > 0) { envir() << "MultiFramedRTPSource::doGetNextFrame1(): The total received frame size exceeds the client's buffer size (" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/OnDemandServerMediaSubsession.cpp new/live/liveMedia/OnDemandServerMediaSubsession.cpp --- old/live/liveMedia/OnDemandServerMediaSubsession.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/OnDemandServerMediaSubsession.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -142,7 +142,7 @@ streamToken = fLastStreamToken; } else { // Normal case: Create a new media source: - unsigned streamBitrate; + unsigned streamBitrate = 0; FramedSource* mediaSource = createNewStreamSource(clientSessionId, streamBitrate); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/ProxyServerMediaSession.cpp new/live/liveMedia/ProxyServerMediaSession.cpp --- old/live/liveMedia/ProxyServerMediaSession.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/ProxyServerMediaSession.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -19,6 +19,10 @@ // another (unicast or multicast) RTSP/RTP stream. // Implementation +// REMINDER: You should not make major changes to this code. +// If you want more features, then you should use subclassing, with separate source code files. +// See: http://live555.com/liveMedia/faq.html#modifying-and-extending + #include "liveMedia.hh" #include "RTSPCommon.hh" #include "GroupsockHelper.hh" // for "our_random()" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTCP.cpp new/live/liveMedia/RTCP.cpp --- old/live/liveMedia/RTCP.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/RTCP.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -116,8 +116,9 @@ return (double) (timeNow.tv_sec + timeNow.tv_usec/1000000.0); } -static unsigned const maxRTCPPacketSize = 1438; - // bytes (1500, minus some allowance for IP, UDP headers; SRTCP trailers) +static unsigned const maxRTCPPacketSize = 65536; + // allow for unusually large RTCP packets, especially when received over TCP + // (in which case there's no preceding IP and UDP headers) static unsigned const preferredRTCPPacketSize = 1000; // bytes RTCPInstance::RTCPInstance(UsageEnvironment& env, Groupsock* RTCPgs, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTPSink.cpp new/live/liveMedia/RTPSink.cpp --- old/live/liveMedia/RTPSink.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/RTPSink.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -74,8 +74,9 @@ if (rtpPayloadType() >= 96) { // the payload format type is dynamic char* encodingParamsPart; if (numChannels() != 1) { - encodingParamsPart = new char[1 + 20 /* max int len */]; - sprintf(encodingParamsPart, "/%d", numChannels()); + size_t const encodingParamsPartSize = 1 + 20 /* max int len */; + encodingParamsPart = new char[encodingParamsPartSize]; + snprintf(encodingParamsPart, encodingParamsPartSize, "/%d", numChannels()); } else { encodingParamsPart = strDup(""); } @@ -84,9 +85,9 @@ + 3 /* max char len */ + strlen(rtpPayloadFormatName()) + 20 /* max int len */ + strlen(encodingParamsPart); char* rtpmapLine = new char[rtpmapLineSize]; - sprintf(rtpmapLine, rtpmapFmt, - rtpPayloadType(), rtpPayloadFormatName(), - rtpTimestampFrequency(), encodingParamsPart); + snprintf(rtpmapLine, rtpmapLineSize, rtpmapFmt, + rtpPayloadType(), rtpPayloadFormatName(), + rtpTimestampFrequency(), encodingParamsPart); delete[] encodingParamsPart; return rtpmapLine; @@ -107,7 +108,7 @@ unsigned keyMgmtLineSize = strlen(keyMgmtFmt) + strlen(base64EncodedData); char* keyMgmtLine = new char[keyMgmtLineSize]; - sprintf(keyMgmtLine, keyMgmtFmt, base64EncodedData); + snprintf(keyMgmtLine, keyMgmtLineSize, keyMgmtFmt, base64EncodedData); delete[] base64EncodedData; return keyMgmtLine; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTSPClient.cpp new/live/liveMedia/RTSPClient.cpp --- old/live/liveMedia/RTSPClient.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/RTSPClient.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -128,8 +128,9 @@ char const* parameterName, char const* parameterValue, Authenticator* authenticator) { if (fCurrentAuthenticator < authenticator) fCurrentAuthenticator = *authenticator; - char* paramString = new char[strlen(parameterName) + strlen(parameterValue) + 10]; - sprintf(paramString, "%s: %s\r\n", parameterName, parameterValue); + size_t const paramStringSize = strlen(parameterName) + strlen(parameterValue) + 10; + char* paramString = new char[paramStringSize]; + snprintf(paramString, paramStringSize, "%s: %s\r\n", parameterName, parameterValue); unsigned result = sendRequest(new RequestRecord(++fCSeq, "SET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString)); delete[] paramString; return result; @@ -143,11 +144,12 @@ // parameterName is NULL or "" means: Send no body in the request. // parameterName is non-empty means: Send "<parameterName>\r\n" as the request body. unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName); - char* paramString = new char[parameterNameLen + 3]; // the 3 is for \r\n + the '\0' byte + size_t const paramStringSize = parameterNameLen + 3; // the 3 is for \r\n + the '\0' byte + char* paramString = new char[paramStringSize]; if (parameterName == NULL || parameterName[0] == '\0') { paramString[0] = '\0'; } else { - sprintf(paramString, "%s\r\n", parameterName); + snprintf(paramString, paramStringSize, "%s\r\n", parameterName); } unsigned result = sendRequest(new RequestRecord(++fCSeq, "GET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString)); delete[] paramString; @@ -384,7 +386,7 @@ unsigned const headerSize = strlen(formatStr) + strlen(userAgentName); delete[] fUserAgentHeaderStr; fUserAgentHeaderStr = new char[headerSize]; - sprintf(fUserAgentHeaderStr, formatStr, userAgentName); + snprintf(fUserAgentHeaderStr, headerSize, formatStr, userAgentName); fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr); } @@ -429,7 +431,7 @@ unsigned userAgentNameSize = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(liveMediaLibraryVersionStr) + strlen(libSuffix) + 1; char* userAgentName = new char[userAgentNameSize]; - sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, liveMediaLibraryVersionStr, libSuffix); + snprintf(userAgentName, userAgentNameSize, "%s%s%s%s%s", applicationName, libPrefix, libName, liveMediaLibraryVersionStr, libSuffix); setUserAgentString(userAgentName); delete[] userAgentName; } @@ -450,6 +452,7 @@ fRequestsAwaitingResponse.reset(); setBaseURL(NULL); + fTCPStreamIdCount = 0; fCurrentAuthenticator.reset(); @@ -526,7 +529,7 @@ unsigned contentLengthHeaderSize = strlen(contentLengthHeaderFmt) + 20 /* max int len */; contentLengthHeader = new char[contentLengthHeaderSize]; - sprintf(contentLengthHeader, contentLengthHeaderFmt, contentStrLen); + snprintf(contentLengthHeader, contentLengthHeaderSize, contentLengthHeaderFmt, contentStrLen); contentLengthHeaderWasAllocated = True; } @@ -552,15 +555,15 @@ + strlen(contentLengthHeader) + contentStrLen; cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - request->commandName(), cmdURL, protocolStr, - request->cseq(), - authenticatorStr, - fUserAgentHeaderStr, - fRequireStr, - extraHeaders, - contentLengthHeader, - contentStr); + snprintf(cmd, cmdSize, cmdFmt, + request->commandName(), cmdURL, protocolStr, + request->cseq(), + authenticatorStr, + fUserAgentHeaderStr, + fRequireStr, + extraHeaders, + contentLengthHeader, + contentStr); delete[] authenticatorStr; if (cmdURLWasAllocated) delete[] cmdURL; if (extraHeadersWereAllocated) delete[] extraHeaders; @@ -581,7 +584,7 @@ char const* errFmt = "%s write() failed: "; unsigned const errLength = strlen(errFmt) + strlen(request->commandName()); char* err = new char[errLength]; - sprintf(err, errFmt, request->commandName()); + snprintf(err, errLength, errFmt, request->commandName()); envir().setResultErrMsg(err); delete[] err; break; @@ -611,8 +614,9 @@ static char* createSessionString(char const* sessionId) { char* sessionStr; if (sessionId != NULL) { - sessionStr = new char[20+strlen(sessionId)]; - sprintf(sessionStr, "Session: %s\r\n", sessionId); + size_t const sessionStrSize = 20 + strlen(sessionId); + sessionStr = new char[sessionStrSize]; + snprintf(sessionStr, sessionStrSize, "Session: %s\r\n", sessionId); } else { sessionStr = strDup(""); } @@ -626,7 +630,7 @@ // This is the default value; we don't need a "Speed:" header: buf[0] = '\0'; } else { - sprintf(buf, "Speed: %.3f\r\n",speed); + snprintf(buf, sizeof buf, "Speed: %.3f\r\n", speed); } return strDup(buf); @@ -639,7 +643,7 @@ buf[0] = '\0'; } else { Locale l("C", Numeric); - sprintf(buf, "Scale: %f\r\n", scale); + snprintf(buf, sizeof buf, "Scale: %f\r\n", scale); } return strDup(buf); @@ -667,11 +671,11 @@ } else if (end < 0) { // There's no end time: Locale l("C", Numeric); - sprintf(buf, "Range: npt=%.3f-\r\n", start); + snprintf(buf, sizeof buf, "Range: npt=%.3f-\r\n", start); } else { // There's both a start and an end time; include them both in the "Range:" hdr Locale l("C", Numeric); - sprintf(buf, "Range: npt=%.3f-%.3f\r\n", start, end); + snprintf(buf, sizeof buf, "Range: npt=%.3f-%.3f\r\n", start, end); } } @@ -713,9 +717,10 @@ transportFmt = "Transport: RAW/RAW/UDP%s%s%s=%d-%d\r\n"; } - cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1]; + size_t const cmdURLSize = strlen(prefix) + strlen(separator) + strlen(suffix) + 1; + cmdURL = new char[cmdURLSize]; cmdURLWasAllocated = True; - sprintf(cmdURL, "%s%s%s", prefix, separator, suffix); + snprintf(cmdURL, cmdURLSize, "%s%s%s", prefix, separator, suffix); // Construct a "Transport:" header. char const* transportTypeStr; @@ -747,8 +752,8 @@ unsigned transportSize = strlen(transportFmt) + strlen(transportTypeStr) + strlen(modeStr) + strlen(portTypeStr) + 2*5 /* max port len */; char* transportStr = new char[transportSize]; - sprintf(transportStr, transportFmt, - transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber); + snprintf(transportStr, transportSize, transportFmt, + transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber); // When sending more than one "SETUP" request, include a "Session:" header in the 2nd and later commands: char* sessionStr = createSessionString(fLastSessionId); @@ -761,9 +766,11 @@ // The "Transport:", "Session:" (if present), "Blocksize:" (if present), and "KeyMgmt:" (if present) // headers make up the 'extra headers': - extraHeaders = new char[transportSize + strlen(sessionStr) + strlen(blocksizeStr) + strlen(keyMgmtStr) + 1]; + size_t const extraHeadersSize + = transportSize + strlen(sessionStr) + strlen(blocksizeStr) + strlen(keyMgmtStr) + 1; + extraHeaders = new char[extraHeadersSize]; extraHeadersWereAllocated = True; - sprintf(extraHeaders, "%s%s%s%s", transportStr, sessionStr, blocksizeStr, keyMgmtStr); + snprintf(extraHeaders, extraHeadersSize, "%s%s%s%s", transportStr, sessionStr, blocksizeStr, keyMgmtStr); delete[] transportStr; delete[] sessionStr; delete[] blocksizeStr; delete[] keyMgmtStr; } else if (strcmp(request->commandName(), "GET") == 0 || strcmp(request->commandName(), "POST") == 0) { // We will be sending a HTTP (not a RTSP) request. @@ -807,9 +814,9 @@ + strlen(fSessionCookie); extraHeaders = new char[extraHeadersSize]; extraHeadersWereAllocated = True; - sprintf(extraHeaders, extraHeadersFmt, - serverAddressString.val(), - fSessionCookie); + snprintf(extraHeaders, extraHeadersSize, extraHeadersFmt, + serverAddressString.val(), + fSessionCookie); } else { // "POST" char const* const extraHeadersFmt = "Host: %s\r\n" @@ -824,9 +831,9 @@ + strlen(fSessionCookie); extraHeaders = new char[extraHeadersSize]; extraHeadersWereAllocated = True; - sprintf(extraHeaders, extraHeadersFmt, - serverAddressString.val(), - fSessionCookie); + snprintf(extraHeaders, extraHeadersSize, extraHeadersFmt, + serverAddressString.val(), + fSessionCookie); } } else { // "PLAY", "PAUSE", "TEARDOWN", "RECORD", "SET_PARAMETER", "GET_PARAMETER" // First, make sure that we have a RTSP session in progress @@ -847,9 +854,10 @@ // Media-level operation char const *prefix, *separator, *suffix; constructSubsessionURL(*request->subsession(), prefix, separator, suffix); - cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1]; + size_t const cmdURLSize = strlen(prefix) + strlen(separator) + strlen(suffix) + 1; + cmdURL = new char[cmdURLSize]; cmdURLWasAllocated = True; - sprintf(cmdURL, "%s%s%s", prefix, separator, suffix); + snprintf(cmdURL, cmdURLSize, "%s%s%s", prefix, separator, suffix); sessionId = request->subsession()->sessionId(); originalScale = request->subsession()->scale(); @@ -863,9 +871,11 @@ float speed = request->session() != NULL ? request->session()->speed() : request->subsession()->speed(); char* speedStr = createSpeedString(speed); char* rangeStr = createRangeString(request->start(), request->end(), request->absStartTime(), request->absEndTime()); - extraHeaders = new char[strlen(sessionStr) + strlen(scaleStr) + strlen(speedStr) + strlen(rangeStr) + 1]; + size_t const extraHeadersSize = + strlen(sessionStr) + strlen(scaleStr) + strlen(speedStr) + strlen(rangeStr) + 1; + extraHeaders = new char[extraHeadersSize]; extraHeadersWereAllocated = True; - sprintf(extraHeaders, "%s%s%s%s", sessionStr, scaleStr, speedStr, rangeStr); + snprintf(extraHeaders, extraHeadersSize, "%s%s%s%s", sessionStr, scaleStr, speedStr, rangeStr); delete[] sessionStr; delete[] scaleStr; delete[] speedStr; delete[] rangeStr; } else { // Create a "Session:" header; this makes up our 'extra headers': @@ -987,21 +997,21 @@ + strlen(auth.username()) + strlen(auth.realm()) + strlen(auth.nonce()) + strlen(url) + strlen(response); authenticatorStr = new char[authBufSize]; - sprintf(authenticatorStr, authFmt, - auth.username(), auth.realm(), - auth.nonce(), url, response); + snprintf(authenticatorStr, authBufSize, authFmt, + auth.username(), auth.realm(), + auth.nonce(), url, response); auth.reclaimDigestResponse(response); } else { // Basic authentication char const* const authFmt = "Authorization: Basic %s\r\n"; unsigned usernamePasswordLength = strlen(auth.username()) + 1 + strlen(auth.password()); char* usernamePassword = new char[usernamePasswordLength+1]; - sprintf(usernamePassword, "%s:%s", auth.username(), auth.password()); + snprintf(usernamePassword, usernamePasswordLength+1, "%s:%s", auth.username(), auth.password()); char* response = base64Encode(usernamePassword, usernamePasswordLength); unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1; authenticatorStr = new char[authBufSize]; - sprintf(authenticatorStr, authFmt, response); + snprintf(authenticatorStr, authBufSize, authFmt, response); delete[] response; delete[] usernamePassword; } @@ -1026,8 +1036,9 @@ } if (maxPacketSize > 0) { - blocksizeStr = new char[25]; // more than enough space - sprintf(blocksizeStr, "Blocksize: %u\r\n", maxPacketSize); + size_t const blocksizeStrSize = 25; // more than enough space + blocksizeStr = new char[blocksizeStrSize]; + snprintf(blocksizeStr, blocksizeStrSize, "Blocksize: %u\r\n", maxPacketSize); } else { blocksizeStr = strDup(""); } @@ -1050,7 +1061,7 @@ unsigned keyMgmtSize = strlen(keyMgmtFmt) + strlen(url) + strlen(base64EncodedData); keyMgmtStr = new char[keyMgmtSize]; - sprintf(keyMgmtStr, keyMgmtFmt, + snprintf(keyMgmtStr, keyMgmtSize, keyMgmtFmt, url, base64EncodedData); delete[] base64EncodedData; } @@ -1439,9 +1450,11 @@ realmHasChanged = fCurrentAuthenticator.realm() == NULL || strcmp(fCurrentAuthenticator.realm(), realm) != 0; isStale = _strncasecmp(stale, "true", 4) == 0; fCurrentAuthenticator.setRealmAndNonce(realm, nonce); + disallowBasicAuthentication(); // any future authentication request must be Digest } else if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) { realmHasChanged = fCurrentAuthenticator.realm() == NULL || strcmp(fCurrentAuthenticator.realm(), realm) != 0; fCurrentAuthenticator.setRealmAndNonce(realm, nonce); + disallowBasicAuthentication(); // any future authentication request must be Digest } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1 && fAllowBasicAuthentication) { realmHasChanged = fCurrentAuthenticator.realm() == NULL || strcmp(fCurrentAuthenticator.realm(), realm) != 0; fCurrentAuthenticator.setRealmAndNonce(realm, NULL); // Basic authentication @@ -1880,7 +1893,7 @@ = (oldBaseURLTail - fBaseURL) + 8/* for "/stream=" */ + strlen(headerParamsStr); char* newBaseURL = new char[newBaseURLLen + 1]; // Note: We couldn't use "asprintf()", because some compilers don't support it - sprintf(newBaseURL, "%.*s/stream=%s", + snprintf(newBaseURL, newBaseURLLen + 1, "%.*s/stream=%s", (int)(oldBaseURLTail - fBaseURL), fBaseURL, headerParamsStr); setBaseURL(newBaseURL); delete[] newBaseURL; @@ -1908,8 +1921,8 @@ unsigned remainingBufferSize = responseBufferSize - fResponseBytesAlreadySeen; if (numExtraBytesNeeded > remainingBufferSize) { char tmpBuf[200]; - sprintf(tmpBuf, "Response buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n", - responseBufferSize, contentLength, fResponseBytesAlreadySeen + numExtraBytesNeeded); + snprintf(tmpBuf, sizeof tmpBuf, "Response buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n", + responseBufferSize, contentLength, fResponseBytesAlreadySeen + numExtraBytesNeeded); envir().setResultMsg(tmpBuf); break; } @@ -1963,7 +1976,6 @@ } } else if (responseCode == 301 || responseCode == 302) { // redirection resetTCPSockets(); // because we need to connect somewhere else next - fCurrentAuthenticator.reset(); needToResendCommand = True; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTSPServer.cpp new/live/liveMedia/RTSPServer.cpp --- old/live/liveMedia/RTSPServer.cpp 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/RTSPServer.cpp 2026-11-08 17:12:02.000000000 +0100 @@ -1363,7 +1363,8 @@ if (streamingMode != UNKNOWN) break; // more than one 'streaming mode' is not allowed streamingMode = RTP_TCP; - } else if (strcmp(field, "RTP/AVP") == 0 || strcmp(field, "RTP/SAVP") == 0) { + } else if (strcmp(field, "RTP/AVP") == 0 || strcmp(field, "RTP/AVP/UDP") == 0 + || strcmp(field, "RTP/SAVP") == 0) { if (streamingMode != UNKNOWN) break; // more than one 'streaming mode' is not allowed streamingMode = RTP_UDP; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/ProxyServerMediaSession.hh new/live/liveMedia/include/ProxyServerMediaSession.hh --- old/live/liveMedia/include/ProxyServerMediaSession.hh 2026-10-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/include/ProxyServerMediaSession.hh 2026-11-08 17:12:02.000000000 +0100 @@ -19,6 +19,10 @@ // another (unicast or multicast) RTSP/RTP stream. // C++ header +// REMINDER: You should not make major changes to this code. +// If you want more features, then you should use subclassing, with separate source code files. +// See: http://live555.com/liveMedia/faq.html#modifying-and-extending + #ifndef _PROXY_SERVER_MEDIA_SESSION_HH #define _PROXY_SERVER_MEDIA_SESSION_HH 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-24 05:04:52.000000000 +0200 +++ new/live/liveMedia/include/liveMedia_version.hh 2026-11-08 17:12:02.000000000 +0100 @@ -19,8 +19,8 @@ #ifndef _LIVEMEDIA_VERSION_HH #define _LIVEMEDIA_VERSION_HH -#define LIVEMEDIA_LIBRARY_VERSION_STRING "2026.10.24" -#define LIVEMEDIA_LIBRARY_VERSION_INT 1792800000 +#define LIVEMEDIA_LIBRARY_VERSION_STRING "2026.11.08" +#define LIVEMEDIA_LIBRARY_VERSION_INT 1794096000 extern char const* const liveMediaLibraryVersionStr; extern int const liveMediaLibraryVersionInt;
