956 lines
35 KiB
C++
956 lines
35 KiB
C++
/*
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*
|
|
*/
|
|
/*
|
|
File: QTSSCallbacks.cpp
|
|
|
|
Contains: Implements QTSS Callback functions.
|
|
|
|
|
|
*/
|
|
|
|
#include "QTSSCallbacks.h"
|
|
#include "QTSSDictionary.h"
|
|
#include "QTSSStream.h"
|
|
#include "OSMemory.h"
|
|
#include "RTSPRequestInterface.h"
|
|
#include "RTPSession.h"
|
|
#include "OS.h"
|
|
#include "EventContext.h"
|
|
#include "Socket.h"
|
|
#include "QTSSFile.h"
|
|
#include "QTSSSocket.h"
|
|
#include "QTSServerInterface.h"
|
|
#include "QTSSDataConverter.h"
|
|
#include "QTSSModule.h"
|
|
|
|
#include <errno.h>
|
|
|
|
#define __QTSSCALLBACKS_DEBUG__ 0
|
|
#define debug_printf if (__QTSSCALLBACKS_DEBUG__) qtss_printf
|
|
|
|
|
|
void* QTSSCallbacks::QTSS_New(FourCharCode /*inMemoryIdentifier*/, UInt32 inSize)
|
|
{
|
|
//
|
|
// This callback is now deprecated because the server no longer uses FourCharCodes
|
|
// for memory debugging. For clients that still use it, the default, non-debugging
|
|
// version of New is used.
|
|
|
|
//return OSMemory::New(inSize, inMemoryIdentifier, false);
|
|
return OSMemory::New(inSize);
|
|
}
|
|
|
|
void QTSSCallbacks::QTSS_Delete(void* inMemory)
|
|
{
|
|
OSMemory::Delete(inMemory);
|
|
}
|
|
|
|
void QTSSCallbacks::QTSS_Milliseconds(SInt64* outMilliseconds)
|
|
{
|
|
if (outMilliseconds != NULL)
|
|
*outMilliseconds = OS::Milliseconds();
|
|
}
|
|
|
|
void QTSSCallbacks::QTSS_ConvertToUnixTime(SInt64 *inQTSS_MilliSecondsPtr, time_t* outSecondsPtr)
|
|
{
|
|
if ( (NULL != outSecondsPtr) && (NULL != inQTSS_MilliSecondsPtr) )
|
|
*outSecondsPtr = OS::TimeMilli_To_UnixTimeSecs(*inQTSS_MilliSecondsPtr);
|
|
}
|
|
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_AddRole(QTSS_Role inRole)
|
|
{
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// Roles can only be added before modules have had their Initialize role invoked.
|
|
if ((theState == NULL) || (theState->curRole != QTSS_Register_Role))
|
|
return QTSS_OutOfState;
|
|
|
|
return theState->curModule->AddRole(inRole);
|
|
}
|
|
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_LockObject(QTSS_Object inDictionary)
|
|
{
|
|
if (inDictionary == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
((QTSSDictionary*)inDictionary)->GetMutex()->Lock();
|
|
((QTSSDictionary*)inDictionary)->SetLocked(true);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_UnlockObject(QTSS_Object inDictionary)
|
|
{
|
|
if (inDictionary == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
((QTSSDictionary*)inDictionary)->SetLocked(false);
|
|
((QTSSDictionary*)inDictionary)->GetMutex()->Unlock();
|
|
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_CreateObjectType(QTSS_ObjectType* outType)
|
|
{
|
|
QTSS_ObjectType type = QTSSDictionaryMap::CreateNewMap();
|
|
if (type == 0)
|
|
return QTSS_RequestFailed;
|
|
|
|
*outType = type;
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_AddAttribute(QTSS_ObjectType inType, const char* inName, void* inUnused)
|
|
{
|
|
//
|
|
// This call is deprecated, make the new call with sensible default arguments
|
|
return QTSSCallbacks::QTSS_AddStaticAttribute(inType, inName, inUnused, qtssAttrDataTypeUnknown);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_AddInstanceAttribute(QTSS_Object inObject, const char* inAttrName, void* inUnused, QTSS_AttrDataType inAttrDataType)
|
|
{
|
|
Assert(inUnused == NULL);
|
|
if ((inObject == NULL) || (inAttrName == NULL))
|
|
return QTSS_BadArgument;
|
|
|
|
return ((QTSSDictionary*)inObject)->AddInstanceAttribute(inAttrName, NULL, inAttrDataType, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModeDelete | qtssAttrModePreempSafe);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_RemoveInstanceAttribute(QTSS_Object inObject, QTSS_AttributeID inID)
|
|
{
|
|
if (inObject == NULL || (inID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
|
|
return ((QTSSDictionary*)inObject)->RemoveInstanceAttribute(inID);
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_IDForAttr(QTSS_ObjectType inType, const char* inName, QTSS_AttributeID* outID)
|
|
{
|
|
if (outID == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
UInt32 theDictionaryIndex = QTSSDictionaryMap::GetMapIndex(inType);
|
|
if (theDictionaryIndex == QTSSDictionaryMap::kIllegalDictionary)
|
|
return QTSS_BadArgument;
|
|
|
|
return QTSSDictionaryMap::GetMap(theDictionaryIndex)->GetAttrID(inName, outID);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetAttrInfoByIndex(QTSS_Object inObject, UInt32 inIndex, QTSS_Object* outAttrInfoObject)
|
|
{
|
|
if (inObject == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
return ((QTSSDictionary*)inObject)->GetAttrInfoByIndex(inIndex, (QTSSAttrInfoDict**)outAttrInfoObject);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetAttrInfoByID(QTSS_Object inObject, QTSS_AttributeID inAttrID, QTSS_Object* outAttrInfoObject)
|
|
{
|
|
if (inObject == NULL || (inAttrID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
|
|
return ((QTSSDictionary*)inObject)->GetAttrInfoByID(inAttrID, (QTSSAttrInfoDict**)outAttrInfoObject);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetAttrInfoByName(QTSS_Object inObject, const char* inAttrName, QTSS_Object* outAttrInfoObject)
|
|
{
|
|
if (inObject == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
return ((QTSSDictionary*)inObject)->GetAttrInfoByName(inAttrName, (QTSSAttrInfoDict**)outAttrInfoObject);
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetValuePtr (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, void** outBuffer, UInt32* outLen)
|
|
{
|
|
if ((inDictionary == NULL) || (outBuffer == NULL) || (outLen == NULL) || (inID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
return ((QTSSDictionary*)inDictionary)->GetValuePtr(inID, inIndex, outBuffer, outLen);
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetValue (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, void* ioBuffer, UInt32* ioLen)
|
|
{
|
|
if (inDictionary == NULL || (inID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
return ((QTSSDictionary*)inDictionary)->GetValue(inID, inIndex, ioBuffer, ioLen);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetValueAsString (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, char** outString)
|
|
{
|
|
if (inDictionary == NULL)
|
|
return QTSS_BadArgument;
|
|
return ((QTSSDictionary*)inDictionary)->GetValueAsString(inID, inIndex, outString);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_TypeToTypeString(const QTSS_AttrDataType inType, char** outTypeString)
|
|
{
|
|
if (outTypeString == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
*outTypeString = QTSSDataConverter::TypeToTypeString(inType);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_TypeStringToType(char* inTypeString, QTSS_AttrDataType* outType)
|
|
{
|
|
if ((inTypeString == NULL) || (outType == NULL))
|
|
return QTSS_BadArgument;
|
|
|
|
*outType = QTSSDataConverter::TypeStringToType(inTypeString);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_StringToValue( char* inValueAsString, const QTSS_AttrDataType inType, void* ioBuffer, UInt32* ioBufSize)
|
|
{
|
|
return QTSSDataConverter::StringToValue(inValueAsString,inType,ioBuffer,ioBufSize);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_ValueToString( void* inValue, const UInt32 inValueLen, const QTSS_AttrDataType inType, char** outString)
|
|
{
|
|
if ((inValue == NULL) || (outString == NULL))
|
|
return QTSS_BadArgument;
|
|
|
|
*outString = QTSSDataConverter::ValueToString(inValue,inValueLen,inType);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SetValue (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, const void* inBuffer, UInt32 inLen)
|
|
{
|
|
if ((inDictionary == NULL) || ((inBuffer == NULL) && (inLen > 0)) || (inID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
return ((QTSSDictionary*)inDictionary)->SetValue(inID, inIndex, inBuffer, inLen);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SetValuePtr (QTSS_Object inDictionary, QTSS_AttributeID inID, const void* inBuffer, UInt32 inLen)
|
|
{
|
|
if ((inDictionary == NULL) || ((inBuffer == NULL) && (inLen > 0)))
|
|
return QTSS_BadArgument;
|
|
return ((QTSSDictionary*)inDictionary)->SetValuePtr(inID, inBuffer, inLen);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_CreateObject (QTSS_Object inDictionary, QTSS_AttributeID inID, QTSS_ObjectType inType, UInt32* outIndex, QTSS_Object* outCreatedObject)
|
|
{
|
|
if ((inDictionary == NULL) || (outCreatedObject == NULL) || (outIndex == NULL) || (inID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
|
|
QTSSDictionaryMap* theMap = NULL;
|
|
if (inType != qtssDynamicObjectType)
|
|
{
|
|
UInt32 theDictionaryIndex = QTSSDictionaryMap::GetMapIndex(inType);
|
|
if (theDictionaryIndex == QTSSDictionaryMap::kIllegalDictionary)
|
|
return QTSS_BadArgument;
|
|
|
|
theMap = QTSSDictionaryMap::GetMap(theDictionaryIndex);
|
|
}
|
|
|
|
return ((QTSSDictionary*)inDictionary)->CreateObjectValue(inID, outIndex, (QTSSDictionary**)outCreatedObject, theMap);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_GetNumValues (QTSS_Object inObject, QTSS_AttributeID inID, UInt32* outNumValues)
|
|
{
|
|
if ((inObject == NULL) || (outNumValues == NULL) || (inID == qtssIllegalAttrID) )
|
|
return QTSS_BadArgument;
|
|
|
|
*outNumValues = ((QTSSDictionary*)inObject)->GetNumValues(inID);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_RemoveValue (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex)
|
|
{
|
|
if (inObject == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
return ((QTSSDictionary*)inObject)->RemoveValue(inID, inIndex);
|
|
}
|
|
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Write(QTSS_StreamRef inStream, void* inBuffer, UInt32 inLen, UInt32* outLenWritten, UInt32 inFlags)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
QTSS_Error theErr = ((QTSSStream*)inStream)->Write(inBuffer, inLen, outLenWritten, inFlags);
|
|
|
|
// Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
|
|
// level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
|
|
// to replace them. So we have to replace them here.
|
|
if (theErr == EAGAIN)
|
|
return QTSS_WouldBlock;
|
|
else if (theErr > 0)
|
|
return QTSS_NotConnected;
|
|
else
|
|
return theErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_WriteV(QTSS_StreamRef inStream, iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength, UInt32* outLenWritten)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
QTSS_Error theErr = ((QTSSStream*)inStream)->WriteV(inVec, inNumVectors, inTotalLength, outLenWritten);
|
|
|
|
// Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
|
|
// level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
|
|
// to replace them. So we have to replace them here.
|
|
if (theErr == EAGAIN)
|
|
return QTSS_WouldBlock;
|
|
else if (theErr > 0)
|
|
return QTSS_NotConnected;
|
|
else
|
|
return theErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Flush(QTSS_StreamRef inStream)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
QTSS_Error theErr = ((QTSSStream*)inStream)->Flush();
|
|
|
|
// Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
|
|
// level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
|
|
// to replace them. So we have to replace them here.
|
|
if (theErr == EAGAIN)
|
|
return QTSS_WouldBlock;
|
|
else if (theErr > 0)
|
|
return QTSS_NotConnected;
|
|
else
|
|
return theErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Read(QTSS_StreamRef inStream, void* ioBuffer, UInt32 inBufLen, UInt32* outLengthRead)
|
|
{
|
|
if ((inStream == NULL) || (ioBuffer == NULL))
|
|
return QTSS_BadArgument;
|
|
QTSS_Error theErr = ((QTSSStream*)inStream)->Read(ioBuffer, inBufLen, outLengthRead);
|
|
|
|
// Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
|
|
// level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
|
|
// to replace them. So we have to replace them here.
|
|
if (theErr == EAGAIN)
|
|
return QTSS_WouldBlock;
|
|
else if (theErr > 0)
|
|
return QTSS_NotConnected;
|
|
else
|
|
return theErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Seek(QTSS_StreamRef inStream, UInt64 inNewPosition)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
return ((QTSSStream*)inStream)->Seek(inNewPosition);
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Advise(QTSS_StreamRef inStream, UInt64 inPosition, UInt32 inAdviseSize)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
return ((QTSSStream*)inStream)->Advise(inPosition, inAdviseSize);
|
|
}
|
|
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_OpenFileObject(char* inPath, QTSS_OpenFileFlags inFlags, QTSS_Object* outFileObject)
|
|
{
|
|
if ((inPath == NULL) || (outFileObject == NULL))
|
|
return QTSS_BadArgument;
|
|
|
|
//
|
|
// Create a new file object
|
|
QTSSFile* theNewFile = NEW QTSSFile();
|
|
QTSS_Error theErr = theNewFile->Open(inPath, inFlags);
|
|
|
|
if (theErr != QTSS_NoErr)
|
|
delete theNewFile; // No module wanted to open the file.
|
|
else
|
|
*outFileObject = theNewFile;
|
|
|
|
return theErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_CloseFileObject(QTSS_Object inFileObject)
|
|
{
|
|
if (inFileObject == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
QTSSFile* theFile = (QTSSFile*)inFileObject;
|
|
|
|
theFile->Close();
|
|
delete theFile;
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_CreateStreamFromSocket(int inFileDesc, QTSS_StreamRef* outStream)
|
|
{
|
|
if (outStream == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
if (inFileDesc < 0)
|
|
return QTSS_BadArgument;
|
|
|
|
//
|
|
// Create a new socket object
|
|
*outStream = (QTSS_StreamRef)NEW QTSSSocket(inFileDesc);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_DestroySocketStream(QTSS_StreamRef inStream)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
//
|
|
// Note that the QTSSSocket destructor will call close on its file descriptor.
|
|
// Calling module should not also close the file descriptor! (This is noted in the API)
|
|
QTSSSocket* theSocket = (QTSSSocket*)inStream;
|
|
delete theSocket;
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_AddService(const char* inServiceName, QTSS_ServiceFunctionPtr inFunctionPtr)
|
|
{
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// This may happen if this callback is occurring on module-created thread
|
|
if (theState == NULL)
|
|
return QTSS_OutOfState;
|
|
|
|
// Roles can only be added before modules have had their Initialize role invoked.
|
|
if (theState->curRole != QTSS_Register_Role)
|
|
return QTSS_OutOfState;
|
|
|
|
return QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServiceDictIndex)->
|
|
AddAttribute(inServiceName, (QTSS_AttrFunctionPtr)inFunctionPtr, qtssAttrDataTypeUnknown, qtssAttrModeRead);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_IDForService(const char* inTag, QTSS_ServiceID* outID)
|
|
{
|
|
return QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServiceDictIndex)->
|
|
GetAttrID(inTag, outID);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SendRTSPHeaders(QTSS_RTSPRequestObject inRef)
|
|
{
|
|
if (inRef == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
((RTSPRequestInterface*)inRef)->SendHeader();
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_AppendRTSPHeader(QTSS_RTSPRequestObject inRef,
|
|
QTSS_RTSPHeader inHeader,
|
|
char* inValue,
|
|
UInt32 inValueLen)
|
|
{
|
|
if ((inRef == NULL) || (inValue == NULL))
|
|
return QTSS_BadArgument;
|
|
if (inHeader >= qtssNumHeaders)
|
|
return QTSS_BadArgument;
|
|
|
|
StrPtrLen theValue(inValue, inValueLen);
|
|
((RTSPRequestInterface*)inRef)->AppendHeader(inHeader, &theValue);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SendStandardRTSPResponse(QTSS_RTSPRequestObject inRTSPRequest,
|
|
QTSS_Object inRTPInfo,
|
|
UInt32 inFlags)
|
|
{
|
|
if ((inRTSPRequest == NULL) || (inRTPInfo == NULL))
|
|
return QTSS_BadArgument;
|
|
|
|
switch (((RTSPRequestInterface*)inRTSPRequest)->GetMethod())
|
|
{
|
|
case qtssDescribeMethod:
|
|
((RTPSession*)inRTPInfo)->SendDescribeResponse((RTSPRequestInterface*)inRTSPRequest);
|
|
return QTSS_NoErr;
|
|
case qtssSetupMethod:
|
|
{
|
|
// Because QTSS_SendStandardRTSPResponse supports sending a proper 304 Not Modified on a SETUP,
|
|
// but a caller typically won't be adding a stream for a 304 response, we have the policy of
|
|
// making the caller pass in the QTSS_ClientSessionObject instead. That means we need to do
|
|
// different things here depending...
|
|
if (((RTSPRequestInterface*)inRTSPRequest)->GetStatus() == qtssRedirectNotModified)
|
|
(void)((RTPSession*)inRTPInfo)->DoSessionSetupResponse((RTSPRequestInterface*)inRTSPRequest);
|
|
else
|
|
{
|
|
if (inFlags & qtssSetupRespDontWriteSSRC)
|
|
((RTPStream*)inRTPInfo)->DisableSSRC();
|
|
else
|
|
((RTPStream*)inRTPInfo)->EnableSSRC();
|
|
|
|
((RTPStream*)inRTPInfo)->SendSetupResponse((RTSPRequestInterface*)inRTSPRequest);
|
|
}
|
|
|
|
return QTSS_NoErr;
|
|
}
|
|
case qtssPlayMethod:
|
|
case qtssRecordMethod:
|
|
((RTPSession*)inRTPInfo)->SendPlayResponse((RTSPRequestInterface*)inRTSPRequest, inFlags);
|
|
return QTSS_NoErr;
|
|
case qtssPauseMethod:
|
|
((RTPSession*)inRTPInfo)->SendPauseResponse((RTSPRequestInterface*)inRTSPRequest);
|
|
return QTSS_NoErr;
|
|
case qtssTeardownMethod:
|
|
((RTPSession*)inRTPInfo)->SendTeardownResponse((RTSPRequestInterface*)inRTSPRequest);
|
|
return QTSS_NoErr;
|
|
case qtssAnnounceMethod:
|
|
((RTPSession*)inRTPInfo)->SendAnnounceResponse((RTSPRequestInterface*)inRTSPRequest);
|
|
return QTSS_NoErr;
|
|
}
|
|
return QTSS_BadArgument;
|
|
}
|
|
|
|
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_AddRTPStream(QTSS_ClientSessionObject inClientSession, QTSS_RTSPRequestObject inRTSPRequest, QTSS_RTPStreamObject* outStream, QTSS_AddStreamFlags inFlags)
|
|
{
|
|
if ((inClientSession == NULL) || (inRTSPRequest == NULL) ||(outStream == NULL))
|
|
return QTSS_BadArgument;
|
|
return ((RTPSession*)inClientSession)->AddStream((RTSPRequestInterface*)inRTSPRequest, (RTPStream**)outStream, inFlags);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Play(QTSS_ClientSessionObject inClientSession, QTSS_RTSPRequestObject inRTSPRequest, QTSS_PlayFlags inPlayFlags)
|
|
{
|
|
if (inClientSession == NULL)
|
|
return QTSS_BadArgument;
|
|
return ((RTPSession*)inClientSession)->Play((RTSPRequestInterface*)inRTSPRequest, inPlayFlags);
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Pause(QTSS_ClientSessionObject inClientSession)
|
|
{
|
|
if (inClientSession == NULL)
|
|
return QTSS_BadArgument;
|
|
((RTPSession*)inClientSession)->Pause();
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Teardown(QTSS_ClientSessionObject inClientSession)
|
|
{
|
|
if (inClientSession == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
((RTPSession*)inClientSession)->Teardown();
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_RefreshTimeOut(QTSS_ClientSessionObject inClientSession)
|
|
{
|
|
if (inClientSession == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
((RTPSession*)inClientSession)->RefreshTimeouts();
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_RequestEvent(QTSS_StreamRef inStream, QTSS_EventType inEventMask)
|
|
{
|
|
// First thing to do is to alter the thread's module state to reflect the fact
|
|
// that an event is outstanding.
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
if (theState == NULL)
|
|
return QTSS_RequestFailed;
|
|
|
|
if (theState->curTask == NULL)
|
|
return QTSS_OutOfState;
|
|
|
|
theState->eventRequested = true;
|
|
|
|
// Now, tell this stream to be ready for the requested event
|
|
QTSSStream* theStream = (QTSSStream*)inStream;
|
|
theStream->SetTask(theState->curTask);
|
|
theStream->RequestEvent(inEventMask);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SignalStream(QTSS_StreamRef inStream)
|
|
{
|
|
if (inStream == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
QTSSStream* theStream = (QTSSStream*)inStream;
|
|
if (theStream->GetTask() != NULL)
|
|
theStream->GetTask()->Signal(Task::kReadEvent);
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SetIdleTimer(SInt64 inMsecToWait)
|
|
{
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// This may happen if this callback is occurring on module-created thread
|
|
if (theState == NULL)
|
|
return QTSS_RequestFailed;
|
|
|
|
if (theState->curTask == NULL)
|
|
return QTSS_OutOfState;
|
|
|
|
theState->eventRequested = true;
|
|
theState->idleTime = inMsecToWait;
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_SetIdleRoleTimer(SInt64 inMsecToWait)
|
|
{
|
|
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// This may happen if this callback is occurring on module-created thread
|
|
if (theState == NULL)
|
|
return QTSS_RequestFailed;
|
|
|
|
if (theState->curModule == NULL)
|
|
return QTSS_RequestFailed;
|
|
|
|
|
|
QTSSModule* theModule = theState->curModule;
|
|
QTSS_ModuleState* thePrivateModuleState = theModule->GetModuleState();
|
|
thePrivateModuleState->idleTime = inMsecToWait;
|
|
theModule->Signal(Task::kUpdateEvent);
|
|
|
|
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_RequestLockedCallback()
|
|
{
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// This may happen if this callback is occurring on module-created thread
|
|
if (theState == NULL)
|
|
return QTSS_RequestFailed;
|
|
|
|
if (theState->curTask == NULL)
|
|
return QTSS_OutOfState;
|
|
|
|
theState->globalLockRequested = true; //x
|
|
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
Bool16 QTSSCallbacks::QTSS_IsGlobalLocked()
|
|
{
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// This may happen if this callback is occurring on module-created thread
|
|
if (theState == NULL)
|
|
return false;
|
|
|
|
if (theState->curTask == NULL)
|
|
return false;
|
|
|
|
return theState->isGlobalLocked;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_UnlockGlobalLock()
|
|
{
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
// This may happen if this callback is occurring on module-created thread
|
|
if (theState == NULL)
|
|
return QTSS_RequestFailed;
|
|
|
|
if (theState->curTask == NULL)
|
|
return QTSS_OutOfState;
|
|
|
|
((Task *)OSThread::GetCurrent())->GlobalUnlock();
|
|
|
|
theState->globalLockRequested = false;
|
|
theState->isGlobalLocked = false;
|
|
|
|
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Authenticate(const char* inAuthUserName, const char* inAuthResourceLocalPath, const char* inAuthMoviesDir, QTSS_ActionFlags inAuthRequestAction, QTSS_AuthScheme inAuthScheme, QTSS_RTSPRequestObject ioAuthRequestObject)
|
|
{
|
|
if((inAuthUserName == NULL) || (inAuthResourceLocalPath == NULL) || (inAuthMoviesDir == NULL) || (ioAuthRequestObject == NULL))
|
|
return QTSS_BadArgument;
|
|
if(inAuthRequestAction == qtssActionFlagsNoFlags)
|
|
return QTSS_BadArgument;
|
|
if(inAuthScheme == qtssAuthNone)
|
|
return QTSS_BadArgument;
|
|
|
|
// First create a RTSPRequestInterface object
|
|
// There is no session attached to it, so just pass in NULL for the RTSPSession
|
|
RTSPRequestInterface *request = (RTSPRequestInterface *) ioAuthRequestObject;
|
|
// Set all the attributes required by the authentication module, using the input values
|
|
(void) request->SetValue(qtssRTSPReqUserName, 0, inAuthUserName , ::strlen(inAuthUserName), QTSSDictionary::kDontObeyReadOnly);
|
|
(void) request->SetValue(qtssRTSPReqLocalPath, 0, inAuthResourceLocalPath , ::strlen(inAuthResourceLocalPath), QTSSDictionary::kDontObeyReadOnly);
|
|
(void) request->SetValue(qtssRTSPReqRootDir, 0, inAuthMoviesDir , ::strlen(inAuthMoviesDir), QTSSDictionary::kNoFlags);
|
|
(void) request->SetValue(qtssRTSPReqAction, 0, (const void *)&inAuthRequestAction , sizeof(QTSS_ActionFlags), QTSSDictionary::kNoFlags);
|
|
(void) request->SetValue(qtssRTSPReqAuthScheme, 0, (const void *)&inAuthScheme , sizeof(QTSS_AuthScheme), QTSSDictionary::kDontObeyReadOnly);
|
|
QTSSUserProfile *profile = request->GetUserProfile();
|
|
(void) profile->SetValue(qtssUserName, 0, inAuthUserName, ::strlen(inAuthUserName), QTSSDictionary::kDontObeyReadOnly);
|
|
|
|
|
|
// Because this is a role being executed from inside a callback, we need to
|
|
// make sure that QTSS_RequestEvent will not work.
|
|
Task* curTask = NULL;
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
if (theState != NULL)
|
|
curTask = theState->curTask;
|
|
|
|
// Setup the authentication param block
|
|
QTSS_RoleParams theAuthenticationParams;
|
|
theAuthenticationParams.rtspAthnParams.inRTSPRequest = request;
|
|
|
|
QTSS_Error theErr = QTSS_RequestFailed;
|
|
|
|
UInt32 x = 0;
|
|
UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPAthnRole);
|
|
QTSSModule* theModulePtr = NULL;
|
|
Bool16 allowedDefault = QTSServerInterface::GetServer()->GetPrefs()->GetAllowGuestDefault();
|
|
Bool16 allowed = allowedDefault; //server pref?
|
|
Bool16 hasUser = false;
|
|
Bool16 handled = false;
|
|
|
|
|
|
// Call all the modules that are registered for the RTSP Authorize Role
|
|
for ( ; x < numModules; x++)
|
|
{
|
|
request->SetAllowed(allowedDefault);
|
|
request->SetHasUser(false);
|
|
request->SetAuthHandled(false);
|
|
|
|
debug_printf(" QTSSCallbacks::QTSS_Authenticate calling module module = %lu numModules=%lu\n", x,numModules);
|
|
theModulePtr = QTSServerInterface::GetModule(QTSSModule::kRTSPAthnRole, x);
|
|
theErr = QTSS_NoErr;
|
|
if (theModulePtr)
|
|
{
|
|
theErr = theModulePtr->CallDispatch(QTSS_RTSPAuthenticate_Role, &theAuthenticationParams);
|
|
debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu ModuleError=%ld\n", x,numModules, theErr);
|
|
}
|
|
else
|
|
{
|
|
debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu is NULL! numModules=%lu\n", x,numModules);
|
|
continue;
|
|
}
|
|
allowed = request->GetAllowed();
|
|
hasUser = request->GetHasUser();
|
|
handled = request->GetAuthHandled();
|
|
debug_printf("QTSSCallbacks::QTSS_Authenticate allowedDefault =%d allowed= %d hasUser = %d handled=%d \n",allowedDefault, allowed,hasUser, handled);
|
|
|
|
|
|
if (hasUser || handled ) //See RTSPSession.cpp::Run state=kAuthenticatingRequest
|
|
{
|
|
debug_printf(" QTSSCallbacks::QTSS_Authenticate skipping other modules fCurrentModule = %lu numModules=%lu\n", x,numModules);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Reset the curTask to what it was before this role started
|
|
if (theState != NULL)
|
|
theState->curTask = curTask;
|
|
|
|
return theErr;
|
|
}
|
|
|
|
QTSS_Error QTSSCallbacks::QTSS_Authorize(QTSS_RTSPRequestObject inAuthRequestObject, char** outAuthRealm, Bool16* outAuthUserAllowed)
|
|
{
|
|
RTSPRequestInterface* request = (RTSPRequestInterface *) inAuthRequestObject;
|
|
if (request == NULL)
|
|
return QTSS_BadArgument;
|
|
|
|
// Because this is a role being executed from inside a callback, we need to
|
|
// make sure that QTSS_RequestEvent will not work.
|
|
Task* curTask = NULL;
|
|
QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
|
|
if (OSThread::GetCurrent() != NULL)
|
|
theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
|
|
|
|
if (theState != NULL)
|
|
curTask = theState->curTask;
|
|
|
|
QTSS_RoleParams theParams;
|
|
theParams.rtspRequestParams.inRTSPSession = NULL;
|
|
theParams.rtspRequestParams.inRTSPRequest = request;
|
|
theParams.rtspRequestParams.inClientSession = NULL;
|
|
|
|
QTSS_Error theErr = QTSS_RequestFailed;
|
|
UInt32 x = 0;
|
|
UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPAuthRole);
|
|
QTSSModule* theModulePtr = NULL;
|
|
Bool16 allowedDefault = QTSServerInterface::GetServer()->GetPrefs()->GetAllowGuestDefault();
|
|
*outAuthUserAllowed = allowedDefault;
|
|
Bool16 allowed = allowedDefault; //server pref?
|
|
Bool16 hasUser = false;
|
|
Bool16 handled = false;
|
|
|
|
|
|
// Call all the modules that are registered for the RTSP Authorize Role
|
|
|
|
for ( ; x < numModules; x++)
|
|
{
|
|
request->SetAllowed(true);
|
|
request->SetHasUser(false);
|
|
request->SetAuthHandled(false);
|
|
|
|
debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu\n", x,numModules);
|
|
theModulePtr = QTSServerInterface::GetModule(QTSSModule::kRTSPAuthRole, x);
|
|
theErr = QTSS_NoErr;
|
|
if (theModulePtr)
|
|
{
|
|
if (__QTSSCALLBACKS_DEBUG__)
|
|
theModulePtr->GetValue(qtssModName)->PrintStr("QTSSModule::CallDispatch ENTER module=", "\n");
|
|
|
|
theErr = theModulePtr->CallDispatch(QTSS_RTSPAuthorize_Role, &theParams);
|
|
debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu ModuleError=%ld\n", x,numModules, theErr);
|
|
}
|
|
else
|
|
{ debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu is NULL! numModules=%lu\n", x,numModules);
|
|
continue;
|
|
}
|
|
|
|
allowed = request->GetAllowed();
|
|
hasUser = request->GetHasUser();
|
|
handled = request->GetAuthHandled();
|
|
debug_printf("QTSSCallbacks::QTSS_Authorize allowedDefault =%d allowed= %d hasUser = %d handled=%d \n",allowedDefault, allowed,hasUser, handled);
|
|
|
|
*outAuthUserAllowed = allowed;
|
|
//notes:
|
|
//if (allowed && !handled) break; //old module
|
|
//if (!allowed && handled) /new module handled the request but not authorized keep trying
|
|
//if (allowed && handled) //new module allowed but keep trying in case someone denies.
|
|
|
|
if (!allowed && !handled) //old module break on !allowed
|
|
{
|
|
debug_printf("RTSPSession.cpp::Run(kAuthorizingRequest) skipping other modules fCurrentModule = %lu numModules=%lu\n", x,numModules);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// outAuthRealm is set to the realm that is given by the module that has denied authentication
|
|
StrPtrLen* realm = request->GetValue(qtssRTSPReqURLRealm);
|
|
*outAuthRealm = realm->GetAsCString();
|
|
|
|
return theErr;
|
|
}
|
|
|
|
void QTSSCallbacks::QTSS_LockStdLib()
|
|
{
|
|
OS::GetStdLibMutex()->Lock();
|
|
}
|
|
|
|
void QTSSCallbacks::QTSS_UnlockStdLib()
|
|
{
|
|
OS::GetStdLibMutex()->Unlock();
|
|
}
|
|
|