首页 > 学院 > 开发设计 > 正文

QTSServerInterface

2019-11-09 20:57:47
字体:
来源:转载
供稿:网友
/* * * @APPLE_LICENSE_HEADER_START@ *  * Copyright (c) 1999-2003 Apple Computer, 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:       QTSSDictionary.h    Contains:   Definitions of two classes: QTSSDictionary and QTSSDictionaryMap.                Collectively, these classes implement the "dictionary" APIs in QTSS                API. A QTSSDictionary corresponds to a QTSS_Object,                a QTSSDictionaryMap corresponds to a QTSS_ObjectType.    Created: Tue, Mar 2, 1999 @ 4:23 PM*/#ifndef _QTSSDICTIONARY_H_#define _QTSSDICTIONARY_H_#include <stdlib.h>#include "SafeStdLib.h"#include "QTSS.h"#include "OSHeaders.h"#include "OSMutex.h"#include "StrPtrLen.h"#include "MyAssert.h"#include "QTSSStream.h"class QTSSDictionary;class QTSSDictionaryMap;class QTSSAttrInfoDict;#define __DICTIONARY_TESTING__ 0//// Function prototype for attr functionstypedef void* (*QTSS_AttrFunctionPtr)(QTSSDictionary* , UInt32* );class QTSSDictionary : public QTSSStream{    public:            //        // CONSTRUCTOR / DESTRUCTOR                QTSSDictionary(QTSSDictionaryMap* inMap, OSMutex* inMutex = NULL);        virtual ~QTSSDictionary();                //        // QTSS API CALLS                // Flags used by internal callers of these routines        enum        {            kNoFlags = 0,            kDontObeyReadOnly = 1,            kDontCallCompletionRoutine = 2        };                // This version of GetValue copies the element into a buffer provided by the caller        // Returns:     QTSS_BadArgument, QTSS_NotPreemptiveSafe (if attribute is not preemptive safe),        //              QTSS_BadIndex (if inIndex is bad)        QTSS_Error GetValue(QTSS_AttributeID inAttrID, UInt32 inIndex, void* ioValueBuffer, UInt32* ioValueLen);        //This version of GetValue returns a pointer to the internal buffer for the attribute.        //Only usable if the attribute is preemptive safe.        //        // Returns:     Same as above, but also QTSS_NotEnoughSpace, if value is too big for buffer.        QTSS_Error GetValuePtr(QTSS_AttributeID inAttrID, UInt32 inIndex, void** outValueBuffer, UInt32* outValueLen)                        { return GetValuePtr(inAttrID, inIndex, outValueBuffer, outValueLen, false); }                // This version of GetValue converts the value to a string before returning it. Memory for        // the string is allocated internally.        //        // Returns: QTSS_BadArgument, QTSS_BadIndex, QTSS_ValueNotFound        QTSS_Error GetValueAsString(QTSS_AttributeID inAttrID, UInt32 inIndex, char** outString);                // Returns:     QTSS_BadArgument, QTSS_ReadOnly (if attribute is read only),        //              QTSS_BadIndex (attempt to set indexed parameter with param retrieval)        QTSS_Error SetValue(QTSS_AttributeID inAttrID, UInt32 inIndex,                            const void* inBuffer,  UInt32 inLen, UInt32 inFlags = kNoFlags);                // Returns:     QTSS_BadArgument, QTSS_ReadOnly (if attribute is read only),        QTSS_Error SetValuePtr(QTSS_AttributeID inAttrID,                            const void* inBuffer,  UInt32 inLen, UInt32 inFlags = kNoFlags);                // Returns:     QTSS_BadArgument, QTSS_ReadOnly (if attribute is read only),        QTSS_Error CreateObjectValue(QTSS_AttributeID inAttrID, UInt32* outIndex,                                        QTSSDictionary** newObject, QTSSDictionaryMap* inMap = NULL,                                         UInt32 inFlags = kNoFlags);                // Returns:     QTSS_BadArgument, QTSS_ReadOnly, QTSS_BadIndex        QTSS_Error RemoveValue(QTSS_AttributeID inAttrID, UInt32 inIndex, UInt32 inFlags = kNoFlags);                // Utility routine used by the two external flavors of GetValue        QTSS_Error GetValuePtr(QTSS_AttributeID inAttrID, UInt32 inIndex,                                            void** outValueBuffer, UInt32* outValueLen,                                            Bool16 isInternal);        //        // accessORS                QTSSDictionaryMap*  GetDictionaryMap() { return fMap; }                // Returns the Instance dictionary map for this dictionary. This may return NULL        // if there are no instance attributes in this dictionary        QTSSDictionaryMap*  GetInstanceDictMap() { return fInstanceMap; }                // Returns the number of values associated with a given attribute        UInt32              GetNumValues(QTSS_AttributeID inAttrID);        void                SetNumValues(QTSS_AttributeID inAttrID, UInt32 inNumValues);                // Meant only for internal server use. Does no error checking,        // doesn't invoke the param retrieval function.        StrPtrLen*  GetValue(QTSS_AttributeID inAttrID)                     {   return &fAttributes[inAttrID].fAttributeData;   }                            OSMutex*    GetMutex() { return fMutexP; }				void		SetLocked(Bool16 inLocked) { fLocked = inLocked; }		Bool16		IsLocked() { return fLocked; }        //        // GETTING ATTRIBUTE INFO        QTSS_Error GetAttrInfoByIndex(UInt32 inIndex, QTSSAttrInfoDict** outAttrInfoDict);        QTSS_Error GetAttrInfoByName(const char* inAttrName, QTSSAttrInfoDict** outAttrInfoDict);        QTSS_Error GetAttrInfoByID(QTSS_AttributeID inAttrID, QTSSAttrInfoDict** outAttrInfoDict);                //        // INSTANCE ATTRIBUTES                QTSS_Error  AddInstanceAttribute(   const char* inAttrName,                                            QTSS_AttrFunctionPtr inFuncPtr,                                            QTSS_AttrDataType inDataType,                                            QTSS_AttrPermission inPermission );                                                    QTSS_Error  RemoveInstanceAttribute(QTSS_AttributeID inAttr);        //        // MODIFIERS        // These functions are meant to be used by the server when it is setting up the        // dictionary attributes. They do no error checking.        // They don't set fNumAttributes & fAllocatedInternally.        void    SetVal(QTSS_AttributeID inAttrID, void* inValueBuffer, UInt32 inBufferLen);        void    SetVal(QTSS_AttributeID inAttrID, StrPtrLen* inNewValue)                    { this->SetVal(inAttrID, inNewValue->Ptr, inNewValue->Len); }        // Call this if you want to assign empty storage to an attribute        void    SetEmptyVal(QTSS_AttributeID inAttrID, void* inBuf, UInt32 inBufLen);        #if __DICTIONARY_TESTING__        static void Test(); // API test for these objects#endif    protected:            // Derived classes can provide a completion routine for some dictionary functions        virtual void    RemoveValueComplete(UInt32 /*inAttrIndex*/, QTSSDictionaryMap* /*inMap*/, UInt32 /*inValueIndex*/) {}                virtual void    SetValueComplete(UInt32 /*inAttrIndex*/, QTSSDictionaryMap* /*inMap*/,                                    UInt32 /*inValueIndex*/,  void* /*inNewValue*/, UInt32 /*inNewValueLen*/) {}        virtual void    RemoveInstanceAttrComplete(UInt32 /*inAttrindex*/, QTSSDictionaryMap* /*inMap*/) {}                virtual QTSSDictionary* CreateNewDictionary(QTSSDictionaryMap* inMap, OSMutex* inMutex);    private:            struct DictValueElement        {            // This stores all necessary information for each attribute value.                        DictValueElement() :    fAllocatedLen(0), fNumAttributes(0),                                    fAllocatedInternally(false), fIsDynamicDictionary(false) {}                                                // Does not delete! You Must call DeleteAttributeData for that            ~DictValueElement() {}                        StrPtrLen   fAttributeData; // The data            UInt32      fAllocatedLen;  // How much space do we have allocated?            UInt32      fNumAttributes; // If this is an iterated attribute, how many?            Bool16      fAllocatedInternally; //Should we delete this memory?            Bool16      fIsDynamicDictionary; //is this a dictionary object?        };                DictValueElement*   fAttributes;        DictValueElement*   fInstanceAttrs;        UInt32              fInstanceArraySize;        QTSSDictionaryMap*  fMap;        QTSSDictionaryMap*  fInstanceMap;        OSMutex*            fMutexP;		Bool16				fMyMutex;		Bool16				fLocked;                void DeleteAttributeData(DictValueElement* inDictValues, UInt32 inNumValues);};class QTSSAttrInfoDict : public QTSSDictionary{    public:            struct AttrInfo        {            // This is all the relevent information for each dictionary            // attribute.            char                    fAttrName[QTSS_MAX_ATTRIBUTE_NAME_SIZE + 1];            QTSS_AttrFunctionPtr    fFuncPtr;            QTSS_AttrDataType       fAttrDataType;            QTSS_AttrPermission     fAttrPermission;        };        QTSSAttrInfoDict();        virtual ~QTSSAttrInfoDict();            private:                AttrInfo fAttrInfo;        QTSS_AttributeID fID;                static AttrInfo sAttributes[];                friend class QTSSDictionaryMap;};class QTSSDictionaryMap{    public:            //        // This must be called before using any QTSSDictionary or QTSSDictionaryMap functionality        static void Initialize();                // Stores all meta-information for attributes                // CONSTRUCTOR FLAGS        enum        {            kNoFlags        = 0,            kAllowRemoval   = 1,    //是否允许删除元素            kIsInstanceMap  = 2,            kInstanceAttrsAllowed = 4,            kCompleteFunctionsAllowed = 8        };                //        // CONSTRUCTOR / DESTRUCTOR                QTSSDictionaryMap(UInt32 inNumReservedAttrs, UInt32 inFlags = kNoFlags);        ~QTSSDictionaryMap(){ delete fAttrArray; }        //        // QTSS API CALLS                 		//添加属性,从头遍历如果发现有        QTSS_Error      AddAttribute(   const char* inAttrName,                                        QTSS_AttrFunctionPtr inFuncPtr,                                        QTSS_AttrDataType inDataType,                                        QTSS_AttrPermission inPermission );                                                //        // Marks this attribute as removed        QTSS_Error  RemoveAttribute(QTSS_AttributeID inAttrID);        QTSS_Error  UnRemoveAttribute(QTSS_AttributeID inAttrID);        QTSS_Error  CheckRemovePermission(QTSS_AttributeID inAttrID);        //        // Searching / Iteration. These never return removed attributes        QTSS_Error  GetAttrInfoByName(const char* inAttrName, QTSSAttrInfoDict** outAttrInfoDict, Bool16 returnRemovedAttr = false);        QTSS_Error  GetAttrInfoByID(QTSS_AttributeID inID, QTSSAttrInfoDict** outAttrInfoDict);        QTSS_Error  GetAttrInfoByIndex(UInt32 inIndex, QTSSAttrInfoDict** outAttrInfoDict);        QTSS_Error  GetAttrID(const char* inAttrName, QTSS_AttributeID* outID);                //        // PRIVATE ATTR PERMISSIONS		//是否已经删除属性        enum        {            qtssPrivateAttrModeRemoved = 0x80000000        };        //        // CONVERTING attribute IDs to array indexes. Returns -1 if inAttrID doesn't exist        inline SInt32                   ConvertAttrIDToArrayIndex(QTSS_AttributeID inAttrID);        static Bool16           IsInstanceAttrID(QTSS_AttributeID inAttrID)            { return (inAttrID & 0x80000000) != 0; }        // ACCESSORS                // These functions do no error checking. Be careful.                // Includes removed attributes        UInt32          GetNumAttrs()           { return fNextAvailableID; }        UInt32          GetNumNonRemovedAttrs() { return fNumValidAttrs; }                Bool16                  IsPreemptiveSafe(UInt32 inIndex)             { Assert(inIndex < fNextAvailableID); return (Bool16) (fAttrArray[inIndex]->fAttrInfo.fAttrPermission & qtssAttrModePreempSafe); }        Bool16                  IsWriteable(UInt32 inIndex)             { Assert(inIndex < fNextAvailableID); return (Bool16) (fAttrArray[inIndex]->fAttrInfo.fAttrPermission & qtssAttrModeWrite); }				Bool16                  IsCacheable(UInt32 inIndex)             { Assert(inIndex < fNextAvailableID); return (Bool16) (fAttrArray[inIndex]->fAttrInfo.fAttrPermission & qtssAttrModeCacheable); }        Bool16                  IsRemoved(UInt32 inIndex)             { Assert(inIndex < fNextAvailableID); return (Bool16) (fAttrArray[inIndex]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved) ; }        QTSS_AttrFunctionPtr    GetAttrFunction(UInt32 inIndex)            { Assert(inIndex < fNextAvailableID); return fAttrArray[inIndex]->fAttrInfo.fFuncPtr; }                    char*                   GetAttrName(UInt32 inIndex)            { Assert(inIndex < fNextAvailableID); return fAttrArray[inIndex]->fAttrInfo.fAttrName; }                    QTSS_AttributeID        GetAttrID(UInt32 inIndex)            { Assert(inIndex < fNextAvailableID); return fAttrArray[inIndex]->fID; }        QTSS_AttrDataType       GetAttrType(UInt32 inIndex)            { Assert(inIndex < fNextAvailableID); return fAttrArray[inIndex]->fAttrInfo.fAttrDataType; }                Bool16                  InstanceAttrsAllowed() { return (Bool16) (fFlags & kInstanceAttrsAllowed); }        Bool16                  CompleteFunctionsAllowed() { return (Bool16) (fFlags & kCompleteFunctionsAllowed) ; }        // MODIFIERS                // Sets this attribute ID to have this information                void        SetAttribute(   QTSS_AttributeID inID,                                     const char* inAttrName,                                    QTSS_AttrFunctionPtr inFuncPtr,                                    QTSS_AttrDataType inDataType,                                    QTSS_AttrPermission inPermission );                //        // DICTIONARY MAPS                // All dictionary maps are stored here, and are accessable        // through these routines                // This enum allows all QTSSDictionaryMaps to be stored in an array         enum        {            kServerDictIndex                = 0,            kPrefsDictIndex                 = 1,            kTextMessagesDictIndex          = 2,            kServiceDictIndex               = 3,                        kRTPStreamDictIndex             = 4,            kClientsessionDictIndex         = 5,            kRTSPSessionDictIndex           = 6,            kRTSPRequestDictIndex           = 7,            kRTSPHeaderDictIndex            = 8,            kFileDictIndex                  = 9,            kModuleDictIndex                = 10,            kModulePrefsDictIndex           = 11,            kAttrInfoDictIndex              = 12,            kQTSSUserProfileDictIndex       = 13,            kQTSSConnectedUserDictIndex     = 14,            kNumDictionaries                = 15,                        kNumDynamicDictionaryTypes      = 500,            kIllegalDictionary              = kNumDynamicDictionaryTypes + kNumDictionaries        };                // This function converts a QTSS_ObjectType to an index        static UInt32                   GetMapIndex(QTSS_ObjectType inType);        // Using one of the above predefined indexes, this returns the corresponding map        static QTSSDictionaryMap*       GetMap(UInt32 inIndex)            { Assert(inIndex < kNumDynamicDictionaryTypes + kNumDictionaries); return sDictionaryMaps[inIndex]; }        static QTSS_ObjectType          CreateNewMap();    private:        //        // Repository for dictionary maps                static QTSSDictionaryMap*       sDictionaryMaps[kNumDictionaries + kNumDynamicDictionaryTypes];        static UInt32                   sNextDynamicMap;                    enum        {            kMinArraySize = 20        };        UInt32                          fNextAvailableID;//所有的分配过的属性,只要该属性有fid标识就算(包含qtssPrivateAttrModeRemoved标识)        UInt32                          fNumValidAttrs;  //所有没有qtssPrivateAttrModeRemoved标识的属性        UInt32                          fAttrArraySize;  //整个数组的大小。如果添加元素超过该大小,会自动增加成之前的两倍。fAttrArraySize>=fNextAvailableID        QTSSAttrInfoDict**              fAttrArray;        UInt32                          fFlags;                friend class QTSSDictionary;};inline SInt32   QTSSDictionaryMap::ConvertAttrIDToArrayIndex(QTSS_AttributeID inAttrID){    SInt32 theIndex = inAttrID & 0x7FFFFFFF;    if ((theIndex < 0) || (theIndex >= (SInt32)fNextAvailableID))        return -1;    else        return theIndex;}#endif
/* * * @APPLE_LICENSE_HEADER_START@ *  * Copyright (c) 1999-2003 Apple Computer, 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:       QTSSDictionary.cpp    Contains:   Implementation of object defined in QTSSDictionary.h                    */#include "QTSSDictionary.h"#include <string.h>#include <stdio.h>#include "MyAssert.h"#include "OSMemory.h"#include "QTSSDataConverter.h"#include <errno.h>QTSSDictionary::QTSSDictionary(QTSSDictionaryMap* inMap, OSMutex* inMutex) :   fAttributes(NULL), fInstanceAttrs(NULL), fInstanceArraySize(0),    fMap(inMap), fInstanceMap(NULL), fMutexP(inMutex), fMyMutex(false), fLocked(false){    if (fMap != NULL)        fAttributes = NEW DictValueElement[inMap->GetNumAttrs()];	if (fMutexP == NULL)	{		fMyMutex = true;		fMutexP = NEW OSMutex();	}}QTSSDictionary::~QTSSDictionary(){    if (fMap != NULL)        this->DeleteAttributeData(fAttributes, fMap->GetNumAttrs());    if (fAttributes != NULL)        delete [] fAttributes;    delete fInstanceMap;    this->DeleteAttributeData(fInstanceAttrs, fInstanceArraySize);    delete [] fInstanceAttrs;	if (fMyMutex)		delete fMutexP;}QTSSDictionary* QTSSDictionary::CreateNewDictionary(QTSSDictionaryMap* inMap, OSMutex* inMutex){    return NEW QTSSDictionary(inMap, inMutex);}QTSS_Error QTSSDictionary::GetValuePtr(QTSS_AttributeID inAttrID, UInt32 inIndex,                                            void** outValueBuffer, UInt32* outValueLen,                                            Bool16 isInternal){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }    if (theMap == NULL)        return QTSS_AttrDoesntExist;        SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);    if (theMapIndex < 0)        return QTSS_AttrDoesntExist;    if (theMap->IsRemoved(theMapIndex))        return QTSS_AttrDoesntExist;    if ((!isInternal) && (!theMap->IsPreemptiveSafe(theMapIndex)) && !this->IsLocked())        return QTSS_NotPreemptiveSafe;    // An iterated attribute cannot have a param retrieval function    if ((inIndex > 0) && (theMap->GetAttrFunction(theMapIndex) != NULL))        return QTSS_BadIndex;    // Check to make sure the index parameter is legal    if ((inIndex > 0) && (inIndex >= theAttrs[theMapIndex].fNumAttributes))        return QTSS_BadIndex;                    // Retrieve the parameter    char* theBuffer = theAttrs[theMapIndex].fAttributeData.Ptr;    *outValueLen = theAttrs[theMapIndex].fAttributeData.Len;    	Bool16 cacheable = theMap->IsCacheable(theMapIndex);	if ( (theMap->GetAttrFunction(theMapIndex) != NULL) && ((cacheable && (*outValueLen == 0)) || !cacheable) )    {        // If function is cacheable: 		// If the parameter doesn't have a value assigned yet, and there is an attribute        // retrieval function provided, invoke that function now.		// If function is *not* cacheable:		// always call the function		        theBuffer = (char*)theMap->GetAttrFunction(theMapIndex)(this, outValueLen);        //If the param retrieval function didn't return an explicit value for this attribute,        //refetch the parameter out of the array, in case the function modified it.                if (theBuffer == NULL)        {            theBuffer = theAttrs[theMapIndex].fAttributeData.Ptr;            *outValueLen = theAttrs[theMapIndex].fAttributeData.Len;        }            }#if DEBUG    else        // Make sure we aren't outside the bounds of attribute memory        Assert(theAttrs[theMapIndex].fAllocatedLen >=            (theAttrs[theMapIndex].fAttributeData.Len * (theAttrs[theMapIndex].fNumAttributes)));#endif    // Return an error if there is no data for this attribute    if (*outValueLen == 0)        return QTSS_ValueNotFound;                theBuffer += theAttrs[theMapIndex].fAttributeData.Len * inIndex;    *outValueBuffer = theBuffer;            // strings need an extra dereference - moved it up    if ((theMap->GetAttrType(theMapIndex) == qtssAttrDataTypeCharArray) && (theAttrs[theMapIndex].fNumAttributes > 1))        {            char** string = (char**)theBuffer;            *outValueBuffer = *string;            //*outValueLen = strlen(*string) + 1;            *outValueLen = strlen(*string);    }        return QTSS_NoErr;}QTSS_Error QTSSDictionary::GetValue(QTSS_AttributeID inAttrID, UInt32 inIndex,                                            void* ioValueBuffer, UInt32* ioValueLen){    // If there is a mutex, lock it and get a pointer to the proper attribute    OSMutexLocker locker(fMutexP);    void* tempValueBuffer = NULL;    UInt32 tempValueLen = 0;    QTSS_Error theErr = this->GetValuePtr(inAttrID, inIndex, &tempValueBuffer, &tempValueLen, true);    if (theErr != QTSS_NoErr)        return theErr;            if (theErr == QTSS_NoErr)    {        // If caller provided a buffer that's too small for this attribute, report that error        if (tempValueLen > *ioValueLen)            theErr = QTSS_NotEnoughSpace;                    // Only copy out the attribute if the buffer is big enough        if ((ioValueBuffer != NULL) && (theErr == QTSS_NoErr))            ::memcpy(ioValueBuffer, tempValueBuffer, tempValueLen);                    // Always set the ioValueLen to be the actual length of the attribute.        *ioValueLen = tempValueLen;    }    return QTSS_NoErr;}QTSS_Error QTSSDictionary::GetValueAsString(QTSS_AttributeID inAttrID, UInt32 inIndex, char** outString){    void* tempValueBuffer;    UInt32 tempValueLen = 0;    if (outString == NULL)          return QTSS_BadArgument;            OSMutexLocker locker(fMutexP);    QTSS_Error theErr = this->GetValuePtr(inAttrID, inIndex, &tempValueBuffer,                                            &tempValueLen, true);    if (theErr != QTSS_NoErr)        return theErr;            QTSSDictionaryMap* theMap = fMap;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))        theMap = fInstanceMap;    if (theMap == NULL)        return QTSS_AttrDoesntExist;        SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);    Assert(theMapIndex >= 0);        *outString = QTSSDataConverter::ValueToString(tempValueBuffer, tempValueLen, theMap->GetAttrType(theMapIndex));    return QTSS_NoErr;}QTSS_Error QTSSDictionary::CreateObjectValue(QTSS_AttributeID inAttrID, UInt32* outIndex,                                        QTSSDictionary** newObject, QTSSDictionaryMap* inMap, UInt32 inFlags){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }        if (theMap == NULL)        return QTSS_AttrDoesntExist;        SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);        // If there is a mutex, make this action atomic.    OSMutexLocker locker(fMutexP);        if (theMapIndex < 0)        return QTSS_AttrDoesntExist;    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))        return QTSS_ReadOnly;    if (theMap->IsRemoved(theMapIndex))        return QTSS_AttrDoesntExist;    if (theMap->GetAttrType(theMapIndex) != qtssAttrDataTypeQTSS_Object)        return QTSS_BadArgument;            UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;    // if normal QTSSObjects have been added, then we can't add a dynamic one    if (!theAttrs[theMapIndex].fIsDynamicDictionary && (numValues > 0))        return QTSS_ReadOnly;    QTSSDictionary* oldDict = NULL;    *outIndex = numValues;  // add the object into the next spot    UInt32 len = sizeof(QTSSDictionary*);    QTSSDictionary* dict = CreateNewDictionary(inMap, fMutexP);        // kind of a hack to avoid the check in SetValue    theAttrs[theMapIndex].fIsDynamicDictionary = false;    QTSS_Error err = SetValue(inAttrID, *outIndex, &dict, len, inFlags);    if (err != QTSS_NoErr)    {        delete dict;        return err;    }        if (oldDict != NULL)    {        delete oldDict;    }        theAttrs[theMapIndex].fIsDynamicDictionary = true;    *newObject = dict;        return QTSS_NoErr;}QTSS_Error QTSSDictionary::SetValue(QTSS_AttributeID inAttrID, UInt32 inIndex,                                        const void* inBuffer,  UInt32 inLen,                                        UInt32 inFlags){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }        if (theMap == NULL)        return QTSS_AttrDoesntExist;        SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);        // If there is a mutex, make this action atomic.    OSMutexLocker locker(fMutexP);        if (theMapIndex < 0)        return QTSS_AttrDoesntExist;    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))        return QTSS_ReadOnly;    if (theMap->IsRemoved(theMapIndex))        return QTSS_AttrDoesntExist;    if (theAttrs[theMapIndex].fIsDynamicDictionary)        return QTSS_ReadOnly;        UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;    QTSS_AttrDataType dataType = theMap->GetAttrType(theMapIndex);    UInt32 attrLen = inLen;    if (dataType == qtssAttrDataTypeCharArray)    {        if (inIndex > 0)            attrLen = sizeof(char*);    // value just contains a pointer                if ((numValues == 1) && (inIndex == 1))        {            // we're adding a second value, so we need to change the storage from directly            // storing the string to an array of string pointers                          // creating new memory here just to create a null terminated string                // instead of directly using the old storage as the old storage didn't                 // have its string null terminated                        UInt32 tempStringLen = theAttrs[theMapIndex].fAttributeData.Len;                        char* temp = NEW char[tempStringLen + 1];                        ::memcpy(temp, theAttrs[theMapIndex].fAttributeData.Ptr, tempStringLen);                        temp[tempStringLen] = '/0';                        delete [] theAttrs[theMapIndex].fAttributeData.Ptr;                                    //char* temp = theAttrs[theMapIndex].fAttributeData.Ptr;                        theAttrs[theMapIndex].fAllocatedLen = 16 * sizeof(char*);            theAttrs[theMapIndex].fAttributeData.Ptr = NEW char[theAttrs[theMapIndex].fAllocatedLen];            theAttrs[theMapIndex].fAttributeData.Len = sizeof(char*);            // store off original string as first value in array            *(char**)theAttrs[theMapIndex].fAttributeData.Ptr = temp;                        // question: why isn't theAttrs[theMapIndex].fAllocatedInternally set to true?        }    }    else    {        // If this attribute is iterated, this new value        // must be the same size as all the others.        if (((inIndex > 0) || (numValues > 1))                 &&(theAttrs[theMapIndex].fAttributeData.Len != 0) && (inLen != theAttrs[theMapIndex].fAttributeData.Len))            return QTSS_BadArgument;    }        //    // Can't put empty space into the array of values    if (inIndex > numValues)        return QTSS_BadIndex;            if ((attrLen * (inIndex + 1)) > theAttrs[theMapIndex].fAllocatedLen)    {        // We need to reallocate this buffer.        UInt32 theLen;                if (inIndex == 0)            theLen = attrLen;   // most attributes are single valued, so allocate just enough space        else            theLen = 2 * (attrLen * (inIndex + 1));// Allocate twice as much as we need        char* theNewBuffer = NEW char[theLen];        if (inIndex > 0)        {            // Copy out the old attribute data            ::memcpy(theNewBuffer, theAttrs[theMapIndex].fAttributeData.Ptr,                        theAttrs[theMapIndex].fAllocatedLen);        }                // Now get rid of the old stuff. Delete the buffer        // if it was already allocated internally        if (theAttrs[theMapIndex].fAllocatedInternally)            delete [] theAttrs[theMapIndex].fAttributeData.Ptr;                // Finally, update this attribute structure with all the new values.        theAttrs[theMapIndex].fAttributeData.Ptr = theNewBuffer;        theAttrs[theMapIndex].fAllocatedLen = theLen;        theAttrs[theMapIndex].fAllocatedInternally = true;    }            // At this point, we should always have enough space to write what we want    Assert(theAttrs[theMapIndex].fAllocatedLen >= (attrLen * (inIndex + 1)));        // Copy the new data to the right place in our data buffer    void *attributeBufferPtr;    if ((dataType != qtssAttrDataTypeCharArray) || ((numValues < 2) && (inIndex == 0)))    {        attributeBufferPtr = theAttrs[theMapIndex].fAttributeData.Ptr + (inLen * inIndex);        theAttrs[theMapIndex].fAttributeData.Len = inLen;    }    else    {            //attributeBufferPtr = NEW char[inLen];            // allocating one extra so that we can null terminate the string            attributeBufferPtr = NEW char[inLen + 1];                char* tempBuffer = (char*)attributeBufferPtr;                tempBuffer[inLen] = '/0';                        //char** valuePtr = (char**)theAttrs[theMapIndex].fAttributeData.Ptr + (inLen * inIndex);        // The offset should be (attrLen * inIndex) and not (inLen * inIndex)         char** valuePtr = (char**)(theAttrs[theMapIndex].fAttributeData.Ptr + (attrLen * inIndex));        if (inIndex < numValues)    // we're replacing an existing string            delete *valuePtr;        *valuePtr = (char*)attributeBufferPtr;    }        ::memcpy(attributeBufferPtr, inBuffer, inLen);        // Set the number of attributes to be proper    if (inIndex >= theAttrs[theMapIndex].fNumAttributes)    {        //        // We should never have to increment num attributes by more than 1        Assert(theAttrs[theMapIndex].fNumAttributes == inIndex);        theAttrs[theMapIndex].fNumAttributes++;    }    //    // Call the completion routine    if (((fMap == NULL) || fMap->CompleteFunctionsAllowed()) && !(inFlags & kDontCallCompletionRoutine))        this->SetValueComplete(theMapIndex, theMap, inIndex, attributeBufferPtr, inLen);        return QTSS_NoErr;}QTSS_Error QTSSDictionary::SetValuePtr(QTSS_AttributeID inAttrID,                                        const void* inBuffer,  UInt32 inLen,                                        UInt32 inFlags){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }        if (theMap == NULL)        return QTSS_AttrDoesntExist;        SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);        // If there is a mutex, make this action atomic.    OSMutexLocker locker(fMutexP);        if (theMapIndex < 0)        return QTSS_AttrDoesntExist;    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))        return QTSS_ReadOnly;    if (theMap->IsRemoved(theMapIndex))        return QTSS_AttrDoesntExist;    if (theAttrs[theMapIndex].fIsDynamicDictionary)        return QTSS_ReadOnly;        UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;    if ((numValues > 0) || (theAttrs[theMapIndex].fAttributeData.Ptr != NULL))        return QTSS_BadArgument;    // you can only set the pointer if you haven't done set value    theAttrs[theMapIndex].fAttributeData.Ptr = (char*) inBuffer;    theAttrs[theMapIndex].fAttributeData.Len = inLen;    theAttrs[theMapIndex].fAllocatedLen = inLen;        // This function assumes there is only one value and that it isn't allocated internally    theAttrs[theMapIndex].fNumAttributes = 1;                return QTSS_NoErr;}QTSS_Error QTSSDictionary::RemoveValue(QTSS_AttributeID inAttrID, UInt32 inIndex, UInt32 inFlags){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }        if (theMap == NULL)        return QTSS_AttrDoesntExist;        SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);        // If there is a mutex, make this action atomic.    OSMutexLocker locker(fMutexP);        if (theMapIndex < 0)        return QTSS_AttrDoesntExist;    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))        return QTSS_ReadOnly;    if (theMap->IsRemoved(theMapIndex))        return QTSS_AttrDoesntExist;    if ((theMap->GetAttrFunction(theMapIndex) != NULL) && (inIndex > 0))        return QTSS_BadIndex;            UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;    UInt32 theValueLen = theAttrs[theMapIndex].fAttributeData.Len;    if (theAttrs[theMapIndex].fIsDynamicDictionary)    {        // this is an internally allocated dictionary, so we need to desctruct it        Assert(theMap->GetAttrType(theMapIndex) == qtssAttrDataTypeQTSS_Object);        Assert(theValueLen == sizeof(QTSSDictionary*));        QTSSDictionary* dict = *(QTSSDictionary**)(theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * inIndex));        delete dict;    }        QTSS_AttrDataType dataType = theMap->GetAttrType(theMapIndex);    if ((dataType == qtssAttrDataTypeCharArray) && (numValues > 1))    {        // we need to delete the string        char* str = *(char**)(theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * inIndex));        delete str;    }    //    // If there are values after this one in the array, move them.    if (inIndex + 1 < theAttrs[theMapIndex].fNumAttributes)     {	        ::memmove(  theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * inIndex),                theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * (inIndex + 1)),                theValueLen * ( (theAttrs[theMapIndex].fNumAttributes) - inIndex - 1));    } // else this is the last in the array so just truncate.    //    // Update our number of values    theAttrs[theMapIndex].fNumAttributes--;    if (theAttrs[theMapIndex].fNumAttributes == 0)        theAttrs[theMapIndex].fAttributeData.Len = 0;    if ((dataType == qtssAttrDataTypeCharArray) && (theAttrs[theMapIndex].fNumAttributes == 1))    {        // we only have one string left, so we don't need the extra pointer        char* str = *(char**)(theAttrs[theMapIndex].fAttributeData.Ptr);        delete theAttrs[theMapIndex].fAttributeData.Ptr;        theAttrs[theMapIndex].fAttributeData.Ptr = str;        theAttrs[theMapIndex].fAttributeData.Len = strlen(str);        theAttrs[theMapIndex].fAllocatedLen = strlen(str);    }    //    // Call the completion routine    if (((fMap == NULL) || fMap->CompleteFunctionsAllowed()) && !(inFlags & kDontCallCompletionRoutine))        this->RemoveValueComplete(theMapIndex, theMap, inIndex);            return QTSS_NoErr;}UInt32  QTSSDictionary::GetNumValues(QTSS_AttributeID inAttrID){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }    if (theMap == NULL)        return 0;    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);    if (theMapIndex < 0)        return 0;    return theAttrs[theMapIndex].fNumAttributes;}void    QTSSDictionary::SetNumValues(QTSS_AttributeID inAttrID, UInt32 inNumValues){    // Check first to see if this is a static attribute or an instance attribute    QTSSDictionaryMap* theMap = fMap;    DictValueElement* theAttrs = fAttributes;    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        theMap = fInstanceMap;        theAttrs = fInstanceAttrs;    }    if (theMap == NULL)        return;    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);    if (theMapIndex < 0)        return;    UInt32 numAttributes = theAttrs[theMapIndex].fNumAttributes;    // this routine can only be ever used to reduce the number of values            if (inNumValues >= numAttributes || numAttributes == 0)        return;    QTSS_AttrDataType dataType = theMap->GetAttrType(theMapIndex);    if (theAttrs[theMapIndex].fIsDynamicDictionary || (dataType == qtssAttrDataTypeCharArray))    {                 // getting rid of dictionaries or strings is tricky, so it's easier to call remove value        for (UInt32 removeCount = numAttributes - inNumValues; removeCount > 0; removeCount--)        {	// the delete index passed to RemoveValue is always the last in the array.            this->RemoveValue(inAttrID, theAttrs[theMapIndex].fNumAttributes - 1, kDontObeyReadOnly);        }    }    else    {        theAttrs[theMapIndex].fNumAttributes = inNumValues;        if (inNumValues == 0)            theAttrs[theMapIndex].fAttributeData.Len = 0;    }}void    QTSSDictionary::SetVal( QTSS_AttributeID inAttrID,                                    void* inValueBuffer,                                    UInt32 inBufferLen){     Assert(inAttrID >= 0);    Assert(fMap);    Assert((UInt32)inAttrID < fMap->GetNumAttrs());    fAttributes[inAttrID].fAttributeData.Ptr = (char*)inValueBuffer;    fAttributes[inAttrID].fAttributeData.Len = inBufferLen;    fAttributes[inAttrID].fAllocatedLen = inBufferLen;        // This function assumes there is only one value and that it isn't allocated internally    fAttributes[inAttrID].fNumAttributes = 1;}void    QTSSDictionary::SetEmptyVal(QTSS_AttributeID inAttrID, void* inBuf, UInt32 inBufLen){    Assert(inAttrID >= 0);    Assert(fMap);    Assert((UInt32)inAttrID < fMap->GetNumAttrs());    fAttributes[inAttrID].fAttributeData.Ptr = (char*)inBuf;    fAttributes[inAttrID].fAllocatedLen = inBufLen;#if !ALLOW_NON_Word_ALIGN_ACCESS    //if (((UInt32) inBuf % 4) > 0)    //  qtss_printf("bad align by %d/n",((UInt32) inBuf % 4) );    Assert( ((PointerSizedInt) inBuf % 4) == 0 );#endif}QTSS_Error  QTSSDictionary::AddInstanceAttribute(   const char* inAttrName,                                                    QTSS_AttrFunctionPtr inFuncPtr,                                                    QTSS_AttrDataType inDataType,                                                    QTSS_AttrPermission inPermission ){    if ((fMap != NULL) && !fMap->InstanceAttrsAllowed())        return QTSS_InstanceAttrsNotAllowed;            OSMutexLocker locker(fMutexP);    //    // Check to see if this attribute exists in the static map. If it does,    // we can't add it as an instance attribute, so return an error    QTSSAttrInfoDict* throwAway = NULL;    QTSS_Error theErr;    if (fMap != NULL)    {        theErr = fMap->GetAttrInfoByName(inAttrName, &throwAway);        if (theErr == QTSS_NoErr)            return QTSS_AttrNameExists;    }        if (fInstanceMap == NULL)    {        UInt32 theFlags = QTSSDictionaryMap::kAllowRemoval | QTSSDictionaryMap::kIsInstanceMap;        if ((fMap == NULL) || fMap->CompleteFunctionsAllowed())            theFlags |= QTSSDictionaryMap::kCompleteFunctionsAllowed;                    fInstanceMap = new QTSSDictionaryMap( 0, theFlags );    }        //    // Add the attribute into the Dictionary Map.    theErr = fInstanceMap->AddAttribute(inAttrName, inFuncPtr, inDataType, inPermission);    if (theErr != QTSS_NoErr)        return theErr;        //    // Check to see if our DictValueElement array needs to be reallocated       if (fInstanceMap->GetNumAttrs() >= fInstanceArraySize)    {        UInt32 theNewArraySize = fInstanceArraySize * 2;        if (theNewArraySize == 0)            theNewArraySize = QTSSDictionaryMap::kMinArraySize;        Assert(theNewArraySize > fInstanceMap->GetNumAttrs());                DictValueElement* theNewArray = NEW DictValueElement[theNewArraySize];        if (fInstanceAttrs != NULL)        {            ::memcpy(theNewArray, fInstanceAttrs, sizeof(DictValueElement) * fInstanceArraySize);            //            // Delete the old instance attr structs, this does not delete the actual attribute memory            delete [] fInstanceAttrs;        }        fInstanceAttrs = theNewArray;        fInstanceArraySize = theNewArraySize;    }    return QTSS_NoErr;}QTSS_Error  QTSSDictionary::RemoveInstanceAttribute(QTSS_AttributeID inAttr){    OSMutexLocker locker(fMutexP);    if (fInstanceMap != NULL)    {           QTSS_Error theErr = fInstanceMap->CheckRemovePermission(inAttr);        if (theErr != QTSS_NoErr)            return theErr;        this->SetNumValues(inAttr,(UInt32) 0); // make sure to set num values to 0 since it is a deleted attribute        fInstanceMap->RemoveAttribute(inAttr);    }    else        return QTSS_BadArgument;        //    // Call the completion routine    SInt32 theMapIndex = fInstanceMap->ConvertAttrIDToArrayIndex(inAttr);    this->RemoveInstanceAttrComplete(theMapIndex, fInstanceMap);        return QTSS_NoErr;}QTSS_Error QTSSDictionary::GetAttrInfoByIndex(UInt32 inIndex, QTSSAttrInfoDict** outAttrInfoDict){    if (outAttrInfoDict == NULL)        return QTSS_BadArgument;            OSMutexLocker locker(fMutexP);    UInt32 numInstanceValues = 0;    UInt32 numStaticValues = 0;        if (fMap != NULL)        numStaticValues = fMap->GetNumNonRemovedAttrs();        if (fInstanceMap != NULL)        numInstanceValues = fInstanceMap->GetNumNonRemovedAttrs();        if (inIndex >= (numStaticValues + numInstanceValues))        return QTSS_AttrDoesntExist;        if ( (numStaticValues > 0)  && (inIndex < numStaticValues) )        return fMap->GetAttrInfoByIndex(inIndex, outAttrInfoDict);    else    {        Assert(fInstanceMap != NULL);        return fInstanceMap->GetAttrInfoByIndex(inIndex - numStaticValues, outAttrInfoDict);    }}QTSS_Error QTSSDictionary::GetAttrInfoByID(QTSS_AttributeID inAttrID, QTSSAttrInfoDict** outAttrInfoDict){    if (outAttrInfoDict == NULL)        return QTSS_BadArgument;            if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))    {        OSMutexLocker locker(fMutexP);        if (fInstanceMap != NULL)            return fInstanceMap->GetAttrInfoByID(inAttrID, outAttrInfoDict);    }    else        if (fMap != NULL) return fMap->GetAttrInfoByID(inAttrID, outAttrInfoDict);                return QTSS_AttrDoesntExist;}QTSS_Error QTSSDictionary::GetAttrInfoByName(const char* inAttrName, QTSSAttrInfoDict** outAttrInfoDict){    QTSS_Error theErr = QTSS_AttrDoesntExist;    if (outAttrInfoDict == NULL)        return QTSS_BadArgument;            // Retrieve the Dictionary Map for this object type    if (fMap != NULL)        theErr = fMap->GetAttrInfoByName(inAttrName, outAttrInfoDict);        if (theErr == QTSS_AttrDoesntExist)    {        OSMutexLocker locker(fMutexP);        if (fInstanceMap != NULL)            theErr = fInstanceMap->GetAttrInfoByName(inAttrName, outAttrInfoDict);    }    return theErr;}void QTSSDictionary::DeleteAttributeData(DictValueElement* inDictValues, UInt32 inNumValues){    for (UInt32 x = 0; x < inNumValues; x++)    {        if (inDictValues[x].fAllocatedInternally)            delete [] inDictValues[x].fAttributeData.Ptr;    }}QTSSAttrInfoDict::AttrInfo  QTSSAttrInfoDict::sAttributes[] ={    /* 0 */ { "qtssAttrName",       NULL,       qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 1 */ { "qtssAttrID",         NULL,       qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe },    /* 2 */ { "qtssAttrDataType",   NULL,       qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe },    /* 3 */ { "qtssAttrPermissions",NULL,       qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe }};QTSSAttrInfoDict::QTSSAttrInfoDict(): QTSSDictionary(QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kAttrInfoDictIndex)), fID(qtssIllegalAttrID){}QTSSAttrInfoDict::~QTSSAttrInfoDict() {}QTSSDictionaryMap*      QTSSDictionaryMap::sDictionaryMaps[kNumDictionaries + kNumDynamicDictionaryTypes];UInt32                  QTSSDictionaryMap::sNextDynamicMap = kNumDictionaries;void QTSSDictionaryMap::Initialize(){    //    // Have to do this one first because this dict map is used by all the other    // dict maps.    sDictionaryMaps[kAttrInfoDictIndex]     = new QTSSDictionaryMap(qtssAttrInfoNumParams);    // Setup the Attr Info attributes before constructing any other dictionaries    for (UInt32 x = 0; x < qtssAttrInfoNumParams; x++)        sDictionaryMaps[kAttrInfoDictIndex]->SetAttribute(x, QTSSAttrInfoDict::sAttributes[x].fAttrName,                                                            QTSSAttrInfoDict::sAttributes[x].fFuncPtr,                                                            QTSSAttrInfoDict::sAttributes[x].fAttrDataType,                                                            QTSSAttrInfoDict::sAttributes[x].fAttrPermission);    sDictionaryMaps[kServerDictIndex]       = new QTSSDictionaryMap(qtssSvrNumParams, QTSSDictionaryMap::kCompleteFunctionsAllowed);    sDictionaryMaps[kPrefsDictIndex]        = new QTSSDictionaryMap(qtssPrefsNumParams, QTSSDictionaryMap::kInstanceAttrsAllowed | QTSSDictionaryMap::kCompleteFunctionsAllowed);    sDictionaryMaps[kTextMessagesDictIndex] = new QTSSDictionaryMap(qtssMsgNumParams);    sDictionaryMaps[kServiceDictIndex]      = new QTSSDictionaryMap(0);    sDictionaryMaps[kRTPStreamDictIndex]    = new QTSSDictionaryMap(qtssRTPStrNumParams);	sDictionaryMaps[kClientSessionDictIndex]= new QTSSDictionaryMap(qtssCliSesNumParams, QTSSDictionaryMap::kCompleteFunctionsAllowed);    sDictionaryMaps[kRTSPSessionDictIndex]  = new QTSSDictionaryMap(qtssRTSPSesNumParams);    sDictionaryMaps[kRTSPRequestDictIndex]  = new QTSSDictionaryMap(qtssRTSPReqNumParams);    sDictionaryMaps[kRTSPHeaderDictIndex]   = new QTSSDictionaryMap(qtssNumHeaders);    sDictionaryMaps[kFileDictIndex]         = new QTSSDictionaryMap(qtssFlObjNumParams);    sDictionaryMaps[kModuleDictIndex]       = new QTSSDictionaryMap(qtssModNumParams);    sDictionaryMaps[kModulePrefsDictIndex]  = new QTSSDictionaryMap(0, QTSSDictionaryMap::kInstanceAttrsAllowed | QTSSDictionaryMap::kCompleteFunctionsAllowed);    sDictionaryMaps[kQTSSUserProfileDictIndex] = new QTSSDictionaryMap(qtssUserNumParams);    sDictionaryMaps[kQTSSConnectedUserDictIndex] = new QTSSDictionaryMap(qtssConnectionNumParams);}QTSSDictionaryMap::QTSSDictionaryMap(UInt32 inNumReservedAttrs, UInt32 inFlags):   fNextAvailableID(inNumReservedAttrs), fNumValidAttrs(inNumReservedAttrs),fAttrArraySize(inNumReservedAttrs), fFlags(inFlags){    if (fAttrArraySize < kMinArraySize)        fAttrArraySize = kMinArraySize;    fAttrArray = NEW QTSSAttrInfoDict*[fAttrArraySize];    ::memset(fAttrArray, 0, sizeof(QTSSAttrInfoDict*) * fAttrArraySize);}QTSS_Error QTSSDictionaryMap::AddAttribute( const char* inAttrName,                                            QTSS_AttrFunctionPtr inFuncPtr,                                            QTSS_AttrDataType inDataType,                                            QTSS_AttrPermission inPermission){    if (inAttrName == NULL || ::strlen(inAttrName) > QTSS_MAX_ATTRIBUTE_NAME_SIZE)        return QTSS_BadArgument;    for (UInt32 count = 0; count < fNextAvailableID; count++)    {        if  (::strcmp(&fAttrArray[count]->fAttrInfo.fAttrName[0], inAttrName) == 0)        {   // found the name in the dictionary            if (fAttrArray[count]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved )            { // it is a previously removed attribute                if (fAttrArray[count]->fAttrInfo.fAttrDataType == inDataType)                { //same type so reuse the attribute                    QTSS_AttributeID attrID = fAttrArray[count]->fID;                     this->UnRemoveAttribute(attrID);                     fAttrArray[count]->fAttrInfo.fFuncPtr = inFuncPtr; // reset                    fAttrArray[count]->fAttrInfo.fAttrPermission = inPermission;// reset                    return QTSS_NoErr; // nothing left to do. It is re-added.                }                                // a removed attribute with the same name but different type--so keep checking                 continue;            }            // an error, an active attribute with this name exists            return QTSS_AttrNameExists;        }    }    if (fAttrArraySize == fNextAvailableID)    {        // If there currently isn't an attribute array, or if the current array        // is full, allocate a new array and copy all the old stuff over to the new array.                UInt32 theNewArraySize = fAttrArraySize * 2;        if (theNewArraySize == 0)            theNewArraySize = kMinArraySize;                QTSSAttrInfoDict** theNewArray = NEW QTSSAttrInfoDict*[theNewArraySize];        ::memset(theNewArray, 0, sizeof(QTSSAttrInfoDict*) * theNewArraySize);        if (fAttrArray != NULL)        {            ::memcpy(theNewArray, fAttrArray, sizeof(QTSSAttrInfoDict*) * fAttrArraySize);            delete [] fAttrArray;        }        fAttrArray = theNewArray;        fAttrArraySize = theNewArraySize;    }        QTSS_AttributeID theID = fNextAvailableID;    fNextAvailableID++;    fNumValidAttrs++;    if (fFlags & kIsInstanceMap)        theID |= 0x80000000; // Set the high order bit to indicate this is an instance attr    // Copy the information into the first available element    // Currently, all attributes added in this fashion are always writeable    this->SetAttribute(theID, inAttrName, inFuncPtr, inDataType, inPermission);     return QTSS_NoErr;}void QTSSDictionaryMap::SetAttribute(   QTSS_AttributeID inID,                                         const char* inAttrName,                                        QTSS_AttrFunctionPtr inFuncPtr,                                        QTSS_AttrDataType inDataType,                                        QTSS_AttrPermission inPermission ){    UInt32 theIndex = QTSSDictionaryMap::ConvertAttrIDToArrayIndex(inID);    UInt32 theNameLen = ::strlen(inAttrName);    Assert(theNameLen < QTSS_MAX_ATTRIBUTE_NAME_SIZE);    Assert(fAttrArray[theIndex] == NULL);        fAttrArray[theIndex] = NEW QTSSAttrInfoDict;        //Copy the information into the first available element    fAttrArray[theIndex]->fID = inID;            ::strcpy(&fAttrArray[theIndex]->fAttrInfo.fAttrName[0], inAttrName);    fAttrArray[theIndex]->fAttrInfo.fFuncPtr = inFuncPtr;    fAttrArray[theIndex]->fAttrInfo.fAttrDataType = inDataType;     fAttrArray[theIndex]->fAttrInfo.fAttrPermission = inPermission;        fAttrArray[theIndex]->SetVal(qtssAttrName, &fAttrArray[theIndex]->fAttrInfo.fAttrName[0], theNameLen);    fAttrArray[theIndex]->SetVal(qtssAttrID, &fAttrArray[theIndex]->fID, sizeof(fAttrArray[theIndex]->fID));    fAttrArray[theIndex]->SetVal(qtssAttrDataType, &fAttrArray[theIndex]->fAttrInfo.fAttrDataType, sizeof(fAttrArray[theIndex]->fAttrInfo.fAttrDataType));    fAttrArray[theIndex]->SetVal(qtssAttrPermissions, &fAttrArray[theIndex]->fAttrInfo.fAttrPermission, sizeof(fAttrArray[theIndex]->fAttrInfo.fAttrPermission));}QTSS_Error  QTSSDictionaryMap::CheckRemovePermission(QTSS_AttributeID inAttrID){    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inAttrID);    if (theIndex < 0)        return QTSS_AttrDoesntExist;        if (0 == (fAttrArray[theIndex]->fAttrInfo.fAttrPermission & qtssAttrModeDelete))         return QTSS_BadArgument;    if (!(fFlags & kAllowRemoval))        return QTSS_BadArgument;        return QTSS_NoErr;}QTSS_Error  QTSSDictionaryMap::RemoveAttribute(QTSS_AttributeID inAttrID){    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inAttrID);    if (theIndex < 0)        return QTSS_AttrDoesntExist;        Assert(fFlags & kAllowRemoval);    if (!(fFlags & kAllowRemoval))        return QTSS_BadArgument;        //qtss_printf("QTSSDictionaryMap::RemoveAttribute arraySize=%lu numNonRemove= %lu fAttrArray[%lu]->fAttrInfo.fAttrName=%s/n",this->GetNumAttrs(), this->GetNumNonRemovedAttrs(), theIndex,fAttrArray[theIndex]->fAttrInfo.fAttrName);    //    // Don't actually touch the attribute or anything. Just flag the    // it as removed.    fAttrArray[theIndex]->fAttrInfo.fAttrPermission |= qtssPrivateAttrModeRemoved;    fNumValidAttrs--;//有效元素减1    Assert(fNumValidAttrs < 1000000);    return QTSS_NoErr;}QTSS_Error  QTSSDictionaryMap::UnRemoveAttribute(QTSS_AttributeID inAttrID){    if (this->ConvertAttrIDToArrayIndex(inAttrID) == -1)        return QTSS_AttrDoesntExist;        SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inAttrID);    if (theIndex < 0)        return QTSS_AttrDoesntExist;            fAttrArray[theIndex]->fAttrInfo.fAttrPermission &= ~qtssPrivateAttrModeRemoved;        fNumValidAttrs++;    return QTSS_NoErr;}QTSS_Error  QTSSDictionaryMap::GetAttrInfoByName(const char* inAttrName, QTSSAttrInfoDict** outAttrInfoObject,                                                    Bool16 returnRemovedAttr){    if (outAttrInfoObject == NULL)        return QTSS_BadArgument;    for (UInt32 count = 0; count < fNextAvailableID; count++)    {        if (::strcmp(&fAttrArray[count]->fAttrInfo.fAttrName[0], inAttrName) == 0)        {            if ((fAttrArray[count]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved) && (!returnRemovedAttr))                continue;                            *outAttrInfoObject = fAttrArray[count];            return QTSS_NoErr;        }       }    return QTSS_AttrDoesntExist;}QTSS_Error  QTSSDictionaryMap::GetAttrInfoByID(QTSS_AttributeID inID, QTSSAttrInfoDict** outAttrInfoObject){    if (outAttrInfoObject == NULL)        return QTSS_BadArgument;    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inID);    if (theIndex < 0)        return QTSS_AttrDoesntExist;        if (fAttrArray[theIndex]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved)        return QTSS_AttrDoesntExist;            *outAttrInfoObject = fAttrArray[theIndex];    return QTSS_NoErr;}QTSS_Error  QTSSDictionaryMap::GetAttrInfoByIndex(UInt32 inIndex, QTSSAttrInfoDict** outAttrInfoObject){    if (outAttrInfoObject == NULL)        return QTSS_BadArgument;    if (inIndex >= this->GetNumNonRemovedAttrs())        return QTSS_AttrDoesntExist;            UInt32 actualIndex = inIndex;    UInt32 max = this->GetNumAttrs();    if (fFlags & kAllowRemoval)    {        // If this dictionary map allows attributes to be removed, then        // the iteration index and array indexes won't line up exactly, so        // we have to iterate over the whole map all the time        actualIndex = 0;        for (UInt32 x = 0; x < max; x++)        {   if (fAttrArray[x] && (fAttrArray[x]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved) )            {   continue;            }                            if (actualIndex == inIndex)            {   actualIndex = x;                break;            }            actualIndex++;        }    }    //qtss_printf("QTSSDictionaryMap::GetAttrInfoByIndex arraySize=%lu numNonRemove= %lu fAttrArray[%lu]->fAttrInfo.fAttrName=%s/n",this->GetNumAttrs(), this->GetNumNonRemovedAttrs(), actualIndex,fAttrArray[actualIndex]->fAttrInfo.fAttrName);    Assert(actualIndex < fNextAvailableID);    Assert(!(fAttrArray[actualIndex]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved));    *outAttrInfoObject = fAttrArray[actualIndex];    return QTSS_NoErr;}QTSS_Error  QTSSDictionaryMap::GetAttrID(const char* inAttrName, QTSS_AttributeID* outID){    if (outID == NULL)        return QTSS_BadArgument;    QTSSAttrInfoDict* theAttrInfo = NULL;    QTSS_Error theErr = this->GetAttrInfoByName(inAttrName, &theAttrInfo);    if (theErr == QTSS_NoErr)        *outID = theAttrInfo->fID;    return theErr;}UInt32  QTSSDictionaryMap::GetMapIndex(QTSS_ObjectType inType){     if (inType < sNextDynamicMap)        return inType;          switch (inType)     {        case qtssRTPStreamObjectType:       return kRTPStreamDictIndex;        case qtssClientSessionObjectType:   return kClientSessionDictIndex;        case qtssRTSPSessionObjectType:     return kRTSPSessionDictIndex;        case qtssRTSPRequestObjectType:     return kRTSPRequestDictIndex;        case qtssRTSPHeaderObjectType:      return kRTSPHeaderDictIndex;        case qtssServerObjectType:          return kServerDictIndex;        case qtssPrefsobjectType:           return kPrefsDictIndex;        case qtssTextMessagesObjectType:    return kTextMessagesDictIndex;        case qtssFileObjectType:            return kFileDictIndex;        case qtssModuleObjectType:          return kModuleDictIndex;        case qtssModulePrefsObjectType:     return kModulePrefsDictIndex;        case qtssAttrInfoObjectType:        return kAttrInfoDictIndex;        case qtssUserProfileObjectType:     return kQTSSUserProfileDictIndex;        case qtssConnectedUserObjectType:   return kQTSSConnectedUserDictIndex;        default:                            return kIllegalDictionary;     }     return kIllegalDictionary;}QTSS_ObjectType QTSSDictionaryMap::CreateNewMap(){    if (sNextDynamicMap == kNumDictionaries + kNumDynamicDictionaryTypes)        return 0;            sDictionaryMaps[sNextDynamicMap] = new QTSSDictionaryMap(0);    QTSS_ObjectType result = (QTSS_ObjectType)sNextDynamicMap;    sNextDynamicMap++;        return result;}
/* * * @APPLE_LICENSE_HEADER_START@ *  * Copyright (c) 1999-2003 Apple Computer, 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 loggerclass 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;  }             //        // 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; };        //        //        // 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]);                                    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;        // 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__
/* * * @APPLE_LICENSE_HEADER_START@ *  * Copyright (c) 1999-2003 Apple Computer, 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.cpp    Contains:   Implementation of object defined in QTSServerInterface.h.        *///INCLUDES:#ifndef kVersionString#include "revision.h"#endif#include "QTSServerInterface.h"#include "RTPSessionInterface.h"#include "OSRef.h"#include "UDPSocketPool.h"#include "RTSPProtocol.h"#include "RTPPacketResender.h"#ifndef __MacOSX__#include "revision.h"#endif// STATIC DATAUInt32                  QTSServerInterface::sServerAPIVersion = QTSS_API_VERSION;QTSServerInterface*     QTSServerInterface::sServer = NULL;#if __MacOSX__StrPtrLen               QTSServerInterface::sServerNameStr("QTSS");#elseStrPtrLen               QTSServerInterface::sServerNameStr("DSS");#endif// kVersionString from revision.h, include with -i at project levelStrPtrLen               QTSServerInterface::sServerVersionStr(kVersionString);StrPtrLen               QTSServerInterface::sServerBuildStr(kBuildString);StrPtrLen               QTSServerInterface::sServerCommentStr(kCommentString);StrPtrLen               QTSServerInterface::sServerPlatformStr(kPlatformNameString);StrPtrLen               QTSServerInterface::sServerBuildDateStr(__DATE__ ", "__TIME__);char                    QTSServerInterface::sServerHeader[kMaxServerHeaderLen];StrPtrLen               QTSServerInterface::sServerHeaderPtr(sServerHeader, kMaxServerHeaderLen);ResizeableStringFormatter       QTSServerInterface::sPublicHeaderFormatter(NULL, 0);StrPtrLen                       QTSServerInterface::sPublicHeaderStr;QTSSModule**            QTSServerInterface::sModuleArray[QTSSModule::kNumRoles];UInt32                  QTSServerInterface::sNumModulesInRole[QTSSModule::kNumRoles];OSQueue                 QTSServerInterface::sModuleQueue;QTSSErrorLogStream      QTSServerInterface::sErrorLogStream;QTSSAttrInfoDict::AttrInfo  QTSServerInterface::sConnectedUserAttributes[] = {   /*fields:   fAttrName, fFuncPtr, fAttrDataType, fAttrPermission */    /* 0  */ { "qtssConnectionType",                    NULL,   qtssAttrDataTypeCharArray,      qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 1  */ { "qtssConnectionCreateTimeInMsec",        NULL,   qtssAttrDataTypeTimeVal,        qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 2  */ { "qtssConnectionTimeConnectedInMsec",     TimeConnected,  qtssAttrDataTypeTimeVal,        qtssAttrModeRead | qtssAttrModePreempSafe },    /* 3  */ { "qtssConnectionBytesSent",               NULL,   qtssAttrDataTypeUInt32,         qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 4  */ { "qtssConnectionMountPoint",              NULL,   qtssAttrDataTypeCharArray,      qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 5  */ { "qtssConnectionHostName",                NULL,   qtssAttrDataTypeCharArray,      qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe } ,    /* 6  */ { "qtssConnectionSessRemoteAddrStr",       NULL,   qtssAttrDataTypeCharArray,      qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 7  */ { "qtssConnectionSessLocalAddrStr",        NULL,   qtssAttrDataTypeCharArray,      qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },        /* 8  */ { "qtssConnectionCurrentBitRate",          NULL,   qtssAttrDataTypeUInt32,         qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 9  */ { "qtssConnectionPacketLossPercent",       NULL,   qtssAttrDataTypeFloat32,        qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    // this last parameter is a workaround for the current dictionary implementation.  For qtssConnectionTimeConnectedInMsec above we have a param    // retrieval function.  This needs storage to keep the value returned, but if it sets its own param then the function no longer gets called.    /* 10 */ { "qtssConnectionTimeStorage",             NULL,   qtssAttrDataTypeTimeVal,        qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },};QTSSAttrInfoDict::AttrInfo  QTSServerInterface::sAttributes[] = {   /*fields:   fAttrName, fFuncPtr, fAttrDataType, fAttrPermission */    /* 0  */ { "qtssServerAPIVersion",          NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe },    /* 1  */ { "qtssSvrDefaultDNSName",         NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead },    /* 2  */ { "qtssSvrDefaultIPAddr",          NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 3  */ { "qtssSvrServerName",             NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 4  */ { "qtssRTSPSvrServerVersion",      NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 5  */ { "qtssRTSPSvrServerBuildDate",    NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 6  */ { "qtssSvrRTSPPorts",              NULL,   qtssAttrDataTypeUInt16,     qtssAttrModeRead },    /* 7  */ { "qtssSvrRTSPServerHeader",       NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 8  */ { "qtssSvrState",              NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModeWrite  },    /* 9  */ { "qtssSvrIsOutOfDescriptors",     IsOutOfDescriptors,     qtssAttrDataTypeBool16, qtssAttrModeRead },    /* 10 */ { "qtssRTSPCurrentSessionCount",   NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 11 */ { "qtssRTSPHTTPCurrentSessionCount",NULL,  qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 12 */ { "qtssRTPSvrNumUDPSockets",       GetTotalUDPSockets,     qtssAttrDataTypeUInt32, qtssAttrModeRead },    /* 13 */ { "qtssRTPSvrCurConn",             NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 14 */ { "qtssRTPSvrTotalConn",           NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 15 */ { "qtssRTPSvrCurBandwidth",        NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 16 */ { "qtssRTPSvrTotalBytes",          NULL,   qtssAttrDataTypeUInt64,     qtssAttrModeRead },    /* 17 */ { "qtssRTPSvrAvgBandwidth",        NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 18 */ { "qtssRTPSvrCurPackets",          NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 19 */ { "qtssRTPSvrTotalPackets",        NULL,   qtssAttrDataTypeUInt64,     qtssAttrModeRead },    /* 20 */ { "qtssSvrHandledMethods",         NULL,   qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe  },    /* 21 */ { "qtssSvrModuleObjects",          NULL,   qtssAttrDataTypeQTSS_Object,qtssAttrModeRead | qtssAttrModePreempSafe },    /* 22 */ { "qtssSvrStartupTime",            NULL,   qtssAttrDataTypeTimeVal,    qtssAttrModeRead },    /* 23 */ { "qtssSvrGMTOffsetInHrs",         NULL,   qtssAttrDataTypeSInt32,     qtssAttrModeRead },    /* 24 */ { "qtssSvrDefaultIPAddrStr",       NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead },    /* 25 */ { "qtssSvrPreferences",            NULL,   qtssAttrDataTypeQTSS_Object,qtssAttrModeRead | qtssAttrModeInstanceAttrAllowed},    /* 26 */ { "qtssSvrMessages",               NULL,   qtssAttrDataTypeQTSS_Object,qtssAttrModeRead },    /* 27 */ { "qtssSvrClientSessions",         NULL,   qtssAttrDataTypeQTSS_Object,qtssAttrModeRead },    /* 28 */ { "qtssSvrCurrentTimeMilliseconds",CurrentUnixTimeMilli,   qtssAttrDataTypeTimeVal,qtssAttrModeRead},    /* 29 */ { "qtssSvrCPULoadPercent",         NULL,   qtssAttrDataTypeFloat32,    qtssAttrModeRead},    /* 30 */ { "qtssSvrNumReliableUDPBuffers",  GetNumUDPBuffers,   qtssAttrDataTypeUInt32,     qtssAttrModeRead },    /* 31 */ { "qtssSvrReliableUDPWastageInBytes",GetNumWastedBytes, qtssAttrDataTypeUInt32,        qtssAttrModeRead },    /* 32 */ { "qtssSvrConnectedUsers",         NULL, qtssAttrDataTypeQTSS_Object,      qtssAttrModeRead | qtssAttrModeWrite },    /* 33 */ { "qtssMP3SvrCurConn",             NULL, qtssAttrDataTypeUInt32,       qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 34 */ { "qtssMP3SvrTotalConn",           NULL, qtssAttrDataTypeUInt32,       qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 35 */ { "qtssMP3SvrCurBandwidth",        NULL, qtssAttrDataTypeUInt32,       qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 36 */ { "qtssMP3SvrTotalBytes",          NULL, qtssAttrDataTypeUInt64,       qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 37 */ { "qtssMP3SvrAvgBandwidth",        NULL, qtssAttrDataTypeUInt32,       qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },    /* 38  */ { "qtssSvrServerBuild",           NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 39  */ { "qtssSvrServerPlatform",        NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 40  */ { "qtssSvrRTSPServerComment",     NULL,   qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },    /* 41  */ { "qtssSvrNumThinned",            NULL,   qtssAttrDataTypeSInt32,     qtssAttrModeRead | qtssAttrModeWrite  }};void    QTSServerInterface::Initialize(){    for (UInt32 x = 0; x < qtssSvrNumParams; x++)        QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServerDictIndex)->            SetAttribute(x, sAttributes[x].fAttrName, sAttributes[x].fFuncPtr,                sAttributes[x].fAttrDataType, sAttributes[x].fAttrPermission);    for (UInt32 y = 0; y < qtssConnectionNumParams; y++)        QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kQTSSConnectedUserDictIndex)->            SetAttribute(y, sConnectedUserAttributes[y].fAttrName, sConnectedUserAttributes[y].fFuncPtr,                sConnectedUserAttributes[y].fAttrDataType, sConnectedUserAttributes[y].fAttrPermission);    //Write out a premade server header    StringFormatter serverFormatter(sServerHeaderPtr.Ptr, kMaxServerHeaderLen);    serverFormatter.Put(RTSPProtocol::GetHeaderString(qtssServerHeader));    serverFormatter.Put(": ");    serverFormatter.Put(sServerNameStr);    serverFormatter.PutChar('/');    serverFormatter.Put(sServerVersionStr);    serverFormatter.PutChar(' ');    serverFormatter.PutChar('(');    serverFormatter.Put("Build/");    serverFormatter.Put(sServerBuildStr);    serverFormatter.Put("; ");    serverFormatter.Put("Platform/");    serverFormatter.Put(sServerPlatformStr);    serverFormatter.PutChar(';');     if (sServerCommentStr.Len > 0)    {        serverFormatter.PutChar(' ');        serverFormatter.Put(sServerCommentStr);    }    serverFormatter.PutChar(')');    sServerHeaderPtr.Len = serverFormatter.GetCurrentOffset();    Assert(sServerHeaderPtr.Len < kMaxServerHeaderLen);}QTSServerInterface::QTSServerInterface() :  QTSSDictionary(QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServerDictIndex), &fMutex),    fSocketPool(NULL),    fRTPMap(NULL),    fSrvrPrefs(NULL),    fSrvrMessages(NULL),    fServerState(qtssStartingUpState),    fDefaultIPAddr(0),    fListeners(NULL),    fNumListeners(0),    fStartupTime_UnixMilli(0),    fGMTOffset(0),    fNumRTSPSessions(0),    fNumRTSPHTTPSessions(0),    fNumRTPSessions(0),    fNumRTPPlayingSessions(0),    fTotalRTPSessions(0),    fTotalRTPBytes(0),    fTotalRTPPackets(0),    fTotalRTPPacketsLost(0),    fPeriodicRTPBytes(0),    fPeriodicRTPPacketsLost(0),    fPeriodicRTPPackets(0),    fCurrentRTPBandwidthInBits(0),    fAvgRTPBandwidthInBits(0),    fRTPPacketsPerSecond(0),    fCPUPercent(0),    fCPUTimeUsedInSec(0),    fUDPWastageInBytes(0),    fNumUDPBuffers(0),    fNumMP3Sessions(0),    fTotalMP3Sessions(0),    fCurrentMP3BandwidthInBits(0),    fTotalMP3Bytes(0),    fAvgMP3BandwidthInBits(0),    fSigInt(false),    fSigTerm(false),    fDebugLevel(0),    fDebugOptions(0),        fMaxLate(0),    fTotalLate(0),    fCurrentMaxLate(0),    fTotalQuality(0),    fNumThinned(0){    for (UInt32 y = 0; y < QTSSModule::kNumRoles; y++)    {        sModuleArray[y] = NULL;        sNumModulesInRole[y] = 0;    }    this->SetVal(qtssSvrState,              &fServerState,              sizeof(fServerState));    this->SetVal(qtssServerAPIVersion,      &sServerAPIVersion,         sizeof(sServerAPIVersion));    this->SetVal(qtssSvrDefaultIPAddr,      &fDefaultIPAddr,            sizeof(fDefaultIPAddr));    this->SetVal(qtssSvrServerName,         sServerNameStr.Ptr,         sServerNameStr.Len);    this->SetVal(qtssSvrServerVersion,      sServerVersionStr.Ptr,      sServerVersionStr.Len);    this->SetVal(qtssSvrServerBuildDate,    sServerBuildDateStr.Ptr,    sServerBuildDateStr.Len);    this->SetVal(qtssSvrRTSPServerHeader,   sServerHeaderPtr.Ptr,       sServerHeaderPtr.Len);    this->SetVal(qtssRTSPCurrentSessionCount, &fNumRTSPSessions,        sizeof(fNumRTSPSessions));    this->SetVal(qtssRTSPHTTPCurrentSessionCount, &fNumRTSPHTTPSessions,sizeof(fNumRTSPHTTPSessions));    this->SetVal(qtssRTPSvrCurConn,         &fNumRTPSessions,           sizeof(fNumRTPSessions));    this->SetVal(qtssRTPSvrTotalConn,       &fTotalRTPSessions,         sizeof(fTotalRTPSessions));    this->SetVal(qtssRTPSvrCurBandwidth,    &fCurrentRTPBandwidthInBits,sizeof(fCurrentRTPBandwidthInBits));    this->SetVal(qtssRTPSvrTotalBytes,      &fTotalRTPBytes,            sizeof(fTotalRTPBytes));    this->SetVal(qtssRTPSvrAvgBandwidth,    &fAvgRTPBandwidthInBits,    sizeof(fAvgRTPBandwidthInBits));    this->SetVal(qtssRTPSvrCurPackets,      &fRTPPacketsPerSecond,      sizeof(fRTPPacketsPerSecond));    this->SetVal(qtssRTPSvrTotalPackets,    &fTotalRTPPackets,          sizeof(fTotalRTPPackets));    this->SetVal(qtssSvrStartupTime,        &fStartupTime_UnixMilli,    sizeof(fStartupTime_UnixMilli));    this->SetVal(qtssSvrGMTOffsetInHrs,     &fGMTOffset,                sizeof(fGMTOffset));    this->SetVal(qtssSvrCPULoadPercent,     &fCPUPercent,               sizeof(fCPUPercent));    this->SetVal(qtssMP3SvrCurConn,         &fNumMP3Sessions,           sizeof(fNumMP3Sessions));    this->SetVal(qtssMP3SvrTotalConn,       &fTotalMP3Sessions,         sizeof(fTotalMP3Sessions));    this->SetVal(qtssMP3SvrCurBandwidth,    &fCurrentMP3BandwidthInBits,sizeof(fCurrentMP3BandwidthInBits));    this->SetVal(qtssMP3SvrTotalBytes,      &fTotalMP3Bytes,            sizeof(fTotalMP3Bytes));    this->SetVal(qtssMP3SvrAvgBandwidth,    &fAvgMP3BandwidthInBits,    sizeof(fAvgMP3BandwidthInBits));    this->SetVal(qtssSvrServerBuild,        sServerBuildStr.Ptr,    sServerBuildStr.Len);    this->SetVal(qtssSvrRTSPServerComment,  sServerCommentStr.Ptr,  sServerCommentStr.Len);    this->SetVal(qtssSvrServerPlatform,     sServerPlatformStr.Ptr, sServerPlatformStr.Len);    this->SetVal(qtssSvrNumThinned,         &fNumThinned,               sizeof(fNumThinned));        sServer = this;}void QTSServerInterface::LogError(QTSS_ErrorVerbosity inVerbosity, char* inBuffer){    QTSS_RoleParams theParams;    theParams.errorParams.inVerbosity = inVerbosity;    theParams.errorParams.inBuffer = inBuffer;    for (UInt32 x = 0; x < QTSServerInterface::GetNumModulesInRole(QTSSModule::kErrorLogRole); x++)        (void)QTSServerInterface::GetModule(QTSSModule::kErrorLogRole, x)->CallDispatch(QTSS_ErrorLog_Role, &theParams);    // If this is a fatal error, set the proper attribute in the RTSPServer dictionary    if ((inVerbosity == qtssFatalVerbosity) && (sServer != NULL))    {        QTSS_ServerState theState = qtssFatalErrorState;        (void)sServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState));    }}void QTSServerInterface::KillAllRTPSessions(){    OSMutexLocker locker(fRTPMap->GetMutex());    for (OSRefHashTableIter theIter(fRTPMap->GetHashTable()); !theIter.IsDone(); theIter.Next())    {        OSRef* theRef = theIter.GetCurrent();        RTPSessionInterface* theSession = (RTPSessionInterface*)theRef->GetObject();        theSession->Signal(Task::kKillEvent);    }   }void QTSServerInterface::SetValueComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap,							UInt32 inValueIndex, void* inNewValue, UInt32 inNewValueLen){    if (inAttrIndex == qtssSvrState)    {        Assert(inNewValueLen == sizeof(QTSS_ServerState));                //        // Invoke the server state change role        QTSS_RoleParams theParams;        theParams.stateChangeParams.inNewState = *(QTSS_ServerState*)inNewValue;                static QTSS_ModuleState sStateChangeState = { NULL, 0, NULL, false };        if (OSThread::GetCurrent() == NULL)            OSThread::SetMainThreadData(&sStateChangeState);        else            OSThread::GetCurrent()->SetThreadData(&sStateChangeState);        UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kStateChangeRole);        {            for (UInt32 theCurrentModule = 0; theCurrentModule < numModules; theCurrentModule++)            {                  QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kStateChangeRole, theCurrentModule);                (void)theModule->CallDispatch(QTSS_StateChange_Role, &theParams);            }        }        //        // Make sure to clear out the thread data        if (OSThread::GetCurrent() == NULL)            OSThread::SetMainThreadData(NULL);        else            OSThread::GetCurrent()->SetThreadData(NULL);    }}RTPStatsUpdaterTask::RTPStatsUpdaterTask():   Task(), fLastBandwidthTime(0), fLastBandwidthAvg(0), fLastBytesSent(0), fLastTotalMP3Bytes(0){    this->SetTaskName("RTPStatsUpdaterTask");    this->Signal(Task::kStartEvent);}Float32 RTPStatsUpdaterTask::GetCPUTimeInSeconds(){    // This function returns the total number of seconds that the    // process running RTPStatsUpdaterTask() has been executing as    // a user process.    Float32 cpuTimeInSec = 0.0;#ifdef __Win32__    // The Win32 way of getting the time for this process    HANDLE hProcess = GetCurrentProcess();    SInt64 createTime, exitTime, kernelTime, userTime;    if(GetProcessTimes(hProcess, (LPFILETIME)&createTime, (LPFILETIME)&exitTime, (LPFILETIME)&kernelTime, (LPFILETIME)&userTime))    {        // userTime is in 10**-7 seconds since Jan.1, 1607.        // (What type of computers did they use in 1607?)        cpuTimeInSec = (Float32) (userTime/10000000.0);    }    else    {        // This should never happen!!!        Assert(0);        cpuTimeInSec = 0.0;    }#else    // The UNIX way of getting the time for this process    clock_t cpuTime = clock();    cpuTimeInSec = (Float32) cpuTime / CLOCKS_PER_SEC;#endif    return cpuTimeInSec;}SInt64 RTPStatsUpdaterTask::Run(){    QTSServerInterface* theServer = QTSServerInterface::sServer;        // All of this must happen atomically wrt dictionary values we are manipulating    OSMutexLocker locker(&theServer->fMutex);        //First update total bytes. This must be done because total bytes is a 64 bit number,    //so no atomic functions can apply.    //    // NOTE: The line below is not thread safe on non-PowerPC platforms. This is    // because the fPeriodicRTPBytes variable is being manipulated from within an    // atomic_add. On PowerPC, assignments are atomic, so the assignment below is ok.    // On a non-PowerPC platform, the following would be thread safe:    //unsigned int periodicBytes = atomic_add(&theServer->fPeriodicRTPBytes, 0);    unsigned int periodicBytes = theServer->fPeriodicRTPBytes;    (void)atomic_sub(&theServer->fPeriodicRTPBytes, periodicBytes);    theServer->fTotalRTPBytes += periodicBytes;        // Same deal for packet totals    unsigned int periodicPackets = theServer->fPeriodicRTPPackets;    (void)atomic_sub(&theServer->fPeriodicRTPPackets, periodicPackets);    theServer->fTotalRTPPackets += periodicPackets;        // ..and for lost packet totals    unsigned int periodicPacketsLost = theServer->fPeriodicRTPPacketsLost;    (void)atomic_sub(&theServer->fPeriodicRTPPacketsLost, periodicPacketsLost);    theServer->fTotalRTPPacketsLost += periodicPacketsLost;        SInt64 curTime = OS::Milliseconds();        //for cpu percent        Float32 cpuTimeInSec = GetCPUTimeInSeconds();        //also update current bandwidth statistic    if (fLastBandwidthTime != 0)    {        Assert(curTime > fLastBandwidthTime);        UInt32 delta = (UInt32)(curTime - fLastBandwidthTime);		// Prevent divide by zero errror        if (delta < 1000) {            WarnV(delta >= 1000, "delta < 1000");			(void)this->GetEvents();//we must clear the event mask!			return theServer->GetPrefs()->GetTotalBytesUpdateTimeInSecs() * 1000;		}        UInt32 packetsPerSecond = periodicPackets;        UInt32 theTime = delta / 1000;         packetsPerSecond /= theTime;        Assert(packetsPerSecond >= 0);        theServer->fRTPPacketsPerSecond = packetsPerSecond;        UInt32 additionalBytes = 28 * packetsPerSecond; // IP headers = 20 + UDP headers = 8        UInt32 headerBits = 8 * additionalBytes;        headerBits  /= theTime;              Float32 bits = periodicBytes * 8;        bits /= theTime;        theServer->fCurrentRTPBandwidthInBits = (UInt32) (bits + headerBits);                 // okay let's do it for MP3 bytes now        bits = (Float32)(((SInt64)theServer->fTotalMP3Bytes - fLastTotalMP3Bytes) * 8);        bits /= theTime;        theServer->fCurrentMP3BandwidthInBits = (UInt32)bits;        //do the computation for cpu percent        Float32 diffTime = cpuTimeInSec - theServer->fCPUTimeUsedInSec;        theServer->fCPUPercent = (diffTime/theTime) * 100;  				UInt32 numProcessors = OS::GetNumProcessors();				if (numProcessors > 1)			theServer->fCPUPercent /= numProcessors;    }        fLastTotalMP3Bytes = (SInt64)theServer->fTotalMP3Bytes;    fLastBandwidthTime = curTime;    // We use a running average for avg. bandwidth calculations    theServer->fAvgMP3BandwidthInBits = (theServer->fAvgMP3BandwidthInBits            + theServer->fCurrentMP3BandwidthInBits)/2;         //for cpu percent    theServer->fCPUTimeUsedInSec    = cpuTimeInSec;         //also compute average bandwidth, a much more smooth value. This is done with    //the fLastBandwidthAvg, a timestamp of the last time we did an average, and    //fLastBytesSent, the number of bytes sent when we last did an average.    if ((fLastBandwidthAvg != 0) && (curTime > (fLastBandwidthAvg +        (theServer->GetPrefs()->GetAvgBandwidthUpdateTimeInSecs() * 1000))))    {        UInt32 delta = (UInt32)(curTime - fLastBandwidthAvg);        SInt64 bytesSent = theServer->fTotalRTPBytes - fLastBytesSent;        Assert(bytesSent >= 0);                //do the bandwidth computation using floating point divides        //for accuracy and speed.        Float32 bits = (Float32)(bytesSent * 8);        Float32 theAvgTime = (Float32)delta;        theAvgTime /= 1000;        bits /= theAvgTime;        Assert(bits >= 0);        theServer->fAvgRTPBandwidthInBits = (UInt32)bits;        fLastBandwidthAvg = curTime;        fLastBytesSent = theServer->fTotalRTPBytes;                //if the bandwidth is above the bandwidth setting, disconnect 1 user by sending them        //a BYE RTCP packet.        SInt32 maxKBits = theServer->GetPrefs()->GetMaxKBitsBandwidth();        if ((maxKBits > -1) && (theServer->fAvgRTPBandwidthInBits > ((UInt32)maxKBits * 1024)))        {            //we need to make sure that all of this happens atomically wrt the session map            OSMutexLocker locker(theServer->GetRTPSessionMap()->GetMutex());            RTPSessionInterface* theSession = this->GetNewestSession(theServer->fRTPMap);            if (theSession != NULL)                if ((curTime - theSession->GetSessionCreateTime()) <                        theServer->GetPrefs()->GetSafePlayDurationInSecs() * 1000)                    theSession->Signal(Task::kKillEvent);        }    }    else if (fLastBandwidthAvg == 0)    {        fLastBandwidthAvg = curTime;        fLastBytesSent = theServer->fTotalRTPBytes;    }        (void)this->GetEvents();//we must clear the event mask!    return theServer->GetPrefs()->GetTotalBytesUpdateTimeInSecs() * 1000;}RTPSessionInterface* RTPStatsUpdaterTask::GetNewestSession(OSRefTable* inRTPSessionMap){    //Caller must lock down the RTP session map    SInt64 theNewestPlayTime = 0;    RTPSessionInterface* theNewestSession = NULL;        //use the session map to iterate through all the sessions, finding the most    //recently connected client    for (OSRefHashTableIter theIter(inRTPSessionMap->GetHashTable()); !theIter.IsDone(); theIter.Next())    {        OSRef* theRef = theIter.GetCurrent();        RTPSessionInterface* theSession = (RTPSessionInterface*)theRef->GetObject();        Assert(theSession->GetSessionCreateTime() > 0);        if (theSession->GetSessionCreateTime() > theNewestPlayTime)        {            theNewestPlayTime = theSession->GetSessionCreateTime();            theNewestSession = theSession;        }    }    return theNewestSession;}void* QTSServerInterface::CurrentUnixTimeMilli(QTSSDictionary* inServer, UInt32* outLen){    QTSServerInterface* theServer = (QTSServerInterface*)inServer;    theServer->fCurrentTime_UnixMilli = OS::TimeMilli_To_UnixTimeMilli(OS::Milliseconds());         // Return the result    *outLen = sizeof(theServer->fCurrentTime_UnixMilli);    return &theServer->fCurrentTime_UnixMilli;}void* QTSServerInterface::GetTotalUDPSockets(QTSSDictionary* inServer, UInt32* outLen){    QTSServerInterface* theServer = (QTSServerInterface*)inServer;    // Multiply by 2 because this is returning the number of socket *pairs*    theServer->fTotalUDPSockets = theServer->fSocketPool->GetSocketQueue()->GetLength() * 2;        // Return the result    *outLen = sizeof(theServer->fTotalUDPSockets);    return &theServer->fTotalUDPSockets;}void* QTSServerInterface::IsOutOfDescriptors(QTSSDictionary* inServer, UInt32* outLen){    QTSServerInterface* theServer = (QTSServerInterface*)inServer;        theServer->fIsOutOfDescriptors = false;    for (UInt32 x = 0; x < theServer->fNumListeners; x++)    {        if (theServer->fListeners[x]->IsOutOfDescriptors())        {            theServer->fIsOutOfDescriptors = true;            break;        }    }    // Return the result    *outLen = sizeof(theServer->fIsOutOfDescriptors);    return &theServer->fIsOutOfDescriptors;}void* QTSServerInterface::GetNumUDPBuffers(QTSSDictionary* inServer, UInt32* outLen){    // This param retrieval function must be invoked each time it is called,    // because whether we are out of descriptors or not is continually changing    QTSServerInterface* theServer = (QTSServerInterface*)inServer;        theServer->fNumUDPBuffers = RTPPacketResender::GetNumRetransmitBuffers();    // Return the result    *outLen = sizeof(theServer->fNumUDPBuffers);    return &theServer->fNumUDPBuffers;}void* QTSServerInterface::GetNumWastedBytes(QTSSDictionary* inServer, UInt32* outLen){    // This param retrieval function must be invoked each time it is called,    // because whether we are out of descriptors or not is continually changing    QTSServerInterface* theServer = (QTSServerInterface*)inServer;        theServer->fUDPWastageInBytes = RTPPacketResender::GetWastedBufferBytes();    // Return the result    *outLen = sizeof(theServer->fUDPWastageInBytes);    return &theServer->fUDPWastageInBytes;  }void* QTSServerInterface::TimeConnected(QTSSDictionary* inConnection, UInt32* outLen){    SInt64 connectTime;    void* result;    UInt32 len = sizeof(connectTime);    inConnection->GetValue(qtssConnectionCreateTimeInMsec, 0, &connectTime, &len);    SInt64 timeConnected = OS::Milliseconds() - connectTime;    *outLen = sizeof(timeConnected);    inConnection->SetValue(qtssConnectionTimeStorage, 0, &timeConnected, sizeof(connectTime));    inConnection->GetValuePtr(qtssConnectionTimeStorage, 0, &result, outLen);    // Return the result    return result;}QTSS_Error  QTSSErrorLogStream::Write(void* inBuffer, UInt32 inLen, UInt32* outLenWritten, UInt32 inFlags){    // For the error log stream, the flags are considered to be the verbosity    // of the error.    if (inFlags >= qtssIllegalVerbosity)        inFlags = qtssMessageVerbosity;            QTSServerInterface::LogError(inFlags, (char*)inBuffer);    if (outLenWritten != NULL)        *outLenWritten = inLen;            return QTSS_NoErr;}void QTSSErrorLogStream::LogAssert(char* inMessage){    QTSServerInterface::LogError(qtssAssertVerbosity, inMessage);}
/* * * @APPLE_LICENSE_HEADER_START@ *  * Copyright (c) 1999-2003 Apple Computer, 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@ * */#ifndef QTSS_H#define QTSS_H//  #ifdef __cplusplus//  extern "C" {//  #endif#include "OSHeaders.h"#include "QTSSRTSPProtocol.h"#ifndef __Win32__#include <sys/uio.h>#endif#define QTSS_API_VERSION                0x00040000#define QTSS_MAX_MODULE_NAME_LENGTH     64#define QTSS_MAX_SESSION_ID_LENGTH      32#define QTSS_MAX_ATTRIBUTE_NAME_SIZE    64//*******************************// ENUMERATED TYPES/**********************************/// Error Codesenum{    QTSS_NoErr              = 0,    QTSS_RequestFailed      = -1,    QTSS_Unimplemented      = -2,    QTSS_RequestArrived     = -3,    QTSS_OutOfState         = -4,    QTSS_NotAModule         = -5,    QTSS_WrongVersion       = -6,    QTSS_IllegalService     = -7,    QTSS_BadIndex           = -8,    QTSS_ValueNotFound      = -9,    QTSS_BadArgument        = -10,    QTSS_ReadOnly           = -11,    QTSS_NotPreemptiveSafe  = -12,    QTSS_NotEnoughSpace     = -13,    QTSS_WouldBlock         = -14,    QTSS_NotConnected       = -15,    QTSS_FileNotFound       = -16,    QTSS_NoMoreData         = -17,    QTSS_AttrDoesntExist    = -18,    QTSS_AttrNameExists     = -19,    QTSS_InstanceAttrsNotAllowed= -20};typedef SInt32 QTSS_Error;// QTSS_AddStreamFlags used in the QTSS_AddStream Callback functionenum{    qtssASFlagsNoFlags              = 0x00000000,    qtssASFlagsAllowDestination     = 0x00000001,    qtssASFlagsForceInterleave      = 0x00000002,    qtssASFlagsDontUseSlowStart     = 0x00000004,    qtssASFlagsForceUDPTransport    = 0x00000008};typedef UInt32 QTSS_AddStreamFlags;// QTSS_PlayFlags used in the QTSS_Play Callback function.enum {    qtssPlayFlagsSendRTCP           = 0x00000001,   // have the server generate RTCP Sender Reports     qtssPlayFlagsAppendServerInfo   = 0x00000002    // have the server append the server info APP packet to your RTCP Sender Reports};typedef UInt32 QTSS_PlayFlags;// Flags for QTSS_Write when writing to a QTSS_ClientSessionObject.enum {    qtssWriteFlagsNoFlags           = 0x00000000,    qtssWriteFlagsIsRTP             = 0x00000001,    qtssWriteFlagsIsRTCP            = 0x00000002,       qtssWriteFlagsWriteBurstBegin   = 0x00000004,    qtssWriteFlagsBufferData        = 0x00000008};typedef UInt32 QTSS_WriteFlags;// Flags for QTSS_SendStandardRTSPResponseenum{    qtssPlayRespWriteTrackInfo      = 0x00000001,    qtssSetupRespDontWriteSSRC      = 0x00000002};// Flags for the qtssRTSPReqAction attribute in a QTSS_RTSPRequestObject.enum {    qtssActionFlagsNoFlags      = 0x00000000,    qtssActionFlagsRead         = 0x00000001,    qtssActionFlagsWrite        = 0x00000002    };typedef UInt32 QTSS_ActionFlags;/**********************************/// RTP SESSION STATES//// Is this session playing, paused, or what?enum{    qtssPausedState         = 0,    qtssPlayingState        = 1};typedef UInt32 QTSS_RTPSessionState;//*********************************/// CLIENT SESSION CLOSING REASON//// Why is this Client going away?enum{    qtssCliSesCloseClientTeardown       = 0, // QTSS_Teardown was called on this session    qtssCliSesCloseTimeout              = 1, // Server is timing this session out    qtssCliSesCloseClientDisconnect     = 2  // Client disconnected.};typedef UInt32 QTSS_CliSesClosingReason;// CLIENT SESSION TEARDOWN REASON////  An attribute in the QTSS_ClientSessionObject ////  When calling QTSS_Teardown, a module should specify the QTSS_CliSesTeardownReason in the QTSS_ClientSessionObject //  if the tear down was not a client request.//  enum{    qtssCliSesTearDownClientRequest             = 0,    qtssCliSesTearDownUnsupportedMedia          = 1,    qtssCliSesTearDownServerShutdown            = 2,    qtssCliSesTearDownServerInternalErr         = 3,    qtssCliSesTearDownBroadcastEnded            = 4 // A broadcast the client was watching ended    };typedef UInt32  QTSS_CliSesTeardownReason;// Eventsenum{    QTSS_ReadableEvent      = 1,    QTSS_WriteableEvent     = 2};typedef UInt32  QTSS_EventType;// Authentication schemesenum{    qtssAuthNone        = 0,    qtssAuthBasic       = 1,    qtssAuthDigest      = 2};typedef UInt32  QTSS_AuthScheme;/**********************************/// RTSP SESSION TYPES//// Is this a normal RTSP session or an RTSP / HTTP session?enum{    qtssRTSPSession         = 0,    qtssRTSPHTTPSession     = 1,    qtssRTSPHTTPInputSession= 2 //The input half of an RTSPHTTP session. These session types are usually very short lived.};typedef UInt32 QTSS_RTSPSessionType;/**********************************///// What type of RTP transport is being used for the RTP stream?enum{    qtssRTPTransportTypeUDP         = 0,    qtssRTPTransportTypeReliableUDP = 1,    qtssRTPTransportTypeTCP         = 2};typedef UInt32 QTSS_RTPTransportType;/**********************************///// What type of RTP network mode is being used for the RTP stream?// unicast | multicast (mutually exclusive)enum{    qtssRTPNetworkModeDefault       = 0, // not declared    qtssRTPNetworkModeMulticast     = 1,    qtssRTPNetworkModeUnicast       = 2};typedef UInt32 QTSS_RTPNetworkMode;/**********************************///// The transport mode in a SETUP requestenum{    qtssRTPTransportModePlay        = 0,    qtssRTPTransportModeRecord      = 1};typedef UInt32 QTSS_RTPTransportMode;/**********************************/// PAYLOAD TYPES//// When a module adds an RTP stream to a client session, it must specify// the stream's payload type. This is so that other modules can find out// this information in a generalized fashion. Here are the currently// defined payload typesenum{    qtssUnknownPayloadType  = 0,    qtssVideoPayloadType    = 1,    qtssAudioPayloadType    = 2};typedef UInt32 QTSS_RTPPayloadType;/**********************************/// QTSS API OBJECT TYPESenum{    qtssDynamicObjectType           = FOUR_CHARS_TO_INT('d', 'y', 'm', 'c'), //dymc    qtssRTPStreamObjectType         = FOUR_CHARS_TO_INT('r', 's', 't', 'o'), //rsto    qtssClientSessionObjectType     = FOUR_CHARS_TO_INT('c', 's', 'e', 'o'), //cSEO    qtssRTSPSessionObjectType       = FOUR_CHARS_TO_INT('s', 's', 'e', 'o'), //sseo    qtssRTSPRequestObjectType       = FOUR_CHARS_TO_INT('s', 'r', 'q', 'o'), //srqo    qtssRTSPHeaderObjectType        = FOUR_CHARS_TO_INT('s', 'h', 'd', 'o'), //shdo    qtssServerObjectType            = FOUR_CHARS_TO_INT('s', 'e', 'r', 'o'), //sero    qtssPrefsObjectType             = FOUR_CHARS_TO_INT('p', 'r', 'f', 'o'), //prfo    qtssTextMessagesObjectType      = FOUR_CHARS_TO_INT('t', 'x', 't', 'o'), //txto    qtssFileObjectType              = FOUR_CHARS_TO_INT('f', 'i', 'l', 'e'), //file    qtssModuleObjectType            = FOUR_CHARS_TO_INT('m', 'o', 'd', 'o'), //modo    qtssModulePrefsObjectType       = FOUR_CHARS_TO_INT('m', 'o', 'd', 'p'), //modp    qtssAttrInfoObjectType          = FOUR_CHARS_TO_INT('a', 't', 't', 'r'), //attr    qtssUserProfileObjectType       = FOUR_CHARS_TO_INT('u', 's', 'p', 'o'), //uspo    qtssConnectedUserObjectType     = FOUR_CHARS_TO_INT('c', 'u', 's', 'r')  //cusr};typedef UInt32 QTSS_ObjectType;/**********************************/// ERROR LOG VERBOSITIES//// This provides some information to the module on the priority or// type of this error message.//// When modules write to the error log stream (see below),// the verbosity is qtssMessageVerbosity.enum{    qtssFatalVerbosity              = 0,    qtssWarningVerbosity            = 1,    qtssMessageVerbosity            = 2,    qtssAssertVerbosity             = 3,    qtssDebugVerbosity              = 4,        qtssIllegalVerbosity            = 5};typedef UInt32 QTSS_ErrorVerbosity;enum{    qtssOpenFileNoFlags =       0,    qtssOpenFileAsync =         1,  // File stream will be asynchronous (read may return QTSS_WouldBlock)    qtssOpenFileReadAhead =     2   // File stream will be used for a linear read through the file.};typedef UInt32 QTSS_OpenFileFlags;/**********************************/// SERVER STATES////  An attribute in the QTSS_ServerObject returns the server state//  as a QTSS_ServerState. Modules may also set the server state.////  Setting the server state to qtssFatalErrorState, or qtssShuttingDownState//  will cause the server to quit.////  Setting the state to qtssRefusingConnectionsState will cause the server//  to start refusing new connections.enum{    qtssStartingUpState             = 0,    qtssRunningState                = 1,    qtssRefusingConnectionsState    = 2,    qtssFatalErrorState             = 3,//a fatal error has occurred, not shutting down yet    qtssShuttingDownState           = 4,    qtssIdleState                   = 5 // Like refusing connections state, but will also kill any currently connected clients};typedef UInt32 QTSS_ServerState;/**********************************/// ILLEGAL ATTRIBUTE IDenum{    qtssIllegalAttrID               = -1,    qtssIllegalServiceID            = -1};//*********************************/// QTSS DON'T CALL SENDPACKETS AGAIN// If this time is specified as the next packet time when returning// from QTSS_SendPackets_Role, the module won't get called again in// that role until another QTSS_Play is issuedenum{    qtssDontCallSendPacketsAgain    = -1};// DATA TYPESenum{    qtssAttrDataTypeUnknown         = 0,    qtssAttrDataTypeCharArray       = 1,    qtssAttrDataTypeBool16          = 2,    qtssAttrDataTypeSInt16          = 3,    qtssAttrDataTypeUInt16          = 4,    qtssAttrDataTypeSInt32          = 5,    qtssAttrDataTypeUInt32          = 6,    qtssAttrDataTypeSInt64          = 7,    qtssAttrDataTypeUInt64          = 8,    qtssAttrDataTypeQTSS_Object     = 9,    qtssAttrDataTypeQTSS_StreamRef  = 10,    qtssAttrDataTypeFloat32         = 11,    qtssAttrDataTypeFloat64         = 12,    qtssAttrDataTypeVoidPointer     = 13,    qtssAttrDataTypeTimeVal         = 14,        qtssAttrDataTypeNumTypes        = 15};typedef UInt32 QTSS_AttrDataType;enum{    qtssAttrModeRead                = 1,    qtssAttrModeWrite               = 2,    qtssAttrModePreempSafe          = 4,    qtssAttrModeInstanceAttrAllowed = 8,	qtssAttrModeCacheable			= 16,    qtssAttrModeDelete              = 32};typedef UInt32 QTSS_AttrPermission;/**********************************///BUILT IN SERVER ATTRIBUTES//The server maintains many attributes internally, and makes these available to plug-ins.//Each value is a standard attribute, with a name and everything. Plug-ins may resolve the id's of//these values by name if they'd like, but in the initialize role they will receive a struct of//all the ids of all the internally maintained server parameters. This enumerated type block defines the indexes//in that array for the id's.enum{    //QTSS_RTPStreamObject parameters. All of these are preemptive safe.        qtssRTPStrTrackID               = 0,    //r/w       //UInt32            //Unique ID identifying each stream. This will default to 0 unless set explicitly by a module.    qtssRTPStrssRC                  = 1,    //read      //UInt32            //SSRC (Synchronization Source) generated by the server. Guarenteed to be unique amongst all streams in the session.                                                                            //This SSRC will be included in all RTCP Sender Reports generated by the server. See The RTP / RTCP RFC for more info on SSRCs.    qtssRTPStrPayloadName           = 2,    //r/w       //char array        //Payload name of the media on this stream. This will be empty unless set explicitly by a module.    qtssRTPStrPayloadType           = 3,    //r/w       //QTSS_RTPPayloadType   //Payload type of the media on this stream. This will default to qtssUnknownPayloadType unless set explicitly by a module.    qtssRTPStrFirstSeqNumber        = 4,    //r/w       //SInt16            //Sequence number of the first RTP packet generated for this stream after the last PLAY request was issued. If known, this must be set by a module before calling QTSS_Play. It is used by the server to generate a proper RTSP PLAY response.    qtssRTPStrFirstTimestamp        = 5,    //r/w       //SInt32            //RTP timestamp of the first RTP packet generated for this stream after the last PLAY request was issued. If known, this must be set by a module before calling QTSS_Play. It is used by the server to generate a proper RTSP PLAY response.    qtssRTPStrTimescale             = 6,    //r/w       //SInt32            //Timescale for the track. If known, this must be set before calling QTSS_Play.    qtssRTPStrQualityLevel          = 7,    //r/w       //UInt32            //Private    qtssRTPStrNumQualityLevels      = 8,    //r/w       //UInt32            //Private    qtssRTPStrBufferDelayInSecs     = 9,    //r/w       //Float32           //Size of the client's buffer. Server always sets this to 3 seconds, it is up to a module to determine what the buffer size is and set this attribute accordingly.    // All of these parameters come out of the last RTCP packet received on this stream.    // If the corresponding field in the last RTCP packet was blank, the attribute value will be 0.        qtssRTPStrFractionLostPackets   = 10,   //read      //UInt32            // Fraction lost packets so far on this stream.    qtssRTPStrTotalLostPackets      = 11,   //read      //UInt32            // Total lost packets so far on this stream.    qtssRTPStrJitter                = 12,   //read      //UInt32            // Cumulative jitter on this stream.    qtssRTPStrRecvBitRate           = 13,   //read      //UInt32            // Average bit rate received by the client in bits / sec.    qtssRTPStrAvgLateMilliseconds   = 14,   //read      //UInt16            // Average msec packets received late.    qtssRTPStrPercentPacketsLost    = 15,   //read      //UInt16            // Percent packets lost on this stream, as a fixed %.    qtssRTPStrAvgBufDelayInMsec     = 16,   //read      //UInt16            // Average buffer delay in milliseconds    qtssRTPStrGettingBetter         = 17,   //read      //UInt16            // Non-zero if the client is reporting that the stream is getting better.    qtssRTPStrGettingWorse          = 18,   //read      //UInt16            // Non-zero if the client is reporting that the stream is getting worse.    qtssRTPStrNumEyes               = 19,   //read      //UInt32            // Number of clients connected to this stream.    qtssRTPStrNumEyesActive         = 20,   //read      //UInt32            // Number of clients playing this stream.    qtssRTPStrNumEyesPaused         = 21,   //read      //UInt32            // Number of clients connected but currently paused.    qtssRTPStrTotPacketsRecv        = 22,   //read      //UInt32            // Total packets received by the client    qtssRTPStrTotPacketsDropped     = 23,   //read      //UInt16            // Total packets dropped by the client.    qtssRTPStrTotPacketsLost        = 24,   //read      //UInt16            // Total packets lost.    qtssRTPStrClientBufFill         = 25,   //read      //UInt16            // How much the client buffer is filled in 10ths of a second.    qtssRTPStrFrameRate             = 26,   //read      //UInt16            // Current frame rate, in frames per second.    qtssRTPStrExpFrameRate          = 27,   //read      //UInt16            // Expected frame rate, in frames per second.    qtssRTPStrAudioDryCount         = 28,   //read      //UInt16            // Number of times the audio has run dry.    // Address & network related parameters    qtssRTPStrIsTCP                 = 29,   //read      //Bool16            //Is this RTP stream being sent over TCP? If false, it is being sent over UDP.    qtssRTPStrStreamRef             = 30,   //read      //QTSS_StreamRef    //A QTSS_StreamRef used for sending RTP or RTCP packets to the client. Use the QTSS_WriteFlags to specify whether each packet is an RTP or RTCP packet.    qtssRTPStrTransportType         = 31,   //read      //QTSS_RTPTransportType // What kind of transport is being used?        qtssRTPStrStalePacketsDropped   = 32,   //read      //UInt32            // Number of packets dropped by QTSS_Write because they were too old.     qtssRTPStrCurrentAckTimeout     = 33,   //read      //UInt32            // Current ack timeout being advertised to the client in msec (part of reliable udp).        qtssRTPStrCurPacketsLostInRTCPInterval      = 34,   // read     //UInt32            // An RTCP delta count of lost packets equal to qtssRTPStrPercentPacketsLost    qtssRTPStrPacketCountInRTCPInterval = 35,           // read     //UInt32            // An RTCP delta count of packets    qtssRTPStrSvrRTPPort            = 36,   //read      //UInt16            // Port the server is sending RTP packets from for this stream    qtssRTPStrClientRTPPort         = 37,   //read      //UInt16            // Port the server is sending RTP packets to for this stream    qtssRTPStrNetworkMode           = 38,   //read      //QTSS_RTPNetworkMode // unicast or multicast    qtssRTPStrNumParams             = 39};typedef UInt32 QTSS_RTPStreamAttributes;enum{    //QTSS_ClientSessionObject parameters. All of these are preemptive safe        qtssCliSesStreamObjects         = 0,    //read      //QTSS_RTPStreamObject//Iterated attribute. All the QTSS_RTPStreamRefs belonging to this session.    qtssCliSesCreateTimeInMsec      = 1,    //read      //QTSS_TimeVal  //Time in milliseconds the session was created.    qtssCliSesFirstPlayTimeInMsec   = 2,    //read      //QTSS_TimeVal  //Time in milliseconds the first QTSS_Play call was issued.    qtssCliSesPlayTimeInMsec        = 3,    //read      //QTSS_TimeVal  //Time in milliseconds the most recent play was issued.    qtssCliSesAdjustedPlayTimeInMsec= 4,    //read      //QTSS_TimeVal  //Private - do not use    qtssCliSesRTPBytesSent          = 5,    //read      //UInt32        //Number of RTP bytes sent so far on this session.    qtssCliSesRTPPacketsSent        = 6,    //read      //UInt32        //Number of RTP packets sent so far on this session.    qtssCliSesState                 = 7,    //read      //QTSS_RTPSessionState // State of this session: is it paused or playing currently?    qtssCliSesPresentationURL       = 8,    //read      //char array    //Presentation URL for this session. This URL is the "base" URL for the session. RTSP requests to this URL are assumed to affect all streams on the session.    qtssCliSesFirstUserAgent        = 9,    //read      //char array    //Private    qtssCliSesMovieDurationInSecs   = 10,   //r/w       //Float64       //Duration of the movie for this session in seconds. This will default to 0 unless set by a module.    qtssCliSesMovieSizeInBytes      = 11,   //r/w       //UInt64        //Movie size in bytes. This will default to 0 unless explictly set by a module    qtssCliSesMovieAverageBitRate   = 12,   //r/w       //UInt32        //average bits per second based on total RTP bits/movie duration. This will default to 0 unless explictly set by a module.    qtssCliSesLastRTSPSession       = 13,   //read      //QTSS_RTSPSessionObject //Private    qtssCliSesFullURL               = 14,   //read      //char array    //full Presentation URL for this session. Same as qtssCliSesPresentationURL, but includes rtsp://domain.com prefix    qtssCliSesHostName              = 15,   //read      //char array    //requestes host name for s session. Just the "domain.com" portion from qtssCliSesFullURL above    qtssCliRTSPSessRemoteAddrStr    = 16,   //read      //char array        //IP address addr of client, in dotted-decimal format.    qtssCliRTSPSessLocalDNS         = 17,   //read      //char array        //DNS name of local IP address for this RTSP connection.    qtssCliRTSPSessLocalAddrStr     = 18,   //read      //char array        //Ditto, in dotted-decimal format.    qtssCliRTSPSesUserName          = 19,   //read      //char array        // from the most recent (last) request.    qtssCliRTSPSesUserPassword      = 20,   //read      //char array        // from the most recent (last) request.    qtssCliRTSPSesURLRealm          = 21,   //read      //char array        // from the most recent (last) request.        qtssCliRTSPReqRealStatusCode    = 22,   //read      //UInt32            //Same as qtssRTSPReqRTSPReqRealStatusCode, the status from the most recent (last) request.    qtssCliTeardownReason           = 23,   //r/w       //QTSS_CliSesTeardownReason // Must be set by a module that calls QTSS_Teardown if it is not a client requested disconnect.    qtssCliSesReQQueryString        = 24,   //read      //char array    //Query string from the request that creates this  client session    qtssCliRTSPReqRespMsg           = 25,   //read      //char array    // from the most recent (last) request. Error message sent back to client if response was an error.    qtssCliSesCurrentBitRate        = 26,   //read      //UInt32    //Current bit rate of all the streams on this session. This is not an average. In bits per second.    qtssCliSesPacketLossPercent     = 27,   //read      //Float32   //Current percent loss as a fraction. .5 = 50%. This is not an average.    qtssCliSesTimeConnectedInMsec   = 28,   //read      //SInt64    //Time in milliseconds that this client has been connected.    qtssCliSesCounterID             = 29,   //read      //UInt32    //A unique, non-repeating ID for this session.    qtssCliSesRTSPSessionID         = 30,   //read      //char array    //The RTSP session ID that refers to this client session    qtssCliSesFramesSkipped         = 31,   //r/w       //UInt32    //Modules can set this to be the number of frames skipped for this client	qtssCliSesTimeoutMsec			= 32,	//r/w		//UInt32	// client session timeout in milliseconds refreshed by RefreshTimeout API call or any rtcp or rtp packet on the session.	qtssCliSesOverBufferEnabled     = 33,   //read      //Bool16    // client overbuffers using dynamic rate streams    qtssCliSesRTCPPacketsRecv       = 34,   //read      //UInt32    //Number of RTCP packets received so far on this session.    qtssCliSesRTCPBytesRecv         = 35,   //read      //UInt32    //Number of RTCP bytes received so far on this session.    qtssCliSesStartedThinning       = 36,   //read      //Bool16    // At least one of the streams in the session is thinned    qtssCliSesNumParams             = 37    };typedef UInt32 QTSS_ClientSessionAttributes;enum{    //QTSS_RTSPSessionObject parameters        //Valid in any role that receives a QTSS_RTSPSessionObject    qtssRTSPSesID           = 0,        //read      //UInt32        //This is a unique ID for each session since the server started up.    qtssRTSPSesLocalAddr    = 1,        //read      //UInt32        //Local IP address for this RTSP connection    qtssRTSPSesLocalAddrStr = 2,        //read      //char array            //Ditto, in dotted-decimal format.    qtssRTSPSesLocalDNS     = 3,        //read      //char array            //DNS name of local IP address for this RTSP connection.    qtssRTSPSesRemoteAddr   = 4,        //read      //UInt32        //IP address of client.    qtssRTSPSesRemoteAddrStr= 5,        //read      //char array            //IP address addr of client, in dotted-decimal format.    qtssRTSPSesEventCntxt   = 6,        //read      //QTSS_EventContextRef //An event context for the RTSP connection to the client. This should primarily be used to wait for EV_WR events if flow-controlled when responding to a client.     qtssRTSPSesType         = 7,        //read      //QTSS_RTSPSessionType //Is this a normal RTSP session, or is it a HTTP tunnelled RTSP session?    qtssRTSPSesStreamRef    = 8,        //read      //QTSS_RTSPSessionStream    // A QTSS_StreamRef used for sending data to the RTSP client.    qtssRTSPSesLastUserName         = 9,//read      //char array        // Private    qtssRTSPSesLastUserPassword     = 10,//read     //char array        // Private    qtssRTSPSesLastURLRealm         = 11,//read     //char array        // Private        qtssRTSPSesLocalPort    = 12,       //read      //UInt16        // This is the local port for the connection    qtssRTSPSesRemotePort   = 13,       //read      //UInt16        // This is the client port for the connection        qtssRTSPSesNumParams    = 14};typedef UInt32 QTSS_RTSPSessionAttributes;enum {    //All text names are identical to the enumerated type names    //QTSS_RTSPRequestObject parameters. All of these are pre-emptive safe parameters    //Available in every role that receives the QTSS_RTSPRequestObject        qtssRTSPReqFullRequest          = 0,    //read      //char array        //The full request sent by the client        //Available in every method that receives the QTSS_RTSPRequestObject except for the QTSS_FilterMethod        qtssRTSPReqMethodStr            = 1,    //read      //char array        //RTSP Method of this request.    qtssRTSPReqFilePath             = 2,    //r/w		//char array        //Not pre-emptive safe!! //URI for this request, converted to a local file system path.    qtssRTSPReqURI                  = 3,    //read      //char array        //URI for this request    qtssRTSPReqFilePathTrunc        = 4,    //read      //char array        //Not pre-emptive safe!! //Same as qtssRTSPReqFilePath, without the last element of the path    qtssRTSPReqFileName             = 5,    //read      //char array        //Not pre-emptive safe!! //Everything after the last path separator in the file system path    qtssRTSPReqFileDigit            = 6,    //read      //char array        //Not pre-emptive safe!! //If the URI ends with one or more digits, this points to those.    qtssRTSPReqAbsoluteURL          = 7,    //read      //char array        //The full URL, starting from "rtsp://"    qtssRTSPReqTruncAbsoluteURL     = 8,    //read      //char array        //Absolute URL without last element of path    qtssRTSPReqMethod               = 9,    //read      //QTSS_RTSPMethod   //Method as QTSS_RTSPMethod    qtssRTSPReqStatusCode           = 10,   //r/w       //QTSS_RTSPStatusCode   //The current status code for the request as QTSS_RTSPStatusCode. By default, it is always qtssSuccessOK. If a module sets this attribute, and calls QTSS_SendRTSPHeaders, the status code of the header generated by the server will reflect this value.    qtssRTSPReqStartTime            = 11,   //read      //Float64   //Start time specified in Range: header of PLAY request.    qtssRTSPReqStopTime             = 12,   //read      //Float64   //Stop time specified in Range: header of PLAY request.    qtssRTSPReqRespKeepAlive        = 13,   //r/w       //Bool16        //Will (should) the server keep the connection alive. Set this to false if the connection should be terminated after completion of this request.    qtssRTSPReqRootDir              = 14,   //r/w       //char array    //Not pre-emptive safe!! //Root directory to use for this request. The default value for this parameter is the server's media folder path. Modules may set this attribute from the QTSS_RTSPRoute_Role.    qtssRTSPReqRealStatusCode       = 15,   //read      //UInt32    //Same as qtssRTSPReqStatusCode, but translated from QTSS_RTSPStatusCode into an actual RTSP status code.    qtssRTSPReqStreamRef            = 16,   //read      //QTSS_RTSPRequestStream //A QTSS_StreamRef for sending data to the RTSP client. This stream ref, unlike the one provided as an attribute in the QTSS_RTSPSessionObject, will never return EWOULDBLOCK in response to a QTSS_Write or a QTSS_WriteV call.    qtssRTSPReqUserName             = 17,   //read      //char array//decoded Authentication information when provided by the RTSP request. See RTSPSessLastUserName.    qtssRTSPReqUserPassword         = 18,   //read      //char array //decoded Authentication information when provided by the RTSP request. See RTSPSessLastUserPassword.    qtssRTSPReqUserAllowed          = 19,   //r/w       //Bool16    //Default is true, set to false if request is denied. Missing or bad movie files should allow the server to handle the situation and return true.    qtssRTSPReqURLRealm             = 20,   //r/w       //char array //The authorization entity for the client to display "Please enter password for -realm- at server name. The default realm is "Streaming Server".    qtssRTSPReqLocalPath            = 21,   //read      //char array //Not pre-emptive safe!! //The full local path to the file. This Attribute is first set after the Routing Role has run and before any other role is called.         qtssRTSPReqIfModSinceDate       = 22,   //read      //QTSS_TimeVal  // If the RTSP request contains an If-Modified-Since header, this is the if-modified date, converted to a QTSS_TimeVal    qtssRTSPReqQueryString          = 23,   //read      //char array  // query stting (CGI parameters) passed to the server in the request URL, does not include the '?' separator    qtssRTSPReqRespMsg              = 24,   //r/w       //char array        // A module sending an RTSP error to the client should set this to be a text message describing why the error occurred. This description is useful to add to log files. Once the RTSP response has been sent, this attribute contains the response message.    qtssRTSPReqContentLen           = 25,   //read      //UInt32            // Content length of incoming RTSP request body    qtssRTSPReqSpeed                = 26,   //read      //Float32           // Value of Speed header, converted to a Float32.    qtssRTSPReqLateTolerance        = 27,   //read      //Float32           // Value of the late-tolerance field of the x-RTP-Options header, or -1 if not present.     qtssRTSPReqTransportType        = 28,   //read      //QTSS_RTPTransportType // What kind of transport?      qtssRTSPReqTransportMode        = 29,   //read      //QTSS_RTPTransportMode // A setup request from the client. * maybe should just be an enum or the text of the mode value?       qtssRTSPReqSetUpServerPort      = 30,   //r/w       //UInt16            // the ServerPort to respond to a client SETUP request with.        qtssRTSPReqAction               = 31,   //r/w       //QTSS_ActionFlags  //Set by a module in the QTSS_RTSPSetAction_Role - for now, the server will set it as the role hasn't been added yet    qtssRTSPReqUserProfile          = 32,   //r/w       //QTSS_UserProfileObject    //Object's username is filled in by the server and its password and group memberships filled in by the authentication module.           qtssRTSPReqPrebufferMaxTime     = 33,   //read      //Float32           //The maxtime field of the x-Prebuffer RTSP header    qtssRTSPReqAuthScheme           = 34,   //read      //QTSS_AuthScheme        qtssRTSPReqSkipAuthorization    = 35,   //r/w       //Bool16            // Set by a module that wants the particular request to be                                                                            // allowed by all authorization modules    qtssRTSPReqNetworkMode          = 36,   //read      //QTSS_RTPNetworkMode // unicast or multicast	qtssRTSPReqDynamicRateState     = 37,   //read      //SInt32            // -1 not in request, 0 off, 1 on	qtssRTSPReqNumParams 			= 38    };typedef UInt32 QTSS_RTSPRequestAttributes;enum{    //QTSS_ServerObject parameters        // These parameters ARE pre-emptive safe.        qtssServerAPIVersion            = 0,    //read  //UInt32            //The API version supported by this server (format 0xMMMMmmmm, where M=major version, m=minor version)    qtssSvrDefaultDNSName           = 1,    //read  //char array        //The "default" DNS name of the server    qtssSvrDefaultIPAddr            = 2,    //read  //UInt32            //The "default" IP address of the server    qtssSvrServerName               = 3,    //read  //char array        //Name of the server    qtssSvrServerVersion            = 4,    //read  //char array        //Version of the server    qtssSvrServerBuildDate          = 5,    //read  //char array        //When was the server built?    qtssSvrRTSPPorts                = 6,    //read  // NOT PREEMPTIVE SAFE!//UInt16         //Indexed parameter: all the ports the server is listening on    qtssSvrRTSPServerHeader         = 7,    //read  //char array        //Server: header that the server uses to respond to RTSP clients    // These parameters are NOT pre-emptive safe, they cannot be accessed    // via. QTSS_GetValuePtr. Some exceptions noted below        qtssSvrState                    = 8,    //r/w   //QTSS_ServerState  //The current state of the server. If a module sets the server state, the server will respond in the appropriate fashion. Setting to qtssRefusingConnectionsState causes the server to refuse connections, setting to qtssFatalErrorState or qtssShuttingDownState causes the server to quit.    qtssSvrIsOutOfDescriptors       = 9,    //read  //Bool16            //true if the server has run out of file descriptors, false otherwise    qtssRTSPCurrentSessionCount     = 10,   //read  //UInt32            //Current number of connected clients over standard RTSP    qtssRTSPHTTPCurrentSessionCount = 11,   //read  //UInt32            //Current number of connected clients over RTSP / HTTP    qtssRTPSvrNumUDPSockets         = 12,   //read      //UInt32    //Number of UDP sockets currently being used by the server    qtssRTPSvrCurConn               = 13,   //read      //UInt32    //Number of clients currently connected to the server    qtssRTPSvrTotalConn             = 14,   //read      //UInt32    //Total number of clients since startup    qtssRTPSvrCurBandwidth          = 15,   //read      //UInt32    //Current bandwidth being output by the server in bits per second    qtssRTPSvrTotalBytes            = 16,   //read      //UInt64    //Total number of bytes served since startup    qtssRTPSvrAvgBandwidth          = 17,   //read      //UInt32    //Average bandwidth being output by the server in bits per second    qtssRTPSvrCurPackets            = 18,   //read      //UInt32    //Current packets per second being output by the server    qtssRTPSvrTotalPackets          = 19,   //read      //UInt64    //Total number of bytes served since startup        qtssSvrHandledMethods           = 20,   //r/w       //QTSS_RTSPMethod   //The methods that the server supports. Modules should append the methods they support to this attribute in their QTSS_Initialize_Role.    qtssSvrModuleObjects            = 21,   //read  // this IS PREMPTIVE SAFE!  //QTSS_ModuleObject // A module object representing each module    qtssSvrStartupTime              = 22,   //read      //QTSS_TimeVal  //Time the server started up    qtssSvrGMTOffsetInHrs           = 23,   //read      //SInt32        //Server time zone (offset from GMT in hours)    qtssSvrDefaultIPAddrStr         = 24,   //read      //char array    //The "default" IP address of the server as a string    qtssSvrPreferences              = 25,   //read      //QTSS_PrefsObject  // An object representing each the server's preferences    qtssSvrMessages                 = 26,   //read      //QTSS_Object   // An object containing the server's error messages.    qtssSvrClientSessions           = 27,   //read      //QTSS_Object // An object containing all client sessions stored as indexed QTSS_ClientSessionObject(s).    qtssSvrCurrentTimeMilliseconds  = 28,   //read      //QTSS_TimeVal  //Server's current time in milliseconds. Retrieving this attribute is equivalent to calling QTSS_Milliseconds    qtssSvrCPULoadPercent           = 29,   //read      //Float32       //Current % CPU being used by the server    qtssSvrNumReliableUDPBuffers    = 30,   //read      //UInt32    //Number of buffers currently allocated for UDP retransmits    qtssSvrReliableUDPWastageInBytes= 31,   //read      //UInt32    //Amount of data in the reliable UDP buffers being wasted    qtssSvrConnectedUsers           = 32,   //r/w       //QTSS_Object   //List of connected user sessions (updated by modules for their sessions)        qtssMP3SvrCurConn               = 33,   //r/w       //UInt32    //Number of MP3 client sessions connected    qtssMP3SvrTotalConn             = 34,   //r/w       //UInt32    //Total number of MP3  clients since startup    qtssMP3SvrCurBandwidth          = 35,   //r/w       //UInt32    //Current MP3 bandwidth being output by the server in bits per second    qtssMP3SvrTotalBytes            = 36,   //r/w       //UInt64    //Total number of MP3 bytes served since startup    qtssMP3SvrAvgBandwidth          = 37,   //r/w       //UInt32    //Average MP3 bandwidth being output by the server in bits per second    qtssSvrServerBuild              = 38,   //read      //char array //build of the server    qtssSvrServerPlatform           = 39,   //read      //char array //Platform (OS) of the server    qtssSvrRTSPServerComment        = 40,   //read      //char array //RTSP comment for the server header        qtssSvrNumThinned               = 41,    //r/w      //SInt32    //Number of thinned sessions    qtssSvrNumParams                = 42};typedef UInt32 QTSS_ServerAttributes;enum{    //QTSS_PrefsObject parameters    // Valid in all methods. None of these are pre-emptive safe, so the version    // of QTSS_GetAttribute that copies data must be used.        // All of these parameters are read-write.         qtssPrefsRTSPTimeout            = 0,    //"rtsp_timeout"                //UInt32    //RTSP timeout in seconds sent to the client.    qtssPrefsRealRTSPTimeout        = 1,    //"real_rtsp_timeout"           //UInt32    //Amount of time in seconds the server will wait before disconnecting idle RTSP clients. 0 means no timeout    qtssPrefsRTPTimeout             = 2,    //"rtp_timeout"                 //UInt32    //Amount of time in seconds the server will wait before disconnecting idle RTP clients. 0 means no timeout    qtssPrefsMaximumConnections     = 3,    //"maximum_connections"         //SInt32    //Maximum # of concurrent RTP connections allowed by the server. -1 means unlimited.    qtssPrefsMaximumBandwidth       = 4,    //"maximum_bandwidth"           //SInt32    //Maximum amt of bandwidth the server is allowed to serve in K bits. -1 means unlimited.    qtssPrefsMovieFolder            = 5,    //"movie_folder"                //char array    //Path to the root movie folder    qtssPrefsRTSPIPAddr             = 6,    //"bind_ip_addr"                //char array    //IP address the server should accept RTSP connections on. 0.0.0.0 means all addresses on the machine.    qtssPrefsBreakOnAssert          = 7,    //"break_on_assert"             //Bool16        //If true, the server will break in the debugger when an assert fails.    qtssPrefsAutoRestart            = 8,    //"auto_restart"                //Bool16        //If true, the server will automatically restart itself if it crashes.    qtssPrefsTotalBytesUpdate       = 9,    //"total_bytes_update"          //UInt32    //Interval in seconds between updates of the server's total bytes and current bandwidth statistics    qtssPrefsAvgBandwidthUpdate     = 10,   //"average_bandwidth_update"    //UInt32    //Interval in seconds between computations of the server's average bandwidth    qtssPrefsSafePlayDuration       = 11,   //"safe_play_duration"          //UInt32    //Hard to explain... see streamingserver.conf    qtssPrefsModuleFolder           = 12,   //"module_folder"               //char array    //Path to the module folder    // There is a compiled-in error log module that loads before all the other modules    // (so it can log errors from the get-go). It uses these prefs.        qtssPrefsErrorLogName           = 13,   //"error_logfile_name"          //char array        //Name of error log file    qtssPrefsErrorLogDir            = 14,   //"error_logfile_dir"           //char array        //Path to error log file directory    qtssPrefsErrorRollInterval      = 15,   //"error_logfile_interval"      //UInt32    //Interval in days between error logfile rolls    qtssPrefsMaxErrorLogSize        = 16,   //"error_logfile_size"          //UInt32    //Max size in bytes of the error log    qtssPrefsErrorLogVerbosity      = 17,   //"error_logfile_verbosity"     //UInt32    //Max verbosity level of messages the error logger will log    qtssPrefsScreenLogging          = 18,   //"screen_logging"              //Bool16        //Should the error logger echo messages to the screen?    qtssPrefsErrorLogEnabled        = 19,   //"error_logging"               //Bool16        //Is error logging enabled?    qtssPrefsDropVideoAllPacketsDelayInMsec = 20,   //"drop_all_video_delay"    //SInt32 // Don't send video packets later than this    qtssPrefsStartThinningDelayInMsec       = 21,   //"start_thinning_delay"    //SInt32 // lateness at which we might start thinning    qtssPrefsLargeWindowSizeInK             = 22,   //"large_window_size"  // UInt32    //default size that will be used for high bitrate movies    qtssPrefsWindowSizeThreshold            = 23,   //"window_size_threshold"  // UInt32    //bitrate at which we switch to larger window size        qtssPrefsMinTCPBufferSizeInBytes        = 24,   //"min_tcp_buffer_size" //UInt32    // When streaming over TCP, this is the minimum size the TCP socket send buffer can be set to    qtssPrefsMaxTCPBufferSizeInBytes        = 25,   //"max_tcp_buffer_size" //UInt32    // When streaming over TCP, this is the maximum size the TCP socket send buffer can be set to    qtssPrefsTCPSecondsToBuffer             = 26,   //"tcp_seconds_to_buffer" //Float32 // When streaming over TCP, the size of the TCP send buffer is scaled based on the bitrate of the movie. It will fit all the data that gets sent in this amount of time.        qtssPrefsDoReportHTTPConnectionAddress  = 27,   //"do_report_http_connection_ip_address"    //Bool16    // when behind a round robin DNS, the client needs to be told the specific ip address of the maching handling its request. this pref tells the server to repot its IP address in the reply to the HTTP GET request when tunneling RTSP through HTTP    qtssPrefsDefaultAuthorizationRealm      = 28,   // "default_authorization_realm" //char array   //        qtssPrefsRunUserName                    = 29,   //"run_user_name"       //char array        //Run under this user's account    qtssPrefsRunGroupName                   = 30,   //"run_group_name"      //char array        //Run under this group's account        qtssPrefsSrcAddrInTransport             = 31,   //"append_source_addr_in_transport" // Bool16   //If true, the server will append the src address to the Transport header responses    qtssPrefsRTSPPorts                      = 32,   //"rtsp_ports"          // UInt16       qtssPrefsMaxRetransDelayInMsec          = 33,   //"max_retransmit_delay" // UInt32  //maximum interval between when a retransmit is supposed to be sent and when it actually gets sent. Lower values means smoother flow but slower server performance    qtssPrefsSmallWindowSizeInK             = 34,   //"small_window_size"  // UInt32    //default size that will be used for low bitrate movies    qtssPrefsAckLoggingEnabled              = 35,   //"ack_logging_enabled"  // Bool16  //Debugging only: turns on detailed logging of UDP acks / retransmits    qtssPrefsRTCPPollIntervalInMsec         = 36,   //"rtcp_poll_interval"      // UInt32   //interval (in Msec) between poll for RTCP packets    qtssPrefsRTCPSockRcvBufSizeInK          = 37,   //"rtcp_rcv_buf_size"   // UInt32   //Size of the receive socket buffer for udp sockets used to receive rtcp packets    qtssPrefsSendInterval                   = 38,   //"send_interval"  // UInt32    //    qtssPrefsThickAllTheWayDelayInMsec      = 39,   //"thick_all_the_way_delay"     // UInt32   //    qtssPrefsAltTransportIPAddr             = 40,   //"alt_transport_src_ipaddr"// char     //If empty, the server uses its own IP addr in the source= param of the transport header. Otherwise, it uses this addr.    qtssPrefsMaxAdvanceSendTimeInSec        = 41,   //"max_send_ahead_time"     // UInt32   //This is the farthest in advance the server will send a packet to a client that supports overbuffering.    qtssPrefsReliableUDPSlowStart           = 42,   //"reliable_udp_slow_start" // Bool16   //Is reliable UDP slow start enabled?    qtssPrefsAutoDeleteSDPFiles             = 43,   //"auto_delete_sdp_files"   // Bool16   //SDP files in the Movies directory tree are deleted after a Broadcaster's RTSP controlled SDP session ends.     qtssPrefsAuthenticationScheme           = 44,   //"authentication_scheme" // char   //Set this to be the authentication scheme you want the server to use. "basic", "digest", and "none" are the currently supported values    qtssPrefsDeleteSDPFilesInterval         = 45,   //"sdp_file_delete_interval_seconds" //UInt32 //Feature rem    qtssPrefsAutoStart                      = 46,   //"auto_start" //Bool16 //If true, streaming server likes to be started at system startup    qtssPrefsReliableUDP                    = 47,   //"reliable_udp" //Bool16 //If true, uses reliable udp transport if requested by the client    qtssPrefsReliableUDPDirs                = 48,   //"reliable_udp_dirs" //CharArray    qtssPrefsReliableUDPPrintfs             = 49,   //"reliable_udp_printfs" //Bool16 //If enabled, server prints out interesting statistics for the reliable UDP clients        qtssPrefsDropAllPacketsDelayInMsec      = 50,   //"drop_all_packets_delay" // SInt32    // don't send any packets later than this    qtssPrefsThinAllTheWayDelayInMsec       = 51,   //"thin_all_the_way_delay" // SInt32    // thin to key frames    qtssPrefsAlwaysThinDelayInMsec          = 52,   //"always_thin_delay" // SInt32         // we always start to thin at this point    qtssPrefsStartThickingDelayInMsec       = 53,   //"start_thicking_delay" // SInt32      // maybe start thicking at this point    qtssPrefsQualityCheckIntervalInMsec     = 54,   //"quality_check_interval" // UInt32    // adjust thinnning params this often       qtssPrefsEnableRTSPErrorMessage         = 55,   //"RTSP_error_message" //Bool16 // Appends a content body string error message for reported RTSP errors.    qtssPrefsEnableRTSPDebugPrintfs         = 56,   //"RTSP_debug_printfs" //Boo1l6 // printfs incoming RTSPRequests and Outgoing RTSP responses.    qtssPrefsEnableMonitorStatsFile         = 57,   //"enable_monitor_stats_file" //Bool16 //write server stats to the monitor file    qtssPrefsMonitorStatsFileIntervalSec    = 58,   //"monitor_stats_file_interval_seconds" // private    qtssPrefsMonitorStatsFileName           = 59,   //"monitor_stats_file_name" // private    qtssPrefsEnablePacketHeaderPrintfs      = 60,   // "enable_packet_header_printfs" //Bool16 // RTP and RTCP printfs of outgoing packets.    qtssPrefsPacketHeaderPrintfOptions      = 61,   // "packet_header_printf_options" //char //set of printfs to print. Form is [text option] [;]  default is "rtp;rr;sr;". This means rtp packets, rtcp sender reports, and rtcp receiver reports.	qtssPrefsOverbufferRate					= 62,	// "overbuffer_rate"	//Float32	qtssPrefsMediumWindowSizeInK			= 63,	// "medium_window_size" // UInt32	//default size that will be used for medium bitrate movies	qtssPrefsWindowSizeMaxThreshold			= 64,	//"window_size_threshold"  // UInt32	//bitrate at which we switch from medium to large window size    qtssPrefsEnableRTSPServerInfo           = 65,   //"RTSP_server_info" //Boo1l6 // Adds server info to the RTSP responses.    qtssPrefsRunNumThreads                  = 66,   //"run_num_threads" //UInt32 // if value is non-zero, will  create that many threads; otherwise a thread will be created for each processor	qtssPrefsPidFile						= 67,	//"pid_file" //Char Array //path to pid file    qtssPrefsCloseLogsOnWrite               = 68,   // "force_logs_close_on_write" //Bool16 // force log files to close after each write.    qtssPrefsDisableThinning                = 69,   // "disable_thinning" //Bool16 // Usually used for performance testing. Turn off stream thinning from packet loss or stream lateness.    qtssPrefsPlayersReqRTPHeader            = 70,   // "player_requires_rtp_header_info" //Char array //name of player to match against the player's user agent header    qtssPrefsPlayersReqBandAdjust           = 71,   // "player_requires_bandwidth_adjustment //Char array //name of player to match against the player's user agent header    qtssPrefsPlayersReqNoPauseTimeAdjust    = 72,   // "player_requires_no_pause_time_adjustment //Char array //name of player to match against the player's user agent header    qtssPrefsNumParams                      = 73};typedef UInt32 QTSS_PrefsAttributes;enum{    //QTSS_TextMessagesObject parameters        // All of these parameters are read-only, char*'s, and preemptive-safe.        qtssMsgNoMessage                = 0,    //"NoMessage"    qtssMsgNoURLInRequest           = 1,    qtssMsgBadRTSPMethod            = 2,    qtssMsgNoRTSPVersion            = 3,    qtssMsgNoRTSPInURL              = 4,    qtssMsgURLTooLong               = 5,    qtssMsgURLInBadFormat           = 6,    qtssMsgNoColonAfterHeader       = 7,    qtssMsgNoEOLAfterHeader         = 8,    qtssMsgRequestTooLong           = 9,    qtssMsgNoModuleFolder           = 10,    qtssMsgCouldntListen            = 11,    qtssMsgInitFailed               = 12,    qtssMsgNotConfiguredForIP       = 13,    qtssMsgDefaultRTSPAddrUnavail   = 14,    qtssMsgBadModule                = 15,    qtssMsgRegFailed                = 16,    qtssMsgRefusingConnections      = 17,    qtssMsgTooManyClients           = 18,    qtssMsgTooMuchThruput           = 19,    qtssMsgNoSessionID              = 20,    qtssMsgFileNameTooLong          = 21,    qtssMsgNoClientPortInTransport  = 22,    qtssMsgRTPPortMustBeEven        = 23,    qtssMsgRTCPPortMustBeOneBigger  = 24,    qtssMsgOutOfPorts               = 25,    qtssMsgNoModuleForRequest       = 26,    qtssMsgAltDestNotAllowed        = 27,    qtssMsgCantSetupMulticast       = 28,    qtssListenPortInUse             = 29,    qtssListenPortAccessDenied      = 30,    qtssListenPortError             = 31,    qtssMsgBadBase64                = 32,    qtssMsgSomePortsFailed          = 33,    qtssMsgNoPortsSucceeded         = 34,    qtssMsgCannotCreatePidFile      = 35,    qtssMsgCannotSetRunUser         = 36,    qtssMsgCannotSetRunGroup        = 37,    qtssMsgNoSesIDOnDescribe        = 38,    qtssServerPrefMissing           = 39,    qtssServerPrefWrongType         = 40,    qtssMsgCantWriteFile            = 41,    qtssMsgSockBufSizesTooLarge     = 42,    qtssMsgBadFormat                = 43,    qtssMsgNumParams                = 44    };typedef UInt32 QTSS_TextMessagesAttributes;enum{    //QTSS_FileObject parameters        // All of these parameters are preemptive-safe.        qtssFlObjStream                 = 0,    // read // QTSS_FileStream. Stream ref for this file object    qtssFlObjFileSysModuleName      = 1,    // read // char array. Name of the file system module handling this file object    qtssFlObjLength                 = 2,    // r/w  // UInt64. Length of the file    qtssFlObjPosition               = 3,    // read // UInt64. Current position of the file pointer in the file.    qtssFlObjModDate                = 4,    // r/w  // QTSS_TimeVal. Date & time of last modification    qtssFlObjNumParams              = 5};typedef UInt32 QTSS_FileObjectAttributes;enum{    //QTSS_ModuleObject parameters        qtssModName                 = 0,    //read      //preemptive-safe       //char array        //Module name.     qtssModDesc                 = 1,    //r/w       //not preemptive-safe   //char array        //Text description of what the module does    qtssModVersion              = 2,    //r/w       //not preemptive-safe   //UInt32            //Version of the module. UInt32 format should be 0xMM.m.v.bbbb M=major version m=minor version v=very minor version b=build #    qtssModRoles                = 3,    //read      //preemptive-safe       //QTSS_Role         //List of all the roles this module has registered for.    qtssModPrefs                = 4,    //read      //preemptive-safe       //QTSS_ModulePrefsObject //An object containing as attributes the preferences for this module        qtssModAttributes           = 5,    //read      //preemptive-safe       //QTSS_Object                qtssModNumParams            = 6};typedef UInt32 QTSS_ModuleObjectAttributes;enum{    //QTSS_AttrInfoObject parameters        // All of these parameters are preemptive-safe.    qtssAttrName                    = 0,    //read //char array             //Attribute name    qtssAttrID                      = 1,    //read //QTSS_AttributeID       //Attribute ID    qtssAttrDataType                = 2,    //read //QTSS_AttrDataType      //Data type    qtssAttrPermissions             = 3,    //read //QTSS_AttrPermission    //Permissions    qtssAttrInfoNumParams           = 4};typedef UInt32 QTSS_AttrInfoObjectAttributes;enum{    //QTSS_UserProfileObject parameters        // All of these parameters are preemptive-safe.        qtssUserName        = 0,    //read  //char array    qtssUserPassword    = 1,    //r/w   //char array    qtssUserGroups      = 2,    //r/w   //char array -  multi-valued attribute, all values should be C strings padded with /0s to                                         //              make them all of the same length     qtssUserRealm       = 3,    //r/w   //char array -  the authentication realm for username        qtssUserNumParams   = 4};typedef UInt32 QTSS_UserProfileObjectAttributes;enum{    //QTSS_ConnectedUserObject parameters        //All of these are preemptive safe        qtssConnectionType                  = 0,    //read      //char array    // type of user connection (e.g. "RTP reflected" or "MP3")    qtssConnectionCreateTimeInMsec      = 1,    //read      //QTSS_TimeVal  //Time in milliseconds the session was created.    qtssConnectionTimeConnectedInMsec   = 2,    //read      //QTSS_TimeVal  //Time in milliseconds the session was created.    qtssConnectionBytesSent             = 3,    //read      //UInt32        //Number of RTP bytes sent so far on this session.    qtssConnectionMountPoint            = 4,    //read      //char array    //Presentation URL for this session. This URL is the "base" URL for the session. RTSP requests to this URL are assumed to affect all streams on the session.    qtssConnectionHostName              = 5,    //read      //char array    //host name for this request    qtssConnectionSessRemoteAddrStr     = 6,    //read      //char array        //IP address addr of client, in dotted-decimal format.    qtssConnectionSessLocalAddrStr      = 7,    //read      //char array        //Ditto, in dotted-decimal format.    qtssConnectionCurrentBitRate        = 8,    //read          //UInt32    //Current bit rate of all the streams on this session. This is not an average. In bits per second.    qtssConnectionPacketLossPercent     = 9,    //read          //Float32   //Current percent loss as a fraction. .5 = 50%. This is not an average.    qtssConnectionTimeStorage           = 10,   //read          //QTSS_TimeVal  //Internal, use qtssConnectionTimeConnectedInMsec above    qtssConnectionNumParams             = 11};typedef UInt32 QTSS_ConnectedUserObjectAttributes;/********************************************************************/// QTSS API ROLES//// Each role represents a unique situation in which a module may be// invoked. Modules must specify which roles they want to be invoked for. enum{    //Global    QTSS_Register_Role =             FOUR_CHARS_TO_INT('r', 'e', 'g', ' '), //reg  //All modules get this once at startup    QTSS_Initialize_Role =           FOUR_CHARS_TO_INT('i', 'n', 'i', 't'), //init //Gets called once, later on in the startup process    QTSS_Shutdown_Role =             FOUR_CHARS_TO_INT('s', 'h', 'u', 't'), //shut //Gets called once at shutdown        QTSS_ErrorLog_Role =             FOUR_CHARS_TO_INT('e', 'l', 'o', 'g'), //elog //This gets called when the server wants to log an error.    QTSS_RereadPrefs_Role =          FOUR_CHARS_TO_INT('p', 'r', 'e', 'f'), //pref //This gets called when the server rereads preferences.    QTSS_StateChange_Role =          FOUR_CHARS_TO_INT('s', 't', 'a', 't'), //stat //This gets called whenever the server changes state.        QTSS_Interval_Role =             FOUR_CHARS_TO_INT('t', 'i', 'm', 'r'), //timr //This gets called whenever the module's interval timer times out calls.        //RTSP-specific    QTSS_RTSPFilter_Role =           FOUR_CHARS_TO_INT('f', 'i', 'l', 't'), //filt //Filter all RTSP requests before the server parses them    QTSS_RTSPRoute_Role =            FOUR_CHARS_TO_INT('r', 'o', 'u', 't'), //rout //Route all RTSP requests to the correct root folder.    QTSS_RTSPAuthenticate_Role =     FOUR_CHARS_TO_INT('a', 't', 'h', 'n'), //athn //Authenticate the RTSP request username.    QTSS_RTSPAuthorize_Role =        FOUR_CHARS_TO_INT('a', 'u', 't', 'h'), //auth //Authorize RTSP requests to proceed    QTSS_RTSPPreProcessor_Role =     FOUR_CHARS_TO_INT('p', 'r', 'e', 'p'), //prep //Pre-process all RTSP requests before the server responds.                                        //Modules may opt to "steal" the request and return a client response.    QTSS_RTSPRequest_Role =          FOUR_CHARS_TO_INT('r', 'e', 'q', 'u'), //requ //Process an RTSP request & send client response    QTSS_RTSPPostProcessor_Role =    FOUR_CHARS_TO_INT('p', 'o', 's', 't'), //post //Post-process all RTSP requests    QTSS_RTSPSessionClosing_Role =   FOUR_CHARS_TO_INT('s', 'e', 's', 'c'), //sesc //RTSP session is going away    QTSS_RTSPIncomingData_Role =     FOUR_CHARS_TO_INT('i', 'c', 'm', 'd'), //icmd //Incoming interleaved RTP data on this RTSP connection    //RTP-specific    QTSS_RTPSendPackets_Role =           FOUR_CHARS_TO_INT('s', 'e', 'n', 'd'), //send //Send RTP packets to the client    QTSS_ClientSessionClosing_Role =     FOUR_CHARS_TO_INT('d', 'e', 's', 's'), //dess //Client session is going away        //RTCP-specific    QTSS_RTCPProcess_Role =          FOUR_CHARS_TO_INT('r', 't', 'c', 'p'), //rtcp //Process all RTCP packets sent to the server    //File system roles    QTSS_OpenFilePreProcess_Role =  FOUR_CHARS_TO_INT('o', 'p', 'p', 'r'),  //oppr    QTSS_OpenFile_Role =            FOUR_CHARS_TO_INT('o', 'p', 'f', 'l'),  //opfl    QTSS_AdviseFile_Role =          FOUR_CHARS_TO_INT('a', 'd', 'f', 'l'),  //adfl    QTSS_ReadFile_Role =            FOUR_CHARS_TO_INT('r', 'd', 'f', 'l'),  //rdfl    QTSS_CloseFile_Role =           FOUR_CHARS_TO_INT('c', 'l', 'f', 'l'),  //clfl    QTSS_RequestEventFile_Role =    FOUR_CHARS_TO_INT('r', 'e', 'f', 'l'),  //refl    };typedef UInt32 QTSS_Role;//***********************************************/// TYPEDEFStypedef void*           QTSS_StreamRef;typedef void*           QTSS_Object;typedef void*           QTSS_ServiceFunctionArgsPtr;typedef SInt32          QTSS_AttributeID;typedef SInt32          QTSS_ServiceID;typedef SInt64          QTSS_TimeVal;typedef QTSS_Object             QTSS_RTPStreamObject;typedef QTSS_Object             QTSS_RTSPSessionObject;typedef QTSS_Object             QTSS_RTSPRequestObject;typedef QTSS_Object             QTSS_RTSPHeaderObject;typedef QTSS_Object             QTSS_ClientSessionObject;typedef QTSS_Object             QTSS_ServerObject;typedef QTSS_Object             QTSS_PrefsObject;typedef QTSS_Object             QTSS_TextMessagesObject;typedef QTSS_Object             QTSS_FileObject;typedef QTSS_Object             QTSS_ModuleObject;typedef QTSS_Object             QTSS_ModulePrefsObject;typedef QTSS_Object             QTSS_AttrInfoObject;typedef QTSS_Object             QTSS_UserProfileObject;typedef QTSS_Object             QTSS_ConnectedUserObject;typedef QTSS_StreamRef          QTSS_ErrorLogStream;typedef QTSS_StreamRef          QTSS_FileStream;typedef QTSS_StreamRef          QTSS_RTSPSessionStream;typedef QTSS_StreamRef          QTSS_RTSPRequestStream;typedef QTSS_StreamRef          QTSS_RTPStreamStream;typedef QTSS_StreamRef          QTSS_SocketStream;typedef QTSS_RTSPStatusCode QTSS_SessionStatusCode;//***********************************************/// ROLE PARAMETER BLOCKS//// Each role has a unique set of parameters that get passed// to the module.typedef struct{    char outModuleName[QTSS_MAX_MODULE_NAME_LENGTH];} QTSS_Register_Params;typedef struct{    QTSS_ServerObject           inServer;           // Global dictionaries    QTSS_PrefsObject            inPrefs;    QTSS_TextMessagesObject     inMessages;    QTSS_ErrorLogStream         inErrorLogStream;   // Writing to this stream causes modules to                                                    // be invoked in the QTSS_ErrorLog_Role    QTSS_ModuleObject           inModule;} QTSS_Initialize_Params;typedef struct{    QTSS_ErrorVerbosity         inVerbosity;    char*                       inBuffer;    } QTSS_ErrorLog_Params;typedef struct{    QTSS_ServerState            inNewState;} QTSS_StateChange_Params;typedef struct {    QTSS_RTSPSessionObject      inRTSPSession;    QTSS_RTSPRequestObject      inRTSPRequest;    QTSS_RTSPHeaderObject       inRTSPHeaders;    QTSS_ClientSessionObject    inClientSession;} QTSS_StandardRTSP_Params;typedef struct {    QTSS_RTSPSessionObject      inRTSPSession;    QTSS_RTSPRequestObject      inRTSPRequest;    char**                      outNewRequest;} QTSS_Filter_Params;typedef struct{    QTSS_RTSPRequestObject      inRTSPRequest;} QTSS_RTSPAuth_Params;typedef struct {    QTSS_RTSPSessionObject      inRTSPSession;    QTSS_ClientSessionObject    inClientSession;    char*                       inPacketData;    UInt32                      inPacketLen;} QTSS_IncomingData_Params;typedef struct{    QTSS_RTSPSessionObject      inRTSPSession;} QTSS_RTSPSession_Params;typedef struct{    QTSS_ClientSessionObject        inClientSession;    QTSS_TimeVal                    inCurrentTime;    QTSS_TimeVal                    outNextPacketTime;} QTSS_RTPSendPackets_Params;typedef struct{    QTSS_ClientSessionObject        inClientSession;    QTSS_CliSesClosingReason        inReason;} QTSS_ClientSessionClosing_Params;typedef struct{    QTSS_ClientSessionObject    inClientSession;    QTSS_RTPStreamObject        inRTPStream;    void*                       inRTCPPacketData;    UInt32                      inRTCPPacketDataLen;} QTSS_RTCPProcess_Params;typedef struct{    char*                       inPath;    QTSS_OpenFileFlags          inFlags;    QTSS_Object                 inFileObject;} QTSS_OpenFile_Params;typedef struct{    QTSS_Object                 inFileObject;    UInt64                      inPosition;    UInt32                      inSize;} QTSS_AdviseFile_Params;typedef struct{    QTSS_Object                 inFileObject;    UInt64                      inFilePosition;    void*                       ioBuffer;    UInt32                      inBufLen;    UInt32*                     outLenRead;} QTSS_ReadFile_Params;typedef struct{    QTSS_Object                 inFileObject;} QTSS_CloseFile_Params;typedef struct{    QTSS_Object                 inFileObject;    QTSS_EventType              inEventMask;} QTSS_RequestEventFile_Params;typedef union{    QTSS_Register_Params                regParams;    QTSS_Initialize_Params              initParams;    QTSS_ErrorLog_Params                errorParams;    QTSS_StateChange_Params             stateChangeParams;    QTSS_Filter_Params                  rtspFilterParams;    QTSS_IncomingData_Params            rtspIncomingDataParams;    QTSS_StandardRTSP_Params            rtspRouteParams;    QTSS_RTSPAuth_Params                rtspAthnParams;    QTSS_StandardRTSP_Params            rtspAuthParams;    QTSS_StandardRTSP_Params            rtspPreProcessorParams;    QTSS_StandardRTSP_Params            rtspRequestParams;    QTSS_StandardRTSP_Params            rtspPostProcessorParams;    QTSS_RTSPSession_Params             rtspSessionClosingParams;    QTSS_RTPSendPackets_Params          rtpSendPacketsParams;    QTSS_ClientSessionClosing_Params    clientSessionClosingParams;    QTSS_RTCPProcess_Params             rtcpProcessParams;        QTSS_OpenFile_Params                openFilePreProcessParams;    QTSS_OpenFile_Params                openFileParams;    QTSS_AdviseFile_Params              adviseFileParams;    QTSS_ReadFile_Params                readFileParams;    QTSS_CloseFile_Params               closeFileParams;    QTSS_RequestEventFile_Params        reqEventFileParams;    } QTSS_RoleParams, *QTSS_RoleParamPtr;typedef struct{    void*                           packetData;    QTSS_TimeVal                    packetTransmitTime;    QTSS_TimeVal                    suggestedWakeupTime;} QTSS_PacketStruct;/********************************************************************/// ENTRYPOINTS & FUNCTION TYPEDEFS// MAIN ENTRYPOINT FOR MODULES//// Every QTSS API must implement two functions: a main entrypoint, and a dispatch// function. The main entrypoint gets called by the server at startup to do some// initialization. Your main entrypoint must follow the convention established below//// QTSS_Error mymodule_main(void* inPrivateArgs)// {//      return _stublibrary_main(inPrivateArgs, MyDispatchFunction);// }////typedef QTSS_Error (*QTSS_MainEntryPointPtr)(void* inPrivateArgs);typedef QTSS_Error (*QTSS_DispatchFuncPtr)(QTSS_Role inRole, QTSS_RoleParamPtr inParamBlock);// STUB LIBRARY MAINQTSS_Error _stublibrary_main(void* inPrivateArgs, QTSS_DispatchFuncPtr inDispatchFunc);/********************************************************************///  QTSS_New//  QTSS_Delete////  These should be used for all dynamic memory allocation done from//  within modules. The memoryIdentifier is used for debugging://  the server can track this memory to make memory leak debugging easier.void*   QTSS_New(FourCharCode inMemoryIdentifier, UInt32 inSize);void    QTSS_Delete(void* inMemory);/********************************************************************///  QTSS_Milliseconds////  The server maintains a millisecond timer internally. The current//  value of that timer can be obtained from this function. This value//  is not valid between server executions.////  All millisecond values used in QTSS API use this timer, unless otherwise notedQTSS_TimeVal    QTSS_Milliseconds();/********************************************************************///  QTSS_MilliSecsTo1970Secs////  Convert milliseconds from the QTSS_Milliseconds call to //  second's since 1970//time_t  QTSS_MilliSecsTo1970Secs(QTSS_TimeVal inQTSS_MilliSeconds);/********************************************************************///  QTSS_AddRole////  Only available from QTSS_Initialize role. Call this for all the roles you//  would like your module to Operate on.////  Returns:    QTSS_NoErr//              QTSS_OutOfState: If this function isn't being called from the Register role//              QTSS_RequestFailed:     If module is registering for the QTSS_RTSPRequest_Role//                                      and there already is such a module.//              QTSS_BadArgument:   Registering for a nonexistent role.QTSS_Error QTSS_AddRole(QTSS_Role inRole);/*****************************************///  ATTRIBUTE / OBJECT CALLBACKS///********************************************************************///  QTSS_LockObject////  Grabs the mutex for this object so that accesses to the objects attributes//  from other threads will block.  Note that objects created through QTSS_CreateObjectValue//  will share a mutex with the parent object.//////  Returns:    QTSS_NoErr//              QTSS_BadArgument:   bad objectQTSS_Error QTSS_LockObject(QTSS_Object inObject);                                    /********************************************************************///  QTSS_UnlockObject////  Releases the mutex for this object.//////  Returns:    QTSS_NoErr//              QTSS_BadArgument:   bad objectQTSS_Error QTSS_UnlockObject(QTSS_Object inObject);                                    /********************************************************************///  QTSS_CreateObjectType////  Creates a new object type.  Attributes can be added to this object type and then it can//  be passed into QTSS_AddObjectValue.////  This may only be called from the QTSS_Register role.////  Returns:    QTSS_NoErr//              QTSS_RequestFailed: Too many object types already exist.QTSS_Error QTSS_CreateObjectType(QTSS_ObjectType* outType);                                    /********************************************************************///  QTSS_AddStaticAttribute////  Adds a new static attribute to a predefined object type. All added attributes implicitly have//  qtssAttrModeRead, qtssAttrModeWrite, and qtssAttrModePreempSafe permissions. "inUnused" should//  always be NULL. Specify the data type and name of the attribute.////  This may only be called from the QTSS_Register role.////  Returns:    QTSS_NoErr//              QTSS_OutOfState: If this function isn't being called from the Register role//              QTSS_BadArgument:   Adding an attribute to a nonexistent object type, attribute//                      name too long, or NULL arguments.//              QTSS_AttrNameExists: The name must be unique.QTSS_Error QTSS_AddStaticAttribute( QTSS_ObjectType inObjectType, char* inAttrName,                void* inUnused, QTSS_AttrDataType inAttrDataType);                /********************************************************************///  QTSS_AddInstanceAttribute////  Adds a new instance attribute to a predefined object type. All added attributes implicitly have//  qtssAttrModeRead, qtssAttrModeWrite, and qtssAttrModePreempSafe permissions. "inUnused" should//  always be NULL. Specify the data type and name of the attribute.////  This may be called at any time.////  Returns:    QTSS_NoErr//              QTSS_OutOfState: If this function isn't being called from the Register role//              QTSS_BadArgument:   Adding an attribute to a nonexistent object type, attribute//                      name too long, or NULL arguments.//              QTSS_AttrNameExists: The name must be unique.QTSS_Error QTSS_AddInstanceAttribute(   QTSS_Object inObject, char* inAttrName,        void* inUnused, QTSS_AttrDataType inAttrDataType);                                        /********************************************************************///  QTSS_RemoveInstanceAttribute////  Removes an existing instance attribute. This may be called at any time////  Returns:    QTSS_NoErr//              QTSS_OutOfState: If this function isn't being called from the Register role//              QTSS_BadArgument:   Bad object type.//              QTSS_AttrDoesntExist: Bad attribute IDQTSS_Error QTSS_RemoveInstanceAttribute(QTSS_Object inObject, QTSS_AttributeID inID);/********************************************************************///  Getting attribute information////  The following callbacks allow modules to discover at runtime what//  attributes exist in which objects and object types, and discover//  all attribute meta-data/********************************************************************///  QTSS_IDForAttr////  Given an attribute name, this returns its accompanying attribute ID.//  The ID can in turn be used to retrieve the attribute value from//  a object. This callback applies only to static attributes ////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error QTSS_IDForAttr(QTSS_ObjectType inObjectType, const char* inAttributeName,                            QTSS_AttributeID* outID);/********************************************************************///  QTSS_GetAttrInfoByID////  Searches for an attribute with the specified ID in the specified object.//  If found, this function returns a QTSS_AttrInfoObject describing the attribute.////  Returns:    QTSS_NoErr//              QTSS_BadArgument//              QTSS_AttrDoesntExistQTSS_Error QTSS_GetAttrInfoByID(QTSS_Object inObject, QTSS_AttributeID inAttrID,                                    QTSS_AttrInfoObject* outAttrInfoObject);/********************************************************************///  QTSS_GetAttrInfoByName////  Searches for an attribute with the specified name in the specified object.//  If found, this function returns a QTSS_AttrInfoObject describing the attribute.////  Returns:    QTSS_NoErr//              QTSS_BadArgument//              QTSS_AttrDoesntExistQTSS_Error QTSS_GetAttrInfoByName(QTSS_Object inObject, char* inAttrName,                                    QTSS_AttrInfoObject* outAttrInfoObject);/********************************************************************///  QTSS_GetAttrInfoByIndex////  Allows caller to iterate over all the attributes in the specified object.//  Returns a QTSS_AttrInfoObject for the attribute with the given index (0.. num attributes).////  Returns:    QTSS_NoErr//              QTSS_BadArgument//              QTSS_AttrDoesntExistQTSS_Error QTSS_GetAttrInfoByIndex(QTSS_Object inObject, UInt32 inIndex,                                    QTSS_AttrInfoObject* outAttrInfoObject);/********************************************************************///  QTSS_GetNumAttributes////  Returns the number of attributes in the specified object.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//QTSS_Error QTSS_GetNumAttributes (QTSS_Object inObject, UInt32* outNumAttributes);/********************************************************************///  QTSS_GetValuePtr////  NOT TO BE USED WITH NON-PREEMPTIVE-SAFE attributes (or provide your own locking//  using QTSS_LockObject).////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_NotPreemptiveSafe: Attempt to get a non-preemptive safe attribute//              QTSS_BadIndex: Attempt to get non-existent index.QTSS_Error QTSS_GetValuePtr (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex,                                void** outBuffer, UInt32* outLen);/********************************************************************///  QTSS_GetValue////  Copies the data into provided buffer. If QTSS_NotEnoughSpace is returned, outLen is still set.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_NotEnoughSpace: Value is too big for buffer provided.//              QTSS_BadIndex: Attempt to get non-existent index.QTSS_Error QTSS_GetValue (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex,                            void* ioBuffer, UInt32* ioLen);/********************************************************************///  QTSS_GetValueAsString////  Returns the specified attribute converted to a C-string. This call allocates//  memory for the string which should be disposed of using QTSS_Delete.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_BadIndex: Attempt to get non-existent index.QTSS_Error QTSS_GetValueAsString (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex,                                    char** outString);/********************************************************************///  QTSS_TypeStringToType//  QTSS_TypeToTypeString////  Returns a text name for the specified QTSS_AttrDataType, or vice-versa////  Returns:    QTSS_NoErr//              QTSS_BadArgumentQTSS_Error  QTSS_TypeStringToType(const char* inTypeString, QTSS_AttrDataType* outType);QTSS_Error  QTSS_TypeToTypeString(const QTSS_AttrDataType inType, char** outTypeString);/********************************************************************///  QTSS_StringToValue////  Given a C-string and a QTSS_AttrDataType, this function converts the C-string//  to the specified type and puts the result in ioBuffer. ioBuffer must be allocated//  by the caller and must be big enough to contain the converted value.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_NotEnoughSpace: Value is too big for buffer provided.////  QTSS_ValueToString////  Given a buffer containing a value of the specified type, this function converts//  the value to a C-string. This string is allocated internally and must be disposed of//  using QTSS_Delete////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error  QTSS_StringToValue(const char* inValueAsString, const QTSS_AttrDataType inType, void* ioBuffer, UInt32* ioBufSize);QTSS_Error  QTSS_ValueToString(const void* inValue, const UInt32 inValueLen, const QTSS_AttrDataType inType, char** outString);/********************************************************************///  QTSS_SetValue////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_ReadOnly: Attribute is read only.//              QTSS_BadIndex: Attempt to set non-0 index of attribute with a param retrieval function.//QTSS_Error QTSS_SetValue (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex, const void* inBuffer,  UInt32 inLen);/********************************************************************///  QTSS_SetValuePtr////  This allows you to have an attribute that simply reflects the value of a variable in your module.//  If the update to this variable is not atomic, you should protect updates using QTSS_LockObject.//  This can't be used with indexed attributes.  Make sure the inBuffer provided exists as long as this//  attribute exists.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_ReadOnly: Attribute is read only.//QTSS_Error QTSS_SetValuePtr (QTSS_Object inObject, QTSS_AttributeID inID, const void* inBuffer,  UInt32 inLen);/********************************************************************///  QTSS_CreateObjectValue////  Returns:    QTSS_NoErr//                              QTSS_BadArgument: Bad argument//                              QTSS_ReadOnly: Attribute is read only.//QTSS_Error QTSS_CreateObjectValue (QTSS_Object inObject, QTSS_AttributeID inID, QTSS_ObjectType inType, UInt32* outIndex, QTSS_Object* outCreatedObject);/********************************************************************///  QTSS_GetNumValues////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//QTSS_Error QTSS_GetNumValues (QTSS_Object inObject, QTSS_AttributeID inID, UInt32* outNumValues);/********************************************************************///  QTSS_RemoveValue////  This function removes the value with the specified index. If there//  are any values following this index, they will be reordered.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_ReadOnly: Attribute is read only.//              QTSS_BadIndex: Attempt to set non-0 index of attribute with a param retrieval function.//QTSS_Error QTSS_RemoveValue (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex);/*****************************************///  STREAM CALLBACKS////  The QTSS API provides QTSS_StreamRefs as a generalized stream abstraction. Mostly,//  QTSS_StreamRefs are used for communicating with the client. For instance,//  in the QTSS_RTSPRequest_Role, modules receive a QTSS_StreamRef which can be//  used for reading RTSP data from the client, and sending RTSP response data to the client.////  Additionally, QTSS_StreamRefs are generalized enough to be used in many other situations.//  For instance, modules receive a QTSS_StreamRef for the error log. When modules want//  to report errors, they can use these same routines, passing in the error log StreamRef./********************************************************************///  QTSS_Write////  Writes data to a stream.////  Returns:    QTSS_NoErr//              QTSS_WouldBlock: The stream cannot accept any data at this time.//              QTSS_NotConnected: The stream receiver is no longer connected.//              QTSS_BadArgument:   NULL argument.QTSS_Error  QTSS_Write(QTSS_StreamRef inRef, const void* inBuffer, UInt32 inLen, UInt32* outLenWritten, QTSS_WriteFlags inFlags);/********************************************************************///  QTSS_WriteV////  Works similar to the POSIX WriteV, and takes a POSIX iovec.//  THE FIRST ENTRY OF THE IOVEC MUST BE BLANK!!!////  Returns:    QTSS_NoErr//              QTSS_WouldBlock: The stream cannot accept any data at this time.//              QTSS_NotConnected: The stream receiver is no longer connected.//              QTSS_BadArgument:   NULL argument.QTSS_Error  QTSS_WriteV(QTSS_StreamRef inRef, iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength, UInt32* outLenWritten);/********************************************************************///  QTSS_Flush////  Some QTSS_StreamRefs (QTSS_RequestRef, for example) buffers data before sending it//  out. Calling this forces the stream to write the data immediately.////  Returns:    QTSS_NoErr//              QTSS_WouldBlock: Stream cannot be completely flushed at this time.//              QTSS_NotConnected: The stream receiver is no longer connected.//              QTSS_BadArgument:   NULL argument.QTSS_Error  QTSS_Flush(QTSS_StreamRef inRef);/********************************************************************///  QTSS_Read////  Reads data out of the stream////  Arguments   inRef:      The stream to read from.//              ioBuffer:   A buffer to place the read data//              inBufLen:   The length of ioBuffer.//              outLengthRead:  If function returns QTSS_NoErr, on output this will be set to the//                              amount of data actually read.////  Returns:    QTSS_NoErr//              QTSS_WouldBlock//              QTSS_RequestFailed//              QTSS_BadArgumentQTSS_Error  QTSS_Read(QTSS_StreamRef inRef, void* ioBuffer, UInt32 inBufLen, UInt32* outLengthRead);/********************************************************************///  QTSS_Seek////  Sets the current stream position to inNewPosition////  Arguments   inRef:      The stream to read from.//              inNewPosition:  Offset from the start of the stream.////  Returns:    QTSS_NoErr//              QTSS_RequestFailed//              QTSS_BadArgumentQTSS_Error  QTSS_Seek(QTSS_StreamRef inRef, UInt64 inNewPosition);/********************************************************************///  QTSS_Advise////  Lets the stream know that the specified section of the stream will be read soon.////  Arguments   inRef:          The stream to advise.//              inPosition:     Offset from the start of the stream of the advise region.//              inAdviseSize:   Size of the advise region.////  Returns:    QTSS_NoErr//              QTSS_RequestFailed//              QTSS_BadArgumentQTSS_Error  QTSS_Advise(QTSS_StreamRef inRef, UInt64 inPosition, UInt32 inAdviseSize);/*****************************************///  SERVICES////  Oftentimes modules have functionality that they want accessable from other//  modules. An example of this might be a logging module that allows other//  modules to write messages to the log.////  Modules can use the following callbacks to register and invoke "services".//  Adding & finding services works much like adding & finding attributes in//  an object. A service has a name. In order to invoke a service, the calling//  module must know the name of the service and resolve that name into an ID.////  Each service has a parameter block format that is specific to that service.//  Modules that are exporting services should carefully document the services they//  export, and modules calling services should take care to fail gracefully//  if the service isn't present or returns an error.typedef QTSS_Error (*QTSS_ServiceFunctionPtr)(QTSS_ServiceFunctionArgsPtr);/********************************************************************///  QTSS_AddService////  This function registers a service with the specified name, and//  associates it with the specified function pointer.//  QTSS_AddService may only be called from the QTSS_Register role////  Returns:    QTSS_NoErr//              QTSS_OutOfState: If this function isn't being called from the Register role//              QTSS_BadArgument:   Service name too long, or NULL arguments.QTSS_Error QTSS_AddService(const char* inServiceName, QTSS_ServiceFunctionPtr inFunctionPtr);/********************************************************************///  QTSS_IDForService////  Much like QTSS_IDForAttr, this resolves a service name into its//  corresponding QTSS_ServiceID. The QTSS_ServiceID can then be used to//  invoke the service.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error QTSS_IDForService(const char* inTag, QTSS_ServiceID* outID);/********************************************************************///  QTSS_DoService////  Invokes the service. Return value from this function comes from the service//  function itself, unless the QTSS_IllegalService errorcode is returned,//  which is returned when the QTSS_ServiceID is bad.QTSS_Error QTSS_DoService(QTSS_ServiceID inID, QTSS_ServiceFunctionArgsPtr inArgs);/********************************************************************///  BUILT-IN SERVICES////  The server registers some built-in services when it starts up.//  Here are macros for their names & descriptions of what they do// Rereads the preferences, also causes the QTSS_RereadPrefs_Role to be invoked#define QTSS_REREAD_PREFS_SERVICE   "RereadPreferences"/*****************************************///  RTSP HEADER CALLBACKS////  As a convience to modules that want to send RTSP responses, the server//  has internal utilities for formatting a proper RTSP response. When a module//  calls QTSS_SendRTSPHeaders, the server sends a proper RTSP status line, using//  the request's current status code, and also sends the proper CSeq header,//  session ID header, and connection header.////  Any other headers can be appended by calling QTSS_AppendRTSPHeader. They will be//  sent along with everything else when QTSS_SendRTSPHeaders is called.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error QTSS_SendRTSPHeaders(QTSS_RTSPRequestObject inRef);////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error QTSS_AppendRTSPHeader(QTSS_RTSPRequestObject inRef, QTSS_RTSPHeader inHeader, const char* inValue, UInt32 inValueLen);/*****************************************///  QTSS_SendStandardRTSPResponse////  This function is also provided as an optional convienence to modules who are sending//  "typical" RTSP responses to clients. The function uses the QTSS_RTSPRequestObject and//  the QTSS_Object as inputs, where the object may either be a QTSS_ClientSessionObject//  or a QTSS_RTPStreamObject, depending on the method. The response is written to the//  stream provided.////  Below is a description of what is returned for each method this function supports:////  DESCRIBE:////   Writes status line, CSeq, SessionID, Connection headers as determined by the request.//   Writes a Content-Base header with the Content-Base being the URL provided.//   Writes a Content-Type header of "application/sdp"//   QTSS_Object must be a QTSS_ClientSessionObject.////  SETUP:////   Writes status line, CSeq, SessionID, Connection headers as determined by the request.//   Writes a Transport header with the client & server ports (if connection is over UDP).//   QTSS_Object must be a QTSS_RTPStreamObject.////  PLAY:////   Writes status line, CSeq, SessionID, Connection headers as determined by the request.//   QTSS_Object must be a QTSS_ClientSessionObject.////   Specify whether you want the server to append the seq#, timestamp, & ssrc info to//   the RTP-Info header via. the qtssPlayRespWriteTrackInfo flag.////  PAUSE:////   Writes status line, CSeq, SessionID, Connection headers as determined by the request.//   QTSS_Object must be a QTSS_ClientSessionObject.////  TEARDOWN:////   Writes status line, CSeq, SessionID, Connection headers as determined by the request.//   QTSS_Object must be a QTSS_ClientSessionObject.////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error  QTSS_SendStandardRTSPResponse(QTSS_RTSPRequestObject inRTSPRequest, QTSS_Object inRTPInfo, UInt32 inFlags);/*****************************************///  CLIENT SESSION CALLBACKS////  QTSS API Modules have the option of generating and sending RTP packets. Only//  one module currently can generate packets for a particular session. In order//  to do this, call QTSS_AddRTPStream. This must be done in response to a RTSP//  request, and typically is done in response to a SETUP request from the client.////  After one or more streams have been added to the session, the module that "owns"//  the packet sending for that session can call QTSS_Play to start the streams playing.//  After calling QTSS_Play, the module will get invoked in the QTSS_SendPackets_Role.//  Calling QTSS_Pause stops playing.////  The "owning" module may call QTSS_Teardown at any time. Doing this closes the//  session and will cause the QTSS_SessionClosing_Role to be invoked for this session. ////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_RequestFailed: QTSS_RTPStreamObject couldn't be created.QTSS_Error  QTSS_AddRTPStream(QTSS_ClientSessionObject inClientSession, QTSS_RTSPRequestObject inRTSPRequest, QTSS_RTPStreamObject* outStream, QTSS_AddStreamFlags inFlags);////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_RequestFailed: No streams added to this session.QTSS_Error  QTSS_Play(QTSS_ClientSessionObject inClientSession, QTSS_RTSPRequestObject inRTSPRequest, QTSS_PlayFlags inPlayFlags);////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error  QTSS_Pause(QTSS_ClientSessionObject inClientSession);////  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error  QTSS_Teardown(QTSS_ClientSessionObject inClientSession);//  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argumentQTSS_Error  QTSS_RefreshTimeOut(QTSS_ClientSessionObject inClientSession);/*****************************************///  FILE SYSTEM CALLBACKS////  All modules that interact with the local file system should use these APIs instead//  of the direct operating system calls.////  This is for two reasons: 1) to ensure portability of your module across different//  platforms such as Win32 and different versions of the UNIX operating system.////  2)  To ensure your module will work properly if there is a 3rd party file system//      or database that contains media files./********************************************************************///  QTSS_OpenFileObject////  Arguments   inPath: a NULL-terminated C-string containing a full path to the file to open.//                      inPath must be in the local (operating system) file system path style.//              inFlags: desired flags.//              outFileObject:  If function returns QTSS_NoErr, on output this will be a QTSS_Object//                              for the file.////  Returns:    QTSS_NoErr//              QTSS_FileNotFound//              QTSS_RequestFailed//              QTSS_BadArgumentQTSS_Error  QTSS_OpenFileObject(char* inPath, QTSS_OpenFileFlags inFlags, QTSS_Object* outFileObject);/********************************************************************///  QTSS_CloseFileObject////  Closes the file object.////  Arguments:  inFileObject: the file to close////  Returns:    QTSS_NoErr//              QTSS_BadArgumentQTSS_Error  QTSS_CloseFileObject(QTSS_Object inFileObject);/*****************************************///  SOCKET CALLBACKS////  It is not necessary for a module that internally uses network I/O to go through//  the QTSS API for their networking APIs. However, it is highly recommended//  to use nonblocking network I/O from a module. With nonblocking network I/O, it//  is very important to be able to receive socket events.////  To facilitate this, QTSS API provides the following two callbacks to link external//  sockets into the QTSS API streams framework.////  Once a module has created a QTSS stream out of its socket, it is possible to use the//  QTSS_RequestEvent callback to receive events on the socket. /********************************************************************///  QTSS_CreateStreamFromSocket////  Creates a socket stream.////  Arguments:  inFileDesc: the socket////  Returns:    QTSS_NoErrQTSS_Error  QTSS_CreateStreamFromSocket(int inFileDesc, QTSS_SocketStream* outStream);/********************************************************************///  QTSS_DestroySocketStream////  Creates a socket stream.////  Arguments:  inFileDesc: the socket////  Returns:    QTSS_NoErrQTSS_Error  QTSS_DestroySocketStream(QTSS_SocketStream inStream);/*****************************************///  ASYNC I/O CALLBACKS////  QTSS modules must be kind in how they use the CPU. The server doesn't//  prevent a poorly implemented QTSS module from hogging the processing//  capability of the server, at the expense of other modules and other clients.////  It is therefore imperitive that a module use non-blocking, or async, I/O.//  If a module were to block, say, waiting to read file data off disk, this stall//  would affect the entire server.////  This problem is resolved in QTSS API in a number of ways.////  Firstly, all QTSS_StreamRefs provided to modules are non-blocking, or async.//  Modules should be prepared to receive EWOULDBLOCK errors in response to//  QTSS_Read, QTSS_Write, & QTSS_WriteV calls, with certain noted exceptions//  in the case of responding to RTSP requests.////  Modules that open their own file descriptors for network or file I/O can//  create separate threads for handling I/O. In this case, these descriptors//  can remain blocking, as long as they always block on the private module threads.////  In most cases, however, creating a separate thread for I/O is not viable for the//  kind of work the module would like to do. For instance, a module may wish//  to respond to a RTSP DESCRIBE request, but can't immediately because constructing//  the response would require I/O that would block.////  The problem is once the module returns from the QTSS_RTSPProcess_Role, the//  server will mistakenly consider the request handled, and move on. It won't//  know that the module has more work to do before it finishes processing the DESCRIBE.////  In this case, the module needs to tell the server to delay processing of the//  DESCRIBE request until the file descriptor's blocking condition is lifted.//  The module can do this by using the provided "event" callback routines.//  Returns:    QTSS_NoErr//              QTSS_BadArgument: Bad argument//              QTSS_OutOfState: if this callback is made from a role that doesn't allow async I/O events//              QTSS_RequestFailed: Not currently possible to request an event. QTSS_Error  QTSS_RequestEvent(QTSS_StreamRef inStream, QTSS_EventType inEventMask);QTSS_Error  QTSS_SignalStream(QTSS_StreamRef inStream, QTSS_EventType inEventMask);QTSS_Error  QTSS_SetIdleTimer(SInt64 inIdleMsec);QTSS_Error  QTSS_SetIntervalRoleTimer(SInt64 inIdleMsec);QTSS_Error  QTSS_RequestGlobalLock();Bool16      QTSS_IsGlobalLocked();QTSS_Error  QTSS_GlobalUnLock();/*****************************************///  AUTHENTICATE and AUTHORIZE CALLBACKS////  All modules that want Authentication outside of the //  QTSS_RTSPAuthenticate_Role must use the QTSS_Authenticate callback //  and must pass in the request object//      All modules that want Authorization outside of the//      QTSS_RTSPAuthorize_Role should use the QTSS_Authorize callback//      and must pass in the request object/********************************************************************///  QTSS_Authenticate////  Arguments inputs:   inAuthUserName:         the username that is to be authenticated//                      inAuthResourceLocalPath:the resource that is to be authorized access//                      inAuthMoviesDir:        the movies directory (reqd. for finding the access file)//                      inAuthRequestAction:    the action that is performed for the resource//                      inAuthScheme:           the authentication scheme (the password retrieved will be based on it)//                      ioAuthRequestObject:    the request object //                                              The object is filled with the attributes passed in  //  Returns:            QTSS_NoErr//                      QTSS_BadArgument        if any of the input arguments are nullQTSS_Error  QTSS_Authenticate(  const char* inAuthUserName,                                 const char* inAuthResourceLocalPath,                                 const char* inAuthMoviesDir,                                 QTSS_ActionFlags inAuthRequestAction,                                 QTSS_AuthScheme inAuthScheme,                                 QTSS_RTSPRequestObject ioAuthRequestObject);//  QTSS_Authorize////  Arguments inputs:   inAuthRequestObject:    the request object////            outputs:  outAuthRealm:           the authentication realm //                      outAuthUserAllowed:     true if user is allowed, and false otherwise//  //  Returns:            QTSS_NoErr//                      QTSS_BadArgumentQTSS_Error	QTSS_Authorize(QTSS_RTSPRequestObject inAuthRequestObject, char** outAuthRealm, Bool16* outAuthUserAllowed);void        QTSS_LockStdLib();void        QTSS_UnlockStdLib();#ifdef QTSS_OLDROUTINENAMES//// Legacy routines//// QTSS_AddAttribute has been replaced by QTSS_AddStaticAttributeQTSS_Error QTSS_AddAttribute(QTSS_ObjectType inObjectType, const char* inAttributeName,                                void* inUnused);#endif// #ifdef __cplusplus// }// #endif#endif


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表