1133 lines
40 KiB
C++
1133 lines
40 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: QTSSModuleUtils.cpp
|
||
|
|
||
|
Contains: Implements utility routines defined in QTSSModuleUtils.h.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "QTSSModuleUtils.h"
|
||
|
#include "QTSS_Private.h"
|
||
|
|
||
|
#include "StrPtrLen.h"
|
||
|
#include "OSArrayObjectDeleter.h"
|
||
|
#include "OSMemory.h"
|
||
|
#include "MyAssert.h"
|
||
|
#include "StringFormatter.h"
|
||
|
#include "ResizeableStringFormatter.h"
|
||
|
#include "QTAccessFile.h"
|
||
|
#include "StringParser.h"
|
||
|
#include "SafeStdLib.h"
|
||
|
#ifndef __Win32__
|
||
|
#include <netinet/in.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef __solaris__
|
||
|
#include <limits.h>
|
||
|
#endif
|
||
|
|
||
|
QTSS_TextMessagesObject QTSSModuleUtils::sMessages = NULL;
|
||
|
QTSS_ServerObject QTSSModuleUtils::sServer = NULL;
|
||
|
QTSS_StreamRef QTSSModuleUtils::sErrorLog = NULL;
|
||
|
Bool16 QTSSModuleUtils::sEnableRTSPErrorMsg = false;
|
||
|
QTSS_ErrorVerbosity QTSSModuleUtils::sMissingPrefVerbosity = qtssMessageVerbosity;
|
||
|
|
||
|
void QTSSModuleUtils::Initialize(QTSS_TextMessagesObject inMessages,
|
||
|
QTSS_ServerObject inServer,
|
||
|
QTSS_StreamRef inErrorLog)
|
||
|
{
|
||
|
sMessages = inMessages;
|
||
|
sServer = inServer;
|
||
|
sErrorLog = inErrorLog;
|
||
|
}
|
||
|
|
||
|
QTSS_Error QTSSModuleUtils::ReadEntireFile(char* inPath, StrPtrLen* outData, QTSS_TimeVal inModDate, QTSS_TimeVal* outModDate)
|
||
|
{
|
||
|
|
||
|
QTSS_Object theFileObject = NULL;
|
||
|
QTSS_Error theErr = QTSS_NoErr;
|
||
|
|
||
|
outData->Ptr = NULL;
|
||
|
outData->Len = 0;
|
||
|
|
||
|
do {
|
||
|
|
||
|
// Use the QTSS file system API to read the file
|
||
|
theErr = QTSS_OpenFileObject(inPath, 0, &theFileObject);
|
||
|
if (theErr != QTSS_NoErr)
|
||
|
break;
|
||
|
|
||
|
UInt32 theParamLen = 0;
|
||
|
QTSS_TimeVal* theModDate = NULL;
|
||
|
theErr = QTSS_GetValuePtr(theFileObject, qtssFlObjModDate, 0, (void**)&theModDate, &theParamLen);
|
||
|
Assert(theParamLen == sizeof(QTSS_TimeVal));
|
||
|
if(theParamLen != sizeof(QTSS_TimeVal))
|
||
|
break;
|
||
|
if(outModDate != NULL)
|
||
|
*outModDate = (QTSS_TimeVal)*theModDate;
|
||
|
|
||
|
if(inModDate != -1) {
|
||
|
// If file hasn't been modified since inModDate, don't have to read the file
|
||
|
if(*theModDate <= inModDate)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
theParamLen = 0;
|
||
|
UInt64* theLength = NULL;
|
||
|
theErr = QTSS_GetValuePtr(theFileObject, qtssFlObjLength, 0, (void**)&theLength, &theParamLen);
|
||
|
if (theParamLen != sizeof(UInt64))
|
||
|
break;
|
||
|
|
||
|
if (*theLength > kSInt32_Max)
|
||
|
break;
|
||
|
|
||
|
// Allocate memory for the file data
|
||
|
outData->Ptr = NEW char[ (SInt32) (*theLength + 1) ];
|
||
|
outData->Len = (SInt32) *theLength;
|
||
|
outData->Ptr[outData->Len] = 0;
|
||
|
|
||
|
// Read the data
|
||
|
UInt32 recvLen = 0;
|
||
|
theErr = QTSS_Read(theFileObject, outData->Ptr, outData->Len, &recvLen);
|
||
|
if (theErr != QTSS_NoErr)
|
||
|
{
|
||
|
outData->Delete();
|
||
|
break;
|
||
|
}
|
||
|
Assert(outData->Len == recvLen);
|
||
|
|
||
|
}while(false);
|
||
|
|
||
|
// Close the file
|
||
|
if(theFileObject != NULL) {
|
||
|
theErr = QTSS_CloseFileObject(theFileObject);
|
||
|
}
|
||
|
|
||
|
return theErr;
|
||
|
}
|
||
|
|
||
|
void QTSSModuleUtils::SetupSupportedMethods(QTSS_Object inServer, QTSS_RTSPMethod* inMethodArray, UInt32 inNumMethods)
|
||
|
{
|
||
|
// Report to the server that this module handles DESCRIBE, SETUP, PLAY, PAUSE, and TEARDOWN
|
||
|
UInt32 theNumMethods = 0;
|
||
|
(void)QTSS_GetNumValues(inServer, qtssSvrHandledMethods, &theNumMethods);
|
||
|
|
||
|
for (UInt32 x = 0; x < inNumMethods; x++)
|
||
|
(void)QTSS_SetValue(inServer, qtssSvrHandledMethods, theNumMethods++, (void*)&inMethodArray[x], sizeof(inMethodArray[x]));
|
||
|
}
|
||
|
|
||
|
void QTSSModuleUtils::LogError( QTSS_ErrorVerbosity inVerbosity,
|
||
|
QTSS_AttributeID inTextMessage,
|
||
|
UInt32 /*inErrNumber*/,
|
||
|
char* inArgument,
|
||
|
char* inArg2)
|
||
|
{
|
||
|
static char* sEmptyArg = "";
|
||
|
|
||
|
if (sMessages == NULL)
|
||
|
return;
|
||
|
|
||
|
// Retrieve the specified text message from the text messages dictionary.
|
||
|
|
||
|
StrPtrLen theMessage;
|
||
|
(void)QTSS_GetValuePtr(sMessages, inTextMessage, 0, (void**)&theMessage.Ptr, &theMessage.Len);
|
||
|
if ((theMessage.Ptr == NULL) || (theMessage.Len == 0))
|
||
|
(void)QTSS_GetValuePtr(sMessages, qtssMsgNoMessage, 0, (void**)&theMessage.Ptr, &theMessage.Len);
|
||
|
|
||
|
if ((theMessage.Ptr == NULL) || (theMessage.Len == 0))
|
||
|
return;
|
||
|
|
||
|
// qtss_sprintf and ::strlen will crash if inArgument is NULL
|
||
|
if (inArgument == NULL)
|
||
|
inArgument = sEmptyArg;
|
||
|
if (inArg2 == NULL)
|
||
|
inArg2 = sEmptyArg;
|
||
|
|
||
|
// Create a new string, and put the argument into the new string.
|
||
|
|
||
|
UInt32 theMessageLen = theMessage.Len + ::strlen(inArgument) + ::strlen(inArg2);
|
||
|
|
||
|
OSCharArrayDeleter theLogString(NEW char[theMessageLen + 1]);
|
||
|
qtss_sprintf(theLogString.GetObject(), theMessage.Ptr, inArgument, inArg2);
|
||
|
Assert(theMessageLen >= ::strlen(theLogString.GetObject()));
|
||
|
|
||
|
(void)QTSS_Write(sErrorLog, theLogString.GetObject(), ::strlen(theLogString.GetObject()),
|
||
|
NULL, inVerbosity);
|
||
|
}
|
||
|
|
||
|
void QTSSModuleUtils::LogErrorStr( QTSS_ErrorVerbosity inVerbosity, char* inMessage)
|
||
|
{
|
||
|
if (inMessage == NULL) return;
|
||
|
(void)QTSS_Write(sErrorLog, inMessage, ::strlen(inMessage), NULL, inVerbosity);
|
||
|
}
|
||
|
|
||
|
|
||
|
void QTSSModuleUtils::LogPrefErrorStr( QTSS_ErrorVerbosity inVerbosity, char* preference, char* inMessage)
|
||
|
{
|
||
|
if (inMessage == NULL || preference == NULL)
|
||
|
{ Assert(0);
|
||
|
return;
|
||
|
}
|
||
|
char buffer[1024];
|
||
|
|
||
|
qtss_snprintf(buffer,sizeof(buffer), "Server preference %s %s", preference, inMessage);
|
||
|
|
||
|
(void)QTSS_Write(sErrorLog, buffer, ::strlen(buffer), NULL, inVerbosity);
|
||
|
}
|
||
|
|
||
|
|
||
|
char* QTSSModuleUtils::GetFullPath( QTSS_RTSPRequestObject inRequest,
|
||
|
QTSS_AttributeID whichFileType,
|
||
|
UInt32* outLen,
|
||
|
StrPtrLen* suffix)
|
||
|
{
|
||
|
Assert(outLen != NULL);
|
||
|
|
||
|
(void)QTSS_LockObject(inRequest);
|
||
|
// Get the proper file path attribute. This may return an error if
|
||
|
// the file type is qtssFilePathTrunc attr, because there may be no path
|
||
|
// once its truncated. That's ok. In that case, we just won't append a path.
|
||
|
StrPtrLen theFilePath;
|
||
|
(void)QTSS_GetValuePtr(inRequest, whichFileType, 0, (void**)&theFilePath.Ptr, &theFilePath.Len);
|
||
|
|
||
|
StrPtrLen theRootDir;
|
||
|
QTSS_Error theErr = QTSS_GetValuePtr(inRequest, qtssRTSPReqRootDir, 0, (void**)&theRootDir.Ptr, &theRootDir.Len);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
|
||
|
//trim off extra / characters before concatenating
|
||
|
// so root/ + /path instead of becoming root//path is now root/path as it should be.
|
||
|
|
||
|
if (theRootDir.Len && theRootDir.Ptr[theRootDir.Len -1] == kPathDelimiterChar
|
||
|
&& theFilePath.Len && theFilePath.Ptr[0] == kPathDelimiterChar)
|
||
|
{
|
||
|
char *thePathEnd = &(theFilePath.Ptr[theFilePath.Len]);
|
||
|
while (theFilePath.Ptr != thePathEnd)
|
||
|
{
|
||
|
if (*theFilePath.Ptr != kPathDelimiterChar)
|
||
|
break;
|
||
|
|
||
|
theFilePath.Ptr ++;
|
||
|
theFilePath.Len --;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//construct a full path out of the root dir path for this request,
|
||
|
//and the url path.
|
||
|
*outLen = theFilePath.Len + theRootDir.Len + 2;
|
||
|
if (suffix != NULL)
|
||
|
*outLen += suffix->Len;
|
||
|
|
||
|
char* theFullPath = NEW char[*outLen];
|
||
|
|
||
|
//write all the pieces of the path into this new buffer.
|
||
|
StringFormatter thePathFormatter(theFullPath, *outLen);
|
||
|
thePathFormatter.Put(theRootDir);
|
||
|
thePathFormatter.Put(theFilePath);
|
||
|
if (suffix != NULL)
|
||
|
thePathFormatter.Put(*suffix);
|
||
|
thePathFormatter.PutTerminator();
|
||
|
|
||
|
*outLen = *outLen - 2;
|
||
|
|
||
|
(void)QTSS_UnlockObject(inRequest);
|
||
|
|
||
|
return theFullPath;
|
||
|
}
|
||
|
|
||
|
QTSS_Error QTSSModuleUtils::AppendRTPMetaInfoHeader( QTSS_RTSPRequestObject inRequest,
|
||
|
StrPtrLen* inRTPMetaInfoHeader,
|
||
|
RTPMetaInfoPacket::FieldID* inFieldIDArray)
|
||
|
{
|
||
|
//
|
||
|
// For formatting the response header
|
||
|
char tempBuffer[128];
|
||
|
ResizeableStringFormatter theFormatter(tempBuffer, 128);
|
||
|
|
||
|
StrPtrLen theHeader(*inRTPMetaInfoHeader);
|
||
|
|
||
|
//
|
||
|
// For marking which fields were requested by the client
|
||
|
Bool16 foundFieldArray[RTPMetaInfoPacket::kNumFields];
|
||
|
::memset(foundFieldArray, 0, sizeof(Bool16) * RTPMetaInfoPacket::kNumFields);
|
||
|
|
||
|
char* theEndP = theHeader.Ptr + theHeader.Len;
|
||
|
UInt16 fieldNameValue = 0;
|
||
|
|
||
|
while (theHeader.Ptr <= (theEndP - sizeof(RTPMetaInfoPacket::FieldName)))
|
||
|
{
|
||
|
RTPMetaInfoPacket::FieldName* theFieldName = (RTPMetaInfoPacket::FieldName*)theHeader.Ptr;
|
||
|
::memcpy (&fieldNameValue, theFieldName, sizeof(UInt16));
|
||
|
|
||
|
RTPMetaInfoPacket::FieldIndex theFieldIndex = RTPMetaInfoPacket::GetFieldIndexForName(ntohs(fieldNameValue));
|
||
|
|
||
|
//
|
||
|
// This field is not supported (not in the field ID array), so
|
||
|
// don't put it in the response
|
||
|
if ((theFieldIndex == RTPMetaInfoPacket::kIllegalField) ||
|
||
|
(inFieldIDArray[theFieldIndex] == RTPMetaInfoPacket::kFieldNotUsed))
|
||
|
{
|
||
|
theHeader.Ptr += 3;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark that this field has been requested by the client
|
||
|
foundFieldArray[theFieldIndex] = true;
|
||
|
|
||
|
//
|
||
|
// This field is good to go... put it in the response
|
||
|
theFormatter.Put(theHeader.Ptr, sizeof(RTPMetaInfoPacket::FieldName));
|
||
|
|
||
|
if (inFieldIDArray[theFieldIndex] != RTPMetaInfoPacket::kUncompressed)
|
||
|
{
|
||
|
//
|
||
|
// If the caller wants this field to be compressed (there
|
||
|
// is an ID associated with the field), put the ID in the response
|
||
|
theFormatter.PutChar('=');
|
||
|
theFormatter.Put(inFieldIDArray[theFieldIndex]);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Field separator
|
||
|
theFormatter.PutChar(';');
|
||
|
|
||
|
//
|
||
|
// Skip onto the next field name in the header
|
||
|
theHeader.Ptr += 3;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Go through the caller's FieldID array, and turn off the fields
|
||
|
// that were not requested by the client.
|
||
|
for (UInt32 x = 0; x < RTPMetaInfoPacket::kNumFields; x++)
|
||
|
{
|
||
|
if (!foundFieldArray[x])
|
||
|
inFieldIDArray[x] = RTPMetaInfoPacket::kFieldNotUsed;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// No intersection between requested headers and supported headers!
|
||
|
if (theFormatter.GetCurrentOffset() == 0)
|
||
|
return QTSS_ValueNotFound; // Not really the greatest error!
|
||
|
|
||
|
//
|
||
|
// When appending the header to the response, strip off the last ';'.
|
||
|
// It's not needed.
|
||
|
return QTSS_AppendRTSPHeader(inRequest, qtssXRTPMetaInfoHeader, theFormatter.GetBufPtr(), theFormatter.GetCurrentOffset() - 1);
|
||
|
}
|
||
|
|
||
|
QTSS_Error QTSSModuleUtils::SendErrorResponse( QTSS_RTSPRequestObject inRequest,
|
||
|
QTSS_RTSPStatusCode inStatusCode,
|
||
|
QTSS_AttributeID inTextMessage,
|
||
|
StrPtrLen* inStringArg)
|
||
|
{
|
||
|
static Bool16 sFalse = false;
|
||
|
|
||
|
//set RTSP headers necessary for this error response message
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode));
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse));
|
||
|
StringFormatter theErrorMsgFormatter(NULL, 0);
|
||
|
char *messageBuffPtr = NULL;
|
||
|
|
||
|
if (sEnableRTSPErrorMsg)
|
||
|
{
|
||
|
// Retrieve the specified message out of the text messages dictionary.
|
||
|
StrPtrLen theMessage;
|
||
|
(void)QTSS_GetValuePtr(sMessages, inTextMessage, 0, (void**)&theMessage.Ptr, &theMessage.Len);
|
||
|
|
||
|
if ((theMessage.Ptr == NULL) || (theMessage.Len == 0))
|
||
|
{
|
||
|
// If we couldn't find the specified message, get the default
|
||
|
// "No Message" message, and return that to the client instead.
|
||
|
|
||
|
(void)QTSS_GetValuePtr(sMessages, qtssMsgNoMessage, 0, (void**)&theMessage.Ptr, &theMessage.Len);
|
||
|
}
|
||
|
Assert(theMessage.Ptr != NULL);
|
||
|
Assert(theMessage.Len > 0);
|
||
|
|
||
|
// Allocate a temporary buffer for the error message, and format the error message
|
||
|
// into that buffer
|
||
|
UInt32 theMsgLen = 256;
|
||
|
if (inStringArg != NULL)
|
||
|
theMsgLen += inStringArg->Len;
|
||
|
|
||
|
messageBuffPtr = NEW char[theMsgLen];
|
||
|
messageBuffPtr[0] = 0;
|
||
|
theErrorMsgFormatter.Set(messageBuffPtr, theMsgLen);
|
||
|
//
|
||
|
// Look for a %s in the string, and if one exists, replace it with the
|
||
|
// argument passed into this function.
|
||
|
|
||
|
//we can safely assume that message is in fact NULL terminated
|
||
|
char* stringLocation = ::strstr(theMessage.Ptr, "%s");
|
||
|
if (stringLocation != NULL)
|
||
|
{
|
||
|
//write first chunk
|
||
|
theErrorMsgFormatter.Put(theMessage.Ptr, stringLocation - theMessage.Ptr);
|
||
|
|
||
|
if (inStringArg != NULL && inStringArg->Len > 0)
|
||
|
{
|
||
|
//write string arg if it exists
|
||
|
theErrorMsgFormatter.Put(inStringArg->Ptr, inStringArg->Len);
|
||
|
stringLocation += 2;
|
||
|
}
|
||
|
//write last chunk
|
||
|
theErrorMsgFormatter.Put(stringLocation, (theMessage.Ptr + theMessage.Len) - stringLocation);
|
||
|
}
|
||
|
else
|
||
|
theErrorMsgFormatter.Put(theMessage);
|
||
|
|
||
|
|
||
|
char buff[32];
|
||
|
qtss_sprintf(buff,"%"_U32BITARG_"",theErrorMsgFormatter.GetBytesWritten());
|
||
|
(void)QTSS_AppendRTSPHeader(inRequest, qtssContentLengthHeader, buff, ::strlen(buff));
|
||
|
}
|
||
|
|
||
|
//send the response header. In all situations where errors could happen, we
|
||
|
//don't really care, cause there's nothing we can do anyway!
|
||
|
(void)QTSS_SendRTSPHeaders(inRequest);
|
||
|
|
||
|
//
|
||
|
// Now that we've formatted the message into the temporary buffer,
|
||
|
// write it out to the request stream and the Client Session object
|
||
|
(void)QTSS_Write(inRequest, theErrorMsgFormatter.GetBufPtr(), theErrorMsgFormatter.GetBytesWritten(), NULL, 0);
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMsgFormatter.GetBufPtr(), theErrorMsgFormatter.GetBytesWritten());
|
||
|
|
||
|
delete [] messageBuffPtr;
|
||
|
return QTSS_RequestFailed;
|
||
|
}
|
||
|
|
||
|
QTSS_Error QTSSModuleUtils::SendErrorResponseWithMessage( QTSS_RTSPRequestObject inRequest,
|
||
|
QTSS_RTSPStatusCode inStatusCode,
|
||
|
StrPtrLen* inErrorMessagePtr)
|
||
|
{
|
||
|
static Bool16 sFalse = false;
|
||
|
|
||
|
//set RTSP headers necessary for this error response message
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode));
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse));
|
||
|
StrPtrLen theErrorMessage(NULL, 0);
|
||
|
|
||
|
if (sEnableRTSPErrorMsg)
|
||
|
{
|
||
|
Assert(inErrorMessagePtr != NULL);
|
||
|
//Assert(inErrorMessagePtr->Ptr != NULL);
|
||
|
//Assert(inErrorMessagePtr->Len != 0);
|
||
|
theErrorMessage.Set(inErrorMessagePtr->Ptr, inErrorMessagePtr->Len);
|
||
|
|
||
|
char buff[32];
|
||
|
qtss_sprintf(buff,"%"_U32BITARG_"",inErrorMessagePtr->Len);
|
||
|
(void)QTSS_AppendRTSPHeader(inRequest, qtssContentLengthHeader, buff, ::strlen(buff));
|
||
|
}
|
||
|
|
||
|
//send the response header. In all situations where errors could happen, we
|
||
|
//don't really care, cause there's nothing we can do anyway!
|
||
|
(void)QTSS_SendRTSPHeaders(inRequest);
|
||
|
|
||
|
//
|
||
|
// Now that we've formatted the message into the temporary buffer,
|
||
|
// write it out to the request stream and the Client Session object
|
||
|
(void)QTSS_Write(inRequest, theErrorMessage.Ptr, theErrorMessage.Len, NULL, 0);
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMessage.Ptr, theErrorMessage.Len);
|
||
|
|
||
|
return QTSS_RequestFailed;
|
||
|
}
|
||
|
|
||
|
|
||
|
QTSS_Error QTSSModuleUtils::SendHTTPErrorResponse( QTSS_RTSPRequestObject inRequest,
|
||
|
QTSS_SessionStatusCode inStatusCode,
|
||
|
Bool16 inKillSession,
|
||
|
char *errorMessage)
|
||
|
{
|
||
|
static Bool16 sFalse = false;
|
||
|
|
||
|
//set status code for access log
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode));
|
||
|
|
||
|
if (inKillSession) // tell the server to end the session
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse));
|
||
|
|
||
|
ResizeableStringFormatter theErrorMessage(NULL, 0); //allocates and deletes memory
|
||
|
ResizeableStringFormatter bodyMessage(NULL,0); //allocates and deletes memory
|
||
|
|
||
|
char messageLineBuffer[64]; // used for each line
|
||
|
static const int maxMessageBufferChars = sizeof(messageLineBuffer) -1;
|
||
|
messageLineBuffer[maxMessageBufferChars] = 0; // guarantee termination
|
||
|
|
||
|
// ToDo: put in a more meaningful http error message for each error. Not required by spec.
|
||
|
// ToDo: maybe use the HTTP protcol class static error strings.
|
||
|
char* errorMsg = "error";
|
||
|
|
||
|
DateBuffer theDate;
|
||
|
DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time
|
||
|
|
||
|
UInt32 realCode = 0;
|
||
|
UInt32 len = sizeof(realCode);
|
||
|
(void) QTSS_GetValue(inRequest, qtssRTSPReqRealStatusCode, 0, (void*)&realCode,&len);
|
||
|
|
||
|
char serverHeaderBuffer[64]; // the qtss Server: header field
|
||
|
len = sizeof(serverHeaderBuffer) -1; // leave room for terminator
|
||
|
(void) QTSS_GetValue(sServer, qtssSvrRTSPServerHeader, 0, (void*)serverHeaderBuffer,&len);
|
||
|
serverHeaderBuffer[len] = 0; // terminate.
|
||
|
|
||
|
qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "HTTP/1.1 %"_U32BITARG_" %s",realCode, errorMsg);
|
||
|
theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
|
||
|
theErrorMessage.PutEOL();
|
||
|
|
||
|
theErrorMessage.Put(serverHeaderBuffer,::strlen(serverHeaderBuffer));
|
||
|
theErrorMessage.PutEOL();
|
||
|
|
||
|
qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "Date: %s",theDate.GetDateBuffer());
|
||
|
theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
|
||
|
theErrorMessage.PutEOL();
|
||
|
|
||
|
Bool16 addBody = (errorMessage != NULL && ::strlen(errorMessage) != 0); // body error message so add body headers
|
||
|
if (addBody) // body error message so add body headers
|
||
|
{
|
||
|
// first create the html body
|
||
|
static const StrPtrLen htmlBodyStart("<html><body>\n");
|
||
|
bodyMessage.Put(htmlBodyStart.Ptr,htmlBodyStart.Len);
|
||
|
|
||
|
//<h1>errorMessage</h1>\n
|
||
|
static const StrPtrLen hStart("<h1>");
|
||
|
bodyMessage.Put(hStart.Ptr,hStart.Len);
|
||
|
|
||
|
bodyMessage.Put(errorMessage,::strlen(errorMessage));
|
||
|
|
||
|
static const StrPtrLen hTerm("</h1>\n");
|
||
|
bodyMessage.Put(hTerm.Ptr,hTerm.Len);
|
||
|
|
||
|
static const StrPtrLen htmlBodyTerm("</body></html>\n");
|
||
|
bodyMessage.Put(htmlBodyTerm.Ptr,htmlBodyTerm.Len);
|
||
|
|
||
|
// write body headers
|
||
|
static const StrPtrLen bodyHeaderType("Content-Type: text/html");
|
||
|
theErrorMessage.Put(bodyHeaderType.Ptr,bodyHeaderType.Len);
|
||
|
theErrorMessage.PutEOL();
|
||
|
|
||
|
qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "Content-Length: %"_U32BITARG_"", bodyMessage.GetBytesWritten());
|
||
|
theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
|
||
|
theErrorMessage.PutEOL();
|
||
|
}
|
||
|
|
||
|
static const StrPtrLen headerClose("Connection: close");
|
||
|
theErrorMessage.Put(headerClose.Ptr,headerClose.Len);
|
||
|
theErrorMessage.PutEOL();
|
||
|
|
||
|
theErrorMessage.PutEOL(); // terminate headers with empty line
|
||
|
|
||
|
if (addBody) // add html body
|
||
|
{
|
||
|
theErrorMessage.Put(bodyMessage.GetBufPtr(),bodyMessage.GetBytesWritten());
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now that we've formatted the message into the temporary buffer,
|
||
|
// write it out to the request stream and the Client Session object
|
||
|
(void)QTSS_Write(inRequest, theErrorMessage.GetBufPtr(), theErrorMessage.GetBytesWritten(), NULL, 0);
|
||
|
(void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMessage.GetBufPtr(), theErrorMessage.GetBytesWritten());
|
||
|
|
||
|
return QTSS_RequestFailed;
|
||
|
}
|
||
|
|
||
|
void QTSSModuleUtils::SendDescribeResponse(QTSS_RTSPRequestObject inRequest,
|
||
|
QTSS_ClientSessionObject inSession,
|
||
|
iovec* describeData,
|
||
|
UInt32 inNumVectors,
|
||
|
UInt32 inTotalLength)
|
||
|
{
|
||
|
//write content size header
|
||
|
char buf[32];
|
||
|
qtss_sprintf(buf, "%"_S32BITARG_"", inTotalLength);
|
||
|
(void)QTSS_AppendRTSPHeader(inRequest, qtssContentLengthHeader, &buf[0], ::strlen(&buf[0]));
|
||
|
|
||
|
(void)QTSS_SendStandardRTSPResponse(inRequest, inSession, 0);
|
||
|
|
||
|
// On solaris, the maximum # of vectors is very low (= 16) so to ensure that we are still able to
|
||
|
// send the SDP if we have a number greater than the maximum allowed, we coalesce the vectors into
|
||
|
// a single big buffer
|
||
|
#ifdef __solaris__
|
||
|
if (inNumVectors > IOV_MAX )
|
||
|
{
|
||
|
char* describeDataBuffer = QTSSModuleUtils::CoalesceVectors(describeData, inNumVectors, inTotalLength);
|
||
|
(void)QTSS_Write(inRequest, (void *)describeDataBuffer, inTotalLength, NULL, qtssWriteFlagsNoFlags);
|
||
|
// deleting memory allocated by the CoalesceVectors call
|
||
|
delete [] describeDataBuffer;
|
||
|
}
|
||
|
else
|
||
|
(void)QTSS_WriteV(inRequest, describeData, inNumVectors, inTotalLength, NULL);
|
||
|
#else
|
||
|
(void)QTSS_WriteV(inRequest, describeData, inNumVectors, inTotalLength, NULL);
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
char* QTSSModuleUtils::CoalesceVectors(iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength)
|
||
|
{
|
||
|
if (inTotalLength == 0)
|
||
|
return NULL;
|
||
|
|
||
|
char* buffer = NEW char[inTotalLength];
|
||
|
UInt32 bufferOffset = 0;
|
||
|
|
||
|
for (UInt32 index = 0; index < inNumVectors; index++)
|
||
|
{
|
||
|
::memcpy (buffer + bufferOffset, inVec[index].iov_base, inVec[index].iov_len);
|
||
|
bufferOffset += inVec[index].iov_len;
|
||
|
}
|
||
|
|
||
|
Assert (bufferOffset == inTotalLength);
|
||
|
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
QTSS_ModulePrefsObject QTSSModuleUtils::GetModulePrefsObject(QTSS_ModuleObject inModObject)
|
||
|
{
|
||
|
QTSS_ModulePrefsObject thePrefsObject = NULL;
|
||
|
UInt32 theLen = sizeof(thePrefsObject);
|
||
|
QTSS_Error theErr = QTSS_GetValue(inModObject, qtssModPrefs, 0, &thePrefsObject, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
return thePrefsObject;
|
||
|
}
|
||
|
|
||
|
QTSS_Object QTSSModuleUtils::GetModuleAttributesObject(QTSS_ModuleObject inModObject)
|
||
|
{
|
||
|
QTSS_Object theAttributesObject = NULL;
|
||
|
UInt32 theLen = sizeof(theAttributesObject);
|
||
|
QTSS_Error theErr = QTSS_GetValue(inModObject, qtssModAttributes, 0, &theAttributesObject, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
return theAttributesObject;
|
||
|
}
|
||
|
|
||
|
QTSS_ModulePrefsObject QTSSModuleUtils::GetModuleObjectByName(const StrPtrLen& inModuleName)
|
||
|
{
|
||
|
QTSS_ModuleObject theModule = NULL;
|
||
|
UInt32 theLen = sizeof(theModule);
|
||
|
|
||
|
for (int x = 0; QTSS_GetValue(sServer, qtssSvrModuleObjects, x, &theModule, &theLen) == QTSS_NoErr; x++)
|
||
|
{
|
||
|
Assert(theModule != NULL);
|
||
|
Assert(theLen == sizeof(theModule));
|
||
|
|
||
|
StrPtrLen theName;
|
||
|
QTSS_Error theErr = QTSS_GetValuePtr(theModule, qtssModName, 0, (void**)&theName.Ptr, &theName.Len);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
if (inModuleName.Equal(theName))
|
||
|
return theModule;
|
||
|
|
||
|
#if DEBUG
|
||
|
theModule = NULL;
|
||
|
theLen = sizeof(theModule);
|
||
|
#endif
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void QTSSModuleUtils::GetAttribute(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType,
|
||
|
void* ioBuffer, void* inDefaultValue, UInt32 inBufferLen)
|
||
|
{
|
||
|
//
|
||
|
// Check to make sure this attribute is the right type. If it's not, this will coerce
|
||
|
// it to be the right type. This also returns the id of the attribute
|
||
|
QTSS_AttributeID theID = QTSSModuleUtils::CheckAttributeDataType(inObject, inAttributeName, inType, inDefaultValue, inBufferLen);
|
||
|
|
||
|
//
|
||
|
// Get the attribute value.
|
||
|
QTSS_Error theErr = QTSS_GetValue(inObject, theID, 0, ioBuffer, &inBufferLen);
|
||
|
|
||
|
//
|
||
|
// Caller should KNOW how big this attribute is
|
||
|
Assert(theErr != QTSS_NotEnoughSpace);
|
||
|
|
||
|
if (theErr != QTSS_NoErr)
|
||
|
{
|
||
|
//
|
||
|
// If we couldn't get the attribute value for whatever reason, just use the
|
||
|
// default if it was provided.
|
||
|
::memcpy(ioBuffer, inDefaultValue, inBufferLen);
|
||
|
|
||
|
if (inBufferLen > 0)
|
||
|
{
|
||
|
//
|
||
|
// Log an error for this pref only if there was a default value provided.
|
||
|
char* theValueAsString = NULL;
|
||
|
theErr = QTSS_ValueToString(inDefaultValue, inBufferLen, inType, &theValueAsString);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
OSCharArrayDeleter theValueStr(theValueAsString);
|
||
|
QTSSModuleUtils::LogError( sMissingPrefVerbosity,
|
||
|
qtssServerPrefMissing,
|
||
|
0,
|
||
|
inAttributeName,
|
||
|
theValueStr.GetObject());
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create an entry for this attribute
|
||
|
QTSSModuleUtils::CreateAttribute(inObject, inAttributeName, inType, inDefaultValue, inBufferLen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char* QTSSModuleUtils::GetStringAttribute(QTSS_Object inObject, char* inAttributeName, char* inDefaultValue)
|
||
|
{
|
||
|
UInt32 theDefaultValLen = 0;
|
||
|
if (inDefaultValue != NULL)
|
||
|
theDefaultValLen = ::strlen(inDefaultValue);
|
||
|
|
||
|
//
|
||
|
// Check to make sure this attribute is the right type. If it's not, this will coerce
|
||
|
// it to be the right type
|
||
|
QTSS_AttributeID theID = QTSSModuleUtils::CheckAttributeDataType(inObject, inAttributeName, qtssAttrDataTypeCharArray, inDefaultValue, theDefaultValLen);
|
||
|
|
||
|
char* theString = NULL;
|
||
|
(void)QTSS_GetValueAsString(inObject, theID, 0, &theString);
|
||
|
if (theString != NULL)
|
||
|
return theString;
|
||
|
|
||
|
//
|
||
|
// If we get here the attribute must be missing, so create it and log
|
||
|
// an error.
|
||
|
|
||
|
QTSSModuleUtils::CreateAttribute(inObject, inAttributeName, qtssAttrDataTypeCharArray, inDefaultValue, theDefaultValLen);
|
||
|
|
||
|
//
|
||
|
// Return the default if it was provided. Only log an error if the default value was provided
|
||
|
if (theDefaultValLen > 0)
|
||
|
{
|
||
|
QTSSModuleUtils::LogError( sMissingPrefVerbosity,
|
||
|
qtssServerPrefMissing,
|
||
|
0,
|
||
|
inAttributeName,
|
||
|
inDefaultValue);
|
||
|
}
|
||
|
|
||
|
if (inDefaultValue != NULL)
|
||
|
{
|
||
|
//
|
||
|
// Whether to return the default value or not from this function is dependent
|
||
|
// solely on whether the caller passed in a non-NULL pointer or not.
|
||
|
// This ensures that if the caller wants an empty-string returned as a default
|
||
|
// value, it can do that.
|
||
|
theString = NEW char[theDefaultValLen + 1];
|
||
|
::strcpy(theString, inDefaultValue);
|
||
|
return theString;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void QTSSModuleUtils::GetIOAttribute(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType,
|
||
|
void* ioDefaultResultBuffer, UInt32 inBufferLen)
|
||
|
{
|
||
|
char *defaultBuffPtr = NEW char[inBufferLen];
|
||
|
::memcpy(defaultBuffPtr,ioDefaultResultBuffer,inBufferLen);
|
||
|
QTSSModuleUtils::GetAttribute(inObject, inAttributeName, inType, ioDefaultResultBuffer, defaultBuffPtr, inBufferLen);
|
||
|
delete [] defaultBuffPtr;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
QTSS_AttributeID QTSSModuleUtils::GetAttrID(QTSS_Object inObject, char* inAttributeName)
|
||
|
{
|
||
|
//
|
||
|
// Get the attribute ID of this attribute.
|
||
|
QTSS_Object theAttrInfo = NULL;
|
||
|
QTSS_Error theErr = QTSS_GetAttrInfoByName(inObject, inAttributeName, &theAttrInfo);
|
||
|
if (theErr != QTSS_NoErr)
|
||
|
return qtssIllegalAttrID;
|
||
|
|
||
|
QTSS_AttributeID theID = qtssIllegalAttrID;
|
||
|
UInt32 theLen = sizeof(theID);
|
||
|
theErr = QTSS_GetValue(theAttrInfo, qtssAttrID, 0, &theID, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
return theID;
|
||
|
}
|
||
|
|
||
|
QTSS_AttributeID QTSSModuleUtils::CheckAttributeDataType(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType, void* inDefaultValue, UInt32 inBufferLen)
|
||
|
{
|
||
|
//
|
||
|
// Get the attribute type of this attribute.
|
||
|
QTSS_Object theAttrInfo = NULL;
|
||
|
QTSS_Error theErr = QTSS_GetAttrInfoByName(inObject, inAttributeName, &theAttrInfo);
|
||
|
if (theErr != QTSS_NoErr)
|
||
|
return qtssIllegalAttrID;
|
||
|
|
||
|
QTSS_AttrDataType theAttributeType = qtssAttrDataTypeUnknown;
|
||
|
UInt32 theLen = sizeof(theAttributeType);
|
||
|
theErr = QTSS_GetValue(theAttrInfo, qtssAttrDataType, 0, &theAttributeType, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
QTSS_AttributeID theID = qtssIllegalAttrID;
|
||
|
theLen = sizeof(theID);
|
||
|
theErr = QTSS_GetValue(theAttrInfo, qtssAttrID, 0, &theID, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
if (theAttributeType != inType)
|
||
|
{
|
||
|
char* theValueAsString = NULL;
|
||
|
theErr = QTSS_ValueToString(inDefaultValue, inBufferLen, inType, &theValueAsString);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
OSCharArrayDeleter theValueStr(theValueAsString);
|
||
|
QTSSModuleUtils::LogError( qtssWarningVerbosity,
|
||
|
qtssServerPrefWrongType,
|
||
|
0,
|
||
|
inAttributeName,
|
||
|
theValueStr.GetObject());
|
||
|
|
||
|
theErr = QTSS_RemoveInstanceAttribute( inObject, theID );
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
return QTSSModuleUtils::CreateAttribute(inObject, inAttributeName, inType, inDefaultValue, inBufferLen);
|
||
|
}
|
||
|
return theID;
|
||
|
}
|
||
|
|
||
|
QTSS_AttributeID QTSSModuleUtils::CreateAttribute(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType, void* inDefaultValue, UInt32 inBufferLen)
|
||
|
{
|
||
|
QTSS_Error theErr = QTSS_AddInstanceAttribute(inObject, inAttributeName, NULL, inType);
|
||
|
Assert((theErr == QTSS_NoErr) || (theErr == QTSS_AttrNameExists));
|
||
|
|
||
|
QTSS_AttributeID theID = QTSSModuleUtils::GetAttrID(inObject, inAttributeName);
|
||
|
Assert(theID != qtssIllegalAttrID);
|
||
|
|
||
|
//
|
||
|
// Caller can pass in NULL for inDefaultValue, in which case we don't add the default
|
||
|
if (inDefaultValue != NULL)
|
||
|
{
|
||
|
theErr = QTSS_SetValue(inObject, theID, 0, inDefaultValue, inBufferLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
}
|
||
|
return theID;
|
||
|
}
|
||
|
|
||
|
QTSS_ActionFlags QTSSModuleUtils::GetRequestActions(QTSS_RTSPRequestObject theRTSPRequest)
|
||
|
{
|
||
|
// Don't touch write requests
|
||
|
QTSS_ActionFlags action = qtssActionFlagsNoFlags;
|
||
|
UInt32 len = sizeof(QTSS_ActionFlags);
|
||
|
QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqAction, 0, (void*)&action, &len);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
Assert(len == sizeof(QTSS_ActionFlags));
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
char* QTSSModuleUtils::GetLocalPath_Copy(QTSS_RTSPRequestObject theRTSPRequest)
|
||
|
{ char* pathBuffStr = NULL;
|
||
|
QTSS_Error theErr = QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqLocalPath, 0, &pathBuffStr);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
return pathBuffStr;
|
||
|
}
|
||
|
|
||
|
char* QTSSModuleUtils::GetMoviesRootDir_Copy(QTSS_RTSPRequestObject theRTSPRequest)
|
||
|
{ char* movieRootDirStr = NULL;
|
||
|
QTSS_Error theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqRootDir, 0, &movieRootDirStr);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
return movieRootDirStr;
|
||
|
}
|
||
|
|
||
|
QTSS_UserProfileObject QTSSModuleUtils::GetUserProfileObject(QTSS_RTSPRequestObject theRTSPRequest)
|
||
|
{ QTSS_UserProfileObject theUserProfile = NULL;
|
||
|
UInt32 len = sizeof(QTSS_UserProfileObject);
|
||
|
QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqUserProfile, 0, (void*)&theUserProfile, &len);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
return theUserProfile;
|
||
|
}
|
||
|
|
||
|
char *QTSSModuleUtils::GetUserName_Copy(QTSS_UserProfileObject inUserProfile)
|
||
|
{
|
||
|
char* username = NULL;
|
||
|
(void) QTSS_GetValueAsString(inUserProfile, qtssUserName, 0, &username);
|
||
|
return username;
|
||
|
}
|
||
|
|
||
|
char** QTSSModuleUtils::GetGroupsArray_Copy(QTSS_UserProfileObject inUserProfile, UInt32 *outNumGroupsPtr)
|
||
|
{
|
||
|
Assert(NULL != outNumGroupsPtr);
|
||
|
|
||
|
char** outGroupCharPtrArray = NULL;
|
||
|
*outNumGroupsPtr = 0;
|
||
|
|
||
|
if (NULL == inUserProfile)
|
||
|
return NULL;
|
||
|
|
||
|
QTSS_Error theErr = QTSS_GetNumValues (inUserProfile,qtssUserGroups, outNumGroupsPtr);
|
||
|
if (theErr != QTSS_NoErr || *outNumGroupsPtr == 0)
|
||
|
return NULL;
|
||
|
|
||
|
outGroupCharPtrArray = NEW char*[*outNumGroupsPtr]; // array of char *
|
||
|
UInt32 len = 0;
|
||
|
for (UInt32 index = 0; index < *outNumGroupsPtr; index++)
|
||
|
{ outGroupCharPtrArray[index] = NULL;
|
||
|
QTSS_GetValuePtr(inUserProfile, qtssUserGroups, index,(void **) &outGroupCharPtrArray[index], &len);
|
||
|
}
|
||
|
|
||
|
return outGroupCharPtrArray;
|
||
|
}
|
||
|
|
||
|
Bool16 QTSSModuleUtils::UserInGroup(QTSS_UserProfileObject inUserProfile, char* inGroup, UInt32 inGroupLen)
|
||
|
{
|
||
|
if (NULL == inUserProfile || NULL == inGroup || inGroupLen == 0)
|
||
|
return false;
|
||
|
|
||
|
char *userName = NULL;
|
||
|
UInt32 len = 0;
|
||
|
QTSS_GetValuePtr(inUserProfile, qtssUserName, 0, (void **)&userName, &len);
|
||
|
if (len == 0 || userName == NULL || userName[0] == 0) // no user to check
|
||
|
return false;
|
||
|
|
||
|
UInt32 numGroups = 0;
|
||
|
QTSS_GetNumValues (inUserProfile,qtssUserGroups, &numGroups);
|
||
|
if (numGroups == 0) // no groups to check
|
||
|
return false;
|
||
|
|
||
|
Bool16 result = false;
|
||
|
char* userGroup = NULL;
|
||
|
StrPtrLenDel userGroupStr; //deletes pointer in destructor
|
||
|
|
||
|
for (UInt32 index = 0; index < numGroups; index++)
|
||
|
{
|
||
|
userGroup = NULL;
|
||
|
QTSS_GetValueAsString(inUserProfile, qtssUserGroups, index, &userGroup); //allocates string
|
||
|
userGroupStr.Delete();
|
||
|
userGroupStr.Set(userGroup);
|
||
|
if(userGroupStr.Equal(inGroup))
|
||
|
{
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
Bool16 QTSSModuleUtils::AddressInList(QTSS_Object inObject, QTSS_AttributeID listID, StrPtrLen *inAddressPtr)
|
||
|
{
|
||
|
StrPtrLenDel strDeleter;
|
||
|
char* theAttributeString = NULL;
|
||
|
IPComponentStr inAddress(inAddressPtr);
|
||
|
IPComponentStr addressFromList;
|
||
|
|
||
|
if (!inAddress.Valid())
|
||
|
return false;
|
||
|
|
||
|
UInt32 numValues = 0;
|
||
|
(void) QTSS_GetNumValues(inObject, listID, &numValues);
|
||
|
|
||
|
for (UInt32 index = 0; index < numValues; index ++)
|
||
|
{
|
||
|
strDeleter.Delete();
|
||
|
(void) QTSS_GetValueAsString(inObject, listID, index, &theAttributeString);
|
||
|
strDeleter.Set(theAttributeString);
|
||
|
|
||
|
addressFromList.Set(&strDeleter);
|
||
|
if (addressFromList.Equal(&inAddress))
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Bool16 QTSSModuleUtils::FindStringInAttributeList(QTSS_Object inObject, QTSS_AttributeID listID, StrPtrLen *inStrPtr)
|
||
|
{
|
||
|
StrPtrLenDel tempString;
|
||
|
|
||
|
if (NULL == inStrPtr || NULL == inStrPtr->Ptr || 0 == inStrPtr->Len)
|
||
|
return false;
|
||
|
|
||
|
UInt32 numValues = 0;
|
||
|
(void) QTSS_GetNumValues(inObject, listID, &numValues);
|
||
|
|
||
|
for (UInt32 index = 0; index < numValues; index ++)
|
||
|
{
|
||
|
tempString.Delete();
|
||
|
(void) QTSS_GetValueAsString(inObject, listID, index, &tempString.Ptr);
|
||
|
tempString.Set(tempString.Ptr);
|
||
|
if (tempString.Ptr == NULL)
|
||
|
return false;
|
||
|
|
||
|
if (tempString.Equal(StrPtrLen("*",1)))
|
||
|
return true;
|
||
|
|
||
|
if (inStrPtr->FindString(tempString.Ptr))
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Bool16 QTSSModuleUtils::HavePlayerProfile(QTSS_PrefsObject inPrefObjectToCheck, QTSS_StandardRTSP_Params* inParams, UInt32 feature)
|
||
|
{
|
||
|
StrPtrLenDel userAgentStr;
|
||
|
(void)QTSS_GetValueAsString(inParams->inClientSession, qtssCliSesFirstUserAgent, 0, &userAgentStr.Ptr);
|
||
|
userAgentStr.Set(userAgentStr.Ptr);
|
||
|
|
||
|
switch (feature)
|
||
|
{
|
||
|
case QTSSModuleUtils::kRequiresRTPInfoSeqAndTime:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReqRTPHeader, &userAgentStr);
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case QTSSModuleUtils::kAdjustBandwidth:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReqBandAdjust, &userAgentStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case QTSSModuleUtils::kDisablePauseAdjustedRTPTime:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReqNoPauseTimeAdjust, &userAgentStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case QTSSModuleUtils::kDelayRTPStreamsUntilAfterRTSPResponse:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReqRTPStartTimeAdjust, &userAgentStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case QTSSModuleUtils::kDisable3gppRateAdaptation:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReqDisable3gppRateAdapt, &userAgentStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case QTSSModuleUtils::kAdjust3gppTargetTime:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReq3GPPTargetTime, &userAgentStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case QTSSModuleUtils::kDisableThinning:
|
||
|
{
|
||
|
return QTSSModuleUtils::FindStringInAttributeList(inPrefObjectToCheck, qtssPrefsPlayersReqDisableThinning, &userAgentStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
QTSS_Error QTSSModuleUtils::AuthorizeRequest(QTSS_RTSPRequestObject theRTSPRequest, Bool16* allowed, Bool16*foundUser, Bool16 *authContinue)
|
||
|
{
|
||
|
QTSS_Error theErr = QTSS_NoErr;
|
||
|
//printf("QTSSModuleUtils::AuthorizeRequest allowed=%d foundUser=%d authContinue=%d\n", *allowed, *foundUser, *authContinue);
|
||
|
|
||
|
if (NULL != allowed)
|
||
|
theErr = QTSS_SetValue(theRTSPRequest,qtssRTSPReqUserAllowed, 0, allowed, sizeof(Bool16));
|
||
|
if (QTSS_NoErr != theErr)
|
||
|
return theErr;
|
||
|
|
||
|
if (NULL != foundUser)
|
||
|
theErr = QTSS_SetValue(theRTSPRequest,qtssRTSPReqUserFound, 0, foundUser, sizeof(Bool16));
|
||
|
if (QTSS_NoErr != theErr)
|
||
|
return theErr;
|
||
|
|
||
|
if (NULL != authContinue)
|
||
|
theErr = QTSS_SetValue(theRTSPRequest,qtssRTSPReqAuthHandled, 0, authContinue, sizeof(Bool16));
|
||
|
|
||
|
return theErr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
IPComponentStr IPComponentStr::sLocalIPCompStr("127.0.0.*");
|
||
|
|
||
|
IPComponentStr::IPComponentStr(char *theAddressPtr)
|
||
|
{
|
||
|
StrPtrLen sourceStr(theAddressPtr);
|
||
|
(void) this->Set(&sourceStr);
|
||
|
}
|
||
|
|
||
|
IPComponentStr::IPComponentStr(StrPtrLen *sourceStrPtr)
|
||
|
{
|
||
|
(void) this->Set(sourceStrPtr);
|
||
|
}
|
||
|
|
||
|
Bool16 IPComponentStr::Set(StrPtrLen *theAddressStrPtr)
|
||
|
{
|
||
|
fIsValid = false;
|
||
|
|
||
|
StringParser IP_Paser(theAddressStrPtr);
|
||
|
StrPtrLen *piecePtr = &fAddressComponent[0];
|
||
|
|
||
|
while (IP_Paser.GetDataRemaining() > 0)
|
||
|
{
|
||
|
IP_Paser.ConsumeUntil(piecePtr,'.');
|
||
|
if (piecePtr->Len == 0)
|
||
|
break;
|
||
|
|
||
|
IP_Paser.ConsumeLength(NULL, 1);
|
||
|
if (piecePtr == &fAddressComponent[IPComponentStr::kNumComponents -1])
|
||
|
{
|
||
|
fIsValid = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
piecePtr++;
|
||
|
};
|
||
|
|
||
|
return fIsValid;
|
||
|
}
|
||
|
|
||
|
|
||
|
Bool16 IPComponentStr::Equal(IPComponentStr *testAddressPtr)
|
||
|
{
|
||
|
if (testAddressPtr == NULL)
|
||
|
return false;
|
||
|
|
||
|
if ( !this->Valid() || !testAddressPtr->Valid() )
|
||
|
return false;
|
||
|
|
||
|
for (UInt16 component= 0 ; component < IPComponentStr::kNumComponents ; component ++)
|
||
|
{
|
||
|
StrPtrLen *allowedPtr = this->GetComponent(component);
|
||
|
StrPtrLen *testPtr = testAddressPtr->GetComponent(component);
|
||
|
|
||
|
if ( testPtr->Equal("*") || allowedPtr->Equal("*") )
|
||
|
continue;
|
||
|
|
||
|
if (!testPtr->Equal(*allowedPtr) )
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|