434 lines
18 KiB
C
434 lines
18 KiB
C
|
/*
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_START@
|
||
|
*
|
||
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||
|
*
|
||
|
* This file contains Original Code and/or Modifications of Original Code
|
||
|
* as defined in and that are subject to the Apple Public Source License
|
||
|
* Version 2.0 (the 'License'). You may not use this file except in
|
||
|
* compliance with the License. Please obtain a copy of the License at
|
||
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||
|
* file.
|
||
|
*
|
||
|
* The Original Code and all software distributed under the License are
|
||
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||
|
* Please see the License for the specific language governing rights and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_END@
|
||
|
*
|
||
|
*/
|
||
|
/*
|
||
|
File: QTSServerInterface.h
|
||
|
|
||
|
Contains: This object defines an interface for getting and setting server-wide
|
||
|
attributes, and storing global server resources.
|
||
|
|
||
|
There can be only one of these objects per process, so there
|
||
|
is a static accessor.
|
||
|
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
#ifndef __QTSSERVERINTERFACE_H__
|
||
|
#define __QTSSERVERINTERFACE_H__
|
||
|
|
||
|
#include "QTSS.h"
|
||
|
#include "QTSSDictionary.h"
|
||
|
#include "QTSServerPrefs.h"
|
||
|
#include "QTSSMessages.h"
|
||
|
#include "QTSSModule.h"
|
||
|
#include "atomic.h"
|
||
|
|
||
|
#include "OSMutex.h"
|
||
|
#include "Task.h"
|
||
|
#include "TCPListenerSocket.h"
|
||
|
#include "ResizeableStringFormatter.h"
|
||
|
|
||
|
// OSRefTable;
|
||
|
class UDPSocketPool;
|
||
|
class QTSServerPrefs;
|
||
|
class QTSSMessages;
|
||
|
//class RTPStatsUpdaterTask;
|
||
|
class RTPSessionInterface;
|
||
|
|
||
|
// This object also functions as our assert logger
|
||
|
class QTSSErrorLogStream : public QTSSStream, public AssertLogger
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// This QTSSStream is used by modules to write to the error log
|
||
|
|
||
|
QTSSErrorLogStream() {}
|
||
|
virtual ~QTSSErrorLogStream() {}
|
||
|
|
||
|
virtual QTSS_Error Write(void* inBuffer, UInt32 inLen, UInt32* outLenWritten, UInt32 inFlags);
|
||
|
virtual void LogAssert(char* inMessage);
|
||
|
};
|
||
|
|
||
|
class QTSServerInterface : public QTSSDictionary
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
//Initialize must be called right off the bat to initialize dictionary resources
|
||
|
static void Initialize();
|
||
|
|
||
|
//
|
||
|
// CONSTRUCTOR / DESTRUCTOR
|
||
|
|
||
|
QTSServerInterface();
|
||
|
virtual ~QTSServerInterface() {}
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// STATISTICS MANIPULATION
|
||
|
// These functions are how the server keeps its statistics current
|
||
|
|
||
|
void AlterCurrentRTSPSessionCount(SInt32 inDifference)
|
||
|
{ OSMutexLocker locker(&fMutex); fNumRTSPSessions += inDifference; }
|
||
|
void AlterCurrentRTSPHTTPSessionCount(SInt32 inDifference)
|
||
|
{ OSMutexLocker locker(&fMutex); fNumRTSPHTTPSessions += inDifference; }
|
||
|
void SwapFromRTSPToHTTP()
|
||
|
{ OSMutexLocker locker(&fMutex); fNumRTSPSessions--; fNumRTSPHTTPSessions++; }
|
||
|
|
||
|
//total rtp bytes sent by the server
|
||
|
void IncrementTotalRTPBytes(UInt32 bytes)
|
||
|
{ (void)atomic_add(&fPeriodicRTPBytes, bytes); }
|
||
|
//total rtp packets sent by the server
|
||
|
void IncrementTotalPackets()
|
||
|
{ (void)atomic_add(&fPeriodicRTPPackets, 1); }
|
||
|
//total rtp bytes reported as lost by the clients
|
||
|
void IncrementTotalRTPPacketsLost(UInt32 packets)
|
||
|
{ (void)atomic_add(&fPeriodicRTPPacketsLost, packets); }
|
||
|
|
||
|
// Also increments current RTP session count
|
||
|
void IncrementTotalRTPSessions()
|
||
|
{ OSMutexLocker locker(&fMutex); fNumRTPSessions++; fTotalRTPSessions++; }
|
||
|
void AlterCurrentRTPSessionCount(SInt32 inDifference)
|
||
|
{ OSMutexLocker locker(&fMutex); fNumRTPSessions += inDifference; }
|
||
|
|
||
|
//track how many sessions are playing
|
||
|
void AlterRTPPlayingSessions(SInt32 inDifference)
|
||
|
{ OSMutexLocker locker(&fMutex); fNumRTPPlayingSessions += inDifference; }
|
||
|
|
||
|
|
||
|
void IncrementTotalLate(SInt64 milliseconds)
|
||
|
{ OSMutexLocker locker(&fMutex);
|
||
|
fTotalLate += milliseconds;
|
||
|
if (milliseconds > fCurrentMaxLate) fCurrentMaxLate = milliseconds;
|
||
|
if (milliseconds > fMaxLate) fMaxLate = milliseconds;
|
||
|
}
|
||
|
|
||
|
void IncrementTotalQuality(SInt32 level)
|
||
|
{ OSMutexLocker locker(&fMutex); fTotalQuality += level; }
|
||
|
|
||
|
|
||
|
void IncrementNumThinned(SInt32 inDifference)
|
||
|
{ OSMutexLocker locker(&fMutex); fNumThinned += inDifference; }
|
||
|
|
||
|
void ClearTotalLate()
|
||
|
{ OSMutexLocker locker(&fMutex); fTotalLate = 0; }
|
||
|
void ClearCurrentMaxLate()
|
||
|
{ OSMutexLocker locker(&fMutex); fCurrentMaxLate = 0; }
|
||
|
void ClearTotalQuality()
|
||
|
{ OSMutexLocker locker(&fMutex); fTotalQuality = 0; }
|
||
|
|
||
|
|
||
|
void InitNumThreads(UInt32 numThreads) { fNumThreads = numThreads; }
|
||
|
//
|
||
|
// ACCESSORS
|
||
|
|
||
|
QTSS_ServerState GetServerState() { return fServerState; }
|
||
|
UInt32 GetNumRTPSessions() { return fNumRTPSessions; }
|
||
|
UInt32 GetNumRTSPSessions() { return fNumRTSPSessions; }
|
||
|
UInt32 GetNumRTSPHTTPSessions(){ return fNumRTSPHTTPSessions; }
|
||
|
|
||
|
UInt32 GetTotalRTPSessions() { return fTotalRTPSessions; }
|
||
|
UInt32 GetNumRTPPlayingSessions() { return fNumRTPPlayingSessions; }
|
||
|
|
||
|
UInt32 GetCurBandwidthInBits() { return fCurrentRTPBandwidthInBits; }
|
||
|
UInt32 GetAvgBandwidthInBits() { return fAvgRTPBandwidthInBits; }
|
||
|
UInt32 GetRTPPacketsPerSec() { return fRTPPacketsPerSecond; }
|
||
|
UInt64 GetTotalRTPBytes() { return fTotalRTPBytes; }
|
||
|
UInt64 GetTotalRTPPacketsLost(){ return fTotalRTPPacketsLost; }
|
||
|
UInt64 GetTotalRTPPackets() { return fTotalRTPPackets; }
|
||
|
Float32 GetCPUPercent() { return fCPUPercent; }
|
||
|
Bool16 SigIntSet() { return fSigInt; }
|
||
|
Bool16 SigTermSet() { return fSigTerm; }
|
||
|
|
||
|
UInt32 GetNumMP3Sessions() { return fNumMP3Sessions; }
|
||
|
UInt32 GetTotalMP3Sessions() { return fTotalMP3Sessions; }
|
||
|
UInt64 GetTotalMP3Bytes() { return fTotalMP3Bytes; }
|
||
|
|
||
|
UInt32 GetDebugLevel() { return fDebugLevel; }
|
||
|
UInt32 GetDebugOptions() { return fDebugOptions; }
|
||
|
void SetDebugLevel(UInt32 debugLevel) { fDebugLevel = debugLevel; }
|
||
|
void SetDebugOptions(UInt32 debugOptions){ fDebugOptions = debugOptions; }
|
||
|
|
||
|
SInt64 GetMaxLate() { return fMaxLate; };
|
||
|
SInt64 GetTotalLate() { return fTotalLate; };
|
||
|
SInt64 GetCurrentMaxLate() { return fCurrentMaxLate; };
|
||
|
SInt64 GetTotalQuality() { return fTotalQuality; };
|
||
|
SInt32 GetNumThinned() { return fNumThinned; };
|
||
|
UInt32 GetNumThreads() { return fNumThreads; };
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// GLOBAL OBJECTS REPOSITORY
|
||
|
// This object is in fact global, so there is an accessor for it as well.
|
||
|
|
||
|
static QTSServerInterface* GetServer() { return sServer; }
|
||
|
|
||
|
//Allows you to map RTP session IDs (strings) to actual RTP session objects
|
||
|
OSRefTable* GetRTPSessionMap() { return fRTPMap; }
|
||
|
|
||
|
//Server provides a statically created & bound UDPSocket / Demuxer pair
|
||
|
//for each IP address setup to serve RTP. You access those pairs through
|
||
|
//this function. This returns a pair pre-bound to the IPAddr specified.
|
||
|
UDPSocketPool* GetSocketPool() { return fSocketPool; }
|
||
|
|
||
|
QTSServerPrefs* GetPrefs() { return fSrvrPrefs; }
|
||
|
QTSSMessages* GetMessages() { return fSrvrMessages; }
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// SERVER NAME & VERSION
|
||
|
|
||
|
static StrPtrLen& GetServerName() { return sServerNameStr; }
|
||
|
static StrPtrLen& GetServerVersion() { return sServerVersionStr; }
|
||
|
static StrPtrLen& GetServerPlatform() { return sServerPlatformStr; }
|
||
|
static StrPtrLen& GetServerBuildDate() { return sServerBuildDateStr; }
|
||
|
static StrPtrLen& GetServerHeader() { return sServerHeaderPtr; }
|
||
|
static StrPtrLen& GetServerBuild() { return sServerBuildStr; }
|
||
|
static StrPtrLen& GetServerComment() { return sServerCommentStr; }
|
||
|
|
||
|
//
|
||
|
// PUBLIC HEADER
|
||
|
static StrPtrLen* GetPublicHeader() { return &sPublicHeaderStr; }
|
||
|
|
||
|
//
|
||
|
// KILL ALL
|
||
|
void KillAllRTPSessions();
|
||
|
|
||
|
//
|
||
|
// SIGINT - to interrupt the server, set this flag and the server will shut down
|
||
|
void SetSigInt() { fSigInt = true; }
|
||
|
|
||
|
// SIGTERM - to kill the server, set this flag and the server will shut down
|
||
|
void SetSigTerm() { fSigTerm = true; }
|
||
|
|
||
|
//
|
||
|
// MODULE STORAGE
|
||
|
|
||
|
// All module objects are stored here, and are accessable through
|
||
|
// these routines.
|
||
|
|
||
|
// Returns the number of modules that act in a given role
|
||
|
static UInt32 GetNumModulesInRole(QTSSModule::RoleIndex inRole)
|
||
|
{ Assert(inRole < QTSSModule::kNumRoles); return sNumModulesInRole[inRole]; }
|
||
|
|
||
|
// Allows the caller to iterate over all modules that act in a given role
|
||
|
static QTSSModule* GetModule(QTSSModule::RoleIndex inRole, UInt32 inIndex)
|
||
|
{ Assert(inRole < QTSSModule::kNumRoles);
|
||
|
Assert(inIndex < sNumModulesInRole[inRole]);
|
||
|
if (inRole >= QTSSModule::kNumRoles) //index out of bounds, shouldn't happen
|
||
|
{ return NULL;
|
||
|
}
|
||
|
if (inIndex >= sNumModulesInRole[inRole]) //index out of bounds, shouldn't happen
|
||
|
{ return NULL;
|
||
|
}
|
||
|
return sModuleArray[inRole][inIndex];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We need to override this. This is how we implement the QTSS_StateChange_Role
|
||
|
virtual void SetValueComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap,
|
||
|
UInt32 inValueIndex, void* inNewValue, UInt32 inNewValueLen);
|
||
|
|
||
|
//
|
||
|
// ERROR LOGGING
|
||
|
|
||
|
// Invokes the error logging modules with some data
|
||
|
static void LogError(QTSS_ErrorVerbosity inVerbosity, char* inBuffer);
|
||
|
|
||
|
// Returns the error log stream
|
||
|
static QTSSErrorLogStream* GetErrorLogStream() { return &sErrorLogStream; }
|
||
|
|
||
|
//
|
||
|
// LOCKING DOWN THE SERVER OBJECT
|
||
|
OSMutex* GetServerObjectMutex() { return &fMutex; }
|
||
|
|
||
|
|
||
|
|
||
|
protected:
|
||
|
|
||
|
// Setup by the derived RTSPServer object
|
||
|
|
||
|
//Sockets are allocated global to the server, and arbitrated through this pool here.
|
||
|
//RTCP data is processed completely within the following task.
|
||
|
UDPSocketPool* fSocketPool;
|
||
|
|
||
|
// All RTP sessions are put into this map
|
||
|
OSRefTable* fRTPMap;
|
||
|
|
||
|
QTSServerPrefs* fSrvrPrefs;
|
||
|
QTSSMessages* fSrvrMessages;
|
||
|
|
||
|
QTSServerPrefs* fStubSrvrPrefs;
|
||
|
QTSSMessages* fStubSrvrMessages;
|
||
|
|
||
|
QTSS_ServerState fServerState;
|
||
|
UInt32 fDefaultIPAddr;
|
||
|
|
||
|
// Array of pointers to TCPListenerSockets.
|
||
|
TCPListenerSocket** fListeners;
|
||
|
UInt32 fNumListeners; // Number of elements in the array
|
||
|
|
||
|
// startup time
|
||
|
SInt64 fStartupTime_UnixMilli;
|
||
|
SInt32 fGMTOffset;
|
||
|
|
||
|
static ResizeableStringFormatter sPublicHeaderFormatter;
|
||
|
static StrPtrLen sPublicHeaderStr;
|
||
|
|
||
|
//
|
||
|
// MODULE DATA
|
||
|
|
||
|
static QTSSModule** sModuleArray[QTSSModule::kNumRoles];
|
||
|
static UInt32 sNumModulesInRole[QTSSModule::kNumRoles];
|
||
|
static OSQueue sModuleQueue;
|
||
|
static QTSSErrorLogStream sErrorLogStream;
|
||
|
|
||
|
private:
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
kMaxServerHeaderLen = 1000
|
||
|
};
|
||
|
|
||
|
static void* TimeConnected(QTSSDictionary* inConnection, UInt32* outLen);
|
||
|
|
||
|
static UInt32 sServerAPIVersion;
|
||
|
static StrPtrLen sServerNameStr;
|
||
|
static StrPtrLen sServerVersionStr;
|
||
|
static StrPtrLen sServerBuildStr;
|
||
|
static StrPtrLen sServerCommentStr;
|
||
|
static StrPtrLen sServerPlatformStr;
|
||
|
static StrPtrLen sServerBuildDateStr;
|
||
|
static char sServerHeader[kMaxServerHeaderLen];
|
||
|
static StrPtrLen sServerHeaderPtr;
|
||
|
|
||
|
OSMutex fMutex;
|
||
|
|
||
|
UInt32 fNumRTSPSessions;
|
||
|
UInt32 fNumRTSPHTTPSessions;
|
||
|
UInt32 fNumRTPSessions;
|
||
|
|
||
|
//stores the current number of playing connections.
|
||
|
UInt32 fNumRTPPlayingSessions;
|
||
|
|
||
|
//stores the total number of connections since startup.
|
||
|
UInt32 fTotalRTPSessions;
|
||
|
//stores the total number of bytes served since startup
|
||
|
UInt64 fTotalRTPBytes;
|
||
|
//total number of rtp packets sent since startup
|
||
|
UInt64 fTotalRTPPackets;
|
||
|
//stores the total number of bytes lost (as reported by clients) since startup
|
||
|
UInt64 fTotalRTPPacketsLost;
|
||
|
|
||
|
//because there is no 64 bit atomic add (for obvious reasons), we efficiently
|
||
|
//implement total byte counting by atomic adding to this variable, then every
|
||
|
//once in awhile updating the sTotalBytes.
|
||
|
unsigned int fPeriodicRTPBytes;
|
||
|
unsigned int fPeriodicRTPPacketsLost;
|
||
|
unsigned int fPeriodicRTPPackets;
|
||
|
|
||
|
//stores the current served bandwidth in BITS per second
|
||
|
UInt32 fCurrentRTPBandwidthInBits;
|
||
|
UInt32 fAvgRTPBandwidthInBits;
|
||
|
UInt32 fRTPPacketsPerSecond;
|
||
|
|
||
|
Float32 fCPUPercent;
|
||
|
Float32 fCPUTimeUsedInSec;
|
||
|
|
||
|
// stores # of UDP sockets in the server currently (gets updated lazily via.
|
||
|
// param retrieval function)
|
||
|
UInt32 fTotalUDPSockets;
|
||
|
|
||
|
// are we out of descriptors?
|
||
|
Bool16 fIsOutOfDescriptors;
|
||
|
|
||
|
// Storage for current time attribute
|
||
|
SInt64 fCurrentTime_UnixMilli;
|
||
|
|
||
|
// Stats for UDP retransmits
|
||
|
UInt32 fUDPWastageInBytes;
|
||
|
UInt32 fNumUDPBuffers;
|
||
|
|
||
|
// MP3 Client Session params
|
||
|
UInt32 fNumMP3Sessions;
|
||
|
UInt32 fTotalMP3Sessions;
|
||
|
UInt32 fCurrentMP3BandwidthInBits;
|
||
|
UInt64 fTotalMP3Bytes;
|
||
|
UInt32 fAvgMP3BandwidthInBits;
|
||
|
|
||
|
Bool16 fSigInt;
|
||
|
Bool16 fSigTerm;
|
||
|
|
||
|
UInt32 fDebugLevel;
|
||
|
UInt32 fDebugOptions;
|
||
|
|
||
|
|
||
|
SInt64 fMaxLate;
|
||
|
SInt64 fTotalLate;
|
||
|
SInt64 fCurrentMaxLate;
|
||
|
SInt64 fTotalQuality;
|
||
|
SInt32 fNumThinned;
|
||
|
UInt32 fNumThreads;
|
||
|
|
||
|
// Param retrieval functions
|
||
|
static void* CurrentUnixTimeMilli(QTSSDictionary* inServer, UInt32* outLen);
|
||
|
static void* GetTotalUDPSockets(QTSSDictionary* inServer, UInt32* outLen);
|
||
|
static void* IsOutOfDescriptors(QTSSDictionary* inServer, UInt32* outLen);
|
||
|
static void* GetNumUDPBuffers(QTSSDictionary* inServer, UInt32* outLen);
|
||
|
static void* GetNumWastedBytes(QTSSDictionary* inServer, UInt32* outLen);
|
||
|
|
||
|
static QTSServerInterface* sServer;
|
||
|
static QTSSAttrInfoDict::AttrInfo sAttributes[];
|
||
|
static QTSSAttrInfoDict::AttrInfo sConnectedUserAttributes[];
|
||
|
|
||
|
friend class RTPStatsUpdaterTask;
|
||
|
friend class SessionTimeoutTask;
|
||
|
};
|
||
|
|
||
|
|
||
|
class RTPStatsUpdaterTask : public Task
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// This class runs periodically to compute current totals & averages
|
||
|
RTPStatsUpdaterTask();
|
||
|
virtual ~RTPStatsUpdaterTask() {}
|
||
|
|
||
|
private:
|
||
|
|
||
|
virtual SInt64 Run();
|
||
|
RTPSessionInterface* GetNewestSession(OSRefTable* inRTPSessionMap);
|
||
|
Float32 GetCPUTimeInSeconds();
|
||
|
|
||
|
SInt64 fLastBandwidthTime;
|
||
|
SInt64 fLastBandwidthAvg;
|
||
|
SInt64 fLastBytesSent;
|
||
|
SInt64 fLastTotalMP3Bytes;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
#endif // __QTSSERVERINTERFACE_H__
|
||
|
|