Darwin-Streaming-Server/APIModules/QTSSRawFileModule.bproj/QTSSRawFileModule.cpp
Darren VanBuren 849723c9cf Add even more of the source
This should be about everything needed to build so far?
2017-03-07 17:14:16 -08:00

380 lines
14 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: QTSSRawFileModule.cpp
Contains: Implementation of Raw File module
*/
#include "QTSSRawFileModule.h"
#include "OSHeaders.h"
#include "StrPtrLen.h"
#include "OSArrayObjectDeleter.h"
#include "QTSSModuleUtils.h"
#include "OSMemory.h"
#include "ev.h"
#include "QTSSMemoryDeleter.h"
#define RAWFILE_FILE_ASYNC 1
#define RAW_FILE_DEBUGGING 0
// ATTRIBUTES IDs
static QTSS_AttributeID sStateAttr = qtssIllegalAttrID;
static QTSS_AttributeID sFileAttr = qtssIllegalAttrID;
static QTSS_AttributeID sFileBufferAttr = qtssIllegalAttrID;
static QTSS_AttributeID sReadOffsetAttr = qtssIllegalAttrID;
static QTSS_AttributeID sWriteOffsetAttr = qtssIllegalAttrID;
// STATIC DATA
static StrPtrLen sRawSuffix(".raw");
static const UInt32 kReadingBufferState = 0;
static const UInt32 kWritingBufferState = 1;
// FUNCTIONS
static QTSS_Error QTSSRawFileModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams);
static QTSS_Error Register(QTSS_Register_Params* inParams);
static QTSS_Error Preprocess(QTSS_StandardRTSP_Params* inParams);
QTSS_Error QTSSRawFileModule_Main(void* inPrivateArgs)
{
return _stublibrary_main(inPrivateArgs, QTSSRawFileModuleDispatch);
}
QTSS_Error QTSSRawFileModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams)
{
switch (inRole)
{
case QTSS_Register_Role:
return Register(&inParams->regParams);
case QTSS_RTSPPreProcessor_Role:
return Preprocess(&inParams->rtspPreProcessorParams);
}
return QTSS_NoErr;
}
QTSS_Error Register(QTSS_Register_Params* inParams)
{
(void)QTSS_AddRole(QTSS_RTSPPreProcessor_Role);
static char* sStateName = "QTSSRawFileModuleState";
static char* sFileName = "QTSSRawFileModuleFile";
static char* sFileBufferName = "QTSSRawFileModuleFileBuffer";
static char* sReadOffsetName = "QTSSRawFileModuleReadOffset";
static char* sWriteOffsetName = "QTSSRawFileModuleWriteOffset";
(void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType, sStateName, NULL, qtssAttrDataTypeUInt32);
(void)QTSS_IDForAttr(qtssRTSPSessionObjectType, sStateName, &sStateAttr);
(void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType, sFileName, NULL, qtssAttrDataTypeUInt32);
(void)QTSS_IDForAttr(qtssRTSPSessionObjectType, sFileName, &sFileAttr);
(void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType, sFileBufferName, NULL, qtssAttrDataTypeCharArray);
(void)QTSS_IDForAttr(qtssRTSPSessionObjectType, sFileBufferName, &sFileBufferAttr);
(void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType, sReadOffsetName, NULL, qtssAttrDataTypeUInt32);
(void)QTSS_IDForAttr(qtssRTSPSessionObjectType, sReadOffsetName, &sReadOffsetAttr);
(void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType, sWriteOffsetName, NULL, qtssAttrDataTypeUInt32);
(void)QTSS_IDForAttr(qtssRTSPSessionObjectType, sWriteOffsetName, &sWriteOffsetAttr);
// Tell the server our name!
static char* sModuleName = "QTSSRawFileModule";
::strcpy(inParams->outModuleName, sModuleName);
return QTSS_NoErr;
}
QTSS_Error Preprocess(QTSS_StandardRTSP_Params* inParams)
{
static UInt32 sFileBufSize = 32768;
static UInt32 sInitialState = kReadingBufferState;
static UInt32 sZero = 0;
UInt32 theLen = 0;
UInt32* theStateP = NULL;
QTSS_Error theErr = QTSS_NoErr;
QTSS_Object theFile = NULL;
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sStateAttr, 0, (void**)&theStateP, &theLen);
if ((theStateP == NULL) || (theLen != sizeof(UInt32)))
{
// Initial state. We haven't started sending the file yet, so
// check to see if this is our request, and if it is, set everything up.
// Only operate if this is a DESCRIBE
QTSS_RTSPMethod* theMethod = NULL;
UInt32 theLen = 0;
if ((QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqMethod, 0,
(void**)&theMethod, &theLen) != QTSS_NoErr) || (theLen != sizeof(QTSS_RTSPMethod)))
{
Assert(0);
return QTSS_RequestFailed;
}
if (*theMethod != qtssDescribeMethod)
return QTSS_RequestFailed;
// Check to see if this is a raw file request
char* theFilePath = NULL;
(void)QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqLocalPath, 0, &theFilePath);
QTSSCharArrayDeleter theFilePathDeleter(theFilePath);
theLen = ::strlen(theFilePath);
// Copy the full path, and append a ".raw"
OSCharArrayDeleter rawPath(NEW char[theLen + sRawSuffix.Len + 4]);
::memcpy(rawPath.GetObject(), theFilePath, theLen);
::strcpy(rawPath.GetObject() + theLen, sRawSuffix.Ptr);
#if RAWFILE_FILE_ASYNC
theErr = QTSS_OpenFileObject(rawPath.GetObject(), qtssOpenFileAsync, &theFile);
#else
theErr = QTSS_OpenFileObject(rawPath.GetObject(), qtssOpenFileAsync, &theFile);
#endif
// If the file doesn't exist, and if this is a path with a '.raw' at the end,
// check to see if the path without the extra .raw exists
if (theErr != QTSS_NoErr)
{
theFile = NULL;
rawPath.GetObject()[theLen] = '\0';
if (theLen > sRawSuffix.Len)
{
StrPtrLen comparer((theFilePath + theLen) - sRawSuffix.Len, sRawSuffix.Len);
if (comparer.Equal(sRawSuffix))
{
#if RAWFILE_FILE_ASYNC
theErr = QTSS_OpenFileObject(rawPath.GetObject(), qtssOpenFileAsync, &theFile);
#else
theErr = QTSS_OpenFileObject(rawPath.GetObject(), kOpenFileNoFlags, &theFile);
#endif
}
}
}
// If the file doesn't exist, we should probably return a 404 not found.
if (theErr != QTSS_NoErr)
return QTSS_RequestFailed;
// Before sending any response, set keep alive to off for this connection
// Regardless of what the client sends, the server always closes the connection after sending the file
static Bool16 sFalse = false;
(void)QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse));
// We have a real file. Setup all the dictionary values we need
(void)QTSS_SetValue(inParams->inRTSPSession, sFileAttr, 0, &theFile, sizeof(theFile));
// Create a buffer to store data.
char* theFileBuffer = NEW char[sFileBufSize];
(void)QTSS_SetValue(inParams->inRTSPSession, sFileBufferAttr, 0, &theFileBuffer, sizeof(theFileBuffer));
// Store our initial state
(void)QTSS_SetValue(inParams->inRTSPSession, sStateAttr, 0, &sInitialState, sizeof(sInitialState));
theStateP = &sInitialState; // so we can proceed normally
(void)QTSS_SetValue(inParams->inRTSPSession, sReadOffsetAttr, 0, &sZero, sizeof(sZero));
(void)QTSS_SetValue(inParams->inRTSPSession, sWriteOffsetAttr, 0, &sZero, sizeof(sZero));
}
// Get our attributes
char** theFileBufferP = NULL;
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sFileBufferAttr, 0, (void**)&theFileBufferP, &theLen);
Assert(theFileBufferP != NULL);
Assert(theLen == sizeof(char*));
QTSS_Object* theFileP = NULL;
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sFileAttr, 0, (void**)&theFileP, &theLen);
Assert(theFileP != NULL);
Assert(theLen == sizeof(QTSS_Object));
UInt32* theReadOffsetP = NULL;
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sReadOffsetAttr, 0, (void**)&theReadOffsetP, &theLen);
Assert(theReadOffsetP != NULL);
Assert(theLen == sizeof(UInt32));
UInt32* theWriteOffsetP = NULL;
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sWriteOffsetAttr, 0, (void**)&theWriteOffsetP, &theLen);
Assert(theWriteOffsetP != NULL);
Assert(theLen == sizeof(UInt32));
UInt32 theReadOffset = *theReadOffsetP;
UInt32 theWriteOffset = *theWriteOffsetP;
UInt32 theState = *theStateP;
Bool16 isBlocked = false;
// Get the length of the file onto the stack
theLen = sizeof(UInt64);
UInt64 theFileLength = 0;
theErr = QTSS_GetValue(*theFileP, qtssFlObjLength, 0, (void*)&theFileLength, &theLen);
Assert(theErr == QTSS_NoErr);
Assert(theLen == sizeof(UInt64));
// Get the offset in the file onto the stack
theLen = sizeof(UInt64);
UInt64 theOffset = 0;
theErr = QTSS_GetValue(*theFileP, qtssFlObjPosition, 0, (void*)&theOffset, &theLen);
Assert(theErr == QTSS_NoErr);
Assert(theLen == sizeof(UInt64));
while (!isBlocked)
{
// If we have less than the full buffer size left to go in the file,
// down adjust our buffer size to be the amount of data remaining in the file
UInt32 theBufferSize = sFileBufSize;
if ((theFileLength - theOffset) < sFileBufSize)
theBufferSize = (UInt32) (theFileLength - theOffset);
switch (theState)
{
case kReadingBufferState:
{
// Read as much data as possible out of the file
UInt32 theRecvLen = 0;
(void)QTSS_Read(*theFileP,
(*theFileBufferP) + theReadOffset,
theBufferSize - theReadOffset,
&theRecvLen);
theReadOffset += theRecvLen;
theOffset += theRecvLen;
#if RAW_FILE_DEBUGGING
qtss_printf("Got %"_U32BITARG_" bytes back from file read. Now at: %"_64BITARG_"u\n", theRecvLen, theOffset);
#endif
if (theReadOffset < theBufferSize)
{
#if RAW_FILE_DEBUGGING
qtss_printf("Flow controlled on file. Waiting for read event\n");
#endif
isBlocked = true;
break;
}
theReadOffset = 0;
Assert(theWriteOffset == 0);
theState = kWritingBufferState;
}
case kWritingBufferState:
{
UInt32 theWrittenLen = 0;
// for debugging purposes, construct an IOVec out of this data
iovec theVec[5];
UInt32 units = (theBufferSize - theWriteOffset) /4;
UInt32 offset = theWriteOffset;
theVec[1].iov_base = (*theFileBufferP) + offset;
theVec[1].iov_len = units;
offset += units;
theVec[2].iov_base = (*theFileBufferP) + offset;
theVec[2].iov_len = units;
offset += units;
theVec[3].iov_base = (*theFileBufferP) + offset;
theVec[3].iov_len = units;
offset += units;
theVec[4].iov_base = (*theFileBufferP) + offset;
theVec[4].iov_len = theBufferSize - offset;
(void)QTSS_WriteV( inParams->inRTSPSession,
theVec, 5,
theBufferSize - theWriteOffset,
&theWrittenLen);
theWriteOffset += theWrittenLen;
#if RAW_FILE_DEBUGGING
qtss_printf("Got %"_U32BITARG_" bytes back from socket write.\n", theWrittenLen);
#endif
if (theWriteOffset < theBufferSize)
{
#if RAW_FILE_DEBUGGING
qtss_printf("Flow controlled on socket. Waiting for write event.\n");
#endif
isBlocked = true;
break;
}
// Check to see if we're done. If we are, delete stuff and return
if (theOffset == theFileLength)
{
#if RAW_FILE_DEBUGGING
qtss_printf("File transfer complete\n");
#endif
return QTSS_NoErr;
}
theWriteOffset = 0;
Assert(theReadOffset == 0);
theState = kReadingBufferState;
}
}
}
Assert(isBlocked);
// We've reached a blocking condition for some reason.
// Save our state, request an event, and return.
(void)QTSS_SetValue(inParams->inRTSPSession, sReadOffsetAttr, 0, &theReadOffset, sizeof(theReadOffset));
(void)QTSS_SetValue(inParams->inRTSPSession, sWriteOffsetAttr, 0, &theWriteOffset, sizeof(theWriteOffset));
(void)QTSS_SetValue(inParams->inRTSPSession, sStateAttr, 0, &theState, sizeof(theState));
// If we're reading, wait for the file to become readable
if (theState == kReadingBufferState)
(void)QTSS_RequestEvent(*theFileP, QTSS_ReadableEvent);
// If we're writing, wait for the socket to become writable
else
(void)QTSS_RequestEvent(inParams->inRTSPSession, QTSS_WriteableEvent);
return QTSS_NoErr;
}
QTSS_Error CloseRTSPSession(QTSS_RTSPSession_Params* inParams)
{
// In this role, the allocated resources are deleted before closing the RTSP session
UInt32 theLen = 0;
// Get our file buffer pointer and delete it
char** theFileBufferP = NULL; // File buffer pointer
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sFileBufferAttr, 0, (void**)&theFileBufferP, &theLen);
if (theFileBufferP != NULL)
delete [] *theFileBufferP;
QTSS_Object* theFileP = NULL;
// Get our file pointer and delete it
(void)QTSS_GetValuePtr(inParams->inRTSPSession, sFileAttr, 0, (void**)&theFileP, &theLen);
Assert(theFileP != NULL);
Assert(theLen == sizeof(QTSS_Object));
(void)QTSS_CloseFileObject(*theFileP);
return QTSS_NoErr;
}