/* * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2008 Apple Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ * */ /* File: QTSSModule.cpp Contains: Implements object defined in QTSSModule.h */ #include #include "QTSSModule.h" #include "OSArrayObjectDeleter.h" #include "OSMemory.h" #include "StringParser.h" #include "Socket.h" #include "QTSServerInterface.h" Bool16 QTSSModule::sHasRTSPRequestModule = false; Bool16 QTSSModule::sHasOpenFileModule = false; Bool16 QTSSModule::sHasRTSPAuthenticateModule = false; QTSSAttrInfoDict::AttrInfo QTSSModule::sAttributes[] = { /*fields: fAttrName, fFuncPtr, fAttrDataType, fAttrPermission */ /* 0 */ { "qtssModName", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe }, /* 1 */ { "qtssModDesc", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModeWrite }, /* 2 */ { "qtssModVersion", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModeWrite }, /* 3 */ { "qtssModRoles", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe }, /* 4 */ { "qtssModPrefs", NULL, qtssAttrDataTypeQTSS_Object,qtssAttrModeRead | qtssAttrModePreempSafe | qtssAttrModeInstanceAttrAllowed }, /* 5 */ { "qtssModAttributes", NULL, qtssAttrDataTypeQTSS_Object, qtssAttrModeRead | qtssAttrModePreempSafe | qtssAttrModeInstanceAttrAllowed } }; char* QTSSModule::sRoleNames[] = { "InitializeRole" , "ShutdownRole" , "RTSPFilterRole" , "RTSPRouteRole" , "RTSPAthnRole" , "RTSPAuthRole" , "RTSPPreProcessorRole" , "RTSPRequestRole" , "RTSPPostProcessorRole" , "RTSPSessionClosingRole" , "RTPSendPacketsRole" , "ClientSessionClosingRole" , "RTCPProcessRole" , "ErrorLogRole" , "RereadPrefsRole" , "OpenFileRole" , "OpenFilePreProcessRole" , "AdviseFileRole" , "ReadFileRole" , "CloseFileRole" , "RequestEventFileRole" , "RTSPIncomingDataRole" , "StateChangeRole" , "TimedIntervalRole" , "" }; void QTSSModule::Initialize() { //Setup all the dictionary stuff for (UInt32 x = 0; x < qtssModNumParams; x++) QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kModuleDictIndex)-> SetAttribute(x, sAttributes[x].fAttrName, sAttributes[x].fFuncPtr, sAttributes[x].fAttrDataType, sAttributes[x].fAttrPermission); } QTSSModule::QTSSModule(char* inName, char* inPath) : QTSSDictionary(QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kModuleDictIndex)), fQueueElem(NULL), fPath(NULL), fFragment(NULL), fDispatchFunc(NULL), fPrefs(NULL), fAttributes(NULL) { fQueueElem.SetEnclosingObject(this); this->SetTaskName("QTSSModule"); if ((inPath != NULL) && (inPath[0] != '\0')) { // Create a code fragment if this module is being loaded from disk fFragment = NEW OSCodeFragment(inPath); fPath = NEW char[::strlen(inPath) + 2]; ::strcpy(fPath, inPath); } fAttributes = NEW QTSSDictionary( NULL, &fAttributesMutex ); this->SetVal(qtssModPrefs, &fPrefs, sizeof(fPrefs)); this->SetVal(qtssModAttributes, &fAttributes, sizeof(fAttributes)); // If there is a name, copy it into the module object's internal buffer if (inName != NULL) this->SetValue(qtssModName, 0, inName, ::strlen(inName), QTSSDictionary::kDontObeyReadOnly); ::memset(fRoleArray, 0, sizeof(fRoleArray)); ::memset(&fModuleState, 0, sizeof(fModuleState)); } QTSS_Error QTSSModule::SetupModule(QTSS_CallbacksPtr inCallbacks, QTSS_MainEntryPointPtr inEntrypoint) { QTSS_Error theErr = QTSS_NoErr; // Load fragment from disk if necessary if ((fFragment != NULL) && (inEntrypoint == NULL)) theErr = this->LoadFromDisk(&inEntrypoint); if (theErr != QTSS_NoErr) return theErr; // At this point, we must have an entrypoint if (inEntrypoint == NULL) return QTSS_NotAModule; // Invoke the private initialization routine QTSS_PrivateArgs thePrivateArgs; thePrivateArgs.inServerAPIVersion = QTSS_API_VERSION; thePrivateArgs.inCallbacks = inCallbacks; thePrivateArgs.outStubLibraryVersion = 0; thePrivateArgs.outDispatchFunction = NULL; theErr = (inEntrypoint)(&thePrivateArgs); if (theErr != QTSS_NoErr) return theErr; if (thePrivateArgs.outStubLibraryVersion > thePrivateArgs.inServerAPIVersion) return QTSS_WrongVersion; // Set the dispatch function so we'll be able to invoke this module later on fDispatchFunc = thePrivateArgs.outDispatchFunction; //Log char msgStr[2048]; char* moduleName = NULL; (void)this->GetValueAsString (qtssModName, 0, &moduleName); qtss_snprintf(msgStr, sizeof(msgStr), "Module Loaded...%s [%s]", moduleName, (fFragment==NULL)?"static":"dynamic"); delete moduleName; QTSServerInterface::LogError(qtssMessageVerbosity, msgStr); return QTSS_NoErr; } QTSS_Error QTSSModule::LoadFromDisk(QTSS_MainEntryPointPtr* outEntrypoint) { static StrPtrLen sMainEntrypointName("_Main"); Assert(outEntrypoint != NULL); // Modules only need to be initialized if they reside on disk. if (fFragment == NULL) return QTSS_NoErr; if (!fFragment->IsValid()) return QTSS_NotAModule; // fPath is actually a path. Extract the file name. StrPtrLen theFileName(fPath); StringParser thePathParser(&theFileName); while (thePathParser.GetThru(&theFileName, kPathDelimiterChar)) ; Assert(theFileName.Len > 0); Assert(theFileName.Ptr != NULL); #ifdef __Win32__ StringParser theDLLTruncator(&theFileName); theDLLTruncator.ConsumeUntil(&theFileName, '.'); // strip off the ".DLL" #endif /** 08/16/01 quellish **/ #if __MacOSX__ StringParser theBundleTruncator(&theFileName); theBundleTruncator.ConsumeUntil(&theFileName, '.'); // strip off the ".bundle" #endif // At this point, theFileName points to the file name. Make this the module name. this->SetValue(qtssModName, 0, theFileName.Ptr, theFileName.Len, QTSSDictionary::kDontObeyReadOnly); // // The main entrypoint symbol name is the file name plus that _Main__ string up there. OSCharArrayDeleter theSymbolName(NEW char[theFileName.Len + sMainEntrypointName.Len + 2]); ::memcpy(theSymbolName, theFileName.Ptr, theFileName.Len); theSymbolName[theFileName.Len] = '\0'; ::strcat(theSymbolName, sMainEntrypointName.Ptr); *outEntrypoint = (QTSS_MainEntryPointPtr)fFragment->GetSymbol(theSymbolName.GetObject()); return QTSS_NoErr; } SInt32 QTSSModule::GetPrivateRoleIndex(QTSS_Role apiRole) { switch (apiRole) { // Map actual QTSS Role names to our private enum values. Turn on the proper one // in the role array case QTSS_Initialize_Role: return kInitializeRole ; case QTSS_Shutdown_Role: return kShutdownRole ; case QTSS_RTSPFilter_Role: return kRTSPFilterRole ; case QTSS_RTSPRoute_Role: return kRTSPRouteRole ; case QTSS_RTSPAuthenticate_Role: return kRTSPAthnRole ; case QTSS_RTSPAuthorize_Role: return kRTSPAuthRole ; case QTSS_RTSPPreProcessor_Role: return kRTSPPreProcessorRole ; case QTSS_RTSPRequest_Role: return kRTSPRequestRole ; case QTSS_RTSPPostProcessor_Role: return kRTSPPostProcessorRole ; case QTSS_RTSPSessionClosing_Role: return kRTSPSessionClosingRole ; case QTSS_RTPSendPackets_Role: return kRTPSendPacketsRole ; case QTSS_ClientSessionClosing_Role:return kClientSessionClosingRole; case QTSS_RTCPProcess_Role: return kRTCPProcessRole ; case QTSS_ErrorLog_Role: return kErrorLogRole ; case QTSS_RereadPrefs_Role: return kRereadPrefsRole ; case QTSS_OpenFile_Role: return kOpenFileRole ; case QTSS_OpenFilePreProcess_Role: return kOpenFilePreProcessRole ; case QTSS_AdviseFile_Role: return kAdviseFileRole ; case QTSS_ReadFile_Role: return kReadFileRole ; case QTSS_CloseFile_Role: return kCloseFileRole ; case QTSS_RequestEventFile_Role: return kRequestEventFileRole ; case QTSS_RTSPIncomingData_Role: return kRTSPIncomingDataRole ; case QTSS_StateChange_Role: return kStateChangeRole ; case QTSS_Interval_Role: return kTimedIntervalRole ; default: return -1; } } QTSS_Error QTSSModule::AddRole(QTSS_Role inRole) { // There can only be one QTSS_RTSPRequest processing module if ((inRole == QTSS_RTSPRequest_Role) && (sHasRTSPRequestModule)) return QTSS_RequestFailed; if ((inRole == QTSS_OpenFilePreProcess_Role) && (sHasOpenFileModule)) return QTSS_RequestFailed; #if 0// Allow multiple modules in QTSS v6.0. Enabling forces the first auth module There can be only one module registered for QTSS_RTSPAuthenticate_Role if ((inRole == QTSS_RTSPAuthenticate_Role) && (sHasRTSPAuthenticateModule)) return QTSS_RequestFailed; #endif SInt32 arrayID = GetPrivateRoleIndex(inRole); if (arrayID < 0) return QTSS_BadArgument; fRoleArray[arrayID] = true; /* switch (inRole) { // Map actual QTSS Role names to our private enum values. Turn on the proper one // in the role array case QTSS_Initialize_Role: fRoleArray[kInitializeRole] = true; break; case QTSS_Shutdown_Role: fRoleArray[kShutdownRole] = true; break; case QTSS_RTSPFilter_Role: fRoleArray[kRTSPFilterRole] = true; break; case QTSS_RTSPRoute_Role: fRoleArray[kRTSPRouteRole] = true; break; case QTSS_RTSPAuthenticate_Role: fRoleArray[kRTSPAthnRole] = true; break; case QTSS_RTSPAuthorize_Role: fRoleArray[kRTSPAuthRole] = true; break; case QTSS_RTSPPreProcessor_Role: fRoleArray[kRTSPPreProcessorRole] = true; break; case QTSS_RTSPRequest_Role: fRoleArray[kRTSPRequestRole] = true; break; case QTSS_RTSPPostProcessor_Role: fRoleArray[kRTSPPostProcessorRole] = true; break; case QTSS_RTSPSessionClosing_Role: fRoleArray[kRTSPSessionClosingRole] = true; break; case QTSS_RTPSendPackets_Role: fRoleArray[kRTPSendPacketsRole] = true; break; case QTSS_ClientSessionClosing_Role:fRoleArray[kClientSessionClosingRole] = true;break; case QTSS_RTCPProcess_Role: fRoleArray[kRTCPProcessRole] = true; break; case QTSS_ErrorLog_Role: fRoleArray[kErrorLogRole] = true; break; case QTSS_RereadPrefs_Role: fRoleArray[kRereadPrefsRole] = true; break; case QTSS_OpenFile_Role: fRoleArray[kOpenFileRole] = true; break; case QTSS_OpenFilePreProcess_Role: fRoleArray[kOpenFilePreProcessRole] = true; break; case QTSS_AdviseFile_Role: fRoleArray[kAdviseFileRole] = true; break; case QTSS_ReadFile_Role: fRoleArray[kReadFileRole] = true; break; case QTSS_CloseFile_Role: fRoleArray[kCloseFileRole] = true; break; case QTSS_RequestEventFile_Role: fRoleArray[kRequestEventFileRole] = true; break; case QTSS_RTSPIncomingData_Role: fRoleArray[kRTSPIncomingDataRole] = true; break; case QTSS_StateChange_Role: fRoleArray[kStateChangeRole] = true; break; case QTSS_Interval_Role: fRoleArray[kTimedIntervalRole] = true; break; default: return QTSS_BadArgument; } */ if (inRole == QTSS_RTSPRequest_Role) sHasRTSPRequestModule = true; if (inRole == QTSS_OpenFile_Role) sHasOpenFileModule = true; if (inRole == QTSS_RTSPAuthenticate_Role) sHasRTSPAuthenticateModule = true; // // Add this role to the array of roles attribute QTSS_Error theErr = this->SetValue(qtssModRoles, this->GetNumValues(qtssModRoles), &inRole, sizeof(inRole), QTSSDictionary::kDontObeyReadOnly); Assert(theErr == QTSS_NoErr); return QTSS_NoErr; } SInt64 QTSSModule::Run() { EventFlags events = this->GetEvents(); OSThreadDataSetter theSetter(&fModuleState, NULL); if (events & Task::kUpdateEvent) { // force us to update to a new idle time return fModuleState.idleTime;// If the module has requested idle time... } if (fRoleArray[kTimedIntervalRole]) { if (events & Task::kIdleEvent || fModuleState.globalLockRequested) { fModuleState.curModule = this; // this structure is setup in each thread fModuleState.curRole = QTSS_Interval_Role; // before invoking a module in a role. Sometimes fModuleState.eventRequested = false; fModuleState.curTask = this; if (fModuleState.globalLockRequested ) { fModuleState.globalLockRequested = false; fModuleState.isGlobalLocked = true; } (void)this->CallDispatch(QTSS_Interval_Role, NULL); fModuleState.isGlobalLocked = false; if (fModuleState.globalLockRequested) // call this request back locked return this->CallLocked(); return fModuleState.idleTime; // If the module has requested idle time... } } return 0; }