예제 #1
0
QTSS_Error QTSSCallbacks::QTSS_GetNumAttributes(QTSS_Object inObject,  UInt32* outNumValues)
{
        
    if (outNumValues == NULL)
        return QTSS_BadArgument;

    if (inObject == NULL)
        return QTSS_BadArgument;

    OSMutexLocker locker(((QTSSDictionary*)inObject)->GetMutex());

    QTSSDictionaryMap* theMap = NULL;
    *outNumValues = 0;

    // Get the Static Attribute count
    theMap = ((QTSSDictionary*)inObject)->GetDictionaryMap();
    if (theMap != NULL)
        *outNumValues += theMap->GetNumNonRemovedAttrs();
    // Get the Instance Attribute count
    theMap = ((QTSSDictionary*)inObject)->GetInstanceDictMap();
    if (theMap != NULL)
        *outNumValues += theMap->GetNumNonRemovedAttrs();

    return QTSS_NoErr;
}
void  RTSPRequestInterface::Initialize()
{
    //make a partially complete header
    StringFormatter headerFormatter(sPremadeHeaderPtr.Ptr, kStaticHeaderSizeInBytes);
    PutStatusLine(&headerFormatter, qtssSuccessOK, RTSPProtocol::k10Version);
    
    headerFormatter.Put(QTSServerInterface::GetServerHeader());
    headerFormatter.PutEOL();
    headerFormatter.Put(RTSPProtocol::GetHeaderString(qtssCSeqHeader));
    headerFormatter.Put(sColonSpace);
    sPremadeHeaderPtr.Len = headerFormatter.GetCurrentOffset();
    Assert(sPremadeHeaderPtr.Len < kStaticHeaderSizeInBytes);
    
        
    StringFormatter noServerInfoHeaderFormatter(sPremadeNoHeaderPtr.Ptr, kStaticHeaderSizeInBytes);
    PutStatusLine(&noServerInfoHeaderFormatter, qtssSuccessOK, RTSPProtocol::k10Version);
    noServerInfoHeaderFormatter.Put(RTSPProtocol::GetHeaderString(qtssCSeqHeader));
    noServerInfoHeaderFormatter.Put(sColonSpace);
    sPremadeNoHeaderPtr.Len = noServerInfoHeaderFormatter.GetCurrentOffset();
    Assert(sPremadeNoHeaderPtr.Len < kStaticHeaderSizeInBytes);
    
    //Setup all the dictionary stuff
    for (UInt32 x = 0; x < qtssRTSPReqNumParams; x++)
        QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kRTSPRequestDictIndex)->
            SetAttribute(x, sAttributes[x].fAttrName, sAttributes[x].fFuncPtr,
                            sAttributes[x].fAttrDataType, sAttributes[x].fAttrPermission);
    
    QTSSDictionaryMap* theHeaderMap = QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kRTSPHeaderDictIndex);
    for (UInt32 y = 0; y < qtssNumHeaders; y++)
        theHeaderMap->SetAttribute(y, RTSPProtocol::GetHeaderString(y).Ptr, NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe);
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
void QTSSMessages::Initialize()
{
	QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kTextMessagesDictIndex);
	Assert(theMap != nullptr);

	for (UInt32 x = 0; x < qtssMsgNumParams; x++)
		theMap->SetAttribute(x, sMessagesKeyStrings[x], nullptr, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe);
}
예제 #6
0
QTSS_Error  QTSSCallbacks::QTSS_DoService(QTSS_ServiceID inID, QTSS_ServiceFunctionArgsPtr inArgs)
{
    // Make sure that the service ID is in fact valid
    
    QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServiceDictIndex);
    SInt32 theIndex = theMap->ConvertAttrIDToArrayIndex(inID);
    if (theIndex < 0)
        return QTSS_IllegalService;
    
    // Get the service function 
    QTSS_ServiceFunctionPtr theFunction = (QTSS_ServiceFunctionPtr)theMap->GetAttrFunction(theIndex);

    // Invoke it, return the result.    
    return (theFunction)(inArgs);
}
예제 #7
0
QTSS_Error  QTSSCallbacks::QTSS_AddStaticAttribute(QTSS_ObjectType inObjectType, const char* inAttrName, void* inUnused, QTSS_AttrDataType inAttrDataType)
{
    Assert(inUnused == NULL);
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();

    // Static attributes can only be added before modules have had their Initialize role invoked.
    if ((theState == NULL) || (theState->curRole != QTSS_Register_Role))
        return QTSS_OutOfState;

    UInt32 theDictionaryIndex = QTSSDictionaryMap::GetMapIndex(inObjectType);
    if (theDictionaryIndex == QTSSDictionaryMap::kIllegalDictionary)
        return QTSS_BadArgument;
        
    QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(theDictionaryIndex);
    return theMap->AddAttribute(inAttrName, NULL, inAttrDataType, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe);
}
예제 #8
0
void QTSServerPrefs::RereadServerPreferences(Bool16 inWriteMissingPrefs)
{
    OSMutexLocker locker(&fPrefsMutex);
    QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kPrefsDictIndex);
    
    for (UInt32 x = 0; x < theMap->GetNumAttrs(); x++)
    {
        //
        // Look for a pref in the file that matches each pref in the dictionary
        char* thePrefTypeStr = NULL;
        char* thePrefName = NULL;
        
        ContainerRef server = fPrefsSource->GetRefForServer();
        ContainerRef pref = fPrefsSource->GetPrefRefByName( server, theMap->GetAttrName(x) );
        char* thePrefValue = NULL;
        if (pref != NULL)
            thePrefValue = fPrefsSource->GetPrefValueByRef( pref, 0, &thePrefName,
                                                                    (char**)&thePrefTypeStr);
        
        if ((thePrefValue == NULL) && (x < qtssPrefsNumParams)) // Only generate errors for server prefs
        {
            //
            // There is no pref, use the default and log an error
            if (::strlen(sPrefInfo[x].fDefaultValue) > 0)
            {
                //
                // Only log this as an error if there is a default (an empty string
                // doesn't count). If there is no default, we will constantly print
                // out an error message...
                QTSSModuleUtils::LogError(  QTSSModuleUtils::GetMisingPrefLogVerbosity(),
                                            qtssServerPrefMissing,
                                            0,
                                            sAttributes[x].fAttrName,
                                            sPrefInfo[x].fDefaultValue);
            }
            
            this->SetPrefValue(x, 0, sPrefInfo[x].fDefaultValue, sAttributes[x].fAttrDataType);
            if (sPrefInfo[x].fAdditionalDefVals != NULL)
            {
                //
                // Add additional default values if they exist
                for (UInt32 y = 0; sPrefInfo[x].fAdditionalDefVals[y] != NULL; y++)
                    this->SetPrefValue(x, y+1, sPrefInfo[x].fAdditionalDefVals[y], sAttributes[x].fAttrDataType);
            }
            
            if (inWriteMissingPrefs)
            {
                //
                // Add this value into the file, cuz we need it.
                pref = fPrefsSource->AddPref( server, sAttributes[x].fAttrName, QTSSDataConverter::TypeToTypeString(sAttributes[x].fAttrDataType));
                fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fDefaultValue);
                
                if (sPrefInfo[x].fAdditionalDefVals != NULL)
                {
                    for (UInt32 a = 0; sPrefInfo[x].fAdditionalDefVals[a] != NULL; a++)
                        fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fAdditionalDefVals[a]);
                }
            }
            continue;
        }
        
        QTSS_AttrDataType theType = QTSSDataConverter::TypeStringToType(thePrefTypeStr);
        
        if ((x < qtssPrefsNumParams) && (theType != sAttributes[x].fAttrDataType)) // Only generate errors for server prefs
        {
            //
            // The pref in the file has the wrong type, use the default and log an error
            
            if (::strlen(sPrefInfo[x].fDefaultValue) > 0)
            {
                //
                // Only log this as an error if there is a default (an empty string
                // doesn't count). If there is no default, we will constantly print
                // out an error message...
                QTSSModuleUtils::LogError(  qtssWarningVerbosity,
                                            qtssServerPrefWrongType,
                                            0,
                                            sAttributes[x].fAttrName,
                                            sPrefInfo[x].fDefaultValue);
            }
            
            this->SetPrefValue(x, 0, sPrefInfo[x].fDefaultValue, sAttributes[x].fAttrDataType);
            if (sPrefInfo[x].fAdditionalDefVals != NULL)
            {
                //
                // Add additional default values if they exist
                for (UInt32 z = 0; sPrefInfo[x].fAdditionalDefVals[z] != NULL; z++)
                    this->SetPrefValue(x, z+1, sPrefInfo[x].fAdditionalDefVals[z], sAttributes[x].fAttrDataType);
            }

            if (inWriteMissingPrefs)
            {
                //
                // Remove it out of the file and add in the default.
                fPrefsSource->RemovePref(pref);
                pref = fPrefsSource->AddPref( server, sAttributes[x].fAttrName, QTSSDataConverter::TypeToTypeString(sAttributes[x].fAttrDataType));
                fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fDefaultValue);
                if (sPrefInfo[x].fAdditionalDefVals != NULL)
                {
                    for (UInt32 b = 0; sPrefInfo[x].fAdditionalDefVals[b] != NULL; b++)
                        fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fAdditionalDefVals[b]);
                }
            }
            continue;
        }
        
        UInt32 theNumValues = 0;
        if ((x < qtssPrefsNumParams) && (!sPrefInfo[x].fAllowMultipleValues))
            theNumValues = 1;
            
        this->SetPrefValuesFromFileWithRef(pref, x, theNumValues);
    }
    
    //
    // Do any special pref post-processing
    this->UpdateAuthScheme();
    QTSSModuleUtils::SetEnableRTSPErrorMsg(fEnableRTSPErrMsg);
    
    QTSSRollingLog::SetCloseOnWrite(fCloseLogsOnWrite);
    //
    // In case we made any changes, write out the prefs file
    (void)fPrefsSource->WritePrefsFile();
}
예제 #9
0
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;
}
예제 #10
0
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?
	    theAttrs[theMapIndex].fAllocatedInternally = true;
        }
    }
/*这是本类最重要的函数:先遍历服务器的属性列表,逐个用预设值文件设置各指定的属性,若预设值出错,就用默认值代替,然后设置认证格式,
	RTP/RTCP包头打印选项,日志写关闭,最后将调整后的预设值内容写入xml预设值文件 */
void QTSServerPrefs::RereadServerPreferences(Bool16 inWriteMissingPrefs)
{
    OSMutexLocker locker(&fPrefsMutex);

	//得到服务器预设值字典对象
    QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kPrefsDictIndex);
    
	//遍历服务器的属性列表,逐个用预设值文件设置该指定的属性
    for (UInt32 x = 0; x < theMap->GetNumAttrs(); x++)
    {
        // Look for a pref in the file that matches each pref in the dictionary
        char* thePrefTypeStr = NULL;
        char* thePrefName = NULL;
		char* thePrefValue = NULL;
        
        ContainerRef server = fPrefsSource->GetRefForServer();/* 在fRootTag下获取子Tag SERVER并返回,没有就生成它 */
        ContainerRef pref = fPrefsSource->GetPrefRefByName( server, theMap->GetAttrName(x) );/* 得到子Tag SERVER指定属性名的子Tag */
        
		/* 假如不空,返回指定Tag的指定index的子Tag的value,得到指定Tag的NAME和TYPE属性值,对Tag的情况作了分析 */
        if (pref != NULL)
            thePrefValue = fPrefsSource->GetPrefValueByRef( pref, 0, &thePrefName,(char**)&thePrefTypeStr);
                                                                    
        /* 假如得到的属性值是空的, */
        if ((thePrefValue == NULL) && (x < qtssPrefsNumParams)) // Only generate errors for server prefs
        {
            // 假如没有设置值,但有默认值,使用默认值,并在日志中记录
            // There is no pref, use the default and log an error
            if (::strlen(sPrefInfo[x].fDefaultValue) > 0)
            {
                // 假如有默认值(空字符串不算),仅在日志中记录;假如没有默认值,在屏幕上打印出来
                // Only log this as an error if there is a default (an empty string
                // doesn't count). If there is no default, we will constantly print
                // out an error message...
                QTSSModuleUtils::LogError(  QTSSModuleUtils::GetMisingPrefLogVerbosity(),
                                            qtssServerPrefMissing,
                                            0,
                                            sAttributes[x].fAttrName,
                                            sPrefInfo[x].fDefaultValue);
            }
            //用默认值设置相应的服务器属性值
            this->SetPrefValue(x, 0, sPrefInfo[x].fDefaultValue, sAttributes[x].fAttrDataType);
			//假如还有附加的默认值,也要依次设置上
            if (sPrefInfo[x].fAdditionalDefVals != NULL)
            {
                // Add additional default values if they exist
                for (UInt32 y = 0; sPrefInfo[x].fAdditionalDefVals[y] != NULL; y++)
                    this->SetPrefValue(x, y+1, sPrefInfo[x].fAdditionalDefVals[y], sAttributes[x].fAttrDataType);
            }
            
			//假如第2个入参为true,生成指定属性值和数据类型的Tag,加入Tag内嵌队列中,并返回该Tag,即将该属性及其(多个)属性值,补充写入xml预配置文件
            if (inWriteMissingPrefs)
            {
                // Add this value into the file, because we need it.
                pref = fPrefsSource->AddPref( server, sAttributes[x].fAttrName, QTSSDataConverter::TypeToTypeString(sAttributes[x].fAttrDataType));
                // 再写入指定的属性值
				fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fDefaultValue);
                //如果有多重值,也一并写入
                if (sPrefInfo[x].fAdditionalDefVals != NULL)
                {
                    for (UInt32 a = 0; sPrefInfo[x].fAdditionalDefVals[a] != NULL; a++)
                        fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fAdditionalDefVals[a]);
                }
            }
            continue; //跳到下一个索引
        }
        
        QTSS_AttrDataType theType = QTSSDataConverter::TypeStringToType(thePrefTypeStr);
        
		// 假如有预设值,但是数据类型不对,使用默认值,并记录错误
		// The pref in the file has the wrong type, use the default and log an error
        if ((x < qtssPrefsNumParams) && (theType != sAttributes[x].fAttrDataType)) // Only generate errors for server prefs
        { 
            // 假如有默认值(空字符串不算),仅在日志中记录;假如没有默认值,在屏幕上打印出来
            if (::strlen(sPrefInfo[x].fDefaultValue) > 0)
            {
                // Only log this as an error if there is a default (an empty string
                // doesn't count). If there is no default, we will constantly print
                // out an error message...
                QTSSModuleUtils::LogError(  qtssWarningVerbosity,
                                            qtssServerPrefWrongType,
                                            0,
                                            sAttributes[x].fAttrName,
                                            sPrefInfo[x].fDefaultValue);
            }
            //用默认值设置相应的服务器属性值
            this->SetPrefValue(x, 0, sPrefInfo[x].fDefaultValue, sAttributes[x].fAttrDataType);
			//假如还有附加的默认值,也要依次设置上
            if (sPrefInfo[x].fAdditionalDefVals != NULL)
            {
                // Add additional default values if they exist
                for (UInt32 z = 0; sPrefInfo[x].fAdditionalDefVals[z] != NULL; z++)
                    this->SetPrefValue(x, z+1, sPrefInfo[x].fAdditionalDefVals[z], sAttributes[x].fAttrDataType);
            }
			//假如第2个入参为true,先删除该Tag,再增加新的Tag,设置其属性,及其(多个)属性值
			// Remove it out of the file and add in the default.
            if (inWriteMissingPrefs)
            {   
                fPrefsSource->RemovePref(pref);
                pref = fPrefsSource->AddPref( server, sAttributes[x].fAttrName, QTSSDataConverter::TypeToTypeString(sAttributes[x].fAttrDataType));
                fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fDefaultValue);
                if (sPrefInfo[x].fAdditionalDefVals != NULL)
                {
                    for (UInt32 b = 0; sPrefInfo[x].fAdditionalDefVals[b] != NULL; b++)
                        fPrefsSource->AddPrefValue(pref, sPrefInfo[x].fAdditionalDefVals[b]);
                }
            }
            continue;//跳到下一个索引
        }
        
		/* 设置单值属性标志,用于下面的函数QTSSPrefs::SetPrefValuesFromFileWithRef()中的第三个参数 */
        UInt32 theNumValues = 0;
        if ((x < qtssPrefsNumParams) && (!sPrefInfo[x].fAllowMultipleValues))
            theNumValues = 1;
        
		//用预设值文件设置该指定的属性
        this->SetPrefValuesFromFileWithRef(pref, x, theNumValues);
    }
    
    
    // Do any special pref post-processing

    //先得到认证格式的预设值,再用其设置数据成员fAuthScheme
    this->UpdateAuthScheme();
    //获取服务器RTP/RTCP包头打印选项的预设值,解析并重新设置数据成员fPacketHeaderPrintfOptions
    this->UpdatePrintfOptions();
	//用数据成员fEnableRTSPErrMsg设置QTSSModuleUtils::sEnableRTSPErrorMsg
    QTSSModuleUtils::SetEnableRTSPErrorMsg(fEnableRTSPErrMsg);
    //用数据成员fCloseLogsOnWrite设置QTSSRollingLog中的静态变量sCloseOnWrite
    QTSSRollingLog::SetCloseOnWrite(fCloseLogsOnWrite);
   
    // In case we made any changes, write out the prefs file,将经过调整后的预设值内容写入xml预设值文件
    (void)fPrefsSource->WritePrefsFile();
}