Very rough first start, not even everything added

This commit is contained in:
Darren VanBuren 2017-03-07 14:51:44 -08:00
commit af3619d4fa
88 changed files with 24251 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.o

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -0,0 +1,681 @@
/*
*
* @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: QTAccessFile.cpp
Contains: This file contains the implementation for finding and parsing qtaccess files.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include "QTSS.h"
#include "OSHeaders.h"
#include "StrPtrLen.h"
#include "StringParser.h"
#include "QTSSModuleUtils.h"
#include "OSFileSource.h"
#include "OSMemory.h"
#include "OSHeaders.h"
#include "QTAccessFile.h"
#include "OSArrayObjectDeleter.h"
#include <grp.h>
#if __MacOSX__
#include <membership.h>
#endif
#include <pwd.h>
#include <signal.h>
#include <unistd.h>
#define DEBUG_QTACCESS 0
#define debug_printf if (DEBUG_QTACCESS) qtss_printf
char* QTAccessFile::sAccessValidUser = "require valid-user\n";
char* QTAccessFile::sAccessAnyUser = "require any-user\n";
UInt8 QTAccessFile::sWhitespaceAndGreaterThanMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 // \t is a stop
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, //10-19 //'\r' & '\n' are stop conditions
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //30-39 ' ' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40-49
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-59
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //60-69 // '>' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150-159
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240-249
0, 0, 0, 0, 0, 0 //250-255
};
char* QTAccessFile::sQTAccessFileName = "qtaccess";
Bool16 QTAccessFile::sAllocatedName = false;
OSMutex* QTAccessFile::sAccessFileMutex = NULL;//QTAccessFile isn't reentrant
const int kBuffLen = 512;
void QTAccessFile::Initialize() // called by server at initialize never call again
{
if (NULL == sAccessFileMutex)
{ sAccessFileMutex = NEW OSMutex();
}
}
void QTAccessFile::SetAccessFileName(const char *inQTAccessFileName)
{
OSMutexLocker locker(sAccessFileMutex);
if (NULL == inQTAccessFileName)
{ Assert(NULL != inQTAccessFileName);
return;
}
if (sAllocatedName)
{ delete [] sQTAccessFileName;
}
sAllocatedName = true;
sQTAccessFileName = NEW char[strlen(inQTAccessFileName)+1];
::strcpy(sQTAccessFileName, inQTAccessFileName);
}
Bool16 QTAccessFile::HaveUser(char *userName, void* extraDataPtr)
{
Bool16 result = false;
if (NULL != userName && 0 != userName[0])
result = true;
return result;
}
Bool16 QTAccessFile::HaveGroups( char** groupArray, UInt32 numGroups, void* extraDataPtr)
{
Bool16 result = false;
if (numGroups > 0 && groupArray != NULL)
result = true;
return result;
}
Bool16 QTAccessFile::HaveRealm( char *userName, StrPtrLen* ioRealmNameStr, void *extraData )
{
Bool16 result = false;
if (ioRealmNameStr != NULL && ioRealmNameStr->Ptr != NULL && ioRealmNameStr->Len > 0)
result = true;
return result;
}
void QTAccessFile::GetRealm(StrPtrLen* accessRealm, StrPtrLen* ioRealmNameStr, char *userName,void *extraDataPtr )
{
if (ioRealmNameStr->Len <= accessRealm->Len)
accessRealm->Len = ioRealmNameStr->Len -1; // just copy what we can
::memcpy(ioRealmNameStr->Ptr, accessRealm->Ptr,accessRealm->Len);
ioRealmNameStr->Ptr[accessRealm->Len] = 0;
}
Bool16 QTAccessFile::TestUser(StrPtrLen* accessUser, char *userName,void *extraDataPtr )
{
Bool16 result = false;
if ( accessUser->Equal(userName) )
result = true;
return result;
}
Bool16 QTAccessFile::TestGroup( StrPtrLen* accessGroup, char *userName, char**groupArray, UInt32 numGroups, void *extraDataPtr)
{
for (UInt32 index = 0; index < numGroups; index ++)
{ if(accessGroup->Equal(groupArray[index]))
return true;
}
return false;
}
Bool16 QTAccessFile::TestExtraData( StrPtrLen* wordPtr, StringParser* lineParserPtr, void* extraDataPtr)
{
return false;
}
Bool16 QTAccessFile::AccessAllowed ( char *userName, char**groupArray, UInt32 numGroups, StrPtrLen *accessFileBufPtr,
QTSS_ActionFlags inFlags,StrPtrLen* ioRealmNameStr, Bool16 *outAllowAnyUserPtr, void *extraDataPtr
)
{
if (NULL == accessFileBufPtr || NULL == accessFileBufPtr->Ptr || 0 == accessFileBufPtr->Len)
return true; // nothing to check
if (ioRealmNameStr != NULL && ioRealmNameStr->Ptr != NULL && ioRealmNameStr->Len > 0)
ioRealmNameStr->Ptr[0] = 0;
StringParser accessFileParser(accessFileBufPtr);
QTSS_ActionFlags currentFlags = qtssActionFlagsRead;
StrPtrLen line;
StrPtrLen word;
Bool16 haveUserName = false;
Bool16 haveRealmResultBuffer = false;
Bool16 haveGroups = false;
*outAllowAnyUserPtr = false;
haveUserName = HaveUser(userName, extraDataPtr);
haveGroups = HaveGroups(groupArray, numGroups, extraDataPtr);
haveRealmResultBuffer = HaveRealm(userName, ioRealmNameStr, extraDataPtr );
while( accessFileParser.GetDataRemaining() != 0 )
{
accessFileParser.GetThruEOL(&line); // Read each line
StringParser lineParser(&line);
lineParser.ConsumeWhitespace();//skip over leading whitespace
if (lineParser.GetDataRemaining() == 0) // must be an empty line
continue;
char firstChar = lineParser.PeekFast();
if ( (firstChar == '#') || (firstChar == '\0') )
continue; //skip over comments and blank lines...
lineParser.ConsumeUntilWhitespace(&word);
if ( word.Equal("<Limit") ) // a limit line
{
currentFlags = qtssActionFlagsNoFlags; // clear to no access
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntil( &word, sWhitespaceAndGreaterThanMask); // the flag <limit Read> or <limit Read >
while (word.Len != 0) // compare each word in the line
{
if (word.Equal("WRITE") )
{ currentFlags |= inFlags & qtssActionFlagsWrite; // accept following lines if inFlags has write
}
if (word.Equal("READ") )
{ currentFlags |= inFlags & qtssActionFlagsRead; // accept following lines if inFlags has read
}
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntil(&word, sWhitespaceAndGreaterThanMask);
}
continue; //done with limit line
}
if ( word.Equal("</Limit>") )
currentFlags = qtssActionFlagsRead; // set the current access state to the default of read access
if (0 == (currentFlags & inFlags))
continue; // ignore lines because inFlags doesn't match the current access state
if (haveRealmResultBuffer && word.Equal("AuthName") ) //realm name
{
lineParser.ConsumeWhitespace();
lineParser.GetThruEOL(&word);
StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them.
GetRealm(&word, ioRealmNameStr, userName, extraDataPtr );
// we don't change the buffer len ioRealmNameStr->Len because we might have another AuthName tag to copy
continue; // done with AuthName (realm)
}
if (word.Equal("require") )
{
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntilWhitespace(&word);
if (haveUserName && word.Equal("valid-user") )
{ return true;
}
if ( word.Equal("any-user") )
{
*outAllowAnyUserPtr = true;
return true;
}
if (!haveUserName)
continue;
if (word.Equal("user") )
{
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntilWhitespace(&word);
while (word.Len != 0) // compare each word in the line
{
if (TestUser(&word, userName, extraDataPtr ))
return true;
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntilWhitespace(&word);
}
continue; // done with "require user" line
}
if (haveGroups && word.Equal("group")) // check if we have groups for the user
{
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntilWhitespace(&word);
while (word.Len != 0) // compare each word in the line
{
if (TestGroup(&word, userName, groupArray, numGroups, extraDataPtr) )
return true;
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntilWhitespace(&word);
}
continue; // done with "require group" line
}
if (TestExtraData(&word, &lineParser, extraDataPtr))
return true;
continue; // done with unparsed "require" line
}
}
return false; // user or group not found
}
char* QTAccessFile::GetAccessFile_Copy( const char* movieRootDir, const char* dirPath)
{
OSMutexLocker locker(sAccessFileMutex);
char* currentDir= NULL;
char* lastSlash = NULL;
int movieRootDirLen = ::strlen(movieRootDir);
int maxLen = strlen(dirPath)+strlen(sQTAccessFileName) + strlen(kPathDelimiterString) + 1;
currentDir = NEW char[maxLen];
::strcpy(currentDir, dirPath);
//strip off filename
lastSlash = ::strrchr(currentDir, kPathDelimiterChar);
if (lastSlash != NULL)
lastSlash[0] = '\0';
//check qtaccess files
while ( true ) //walk backward up the dir tree.
{
int curLen = strlen(currentDir) + strlen(sQTAccessFileName) + strlen(kPathDelimiterString);
if ( curLen >= maxLen )
break;
::strcat(currentDir, kPathDelimiterString);
::strcat(currentDir, sQTAccessFileName);
QTSS_Object fileObject = NULL;
if( QTSS_OpenFileObject(currentDir, qtssOpenFileNoFlags, &fileObject) == QTSS_NoErr)
{
(void)QTSS_CloseFileObject(fileObject);
return currentDir;
}
//strip off the "/qtaccess"
lastSlash = ::strrchr(currentDir, kPathDelimiterChar);
lastSlash[0] = '\0';
//strip of the tailing directory
lastSlash = ::strrchr(currentDir, kPathDelimiterChar);
if (lastSlash == NULL)
break;
else
lastSlash[0] = '\0';
if ( (lastSlash-currentDir) < movieRootDirLen ) //bail if we start eating our way out of fMovieRootDir
break;
}
delete[] currentDir;
return NULL;
}
// allocates memory for outUsersFilePath and outGroupsFilePath - remember to delete
// returns the auth scheme
QTSS_AuthScheme QTAccessFile::FindUsersAndGroupsFilesAndAuthScheme(char* inAccessFilePath, QTSS_ActionFlags inAction, char** outUsersFilePath, char** outGroupsFilePath)
{
QTSS_AuthScheme authScheme = qtssAuthNone;
QTSS_ActionFlags currentFlags = qtssActionFlagsRead;
if (inAccessFilePath == NULL)
return authScheme;
*outUsersFilePath = NULL;
*outGroupsFilePath = NULL;
//Assert(outUsersFilePath == NULL);
//Assert(outGroupsFilePath == NULL);
StrPtrLen accessFileBuf;
(void)QTSSModuleUtils::ReadEntireFile(inAccessFilePath, &accessFileBuf);
OSCharArrayDeleter accessFileBufDeleter(accessFileBuf.Ptr);
StringParser accessFileParser(&accessFileBuf);
StrPtrLen line;
StrPtrLen word;
while( accessFileParser.GetDataRemaining() != 0 )
{
accessFileParser.GetThruEOL(&line); // Read each line
StringParser lineParser(&line);
lineParser.ConsumeWhitespace(); //skip over leading whitespace
if (lineParser.GetDataRemaining() == 0) // must be an empty line
continue;
char firstChar = lineParser.PeekFast();
if ( (firstChar == '#') || (firstChar == '\0') )
continue; //skip over comments and blank lines...
lineParser.ConsumeUntilWhitespace(&word);
if ( word.Equal("<Limit") ) // a limit line
{
currentFlags = qtssActionFlagsNoFlags; // clear to no access
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntil( &word, sWhitespaceAndGreaterThanMask); // the flag <limit Read> or <limit Read >
while (word.Len != 0) // compare each word in the line
{
if (word.Equal("WRITE") )
{
currentFlags |= inAction & qtssActionFlagsWrite; // accept following lines if inFlags has write
}
if (word.Equal("READ") )
{
currentFlags |= inAction & qtssActionFlagsRead; // accept following lines if inFlags has read
}
lineParser.ConsumeWhitespace();
lineParser.ConsumeUntil(&word, sWhitespaceAndGreaterThanMask);
}
continue; //done with limit line
}
if ( word.Equal("</Limit>") )
currentFlags = qtssActionFlagsRead; // set the current access state to the default of read access
if (0 == (currentFlags & inAction))
continue; // ignore lines because inFlags doesn't match the current access state
if (word.Equal("AuthUserFile") )
{
lineParser.ConsumeWhitespace();
lineParser.GetThruEOL(&word);
StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them.
if(*outUsersFilePath != NULL) // we are encountering the AuthUserFile keyword twice!
delete[] *outUsersFilePath; // The last one found takes precedence...delete the previous path
*outUsersFilePath = word.GetAsCString();
continue;
}
if (word.Equal("AuthGroupFile") )
{
lineParser.ConsumeWhitespace();
lineParser.GetThruEOL(&word);
StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them.
if(*outGroupsFilePath != NULL) // we are encountering the AuthGroupFile keyword twice!
delete[] *outGroupsFilePath; // The last one found takes precedence...delete the previous path
*outGroupsFilePath = word.GetAsCString();
continue;
}
if (word.Equal("AuthScheme") )
{
lineParser.ConsumeWhitespace();
lineParser.GetThruEOL(&word);
StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them.
if (word.Equal("basic"))
authScheme = qtssAuthBasic;
else if (word.Equal("digest"))
authScheme = qtssAuthDigest;
continue;
}
}
return authScheme;
}
QTSS_Error QTAccessFile::AuthorizeRequest(QTSS_StandardRTSP_Params* inParams, Bool16 allowNoAccessFiles, QTSS_ActionFlags noAction, QTSS_ActionFlags authorizeAction, Bool16 *outAuthorizedPtr, Bool16 *outAllowAnyUserPtr)
{
if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) || (NULL == outAllowAnyUserPtr) || (NULL == outAuthorizedPtr) )
return QTSS_RequestFailed;
*outAllowAnyUserPtr = false;
*outAuthorizedPtr = false;
QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest;
// get the type of request
// Don't touch write requests
QTSS_ActionFlags action = QTSSModuleUtils::GetRequestActions(theRTSPRequest);
if(action == qtssActionFlagsNoFlags)
return QTSS_RequestFailed;
if( (action & noAction) != 0)
return QTSS_NoErr; // we don't handle
//get the local file path
char* pathBuffStr = QTSSModuleUtils::GetLocalPath_Copy(theRTSPRequest);
OSCharArrayDeleter pathBuffDeleter(pathBuffStr);
if (NULL == pathBuffStr)
return QTSS_RequestFailed;
//get the root movie directory
char* movieRootDirStr = QTSSModuleUtils::GetMoviesRootDir_Copy(theRTSPRequest);
OSCharArrayDeleter movieRootDeleter(movieRootDirStr);
if (NULL == movieRootDirStr)
return QTSS_RequestFailed;
QTSS_UserProfileObject theUserProfile = QTSSModuleUtils::GetUserProfileObject(theRTSPRequest);
if (NULL == theUserProfile)
return QTSS_RequestFailed;
char* accessFilePath = QTAccessFile::GetAccessFile_Copy(movieRootDirStr, pathBuffStr);
OSCharArrayDeleter accessFilePathDeleter(accessFilePath);
char* username = QTSSModuleUtils::GetUserName_Copy(theUserProfile);
OSCharArrayDeleter usernameDeleter(username);
UInt32 numGroups = 0;
char** groupCharPtrArray = QTSSModuleUtils::GetGroupsArray_Copy(theUserProfile, &numGroups);
OSCharPointerArrayDeleter groupCharPtrArrayDeleter(groupCharPtrArray);
StrPtrLen accessFileBuf;
(void)QTSSModuleUtils::ReadEntireFile(accessFilePath, &accessFileBuf);
OSCharArrayDeleter accessFileBufDeleter(accessFileBuf.Ptr);
if (accessFileBuf.Len == 0 && !allowNoAccessFiles)
{ accessFileBuf.Set(sAccessValidUser);
if (DEBUG_QTACCESS)
qtss_printf("QTAccessFile::AuthorizeRequest SET Accessfile valid user for no accessfile %s\n", sAccessValidUser);
}
if (accessFileBuf.Len == 0 && allowNoAccessFiles)
{ accessFileBuf.Set(sAccessAnyUser);
if (DEBUG_QTACCESS)
qtss_printf("QTAccessFile::AuthorizeRequest SET Accessfile any user for no access file %s\n", sAccessAnyUser);
}
char realmName[kBuffLen] = { 0 };
StrPtrLen realmNameStr(realmName,kBuffLen -1);
//check if this user is allowed to see this movie
Bool16 allowRequest = this->AccessAllowed(username, groupCharPtrArray, numGroups, &accessFileBuf, authorizeAction,&realmNameStr, outAllowAnyUserPtr );
debug_printf("accessFile.AccessAllowed for user=%s returned %d\n", username, allowRequest);
// Get the auth scheme
QTSS_AuthScheme theAuthScheme = qtssAuthNone;
UInt32 len = sizeof(theAuthScheme);
QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqAuthScheme, 0, (void*)&theAuthScheme, &len);
Assert(len == sizeof(theAuthScheme));
if(theErr != QTSS_NoErr)
return theErr;
// If auth scheme is basic and the realm is present in the access file, use it
if((theAuthScheme == qtssAuthBasic) && (realmNameStr.Ptr[0] != '\0')) //set the realm if we have one
(void) QTSS_SetValue(theRTSPRequest,qtssRTSPReqURLRealm, 0, realmNameStr.Ptr, ::strlen(realmNameStr.Ptr));
else // if auth scheme is basic and no realm is present, or if the auth scheme is digest, use the realm from the users file
{
char* userRealm = NULL;
(void) QTSS_GetValueAsString(theUserProfile, qtssUserRealm, 0, &userRealm);
if(userRealm != NULL)
{
OSCharArrayDeleter userRealmDeleter(userRealm);
(void) QTSS_SetValue(theRTSPRequest,qtssRTSPReqURLRealm, 0, userRealm, ::strlen(userRealm));
}
}
*outAuthorizedPtr = allowRequest;
Bool16 founduser = this->HaveUser(username, NULL);
Bool16 authContinue = true;
char nameBuff[256];
StrPtrLen reqNameStr(nameBuff, kBuffLen);
StrPtrLen profileNameStr(username);
theErr = QTSS_GetValue (theRTSPRequest,qtssRTSPReqUserName,0, (void *) reqNameStr.Ptr, &reqNameStr.Len);
if (DEBUG_QTACCESS)
{ qtss_printf("QTAccessFile::AuthorizeRequest qtaccess profile user =%s ", username);
reqNameStr.PrintStr("request user=","\n");
qtss_printf("QTAccessFile::AuthorizeRequest allowRequest=%d founduser=%d authContinue=%d\n", allowRequest, founduser, authContinue);
}
if (allowRequest && founduser)
theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &founduser,&authContinue);
if (!allowRequest && !founduser)
theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &founduser,&authContinue);
if (DEBUG_QTACCESS)
{ qtss_printf("QTAccessFile::AuthorizeRequest QTSSModuleUtils::AuthorizeRequest qtaccess profile user =%s ", username);
reqNameStr.PrintStr("request user=","\n");
qtss_printf("QTAccessFile::AuthorizeRequest allowRequest=%d founduser=%d authContinue=%d\n", allowRequest, founduser, authContinue);
}
return theErr;
}
bool DSAccessFile::CheckGroupMembership(const char* inUsername, const char* inGroupName)
{
struct passwd *user = NULL;
struct group *group = NULL;
#if __MacOSX__
uuid_t userID;
uuid_t groupID;
int isMember = 0;
#else
int numGroups = 50;
gid_t *groupList;
groupList = (gid_t *) malloc(numGroups * sizeof(gid_t));
#endif
// Look up the user using the POSIX APIs: only care about the UID.
user = getpwnam(inUsername);
if ( user == NULL )
return false;
#if __MacOSX__
uuid_clear(userID);
if ( mbr_uid_to_uuid(user->pw_uid, userID) )
return false;
#endif
// Look up the group using the POSIX APIs: only care about the GID.
group = getgrnam(inGroupName);
endgrent();
if ( group == NULL )
return false;
#if __MacOSX__
uuid_clear(groupID);
if ( mbr_gid_to_uuid(group->gr_gid, groupID) )
return false;
// In Tiger, group membership is painfully simple: we ask memberd for it!
// mbr_check_membership() returns 0 on success and error code on failure.
if ( mbr_check_membership(userID, groupID, &isMember) )
return false;
return (bool)isMember;
#else
if(getgrouplist(inUsername, user->pw_gid, groupList, &numGroups) == -1) {
qtss_printf("QTAccessFile::CheckGroupMembership getgrouplist for user %s returned -1 and numGroups = %d", inUsername, numGroups);
return false;
}
for(int i = 0; i < numGroups; i++) {
if(groupList[i] == group->gr_gid) {
return true;
}
}
return false;
#endif
}
Bool16 DSAccessFile::ValidUser( char*userName, void* extraDataPtr)
{
struct passwd *user = getpwnam(userName);
Bool16 result =true;
if ( user == NULL )
{
return result;
}
return true;
}

View file

@ -0,0 +1,117 @@
/*
*
* @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: QTAccessFile.h
Contains: This object contains an interface for finding and parsing qtaccess files.
*/
#ifndef _QT_ACCESS_FILE_H_
#define _QT_ACCESS_FILE_H_
#include <stdlib.h>
#include "SafeStdLib.h"
#include "QTSS.h"
#include "StrPtrLen.h"
#include "OSHeaders.h"
#include "StringParser.h"
#include "OSMutex.h"
class QTAccessFile
{
public:
static UInt8 sWhitespaceAndGreaterThanMask[];
static void Initialize();
static char * GetUserNameCopy(QTSS_UserProfileObject inUserProfile);
//GetGroupsArrayCopy
//
// GetGroupsArrayCopy allocates outGroupCharPtrArray. Caller must "delete [] outGroupCharPtrArray" when done.
static char* GetAccessFile_Copy( const char* movieRootDir, const char* dirPath);
//over ride these in a sub class
virtual Bool16 HaveUser(char *userName, void* extraDataPtr);
virtual Bool16 HaveGroups( char** groupArray, UInt32 numGroups, void* extraDataPtr);
virtual Bool16 HaveRealm( char *userName, StrPtrLen* ioRealmNameStr, void *extraData );
virtual Bool16 TestUser(StrPtrLen* accessUser, char *userName,void *extraDataPtr );
virtual Bool16 TestGroup( StrPtrLen* accessGroup, char *userName, char**groupArray, UInt32 numGroups, void *extraDataPtr);
virtual Bool16 TestExtraData( StrPtrLen* wordPtr, StringParser* lineParserPtr, void* extraDataPtr);
virtual void GetRealm(StrPtrLen* accessRealm, StrPtrLen* ioRealmNameStr, char *userName,void *extraDataPtr );
virtual Bool16 ValidUser(char* userName, void* extraDataPtr) { return false; };
//AccessAllowed
//
// This routine is used to get the Realm to send back to a user and to check if a user has access
// userName: may be null.
// accessFileBufPtr:If accessFileBufPtr is NULL or contains a NULL PTR or 0 LEN then false is returned
// ioRealmNameStr: ioRealmNameStr and ioRealmNameStr->Ptr may be null.
// To get a returned ioRealmNameStr value the ioRealmNameStr and ioRealmNameStr->Ptr must be non-NULL
// valid pointers. The ioRealmNameStr.Len should be set to the ioRealmNameStr->Ptr's allocated len.
// numGroups: The number of groups in the groupArray. Use GetGroupsArrayCopy to create the groupArray.
Bool16 AccessAllowed ( char *userName, char**groupArray, UInt32 numGroups,
StrPtrLen *accessFileBufPtr,QTSS_ActionFlags inFlags,StrPtrLen* ioRealmNameStr,
Bool16* outAllowAnyUserPtr,
void *extraDataPtr = NULL
);
static void SetAccessFileName(const char *inQTAccessFileName); //makes a copy and stores it
static char* GetAccessFileName() { return sQTAccessFileName; }; // a reference. Don't delete!
// allocates memory for outUsersFilePath and outGroupsFilePath - remember to delete
// returns the auth scheme
static QTSS_AuthScheme FindUsersAndGroupsFilesAndAuthScheme(char* inAccessFilePath, QTSS_ActionFlags inAction, char** outUsersFilePath, char** outGroupsFilePath);
QTSS_Error AuthorizeRequest(QTSS_StandardRTSP_Params* inParams, Bool16 allowNoAccessFiles, QTSS_ActionFlags noAction, QTSS_ActionFlags authorizeAction, Bool16 *outAuthorizedPtr, Bool16* outAllowAnyUserPtr = NULL);
virtual ~QTAccessFile() {};
private:
static char* sQTAccessFileName; // managed by the QTAccess module
static Bool16 sAllocatedName;
static OSMutex* sAccessFileMutex;
static char* sAccessValidUser;
static char* sAccessAnyUser;
};
class DSAccessFile : public QTAccessFile
{
public:
virtual ~DSAccessFile() {}
virtual Bool16 HaveGroups( char** groupArray, UInt32 numGroups, void* extraDataPtr) { return true; }
virtual Bool16 TestGroup( StrPtrLen* accessGroup, char *userName, char**groupArray, UInt32 numGroups, void *extraDataPtr)
{ StrPtrLenDel deleter( accessGroup->GetAsCString() );
return this->CheckGroupMembership(userName, deleter.Ptr );
}
virtual Bool16 ValidUser(char* userName, void* extraDataPtr);
bool CheckGroupMembership(const char* inUsername, const char* inGroupName);
};
#endif //_QT_ACCESS_FILE_H_

View file

@ -0,0 +1,128 @@
/*
*
* @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: QTSS3GPPModuleUtils.cpp
Contains: Implements utility routines defined in QTSS3GPPModuleUtils.h.
*/
#include "QTSS3GPPModuleUtils.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 "StringParser.h"
#include "SafeStdLib.h"
QTSS_TextMessagesObject QTSS3GPPModuleUtils::sMessages = NULL;
QTSS_ServerObject QTSS3GPPModuleUtils::sServer = NULL;
QTSS_PrefsObject QTSS3GPPModuleUtils::sServerPrefs = NULL;
QTSS_StreamRef QTSS3GPPModuleUtils::sErrorLog = NULL;
StrPtrLen QTSS3GPPModuleUtils::s3gppBitRateAdaptationSDPStr("a=3GPP-Adaptation-Support:");
const char* k3gppRateAdaptationReportFreqPrefName = "3gpp_protocol_rate_adaptation_report_frequency";
Bool16 QTSS3GPPModuleUtils::s3gppEnabled = false;
Bool16 QTSS3GPPModuleUtils::s3gppRateAdaptationEnabled = false;
UInt16 QTSS3GPPModuleUtils::s3gppRateAdaptationReportFrequency = 1;
void QTSS3GPPModuleUtils::Initialize(QTSS_Initialize_Params* initParams)
{
if (NULL == initParams)
return;
sServer = initParams->inServer;
sServerPrefs = initParams->inPrefs;
sMessages = initParams->inMessages;
sErrorLog = initParams->inErrorLogStream;
}
void QTSS3GPPModuleUtils::ValidatePrefs()
{
// min and max values per 3gpp rel-6 A26234 5.3.3.5
if (s3gppRateAdaptationReportFrequency < 1 || s3gppRateAdaptationReportFrequency > 9)
QTSSModuleUtils::LogPrefErrorStr( qtssWarningVerbosity, (char*) k3gppRateAdaptationReportFreqPrefName, "has an invalid value: valid range is [1..9]");
if (s3gppRateAdaptationReportFrequency < 1)
s3gppRateAdaptationReportFrequency = 1;
if (s3gppRateAdaptationReportFrequency > 9)
s3gppRateAdaptationReportFrequency = 9;
}
void QTSS3GPPModuleUtils::ReadPrefs()
{
const Bool16 kDefaultEnable = true;
const UInt16 kDefaultReportFreq = 1;
QTSSModuleUtils::GetAttribute(sServerPrefs,"enable_3gpp_protocol", qtssAttrDataTypeBool16,
&s3gppEnabled,(void *)&kDefaultEnable, sizeof(s3gppEnabled));
QTSSModuleUtils::GetAttribute(sServerPrefs,"enable_3gpp_protocol_rate_adaptation", qtssAttrDataTypeBool16,
&s3gppRateAdaptationEnabled,(void *)&kDefaultEnable, sizeof(s3gppRateAdaptationEnabled));
QTSSModuleUtils::GetAttribute(sServerPrefs, (char *) k3gppRateAdaptationReportFreqPrefName, qtssAttrDataTypeUInt16,
&s3gppRateAdaptationReportFrequency,(void *)&kDefaultReportFreq, sizeof(s3gppRateAdaptationReportFrequency));
QTSS3GPPModuleUtils::ValidatePrefs();
}
SDPContainer* QTSS3GPPModuleUtils::Get3GPPSDPFeatureListCopy(ResizeableStringFormatter &buffer)
{
SDPContainer* resultList = NEW SDPContainer;
StrPtrLen theLinePtr;
if (s3gppEnabled)
{
if (s3gppRateAdaptationEnabled)
{
buffer.Put(s3gppBitRateAdaptationSDPStr);
buffer.Put((SInt32) s3gppRateAdaptationReportFrequency);
buffer.PutEOL();
theLinePtr.Set(buffer.GetBufPtr(),buffer.GetBytesWritten());
resultList->AddHeaderLine(&theLinePtr);
buffer.Reset();
}
}
return resultList;
}

View file

@ -0,0 +1,74 @@
/*
*
* @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: QTSS3GPPModuleUtils.h
Contains: Utility routines for 3GPP modules to use.
*/
#ifndef _QTSS_3GPP_MODULE_UTILS_H_
#define _QTSS_3GPP_MODULE_UTILS_H_
#include <stdlib.h>
#include "SafeStdLib.h"
#include "QTSS.h"
#include "StrPtrLen.h"
#include "SDPUtils.h"
class QTSS3GPPModuleUtils
{
public:
static void Initialize(QTSS_Initialize_Params* initParams);
static void ReadPrefs();
static SDPContainer* Get3GPPSDPFeatureListCopy(ResizeableStringFormatter &buffer);
private:
static void ValidatePrefs();
//
// Used in the implementation of the above functions
static QTSS_TextMessagesObject sMessages;
static QTSS_ServerObject sServer;
static QTSS_PrefsObject sServerPrefs;
static QTSS_StreamRef sErrorLog;
static StrPtrLen s3gppBitRateAdaptationSDPStr;
static Bool16 s3gppEnabled;
static Bool16 s3gppRateAdaptationEnabled;
static UInt16 s3gppRateAdaptationReportFrequency;
};
#endif //_QTSS_3GPP_MODULE_UTILS_H_

View file

@ -0,0 +1,66 @@
/*
*
* @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: QTSSMemoryDeleter.h
Contains: Auto object for deleting memory allocated by QTSS API callbacks,
such as QTSS_GetValueAsString
*/
#ifndef __QTSS_MEMORY_DELETER_H__
#define __QTSS_MEMORY_DELETER_H__
#include "MyAssert.h"
#include "QTSS.h"
template <class T>
class QTSSMemoryDeleter
{
public:
QTSSMemoryDeleter(T* victim) : fT(victim) {}
~QTSSMemoryDeleter() { QTSS_Delete(fT); }
void ClearObject() { fT = NULL; }
void SetObject(T* victim)
{
Assert(fT == NULL);
fT = victim;
}
T* GetObject() { return fT; }
operator T*() { return fT; }
private:
T* fT;
};
typedef QTSSMemoryDeleter<char> QTSSCharArrayDeleter;
#endif //__QTSS_MEMORY_DELETER_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,291 @@
/*
*
* @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,QTSSCharArrayDeleter theDigitStrDeleter(theDigitStr);
* 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.h
Contains: Utility routines for modules to use.
*/
#ifndef _QTSS_MODULE_UTILS_H_
#define _QTSS_MODULE_UTILS_H_
#include <stdlib.h>
#include "SafeStdLib.h"
#include "QTSS.h"
#include "StrPtrLen.h"
#include "RTPMetaInfoPacket.h"
class QTSSModuleUtils
{
public:
// compatibiltiy features for certain players
enum {
kRequiresRTPInfoSeqAndTime = 0,
kAdjustBandwidth = 1,
kDisablePauseAdjustedRTPTime= 2,
kDelayRTPStreamsUntilAfterRTSPResponse = 3,
kDisable3gppRateAdaptation =4,
kAdjust3gppTargetTime = 5,
kDisableThinning =6,
};
static void Initialize( QTSS_TextMessagesObject inMessages,
QTSS_ServerObject inServer,
QTSS_StreamRef inErrorLog);
// Read the complete contents of the file at inPath into the StrPtrLen.
// This function allocates memory for the file data.
static QTSS_Error ReadEntireFile(char* inPath, StrPtrLen* outData, QTSS_TimeVal inModDate = -1, QTSS_TimeVal* outModDate = NULL);
// If your module supports RTSP methods, call this function from your QTSS_Initialize
// role to tell the server what those methods are.
static void SetupSupportedMethods( QTSS_Object inServer,
QTSS_RTSPMethod* inMethodArray,
UInt32 inNumMethods);
// Using a message out of the text messages dictionary is a common
// way to log errors to the error log. Here is a function to
// make that process very easy.
static void LogError( QTSS_ErrorVerbosity inVerbosity,
QTSS_AttributeID inTextMessage,
UInt32 inErrNumber,
char* inArgument = NULL,
char* inArg2 = NULL);
static void LogErrorStr( QTSS_ErrorVerbosity inVerbosity, char* inMessage);
static void LogPrefErrorStr( QTSS_ErrorVerbosity inVerbosity, char* preference, char* inMessage);
// This function constructs a C-string of the full path to the file being requested.
// You may opt to append an optional suffix, or pass in NULL. You are responsible
// for disposing this memory
static char* GetFullPath( QTSS_RTSPRequestObject inRequest,
QTSS_AttributeID whichFileType,
UInt32* outLen,
StrPtrLen* suffix = NULL);
//
// This function does 2 things:
// 1. Compares the enabled fields in the field ID array with the fields in the
// x-RTP-Meta-Info header. Turns off the fields in the array that aren't in the request.
//
// 2. Appends the x-RTP-Meta-Info header to the response, using the proper
// fields from the array, as well as the IDs provided in the array
static QTSS_Error AppendRTPMetaInfoHeader( QTSS_RTSPRequestObject inRequest,
StrPtrLen* inRTPMetaInfoHeader,
RTPMetaInfoPacket::FieldID* inFieldIDArray);
// This function sends an error to the RTSP client. You must provide a
// status code for the error, and a text message ID to describe the error.
//
// It always returns QTSS_RequestFailed.
static QTSS_Error SendErrorResponse( QTSS_RTSPRequestObject inRequest,
QTSS_RTSPStatusCode inStatusCode,
QTSS_AttributeID inTextMessage,
StrPtrLen* inStringArg = NULL);
// This function sends an error to the RTSP client. You don't have to provide
// a text message ID, but instead you need to provide the error message in a
// string
//
// It always returns QTSS_RequestFailed
static QTSS_Error SendErrorResponseWithMessage( QTSS_RTSPRequestObject inRequest,
QTSS_RTSPStatusCode inStatusCode,
StrPtrLen* inErrorMessageStr);
// Sends and HTTP 1.1 error message with an error message in HTML if errorMessage != NULL.
// The session must be flagged by KillSession set to true to kill.
// Use the QTSS_RTSPStatusCodes for the inStatusCode, for now they are the same as HTTP.
//
// It always returns QTSS_RequestFailed
static QTSS_Error SendHTTPErrorResponse( QTSS_RTSPRequestObject inRequest,
QTSS_SessionStatusCode inStatusCode,
Bool16 inKillSession,
char *errorMessage);
//Modules most certainly don't NEED to use this function, but it is awfully handy
//if they want to take advantage of it. Using the SDP data provided in the iovec,
//this function sends a standard describe response.
//NOTE: THE FIRST ENTRY OF THE IOVEC MUST BE EMPTY!!!!
static void SendDescribeResponse(QTSS_RTSPRequestObject inRequest,
QTSS_ClientSessionObject inSession,
iovec* describeData,
UInt32 inNumVectors,
UInt32 inTotalLength);
// Called by SendDescribeResponse to coalesce iovec to a buffer
// Allocates memory - remember to delete it!
static char* CoalesceVectors(iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength);
//
// SEARCH FOR A SPECIFIC MODULE OBJECT
static QTSS_ModulePrefsObject GetModuleObjectByName(const StrPtrLen& inModuleName);
//
// GET MODULE PREFS OBJECT
static QTSS_ModulePrefsObject GetModulePrefsObject(QTSS_ModuleObject inModObject);
// GET MODULE ATTRIBUTES OBJECT
static QTSS_Object GetModuleAttributesObject(QTSS_ModuleObject inModObject);
//
// GET ATTRIBUTE
//
// This function retrieves an attribute
// (from any QTSS_Object, including the QTSS_ModulePrefsObject)
// with the specified name and type
// out of the specified object.
//
// Caller should pass in a buffer for ioBuffer that is large enough
// to hold the attribute value. inBufferLen should be set to the length
// of this buffer.
//
// Pass in a buffer containing a default value to use for the attribute
// in the inDefaultValue parameter. If the attribute isn't found, or is
// of the wrong type, the default value will be copied into ioBuffer.
// Also, this function adds the default value to object if it is not
// found or is of the wrong type. If no default value is provided, the
// attribute is still added but no value is assigned to it.
//
// Pass in NULL for the default value or 0 for the default value length if it is not known.
//
// This function logs an error if there was a default value provided.
static void GetAttribute(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType,
void* ioBuffer, void* inDefaultValue, UInt32 inBufferLen);
static void GetIOAttribute(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType,
void* ioDefaultResultBuffer, UInt32 inBufferLen);
//
// GET STRING ATTRIBUTE
//
// Does the same thing as GetAttribute, but does it for string attribute. Returns a newly
// allocated buffer with the attribute value inside it.
//
// Pass in NULL for the default value or an empty string if the default is not known.
static char* GetStringAttribute(QTSS_Object inObject, char* inAttributeName, char* inDefaultValue);
//
// GET ATTR ID
//
// Given an attribute in an object, returns its attribute ID
// or qtssIllegalAttrID if it isn't found.
static QTSS_AttributeID GetAttrID(QTSS_Object inObject, char* inAttributeName);
//
//
//
/// Get the type of request. Returns qtssActionFlagsNoFlags on failure.
// Result is a bitmap of flags
//
static QTSS_ActionFlags GetRequestActions(QTSS_RTSPRequestObject theRTSPRequest);
static char* GetLocalPath_Copy(QTSS_RTSPRequestObject theRTSPRequest);
static char* GetMoviesRootDir_Copy(QTSS_RTSPRequestObject theRTSPRequest);
static QTSS_UserProfileObject GetUserProfileObject(QTSS_RTSPRequestObject theRTSPRequest);
static QTSS_AttrRights GetRights(QTSS_UserProfileObject theUserProfileObject);
static char* GetExtendedRights(QTSS_UserProfileObject theUserProfileObject, UInt32 index);
static char* GetUserName_Copy(QTSS_UserProfileObject inUserProfile);
static char** GetGroupsArray_Copy(QTSS_UserProfileObject inUserProfile, UInt32 *outNumGroupsPtr);
static Bool16 UserInGroup(QTSS_UserProfileObject inUserProfile, char* inGroupName, UInt32 inGroupNameLen);
static void SetEnableRTSPErrorMsg(Bool16 enable) {QTSSModuleUtils::sEnableRTSPErrorMsg = enable; }
static QTSS_AttributeID CreateAttribute(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType, void* inDefaultValue, UInt32 inBufferLen);
static Bool16 AddressInList(QTSS_Object inObject, QTSS_AttributeID listID, StrPtrLen *theAddressPtr);
static void SetMisingPrefLogVerbosity(QTSS_ErrorVerbosity verbosityLevel) { QTSSModuleUtils::sMissingPrefVerbosity = verbosityLevel;}
static QTSS_ErrorVerbosity GetMisingPrefLogVerbosity() { return QTSSModuleUtils::sMissingPrefVerbosity;}
static Bool16 FindStringInAttributeList(QTSS_Object inObject, QTSS_AttributeID listID, StrPtrLen *inStrPtr);
static Bool16 HavePlayerProfile(QTSS_PrefsObject inPrefObjectToCheck, QTSS_StandardRTSP_Params* inParams, UInt32 feature);
static QTSS_Error AuthorizeRequest(QTSS_RTSPRequestObject theRTSPRequest, Bool16* allowed, Bool16*haveUser,Bool16 *authContinue);
private:
//
// Used in the implementation of the above functions
static QTSS_AttributeID CheckAttributeDataType(QTSS_Object inObject, char* inAttributeName, QTSS_AttrDataType inType, void* inDefaultValue, UInt32 inBufferLen);
static QTSS_TextMessagesObject sMessages;
static QTSS_ServerObject sServer;
static QTSS_StreamRef sErrorLog;
static Bool16 sEnableRTSPErrorMsg;
static QTSS_ErrorVerbosity sMissingPrefVerbosity;
};
class IPComponentStr
{
public:
enum { kNumComponents = 4 };
StrPtrLen fAddressComponent[kNumComponents];
Bool16 fIsValid;
static IPComponentStr sLocalIPCompStr;
IPComponentStr() : fIsValid(false) {}
IPComponentStr(char *theAddress);
IPComponentStr(StrPtrLen *sourceStrPtr);
inline StrPtrLen* GetComponent(UInt16 which);
Bool16 Equal(IPComponentStr *testAddressPtr);
Bool16 Set(StrPtrLen *theAddressStrPtr);
Bool16 Valid() { return fIsValid; }
inline Bool16 IsLocal();
};
Bool16 IPComponentStr::IsLocal()
{
if (this->Equal(&sLocalIPCompStr))
return true;
return false;
}
StrPtrLen* IPComponentStr::GetComponent(UInt16 which)
{
if (which < IPComponentStr::kNumComponents)
return &fAddressComponent[which];
Assert(0);
return NULL;
}
#endif //_QTSS_MODULE_UTILS_H_

View file

@ -0,0 +1,550 @@
/*
*
* @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: QTSSRollingLog.cpp
Contains: Implements object defined in .h file
*/
#include <time.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/time.h>
#endif
#include "QTSSRollingLog.h"
#include "OS.h"
#include "OSMemory.h"
#include "OSArrayObjectDeleter.h"
#include "ResizeableStringFormatter.h"
static Bool16 sCloseOnWrite = true;
QTSSRollingLog::QTSSRollingLog() :
fLog(NULL),
fLogCreateTime(-1),
fLogFullPath(NULL),
fAppendDotLog(true),
fLogging(true)
{
this->SetTaskName("QTSSRollingLog");
}
QTSSRollingLog::~QTSSRollingLog()
{
//
// Log should already be closed, but just in case...
this->CloseLog();
delete [] fLogFullPath;
}
// Set this to true to get the log to close the file between writes.
void QTSSRollingLog::SetCloseOnWrite(Bool16 closeOnWrite)
{
sCloseOnWrite = closeOnWrite;
}
Bool16 QTSSRollingLog::IsLogEnabled()
{
return sCloseOnWrite || (fLog != NULL);
}
void QTSSRollingLog::WriteToLog(char* inLogData, Bool16 allowLogToRoll)
{
OSMutexLocker locker(&fMutex);
if (fLogging == false)
return;
if (sCloseOnWrite && fLog == NULL)
this->EnableLog(fAppendDotLog ); //re-open log file before we write
if (allowLogToRoll)
(void)this->CheckRollLog();
if (fLog != NULL)
{
qtss_fprintf(fLog, "%s", inLogData);
::fflush(fLog);
}
if (sCloseOnWrite)
this->CloseLog( false );
}
Bool16 QTSSRollingLog::RollLog()
{
OSMutexLocker locker(&fMutex);
//returns false if an error occurred, true otherwise
//close the old file.
if (fLog != NULL)
this->CloseLog();
if (fLogging == false)
return false;
//rename the old file
Bool16 result = this->RenameLogFile(fLogFullPath);
if (result)
this->EnableLog(fAppendDotLog);//re-opens log file
return result;
}
char* QTSSRollingLog::GetLogPath(char *extension)
{
char *thePath = NULL;
OSCharArrayDeleter logDir(this->GetLogDir()); //The string passed into this function is a copy
OSCharArrayDeleter logName(this->GetLogName()); //The string passed into this function is a copy
ResizeableStringFormatter formatPath(NULL,0); //allocate the buffer
formatPath.PutFilePath(logDir, logName);
if ( extension != NULL)
formatPath.Put(extension);
formatPath.PutTerminator();
thePath = formatPath.GetBufPtr();
formatPath.Set(NULL,0); //don't delete buffer we are returning the path as a result
return thePath;
}
void QTSSRollingLog::EnableLog( Bool16 appendDotLog )
{
//
// Start this object running!
this->Signal(Task::kStartEvent);
OSMutexLocker locker(&fMutex);
fAppendDotLog = appendDotLog;
if (fLogging == false)
return;
char *extension = ".log";
if (!appendDotLog)
extension = NULL;
delete[] fLogFullPath;
fLogFullPath = this->GetLogPath(extension);
//we need to make sure that when we create a new log file, we write the
//log header at the top
Bool16 logExists = this->DoesFileExist(fLogFullPath);
//create the log directory if it doesn't already exist
if (!logExists)
{
OSCharArrayDeleter tempDir(this->GetLogDir());
OS::RecursiveMakeDir(tempDir.GetObject());
}
fLog = ::fopen(fLogFullPath, "a+");//open for "append"
if (NULL != fLog)
{
if (!logExists) //the file is new, write a log header with the create time of the file.
{ fLogCreateTime = this->WriteLogHeader(fLog);
#if __MacOSX__
(void) ::chown(fLogFullPath, 76, (gid_t)-1);//set owner to user qtss.
#endif
}
else //the file is old, read the log header to find the create time of the file.
fLogCreateTime = this->ReadLogHeader(fLog);
}
}
void QTSSRollingLog::CloseLog( Bool16 leaveEnabled )
{
OSMutexLocker locker(&fMutex);
if (leaveEnabled)
sCloseOnWrite = true;
if (fLog != NULL)
{
::fclose(fLog);
fLog = NULL;
}
}
//returns false if some error has occurred
Bool16 QTSSRollingLog::FormatDate(char *ioDateBuffer, Bool16 logTimeInGMT)
{
Assert(NULL != ioDateBuffer);
//use ansi routines for getting the date.
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
if (-1 == calendarTime)
return false;
struct tm* theTime = NULL;
struct tm timeResult;
if (logTimeInGMT)
theTime = ::qtss_gmtime(&calendarTime, &timeResult);
else
theTime = qtss_localtime(&calendarTime, &timeResult);
Assert(NULL != theTime);
if (NULL == theTime)
return false;
// date time needs to look like this for extended log file format: 2001-03-16 23:34:54
// this wonderful ANSI routine just does it for you.
// the format is YYYY-MM-DD HH:MM:SS
// the date time is in GMT, unless logTimeInGMT is false, in which case
// the time logged is local time
//qtss_strftime(ioDateBuffer, kMaxDateBufferSize, "%d/%b/%Y:%H:%M:%S", theLocalTime);
qtss_strftime(ioDateBuffer, kMaxDateBufferSizeInBytes, "%Y-%m-%d %H:%M:%S", theTime);
return true;
}
Bool16 QTSSRollingLog::CheckRollLog()
{
//returns false if an error occurred, true otherwise
if (fLog == NULL)
return true;
//first check to see if log rolling should happen because of a date interval.
//This takes precedence over size based log rolling
// this is only if a client connects just between 00:00:00 and 00:01:00
// since the task object runs every minute
// when an entry is written to the log file, only the file size must be checked
// to see if it exceeded the limits
// the roll interval should be monitored in a task object
// and rolled at midnight if the creation time has exceeded.
if ((-1 != fLogCreateTime) && (0 != this->GetRollIntervalInDays()))
{
time_t logCreateTimeMidnight = -1;
QTSSRollingLog::ResetToMidnight(&fLogCreateTime, &logCreateTimeMidnight);
Assert(logCreateTimeMidnight != -1);
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
if (-1 != calendarTime)
{
double theExactInterval = ::difftime(calendarTime, logCreateTimeMidnight);
SInt32 theCurInterval = (SInt32)::floor(theExactInterval);
//transfer_roll_interval is in days, theCurInterval is in seconds
SInt32 theRollInterval = this->GetRollIntervalInDays() * 60 * 60 * 24;
if (theCurInterval > theRollInterval)
return this->RollLog();
}
}
//now check size based log rolling
UInt32 theCurrentPos = ::ftell(fLog);
//max_transfer_log_size being 0 is a signal to ignore the setting.
if ((this->GetMaxLogBytes() != 0) &&
(theCurrentPos > this->GetMaxLogBytes()))
return this->RollLog();
return true;
}
Bool16 QTSSRollingLog::RenameLogFile(const char* inFileName)
{
//returns false if an error occurred, true otherwise
//this function takes care of renaming a log file from "myLogFile.log" to
//"myLogFile.981217000.log" or if that is already taken, myLogFile.981217001.log", etc
//fix 2287086. Rolled log name can be different than original log name
//GetLogDir returns a copy of the log dir
OSCharArrayDeleter logDirectory(this->GetLogDir());
//create the log directory if it doesn't already exist
OS::RecursiveMakeDir(logDirectory.GetObject());
//GetLogName returns a copy of the log name
OSCharArrayDeleter logBaseName(this->GetLogName());
//QTStreamingServer.981217003.log
//format the new file name
OSCharArrayDeleter theNewNameBuffer(NEW char[::strlen(logDirectory) + kMaxFilenameLengthInBytes + 3]);
//copy over the directory - append a '/' if it's missing
::strcpy(theNewNameBuffer, logDirectory);
if (theNewNameBuffer[::strlen(theNewNameBuffer)-1] != kPathDelimiterChar)
{
::strcat(theNewNameBuffer, kPathDelimiterString);
}
//copy over the base filename
::strcat(theNewNameBuffer, logBaseName.GetObject());
//append the date the file was created
struct tm timeResult;
struct tm* theLocalTime = qtss_localtime(&fLogCreateTime, &timeResult);
char timeString[10];
qtss_strftime(timeString, 10, ".%y%m%d", theLocalTime);
::strcat(theNewNameBuffer, timeString);
SInt32 theBaseNameLength = ::strlen(theNewNameBuffer);
//loop until we find a unique name to rename this file
//and append the log number and suffix
SInt32 theErr = 0;
for (SInt32 x = 0; (theErr == 0) && (x<=1000); x++)
{
if (x == 1000) //we don't have any digits left, so just reuse the "---" until tomorrow...
{
//add a bogus log number and exit the loop
qtss_sprintf(theNewNameBuffer + theBaseNameLength, "---.log");
break;
}
//add the log number & suffix
qtss_sprintf(theNewNameBuffer + theBaseNameLength, "%03"_S32BITARG_".log", x);
//assume that when ::stat returns an error, it is becase
//the file doesnt exist. Once that happens, we have a unique name
// csl - shouldn't you watch for a ENOENT result?
struct stat theIdontCare;
theErr = ::stat(theNewNameBuffer, &theIdontCare);
WarnV((theErr == 0 || OSThread::GetErrno() == ENOENT), "unexpected stat error in RenameLogFile");
}
//rename the file. Use posix rename function
int result = ::rename(inFileName, theNewNameBuffer);
if (result == -1)
theErr = (SInt32)OSThread::GetErrno();
else
theErr = 0;
WarnV(theErr == 0 , "unexpected rename error in RenameLogFile");
if (theErr != 0)
return false;
else
return true;
}
Bool16 QTSSRollingLog::DoesFileExist(const char *inPath)
{
struct stat theStat;
int theErr = ::stat(inPath, &theStat);
if (theErr != 0)
return false;
else
return true;
}
time_t QTSSRollingLog::WriteLogHeader(FILE* inFile)
{
OSMutexLocker locker(&fMutex);
//The point of this header is to record the exact time the log file was created,
//in a format that is easy to parse through whenever we open the file again.
//This is necessary to support log rolling based on a time interval, and POSIX doesn't
//support a create date in files.
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
if (-1 == calendarTime)
return -1;
struct tm timeResult;
struct tm* theLocalTime = qtss_localtime(&calendarTime, &timeResult);
Assert(NULL != theLocalTime);
if (NULL == theLocalTime)
return -1;
//
// Files are always created at hour 0 (we don't care about the time, we always
// want them to roll at midnight.
//theLocalTime->tm_hour = 0;
//theLocalTime->tm_min = 0;
//theLocalTime->tm_sec = 0;
char tempbuf[1024];
qtss_strftime(tempbuf, sizeof(tempbuf), "#Log File Created On: %m/%d/%Y %H:%M:%S\n", theLocalTime);
//qtss_sprintf(tempbuf, "#Log File Created On: %d/%d/%d %d:%d:%d %d:%d:%d GMT\n",
// theLocalTime->tm_mon, theLocalTime->tm_mday, theLocalTime->tm_year,
// theLocalTime->tm_hour, theLocalTime->tm_min, theLocalTime->tm_sec,
// theLocalTime->tm_yday, theLocalTime->tm_wday, theLocalTime->tm_isdst);
this->WriteToLog(tempbuf, !kAllowLogToRoll);
return this->ReadLogHeader(inFile);
}
time_t QTSSRollingLog::ReadLogHeader(FILE* inFile)
{
OSMutexLocker locker(&fMutex);
//This function reads the header in a log file, returning the time stored
//at the beginning of this file. This value is used to determine when to
//roll the log.
//Returns -1 if the header is bogus. In that case, just ignore time based log rolling
//first seek to the beginning of the file
SInt32 theCurrentPos = ::ftell(inFile);
if (theCurrentPos == -1)
return -1;
(void)::rewind(inFile);
const UInt32 kMaxHeaderLength = 500;
char theFirstLine[kMaxHeaderLength];
if (NULL == ::fgets(theFirstLine, kMaxHeaderLength, inFile))
{
::fseek(inFile, 0, SEEK_END);
return -1;
}
::fseek(inFile, 0, SEEK_END);
struct tm theFileCreateTime;
// Zero out fields we will not be using
theFileCreateTime.tm_isdst = -1;
theFileCreateTime.tm_wday = 0;
theFileCreateTime.tm_yday = 0;
//if (EOF == ::sscanf(theFirstLine, "#Log File Created On: %d/%d/%d %d:%d:%d\n",
// &theFileCreateTime.tm_mon, &theFileCreateTime.tm_mday, &theFileCreateTime.tm_year,
// &theFileCreateTime.tm_hour, &theFileCreateTime.tm_min, &theFileCreateTime.tm_sec))
// return -1;
//
// We always want to roll at hour 0, so ignore the time of creation
if (EOF == ::sscanf(theFirstLine, "#Log File Created On: %d/%d/%d %d:%d:%d\n",
&theFileCreateTime.tm_mon, &theFileCreateTime.tm_mday, &theFileCreateTime.tm_year,
&theFileCreateTime.tm_hour, &theFileCreateTime.tm_min, &theFileCreateTime.tm_sec))
return -1;
//
// It should be like this anyway, but if the log file is legacy, then...
// No! The log file will have the actual time in it but we shall return the exact time
//theFileCreateTime.tm_hour = 0;
//theFileCreateTime.tm_min = 0;
//theFileCreateTime.tm_sec = 0;
// Actually, it seems like all platforms need this.
//#ifdef __Win32__
// Win32 has slightly different atime basis than UNIX.
theFileCreateTime.tm_yday--;
theFileCreateTime.tm_mon--;
theFileCreateTime.tm_year -= 1900;
//#endif
#if 0
//use ansi routines for getting the date.
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
if (-1 == calendarTime)
return false;
struct tm timeResult;
struct tm* theLocalTime = qtss_localtime(&calendarTime, &timeResult);
Assert(NULL != theLocalTime);
if (NULL == theLocalTime)
return false;
#endif
//ok, we should have a filled in tm struct. Convert it to a time_t.
//time_t thePoopTime = ::mktime(theLocalTime);
time_t theTime = ::mktime(&theFileCreateTime);
return theTime;
}
SInt64 QTSSRollingLog::Run()
{
//
// If we are going away, just return
EventFlags events = this->GetEvents();
if (events & Task::kKillEvent)
return -1;
OSMutexLocker locker(&fMutex);
UInt32 theRollInterval = (this->GetRollIntervalInDays()) * 60 * 60 * 24;
if((fLogCreateTime != -1) && (fLog != NULL))
{
time_t logRollTimeMidnight = -1;
this->ResetToMidnight(&fLogCreateTime, &logRollTimeMidnight);
Assert(logRollTimeMidnight != -1);
if(theRollInterval != 0)
{
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
double theExactInterval = ::difftime(calendarTime, logRollTimeMidnight);
if(theExactInterval > 0) {
UInt32 theCurInterval = (UInt32)::floor(theExactInterval);
if (theCurInterval >= theRollInterval)
this->RollLog();
}
}
}
return 60 * 1000;
}
void QTSSRollingLog::ResetToMidnight(time_t* inTimePtr, time_t* outTimePtr)
{
if(*inTimePtr == -1)
{
*outTimePtr = -1;
return;
}
struct tm timeResult;
struct tm* theLocalTime = qtss_localtime(inTimePtr, &timeResult);
Assert(theLocalTime != NULL);
theLocalTime->tm_hour = 0;
theLocalTime->tm_min = 0;
theLocalTime->tm_sec = 0;
// some weird stuff
//theLocalTime->tm_yday--;
//theLocalTime->tm_mon--;
//theLocalTime->tm_year -= 1900;
*outTimePtr = ::mktime(theLocalTime);
}

View file

@ -0,0 +1,142 @@
/*
*
* @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: QTSSRollingLog.h
Contains: A log toolkit, log can roll either by time or by size, clients
must derive off of this object ot provide configuration information.
*/
#ifndef __QTSS_ROLLINGLOG_H__
#define __QTSS_ROLLINGLOG_H__
#include <stdio.h>
#include <time.h>
#ifndef __Win32__
#include <sys/time.h>
#endif
#include "OSHeaders.h"
#include "OSMutex.h"
#include "Task.h"
const Bool16 kAllowLogToRoll = true;
class QTSSRollingLog : public Task
{
public:
//pass in whether you'd like the log roller to log errors.
QTSSRollingLog();
//
// Call this to delete. Closes the log and sends a kill event
void Delete()
{ CloseLog(false); this->Signal(Task::kKillEvent); }
//
// Write a log message
void WriteToLog(char* inLogData, Bool16 allowLogToRoll);
//log rolls automatically based on the configuration criteria,
//but you may roll the log manually by calling this function.
//Returns true if no error, false otherwise
Bool16 RollLog();
//
// Call this to open the log file and begin logging
void EnableLog( Bool16 appendDotLog = true);
//
// Call this to close the log
// (pass leaveEnabled as true when we are temporarily closing.)
void CloseLog( Bool16 leaveEnabled = false);
//
//mainly to check and see if errors occurred
Bool16 IsLogEnabled();
//master switch
Bool16 IsLogging() { return fLogging; }
void SetLoggingEnabled( Bool16 logState ) { fLogging = logState; }
//General purpose utility function
//returns false if some error has occurred
static Bool16 FormatDate(char *ioDateBuffer, Bool16 logTimeInGMT);
// Check the log to see if it needs to roll
// (rolls the log if necessary)
Bool16 CheckRollLog();
// Set this to true to get the log to close the file between writes.
static void SetCloseOnWrite(Bool16 closeOnWrite);
enum
{
kMaxDateBufferSizeInBytes = 30, //UInt32
kMaxFilenameLengthInBytes = 31 //UInt32
};
protected:
//
// Task object. Do not delete directly
virtual ~QTSSRollingLog();
//Derived class must provide a way to get the log & rolled log name
virtual char* GetLogName() = 0;
virtual char* GetLogDir() = 0;
virtual UInt32 GetRollIntervalInDays() = 0;//0 means no interval
virtual UInt32 GetMaxLogBytes() = 0;//0 means unlimited
//to record the time the file was created (for time based rolling)
virtual time_t WriteLogHeader(FILE *inFile);
time_t ReadLogHeader(FILE* inFile);
private:
//
// Run function to roll log right at midnight
virtual SInt64 Run();
FILE* fLog;
time_t fLogCreateTime;
char* fLogFullPath;
Bool16 fAppendDotLog;
Bool16 fLogging;
Bool16 RenameLogFile(const char* inFileName);
Bool16 DoesFileExist(const char *inPath);
static void ResetToMidnight(time_t* inTimePtr, time_t* outTimePtr);
char* GetLogPath(char *extension);
// To make sure what happens in Run doesn't also happen at the same time
// in the public functions.
OSMutex fMutex;
};
#endif // __QTSS_ROLLINGLOG_H__

View file

@ -0,0 +1,437 @@
/*
*
* @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: SDPSourceInfo.cpp
Contains: Implementation of object defined in .h file
*/
#include "SDPSourceInfo.h"
#include "StringParser.h"
#include "StringFormatter.h"
#include "OSMemory.h"
#include "SocketUtils.h"
#include "StrPtrLen.h"
#include "SDPUtils.h"
#include "OSArrayObjectDeleter.h"
static StrPtrLen sCLine("c=IN IP4 0.0.0.0");
static StrPtrLen sControlLine("a=control:*");
static StrPtrLen sVideoStr("video");
static StrPtrLen sAudioStr("audio");
static StrPtrLen sRtpMapStr("rtpmap");
static StrPtrLen sControlStr("control");
static StrPtrLen sBufferDelayStr("x-bufferdelay");
static StrPtrLen sBroadcastControlStr("x-broadcastcontrol");
static StrPtrLen sAutoDisconnect("RTSP");
static StrPtrLen sAutoDisconnectTime("TIME");
SDPSourceInfo::~SDPSourceInfo()
{
// Not reqd as the destructor of the
// base class will take care of delete the stream array
// and output array if allocated
/*
if (fStreamArray != NULL)
{
char* theCharArray = (char*)fStreamArray;
delete [] theCharArray;
}
*/
fSDPData.Delete();
}
char* SDPSourceInfo::GetLocalSDP(UInt32* newSDPLen)
{
Assert(fSDPData.Ptr != NULL);
Bool16 appendCLine = true;
UInt32 trackIndex = 0;
char *localSDP = NEW char[fSDPData.Len * 2];
OSCharArrayDeleter charArrayPathDeleter(localSDP);
StringFormatter localSDPFormatter(localSDP, fSDPData.Len * 2);
StrPtrLen sdpLine;
StringParser sdpParser(&fSDPData);
char trackIndexBuffer[50];
// Only generate our own trackIDs if this file doesn't have 'em.
// Our assumption here is that either the file has them, or it doesn't.
// A file with some trackIDs, and some not, won't work.
Bool16 hasControlLine = false;
while (sdpParser.GetDataRemaining() > 0)
{
//stop when we reach an empty line.
sdpParser.GetThruEOL(&sdpLine);
if (sdpLine.Len == 0)
continue;
switch (*sdpLine.Ptr)
{
case 'c':
break;//ignore connection information
case 'm':
{
//append new connection information right before the first 'm'
if (appendCLine)
{
localSDPFormatter.Put(sCLine);
localSDPFormatter.PutEOL();
if (!hasControlLine)
{
localSDPFormatter.Put(sControlLine);
localSDPFormatter.PutEOL();
}
appendCLine = false;
}
//the last "a=" for each m should be the control a=
if ((trackIndex > 0) && (!hasControlLine))
{
qtss_sprintf(trackIndexBuffer, "a=control:trackID=%"_S32BITARG_"\r\n",trackIndex);
localSDPFormatter.Put(trackIndexBuffer, ::strlen(trackIndexBuffer));
}
//now write the 'm' line, but strip off the port information
StringParser mParser(&sdpLine);
StrPtrLen mPrefix;
mParser.ConsumeUntil(&mPrefix, StringParser::sDigitMask);
localSDPFormatter.Put(mPrefix);
localSDPFormatter.Put("0", 1);
(void)mParser.ConsumeInteger(NULL);
localSDPFormatter.Put(mParser.GetCurrentPosition(), mParser.GetDataRemaining());
localSDPFormatter.PutEOL();
trackIndex++;
break;
}
case 'a':
{
StringParser aParser(&sdpLine);
aParser.ConsumeLength(NULL, 2);//go past 'a='
StrPtrLen aLineType;
aParser.ConsumeWord(&aLineType);
if (aLineType.Equal(sControlStr))
{
aParser.ConsumeUntil(NULL, '=');
aParser.ConsumeUntil(NULL, StringParser::sDigitMask);
StrPtrLen aDigitType;
(void)aParser.ConsumeInteger(&aDigitType);
if (aDigitType.Len > 0)
{
localSDPFormatter.Put("a=control:trackID=", 18);
localSDPFormatter.Put(aDigitType);
localSDPFormatter.PutEOL();
hasControlLine = true;
break;
}
}
localSDPFormatter.Put(sdpLine);
localSDPFormatter.PutEOL();
break;
}
default:
{
localSDPFormatter.Put(sdpLine);
localSDPFormatter.PutEOL();
}
}
}
if ((trackIndex > 0) && (!hasControlLine))
{
qtss_sprintf(trackIndexBuffer, "a=control:trackID=%"_S32BITARG_"\r\n",trackIndex);
localSDPFormatter.Put(trackIndexBuffer, ::strlen(trackIndexBuffer));
}
*newSDPLen = (UInt32)localSDPFormatter.GetCurrentOffset();
StrPtrLen theSDPStr(localSDP, *newSDPLen);//localSDP is not 0 terminated so initialize theSDPStr with the len.
SDPContainer rawSDPContainer;
(void) rawSDPContainer.SetSDPBuffer( &theSDPStr );
SDPLineSorter sortedSDP(&rawSDPContainer);
return sortedSDP.GetSortedSDPCopy(); // return a new copy of the sorted SDP
}
void SDPSourceInfo::Parse(char* sdpData, UInt32 sdpLen)
{
//
// There are some situations in which Parse can be called twice.
// If that happens, just return and don't do anything the second time.
if (fSDPData.Ptr != NULL)
return;
Assert(fStreamArray == NULL);
char *sdpDataCopy = NEW char[sdpLen];
Assert(sdpDataCopy != NULL);
memcpy(sdpDataCopy,sdpData, sdpLen);
fSDPData.Set(sdpDataCopy, sdpLen);
// If there is no trackID information in this SDP, we make the track IDs start
// at 1 -> N
UInt32 currentTrack = 1;
Bool16 hasGlobalStreamInfo = false;
StreamInfo theGlobalStreamInfo; //needed if there is one c= header independent of
//individual streams
StrPtrLen sdpLine;
StringParser trackCounter(&fSDPData);
StringParser sdpParser(&fSDPData);
UInt32 theStreamIndex = 0;
//walk through the SDP, counting up the number of tracks
// Repeat until there's no more data in the SDP
while (trackCounter.GetDataRemaining() > 0)
{
//each 'm' line in the SDP file corresponds to another track.
trackCounter.GetThruEOL(&sdpLine);
if ((sdpLine.Len > 0) && (sdpLine.Ptr[0] == 'm'))
fNumStreams++;
}
//We should scale the # of StreamInfos to the # of trax, but we can't because
//of an annoying compiler bug...
fStreamArray = NEW StreamInfo[fNumStreams];
::memset(fStreamArray, 0, sizeof(StreamInfo) * fNumStreams);
// set the default destination as our default IP address and set the default ttl
theGlobalStreamInfo.fDestIPAddr = INADDR_ANY;
theGlobalStreamInfo.fTimeToLive = kDefaultTTL;
//Set bufferdelay to default of 3
theGlobalStreamInfo.fBufferDelay = (Float32) eDefaultBufferDelay;
//Now actually get all the data on all the streams
while (sdpParser.GetDataRemaining() > 0)
{
sdpParser.GetThruEOL(&sdpLine);
if (sdpLine.Len == 0)
continue;//skip over any blank lines
switch (*sdpLine.Ptr)
{
case 't':
{
StringParser mParser(&sdpLine);
mParser.ConsumeUntil(NULL, StringParser::sDigitMask);
UInt32 ntpStart = mParser.ConsumeInteger(NULL);
mParser.ConsumeUntil(NULL, StringParser::sDigitMask);
UInt32 ntpEnd = mParser.ConsumeInteger(NULL);
SetActiveNTPTimes(ntpStart,ntpEnd);
}
break;
case 'm':
{
if (hasGlobalStreamInfo)
{
fStreamArray[theStreamIndex].fDestIPAddr = theGlobalStreamInfo.fDestIPAddr;
fStreamArray[theStreamIndex].fTimeToLive = theGlobalStreamInfo.fTimeToLive;
}
fStreamArray[theStreamIndex].fTrackID = currentTrack;
currentTrack++;
StringParser mParser(&sdpLine);
//find out what type of track this is
mParser.ConsumeLength(NULL, 2);//go past 'm='
StrPtrLen theStreamType;
mParser.ConsumeWord(&theStreamType);
if (theStreamType.Equal(sVideoStr))
fStreamArray[theStreamIndex].fPayloadType = qtssVideoPayloadType;
else if (theStreamType.Equal(sAudioStr))
fStreamArray[theStreamIndex].fPayloadType = qtssAudioPayloadType;
//find the port for this stream
mParser.ConsumeUntil(NULL, StringParser::sDigitMask);
SInt32 tempPort = mParser.ConsumeInteger(NULL);
if ((tempPort > 0) && (tempPort < 65536))
fStreamArray[theStreamIndex].fPort = (UInt16) tempPort;
// find out whether this is TCP or UDP
mParser.ConsumeWhitespace();
StrPtrLen transportID;
mParser.ConsumeWord(&transportID);
static const StrPtrLen kTCPTransportStr("RTP/AVP/TCP");
if (transportID.Equal(kTCPTransportStr))
fStreamArray[theStreamIndex].fIsTCP = true;
theStreamIndex++;
}
break;
case 'a':
{
StringParser aParser(&sdpLine);
aParser.ConsumeLength(NULL, 2);//go past 'a='
StrPtrLen aLineType;
aParser.ConsumeWord(&aLineType);
if (aLineType.Equal(sBroadcastControlStr))
{ // found a control line for the broadcast (delete at time or delete at end of broadcast/server startup)
// qtss_printf("found =%s\n",sBroadcastControlStr);
aParser.ConsumeUntil(NULL,StringParser::sWordMask);
StrPtrLen sessionControlType;
aParser.ConsumeWord(&sessionControlType);
if (sessionControlType.Equal(sAutoDisconnect))
{
fSessionControlType = kRTSPSessionControl;
}
else if (sessionControlType.Equal(sAutoDisconnectTime))
{
fSessionControlType = kSDPTimeControl;
}
}
//if we haven't even hit an 'm' line yet, just ignore all 'a' lines
if (theStreamIndex == 0)
break;
if (aLineType.Equal(sRtpMapStr))
{
//mark the codec type if this line has a codec name on it. If we already
//have a codec type for this track, just ignore this line
if ((fStreamArray[theStreamIndex - 1].fPayloadName.Len == 0) &&
(aParser.GetThru(NULL, ' ')))
{
StrPtrLen payloadNameFromParser;
(void)aParser.GetThruEOL(&payloadNameFromParser);
char* temp = payloadNameFromParser.GetAsCString();
// qtss_printf("payloadNameFromParser (%x) = %s\n", temp, temp);
(fStreamArray[theStreamIndex - 1].fPayloadName).Set(temp, payloadNameFromParser.Len);
// qtss_printf("%s\n", fStreamArray[theStreamIndex - 1].fPayloadName.Ptr);
}
}
else if (aLineType.Equal(sControlStr))
{
//mark the trackID if that's what this line has
aParser.ConsumeUntil(NULL, '=');
aParser.ConsumeUntil(NULL, StringParser::sDigitMask);
fStreamArray[theStreamIndex - 1].fTrackID = aParser.ConsumeInteger(NULL);
}
else if (aLineType.Equal(sBufferDelayStr))
{ // if a BufferDelay is found then set all of the streams to the same buffer delay (it's global)
aParser.ConsumeUntil(NULL, StringParser::sDigitMask);
theGlobalStreamInfo.fBufferDelay = aParser.ConsumeFloat();
}
}
break;
case 'c':
{
//get the IP address off this header
StringParser cParser(&sdpLine);
cParser.ConsumeLength(NULL, 9);//strip off "c=in ip4 "
UInt32 tempIPAddr = SDPSourceInfo::GetIPAddr(&cParser, '/');
//grab the ttl
SInt32 tempTtl = kDefaultTTL;
if (cParser.GetThru(NULL, '/'))
{
tempTtl = cParser.ConsumeInteger(NULL);
Assert(tempTtl >= 0);
Assert(tempTtl < 65536);
}
if (theStreamIndex > 0)
{
//if this c= line is part of a stream, it overrides the
//global stream information
fStreamArray[theStreamIndex - 1].fDestIPAddr = tempIPAddr;
fStreamArray[theStreamIndex - 1].fTimeToLive = (UInt16) tempTtl;
} else {
theGlobalStreamInfo.fDestIPAddr = tempIPAddr;
theGlobalStreamInfo.fTimeToLive = (UInt16) tempTtl;
hasGlobalStreamInfo = true;
}
}
}
}
// Add the default buffer delay
Float32 bufferDelay = (Float32) eDefaultBufferDelay;
if (theGlobalStreamInfo.fBufferDelay != (Float32) eDefaultBufferDelay)
bufferDelay = theGlobalStreamInfo.fBufferDelay;
UInt32 count = 0;
while (count < fNumStreams)
{ fStreamArray[count].fBufferDelay = bufferDelay;
count ++;
}
}
UInt32 SDPSourceInfo::GetIPAddr(StringParser* inParser, char inStopChar)
{
StrPtrLen ipAddrStr;
// Get the IP addr str
inParser->ConsumeUntil(&ipAddrStr, inStopChar);
if (ipAddrStr.Len == 0)
return 0;
// NULL terminate it
char endChar = ipAddrStr.Ptr[ipAddrStr.Len];
ipAddrStr.Ptr[ipAddrStr.Len] = '\0';
//inet_addr returns numeric IP addr in network byte order, make
//sure to convert to host order.
UInt32 ipAddr = SocketUtils::ConvertStringToAddr(ipAddrStr.Ptr);
// Make sure to put the old char back!
ipAddrStr.Ptr[ipAddrStr.Len] = endChar;
return ipAddr;
}

View file

@ -0,0 +1,77 @@
/*
*
* @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: SDPSourceInfo.h
Contains: This object takes input SDP data, and uses it to support the SourceInfo
API.
Works only for QTSS
*/
#ifndef __SDP_SOURCE_INFO_H__
#define __SDP_SOURCE_INFO_H__
#include "StrPtrLen.h"
#include "SourceInfo.h"
#include "StringParser.h"
class SDPSourceInfo : public SourceInfo
{
public:
// Uses the SDP Data to build up the StreamInfo structures
SDPSourceInfo(char* sdpData, UInt32 sdpLen) { Parse(sdpData, sdpLen); }
SDPSourceInfo() {}
virtual ~SDPSourceInfo();
// Parses out the SDP file provided, sets up the StreamInfo structures
void Parse(char* sdpData, UInt32 sdpLen);
// This function uses the Parsed SDP file, and strips out all the network information,
// producing an SDP file that appears to be local.
virtual char* GetLocalSDP(UInt32* newSDPLen);
// Returns the SDP data
StrPtrLen* GetSDPData() { return &fSDPData; }
// Utility routines
// Assuming the parser is currently pointing at the beginning of an dotted-
// decimal IP address, this consumes it (stopping at inStopChar), and returns
// the IP address (host ordered) as a UInt32
static UInt32 GetIPAddr(StringParser* inParser, char inStopChar);
private:
enum
{
kDefaultTTL = 15 //UInt16
};
StrPtrLen fSDPData;
};
#endif // __SDP_SOURCE_INFO_H__

View file

@ -0,0 +1,329 @@
/*
*
* @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: SourceInfo.cpp
Contains: Implements object defined in .h file.
*/
#include "SourceInfo.h"
#include "SocketUtils.h"
#include "SDPSourceInfo.h"
#include "OSMemory.h"
#include "StringParser.h"
SourceInfo::SourceInfo(const SourceInfo& copy)
: fStreamArray(NULL), fNumStreams(copy.fNumStreams),
fOutputArray(NULL), fNumOutputs(copy.fNumOutputs),
fTimeSet(copy.fTimeSet),fStartTimeUnixSecs(copy.fStartTimeUnixSecs),
fEndTimeUnixSecs(copy.fEndTimeUnixSecs), fSessionControlType(copy.fSessionControlType),
fHasValidTime(false)
{
if(copy.fStreamArray != NULL && fNumStreams != 0)
{
fStreamArray = NEW StreamInfo[fNumStreams];
for (UInt32 index=0; index < fNumStreams; index++)
fStreamArray[index].Copy(copy.fStreamArray[index]);
}
if(copy.fOutputArray != NULL && fNumOutputs != 0)
{
fOutputArray = NEW OutputInfo[fNumOutputs];
for (UInt32 index2=0; index2 < fNumOutputs; index2++)
fOutputArray[index2].Copy(copy.fOutputArray[index2]);
}
}
SourceInfo::~SourceInfo()
{
if(fStreamArray != NULL)
delete [] fStreamArray;
if(fOutputArray != NULL)
delete [] fOutputArray;
}
Bool16 SourceInfo::IsReflectable()
{
if (fStreamArray == NULL)
return false;
if (fNumStreams == 0)
return false;
//each stream's info must meet certain criteria
for (UInt32 x = 0; x < fNumStreams; x++)
{
if (fStreamArray[x].fIsTCP)
continue;
if ((!this->IsReflectableIPAddr(fStreamArray[x].fDestIPAddr)) ||
(fStreamArray[x].fTimeToLive == 0))
return false;
}
return true;
}
Bool16 SourceInfo::IsReflectableIPAddr(UInt32 inIPAddr)
{
if (SocketUtils::IsMulticastIPAddr(inIPAddr) || SocketUtils::IsLocalIPAddr(inIPAddr))
return true;
return false;
}
Bool16 SourceInfo::HasTCPStreams()
{
//each stream's info must meet certain criteria
for (UInt32 x = 0; x < fNumStreams; x++)
{
if (fStreamArray[x].fIsTCP)
return true;
}
return false;
}
Bool16 SourceInfo::HasIncomingBroacast()
{
//each stream's info must meet certain criteria
for (UInt32 x = 0; x < fNumStreams; x++)
{
if (fStreamArray[x].fSetupToReceive)
return true;
}
return false;
}
SourceInfo::StreamInfo* SourceInfo::GetStreamInfo(UInt32 inIndex)
{
Assert(inIndex < fNumStreams);
if (fStreamArray == NULL)
return NULL;
if (inIndex < fNumStreams)
return &fStreamArray[inIndex];
else
return NULL;
}
SourceInfo::StreamInfo* SourceInfo::GetStreamInfoByTrackID(UInt32 inTrackID)
{
if (fStreamArray == NULL)
return NULL;
for (UInt32 x = 0; x < fNumStreams; x++)
{
if (fStreamArray[x].fTrackID == inTrackID)
return &fStreamArray[x];
}
return NULL;
}
SourceInfo::OutputInfo* SourceInfo::GetOutputInfo(UInt32 inIndex)
{
Assert(inIndex < fNumOutputs);
if (fOutputArray == NULL)
return NULL;
if (inIndex < fNumOutputs)
return &fOutputArray[inIndex];
else
return NULL;
}
UInt32 SourceInfo::GetNumNewOutputs()
{
UInt32 theNumNewOutputs = 0;
for (UInt32 x = 0; x < fNumOutputs; x++)
{
if (!fOutputArray[x].fAlreadySetup)
theNumNewOutputs++;
}
return theNumNewOutputs;
}
Bool16 SourceInfo::SetActiveNTPTimes(UInt32 startTimeNTP,UInt32 endTimeNTP)
{ // right now only handles earliest start and latest end time.
//qtss_printf("SourceInfo::SetActiveNTPTimes start=%"_U32BITARG_" end=%"_U32BITARG_"\n",startTimeNTP,endTimeNTP);
Bool16 accepted = false;
do
{
if ((startTimeNTP > 0) && (endTimeNTP > 0) && (endTimeNTP < startTimeNTP)) break; // not valid NTP time
UInt32 startTimeUnixSecs = 0;
UInt32 endTimeUnixSecs = 0;
if (startTimeNTP != 0 && IsValidNTPSecs(startTimeNTP)) // allow anything less than 1970
startTimeUnixSecs = NTPSecs_to_UnixSecs(startTimeNTP);// convert to 1970 time
if (endTimeNTP != 0 && !IsValidNTPSecs(endTimeNTP)) // don't allow anything less than 1970
break;
if (endTimeNTP != 0) // convert to 1970 time
endTimeUnixSecs = NTPSecs_to_UnixSecs(endTimeNTP);
fStartTimeUnixSecs = startTimeUnixSecs;
fEndTimeUnixSecs = endTimeUnixSecs;
accepted = true;
} while(0);
//char buffer[kTimeStrSize];
//qtss_printf("SourceInfo::SetActiveNTPTimes fStartTimeUnixSecs=%"_U32BITARG_" fEndTimeUnixSecs=%"_U32BITARG_"\n",fStartTimeUnixSecs,fEndTimeUnixSecs);
//qtss_printf("SourceInfo::SetActiveNTPTimes start time = %s",qtss_ctime(&fStartTimeUnixSecs, buffer, sizeof(buffer)) );
//qtss_printf("SourceInfo::SetActiveNTPTimes end time = %s",qtss_ctime(&fEndTimeUnixSecs, buffer, sizeof(buffer)) );
fHasValidTime = accepted;
return accepted;
}
Bool16 SourceInfo::IsActiveTime(time_t unixTimeSecs)
{
// order of tests are important here
// we do it this way because of the special case time value of 0 for end time
// start - 0 = unbounded
// 0 - 0 = permanent
if (false == fHasValidTime)
return false;
if (unixTimeSecs < 0) //check valid value
return false;
if (IsPermanentSource()) //check for 0 0
return true;
if (unixTimeSecs < fStartTimeUnixSecs)
return false; //too early
if (fEndTimeUnixSecs == 0)
return true;// accept any time after start
if (unixTimeSecs > fEndTimeUnixSecs)
return false; // too late
return true; // ok start <= time <= end
}
UInt32 SourceInfo::GetDurationSecs()
{
if (fEndTimeUnixSecs == 0) // unbounded time
return (UInt32) ~0; // max time
time_t timeNow = OS::UnixTime_Secs();
if (fEndTimeUnixSecs <= timeNow) // the active time has past or duration is 0 so return the minimum duration
return (UInt32) 0;
if (fStartTimeUnixSecs == 0) // relative duration = from "now" to end time
return fEndTimeUnixSecs - timeNow;
return fEndTimeUnixSecs - fStartTimeUnixSecs; // this must be a duration because of test for endtime above
}
Bool16 SourceInfo::Equal(SourceInfo* inInfo)
{
// Check to make sure the # of streams matches up
if (this->GetNumStreams() != inInfo->GetNumStreams())
return false;
// Check the src & dest addr, and port of each stream.
for (UInt32 x = 0; x < this->GetNumStreams(); x++)
{
if (GetStreamInfo(x)->fDestIPAddr != inInfo->GetStreamInfo(x)->fDestIPAddr)
return false;
if (GetStreamInfo(x)->fSrcIPAddr != inInfo->GetStreamInfo(x)->fSrcIPAddr)
return false;
// If either one of the comparators is 0 (the "wildcard" port), then we know at this point
// they are equivalent
if ((GetStreamInfo(x)->fPort == 0) || (inInfo->GetStreamInfo(x)->fPort == 0))
return true;
// Neither one is the wildcard port, so they must be the same
if (GetStreamInfo(x)->fPort != inInfo->GetStreamInfo(x)->fPort)
return false;
}
return true;
}
void SourceInfo::StreamInfo::Copy(const StreamInfo& copy)
{
fSrcIPAddr = copy.fSrcIPAddr;
fDestIPAddr = copy.fDestIPAddr;
fPort = copy.fPort;
fTimeToLive = copy.fTimeToLive;
fPayloadType = copy.fPayloadType;
if ((copy.fPayloadName).Ptr != NULL)
fPayloadName.Set((copy.fPayloadName).GetAsCString(), (copy.fPayloadName).Len);
fTrackID = copy.fTrackID;
fBufferDelay = copy.fBufferDelay;
fIsTCP = copy.fIsTCP;
fSetupToReceive = copy.fSetupToReceive;
fTimeScale = copy.fTimeScale;
}
SourceInfo::StreamInfo::~StreamInfo()
{
if (fPayloadName.Ptr != NULL)
delete fPayloadName.Ptr;
fPayloadName.Len = 0;
}
void SourceInfo::OutputInfo::Copy(const OutputInfo& copy)
{
fDestAddr = copy.fDestAddr;
fLocalAddr = copy.fLocalAddr;
fTimeToLive = copy.fTimeToLive;
fNumPorts = copy.fNumPorts;
if(fNumPorts != 0)
{
fPortArray = NEW UInt16[fNumPorts];
::memcpy(fPortArray, copy.fPortArray, fNumPorts * sizeof(UInt16));
}
fBasePort = copy.fBasePort;
fAlreadySetup = copy.fAlreadySetup;
}
SourceInfo::OutputInfo::~OutputInfo()
{
if (fPortArray != NULL)
delete [] fPortArray;
}
Bool16 SourceInfo::OutputInfo::Equal(const OutputInfo& info)
{
if ((fDestAddr == info.fDestAddr) && (fLocalAddr == info.fLocalAddr) && (fTimeToLive == info.fTimeToLive))
{
if ((fBasePort != 0) && (fBasePort == info.fBasePort))
return true;
else if ((fNumPorts == 0) || ((fNumPorts == info.fNumPorts) && (fPortArray[0] == info.fPortArray[0])))
return true;
}
return false;
}

174
APICommonCode/SourceInfo.h Normal file
View file

@ -0,0 +1,174 @@
/*
*
* @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: SourceInfo.h
Contains: This object contains an interface for getting at any bit
of "interesting" information regarding a content source in a
format - independent manner.
For instance, the derived object SDPSourceInfo parses an
SDP file and retrieves all the SourceInfo information from that file.
*/
#ifndef __SOURCE_INFO_H__
#define __SOURCE_INFO_H__
#include "QTSS.h"
#include "StrPtrLen.h"
#include "OSQueue.h"
#include "OS.h"
class SourceInfo
{
public:
SourceInfo() : fStreamArray(NULL), fNumStreams(0),
fOutputArray(NULL), fNumOutputs(0),
fTimeSet(false),fStartTimeUnixSecs(0),fEndTimeUnixSecs(0),
fSessionControlType(kRTSPSessionControl) {}
SourceInfo(const SourceInfo& copy);// Does copy dynamically allocated data
virtual ~SourceInfo(); // Deletes the dynamically allocated data
enum
{
eDefaultBufferDelay = 3
};
// Returns whether this source is reflectable.
Bool16 IsReflectable();
// Each source is comprised of a set of streams. Those streams have
// the following metadata.
struct StreamInfo
{
StreamInfo() : fSrcIPAddr(0), fDestIPAddr(0), fPort(0), fTimeToLive(0), fPayloadType(0), fPayloadName(NULL), fTrackID(0), fBufferDelay((Float32) eDefaultBufferDelay), fIsTCP(false),fSetupToReceive(false), fTimeScale(0){}
~StreamInfo(); // Deletes the memory allocated for the fPayloadName string
void Copy(const StreamInfo& copy);// Does copy dynamically allocated data
UInt32 fSrcIPAddr; // Src IP address of content (this may be 0 if not known for sure)
UInt32 fDestIPAddr; // Dest IP address of content (destination IP addr for source broadcast!)
UInt16 fPort; // Dest (RTP) port of source content
UInt16 fTimeToLive; // Ttl for this stream
QTSS_RTPPayloadType fPayloadType; // Payload type of this stream
StrPtrLen fPayloadName; // Payload name of this stream
UInt32 fTrackID; // ID of this stream
Float32 fBufferDelay; // buffer delay (default is 3 seconds)
Bool16 fIsTCP; // Is this a TCP broadcast? If this is the case, the port and ttl are not valid
Bool16 fSetupToReceive; // If true then a push to the server is setup on this stream.
UInt32 fTimeScale;
};
// Returns the number of StreamInfo objects (number of Streams in this source)
UInt32 GetNumStreams() { return fNumStreams; }
StreamInfo* GetStreamInfo(UInt32 inStreamIndex);
StreamInfo* GetStreamInfoByTrackID(UInt32 inTrackID);
// If this source is to be Relayed, it may have "Output" information. This
// tells the reader where to forward the incoming streams onto. There may be
// 0 -> N OutputInfo objects in this SourceInfo. Each OutputInfo refers to a
// single, complete copy of ALL the input streams. The fPortArray field
// contains one RTP port for each incoming stream.
struct OutputInfo
{
OutputInfo() : fDestAddr(0), fLocalAddr(0), fTimeToLive(0), fPortArray(NULL), fNumPorts(0), fBasePort(0), fAlreadySetup(false) {}
~OutputInfo(); // Deletes the memory allocated for fPortArray
// Returns true if the two are equal
Bool16 Equal(const OutputInfo& info);
void Copy(const OutputInfo& copy);// Does copy dynamically allocated data
UInt32 fDestAddr; // Destination address to forward the input onto
UInt32 fLocalAddr; // Address of local interface to send out on (may be 0)
UInt16 fTimeToLive; // Time to live for resulting output (if multicast)
UInt16* fPortArray; // 1 destination RTP port for each Stream.
UInt32 fNumPorts; // Size of the fPortArray (usually equal to fNumStreams)
UInt16 fBasePort; // The base destination RTP port - for i=1 to fNumStreams fPortArray[i] = fPortArray[i-1] + 2
Bool16 fAlreadySetup; // A flag used in QTSSReflectorModule.cpp
};
// Returns the number of OutputInfo objects.
UInt32 GetNumOutputs() { return fNumOutputs; }
UInt32 GetNumNewOutputs(); // Returns # of outputs not already setup
OutputInfo* GetOutputInfo(UInt32 inOutputIndex);
// GetLocalSDP. This may or may not be supported by sources. Typically, if
// the source is reflectable, this must be supported. It returns a newly
// allocated buffer (that the caller is responsible for) containing an SDP
// description of the source, stripped of all network info.
virtual char* GetLocalSDP(UInt32* /*newSDPLen*/) { return NULL; }
// This is only supported by the RTSPSourceInfo sub class
virtual Bool16 IsRTSPSourceInfo() { return false; }
// This is only supported by the RCFSourceInfo sub class and its derived classes
virtual char* Name() { return NULL; }
virtual Bool16 Equal(SourceInfo* inInfo);
// SDP scheduled times supports earliest start and latest end -- doesn't handle repeat times or multiple active times.
#define kNTP_Offset_From_1970 2208988800LU
time_t NTPSecs_to_UnixSecs(time_t time) {return (time_t) (time - (UInt32)kNTP_Offset_From_1970);}
UInt32 UnixSecs_to_NTPSecs(time_t time) {return (UInt32) (time + (UInt32)kNTP_Offset_From_1970);}
Bool16 SetActiveNTPTimes(UInt32 startNTPTime,UInt32 endNTPTime);
Bool16 IsValidNTPSecs(UInt32 time) {return time >= (UInt32) kNTP_Offset_From_1970 ? true : false;}
Bool16 IsPermanentSource() { return ((fStartTimeUnixSecs == 0) && (fEndTimeUnixSecs == 0)) ? true : false; }
Bool16 IsActiveTime(time_t unixTimeSecs);
Bool16 IsActiveNow() { return IsActiveTime(OS::UnixTime_Secs()); }
Bool16 IsRTSPControlled() {return (fSessionControlType == kRTSPSessionControl) ? true : false; }
Bool16 HasTCPStreams();
Bool16 HasIncomingBroacast();
time_t GetStartTimeUnixSecs() {return fStartTimeUnixSecs; }
time_t GetEndTimeUnixSecs() {return fEndTimeUnixSecs; }
UInt32 GetDurationSecs();
enum {kSDPTimeControl, kRTSPSessionControl};
protected:
//utility function used by IsReflectable
Bool16 IsReflectableIPAddr(UInt32 inIPAddr);
StreamInfo* fStreamArray;
UInt32 fNumStreams;
OutputInfo* fOutputArray;
UInt32 fNumOutputs;
Bool16 fTimeSet;
time_t fStartTimeUnixSecs;
time_t fEndTimeUnixSecs;
UInt32 fSessionControlType;
Bool16 fHasValidTime;
};
#endif //__SOURCE_INFO_H__

503
CMakeLists.txt Normal file
View file

@ -0,0 +1,503 @@
cmake_minimum_required(VERSION 3.6)
project(DarwinStreamingServer C CXX)
include_directories(APICommonCode
APIModules/QTSSAccessLogModule
APIModules/QTSSAccessModule
APIModules/QTSSAdminModule
APIModules/QTSSDemoAuthorizationModule.bproj
APIModules/QTSSDemoRedirectModule.bproj
APIModules/QTSSDemoSMILModule.bproj
APIModules/QTSSDSAuthModule
APIModules/QTSSDSAuthModule/DSWrappers
APIModules/QTSSFileModule
APIModules/QTSSFilePrivsModule.bproj
APIModules/QTSSFlowControlModule
APIModules/QTSSHomeDirectoryModule
APIModules/QTSSHttpFileModule
APIModules/QTSSMP3StreamingModule
APIModules/QTSSPOSIXFileSysModule
APIModules/QTSSProxyModule
APIModules/QTSSRawFileModule.bproj
APIModules/QTSSReflectorModule
APIModules/QTSSRefMovieModule
APIModules/QTSSRTPFileModule
APIModules/QTSSSpamDefenseModule.bproj
APIModules/QTSSWebDebugModule
APIModules/QTSSWebStatsModule
APIStubLib
AtomicLib
broadcasterctl
CommonUtilitiesLib
HTTPUtilitiesLib
MP3Broadcaster
PlaylistBroadcaster.tproj
PrefsSourceLib
QTFileLib
QTFileTools/RTPFileGen.tproj
RTCPUtilitiesLib
RTPMetaInfoLib
RTSPClientLib
Server.tproj
StreamingProxy.tproj)
add_definitions(-D_REENTRANT -D__USE_POSIX -D__linux__ -D__PTHREADS_MUTEXES__ -D__PTHREADS__)
#target_link_libraries(DarwinStreamingServer -lpthread -ldl -lstdc++ -lm -lcrypt)
set(DSS_SOURCE_FILES
APICommonCode/QTAccessFile.cpp
APICommonCode/QTAccessFile.h
APICommonCode/QTSS3GPPModuleUtils.cpp
APICommonCode/QTSS3GPPModuleUtils.h
APICommonCode/QTSSMemoryDeleter.h
APICommonCode/QTSSModuleUtils.cpp
APICommonCode/QTSSModuleUtils.h
APICommonCode/QTSSRollingLog.cpp
APICommonCode/QTSSRollingLog.h
APICommonCode/SDPSourceInfo.cpp
APICommonCode/SDPSourceInfo.h
APICommonCode/SourceInfo.cpp
APICommonCode/SourceInfo.h
APIModules/OSMemory_Modules/OSMemory_Modules.cpp
APIModules/QTSSAccessLogModule/QTSSAccessLogModule.cpp
APIModules/QTSSAccessLogModule/QTSSAccessLogModule.h
APIModules/QTSSAccessModule/AccessChecker.cpp
APIModules/QTSSAccessModule/AccessChecker.h
APIModules/QTSSAccessModule/QTSSAccessModule.cpp
APIModules/QTSSAccessModule/QTSSAccessModule.h
APIModules/QTSSAdminModule/AdminElementNode.cpp
APIModules/QTSSAdminModule/AdminElementNode.h
APIModules/QTSSAdminModule/AdminQuery.cpp
APIModules/QTSSAdminModule/AdminQuery.h
APIModules/QTSSAdminModule/QTSSAdminModule.cpp
APIModules/QTSSAdminModule/QTSSAdminModule.h
APIModules/QTSSDemoAuthorizationModule.bproj/QTSSDemoAuthorizationModule.cpp
APIModules/QTSSDemoAuthorizationModule.bproj/QTSSDemoAuthorizationModule.h
APIModules/QTSSDemoRedirectModule.bproj/QTSSDemoRedirectModule.cpp
APIModules/QTSSDemoRedirectModule.bproj/QTSSDemoRedirectModule.h
APIModules/QTSSDemoSMILModule.bproj/QTSSDemoSMILModule.cpp
APIModules/QTSSDemoSMILModule.bproj/QTSSDemoSMILModule.h
# APIModules/QTSSDSAuthModule/DSWrappers/CDirService.cpp
# APIModules/QTSSDSAuthModule/DSWrappers/CDirService.h
# APIModules/QTSSDSAuthModule/DSWrappers/DSBuffer.cpp
# APIModules/QTSSDSAuthModule/DSWrappers/DSBuffer.h
# APIModules/QTSSDSAuthModule/DSWrappers/DSDataList.h
# APIModules/QTSSDSAuthModule/DSWrappers/DSDataNode.h
# APIModules/QTSSDSAuthModule/DSAccessChecker.cpp
# APIModules/QTSSDSAuthModule/DSAccessChecker.h
# APIModules/QTSSDSAuthModule/QTSSDSAuthModule.cpp
# APIModules/QTSSDSAuthModule/QTSSDSAuthModule.h
APIModules/QTSSFileModule/QTSSFileModule.cpp
APIModules/QTSSFileModule/QTSSFileModule.h
APIModules/QTSSFilePrivsModule.bproj/QTSSFilePrivsModule.cpp
APIModules/QTSSFilePrivsModule.bproj/QTSSFilePrivsModule.h
APIModules/QTSSFlowControlModule/QTSSFlowControlModule.cpp
APIModules/QTSSFlowControlModule/QTSSFlowControlModule.h
APIModules/QTSSHomeDirectoryModule/DirectoryInfo.cpp
APIModules/QTSSHomeDirectoryModule/DirectoryInfo.h
APIModules/QTSSHomeDirectoryModule/QTSSHomeDirectoryModule.cpp
APIModules/QTSSHomeDirectoryModule/QTSSHomeDirectoryModule.h
APIModules/QTSSHttpFileModule/QTSSHttpFileModule.cpp
APIModules/QTSSHttpFileModule/QTSSHttpFileModule.h
APIModules/QTSSMP3StreamingModule/QTSSMP3StreamingModule.cpp
APIModules/QTSSMP3StreamingModule/QTSSMP3StreamingModule.h
APIModules/QTSSPOSIXFileSysModule/QTSSPosixFileSysModule.cpp
APIModules/QTSSPOSIXFileSysModule/QTSSPosixFileSysModule.h
APIModules/QTSSProxyModule/QTSSProxyModule.cpp
APIModules/QTSSProxyModule/QTSSProxyModule.h
APIModules/QTSSRawFileModule.bproj/QTSSRawFileModule.cpp
APIModules/QTSSRawFileModule.bproj/QTSSRawFileModule.h
APIModules/QTSSReflectorModule/QTSSReflectorModule.cpp
APIModules/QTSSReflectorModule/QTSSReflectorModule.h
APIModules/QTSSReflectorModule/QTSSRelayModule.cpp
APIModules/QTSSReflectorModule/QTSSRelayModule.h
# APIModules/QTSSReflectorModule/QTSSSplitterModule.cpp
# APIModules/QTSSReflectorModule/QTSSSplitterModule.h
APIModules/QTSSReflectorModule/RCFSourceInfo.cpp
APIModules/QTSSReflectorModule/RCFSourceInfo.h
APIModules/QTSSReflectorModule/ReflectorOutput.h
APIModules/QTSSReflectorModule/ReflectorSession.cpp
APIModules/QTSSReflectorModule/ReflectorSession.h
APIModules/QTSSReflectorModule/ReflectorStream.cpp
APIModules/QTSSReflectorModule/ReflectorStream.h
APIModules/QTSSReflectorModule/RelayOutput.cpp
APIModules/QTSSReflectorModule/RelayOutput.h
APIModules/QTSSReflectorModule/RelaySDPSourceInfo.cpp
APIModules/QTSSReflectorModule/RelaySDPSourceInfo.h
APIModules/QTSSReflectorModule/RelaySession.cpp
APIModules/QTSSReflectorModule/RelaySession.h
APIModules/QTSSReflectorModule/RTPSessionOutput.cpp
APIModules/QTSSReflectorModule/RTPSessionOutput.h
APIModules/QTSSReflectorModule/RTSPSourceInfo.cpp
APIModules/QTSSReflectorModule/RTSPSourceInfo.h
APIModules/QTSSReflectorModule/SequenceNumberMap.cpp
APIModules/QTSSReflectorModule/SequenceNumberMap.h
APIModules/QTSSRefMovieModule/QTSSRefMovieModule.cpp
APIModules/QTSSRefMovieModule/QTSSRefMovieModule.h
APIModules/QTSSRTPFileModule/QTSSRTPFileModule.cpp
APIModules/QTSSRTPFileModule/QTSSRTPFileModule.h
APIModules/QTSSRTPFileModule/RTPFileSession.cpp
APIModules/QTSSRTPFileModule/RTPFileSession.h
APIModules/QTSSSpamDefenseModule.bproj/QTSSSpamDefenseModule.cpp
APIModules/QTSSSpamDefenseModule.bproj/QTSSSpamDefenseModule.h
APIModules/QTSSWebDebugModule/QTSSWebDebugModule.cpp
APIModules/QTSSWebDebugModule/QTSSWebDebugModule.h
APIModules/QTSSWebStatsModule/QTSSWebStatsModule.cpp
APIModules/QTSSWebStatsModule/QTSSWebStatsModule.h
APIStubLib/QTSS.h
APIStubLib/QTSS_Private.cpp
APIStubLib/QTSS_Private.h
APIStubLib/QTSSRTSPProtocol.h
AtomicLib/atomic.h
AtomicLib/hmi.c
AtomicLib/timescale.c
AtomicLib/timestamp.h
broadcasterctl/BroadcasterAdminController.h
broadcasterctl/BroadcasterRemoteAdmin.h
CommonUtilitiesLib/atomic.cpp
CommonUtilitiesLib/atomic.h
CommonUtilitiesLib/base64.c
CommonUtilitiesLib/base64.h
CommonUtilitiesLib/ConfParser.cpp
CommonUtilitiesLib/ConfParser.h
CommonUtilitiesLib/daemon.c
CommonUtilitiesLib/daemon.h
CommonUtilitiesLib/DateTranslator.cpp
CommonUtilitiesLib/DateTranslator.h
CommonUtilitiesLib/DssStopwatch.h
CommonUtilitiesLib/ev.cpp
CommonUtilitiesLib/ev.h
CommonUtilitiesLib/EventContext.cpp
CommonUtilitiesLib/EventContext.h
CommonUtilitiesLib/FastCopyMacros.h
CommonUtilitiesLib/getopt.c
CommonUtilitiesLib/getopt.h
CommonUtilitiesLib/GetWord.c
CommonUtilitiesLib/GetWord.h
CommonUtilitiesLib/IdleTask.cpp
CommonUtilitiesLib/IdleTask.h
CommonUtilitiesLib/MakeDir.c
CommonUtilitiesLib/MakeDir.h
CommonUtilitiesLib/md5.c
CommonUtilitiesLib/md5.h
CommonUtilitiesLib/md5digest.cpp
CommonUtilitiesLib/md5digest.h
CommonUtilitiesLib/MyAssert.cpp
CommonUtilitiesLib/MyAssert.h
# CommonUtilitiesLib/mycondition.cpp
# CommonUtilitiesLib/mycondition.h
# CommonUtilitiesLib/mymutex.cpp
# CommonUtilitiesLib/mymutex.h
CommonUtilitiesLib/OS.cpp
CommonUtilitiesLib/OS.h
CommonUtilitiesLib/OSArrayObjectDeleter.h
CommonUtilitiesLib/OSBufferPool.cpp
CommonUtilitiesLib/OSBufferPool.h
CommonUtilitiesLib/OSCodeFragment.cpp
CommonUtilitiesLib/OSCodeFragment.h
CommonUtilitiesLib/OSCond.cpp
CommonUtilitiesLib/OSCond.h
CommonUtilitiesLib/OSFileSource.cpp
CommonUtilitiesLib/OSFileSource.h
CommonUtilitiesLib/OSHashTable.h
CommonUtilitiesLib/OSHeaders.c
CommonUtilitiesLib/OSHeaders.h
CommonUtilitiesLib/OSHeap.cpp
CommonUtilitiesLib/OSHeap.h
CommonUtilitiesLib/OSMemory.h
CommonUtilitiesLib/OSMutex.cpp
CommonUtilitiesLib/OSMutex.h
CommonUtilitiesLib/OSMutexRW.cpp
CommonUtilitiesLib/OSMutexRW.h
CommonUtilitiesLib/OSQueue.cpp
CommonUtilitiesLib/OSQueue.h
CommonUtilitiesLib/OSRef.cpp
CommonUtilitiesLib/OSRef.h
CommonUtilitiesLib/OSThread.cpp
CommonUtilitiesLib/OSThread.h
CommonUtilitiesLib/PathDelimiter.h
CommonUtilitiesLib/PLDoubleLinkedList.h
CommonUtilitiesLib/QueryParamList.cpp
CommonUtilitiesLib/QueryParamList.h
CommonUtilitiesLib/ResizeableStringFormatter.cpp
CommonUtilitiesLib/ResizeableStringFormatter.h
CommonUtilitiesLib/SafeStdLib.h
CommonUtilitiesLib/SDPUtils.cpp
CommonUtilitiesLib/SDPUtils.h
CommonUtilitiesLib/Socket.cpp
CommonUtilitiesLib/Socket.h
CommonUtilitiesLib/SocketUtils.cpp
CommonUtilitiesLib/SocketUtils.h
CommonUtilitiesLib/StopWatch.h
CommonUtilitiesLib/StringFormatter.cpp
CommonUtilitiesLib/StringFormatter.h
CommonUtilitiesLib/StringParser.cpp
CommonUtilitiesLib/StringParser.h
CommonUtilitiesLib/StringTranslator.cpp
CommonUtilitiesLib/StringTranslator.h
CommonUtilitiesLib/StrPtrLen.cpp
CommonUtilitiesLib/StrPtrLen.h
CommonUtilitiesLib/SVector.h
CommonUtilitiesLib/Task.cpp
CommonUtilitiesLib/Task.h
CommonUtilitiesLib/TCPListenerSocket.cpp
CommonUtilitiesLib/TCPListenerSocket.h
CommonUtilitiesLib/TCPSocket.cpp
CommonUtilitiesLib/TCPSocket.h
CommonUtilitiesLib/tempcalls.h
CommonUtilitiesLib/TimeoutTask.cpp
CommonUtilitiesLib/TimeoutTask.h
CommonUtilitiesLib/Trim.c
CommonUtilitiesLib/Trim.h
CommonUtilitiesLib/UDPDemuxer.cpp
CommonUtilitiesLib/UDPDemuxer.h
CommonUtilitiesLib/UDPSocket.cpp
CommonUtilitiesLib/UDPSocket.h
CommonUtilitiesLib/UDPSocketPool.cpp
CommonUtilitiesLib/UDPSocketPool.h
CommonUtilitiesLib/UserAgentParser.cpp
CommonUtilitiesLib/UserAgentParser.h
# CommonUtilitiesLib/win32ev.cpp
HTTPUtilitiesLib/HTTPProtocol.cpp
HTTPUtilitiesLib/HTTPProtocol.h
HTTPUtilitiesLib/HTTPRequest.cpp
HTTPUtilitiesLib/HTTPRequest.h
OSMemoryLib/OSMemory.cpp
PrefsSourceLib/FilePrefsSource.cpp
PrefsSourceLib/FilePrefsSource.h
# PrefsSourceLib/NetInfoPrefsSource.cpp
# PrefsSourceLib/NetInfoPrefsSource.h
# PrefsSourceLib/nilib2.c
# PrefsSourceLib/nilib2.h
PrefsSourceLib/PrefsSource.h
PrefsSourceLib/XMLParser.cpp
PrefsSourceLib/XMLParser.h
PrefsSourceLib/XMLPrefsParser.cpp
PrefsSourceLib/XMLPrefsParser.h
QTFileLib/QTAtom.cpp
QTFileLib/QTAtom.h
QTFileLib/QTAtom_dref.cpp
QTFileLib/QTAtom_dref.h
QTFileLib/QTAtom_elst.cpp
QTFileLib/QTAtom_elst.h
QTFileLib/QTAtom_hinf.cpp
QTFileLib/QTAtom_hinf.h
QTFileLib/QTAtom_mdhd.cpp
QTFileLib/QTAtom_mdhd.h
QTFileLib/QTAtom_mvhd.cpp
QTFileLib/QTAtom_mvhd.h
QTFileLib/QTAtom_stco.cpp
QTFileLib/QTAtom_stco.h
QTFileLib/QTAtom_stsc.cpp
QTFileLib/QTAtom_stsc.h
QTFileLib/QTAtom_stsd.cpp
QTFileLib/QTAtom_stsd.h
QTFileLib/QTAtom_stss.cpp
QTFileLib/QTAtom_stss.h
QTFileLib/QTAtom_stsz.cpp
QTFileLib/QTAtom_stsz.h
QTFileLib/QTAtom_stts.cpp
QTFileLib/QTAtom_stts.h
QTFileLib/QTAtom_tkhd.cpp
QTFileLib/QTAtom_tkhd.h
QTFileLib/QTAtom_tref.cpp
QTFileLib/QTAtom_tref.h
QTFileLib/QTFile.cpp
QTFileLib/QTFile.h
QTFileLib/QTFile_FileControlBlock.cpp
QTFileLib/QTFile_FileControlBlock.h
QTFileLib/QTHintTrack.cpp
QTFileLib/QTHintTrack.h
QTFileLib/QTRTPFile.cpp
QTFileLib/QTRTPFile.h
QTFileLib/QTTrack.cpp
QTFileLib/QTTrack.h
QTFileTools/QTFileTest.tproj/QTFileTest.cpp
QTFileTools/QTRTPFileTest.tproj/QTRTPFileTest.cpp
QTFileTools/QTRTPGen.tproj/QTRTPGen.cpp
QTFileTools/QTSampleLister.tproj/QTSampleLister.cpp
QTFileTools/QTSDPGen.tproj/QTSDPGen.cpp
QTFileTools/QTTrackInfo.tproj/QTTrackInfo.cpp
QTFileTools/RTPFileGen.tproj/RTPFileDefs.h
QTFileTools/RTPFileGen.tproj/RTPFileGen.cpp
qtpasswd.tproj/QTSSPasswd.cpp
RTCPUtilitiesLib/RTCPAckPacket.cpp
RTCPUtilitiesLib/RTCPAckPacket.h
RTCPUtilitiesLib/RTCPAckPacketFmt.h
RTCPUtilitiesLib/RTCPAPPNADUPacket.cpp
RTCPUtilitiesLib/RTCPAPPNADUPacket.h
RTCPUtilitiesLib/RTCPAPPPacket.cpp
RTCPUtilitiesLib/RTCPAPPPacket.h
RTCPUtilitiesLib/RTCPAPPQTSSPacket.cpp
RTCPUtilitiesLib/RTCPAPPQTSSPacket.h
RTCPUtilitiesLib/RTCPNADUPacketFmt.h
RTCPUtilitiesLib/RTCPPacket.cpp
RTCPUtilitiesLib/RTCPPacket.h
RTCPUtilitiesLib/RTCPRRPacket.h
RTCPUtilitiesLib/RTCPSRPacket.cpp
RTCPUtilitiesLib/RTCPSRPacket.h
RTPMetaInfoLib/RTPMetaInfoPacket.cpp
RTPMetaInfoLib/RTPMetaInfoPacket.h
RTSPClientLib/ClientSession.cpp
RTSPClientLib/ClientSession.h
RTSPClientLib/ClientSocket.cpp
RTSPClientLib/ClientSocket.h
RTSPClientLib/PlayerSimulator.h
RTSPClientLib/RTPPacket.h
RTSPClientLib/RTSPClient.cpp
RTSPClientLib/RTSPClient.h
SafeStdLib/DynamicModuleStdLib.cpp
SafeStdLib/InternalStdLib.cpp
Server.tproj/GenerateXMLPrefs.cpp
Server.tproj/GenerateXMLPrefs.h
Server.tproj/main.cpp
Server.tproj/QTSSCallbacks.cpp
Server.tproj/QTSSCallbacks.h
Server.tproj/QTSSDataConverter.cpp
Server.tproj/QTSSDataConverter.h
Server.tproj/QTSSDictionary.cpp
Server.tproj/QTSSDictionary.h
Server.tproj/QTSSErrorLogModule.cpp
Server.tproj/QTSSErrorLogModule.h
Server.tproj/QTSServer.cpp
Server.tproj/QTSServer.h
Server.tproj/QTSServerInterface.cpp
Server.tproj/QTSServerInterface.h
Server.tproj/QTSServerPrefs.cpp
Server.tproj/QTSServerPrefs.h
Server.tproj/QTSSExpirationDate.cpp
Server.tproj/QTSSExpirationDate.h
Server.tproj/QTSSFile.cpp
Server.tproj/QTSSFile.h
Server.tproj/QTSSMessages.cpp
Server.tproj/QTSSMessages.h
Server.tproj/QTSSModule.cpp
Server.tproj/QTSSModule.h
Server.tproj/QTSSPrefs.cpp
Server.tproj/QTSSPrefs.h
Server.tproj/QTSSSocket.cpp
Server.tproj/QTSSSocket.h
Server.tproj/QTSSStream.h
Server.tproj/QTSSUserProfile.cpp
Server.tproj/QTSSUserProfile.h
Server.tproj/RTCPTask.cpp
Server.tproj/RTCPTask.h
Server.tproj/RTPBandwidthTracker.cpp
Server.tproj/RTPBandwidthTracker.h
Server.tproj/RTPOverbufferWindow.cpp
Server.tproj/RTPOverbufferWindow.h
Server.tproj/RTPPacketResender.cpp
Server.tproj/RTPPacketResender.h
Server.tproj/RTPSession.cpp
Server.tproj/RTPSession.h
Server.tproj/RTPSession3GPP.cpp
Server.tproj/RTPSession3GPP.h
Server.tproj/RTPSessionInterface.cpp
Server.tproj/RTPSessionInterface.h
Server.tproj/RTPStream.cpp
Server.tproj/RTPStream.h
Server.tproj/RTPStream3GPP.cpp
Server.tproj/RTPStream3GPP.h
Server.tproj/RTSPProtocol.cpp
Server.tproj/RTSPProtocol.h
Server.tproj/RTSPRequest.cpp
Server.tproj/RTSPRequest.h
Server.tproj/RTSPRequest3GPP.cpp
Server.tproj/RTSPRequest3GPP.h
Server.tproj/RTSPRequestInterface.cpp
Server.tproj/RTSPRequestInterface.h
Server.tproj/RTSPRequestStream.cpp
Server.tproj/RTSPRequestStream.h
Server.tproj/RTSPResponseStream.cpp
Server.tproj/RTSPResponseStream.h
Server.tproj/RTSPSession.cpp
Server.tproj/RTSPSession.h
Server.tproj/RTSPSession3GPP.cpp
Server.tproj/RTSPSession3GPP.h
Server.tproj/RTSPSessionInterface.cpp
Server.tproj/RTSPSessionInterface.h
Server.tproj/RunServer.cpp
Server.tproj/RunServer.h
StreamingProxy.tproj/get_opt.c
StreamingProxy.tproj/get_opt.h
StreamingProxy.tproj/proxy.c
StreamingProxy.tproj/proxy.h
StreamingProxy.tproj/proxy_plat.h
StreamingProxy.tproj/proxy_unix.c
StreamingProxy.tproj/shared_udp.c
StreamingProxy.tproj/shared_udp.h
StreamingProxy.tproj/util.c
StreamingProxy.tproj/util.h
defaultPaths.h
PlatformHeader.h
revision.h)
add_executable(DarwinStreamingServer ${DSS_SOURCE_FILES})
add_executable(StreamingLoadTool StreamingLoadTool/StreamingLoadTool.cpp)
set(PLAYLIST_BROADCASTER_SOURCE_FILES
PlaylistBroadcaster.tproj/BCasterTracker.cpp
PlaylistBroadcaster.tproj/BCasterTracker.h
PlaylistBroadcaster.tproj/BroadcasterSession.cpp
PlaylistBroadcaster.tproj/BroadcasterSession.h
PlaylistBroadcaster.tproj/BroadcastLog.cpp
PlaylistBroadcaster.tproj/BroadcastLog.h
PlaylistBroadcaster.tproj/GetLocalIPAddressString.c
PlaylistBroadcaster.tproj/GetLocalIPAddressString.h
PlaylistBroadcaster.tproj/NoRepeat.cpp
PlaylistBroadcaster.tproj/NoRepeat.h
PlaylistBroadcaster.tproj/notes.c
PlaylistBroadcaster.tproj/PickerFromFile.cpp
PlaylistBroadcaster.tproj/PickerFromFile.h
PlaylistBroadcaster.tproj/playlist_array.h
PlaylistBroadcaster.tproj/playlist_broadcaster.cpp
PlaylistBroadcaster.tproj/playlist_broadcaster.h
PlaylistBroadcaster.tproj/playlist_elements.cpp
PlaylistBroadcaster.tproj/playlist_elements.h
PlaylistBroadcaster.tproj/playlist_lists.cpp
PlaylistBroadcaster.tproj/playlist_lists.h
PlaylistBroadcaster.tproj/playlist_parsers.cpp
PlaylistBroadcaster.tproj/playlist_parsers.h
PlaylistBroadcaster.tproj/playlist_QTRTPBroadcastFile.cpp
PlaylistBroadcaster.tproj/playlist_QTRTPBroadcastFile.h
PlaylistBroadcaster.tproj/playlist_SDPGen.cpp
PlaylistBroadcaster.tproj/playlist_SDPGen.h
PlaylistBroadcaster.tproj/playlist_SimpleParse.cpp
PlaylistBroadcaster.tproj/playlist_SimpleParse.h
PlaylistBroadcaster.tproj/playlist_timestamp.h
PlaylistBroadcaster.tproj/playlist_utils.cpp
PlaylistBroadcaster.tproj/playlist_utils.h
PlaylistBroadcaster.tproj/PlaylistBroadcaster.cpp
PlaylistBroadcaster.tproj/PlaylistPicker.cpp
PlaylistBroadcaster.tproj/PlaylistPicker.h
PlaylistBroadcaster.tproj/PLBroadcastDef.cpp
PlaylistBroadcaster.tproj/PLBroadcastDef.h
PlaylistBroadcaster.tproj/SimplePlayListElement.h
PlaylistBroadcaster.tproj/StSmartArrayPointer.h
PlaylistBroadcaster.tproj/tailor.h
PlaylistBroadcaster.tproj/TrackingElement.h)
add_executable(PlaylistBroadcaster ${PLAYLIST_BROADCASTER_SOURCE_FILES})
set(MP3_BROADCASTER_SOURCE_FILES
MP3Broadcaster/BroadcasterMain.cpp
MP3Broadcaster/MP3Broadcaster.cpp
MP3Broadcaster/MP3Broadcaster.h
MP3Broadcaster/MP3BroadcasterLog.cpp
MP3Broadcaster/MP3BroadcasterLog.h
MP3Broadcaster/MP3FileBroadcaster.cpp
MP3Broadcaster/MP3FileBroadcaster.h
MP3Broadcaster/MP3MetaInfoUpdater.cpp
MP3Broadcaster/MP3MetaInfoUpdater.h)
add_executable(MP3Broadcaster ${MP3_BROADCASTER_SOURCE_FILES})
add_executable(QTBroadcaster QTFileTools/QTBroadcaster.tproj/QTBroadcaster.cpp)
set(QTFILEINFO_SOURCE_FILES
QTFileLib/QTFile.cpp
QTFileLib/QTFile.h
QTFileTools/QTFileInfo.tproj/QTFileInfo.cpp)
add_executable(QTFileInfo ${QTFILEINFO_SOURCE_FILES})

View file

@ -0,0 +1,313 @@
/*
*
* @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@
*
*/
#include "HTTPProtocol.h"
StrPtrLen HTTPProtocol::sMethods[] =
{
StrPtrLen("GET"),
StrPtrLen("HEAD"),
StrPtrLen("POST"),
StrPtrLen("OPTIONS"),
StrPtrLen("PUT"),
StrPtrLen("DELETE"),
StrPtrLen("TRACE"),
StrPtrLen("CONNECT"),
};
HTTPMethod HTTPProtocol::GetMethod(const StrPtrLen* inMethodStr)
{
HTTPMethod theMethod = httpIllegalMethod;
if (inMethodStr->Len == 0)
return httpIllegalMethod;
switch((inMethodStr->Ptr)[0])
{
case 'G': theMethod = httpGetMethod; break;
case 'H': theMethod = httpHeadMethod; break;
case 'P': theMethod = httpPostMethod; break; // Most likely POST and not PUT
case 'O': theMethod = httpOptionsMethod; break;
case 'D': theMethod = httpDeleteMethod; break;
case 'T': theMethod = httpTraceMethod; break;
case 'C': theMethod = httpConnectMethod; break;
}
if ( (theMethod != httpIllegalMethod) && (inMethodStr->Equal(sMethods[theMethod])) )
return theMethod;
// Check for remaining methods (Only PUT method is left)
if ( inMethodStr->Equal(sMethods[httpPutMethod]) )
return httpPutMethod;
return httpIllegalMethod;
}
StrPtrLen HTTPProtocol::sHeaders[] =
{
StrPtrLen("Connection"),
StrPtrLen("Date"),
StrPtrLen("Authorization"),
StrPtrLen("If-Modified-Since"),
StrPtrLen("Server"),
StrPtrLen("WWW-Authenticate"),
StrPtrLen("Expires"),
StrPtrLen("Last-Modified"),
StrPtrLen("Cache-Control"),
StrPtrLen("Pragma"),
StrPtrLen("Trailer"),
StrPtrLen("Transfer-Encoding"),
StrPtrLen("Upgrade"),
StrPtrLen("Via"),
StrPtrLen("Warning"),
StrPtrLen("Accept"),
StrPtrLen("Accept-Charset"),
StrPtrLen("Accept-Encoding"),
StrPtrLen("Accept-Language"),
StrPtrLen("Expect"),
StrPtrLen("From"),
StrPtrLen("Host"),
StrPtrLen("If-Match"),
StrPtrLen("If-None-Match"),
StrPtrLen("If-Range"),
StrPtrLen("If-Unmodified-Since"),
StrPtrLen("Max-Forwards"),
StrPtrLen("Proxy-Authorization"),
StrPtrLen("Range"),
StrPtrLen("Referer"),
StrPtrLen("TE"),
StrPtrLen("User-Agent"),
StrPtrLen("Accept-Ranges"),
StrPtrLen("Age"),
StrPtrLen("ETag"),
StrPtrLen("Location"),
StrPtrLen("Proxy-Authenticate"),
StrPtrLen("Retry-After"),
StrPtrLen("Vary"),
StrPtrLen("Allow"),
StrPtrLen("Content-Encoding"),
StrPtrLen("Content-Language"),
StrPtrLen("Content-Length"),
StrPtrLen("Content-Location"),
StrPtrLen("Content-MD5"),
StrPtrLen("Content-Range"),
StrPtrLen("Content-Type"),
StrPtrLen("X-SessionCookie"),
StrPtrLen("X-Server-IP-Address"),
StrPtrLen(" ,")
};
HTTPHeader HTTPProtocol::GetHeader(const StrPtrLen* inHeaderStr)
{
if (inHeaderStr->Len == 0)
return httpIllegalHeader;
HTTPHeader theHeader = httpIllegalHeader;
//chances are this is one of our selected "VIP" headers. so check for this.
switch((inHeaderStr->Ptr)[0])
{
case 'C': case 'c': theHeader = httpConnectionHeader; break;
case 'S': case 's': theHeader = httpServerHeader; break;
case 'D': case 'd': theHeader = httpDateHeader; break;
case 'A': case 'a': theHeader = httpAuthorizationHeader; break;
case 'W': case 'w': theHeader = httpWWWAuthenticateHeader; break;
case 'I': case 'i': theHeader = httpIfModifiedSinceHeader; break;
case 'E': case 'e': theHeader = httpExpiresHeader; break;
case 'L': case 'l': theHeader = httpLastModifiedHeader; break;
// Added this to optimize for HTTP tunnelling in the server (Not really a VIP header)
case 'X': case 'x': theHeader = httpSessionCookieHeader; break;
}
if ((theHeader != httpIllegalHeader) &&
(inHeaderStr->EqualIgnoreCase(sHeaders[theHeader].Ptr, sHeaders[theHeader].Len)))
return theHeader;
//If this isn't one of our VIP headers, go through the remaining request headers, trying
//to find the right one.
for (SInt32 x = httpNumVIPHeaders; x < httpNumHeaders; x++)
if (inHeaderStr->EqualIgnoreCase(sHeaders[x].Ptr, sHeaders[x].Len))
return x;
return httpIllegalHeader;
}
StrPtrLen HTTPProtocol::sStatusCodeStrings[] =
{
StrPtrLen("Continue"), //kContinue
StrPtrLen("Switching Protocols"), //kSwitchingProtocols
StrPtrLen("OK"), //kOK
StrPtrLen("Created"), //kCreated
StrPtrLen("Accepted"), //kAccepted
StrPtrLen("Non Authoritative Information"), //kNonAuthoritativeInformation
StrPtrLen("No Content"), //kNoContent
StrPtrLen("Reset Content"), //kResetContent
StrPtrLen("Partial Content"), //kPartialContent
StrPtrLen("Multiple Choices"), //kMultipleChoices
StrPtrLen("Moved Permanently"), //kMovedPermanently
StrPtrLen("Found"), //kFound
StrPtrLen("See Other"), //kSeeOther
StrPtrLen("Not Modified"), //kNotModified
StrPtrLen("Use Proxy"), //kUseProxy
StrPtrLen("Temporary Redirect"), //kTemporaryRedirect
StrPtrLen("Bad Request"), //kBadRequest
StrPtrLen("Unauthorized"), //kUnAuthorized
StrPtrLen("Payment Required"), //kPaymentRequired
StrPtrLen("Forbidden"), //kForbidden
StrPtrLen("Not Found"), //kNotFound
StrPtrLen("Method Not Allowed"), //kMethodNotAllowed
StrPtrLen("Not Acceptable"), //kNotAcceptable
StrPtrLen("Proxy Authentication Required"), //kProxyAuthenticationRequired
StrPtrLen("Request Time-out"), //kRequestTimeout
StrPtrLen("Conflict"), //kConflict
StrPtrLen("Gone"), //kGone
StrPtrLen("Length Required"), //kLengthRequired
StrPtrLen("Precondition Failed"), //kPreconditionFailed
StrPtrLen("Request Entity Too Large"), //kRequestEntityTooLarge
StrPtrLen("Request-URI Too Large"), //kRequestURITooLarge
StrPtrLen("Unsupported Media Type"), //kUnsupportedMediaType
StrPtrLen("Request Range Not Satisfiable"), //kRequestRangeNotSatisfiable
StrPtrLen("Expectation Failed"), //kExpectationFailed
StrPtrLen("Internal Server Error"), //kInternalServerError
StrPtrLen("Not Implemented"), //kNotImplemented
StrPtrLen("Bad Gateway"), //kBadGateway
StrPtrLen("Service Unavailable"), //kServiceUnavailable
StrPtrLen("Gateway Timeout"), //kGatewayTimeout
StrPtrLen("HTTP Version not supported") //kHTTPVersionNotSupported
};
SInt32 HTTPProtocol::sStatusCodes[] =
{
100, //kContinue
101, //kSwitchingProtocols
200, //kOK
201, //kCreated
202, //kAccepted
203, //kNonAuthoritativeInformation
204, //kNoContent
205, //kResetContent
206, //kPartialContent
300, //kMultipleChoices
301, //kMovedPermanently
302, //kFound
303, //kSeeOther
304, //kNotModified
305, //kUseProxy
307, //kTemporaryRedirect
400, //kBadRequest
401, //kUnAuthorized
402, //kPaymentRequired
403, //kForbidden
404, //kNotFound
405, //kMethodNotAllowed
406, //kNotAcceptable
407, //kProxyAuthenticationRequired
408, //kRequestTimeout
409, //kConflict
410, //kGone
411, //kLengthRequired
412, //kPreconditionFailed
413, //kRequestEntityTooLarge
414, //kRequestURITooLarge
415, //kUnsupportedMediaType
416, //kRequestRangeNotSatisfiable
417, //kExpectationFailed
500, //kInternalServerError
501, //kNotImplemented
502, //kBadGateway
503, //kServiceUnavailable
504, //kGatewayTimeout
505 //kHTTPVersionNotSupported
};
StrPtrLen HTTPProtocol::sStatusCodeAsStrings[] =
{
StrPtrLen("100"), //kContinue
StrPtrLen("101"), //kSwitchingProtocols
StrPtrLen("200"), //kOK
StrPtrLen("201"), //kCreated
StrPtrLen("202"), //kAccepted
StrPtrLen("203"), //kNonAuthoritativeInformation
StrPtrLen("204"), //kNoContent
StrPtrLen("205"), //kResetContent
StrPtrLen("206"), //kPartialContent
StrPtrLen("300"), //kMultipleChoices
StrPtrLen("301"), //kMovedPermanently
StrPtrLen("302"), //kFound
StrPtrLen("303"), //kSeeOther
StrPtrLen("304"), //kNotModified
StrPtrLen("305"), //kUseProxy
StrPtrLen("307"), //kTemporaryRedirect
StrPtrLen("400"), //kBadRequest
StrPtrLen("401"), //kUnAuthorized
StrPtrLen("402"), //kPaymentRequired
StrPtrLen("403"), //kForbidden
StrPtrLen("404"), //kNotFound
StrPtrLen("405"), //kMethodNotAllowed
StrPtrLen("406"), //kNotAcceptable
StrPtrLen("407"), //kProxyAuthenticationRequired
StrPtrLen("408"), //kRequestTimeout
StrPtrLen("409"), //kConflict
StrPtrLen("410"), //kGone
StrPtrLen("411"), //kLengthRequired
StrPtrLen("412"), //kPreconditionFailed
StrPtrLen("413"), //kRequestEntityTooLarge
StrPtrLen("414"), //kRequestURITooLarge
StrPtrLen("415"), //kUnsupportedMediaType
StrPtrLen("416"), //kRequestRangeNotSatisfiable
StrPtrLen("417"), //kExpectationFailed
StrPtrLen("500"), //kInternalServerError
StrPtrLen("501"), //kNotImplemented
StrPtrLen("502"), //kBadGateway
StrPtrLen("503"), //kServiceUnavailable
StrPtrLen("504"), //kGatewayTimeout
StrPtrLen("505") //kHTTPVersionNotSupported
};
StrPtrLen HTTPProtocol::sVersionStrings[] =
{
StrPtrLen("HTTP/0.9"),
StrPtrLen("HTTP/1.0"),
StrPtrLen("HTTP/1.1")
};
HTTPVersion HTTPProtocol::GetVersion(StrPtrLen* versionStr)
{
if (versionStr->Len != 8)
return httpIllegalVersion;
SInt32 limit = httpNumVersions;
for (SInt32 x = 0; x < limit; x++)
{
if (versionStr->EqualIgnoreCase(sVersionStrings[x].Ptr, sVersionStrings[x].Len))
return x;
}
return httpIllegalVersion;
}

View file

@ -0,0 +1,204 @@
/*
*
* @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@
*
*/
#ifndef __HTTPPROTOCOL_H__
#define __HTTPPROTOCOL_H__
#include "OSHeaders.h"
#include "StrPtrLen.h"
// Versions
enum
{
http09version = 0,
http10Version = 1,
http11Version = 2,
httpNumVersions = 3,
httpIllegalVersion = 3
};
typedef UInt32 HTTPVersion;
// Methods
enum
{
httpGetMethod = 0,
httpHeadMethod = 1,
httpPostMethod = 2,
httpOptionsMethod = 3,
httpPutMethod = 4,
httpDeleteMethod = 5,
httpTraceMethod = 6,
httpConnectMethod = 7,
httpNumMethods = 8,
httpIllegalMethod = 8
};
typedef UInt32 HTTPMethod;
// Headers
enum
{
// VIP headers
httpConnectionHeader = 0, // general header
httpDateHeader = 1, // general header
httpAuthorizationHeader = 2, // request header
httpIfModifiedSinceHeader = 3, // request header
httpServerHeader = 4, // response header
httpWWWAuthenticateHeader = 5, // response header
httpExpiresHeader = 6, // entity header
httpLastModifiedHeader = 7, // entity header
httpNumVIPHeaders = 8,
//Other general http headers
httpCacheControlHeader = 8,
httpPragmaHeader = 9,
httpTrailerHeader = 10,
httpTransferEncodingHeader = 11,
httpUpgradeHeader = 12,
httpViaHeader = 13,
httpWarningHeader = 14,
// Other request headers
httpAcceptHeader = 15,
httpAcceptCharsetHeader = 16,
httpAcceptEncodingHeader = 17,
httpAcceptLanguageHeader = 18,
httpExpectHeader = 19,
httpFromHeader = 20,
httpHostHeader = 21,
httpIfMatchHeader = 22,
httpIfNoneMatchHeader = 23,
httpIfRangeHeader = 24,
httpIfUnmodifiedSinceHeader = 25,
httpMaxForwardsHeader = 26,
httpProxyAuthorizationHeader = 27,
httpRangeHeader = 28,
httpRefererHeader = 29,
httpTEHeader = 30,
httpUserAgentHeader = 31,
// Other response headers
httpAcceptRangesHeader = 32,
httpAgeHeader = 33,
httpETagHeader = 34,
httpLocationHeader = 35,
httpProxyAuthenticateHeader = 36,
httpRetryAfterHeader = 37,
httpVaryHeader = 38,
// Other entity headers
httpAllowHeader = 39,
httpContentEncodingHeader = 40,
httpContentLanguageHeader = 41,
httpContentLengthHeader = 42,
httpContentLocationHeader = 43,
httpContentMD5Header = 44,
httpContentRangeHeader = 45,
httpContentTypeHeader = 46,
// QTSS Specific headers
// Add headers that are not part of the HTTP spec here
// Make sure and up the number of headers and httpIllegalHeader number
httpSessionCookieHeader = 47, // Used for HTTP tunnelling
httpServerIPAddressHeader = 48,
httpNumHeaders = 49,
httpIllegalHeader = 49
};
typedef UInt32 HTTPHeader;
// Status codes
enum
{
httpContinue = 0, //100
httpSwitchingProtocols = 1, //101
httpOK = 2, //200
httpCreated = 3, //201
httpAccepted = 4, //202
httpNonAuthoritativeInformation = 5, //203
httpNoContent = 6, //204
httpResetContent = 7, //205
httpPartialContent = 8, //206
httpMultipleChoices = 9, //300
httpMovedPermanently = 10, //301
httpFound = 11, //302
httpSeeOther = 12, //303
httpNotModified = 13, //304
httpUseProxy = 14, //305
httpTemporaryRedirect = 15, //307
httpBadRequest = 16, //400
httpUnAuthorized = 17, //401
httpPaymentRequired = 18, //402
httpForbidden = 19, //403
httpNotFound = 20, //404
httpMethodNotAllowed = 21, //405
httpNotAcceptable = 22, //406
httpProxyAuthenticationRequired = 23, //407
httpRequestTimeout = 24, //408
httpConflict = 25, //409
httpGone = 26, //410
httpLengthRequired = 27, //411
httpPreconditionFailed = 28, //412
httpRequestEntityTooLarge = 29, //413
httpRequestURITooLarge = 30, //414
httpUnsupportedMediaType = 31, //415
httpRequestRangeNotSatisfiable = 32, //416
httpExpectationFailed = 33, //417
httpInternalServerError = 34, //500
httpNotImplemented = 35, //501
httpBadGateway = 36, //502
httpServiceUnavailable = 37, //503
httpGatewayTimeout = 38, //504
httpHTTPVersionNotSupported = 39, //505
httpNumStatusCodes = 40
};
typedef UInt32 HTTPStatusCode;
class HTTPProtocol
{
public:
// Methods
static HTTPMethod GetMethod(const StrPtrLen* inMethodStr);
static StrPtrLen* GetMethodString(HTTPMethod inMethod) { return &sMethods[inMethod]; }
// Headers
static HTTPHeader GetHeader(const StrPtrLen* inHeaderStr);
static StrPtrLen* GetHeaderString(HTTPHeader inHeader) { return &sHeaders[inHeader]; }
// Status codes
static StrPtrLen* GetStatusCodeString(HTTPStatusCode inStat) { return &sStatusCodeStrings[inStat]; }
static SInt32 GetStatusCode(HTTPStatusCode inStat) { return sStatusCodes[inStat]; }
static StrPtrLen* GetStatusCodeAsString(HTTPStatusCode inStat) { return &sStatusCodeAsStrings[inStat]; }
// Versions
static HTTPVersion GetVersion(StrPtrLen* versionStr);
static StrPtrLen* GetVersionString(HTTPVersion version) { return &sVersionStrings[version]; }
private:
static StrPtrLen sMethods[];
static StrPtrLen sHeaders[];
static StrPtrLen sStatusCodeStrings[];
static StrPtrLen sStatusCodeAsStrings[];
static SInt32 sStatusCodes[];
static StrPtrLen sVersionStrings[];
};
#endif // __HTTPPROTOCOL_H__

View file

@ -0,0 +1,419 @@
/*
*
* @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@
*
*/
#include "HTTPRequest.h"
#include "HTTPProtocol.h"
#include "OSMemory.h"
#include "StringParser.h"
#include "StringTranslator.h"
#include "ResizeableStringFormatter.h"
#include "DateTranslator.h"
StrPtrLen HTTPRequest::sColonSpace(": ", 2);
static Bool16 sFalse = false;
static Bool16 sTrue = true;
static StrPtrLen sCloseString("close", 5);
static StrPtrLen sKeepAliveString("keep-alive", 10);
static StrPtrLen sDefaultRealm("Streaming Server", 19);
UInt8 HTTPRequest::sURLStopConditions[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 //'\t' is a stop condition
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, //10-19 //'\r' & '\n' are stop conditions
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //30-39 //' '
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40-49
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-59
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //60-69
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150-159
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240-249
0, 0, 0, 0, 0, 0 //250-255
};
// Constructor
HTTPRequest::HTTPRequest(StrPtrLen* serverHeader, StrPtrLen* requestPtr)
{
// Store the pointer to the server header field
fSvrHeader = *serverHeader;
// Set initial state
fRequestHeader = *requestPtr;
fResponseHeader = NULL;
fResponseFormatter = NULL;
fMethod = httpIllegalMethod;
fVersion = httpIllegalVersion;
fAbsoluteURI = NULL;
fRelativeURI = NULL;
fAbsoluteURIScheme = NULL;
fHostHeader = NULL;
fRequestPath = NULL;
fStatusCode = httpOK;
fRequestKeepAlive = false; // Default value when there is no version string
}
// Constructor for creating a response only
HTTPRequest::HTTPRequest(StrPtrLen* serverHeader)
{
// Store the pointer to the server header field
fSvrHeader = *serverHeader;
// We do not require any of these:
fRequestHeader = NULL;
fMethod = httpIllegalMethod;
fVersion = httpIllegalVersion;
fRequestLine = NULL;
fAbsoluteURI = NULL;
fRelativeURI = NULL;
fAbsoluteURIScheme = NULL;
fHostHeader = NULL;
fRequestPath = NULL;
fStatusCode = 0;
fRequestKeepAlive = false;
// We require the response but we allocate memory only when we call
// CreateResponseHeader
fResponseHeader = NULL;
fResponseFormatter = NULL;
}
// Destructor
HTTPRequest::~HTTPRequest()
{
if (fResponseHeader != NULL)
{
if (fResponseHeader->Ptr != NULL)
delete fResponseHeader->Ptr;
delete fResponseHeader;
}
if (fResponseFormatter != NULL)
delete fResponseFormatter;
if (fRequestPath != NULL)
delete [] fRequestPath;
}
//Parses the request
QTSS_Error HTTPRequest::Parse()
{
Assert(fRequestHeader.Ptr != NULL);
StringParser parser(&fRequestHeader);
// Store the request line (used for logging)
// (ex: GET /index.html HTTP/1.0)
StringParser requestLineParser(&fRequestHeader);
requestLineParser.ConsumeUntil(&fRequestLine, StringParser::sEOLMask);
// Parse request line returns an error if there is an error in the
// request URI or the formatting of the request line.
// If the method or version are not found, they are set
// to httpIllegalMethod or httpIllegalVersion respectively,
// and QTSS_NoErr is returned.
QTSS_Error err = ParseRequestLine(&parser);
if (err != QTSS_NoErr)
return err;
// Parse headers and set values of headers into fFieldValues array
err = ParseHeaders(&parser);
if (err != QTSS_NoErr)
return err;
return QTSS_NoErr;
}
QTSS_Error HTTPRequest::ParseRequestLine(StringParser* parser)
{
// Get the method - If the method is not one of the defined methods
// then it doesn't return an error but sets fMethod to httpIllegalMethod
StrPtrLen theParsedData;
parser->ConsumeWord(&theParsedData);
fMethod = HTTPProtocol::GetMethod(&theParsedData);
// Consume whitespace
parser->ConsumeWhitespace();
// Parse the URI - If it fails returns an error after setting
// the fStatusCode to the appropriate error code
QTSS_Error err = ParseURI(parser);
if (err != QTSS_NoErr)
return err;
// Consume whitespace
parser->ConsumeWhitespace();
// If there is a version, consume the version string
StrPtrLen versionStr;
parser->ConsumeUntil(&versionStr, StringParser::sEOLMask);
// Check the version
if (versionStr.Len > 0)
fVersion = HTTPProtocol::GetVersion(&versionStr);
// Go past the end of line
if (!parser->ExpectEOL())
{
fStatusCode = httpBadRequest;
return QTSS_BadArgument; // Request line is not properly formatted!
}
return QTSS_NoErr;
}
QTSS_Error HTTPRequest::ParseURI(StringParser* parser)
{
// read in the complete URL into fRequestAbsURI
parser->ConsumeUntil(&fAbsoluteURI, sURLStopConditions);
StringParser urlParser(&fAbsoluteURI);
// we always should have a slash before the URI
// If not, that indicates this is a full URI
if (fAbsoluteURI.Ptr[0] != '/')
{
//if it is a full URL, store the scheme and host name
urlParser.ConsumeLength(&fAbsoluteURIScheme, 7); //consume "http://"
urlParser.ConsumeUntil(&fHostHeader, '/');
}
// whatever is in this position is the relative URI
StrPtrLen relativeURI(urlParser.GetCurrentPosition(), urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen());
// read this URI into fRequestRelURI
fRelativeURI = relativeURI;
// Allocate memory for fRequestPath
UInt32 len = fRelativeURI.Len;
len++;
char* relativeURIDecoded = NEW char[len];
SInt32 theBytesWritten = StringTranslator::DecodeURL(fRelativeURI.Ptr, fRelativeURI.Len,
relativeURIDecoded, len);
//if negative, an error occurred, reported as an QTSS_Error
//we also need to leave room for a terminator.
if ((theBytesWritten < 0) || ((UInt32)theBytesWritten == len))
{
fStatusCode = httpBadRequest;
return QTSS_BadArgument;
}
fRequestPath = NEW char[theBytesWritten + 1];
::memcpy(fRequestPath, relativeURIDecoded + 1, theBytesWritten);
delete relativeURIDecoded;
fRequestPath[theBytesWritten] = '\0';
return QTSS_NoErr;
}
// Parses the Connection header and makes sure that request is properly terminated
QTSS_Error HTTPRequest::ParseHeaders(StringParser* parser)
{
StrPtrLen theKeyWord;
Bool16 isStreamOK;
//Repeat until we get a \r\n\r\n, which signals the end of the headers
while ((parser->PeekFast() != '\r') && (parser->PeekFast() != '\n'))
{
//First get the header identifier
isStreamOK = parser->GetThru(&theKeyWord, ':');
if (!isStreamOK)
{ // No colon after header!
fStatusCode = httpBadRequest;
return QTSS_BadArgument;
}
if (parser->PeekFast() == ' ')
{ // handle space, if any
isStreamOK = parser->Expect(' ');
Assert(isStreamOK);
}
//Look up the proper header enumeration based on the header string.
HTTPHeader theHeader = HTTPProtocol::GetHeader(&theKeyWord);
StrPtrLen theHeaderVal;
isStreamOK = parser->GetThruEOL(&theHeaderVal);
if (!isStreamOK)
{ // No EOL after header!
fStatusCode = httpBadRequest;
return QTSS_BadArgument;
}
// If this is the connection header
if ( theHeader == httpConnectionHeader )
{ // Set the keep alive boolean based on the connection header value
SetKeepAlive(&theHeaderVal);
}
// Have the header field and the value; Add value to the array
// If the field is invalid (or unrecognized) just skip over gracefully
if ( theHeader != httpIllegalHeader )
fFieldValues[theHeader] = theHeaderVal;
}
isStreamOK = parser->ExpectEOL();
Assert(isStreamOK);
return QTSS_NoErr;
}
void HTTPRequest::SetKeepAlive(StrPtrLen *keepAliveValue)
{
if ( sCloseString.EqualIgnoreCase(keepAliveValue->Ptr, keepAliveValue->Len) )
fRequestKeepAlive = sFalse;
else
{
Assert( sKeepAliveString.EqualIgnoreCase(keepAliveValue->Ptr, keepAliveValue->Len) );
fRequestKeepAlive = sTrue;
}
}
void HTTPRequest::PutStatusLine(StringFormatter* putStream, HTTPStatusCode status,
HTTPVersion version)
{
putStream->Put(*(HTTPProtocol::GetVersionString(version)));
putStream->PutSpace();
putStream->Put(*(HTTPProtocol::GetStatusCodeAsString(status)));
putStream->PutSpace();
putStream->Put(*(HTTPProtocol::GetStatusCodeString(status)));
putStream->PutEOL();
}
StrPtrLen* HTTPRequest::GetHeaderValue(HTTPHeader inHeader)
{
if ( inHeader != httpIllegalHeader )
return &fFieldValues[inHeader];
return NULL;
}
void HTTPRequest:: CreateResponseHeader(HTTPVersion version, HTTPStatusCode statusCode)
{
// If we are creating a second response for the same request, make sure and
// deallocate memory for old response and allocate fresh memory
if (fResponseFormatter != NULL)
{
if(fResponseHeader->Ptr != NULL)
delete fResponseHeader->Ptr;
delete fResponseHeader;
delete fResponseFormatter;
}
// Allocate memory for the response when you first create it
char* responseString = NEW char[kMinHeaderSizeInBytes];
fResponseHeader = NEW StrPtrLen(responseString, kMinHeaderSizeInBytes);
fResponseFormatter = NEW ResizeableStringFormatter(fResponseHeader->Ptr, fResponseHeader->Len);
//make a partial header for the given version and status code
PutStatusLine(fResponseFormatter, statusCode, version);
Assert(fSvrHeader.Ptr != NULL);
fResponseFormatter->Put(fSvrHeader);
fResponseFormatter->PutEOL();
fResponseHeader->Len = fResponseFormatter->GetCurrentOffset();
}
StrPtrLen* HTTPRequest::GetCompleteResponseHeader()
{
fResponseFormatter->PutEOL();
fResponseHeader->Len = fResponseFormatter->GetCurrentOffset();
return fResponseHeader;
}
void HTTPRequest::AppendResponseHeader(HTTPHeader inHeader, StrPtrLen* inValue)
{
fResponseFormatter->Put(*(HTTPProtocol::GetHeaderString(inHeader)));
fResponseFormatter->Put(sColonSpace);
fResponseFormatter->Put(*inValue);
fResponseFormatter->PutEOL();
fResponseHeader->Len = fResponseFormatter->GetCurrentOffset();
}
void HTTPRequest::AppendContentLengthHeader(UInt64 length_64bit)
{
char* contentLength = NEW char[256];
qtss_sprintf(contentLength, "%"_64BITARG_"d", length_64bit);
StrPtrLen contentLengthPtr(contentLength);
AppendResponseHeader(httpContentLengthHeader, &contentLengthPtr);
}
void HTTPRequest::AppendContentLengthHeader(UInt32 length_32bit)
{
char* contentLength = NEW char[256];
qtss_sprintf(contentLength, "%"_U32BITARG_"", length_32bit);
StrPtrLen contentLengthPtr(contentLength);
AppendResponseHeader(httpContentLengthHeader, &contentLengthPtr);
}
void HTTPRequest::AppendConnectionCloseHeader()
{
AppendResponseHeader(httpConnectionHeader, &sCloseString);
}
void HTTPRequest::AppendConnectionKeepAliveHeader()
{
AppendResponseHeader(httpConnectionHeader, &sKeepAliveString);
}
void HTTPRequest::AppendDateAndExpiresFields()
{
Assert(OSThread::GetCurrent() != NULL);
DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
// Append dates, and have this response expire immediately
this->AppendResponseHeader(httpDateHeader, &theDate);
this->AppendResponseHeader(httpExpiresHeader, &theDate);
}
void HTTPRequest::AppendDateField()
{
Assert(OSThread::GetCurrent() != NULL);
DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
// Append date
this->AppendResponseHeader(httpDateHeader, &theDate);
}
time_t HTTPRequest::ParseIfModSinceHeader()
{
time_t theIfModSinceDate = (time_t) DateTranslator::ParseDate(&fFieldValues[httpIfModifiedSinceHeader]);
return theIfModSinceDate;
}

View file

@ -0,0 +1,137 @@
/*
*
* @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@
*
*/
#ifndef __HTTPREQUEST_H__
#define __HTTPREQUEST_H__
#include "HTTPProtocol.h"
#include "StrPtrLen.h"
#include "StringParser.h"
#include "ResizeableStringFormatter.h"
#include "OSHeaders.h"
#include "QTSS.h"
class HTTPRequest
{
public:
// Constructor
HTTPRequest(StrPtrLen* serverHeader, StrPtrLen* requestPtr);
// This cosntructor is used when the request has been parsed and thrown away
// and the response has to be created
HTTPRequest(StrPtrLen* serverHeader);
// Destructor
virtual ~HTTPRequest();
// Should be called before accessing anything in the request header
// Calls ParseRequestLine and ParseHeaders
QTSS_Error Parse();
// Basic access methods for the HTTP method, the absolute request URI,
// the host name from URI, the relative request URI, the request file path,
// the HTTP version, the Status code, the keep-alive tag.
HTTPMethod GetMethod(){ return fMethod; }
StrPtrLen* GetRequestLine(){ return &fRequestLine; }
StrPtrLen* GetRequestAbsoluteURI(){ return &fAbsoluteURI; }
StrPtrLen* GetSchemefromAbsoluteURI(){ return &fAbsoluteURIScheme; }
StrPtrLen* GetHostfromAbsoluteURI(){ return &fHostHeader; }
StrPtrLen* GetRequestRelativeURI(){ return &fRelativeURI; }
char* GetRequestPath(){ return fRequestPath; }
HTTPVersion GetVersion(){ return fVersion; }
HTTPStatusCode GetStatusCode(){ return fStatusCode; }
Bool16 IsRequestKeepAlive(){ return fRequestKeepAlive; }
// If header field exists in the request, it will be found in the dictionary
// and the value returned. Otherwise, NULL is returned.
StrPtrLen* GetHeaderValue(HTTPHeader inHeader);
// Creates a header with the corresponding version and status code
void CreateResponseHeader(HTTPVersion version, HTTPStatusCode statusCode);
// To append response header fields as appropriate
void AppendResponseHeader(HTTPHeader inHeader, StrPtrLen* inValue);
void AppendDateAndExpiresFields();
void AppendDateField();
void AppendConnectionCloseHeader();
void AppendConnectionKeepAliveHeader();
void AppendContentLengthHeader(UInt64 length_64bit);
void AppendContentLengthHeader(UInt32 length_32bit);
// Returns the completed response header by appending CRLF to the end of the header
// fields buffer
StrPtrLen* GetCompleteResponseHeader();
// Parse if-modified-since header
time_t ParseIfModSinceHeader();
private:
enum { kMinHeaderSizeInBytes = 512 };
// Gets the method, version and calls ParseURI
QTSS_Error ParseRequestLine(StringParser* parser);
// Parses the URI to get absolute and relative URIs, the host name and the file path
QTSS_Error ParseURI(StringParser* parser);
// Parses the headers and adds them into a dictionary
// Also calls SetKeepAlive with the Connection header field's value if it exists
QTSS_Error ParseHeaders(StringParser* parser);
// Sets fRequestKeepAlive
void SetKeepAlive(StrPtrLen* keepAliveValue);
// Used in initialize and CreateResponseHeader
void PutStatusLine(StringFormatter* putStream, HTTPStatusCode status, HTTPVersion version);
//For writing into the premade headers
StrPtrLen* GetServerHeader(){ return &fSvrHeader; }
// Complete request and response headers
StrPtrLen fRequestHeader;
ResizeableStringFormatter* fResponseFormatter;
StrPtrLen* fResponseHeader;
// Private members
HTTPMethod fMethod;
HTTPVersion fVersion;
StrPtrLen fRequestLine;
// For the URI (fAbsoluteURI and fRelativeURI are the same if the URI is of the form "/path")
StrPtrLen fAbsoluteURI; // If it is of the form "http://foo.bar.com/path"
StrPtrLen fRelativeURI; // If it is of the form "/path"
// If it is an absolute URI, these fields will be filled in
// "http://foo.bar.com/path" => fAbsoluteURIScheme = "http", fHostHeader = "foo.bar.com",
// fRequestPath = "path"
StrPtrLen fAbsoluteURIScheme;
StrPtrLen fHostHeader; // If the full url is given in the request line
char* fRequestPath; // Also contains the query string
HTTPStatusCode fStatusCode;
Bool16 fRequestKeepAlive; // Keep-alive information in the client request
StrPtrLen fFieldValues[httpNumHeaders]; // Array of header field values parsed from the request
StrPtrLen fSvrHeader; // Server header set up at initialization
static StrPtrLen sColonSpace;
static UInt8 sURLStopConditions[];
};
#endif // __HTTPREQUEST_H__

236
PlatformHeader.h Normal file
View file

@ -0,0 +1,236 @@
/*
*
* @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@
*
*/
// Build flags. How do you want your server built?
#define DEBUG 0
#define ASSERT 1
#define MEMORY_DEBUGGING 0 //enable this to turn on really fancy debugging of memory leaks, etc...
#define QTFILE_MEMORY_DEBUGGING 0
#if __MacOSX__
#define PLATFORM_SERVER_BIN_NAME "QuickTimeStreamingServer"
#define PLATFORM_SERVER_TEXT_NAME "QuickTime Streaming Server"
#else
#define PLATFORM_SERVER_BIN_NAME "DarwinStreamingServer"
#define PLATFORM_SERVER_TEXT_NAME "Darwin Streaming Server"
#define MMAP_TABLES 0
#endif
// Platform-specific switches
#if __MacOSX__
#define USE_ATOMICLIB 0
//#define MACOSXEVENTQUEUE 1
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#include <machine/endian.h>
#include <machine/limits.h>
#if BYTE_ORDER == BIG_ENDIAN
#define BIGENDIAN 1
#else
#define BIGENDIAN 0
#endif
#define ALLOW_NON_WORD_ALIGN_ACCESS 1
#define USE_THREAD 0 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "MacOSX"
#define EXPORT
#define MACOSX_PUBLICBETA 0
#define USE_DEFAULT_STD_LIB 1
#ifdef __LP64__
#define MACOSXEVENTQUEUE 1
#define EVENTS_KQUEUE 0 // future
#define EVENTS_SELECT 0 // future
#define EVENTS_OSXEVENTQUEUE 0 // future
#define SET_SELECT_SIZE 1024
#define MMAP_TABLES 0
#else
#define MACOSXEVENTQUEUE 1
#define EVENTS_KQUEUE 0
#define EVENTS_SELECT 0
#define EVENTS_OSXEVENTQUEUE 1
#define SET_SELECT_SIZE 0
#define MMAP_TABLES 0
#endif
#elif __Win32__
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 0
#define __PTHREADS_MUTEXES__ 0
//#define BIGENDIAN 0 // Defined equivalently inside windows
#define ALLOW_NON_WORD_ALIGN_ACCESS 1
#define USE_THREAD 0 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "Win32"
#define EXPORT __declspec(dllexport)
#ifndef USE_DEFAULT_STD_LIB
#define USE_DEFAULT_STD_LIB 1
#endif
#elif __linux__
#include <endian.h>
#if __BYTE_ORDER == BIG_ENDIAN
#define BIGENDIAN 1
#else
#define BIGENDIAN 0
#endif
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define ALLOW_NON_WORD_ALIGN_ACCESS 1
#define USE_THREAD 0 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "Linux"
#define EXPORT
#define _REENTRANT 1
#elif __linuxppc__
#include <endian.h>
#if __BYTE_ORDER == BIG_ENDIAN
#define BIGENDIAN 1
#else
#define BIGENDIAN 0
#endif
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define ALLOW_NON_WORD_ALIGN_ACCESS 1
#define USE_THREAD 0 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "LinuxPPC"
#define EXPORT
#define _REENTRANT 1
#elif __FreeBSD__
#include <machine/endian.h>
#if BYTE_ORDER == BIG_ENDIAN
#define BIGENDIAN 1
#else
#define BIGENDIAN 0
#endif
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define ALLOW_NON_WORD_ALIGN_ACCESS 1
#define USE_THREAD 1 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 1
#define USE_THR_YIELD 0
#define kPlatformNameString "FreeBSD"
#define EXPORT
#define _REENTRANT 1
#elif __solaris__
#ifdef sparc
#define BIGENDIAN 1
#endif
#ifdef _M_IX86
#define BIGENDIAN 0
#endif
#ifdef _M_ALPHA
#define BIGENDIAN 0
#endif
#ifndef BIGENDIAN
#error NEED BIGENDIAN DEFINITION 0 OR 1 FOR PLATFORM
#endif
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define ALLOW_NON_WORD_ALIGN_ACCESS 0
#define USE_THREAD 1 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "Solaris"
#define EXPORT
#define _REENTRANT 1
#elif __sgi__
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define BIGENDIAN 1
#define ALLOW_NON_WORD_ALIGN_ACCESS 0
#define USE_THREAD 1 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "IRIX"
#define EXPORT
#define _REENTRANT 1
#elif __hpux__
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define BIGENDIAN 1
#define ALLOW_NON_WORD_ALIGN_ACCESS 0
#define USE_THREAD 1 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "HP-UX"
#define EXPORT
#define _REENTRANT 1
#elif defined(__osf__)
#define __osf__ 1
#define USE_ATOMICLIB 0
#define MACOSXEVENTQUEUE 0
#define __PTHREADS__ 1
#define __PTHREADS_MUTEXES__ 1
#define BIGENDIAN 0
#define ALLOW_NON_WORD_ALIGN_ACCESS 0
#define USE_THREAD 1 //Flag used in QTProxy
#define THREADING_IS_COOPERATIVE 0
#define USE_THR_YIELD 0
#define kPlatformNameString "Tru64UNIX"
#define EXPORT
#endif

View file

@ -0,0 +1,578 @@
/*
*
* @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@
*
*/
/*
8.30.99 - changes for linux version
- IsProcessRunning changed
- fputs difference.
8.2.99 rt
- changed BCasterTracker::BCasterTracker to 5 second open timer.
- no longer lists broadcasts that are not running. file is
cleaned up on next "stop"
*/
#include "BCasterTracker.h"
#include "MyAssert.h"
#include "Trim.h"
#include "GetWord.h"
#include "OSThread.h"
#include <stdlib.h>
#include "SafeStdLib.h"
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#if !(defined(__solaris__) || defined(__osf__) || defined(__hpux__))
#include <sys/sysctl.h>
#endif
#include <sys/time.h>
#include <signal.h>
char gTrackerFileTempDataPath[256];
void TestBCasterTracker(int x )
{
BCasterTracker tracker( "trackerfile" );
if ( tracker.IsOpen() )
{
if ( x > - 1 )
{ int error;
error = tracker.Remove( x );
if ( error ) // remove the xth item from the list.
qtss_printf( "Playlist Broadcast (%li) not found.\n", (SInt32)x );
else
tracker.Save();
}
else
{
tracker.Show();
}
}
else
qtss_printf("PlaylistBroadcaster trackerfile open FAILED.\n");
}
static void ShowElement( PLDoubleLinkedListNode<TrackingElement>* ten, void* userData)
{
int* showIndex = (int*)userData;
char *info;
if ( BCasterTracker::IsProcessRunning( ten->fElement->mPID ) )
info = "";
else
info = ", (not running)";
//qtss_printf( "[%li] %li %s%s\n", (SInt32)*showIndex, (SInt32)ten->fElement->mPID, ten->fElement->mName, info );
qtss_printf( "[%3li] %s; pid: %li%s\n", (SInt32)*showIndex, ten->fElement->mName, (SInt32)ten->fElement->mPID, info );
*(int*)userData = *showIndex + 1;
}
void BCasterTracker::Show()
{
int showIndex = 1;
if ( mTrackingList.GetNumNodes() )
{
qtss_printf( "\n" );
qtss_printf( "Current Playlist Broadcasts\n" );
qtss_printf( " ID Description file; Process ID\n" );
qtss_printf( "----------------------------------\n" );
// display the elements in the list
mTrackingList.ForEach( ShowElement, &showIndex );
}
else
{ qtss_printf( "\n" );
qtss_printf( "- PlaylistBroadcaster: No Broadcasts running.\n" );
}
}
bool BCasterTracker::IsProcessRunning( pid_t pid )
{
bool isRunning=false;
/*
// Generic unix code
char procPath[256];
qtss_sprintf( procPath, "ps -p%li | grep %li > %s ",(SInt32)pid,(SInt32)pid,gTrackerFileTempDataPath);
int result = system(procPath);
if (0 == result)
{ isRunning = true;
}
*/
// a no-grep version to find the pid
char pidStr[32];
qtss_sprintf( pidStr, "%li",(SInt32)pid);
char procPath[64] = "ps -p";
::strcat( procPath, pidStr);
FILE *inPipe = ::popen(procPath, "r");
if (NULL == inPipe)
return false;
char inBuff[256] = "";
while (!isRunning && ::fgets(inBuff, sizeof(inBuff), inPipe) != 0)
{ if (::strstr(inBuff,pidStr) != NULL)
{ isRunning = true;
break;
}
}
(void) ::pclose(inPipe);
return isRunning;
}
bool IsProcessID( PLDoubleLinkedListNode<TrackingElement>*ten, void* userData)
{
/*
used by ForEachUntil to find a TrackingElement with a given Process ID
userData is a pointer to the process id we want find in our list.
*/
pid_t pid;
bool isProcID = false;
pid = *(pid_t*)userData;
if ( pid == ten->fElement->mPID )
isProcID = true;
return isProcID;
}
int BCasterTracker::RemoveByProcessID( pid_t pid )
{
int error = -1;
// remove the element with the given process ID
// from the tracking list.
// called by the app when it is going away.
// DO NOT kill the pid being passed in.
PLDoubleLinkedListNode<TrackingElement> *te;
te = mTrackingList.ForEachUntil( IsProcessID, &pid );
// remove that element
if ( te )
{
mTrackingList.RemoveNode(te);
error = 0;
}
return error;
}
static bool IsElementID( PLDoubleLinkedListNode<TrackingElement> */*ten*/, void* userData)
{
/*
used by ForEachUntil to find a TrackingElement with a given index number
userData is a pointer to the counter, initialized to the index we want
to find.
we decrement it until is reaches zero.
*/
UInt32* showIndex = (UInt32*)userData;
bool isItemId = false;
// when the counter reduces to zero, return true.
if ( *showIndex == 0 )
isItemId = true;
else
*(int*)userData = *showIndex - 1;
return isItemId;
}
int BCasterTracker::Remove( UInt32 itemID )
{
int error = -1;
UInt32 itemIDIndex = itemID;
// KILL the process that is associated with the item
// id in our list.
// remove the element with the given index in the list
// from the tracking list.
// itemID is zero based
// set the index to the item number we want to find. Use ForEachUntil with IsElementID
// to count down through the elements until we get to the Nth element.
PLDoubleLinkedListNode<TrackingElement> *te;
te = mTrackingList.ForEachUntil( IsElementID, &itemIDIndex );
// remove that element, and kill the process
if ( te )
{
if ( ::kill( te->fElement->mPID, SIGTERM ) == 0 )
{
error = 0;
}
else
{
error = OSThread::GetErrno();
if ( error != ESRCH ) // no such process
{
// we probably cannot kill this process because it is not ours
}
else
{ // this process already died, or was killed by other means.
error = 0;
}
}
if ( !error )
{
mTrackingList.RemoveNode(te);
}
}
return error;
}
int BCasterTracker::Add( pid_t pid, const char* bcastList )
{
/*
add an entry to our tracking list
*/
int addErr = -1;
TrackingElement* te = new TrackingElement( pid, bcastList );
Assert( te );
if ( te )
{
PLDoubleLinkedListNode<TrackingElement>* ten = new PLDoubleLinkedListNode<TrackingElement>( te );
Assert( ten );
if ( ten )
{ mTrackingList.AddNodeToTail( ten );
addErr = 0;
}
else
delete te;
}
return addErr;
}
BCasterTracker::~BCasterTracker()
{
// truncate the file to the desired size and close.
if ( mTrackerFile != NULL )
{
int err = OSThread::GetErrno();
if ( ::fseek( mTrackerFile, mEofPos, SEEK_SET ) < 0 )
qtss_printf( "fseek at close eof(%li), err(%li), fileno(%li)\n", mEofPos, (SInt32)err, (SInt32)fileno(mTrackerFile) );
if ( ::fflush( mTrackerFile ) )
qtss_printf( "fflush at close eof(%li), err(%li), fileno(%li)\n", mEofPos, (SInt32)err, (SInt32)fileno(mTrackerFile) );
if ( ::ftruncate( fileno(mTrackerFile), (off_t)mEofPos ) )
{
qtss_printf( "ftruncate at close eof(%li), err(%li), fileno(%li)\n", mEofPos, (SInt32)err, (SInt32)fileno(mTrackerFile) );
}
(void)::fclose( mTrackerFile );
}
}
static bool SaveElement( PLDoubleLinkedListNode<TrackingElement>* ten, void* userData)
{
FILE* fp = (FILE*) userData;
char buff[512];
/*
used by ForEachUntil to find a SaveElement each element to the tracking file.
userData is a pointer to the FILE of our open tracking file.
*/
qtss_sprintf( buff, "%li \"%s\"\n", (SInt32)ten->fElement->mPID, ten->fElement->mName );
// linux version of fputs returns <0 for err, or num bytes written
// mac os X version of fputs returns <0 for err, or 0 for no err
if (::fputs( buff, fp ) < 0 )
return true;
return false;
}
int BCasterTracker::Save()
{
/*
save each record in the the tracker to disk.
return 0 on success, < 0 otherwise.
*/
int error = -1;
mEofPos = 0;
if ( mTrackerFile != NULL )
{
if ( !::fseek( mTrackerFile, 0, SEEK_SET ) )
{
if ( !mTrackingList.ForEachUntil( SaveElement, mTrackerFile ) )
{
mEofPos = ::ftell( mTrackerFile );
error = 0;
}
}
}
return error;
}
bool BCasterTracker::IsOpen()
{
// return false if the file is not open,
// true if the file is open.
if ( mTrackerFile == NULL )
return false;
else
return true;
}
BCasterTracker::BCasterTracker( const char* name )
{
mEofPos = 0;
mTrackerFile = NULL;
time_t calendarTime = 0;
calendarTime = ::time(NULL) + 10;
// wait a SInt32 time for access to the file.
// 2 possible loops one to try to open ( and possible create ) the file
// the second to obtain an exclusive lock on the file.
// the app should probably fail if this cannot be done within the alloted time
//qtss_printf("time=%"_S32BITARG_"\n",calendarTime);
while ( mTrackerFile == NULL && calendarTime > ::time(NULL) )
{ mTrackerFile = ::fopen( name, "r+" );
if ( !mTrackerFile )
{ // try and create
mTrackerFile = ::fopen( name, "a+" );
if ( mTrackerFile )
{
// let "everyone" read and write this file so that we can track
// all the broadcasters no matter which user starts them
(void)::chmod( name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
(void)::fclose( mTrackerFile );
}
mTrackerFile = NULL;
}
::sleep(1);
}
::strcpy(gTrackerFileTempDataPath,name);
::strcat( gTrackerFileTempDataPath, "_tmp" );
FILE * tempFile = NULL;
calendarTime = ::time(NULL) + 10;
while ( tempFile == NULL && calendarTime > ::time(NULL) )
{ tempFile = ::fopen( gTrackerFileTempDataPath, "r+" );
if ( !tempFile )
{ // try and create
tempFile = ::fopen( gTrackerFileTempDataPath, "a+" );
if ( tempFile )
{
// let "everyone" read and write this file so that we can track
// all the broadcasters no matter which user starts them
(void)::chmod( gTrackerFileTempDataPath, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
}
}
}
if (tempFile)
(void)::fclose( tempFile );
if ( mTrackerFile )
{
bool haveLock = false;
while ( !haveLock && calendarTime > ::time(NULL) )
{
struct flock lock_params;
lock_params.l_start = 0; /* starting offset */
lock_params.l_len = 0; /* len = 0 means until end of file */
lock_params.l_pid = getpid(); /* lock owner */
lock_params.l_type = F_WRLCK; /* lock type: read/write, etc. */
lock_params.l_whence = 0; /* type of l_start */
if ( !::fcntl( fileno(mTrackerFile), F_SETLK, &lock_params ) )
haveLock = true;
}
// if can't lock it, close it.
if ( !haveLock )
{ (void)::fclose( mTrackerFile );
mTrackerFile = NULL;
}
}
if ( mTrackerFile )
{
SInt32 lineBuffSize = kTrackerLineBuffSize;
SInt32 wordBuffSize = kTrackerLineBuffSize;
char lineBuff[kTrackerLineBuffSize];
char wordBuff[kTrackerLineBuffSize];
char *next;
UInt32 pid;
int error = 0;
error = ::fseek( mTrackerFile, 0, SEEK_SET );
Assert(error == 0);
do
{
// get a line ( fgets adds \n+ 0x00 )
if ( ::fgets( lineBuff, lineBuffSize, mTrackerFile ) == NULL )
break;
// trim the leading whitespace
next = ::TrimLeft( lineBuff );
if (*next)
{
// grab the pid
next = ::GetWord( wordBuff, next, wordBuffSize );
Assert( *wordBuff );
pid = ::atoi( wordBuff );
if (*next)
next = ::TrimLeft( next );
// grab the broadcast list string
if (*next)
{
next = ::TrimLeft( next );
if (*next == '"' )
next = ::GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = ::GetWord( wordBuff, next, wordBuffSize );
if ( this->IsProcessRunning( pid ) )
{
if (*wordBuff)
{ error = this->Add( pid, wordBuff );
}
}
}
}
} while ( feof( mTrackerFile ) == 0 && error == 0 );
mEofPos = ::ftell( mTrackerFile );
}
// dtor closes file...
}

View file

@ -0,0 +1,61 @@
/*
*
* @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@
*
*/
#ifndef __BCASTERTRACKER__
#define __BCASTERTRACKER__
#include <stdio.h>
#include "TrackingElement.h"
#include "PLDoubleLinkedList.h"
class BCasterTracker
{
public:
BCasterTracker( const char* fName );
virtual ~BCasterTracker();
int RemoveByProcessID( pid_t pid );
int Remove( UInt32 itemID );
int Add( pid_t pid, const char* bcastList );
int Save();
void Show();
static bool IsProcessRunning( pid_t pid );
bool IsOpen();
protected:
enum { kTrackerLineBuffSize = 512 };
FILE* mTrackerFile;
SInt32 mEofPos;
PLDoubleLinkedList<TrackingElement> mTrackingList;
};
void TestBCasterTracker(int x);
#endif

View file

@ -0,0 +1,302 @@
/*
*
* @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@
*
*/
#ifndef kVersionString
#include "../revision.h"
#endif
#include "BroadcastLog.h"
static Bool16 sLogTimeInGMT = false;
static char* sLogHeader = "#Software: %s\n"
"#Version: %s\n" //%s == version
"#Date: %s\n" //%s == date/time
"#Remark: All date values are in %s.\n" //%s == "GMT" or "local time"
"#Fields: date time filepath title copyright comment author artist album duration result\n";
BroadcastLog::BroadcastLog( PLBroadcastDef* broadcastParms, StrPtrLen* defaultPathPtr )
: QTSSRollingLog()
{
*mDirPath = 0;
*mLogFileName = 0;
mWantsLogging = false;
if (broadcastParms->mLogging)
{
if (!::strcmp( broadcastParms->mLogging, "enabled" ) )
{
mWantsLogging = true;
::strcpy( mDirPath, broadcastParms->mLogFile );
char* nameBegins = ::strrchr( mDirPath, kPathDelimiterChar );
if ( nameBegins )
{
*nameBegins = 0; // terminate mDirPath at the last PathDelimeter
nameBegins++;
::strcpy( mLogFileName, nameBegins );
}
else
{ // it was just a file name, no dir spec'd
memcpy(mDirPath,defaultPathPtr->Ptr,defaultPathPtr->Len);
mDirPath[defaultPathPtr->Len] = 0;
::strcpy( mLogFileName, broadcastParms->mLogFile );
}
}
}
this->SetLoggingEnabled(mWantsLogging);
}
time_t BroadcastLog::WriteLogHeader(FILE *inFile)
{
// Write a W3C compatable log header
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
if (-1 == calendarTime)
return -1;
struct tm timeResult;
struct tm* theLocalTime = qtss_localtime(&calendarTime, &timeResult);
Assert(NULL != theLocalTime);
if (NULL == theLocalTime)
return -1;
char tempBuffer[1024] = { 0 };
qtss_strftime(tempBuffer, sizeof(tempBuffer), "#Log File Created On: %m/%d/%Y %H:%M:%S\n", theLocalTime);
this->WriteToLog(tempBuffer, !kAllowLogToRoll);
tempBuffer[0] = '\0';
// format a date for the startup time
char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes] = { 0 };
Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
if (result)
{
qtss_sprintf(tempBuffer, sLogHeader, "PlaylistBroadcaster" , kVersionString,
theDateBuffer, sLogTimeInGMT ? "GMT" : "local time");
this->WriteToLog(tempBuffer, !kAllowLogToRoll);
}
return calendarTime;
}
void BroadcastLog::LogInfo( const char* infoStr )
{
// log a generic comment
char strBuff[1024] = "# ";
char dateBuff[80] = "";
if ( this->FormatDate( dateBuff, false ) )
{
if ( (NULL != infoStr)
&& ( ( strlen(infoStr) + strlen(strBuff) + strlen(dateBuff) ) < 800)
)
{
qtss_sprintf(strBuff,"#Remark: %s %s\n",dateBuff, infoStr);
this->WriteToLog( strBuff, kAllowLogToRoll );
}
else
{
::strcat(strBuff,dateBuff);
::strcat(strBuff," internal error in LogInfo\n");
this->WriteToLog( strBuff, kAllowLogToRoll );
}
}
}
void BroadcastLog::LogMediaError( const char* path, const char* errStr , const char* messageStr)
{
// log movie play info
char strBuff[1024] = "";
char dateBuff[80] = "";
if ( this->FormatDate( dateBuff, false ) )
{
if ( (NULL != path)
&& ( (strlen(path) + strlen(dateBuff) ) < 800)
)
{
qtss_sprintf(strBuff,"#Remark: %s %s ",dateBuff, path);
if ( errStr )
{ if ( (strlen(strBuff) + strlen(errStr) ) < 1000 )
{
::strcat(strBuff,"Error:");
::strcat(strBuff,errStr);
}
}
else
if ( (NULL != messageStr)
&&
( (strlen(strBuff) + strlen(messageStr) ) < 1000 )
)
{ ::strcat(strBuff,messageStr);
}
else
::strcat(strBuff,"OK");
::strcat(strBuff,"\n");
this->WriteToLog(strBuff, kAllowLogToRoll );
}
else
{
::strcat(strBuff,dateBuff);
::strcat(strBuff," internal error in LogMediaError\n");
this->WriteToLog( strBuff, kAllowLogToRoll );
}
}
}
void BroadcastLog::LogMediaData( const char* path, const char* title, const char* copyright,
const char* comment, const char* author, const char* artist,
const char* album, UInt32 duration, SInt16 result)
{
// log movie play info
char strBuff[1024] = "";
char dateBuff[80] = "";
if ( this->FormatDate( dateBuff, false ) )
{
if ( (NULL != path)
&& ( (strlen(path) + strlen(dateBuff) ) < 800)
)
{
qtss_sprintf(strBuff,"%s '%s'",dateBuff, path);
if ( title || title[0] != 0)
{ if ( (strlen(strBuff) + strlen(title) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, title);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( copyright || copyright[0] != 0)
{ if ( (strlen(strBuff) + strlen(copyright) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, copyright);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( comment || comment[0] != 0)
{ if ( (strlen(strBuff) + strlen(comment) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, comment);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( author || author[0] != 0)
{ if ( (strlen(strBuff) + strlen(author) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, author);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( artist || artist[0] != 0)
{ if ( (strlen(strBuff) + strlen(artist) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, artist);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( album || album[0] != 0)
{ if ( (strlen(strBuff) + strlen(album) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, album);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
// add the duration in seconds
qtss_sprintf(dateBuff, " %"_S32BITARG_" ", duration);
::strcat(strBuff,dateBuff);
// add the result code
qtss_sprintf(dateBuff, " %d\n", result);
::strcat(strBuff,dateBuff);
this->WriteToLog(strBuff, kAllowLogToRoll );
}
else
{
::strcat(strBuff,dateBuff);
::strcat(strBuff," internal error in LogMediaData\n");
this->WriteToLog( strBuff, kAllowLogToRoll );
}
}
}

View file

@ -0,0 +1,90 @@
#ifndef __BroadcastLog__
#define __BroadcastLog__
/*
*
* @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@
*
*/
#include "QTSSRollingLog.h"
#include "PLBroadcastDef.h"
#include "StrPtrLen.h"
#include <string.h>
class BroadcastLog : public QTSSRollingLog
{
enum { eLogMaxBytes = 0, eLogMaxDays = 0 };
public:
BroadcastLog( PLBroadcastDef* broadcastParms, StrPtrLen* defaultPathPtr);
virtual ~BroadcastLog() {}
virtual char* GetLogName()
{ // RTSPRollingLog wants to see a "new'd" copy of the file name
char* name = new char[strlen( mLogFileName ) + 1 ];
if ( name )
::strcpy( name, mLogFileName );
return name;
}
virtual char* GetLogDir()
{ // RTSPRollingLog wants to see a "new'd" copy of the file name
char *name = new char[strlen( mDirPath ) + 1 ];
if ( name )
::strcpy( name, mDirPath );
return name;
}
virtual UInt32 GetRollIntervalInDays() { return eLogMaxDays; /* we dont' roll*/ }
virtual UInt32 GetMaxLogBytes() { return eLogMaxBytes; /* we dont' roll*/ }
void LogInfo( const char* infoStr );
void LogMediaError( const char* path, const char* errStr, const char* messageStr);
void LogMediaData( const char* path, const char* title, const char* copyright,
const char* comment, const char* author, const char* artist,
const char* album, UInt32 duration, SInt16 result);
bool WantsLogging() { return mWantsLogging; }
const char* LogFileName() { return mLogFileName; }
const char* LogDirName() { return mDirPath; }
virtual time_t WriteLogHeader(FILE *inFile);
protected:
char mDirPath[256];
char mLogFileName[256];
bool mWantsLogging;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,288 @@
/*
*
* @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: BroadcasterSession.h
*/
#ifndef __BROADCASTER_SESSION__
#define __BROADCASTER_SESSION__
#include "Task.h"
#include "TimeoutTask.h"
#include "RTSPClient.h"
#include "ClientSocket.h"
#include "SDPSourceInfo.h"
#include "UDPSocket.h"
#include "StrPtrLen.h"
#include "OSMutex.h"
class BroadcasterSession : public Task
{
public:
enum
{
kRTSPUDPBroadcasterType = 0,
kRTSPTCPBroadcasterType = 1,
kRTSPHTTPBroadcasterType = 2,
kRTSPHTTPDropPostBroadcasterType = 3,
kRTSPReliableUDPBroadcasterType = 4
};
typedef UInt32 BroadcasterType;
BroadcasterSession( UInt32 inAddr, UInt16 inPort, char* inURL,
BroadcasterType inBroadcasterType,
UInt32 inDurationInSec, UInt32 inStartPlayTimeInSec,
UInt32 inRTCPIntervalInSec, UInt32 inOptionsIntervalInSec,
UInt32 inHTTPCookie, Bool16 inAppendJunkData, UInt32 inReadInterval,
UInt32 inSockRcvBufSize,
StrPtrLen *sdpSPLPtr,
char *namePtr,
char *passwordPtr,
Bool16 deepDebug,
Bool16 burst);
virtual ~BroadcasterSession();
//
// Signals.
//
// Send a kKillEvent to delete this object.
// Send a kTeardownEvent to tell the object to send a TEARDOWN and abort
enum
{
kTeardownEvent = 0x00000100
};
virtual SInt64 Run();
//
// States. Find out what the object is currently doing
enum
{
kSendingAnnounce = 0,
kSendingSetup = 1,
kSendingReceive = 2,
kBroadcasting = 3,
kSendingTeardown = 4,
kDone = 5
};
//
// Why did this session die?
enum
{
kDiedNormally = 0, // Session went fine
kTeardownFailed = 1, // Teardown failed, but session stats are all valid
kRequestFailed = 2, // Session couldn't be setup because the server returned an error
kBadSDP = 3, // Server sent back some bad SDP
kSessionTimedout = 4, // Server not responding
kConnectionFailed = 5, // Couldn't connect at all.
kDiedWhileBroadcasting = 6, // Connection was forceably closed while Broadcasting the movie
kMemoryError = 7
};
//
// Once this client session is completely done with the TEARDOWN and ready to be
// destructed, this will return true. Until it returns true, this object should not
// be deleted. When it does return true, this object should be deleted.
Bool16 IsDone() { return fState == kDone; }
//
// ACCESSORS
RTSPClient* GetBroadcaster() { return fRTSPClient; }
ClientSocket* GetSocket() { return fSocket; }
SDPSourceInfo* GetSDPInfo() { return &fSDPParser; }
UInt32 GetState() { return fState; }
UInt32 GetDeathState() { return fDeathState; }
// When this object is in the kDone state, this will tell you why the session died.
UInt32 GetReasonForDying() { return fDeathReason; }
UInt32 GetRequestStatus() { return fRTSPClient->GetStatus(); }
// Tells you the total time we were receiving packets. You can use this
// for computing bit rate
SInt64 GetTotalPlayTimeInMsec() { return fTotalPlayTime; }
QTSS_RTPPayloadType GetTrackType(UInt32 inTrackIndex)
{ return fSDPParser.GetStreamInfo(inTrackIndex)->fPayloadType; }
UInt32 GetNumPacketsReceived(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumPacketsReceived; }
UInt32 GetNumBytesReceived(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumBytesReceived; }
UInt32 GetNumPacketsLost(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumLostPackets; }
UInt32 GetNumPacketsOutOfOrder(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumOutOfOrderPackets; }
UInt32 GetNumDuplicates(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumDuplicates; }
UInt32 GetNumAcks(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumAcks; }
UInt32 GetNumStreams()
{ return fSDPParser.GetNumStreams();}
UInt32 GetStreamDestPort(UInt32 inIndex)
{ return fStats[inIndex].fDestRTPPort;}
void TearDownNow() {fTeardownImmediately = true; this->Signal(Task::kKillEvent);}
//
// Global stats
static UInt32 GetActiveConnections() { return sActiveConnections; }
static UInt32 GetBroadcastingConnections() { return sBroadcastingConnections; }
static UInt32 GetConnectionAttempts() { return sTotalConnectionAttempts; }
char* GetNextPacket(UInt32 *packetLen, UInt8 *channel);
OS_Error SendPacket(char* data, UInt32 len,UInt8 channel);
OS_Error SendWaitingPackets();
enum
{
kUDPTransportType = 0,
kReliableUDPTransportType = 1,
kTCPTransportType = 2
};
typedef UInt32 TransportType;
TransportType GetTransportType() { return fTransportType; }
UInt32 GetPacketQLen() { return fPacketQueue.GetLength(); }
OSMutex* GetMutex() { return &fMutex; }
private:
enum
{
kRawRTSPControlType = 0,
kRTSPHTTPControlType = 1,
kRTSPHTTPDropPostControlType= 2
};
typedef UInt32 ControlType;
ClientSocket* fSocket; // Connection object
RTSPClient* fRTSPClient; // Manages the client connection
SDPSourceInfo fSDPParser; // Parses the SDP in the DESCRIBE response
TimeoutTask fTimeoutTask; // Kills this connection in the event the server isn't responding
ControlType fControlType;
TransportType fTransportType;
UInt32 fDurationInSec;
UInt32 fStartPlayTimeInSec;
UInt32 fRTCPIntervalInSec;
UInt32 fOptionsIntervalInSec;
UInt32 fState; // For managing the state machine
UInt32 fDeathState; // state at time of death
UInt32 fDeathReason;
UInt32 fNumSetups;
UDPSocket** fUDPSocketArray;
SInt64 fPlayTime;
SInt64 fTotalPlayTime;
SInt64 fLastRTCPTime;
Bool16 fTeardownImmediately;
Bool16 fAppendJunk;
UInt32 fReadInterval;
UInt32 fSockRcvBufSize;
Bool16 fBurst;
UInt32 fBurstTime;
//
// Broadcaster stats
struct TrackStats
{
enum
{
kSeqNumMapSize = 100,
kHalfSeqNumMap = 50
};
UInt16 fDestRTPPort;
UInt16 fDestRTCPPort;
UInt32 fNumPacketsReceived;
UInt32 fNumBytesReceived;
UInt32 fNumLostPackets;
UInt32 fNumOutOfOrderPackets;
UInt32 fNumThrownAwayPackets;
UInt8 fSequenceNumberMap[kSeqNumMapSize];
UInt16 fWrapSeqNum;
UInt16 fLastSeqNum;
UInt32 fSSRC;
Bool16 fIsSSRCValid;
UInt16 fHighestSeqNum;
UInt16 fLastAckedSeqNum;
Bool16 fHighestSeqNumValid;
UInt32 fNumAcks;
UInt32 fNumDuplicates;
};
TrackStats* fStats;
static char* fPacket;
//
// Global stats
static UInt32 sActiveConnections;
static UInt32 sBroadcastingConnections;
static UInt32 sTotalConnectionAttempts;
//
// Helper functions for Run()
void SetupUDPSockets();
void ProcessMediaPacket(char* inPacket, UInt32 inLength, UInt32 inTrackID, Bool16 isRTCP);
OS_Error ReadMediaData();
void SendReceiverReport();
void AckPackets(UInt32 inTrackIndex, UInt16 inCurSeqNum, Bool16 inCurSeqNumValid);
OSMutex fMutex;//this data structure is shared!
struct RTPPacket
{
RTPPacket() : fQueueElem(NULL), fData(NULL), fLen(0), fChannel(0),fCount(0){}
~RTPPacket() { fData = NULL; fLen = 0; fChannel = 0; }
void SetEnclosingObject(void *obj) {fQueueElem.SetEnclosingObject(obj);}
void SetPacketData(char* data, UInt32 len,UInt8 channel) { fData = data; fLen = len; fChannel = channel; }
OSQueueElem *GetQElement() {return &fQueueElem;}
OSQueueElem fQueueElem;
char* fData;
UInt32 fLen;
UInt8 fChannel;
UInt64 fCount;
};
UInt64 fPacketCount;
OSQueue fPacketQueue;
UInt32 fPacketLen;
UInt8 fChannel;
// char* fPacket;
};
#endif //__BROADCASTER_SESSION__

View file

@ -0,0 +1,165 @@
/*
*
* @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@
*
*/
#include "GetLocalIPAddressString.h"
#ifdef __MACOS__
#include "BogusDefs.h"
#else
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <unistd.h>
#include <string.h>
#if __solaris__ || __sgi__
#include <sys/sockio.h>
#include <stropts.h>
#endif
short GetLocalIPAddressString(char *returnStr, short maxSize)
{
short result = 0;
int err = -1;
char defaultAddress[] = "255.255.255.255";
char* addr = defaultAddress;
do
{
//Most of this code is similar to the SIOCGIFCONF code presented in Stevens,
//Unix Network Programming, section 16.6
//Use the SIOCGIFCONF ioctl call to iterate through the network interfaces
static const UInt32 kMaxAddrBufferSize = 2048;
char* ifReqIter = NULL;
struct ifconf ifc;
struct ifreq* ifr;
char buffer[kMaxAddrBufferSize];
int tempSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (tempSocket == -1) break;
ifc.ifc_len = kMaxAddrBufferSize;
ifc.ifc_buf = buffer;
#if (__linux__ || __MacOSX__ || __MACOS__ || __linuxppc__ || __solaris__ || __sgi__)
err = ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
#elif __FreeBSD__
err = ioctl(tempSocket, OSIOCGIFCONF, (char*)&ifc);
#else
#error
#endif
if (err == -1) break;
#if __FreeBSD__
{
int netdev1, netdev2;
struct ifreq *netdevifr;
netdevifr = ifc.ifc_req;
netdev1 = ifc.ifc_len / sizeof(struct ifreq);
for (netdev2=netdev1-1; netdev2>=0; netdev2--)
{
if (ioctl(tempSocket, SIOCGIFADDR, &netdevifr[netdev2]) != 0)
continue;
}
}
#endif
close(tempSocket);
tempSocket = -1;
// int numIPAddrs = 0;
for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
{
ifr = (struct ifreq*)ifReqIter;
#if __MacOSX__
ifReqIter += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
if (ifr->ifr_addr.sa_len == 0)
{
switch (ifr->ifr_addr.sa_family)
{
case AF_INET:
ifReqIter += sizeof(struct sockaddr_in);
break;
default:
ifReqIter += sizeof(struct sockaddr);
}
}
#else
ifReqIter += sizeof(ifr->ifr_name) + 0;
switch (ifr->ifr_addr.sa_family)
{
case AF_INET:
ifReqIter += sizeof(struct sockaddr_in);
break;
default:
ifReqIter += sizeof(struct sockaddr);
}
#endif
//Only count interfaces in the AF_INET family.
//And don't count localhost, loopback interfaces
if ((ifr->ifr_addr.sa_family == AF_INET) && (strncmp(ifr->ifr_name, "lo", 2) != 0))
{
struct sockaddr_in* addrPtr = (struct sockaddr_in*)&ifr->ifr_addr;
addr = inet_ntoa(addrPtr->sin_addr);
//qtss_printf("found local address: %s\n", addr);
err = 0;
break;
}
}
} while (0);
result = strlen(addr);
if (maxSize < result)
{ err = -1;
}
else
strcpy(returnStr, addr);
return err;
}

View file

@ -0,0 +1,44 @@
#ifndef __getlocalipaddressstring__
#define __getlocalipaddressstring__
/*
*
* @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@
*
*/
#ifdef __cplusplus
extern "C" {
#endif
short GetLocalIPAddressString(char *returnStr, short maxSize);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,118 @@
/*
*
* @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@
*
*/
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include "NoRepeat.h"
NoRepeat::NoRepeat ( UInt32 numNoRepeats )
: PLDoubleLinkedList<SimplePlayListElement>()
{
mMaxElements = numNoRepeats;
}
NoRepeat::~NoRepeat()
{
// we have nothing to do, just let the PLDoubleLinkedList clear itself
}
bool NoRepeat::CompareNameToElement( PLDoubleLinkedListNode<SimplePlayListElement>* node, void* name )
{
if ( !::strcmp( node->fElement->mElementName, (const char*)name ) )
return true;
return false;
}
bool NoRepeat::IsInList( char* name )
{
PLDoubleLinkedListNode<SimplePlayListElement>* whichElement;
whichElement = ForEachUntil( CompareNameToElement, (void*)name );
if ( whichElement )
return true;
return false;
}
PLDoubleLinkedListNode<SimplePlayListElement>* NoRepeat::AddToList( PLDoubleLinkedListNode<SimplePlayListElement>* node )
{
AddNode(node);
PLDoubleLinkedListNode<SimplePlayListElement>* oldTail = NULL;
if ( fNumNodes > mMaxElements )
{ oldTail = fTail;
this->RemoveNode( fTail );
}
return oldTail;
}
bool NoRepeat::AddToList( char* name )
{
Assert( false );
bool addedSuccesfully = false;
if ( !this->IsInList( name ) )
{
SimplePlayListElement* element;
PLDoubleLinkedListNode<SimplePlayListElement>* node = NULL;
element = new SimplePlayListElement(name);
Assert( element );
if ( element )
node = new PLDoubleLinkedListNode<SimplePlayListElement>(element);
Assert( node );
if ( node )
{
PLDoubleLinkedListNode<SimplePlayListElement>* deadNode;
deadNode = this->AddToList(node);
delete deadNode;
addedSuccesfully = true;
}
}
return addedSuccesfully;
}

View file

@ -0,0 +1,52 @@
#ifndef __no_repeat__
#define __no_repeat__
/*
*
* @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@
*
*/
#include "PLDoubleLinkedList.h"
#include "SimplePlayListElement.h"
#include "OSHeaders.h"
class NoRepeat : public PLDoubleLinkedList<SimplePlayListElement> {
public:
NoRepeat( UInt32 numNoRepeats );
virtual ~NoRepeat();
bool IsInList( char* name ); // return true if name is in list, false if not
bool AddToList( char* name );// return true if could be added to list, no dupes allowd
PLDoubleLinkedListNode<SimplePlayListElement>* AddToList( PLDoubleLinkedListNode<SimplePlayListElement>* node );
protected:
static bool CompareNameToElement( PLDoubleLinkedListNode<SimplePlayListElement>*node, void *name );
UInt32 mMaxElements;
};
#endif

View file

@ -0,0 +1,630 @@
/*
*
* @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@
*
*/
/*
8.2.99 - rt updated ShowSettings() to display user names for fields instead of C++ member names.
*/
#include "PLBroadcastDef.h"
#include "MyAssert.h"
#include "SocketUtils.h"
#include "ConfParser.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#ifndef __Win32__
#include <netdb.h>
#endif
#include "BroadcasterSession.h"
Bool16 PLBroadcastDef::ConfigSetter( const char* paramName, const char* paramValue[], void* userData )
{
// return true if set fails
PLBroadcastDef* broadcastParms = (PLBroadcastDef*)userData;
if (!::strcmp( "destination_ip_address", paramName) )
{
broadcastParms->SetValue( &broadcastParms->mOrigDestAddress, paramValue[0] );
if (broadcastParms->mIgnoreFileIP)
return false;
else
return broadcastParms->SetValue( &broadcastParms->mDestAddress, paramValue[0] );
}
else if (!::strcmp( "destination_base_port", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mBasePort, paramValue[0] );
}
else if (!::strcmp( "max_upcoming_list_size", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mMaxUpcomingMovieListSize, paramValue[0] );
}
else if (!::strcmp( "play_mode", paramName) )
{
if ( ::strcmp( "sequential", paramValue[0])
&& ::strcmp( "sequential_looped", paramValue[0])
&& ::strcmp( "weighted_random", paramValue[0])
)
return true;
return broadcastParms->SetValue( &broadcastParms->mPlayMode, paramValue[0] );
}
/*
rt- rremoved for buld 12
else if (!::strcmp( "limit_play", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mLimitPlay, paramValue[0] );
}
*/
// changed at bulid 12 else if (!::strcmp( "repeats_queue_size", paramName) )
else if (!::strcmp( "recent_movies_list_size", paramName) )
{
if ( ::atoi( paramValue[0] ) < 0 )
return true;
broadcastParms->mLimitPlayQueueLength = atoi(paramValue[0]);
return false;
}
else if (!::strcmp( "playlist_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mPlayListFile, paramValue[0] );
}
else if (!::strcmp( "sdp_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mSDPFile, paramValue[0] );
}
else if (!::strcmp( "destination_sdp_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mDestSDPFile, paramValue[0] );
}
else if (!::strcmp( "logging", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mLogging, paramValue[0] );
}
else if (!::strcmp( "log_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mLogFile, paramValue[0] );
}
else if (!::strcmp( "sdp_reference_movie", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mSDPReferenceMovie, paramValue[0] );
}
else if (!::strcmp( "show_current", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mShowCurrent, paramValue[0] );
}
else if (!::strcmp( "show_upcoming", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mShowUpcoming, paramValue[0] );
}
else if (!::strcmp( "broadcast_start_time", paramName) )
{
const char* theValue = paramValue[0];
if ('*' == theValue[0])
{
UInt32 startTime = time(NULL) + 2208988800LU + (time_t) ::strtol(&theValue[1], NULL, 10);
char startTimeStr[20] = "";
qtss_sprintf(startTimeStr,"%"_U32BITARG_"", startTime); // current time
return broadcastParms->SetValue( &broadcastParms->mStartTime, startTimeStr );
}
return broadcastParms->SetValue( &broadcastParms->mStartTime, paramValue[0] );
}
else if (!::strcmp( "broadcast_end_time", paramName) )
{
UInt32 endTime = 0;
const char* theValue = paramValue[0];
if ('*' == theValue[0])
endTime = time(NULL) + 2208988800LU + (SInt32) ::strtol(&theValue[1], NULL, 10);
else
endTime = ::strtoul(theValue, NULL, 10);
if ( (endTime > 0) && endTime < 2208988800LU) // not a valid time
return true;
char endTimeStr[20] = "";
qtss_sprintf(endTimeStr,"%"_U32BITARG_"", endTime); // current time + offset time
return broadcastParms->SetValue( &broadcastParms->mEndTime, endTimeStr );
}
else if (!::strcmp( "broadcast_SDP_is_dynamic", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mIsDynamic, paramValue[0] );
}
else if (!::strcmp( "broadcaster_name", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mName, paramValue[0] );
}
else if (!::strcmp( "broadcaster_password", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mPassword, paramValue[0] );
}
else if (!::strcmp( "multicast_ttl", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mTTL, paramValue[0] );
}
else if (!::strcmp( "rtsp_port", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mRTSPPort, paramValue[0] );
}
else if (!::strcmp( "pid_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mPIDFile, paramValue[0] );
}
else if (!::strcmp( "client_buffer_delay", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mClientBufferDelay, paramValue[0] );
}
else if (!::strcmp( "max_err_file_k_size", paramName) )
{
if ( !paramValue[0] || !strlen(paramValue[0]) )
return true;
UInt32 setvalue = kSInt32_Max;
int maxValue = ::atoi( paramValue[0] );
if (maxValue >= 0)
setvalue = (UInt32) maxValue;
qtss_setmaxprintfcharsinK( (UInt32) setvalue);
return false;
}
return true;
}
Bool16 PLBroadcastDef::SetValue( char** dest, const char* value)
{
Bool16 didFail = false;
// if same param occurs more than once in file, delete
// initial occurance and override with second.
if ( *dest )
delete [] *dest;
*dest = new char[ strlen(value) + 1 ];
Assert( *dest );
if ( *dest )
::strcpy( *dest, value );
else
didFail = true;
return didFail;
}
Bool16 PLBroadcastDef::SetDefaults( const char* setupFileName )
{
Bool16 didFail = false;
if (mDestAddress != NULL)
mIgnoreFileIP = true;
if ( !didFail && !mIgnoreFileIP)
didFail = this->SetValue( &mDestAddress, SocketUtils::GetIPAddrStr(0)->Ptr );
if ( !didFail )
didFail = this->SetValue( &mBasePort, "5004" );
if ( !didFail )
didFail = this->SetValue( &mPlayMode, "sequential_looped" );
if ( !didFail )
didFail = this->SetValue( &mMaxUpcomingMovieListSize, "7" );
if ( !didFail )
didFail = this->SetValue( &mLogging, "enabled" );
if ( !didFail )
didFail = this->SetValue( &mRTSPPort, "554" );
char nameBuff[kBufferLen];
int maxNameLen = kMaxBufferStringLen; //maxNameLen = 492
nameBuff[ sizeof(nameBuff) -1] = 0; //term buffer
::strncpy( nameBuff, "broadcast" , maxNameLen);
if (setupFileName)
::strncpy( nameBuff, setupFileName , maxNameLen);
nameBuff[maxNameLen] = '\0'; //zero term the name
int baseLen = ::strlen(nameBuff); //maxNameLen max
//add .log to the base name of the description file with the .ext stripped
char *ext = NULL;
ext = ::strrchr( nameBuff, '.' );
if ( ext )
{
*ext = 0;
baseLen = ::strlen(nameBuff);
}
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".log",sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mLogFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".ply" ,sizeof(nameBuff) - strlen(nameBuff) - 1);
if ( !didFail )
didFail = this->SetValue( &mPlayListFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".sdp" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mSDPFile, nameBuff );
if ( !didFail )
didFail = this->SetValue( &mDestSDPFile, "no_name" );
/* current, upcoming, and replacelist created by emil@popwire.com */
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".current" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mCurrentFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".upcoming" ,sizeof(nameBuff) - strlen(nameBuff) - 1);
if ( !didFail )
didFail = this->SetValue( &mUpcomingFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".replacelist" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mReplaceFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".stoplist" ,sizeof(nameBuff) - strlen(nameBuff) - 1);
if ( !didFail )
didFail = this->SetValue( &mStopFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".insertlist" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mInsertFile, nameBuff );
if ( !didFail )
didFail = this->SetValue( &mShowCurrent, "enabled" );
if ( !didFail )
didFail = this->SetValue( &mShowUpcoming, "enabled" );
if ( !didFail )
didFail = this->SetValue( &mStartTime, "0" );
if ( !didFail )
didFail = this->SetValue( &mEndTime, "0" );
if ( !didFail )
didFail = this->SetValue( &mIsDynamic, "disabled" );
if ( !didFail )
didFail = this->SetValue( &mName, "" );
if ( !didFail )
didFail = this->SetValue( &mPassword, "" );
if ( !didFail )
didFail = this->SetValue( &mTTL, "1" );
if ( !didFail )
didFail = this->SetValue( &mClientBufferDelay, "0" );
//see if there is a defaults File.
//if there is one load it and over-ride the other defaults
if (NULL != setupFileName)
{
int len = ::strlen(setupFileName) + 10;
char *defaultFileName = new char[len];
qtss_snprintf(defaultFileName, len, "%s%s", setupFileName, ".def");
(void) ::ParseConfigFile( false, defaultFileName, ConfigSetter, this ); //ignore if no defaults file
delete [] defaultFileName;
}
/* ***************************************************** */
return didFail;
}
PLBroadcastDef::PLBroadcastDef( const char* setupFileName, char *destinationIP, Bool16 debug )
: mDestAddress(destinationIP)
, mOrigDestAddress(NULL)
, mBasePort(NULL)
, mPlayMode(NULL)
// removed at build 12 , mLimitPlay(NULL)
, mLimitPlayQueueLength(0)
, mPlayListFile(NULL)
, mSDPFile(NULL)
, mLogging(NULL)
, mLogFile(NULL)
, mSDPReferenceMovie( NULL )
, mCurrentFile( NULL )
, mUpcomingFile( NULL )
, mReplaceFile( NULL )
, mStopFile( NULL )
, mInsertFile( NULL )
, mShowCurrent( NULL )
, mShowUpcoming( NULL )
, mTheSession( NULL )
, mIgnoreFileIP(false)
, mMaxUpcomingMovieListSize(NULL)
, mDestSDPFile(NULL)
, mStartTime(NULL)
, mEndTime(NULL)
, mIsDynamic(NULL)
, mName( NULL)
, mPassword( NULL)
, mTTL(NULL)
, mRTSPPort(NULL)
, mPIDFile(NULL)
, mClientBufferDelay(NULL)
, mParamsAreValid(false)
, mInvalidParamFlags(kInvalidNone)
{
if (!setupFileName && !destinationIP)
{ this->SetDefaults( NULL );
qtss_printf( "default settings\n" );
this->ShowSettings();
return;
}
fDebug = debug;
if (destinationIP != NULL) //we were given an IP to use
mIgnoreFileIP = true;
Assert( setupFileName );
if (setupFileName )
{
int err = -1;
if ( !this->SetDefaults( setupFileName ) )
{ err = ::ParseConfigFile( false, setupFileName, ConfigSetter, this );
}
if ( !err )
{ mParamsAreValid = true;
}
ValidateSettings();
}
}
void PLBroadcastDef::ValidateSettings()
{
// For now it just validates the destination ip address
UInt32 inAddr = 0;
inAddr = SocketUtils::ConvertStringToAddr(mDestAddress);
if(inAddr == INADDR_NONE)
{
struct hostent* theHostent = ::gethostbyname(mDestAddress);
if (theHostent != NULL)
{
inAddr = ntohl(*(UInt32*)(theHostent->h_addr_list[0]));
struct in_addr inAddrStruct;
char buffer[50];
StrPtrLen temp(buffer);
inAddrStruct.s_addr = *(UInt32*)(theHostent->h_addr_list[0]);
SocketUtils::ConvertAddrToString(inAddrStruct, &temp);
SetValue( &mDestAddress, buffer );
}
}
if(inAddr == INADDR_NONE)
mInvalidParamFlags |= kInvalidDestAddress;
// If mInvalidParamFlags is set, set mParamsAreValid to false
if ( mInvalidParamFlags | kInvalidNone )
mParamsAreValid = false;
}
void PLBroadcastDef::ShowErrorParams()
{
if( mInvalidParamFlags & kInvalidDestAddress )
qtss_printf( "destination_ip_address \"%s\" is Invalid\n", mOrigDestAddress );
}
void PLBroadcastDef::ShowSettings()
{
qtss_printf( "\n" );
qtss_printf( "Description File Settings\n" );
qtss_printf( "----------------------------\n" );
qtss_printf( "destination_ip_address %s\n", mOrigDestAddress );
qtss_printf( "destination_sdp_file %s\n", mDestSDPFile );
qtss_printf( "destination_base_port %s\n", mBasePort );
qtss_printf( "play_mode %s\n", mPlayMode );
qtss_printf( "recent_movies_list_size %d\n", mLimitPlayQueueLength );
qtss_printf( "playlist_file %s\n", mPlayListFile );
qtss_printf( "logging %s\n", mLogging );
qtss_printf( "log_file %s\n", mLogFile );
if (mSDPReferenceMovie != NULL)
qtss_printf( "sdp_reference_movie %s\n", mSDPReferenceMovie );
qtss_printf( "sdp_file %s\n", mSDPFile );
qtss_printf( "max_upcoming_list_size %s\n", mMaxUpcomingMovieListSize );
qtss_printf( "show_current %s\n", mShowCurrent );
qtss_printf( "show_upcoming %s\n", mShowUpcoming );
qtss_printf( "broadcaster_name \"%s\"\n", mName);
qtss_printf( "broadcaster_password \"XXXXX\"\n");
qtss_printf( "multicast_ttl %s\n",mTTL);
qtss_printf( "rtsp_port %s\n",mRTSPPort);
Float32 bufferDelay = 0.0;
::sscanf(mClientBufferDelay, "%f", &bufferDelay);
if (bufferDelay != 0.0)
qtss_printf( "client_buffer_delay %.2f\n",bufferDelay);
else
qtss_printf( "client_buffer_delay default\n");
if (mPIDFile != NULL)
qtss_printf( "pid_file %s\n",mPIDFile);
qtss_printf( "broadcast_SDP_is_dynamic %s\n", mIsDynamic );
UInt32 startTime = (UInt32) ::strtoul(mStartTime, NULL, 10);
if ( startTime > 2208988800LU)
{
qtss_printf( "broadcast_start_time %s (NTP seconds)\n",mStartTime);
startTime -= 2208988800LU; //1970 - 1900 secs
qtss_printf( "-->broadcast_start_time = %"_U32BITARG_" (unix seconds)\n",startTime);
time_t tmpTime;
tmpTime = (time_t) startTime;
struct tm timeResult;
struct tm *localTM = qtss_localtime(&tmpTime, &timeResult);
char timeBuffer[kTimeStrSize];
char *theTime = qtss_asctime(localTM,timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_start_time = %s (local time)\n",theTime);
tmpTime = (time_t) startTime;
struct tm *gmTM = qtss_gmtime(&tmpTime, &timeResult);
theTime = qtss_asctime(gmTM, timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_start_time = %s (UTC/GM time)\n",theTime);
}
else if (0 == startTime)
qtss_printf( "broadcast_start_time 0 (allow all)\n");
else
qtss_printf( "broadcast_start_time %s (NTPseconds allow all)\n", mStartTime);
UInt32 endTime = strtoul(mEndTime, NULL, 10);
if (endTime > 2208988800LU)
{
qtss_printf( "broadcast_end_time %s (NTP seconds)\n",mEndTime);
endTime -= 2208988800LU;//convert to 1970 secs
qtss_printf( "-->broadcast_end_time = %"_U32BITARG_" (unix seconds)\n",endTime);
time_t tmpTime = (time_t) endTime;
struct tm timeResult;
struct tm *localTM = qtss_localtime(&tmpTime, &timeResult);
char timeBuffer[kTimeStrSize];
char *theTime = qtss_asctime(localTM,timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_end_time = %s (local time)\n",theTime);
tmpTime = (time_t) endTime;
struct tm *gmTM = qtss_gmtime(&tmpTime, &timeResult);
theTime = qtss_asctime(gmTM, timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_end_time = %s (UTC/GM time)\n",theTime);
}
else if (0 == endTime)
qtss_printf( "broadcast_end_time 0 (unbounded)\n");
else
qtss_printf( "broadcast_end_time 1900 + %s seconds (looks invalid)\n", mEndTime);
qtss_printf( "max_err_file_k_size %"_U32BITARG_"\n", qtss_getmaxprintfcharsinK());
qtss_printf( "============================\n" );
}
PLBroadcastDef::~PLBroadcastDef()
{
delete [] mDestAddress;
delete [] mOrigDestAddress;
delete [] mBasePort;
delete [] mPlayMode;
// removed at build 12 delete [] mLimitPlay;
delete [] mPlayListFile;
delete [] mSDPFile;
delete [] mLogging;
delete [] mLogFile;
if (mSDPReferenceMovie != NULL)
delete [] mSDPReferenceMovie;
delete [] mMaxUpcomingMovieListSize;
delete [] mTTL;
delete [] mName;
delete [] mShowUpcoming;
delete [] mShowCurrent;
delete [] mPassword;
delete [] mIsDynamic;
delete [] mStartTime;
delete [] mEndTime;
}

View file

@ -0,0 +1,129 @@
#ifndef __PLBroadcastDef__
#define __PLBroadcastDef__
/*
*
* @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@
*
*/
/*
#example (1) A FULL 1.0 DECLARED FILE
#Lines beginning with "#" characters are comments
#The order of the following entries is unimportant
#Quotes are optional for values
destination_ip_address 225.225.225.225
destination_base_port 5004
play_mode [sequential, sequential_looped, weighted]
limit_play enabled
limit_seq_length 10
play_list_file /path/file
sdp_file /path/file
log_file /path/file
*/
#include "OSHeaders.h"
#include "BroadcasterSession.h"
class PLBroadcastDef {
public:
PLBroadcastDef( const char* setupFileName, char *destinationIP, Bool16 debug );
virtual ~PLBroadcastDef();
Bool16 ParamsAreValid() { return mParamsAreValid; }
void ValidateSettings();
void ShowErrorParams();
void ShowSettings();
static Bool16 ConfigSetter( const char* paramName, const char* paramValue[], void * userData );
// * == default value, <r> required input
char* mDestAddress; // set by PLB to be resolved address
char* mOrigDestAddress; // [0.0.0.0 | domain name?] *127.0.0.1 ( self )
char* mBasePort; // [ 0...32k?] *5004
char* mPlayMode; // [sequential | *sequential_looped | weighted]
// removed at build 12 char* mLimitPlay; // [*enabled | disabled]
int mLimitPlayQueueLength; // [ 0...32k?] *20
//char* mLimitPlayQueueLength; // [ 0...32k?] *20
char* mPlayListFile; // [os file path] *<PLBroadcastDef-name>.ply
char* mSDPFile; // [os file path] <r>
char* mLogging; // [*enabled | disabled]
char* mLogFile; // [os file path] *<PLBroadcastDef-name>.log
char* mSDPReferenceMovie; // [os file path]
char* mCurrentFile; // [os file path] *<PLBroadcastDef-name>.current
char* mUpcomingFile; // [os file path] *<PLBroadcastDef-name>.upcoming
char* mReplaceFile; // [os file path] *<PLBroadcastDef-name>.replacelist
char* mStopFile; // [os file path] *<PLBroadcastDef-name>.stoplist
char* mInsertFile; // [os file path] *<PLBroadcastDef-name>.insertlist
char* mShowCurrent; // [*enabled | disabled]
char* mShowUpcoming; // [*enabled | disabled]
BroadcasterSession *mTheSession;// a broadcaster RTSP/RTP session with the server.
bool mIgnoreFileIP;
char* mMaxUpcomingMovieListSize; // [ 2^31] *7
char* mDestSDPFile; // [movies folder relative file path]
char* mStartTime; // NTP start time
char* mEndTime; // NTP end time
char* mIsDynamic; // true
char* mName; // Authentication name
char* mPassword; // Authentication password
char * mTTL; // TTL for multicast [1..15] *1
char * mRTSPPort;
char * mPIDFile;
char * mClientBufferDelay; // sdp option a=x-bufferdelay: float
enum {
kInvalidNone = 0x00000000,
kInvalidDestAddress = 0x00000001,
kBufferLen = 512,
kExtensionLen = 20,
kMaxBufferStringLen = kBufferLen - kExtensionLen
};
protected:
Bool16 mParamsAreValid;
UInt32 mInvalidParamFlags;
Bool16 SetValue( char** dest, const char* value);
Bool16 SetDefaults( const char* setupFileName );
Bool16 fDebug;
};
#endif

View file

@ -0,0 +1,483 @@
/*
*
* @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@
*
*/
#include "PickerFromFile.h"
#include <stdlib.h>
#include "GetWord.h"
#include "Trim.h"
#include "MyAssert.h"
#include <sys/stat.h>
#ifndef __Win32__
#include <dirent.h>
#endif
#ifdef __hpux__
#include <sys/types.h>
#endif
#define kMaxPickerPath 512
#include <stdio.h>
static bool CompareNameToElement( PLDoubleLinkedListNode<LoopDetectionListElement>* node, void* name );
static void DisplayPickerErr( int pickErr, const char *message, const char*fname, int lineCount, const char*lineBuff );
static bool CompareNameToElement( PLDoubleLinkedListNode<LoopDetectionListElement>* node, void* name )
{
if ( !::strcmp( node->fElement->mPathName, (const char*)name ) )
return true;
return false;
}
static bool IsDir(char* path);
static bool IsDir(char* path)
{
struct stat data;
int err = stat(path, &data);
if (err == -1)
return false;
return ((data.st_mode & S_IFDIR) == S_IFDIR );
}
static void DisplayPickerErr( int pickErr, const char *message, const char*fname, int lineCount, const char*lineBuff )
{
char *errMessage;
qtss_printf( "- %s:\n", message );
if ( lineCount )
qtss_printf( " Playlist: %s, line# %i\n", fname, lineCount );
else
qtss_printf( " Playlist: %s\n", fname );
if ( lineBuff )
qtss_printf( " Playlist text: %s", lineBuff ); // lineBuff already includes a \n
switch ( pickErr )
{
case kPickerPopulateLoopDetected:
errMessage = "Include would create a loop.\n";
break;
case kPickerPopulateBadFormat:
errMessage = "Playlist file is missing *PLAY-LIST* identifier.\n";
break;
case kPickerPopulateFileError:
errMessage = "Playlist file could not be opened.\n";
break;
case kPickerPopulateNoMem:
default:
errMessage = "Internal error occurred.\n";
break;
}
qtss_printf( " Reason: %s\n", errMessage);
}
bool PathIsAbsolute(char *pathPtr)
{
bool result = false;
#ifdef __Win32__
if ( (pathPtr[1] == ':') && ( pathPtr[2] == kPathDelimiterChar ) )
result = true;
#else
if ( *pathPtr == kPathDelimiterChar )
result = true;
#endif
return result;
}
int PopulatePickerFromFile( PlaylistPicker* picker, char* fname, const char* basePath, LoopDetectionList *ldList )
{
Assert( picker );
Assert( fname );
FILE* weightings = NULL;
LoopDetectionListElement* ldElement = NULL;
LoopDetectionNode* ldNode = NULL;
int lineCount = 0;
int pickErr = kPickerPopulateNoErr;
char path[kMaxPickerPath];
#if kPartialPathBeginsWithDelimiter
if (PathIsAbsolute(fname))
{
if ( *basePath )
fname++;
#else
if ( !PathIsAbsolute(fname) )
{
#endif
// it's a partial path, expand it to include all
// previously traversed paths
::strncpy( path, basePath, kMaxPickerPath-1 );
::strncat( path, fname, kMaxPickerPath-1 );
}
else
{
// it's an absolute reference. use the path
// part of this for the new basePath
::strncpy( path, fname, kMaxPickerPath-1 );
}
// path is now either an absolute or working directory
// referenced partial path to the playlist file.
int len = strlen(path);
char lastChar = path[len-1];
if (lastChar == '\n' || lastChar == '\r' || lastChar == ' ')
path[len-1] = '\0';
// ldList is passed as NULL by the initial caller. recursive calls
// pass along the ldList we create hre
if ( ldList == NULL )
ldList = new LoopDetectionList;
Assert( ldList );
if ( !ldList )
pickErr = kPickerPopulateNoMem;
if ( !pickErr )
{
if ( ldList->ForEachUntil( CompareNameToElement, path ) )
{
// we're already in the include chain, this is a loop
// print a warning (error?) and continue past the loop.
//qtss_printf("- Playlists include loop at file: %s\n", path );
pickErr = kPickerPopulateLoopDetected;
}
}
if ( !pickErr )
{
ldElement = new LoopDetectionListElement( path );
Assert( ldElement );
if ( ldElement )
{ ldNode = new LoopDetectionNode( ldElement );
Assert( ldNode );
if ( !ldNode )
pickErr = kPickerPopulateNoMem;
}
else
pickErr = kPickerPopulateNoMem;
}
if (::IsDir(path))
return ::PopulatePickerFromDir(picker, path);
if ( !pickErr )
{
weightings = ::fopen( path, "r" );
if (!weightings)
{
qtss_printf("- Playlist picker failed opening list file %s\n", path);
pickErr = kPickerPopulateFileError;
}
}
if ( !pickErr )
{
SInt32 lineBuffSize = (kMaxPickerPath *2) - 1;
SInt32 wordBuffSize = kMaxPickerPath - 1;
char lineBuff[kMaxPickerPath * 2];
char wordBuff[kMaxPickerPath];
char* next;
char* pathEnd;
char* thisLine;
// add ourselves to the list
ldList->AddNode( ldNode );
// trim off the file name to get just the path part
pathEnd = ::strrchr( path, kPathDelimiterChar );
if ( pathEnd )
{
pathEnd++;
*pathEnd = 0;
}
else
*path = 0;
thisLine = lineBuff;
if ( ::fgets( lineBuff, lineBuffSize, weightings ) != NULL )
{
lineCount++;
thisLine = ::TrimLeft( lineBuff );
if ( 0 != ::strncmp(thisLine,"*PLAY-LIST*",11) )
{
//qtss_printf("- Playlist file missing *PLAY-LIST* identifier as first line:\n");
//qtss_printf(" %s%s\n", basePath, fname);
pickErr = kPickerPopulateBadFormat;
}
}
if ( !pickErr )
{
do
{
next = lineBuff;
if ( ::fgets( lineBuff, lineBuffSize, weightings ) == NULL )
break;
// qtss_printf("line = %s\n", lineBuff);
lineCount++;
next = ::TrimLeft( lineBuff );
if ( *next == '#' )
{
// it's a comment - just toss
//if ( *next )
// qtss_printf( "comment: %s" , &lineBuff[1] );
}
else if (*next == '+') // a list
{
next = ::TrimLeft( next+1 ); // skip past + include
if ( *next == '"' ) // get the name from the next part of the buff
next = ::GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = ::GetWord( wordBuff, next, wordBuffSize );
// recusively populate from the include file.
pickErr = PopulatePickerFromFile( picker, wordBuff, path, ldList );
if ( pickErr )
{
DisplayPickerErr( pickErr, "Playlist Include failed", fname, lineCount, lineBuff );
pickErr = kPickerPopulateNoErr;
}
}
else if ( *next )
{
char numBuff[32];
char expandedFileName[kMaxPickerPath];
int weight = 10; // default weight is 10
// get the movie file name
if ( *next == '"' )
next = ::GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = ::GetWord( wordBuff, next, wordBuffSize );
if (*wordBuff)
{
#if kPartialPathBeginsWithDelimiter
if ( PathIsAbsolute(wordBuff) )
{
char *wordStart = wordBuff;
if ( *path )
wordStart++;
// full or partial path to the movie
::strcpy( expandedFileName, path );
::strcat( expandedFileName, wordStart );
}
#else
if ( !PathIsAbsolute(wordBuff) )
{
// it's a partial path..
// cat the path and fname to form the
// full or partial path to the movie
::strcpy( expandedFileName, path );
::strcat( expandedFileName, wordBuff );
}
#endif
else
{ // it's an absolute path..
::strcpy( expandedFileName, wordBuff );
}
// then get the weighting ( if supplied )
next = ::GetWord( numBuff, next, 32 );
if ( *numBuff )
weight = ::atoi(numBuff);
// qtss_printf("expanded file name = %s\n", expandedFileName);
if (::IsDir(expandedFileName))
pickErr = ::PopulatePickerFromDir(picker, expandedFileName, weight);
else if ( !picker->AddToList( expandedFileName, weight ) )
pickErr = kPickerPopulateNoMem;
}
}
} while ( feof( weightings ) == 0 && pickErr == kPickerPopulateNoErr );
}
// remove ourselves from the list
ldList->RemoveNode( ldNode );
}
// only report unreported errors.
if ( ldList && ldList->GetNumNodes() == 0 && pickErr )
::DisplayPickerErr( pickErr, "Playlist error", fname, lineCount, NULL );
if ( ldNode )
delete ldNode; // node deletes element
else if ( ldElement )
delete ldElement;
if ( weightings )
(void)::fclose( weightings );
if ( ldList && ldList->GetNumNodes() == 0 )
{
// all done now!
delete ldList;
ldList = NULL;
}
return pickErr;
}
int PopulatePickerFromDir( PlaylistPicker* picker, char* dirPath, int weight )
{
static char expandedFileName[kMaxPickerPath]; // static so we don't build up the stack frame on recursion
int pickErr = 0;
if (dirPath != NULL)
strcpy(expandedFileName, dirPath);
#ifdef __Win32__
WIN32_FIND_DATA findData;
HANDLE findResultHandle;
Bool16 keepSearching = true;
int len = strlen(expandedFileName);
if (expandedFileName[len - 1] != kPathDelimiterChar)
{
expandedFileName[len] = kPathDelimiterChar;
expandedFileName[len+1] = 0;
len++;
}
strcat(expandedFileName, "*");
findResultHandle = ::FindFirstFile( expandedFileName, &findData);
if ( NULL == findResultHandle || INVALID_HANDLE_VALUE == findResultHandle )
{
//qtss_printf( "FindFirstFile( \"%s\" ): gle = %"_U32BITARG_"\n", searchPath, GetLastError() );
return 0;
}
while ( (pickErr == 0) && keepSearching )
{
expandedFileName[len] = 0; // retruncate name
if (findData.cFileName[0] != '.') // ignore anything beginning with a "."
{
strcat(expandedFileName, findData.cFileName);
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
pickErr = PopulatePickerFromDir(picker, NULL, weight);
else if ( !picker->AddToList( expandedFileName, weight ) )
pickErr = kPickerPopulateNoMem;
}
keepSearching = FindNextFile( findResultHandle, &findData );
}
#else
DIR* dir;
struct dirent* entry;
int len = strlen(expandedFileName);
if (expandedFileName[len - 1] != kPathDelimiterChar)
{
expandedFileName[len] = kPathDelimiterChar;
expandedFileName[len+1] = 0;
len++;
}
dir = opendir(expandedFileName);
if (dir == NULL)
return kPickerPopulateFileError;
do {
entry = readdir(dir);
if (entry == NULL) break;
if (entry->d_name[0] == '.') // ignore anything beginning with a "."
continue;
if (len + strlen(entry->d_name) < kMaxPickerPath)
{
strcat(expandedFileName, entry->d_name);
#if __solaris__ || __sgi__ || __osf__ || __hpux__
if (::IsDir(expandedFileName))
#else
if ((entry->d_type & DT_DIR) != 0)
#endif
pickErr = PopulatePickerFromDir(picker, NULL, weight);
else if ( !picker->AddToList( expandedFileName, weight ) )
pickErr = kPickerPopulateNoMem;
}
expandedFileName[len] = 0; // retruncate name
} while (pickErr == 0);
//close the directory back up
(void)::closedir(dir);
#endif
return pickErr;
}

View file

@ -0,0 +1,77 @@
#ifndef __picker_from_file__
#define __picker_from_file__
/*
*
* @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@
*
*/
#include "PlaylistPicker.h"
#include "PLDoubleLinkedList.h"
#include <string.h>
class LoopDetectionListElement {
public:
LoopDetectionListElement( const char * name )
{
mPathName = new char[ strlen(name) + 1 ];
Assert( mPathName );
if( mPathName )
::strcpy( mPathName, name );
}
virtual ~LoopDetectionListElement()
{
if ( mPathName )
delete [] mPathName;
}
char *mPathName;
};
typedef PLDoubleLinkedList<LoopDetectionListElement> LoopDetectionList;
typedef PLDoubleLinkedListNode<LoopDetectionListElement> LoopDetectionNode;
enum PickerPopulationErrors {
kPickerPopulateLoopDetected = 1000
, kPickerPopulateBadFormat
, kPickerPopulateFileError
, kPickerPopulateNoMem
, kPickerPopulateNoErr = 0
};
int PopulatePickerFromFile( PlaylistPicker* picker, char* fname, const char* basePath, LoopDetectionList *ldList );
int PopulatePickerFromDir( PlaylistPicker* picker, char* dirPath, int weight = 10 );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,430 @@
/*
*
* @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@
*
*/
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <stdio.h>
#include "MyAssert.h"
#include "OS.h"
#include "PlaylistPicker.h"
/*
PlaylistPicker has 3 modes
- sequential looping through the items in the play list(s)
in the order they are entered.
- above w/ looping
- weighted picking "randomly" from weighted buckets
*/
PlaylistPicker::PlaylistPicker( UInt32 numBuckets, UInt32 numNoRepeats )
{
// weighted random ctor
mFirstElement = NULL;
mNumToPickFrom = 0;
mBuckets = numBuckets;
mIsSequentialPicker = false;
mRecentMoviesListSize = numNoRepeats;
/* changed by emil@popwire.com (see relaod.txt for info) */
mRemoveFlag = false;
mStopFlag = false;
/* ***************************************************** */
mLastResult = (UInt32) OS::Milliseconds();
mPickCounts = new SInt32[numBuckets];
UInt32 x;
for ( x = 0; x < mBuckets; x++ )
{ mPickCounts[x] = 0;
mElementLists[x] = new PLDoubleLinkedList<SimplePlayListElement>;
Assert( mElementLists[x] );
}
mUsedElements = new NoRepeat( numNoRepeats );
Assert( mUsedElements );
}
PlaylistPicker::PlaylistPicker(bool doLoop)
{
// sequential ctor
mFirstElement = NULL;
mIsSequentialLooping = doLoop;
mIsSequentialPicker = true;
mWhichSequentialBucket = 0;
mRecentMoviesListSize = 0;
mNumToPickFrom = 0;
mBuckets = 2; // alternating used/remaining pick buckets
/* changed by emil@popwire.com (see relaod.txt for info) */
mRemoveFlag = false;
mStopFlag = false;
fLastPick = NULL;
/* ***************************************************** */
mPickCounts = new SInt32[mBuckets];
UInt32 bucketIndex;
for ( bucketIndex = 0; bucketIndex < mBuckets; bucketIndex++ )
{
mPickCounts[bucketIndex] = 0;
mElementLists[bucketIndex] = new PLDoubleLinkedList<SimplePlayListElement>;
Assert( mElementLists[bucketIndex] );
}
mUsedElements = NULL;
}
PlaylistPicker::~PlaylistPicker()
{
UInt32 bucketIndex;
delete mUsedElements;
for ( bucketIndex = 0; bucketIndex < mBuckets; bucketIndex++ )
{
delete mElementLists[bucketIndex] ;
}
delete [] mPickCounts;
}
UInt32 PlaylistPicker::Random()
{
UInt32 seed = 1664525L * mLastResult + 1013904223L; //1013904223 is prime .. Knuth D.E.
::srand( seed );
UInt32 result = ::rand();
mLastResult = result;
return result;
}
char* PlaylistPicker::PickOne()
{
char* foundName = NULL; // pointer to name of pick we find, caller deletes.
if ( mIsSequentialPicker )
{
if ( mElementLists[mWhichSequentialBucket]->GetNumNodes() == 0 && mIsSequentialLooping )
{ // ran out of items switch to other list.
if ( mWhichSequentialBucket == 0 )
mWhichSequentialBucket = 1;
else
mWhichSequentialBucket = 0;
}
if ( mElementLists[mWhichSequentialBucket]->GetNumNodes() > 0 )
{
PLDoubleLinkedListNode<SimplePlayListElement>* node;
node = mElementLists[mWhichSequentialBucket]->GetFirst();
Assert( node );
int nameLen = ::strlen( node->fElement->mElementName );
foundName = new char[ nameLen +1 ];
Assert( foundName );
if ( foundName )
{
int usedBucketIndex;
::strcpy( foundName, node->fElement->mElementName );
// take him out of the bucket since he's now in play
mElementLists[mWhichSequentialBucket]->RemoveNode( node );
if ( mWhichSequentialBucket == 0 )
usedBucketIndex = 1;
else
usedBucketIndex = 0;
/* changed by emil@popwire.com (see relaod.txt for info) */
if(!mRemoveFlag)
/* ***************************************************** */
mElementLists[usedBucketIndex]->AddNodeToTail( node );
/* changed by emil@popwire.com (see relaod.txt for info) */
else
mNumToPickFrom--;
/* ***************************************************** */
}
}
}
else
{
SInt32 bucketIndex;
UInt32 minimumBucket = 0;
UInt32 avaiableToPick;
UInt32 theOneToPick;
SInt32 topBucket;
// find the highest bucket with some elements.
bucketIndex = this->GetNumBuckets() - 1;
while ( bucketIndex >= 0 && mElementLists[bucketIndex]->GetNumNodes() == 0 )
{
bucketIndex--;
}
// adjust to 1 based so we can use MOD
topBucket = bucketIndex + 1;
//qtss_printf( "topBucket %li \n", topBucket );
if (topBucket > 0)
minimumBucket = this->Random() % topBucket; // find our minimum bucket
//qtss_printf( "minimumBucket %li \n", minimumBucket );
// pick randomly from the movies in this and higher buckets
// sum the available elements, then pick randomly from them.
avaiableToPick = 0;
bucketIndex = minimumBucket;
while ( bucketIndex < topBucket )
{
avaiableToPick += mElementLists[bucketIndex]->GetNumNodes();
bucketIndex++;
}
//qtss_printf( "avaiableToPick %li \n", avaiableToPick );
// was anyone left??
if ( avaiableToPick )
{
theOneToPick = this->Random() % avaiableToPick;
//qtss_printf( "theOneToPick %li \n", theOneToPick );
// now walk through the lists unitl we get to the list
// that contains our pick, then pick that one.
bucketIndex = minimumBucket;
while ( bucketIndex < topBucket && foundName == NULL )
{
//qtss_printf( "theOneToPick %li, index %li numelements %li\n", theOneToPick , bucketIndex, mElementLists[bucketIndex]->GetNumNodes());
if ( theOneToPick >= mElementLists[bucketIndex]->GetNumNodes() )
theOneToPick -= mElementLists[bucketIndex]->GetNumNodes();
else
{ //qtss_printf( "will pick theOneToPick %li, index %li \n", theOneToPick, bucketIndex);
foundName = this->PickFromList( mElementLists[bucketIndex], theOneToPick );
if ( foundName )
mPickCounts[bucketIndex]++;
}
bucketIndex++;
}
// we messed up if we don't have a name at this point.
Assert( foundName );
}
}
fLastPick = foundName;
return foundName;
}
void PlaylistPicker::CleanList()
{
mFirstElement = NULL;
mNumToPickFrom = 0;
delete mUsedElements;
mUsedElements = new NoRepeat( mRecentMoviesListSize );
delete [] mPickCounts;
mPickCounts = new SInt32[mBuckets];
UInt32 x;
for ( x = 0; x < mBuckets; x++ )
{
mPickCounts[x] = 0;
delete mElementLists[x];
mElementLists[x] = new PLDoubleLinkedList<SimplePlayListElement>;
Assert( mElementLists[x] );
}
};
char* PlaylistPicker::PickFromList( PLDoubleLinkedList<SimplePlayListElement>* list, UInt32 elementIndex )
{
PLDoubleLinkedListNode<SimplePlayListElement>* plNode;
char* foundName = NULL;
plNode = list->GetNthNode( elementIndex );
if ( plNode )
{
int nameLen = ::strlen(plNode->fElement->mElementName );
foundName = new char[ nameLen +1 ];
Assert( foundName );
if ( foundName )
{
::strcpy( foundName, plNode->fElement->mElementName );
// take him out of the bucket since he's now in play
list->RemoveNode( plNode );
mNumToPickFrom--;
// add him to our used list, and possibly
// get an older one to put back into play
PLDoubleLinkedListNode<SimplePlayListElement>* recycleNode = mUsedElements->AddToList( plNode );
// if we got an old one to recycle, do so.
if ( recycleNode )
this->AddNode( recycleNode );
}
}
return foundName;
}
bool PlaylistPicker::AddToList( const char* name, int weight )
{
bool addedSuccesfully;
PLDoubleLinkedListNode<SimplePlayListElement>* node;
SimplePlayListElement* element;
node = NULL;
addedSuccesfully = false;
element = new SimplePlayListElement(name);
if (mFirstElement == NULL)
mFirstElement = element->mElementName;
Assert( element );
if ( element )
{ element->mElementWeight = weight;
node = new PLDoubleLinkedListNode<SimplePlayListElement>(element);
Assert( node );
}
if ( node )
addedSuccesfully = AddNode(node);
return addedSuccesfully;
}
bool PlaylistPicker::AddNode( PLDoubleLinkedListNode<SimplePlayListElement>* node )
{
bool addSucceeded = false;
Assert( node );
Assert( node->fElement );
if ( mIsSequentialPicker ) // make picks in sequential order, not weighted random
{
// add all to bucket 0
mElementLists[0]->AddNodeToTail( node );
addSucceeded = true;
mNumToPickFrom++;
}
else
{
int weight;
weight = node->fElement->mElementWeight;
// weights are 1 based, correct to zero based for use as array myIndex
weight--;
Assert( weight >= 0 );
Assert( (UInt32)weight < mBuckets );
if ( (UInt32)weight < mBuckets )
{
// the elements weighting defines the list it is in.
mElementLists[weight]->AddNode( node );
addSucceeded = true;
mNumToPickFrom++;
}
}
return addSucceeded;
}

View file

@ -0,0 +1,86 @@
#ifndef __playlist_picker__
#define __playlist_picker__
/*
*
* @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@
*
*/
#include "PLDoubleLinkedList.h"
#include "SimplePlayListElement.h"
#include "OSHeaders.h"
#include "NoRepeat.h"
class PlaylistPicker
{
public:
enum { kMaxBuckets = 10 };
PlaylistPicker(bool doLoop);
PlaylistPicker( UInt32 numBuckets, UInt32 numNoRepeats );
virtual ~PlaylistPicker();
void CleanList();
bool AddToList( const char *name, int weight );
bool AddNode( PLDoubleLinkedListNode<SimplePlayListElement> *node );
char* PickOne();
char* LastPick() { return fLastPick; }
UInt32 GetNumBuckets() { return mBuckets; }
/* changed by emil@popwire.com (see relaod.txt for info) */
UInt32 GetNumMovies() { return mNumToPickFrom; }
bool mRemoveFlag;
bool mStopFlag;
/* ***************************************************** */
SInt32* mPickCounts;
SInt32 mNumToPickFrom;
UInt32 mRecentMoviesListSize;
char* fLastPick;
PLDoubleLinkedList<SimplePlayListElement>* GetBucket( UInt32 myIndex ) { return mElementLists[myIndex]; }
char* GetFirstFile() { return mFirstElement; }
protected:
bool mIsSequentialPicker; // picker picks sequentially?
bool mIsSequentialLooping; // loop over and over?
int mWhichSequentialBucket; // sequential picker picks from list0 or list1?
UInt32 Random();
UInt32 mLastResult;
char* PickFromList( PLDoubleLinkedList<SimplePlayListElement>* list, UInt32 elementIndex );
PLDoubleLinkedList<SimplePlayListElement>* mElementLists[kMaxBuckets];
UInt32 mBuckets;
NoRepeat *mUsedElements;
char* mFirstElement;
};
#endif

View file

@ -0,0 +1,60 @@
/*
*
* @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@
*
*/
#ifndef __SimplePlayListElement__
#define __SimplePlayListElement__
#include <string.h>
#include "MyAssert.h"
class SimplePlayListElement {
public:
SimplePlayListElement( const char * name )
{
mElementName = new char[ strlen(name) + 1 ];
Assert( mElementName );
if( mElementName )
strcpy( mElementName, name );
mElementWeight = -1;
mWasPlayed = false;
}
virtual ~SimplePlayListElement()
{
if ( mElementName )
delete [] mElementName;
}
int mElementWeight;
bool mWasPlayed;
char *mElementName;
};
#endif

View file

@ -0,0 +1,56 @@
/*
*
* @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@
*
*/
#ifndef __StSmartArrayPointer__
#define __StSmartArrayPointer__
template <class T>
class StSmartArrayPointer
{
public:
StSmartArrayPointer(T* victim) : fT(victim) {}
~StSmartArrayPointer() { delete [] fT; }
void SetObject(T* victim)
{
//can't use a normal assert here because "Assert.h" eventually includes this file....
#ifdef ASSERT
//char s[65];
if (fT != NULL) qtss_printf ("_Assert: StSmartArrayPointer::SetObject() %s, %d\n", __FILE__, __LINE__);
#endif
fT = victim;
}
T* GetObject() { return fT; }
operator T*() { return fT; }
private:
T* fT;
};
typedef StSmartArrayPointer<char> OSCharArrayDeleter;
#endif

View file

@ -0,0 +1,59 @@
/*
*
* @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@
*
*/
#ifndef __tracking_element__
#define __tracking_element__
#include <unistd.h>
#include <string.h>
#include "OSHeaders.h"
#include "MyAssert.h"
class TrackingElement {
public:
TrackingElement( pid_t pid, const char * name )
{
mName = new char[ strlen(name) + 1 ];
Assert( mName );
if( mName )
strcpy( mName, name );
mPID = pid;
}
virtual ~TrackingElement()
{
if ( mName )
delete [] mName;
}
char *mName;
pid_t mPID;
};
#endif

View file

@ -0,0 +1,209 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @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@
*/
#if 0
todo
v12 --
- changed PlayListBroadcaster to PlaylistBroadcaster
- don't strip ext from Descr filename before adding .log in a default file name.
- play_list_file becomes playlist_file
- repeats_queue_size becomes recent_movies_list_size
- limit_play is not used anymore
v11--
- changed a bunch of error messages
- fixed: In my broadcast description file, I left off any keyword after "logging"
and both the preflight and the regular run of the file caused a Bus error.
- added descriptive messages about setup file errors.
- changed name from /tmp/trackerfile to /tmp/broadcastlist
- chdir to location of Setup file ( means that paths in Setup file are
relative to locaation of setup file, not PlayListBroadcaster
v10
-- writes message that SDP file was generated in debug or preflight? 2365986
-- fixed pathname display bug for log file name errors. ... "the.log", or else "./the.log", or else
the full path should have been displayed...
-- added "PlayListBroadcaster preflight finished.\n" at end of prefilght ( already logged ).
-- err desc is logged, not err #
Error:#
as in these samples
# 1999-08-04 13:36:25 PlayListBroadcaster started
1999-08-04 13:44:53 /Beamer/projects/Servers/TimeShare/PlayListBroadcaster/pl_files/lists/3movie3.mov Error:12
1999-08-04 13:44:55 /Beamer/projects/Servers/TimeShare/PlaylistBroadcaster/pl_files/lists/test1.mov OK
# 1999-08-04 14:57:49 PlaylistBroadcaster finished
to
Error:"errstring"
where "errstring" is one of the following:
Movie file not found
Movie file has no hinted tracks
Movie file does not match SDP
Movie file is invalid
Movie file name is missing or too long
8.6.99 build 9
- PLB logs preflights, # movie problems
- cleaned up code in PlayListBroadcaster.cpp
- only complains about lack of tracker and logfile access when necessary
- "Setup File Name".los is the default logfile name
- changed display occurances of PlaylistBroadcaster to PlayListBroadcaster
- report permission to stop denied error, not just "not running"
8.5.99 build 8
- chanegd track match error to warning and reworded
- added check for tracker access.
- added Lock to log file
- fixed problems when running in background ( loss of tracking and logging )
8.4.99 build 7
- added Error message "- PlayListBroadcaster: Error, unsupported Play Mode (%s)\n"
- uses Setup supplied logfile name, doed not append .log 2364223
- added error messages about not being able to open the log file
- added error messages about not being able to open the Broadcast setup file.
- added playError messages to log file:
# 1999-08-04 13:36:25 PlayListBroadcaster started
1999-08-04 13:44:53 /Beamer/projects/Servers/TimeShare/PlayListBroadcaster/pl_files/lists/3movie3.mov Error:12
1999-08-04 13:44:55 /Beamer/projects/Servers/TimeShare/PlaylistBroadcaster/pl_files/lists/test1.mov OK
# 1999-08-04 14:57:49 PlaylistBroadcaster finished
- will not ignore ^C's when there is an initial problem with the tracker file.
8.2.99 -- build 6
- gen error messages from broadcaster
- changed to all verbose options
- removed -c option, just list file the name at end of command.
- destination ip now defaults to machine's primary address
- changed BCasterTracker::BCasterTracker to 5 second open timer.
- changed reference to "channel setup" to "PlaylistBroadcaster Description"
- changed &d's in qtss_printf's to %d in Broadcaster error messages
- only print errors when walking the play list
- only show Setup options in Preflight mode
- changed display of setup options to show user names, not C++ names.
- the -list option no longer lists broadcasts that are not running. file is
cleaned up on next "stop"
- multiple options per command line are now supported, exits on first error.
- command line options uses "getopt"'s long form that allows -fullword options
and partial ( down to one char ) options as long as they are unambiguous.
8.3.99
- fixed include loops
- better error reporting from building the picklist
- chmod's the "trackerfile" to 666 so that all users can run broadcasts
and track them.
- Shows permission error if that is the reason a "stop" fails.
- fixes problems with fully qualified paths in both Playlist and "play_list_file"
Setup file option
7.30.99 - build 5
- Movie file and SDP parsing now includes "user" error reporting ( not using Assert ).
So the program should continue past recoverable errors and stop only on non recoverable
errors.
- Playlists no longer require weights, non - weighted files in a random playlist
default to a weight of 10.
- + symbol introduces an "included" play list
- play list files MUST have "*PLAY-LIST*" as the first line ( exactly ).
Else they will be treated as an invalid play list file.
- new "-prefilght" option displays Setup, SDP, and walks the movie list to check
files for correctness.
- removed debug options from command line options.
7.27.99 - build 4
- removed license from about display
- updated credit names
- fixed mapping of --stop to 's' from 'l'
- added -a (about) to help
- builds from libQTRTPFile.a
- added ppc only instructions to make.preamble
- uses a well known place to keep the tracker file, was kept is same dir
as PlaylistBroadcaster ( now uses /tmp/ )
- better error message on "stop" with bad parameters.
- removed Assert on playlist "includes"
- added default destination adddress ( 127.0.0.1 "localhost" )
- changed "weighted" mode parameter to "weighted_random" as per docs
- changes picking algorithm to provide better weighting
- fixes the "count5.mov" crash
- fixes the "can't play more than 8 movies without losing audio" bug
7.26.99 -- build 3 Notes and Errata
not documented: uses "sdp_reference_movie" option (mSDPReferenceMovie) to bulid SDP file.
Add this option to the config file. It's a required field.
Use the -g file.config option to cause PlaylistBroadcaster to parse and display the
settings in a config file.
SDP generation displays the raw SDP of the reference file, not the generated
file.
If you set the config "limit_seq_length" to a value greater than the number of
movies available for play in random mode, the movies will play once and the
broadcast will stop.
The executable is incorrectly named BroadcastPlaylist, instead of PlaylistBroacaster.
The installer read me references v1.0.1, not v1.0.2.
The broadcast will lose audio after 7 or 8 movies play. You can restore audio
by pausing the client and then restarting.
#endif

View file

@ -0,0 +1,70 @@
/*
*
* @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@
*
*/
// $Id: playlist_QTRTPBroadcastFile.cpp,v 1.1 2006/01/05 13:20:36 murata Exp $
//
// QTRTPBroadcastFile:
// An interface to QTFile for TimeShare.
// -------------------------------------
// Includes
//
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
//#include "OSMutex.h"
//#include "QTFile.h"
//#include "QTTrack.h"
//#include "QTHintTrack.h"
#include "playlist_QTRTPBroadcastFile.h"
bool QTRTPBroadcastFile::FindTrackSSRC( UInt32 SSRC)
{
// General vars
RTPTrackListEntry *ListEntry;
//
// Find the specified track.
for( ListEntry = fFirstTrack; ListEntry != NULL; ListEntry = ListEntry->NextTrack )
{
// Check for matches.
if( ListEntry->SSRC == SSRC )
{ return true;
}
}
// The search failed.
return false;
}

View file

@ -0,0 +1,56 @@
/*
*
* @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@
*
*/
// $Id: playlist_QTRTPBroadcastFile.h,v 1.1 2006/01/05 13:20:36 murata Exp $
//
// QTRTPFile:
// An interface to QTFile for TimeShare.
#ifndef QTRTPBroadcastFile_H
#define QTRTPBroadcastFile_H
//
// Includes
#include "OSHeaders.h"
#include "QTRTPFile.h"
#ifndef __Win32__
#include <sys/stat.h>
#endif
class QTRTPBroadcastFile : public QTRTPFile {
public:
bool FindTrackSSRC( UInt32 SSRC);
};
#endif // QTRTPBroadcastFile

View file

@ -0,0 +1,450 @@
/*
*
* @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@
*
*/
#include "playlist_utils.h"
#include "playlist_SDPGen.h"
#include "playlist_broadcaster.h"
#include "QTRTPFile.h"
#include "OS.h"
#include "SocketUtils.h"
#include "SDPUtils.h"
#include "OSArrayObjectDeleter.h"
short SDPGen::AddToBuff(char *aSDPFile, short currentFilePos, char *chars)
{
short charLen = strlen(chars);
short newPos = currentFilePos + charLen;
if (newPos <= eMaxSDPFileSize)
{ memcpy(&aSDPFile[currentFilePos],chars,charLen); // only the chars not the \0
aSDPFile[currentFilePos +charLen] = '\0';
}
else
{ newPos = (-newPos);
}
currentFilePos = newPos;
return currentFilePos;
}
UInt32 SDPGen::RandomTime(void)
{
SInt64 curTime = 0;
curTime = PlayListUtils::Milliseconds();
curTime += rand() ;
return (UInt32) curTime;
}
short SDPGen::GetNoExtensionFileName(char *pathName, char *result, short maxResult)
{
char *start;
char *end;
char *sdpPath = pathName;
short pathNameLen = strlen(pathName);
short copyLen = 0;
do
{
start = strrchr(sdpPath, ePath_Separator);
if(start == NULL ) // no path separator
{ start = sdpPath;
copyLen = pathNameLen;
break;
}
start ++; // move start to one past the separator
end = strrchr(sdpPath, eExtension_Separator);
if (end == NULL) // no extension
{ copyLen = strlen(start) + 1;
break;
}
// both path separator and an extension
short startLen = strlen(start);
short endLen = strlen(end);
copyLen = startLen - endLen;
} while (false);
if (copyLen > maxResult)
copyLen = maxResult;
memcpy(result, start, copyLen);
result[copyLen] = '\0';
return copyLen;
}
char *SDPGen::Process( char *sdpFileName,
char * basePort,
char *ipAddress,
char *anSDPBuffer,
char *startTime,
char *endTime,
char *isDynamic,
char *ttl,
int *error
)
{
char *resultBuf = NULL;
short currentPos = 0;
short trackID = 1;
*error = -1;
do
{
fSDPFileContentsBuf = new char[eMaxSDPFileSize];
// SDP required RFC 2327
// v= (protocol version)
// o=<username> <session id = random time> <version = random time *> <network type = IN> <address type = IP4> <local address>
// s= (session name)
// c=IN IP4 (destinatin ip address)
// * see RFC for recommended Network Time Stamp (NTP implementation not required)
// v= (protocol version)
{ char version[] = "v=0\r\n";
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, version);
if (currentPos < 0) break;
}
// o=<username> <session id = random time> <version = random time *> <network type = IN> <address type = IP4> <address>
{ char *userName = "QTSS_Play_List";
UInt32 sessIDAsRandomTime = RandomTime();
UInt32 versAsRandomTime = RandomTime();
char ownerLine[255];
Assert(SocketUtils::GetIPAddrStr(0) != NULL);
Assert(SocketUtils::GetIPAddrStr(0)->Ptr != NULL);
qtss_sprintf(ownerLine, "o=%s %"_U32BITARG_" %"_U32BITARG_" IN IP4 %s\r\n",userName ,sessIDAsRandomTime,versAsRandomTime,SocketUtils::GetIPAddrStr(0)->Ptr);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, ownerLine);
if (currentPos < 0) break;
}
// s= (session name)
{ enum { eMaxSessionName = 64};
char newSessionName[eMaxSessionName];
short nameSize = 0;
char sessionLine[255];
nameSize = GetNoExtensionFileName(sdpFileName, newSessionName, eMaxSessionName);
if (nameSize < 0) break;
qtss_sprintf(sessionLine, "s=%s\r\n", newSessionName);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, sessionLine);
if (currentPos < 0) break;
}
// c=IN IP4 (destinatin ip address)
{
char sdpLine[255];
if (SocketUtils::IsMulticastIPAddr(ntohl(inet_addr(ipAddress))))
qtss_sprintf(sdpLine, "c=IN IP4 %s/%s\r\n", ipAddress,ttl);
else
qtss_sprintf(sdpLine, "c=IN IP4 %s\r\n", ipAddress);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, sdpLine);
if (currentPos < 0) break;
}
{
char controlLine[255];
if ( 0 == ::strcmp( "enabled", isDynamic) )
qtss_sprintf(controlLine, "a=x-broadcastcontrol:RTSP\r\n");
else
qtss_sprintf(controlLine, "a=x-broadcastcontrol:TIME\r\n");
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, controlLine);
if (currentPos < 0) break;
}
{
char timeLine[255];
UInt32 startTimeNTPSecs = strtoul(startTime, NULL, 10);
UInt32 endTimeNTPSecs = strtoul(endTime, NULL, 10);
qtss_sprintf(timeLine, "t=%"_U32BITARG_" %"_U32BITARG_"\r\n", startTimeNTPSecs, endTimeNTPSecs);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, timeLine);
if (currentPos < 0) break;
}
{
SimpleString resultString;
SimpleString sdpBuffString(anSDPBuffer);
short numLines = 0;
char *found = NULL;
enum {eMaxLineLen = 1024};
char aLine[eMaxLineLen +1];
::memset(aLine, 0, sizeof(aLine));
int portCount = atoi(basePort);
SimpleParser sdpParser;
while ( sdpParser.GetLine(&sdpBuffString,&resultString) )
{
numLines ++;
if (resultString.fLen > eMaxLineLen) continue;
memcpy(aLine,resultString.fTheString,resultString.fLen);
aLine[resultString.fLen] = '\0';
int newBuffSize = sdpBuffString.fLen - (resultString.fLen);
char *newBuffPtr = &resultString.fTheString[resultString.fLen];
sdpBuffString.SetString(newBuffPtr, newBuffSize);
char firstChar = aLine[0];
{ // we are setting these so ignore any defined
if (firstChar == 'v') continue;// (protocol version)
if (firstChar == 'o') continue; //(owner/creator and session identifier).
if (firstChar == 's') continue; //(session name)
if (firstChar == 'c') continue; //(connection information - optional if included at session-level)
}
{ // no longer important as a play list broadcast
// there may be others that should go here.......
if (firstChar == 't') continue;// (time the session is active)
if (firstChar == 'r') continue;// (zero or more repeat times)
// found = strstr(aLine, "a=cliprect"); // turn this off
// if (found != NULL) continue;
found = strstr(aLine, "a=control:trackID"); // turn this off
if (!fKeepTracks)
{
if (fAddIndexTracks)
{
if (found != NULL)
{ char mediaLine[eMaxLineLen];
qtss_sprintf(mediaLine,"a=control:trackID=%d\r\n",trackID);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, mediaLine); // copy rest of line starting with the transport protocol
trackID ++;
}
}
if (found != NULL) continue;
}
found = strstr(aLine, "a=range"); // turn this off
if (found != NULL) continue;
// found = strstr(aLine, "a=x"); // turn this off -
// if (found != NULL) continue;
}
{ // handle the media line and put in the port value past the media type
found = strstr(aLine,"m="); //(media name and transport address)
if (found != NULL)
{
char *startToPortVal = strtok(aLine," ");
strtok(NULL," "); // step past the current port value we put it in below
if (found != NULL)
{ char mediaLine[eMaxLineLen];
char *protocol = strtok(NULL,"\r\n"); // the transport protocol
qtss_sprintf(mediaLine,"%s %d %s\r\n",startToPortVal,portCount,protocol);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, mediaLine); // copy rest of line starting with the transport protocol
if (portCount != 0)
portCount += 2; // set the next port value ( this port + 1 is the RTCP port for this port so we skip by 2)
continue;
}
}
}
{ // this line looks ok so just get it and make sure it has a carriage return + new line at the end
// also remove any garbage that might be there
// this is a defensive measure because the hinter may have bad line endings like a single \n or \r or
// there might also be chars after the last line delimeter and before a \0 so we get rid of it.
short lineLen = strlen(aLine);
// get rid of trailing characters
while (lineLen > 0 && (NULL == strchr("\r\n",aLine[lineLen])) )
{ aLine[lineLen] = '\0';
lineLen --;
}
// get rid of any line feeds and carriage returns
while (lineLen > 0 && (NULL != strchr("\r\n",aLine[lineLen])) )
{ aLine[lineLen] = '\0';
lineLen --;
}
aLine[lineLen + 1] = '\r';
aLine[lineLen + 2] = '\n';
aLine[lineLen + 3] = 0;
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, aLine); // copy this line
}
}
// buffer delay
if (fClientBufferDelay > 0.0)
{
char delayLine[255];
qtss_sprintf(delayLine, "a=x-bufferdelay:%.2f\r\n", fClientBufferDelay);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, delayLine);
if (currentPos < 0) break;
}
}
StrPtrLen theSDPStr(fSDPFileContentsBuf);
SDPContainer rawSDPContainer;
if (!rawSDPContainer.SetSDPBuffer( &theSDPStr ))
{ delete [] fSDPFileContentsBuf;
fSDPFileContentsBuf = NULL;
return NULL;
}
SDPLineSorter sortedSDP(&rawSDPContainer);
resultBuf = sortedSDP.GetSortedSDPCopy(); // return a new copy of the sorted SDP
delete [] fSDPFileContentsBuf; // this has to happen after GetSortedSDPCopy
fSDPFileContentsBuf = resultBuf;
*error = 0;
} while (false);
return resultBuf;
}
int SDPGen::Run( char *movieFilename
, char *sdpFilename
, char *basePort
, char *ipAddress
, char *buff
, short buffSize
, bool overWriteSDP
, bool forceNewSDP
, char *startTime
, char *endTime
, char *isDynamic
, char *ttl
)
{
int result = -1;
int fdsdp = -1;
bool sdpExists = false;
do
{
if (!movieFilename) break;
if (!sdpFilename) break;
if (buff && buffSize > 0) // set buff to 0 length string
buff[0] = 0;
fdsdp = open(sdpFilename, O_RDONLY, 0);
if (fdsdp != -1)
sdpExists = true;
if (sdpExists && !forceNewSDP)
{
if (!overWriteSDP)
{
if (buff && (buffSize > 0))
{ int count = ::read(fdsdp,buff, buffSize -1);
if (count > 0)
buff[count] = 0;
}
}
close(fdsdp);
fdsdp = -1;
if (!overWriteSDP)
{ result = 0;
break; // leave nothing to do
}
}
QTRTPFile::ErrorCode err = fRTPFile.Initialize(movieFilename);
result = QTFileBroadcaster::EvalErrorCode(err);
if( result != QTRTPFile::errNoError )
break;
// Get the file
int sdpFileLength=0;
int processedSize=0;
char *theSDPText = fRTPFile.GetSDPFile(&sdpFileLength);
if( theSDPText == NULL || sdpFileLength <= 0)
{ break;
}
char *processedSDP = NULL;
processedSDP = Process(sdpFilename, basePort, ipAddress, theSDPText,startTime,endTime,isDynamic, ttl, &result);
if (result != 0) break;
processedSize = strlen(processedSDP);
if (buff != NULL)
{ if (buffSize > processedSize )
{
buffSize = processedSize;
}
memcpy(buff,processedSDP,buffSize);
buff[buffSize] = 0;
}
if (!overWriteSDP && sdpExists)
{
break;
}
// Create our SDP file and write out the data
#ifdef __Win32__
fdsdp = open(sdpFilename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0664);
#else
fdsdp = open(sdpFilename, O_CREAT | O_TRUNC | O_WRONLY, 0664);
#endif
if( fdsdp == -1 )
{
//result = -1;
result = -2;
break;
}
write(fdsdp, processedSDP, processedSize);
result = 0;
// report that we made a file
fSDPFileCreated = true;
} while (false);
if (fdsdp != -1)
{ result = 0;
close(fdsdp);
fdsdp = -1;
}
return result;
}

View file

@ -0,0 +1,106 @@
/*
*
* @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@
*
*/
// SimpleParse:
#ifndef SDPGen_H
#define SDPGen_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <fcntl.h>
#include <string.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <net/if.h>
#endif
#include "playlist_SimpleParse.h"
#include "QTRTPFile.h"
class SDPGen
{
enum {eMaxSDPFileSize = 10240};
enum {ePath_Separator = '/', eExtension_Separator = '.'};
private:
char *fSDPFileContentsBuf;
protected:
QTRTPFile fRTPFile;
bool fKeepTracks;
bool fAddIndexTracks;
short AddToBuff(char *aSDPFile, short currentFilePos, char *chars);
UInt32 RandomTime(void);
short GetNoExtensionFileName(char *pathName, char *result, short maxResult);
char *Process( char *sdpFileName,
char * basePort,
char *ipAddress,
char *anSDPBuffer,
char *startTime,
char *endTime,
char *isDynamic,
char *ttl,
int *error
);
public:
SDPGen() : fSDPFileContentsBuf(NULL), fKeepTracks(false),fAddIndexTracks(false), fSDPFileCreated(false),fClientBufferDelay(0.0) { QTRTPFile::Initialize(); };
~SDPGen() { if (fSDPFileContentsBuf) delete fSDPFileContentsBuf; };
void KeepSDPTracks(bool enabled) { fKeepTracks = enabled;} ;
void AddIndexTracks(bool enabled) { fAddIndexTracks = enabled;} ;
void SetClientBufferDelay(Float32 bufferDelay) { fClientBufferDelay = bufferDelay;} ;
int Run( char *movieFilename
, char *sdpFilename
, char *basePort
, char *ipAddress
, char *buff
, short buffSize
, bool overWriteSDP
, bool forceNewSDP
, char *startTime
, char *endTime
, char *isDynamic
, char *ttl
);
bool fSDPFileCreated;
Float32 fClientBufferDelay;
};
#endif

View file

@ -0,0 +1,357 @@
/*
*
* @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@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include "playlist_SimpleParse.h"
SimpleString::SimpleString(char *theString)
{
fTheString = theString;
if (theString == NULL)
fLen = 0;
else
fLen = strlen(theString);
}
void SimpleString::Init()
{
fTheString = NULL;
fLen = 0;
}
void SimpleString::SetString(char *theString, SInt32 len)
{
fTheString = theString;
fLen = len;
}
SInt32 SimpleString::GetString(char *theString, SInt32 len)
{
SInt32 copyLen = fLen + 1;
if (len < copyLen ) copyLen = len;
if (copyLen > 0)
{ memcpy(theString,fTheString,copyLen);
theString[copyLen -1] = 0;
}
return copyLen;
}
SInt32 SimpleString::GetInt()
{
SInt32 result = 0;
if (fTheString == NULL|| fLen == 0 || fLen > 32)
return result;
char* buff = new char[fLen +1];
memcpy (buff, fTheString,fLen);
buff[fLen] = 0;
result = strtol(buff, NULL, 0);
delete [] buff;
return result;
}
void SimpleString::Print()
{
char* buff = new char[fLen +1];
memcpy (buff, fTheString,fLen);
buff[fLen] = 0;
printf("SimpleString( len=%"_S32BITARG_" str=>%s< )\n",fLen,buff);
delete [] buff;
}
char SimpleParser::sWordDelimeters[] = "=:/\t \r\n";
char SimpleParser::sLineDelimeters[] = "\r\n";
bool SimpleParser::Compare(SimpleString *str1Ptr, SimpleString *str2Ptr, bool caseSensitive)
{
bool result = false;
do
{
if (NULL == str1Ptr) break;
if (NULL == str2Ptr) break;
if (NULL == str1Ptr->fTheString) break;
if (NULL == str2Ptr->fTheString) break;
if (str1Ptr->fLen != str2Ptr->fLen)
break;
int test = 0;
if (caseSensitive)
test = strncmp(str1Ptr->fTheString, str2Ptr->fTheString,str1Ptr->fLen);
else
#if __Win32__
test = _strnicmp(str1Ptr->fTheString, str2Ptr->fTheString,str1Ptr->fLen);
#else
test = strncasecmp(str1Ptr->fTheString, str2Ptr->fTheString,str1Ptr->fLen);
#endif
if (test != 0) break;
result = true;
} while (false);
return result;
}
bool SimpleParser::FindString( SimpleString *sourcePtr, SimpleString *findPtr, SimpleString *resultStringPtr)
{
bool result = false;
do
{
if (NULL == sourcePtr) break;
if (NULL == findPtr) break;
if (NULL == sourcePtr->fTheString) break;
if (NULL == findPtr->fTheString) break;
if (findPtr->fLen > sourcePtr->fLen)
break;
char *start = strstr(sourcePtr->fTheString, findPtr->fTheString);
if (start == NULL) break;
if (NULL != resultStringPtr)
{
SInt32 len = (PointerSizedInt) start - (PointerSizedInt) sourcePtr->fTheString;
if (len > sourcePtr->fLen) break;
resultStringPtr->SetString(start, findPtr->fLen);
}
result = true;
} while (false);
return result;
}
bool SimpleParser::FindNextString( SimpleString *sourcePtr, SimpleString *currentPtr, SimpleString *findPtr, SimpleString *resultStringPtr)
{
bool result = false;
SInt32 length = 0;
do
{
if (NULL == sourcePtr) break;
if (NULL == currentPtr) break;
if (NULL == findPtr) break;
if (NULL == sourcePtr->fTheString) break;
if (NULL == currentPtr->fTheString) break;
SimpleString tempSource(NULL);
length = currentPtr->fTheString - sourcePtr->fTheString;
if (length < 0) break;
if (length > sourcePtr->fLen) break;
length = sourcePtr->fLen - (length + currentPtr->fLen); // the remaining length to search
tempSource.SetString(&currentPtr->fTheString[currentPtr->fLen], length); // step past the end of current with remaining length
result = FindString(&tempSource, findPtr, resultStringPtr);
} while (false);
return result;
}
bool SimpleParser::GetString( SimpleString *sourcePtr, SimpleString *findPtr, SimpleString *resultStringPtr)
{
bool result = false;
result = FindString(sourcePtr, findPtr, resultStringPtr);
if (result)
{ resultStringPtr->fLen = (PointerSizedInt) resultStringPtr->fTheString -(PointerSizedInt) sourcePtr->fTheString;
resultStringPtr->fTheString = sourcePtr->fTheString;
}
return result;
}
bool SimpleParser::FindDelimeter( SimpleString *sourcePtr, char *findChars, SimpleString *resultStringPtr)
{
bool result = false;
do
{
if (NULL == sourcePtr) break;
if (NULL == findChars) break;
if (NULL == resultStringPtr) break;
SInt32 charCount = 0;
char* charOffset = sourcePtr->fTheString;
char* foundChar = NULL;
if ( (NULL == sourcePtr->fTheString) || (0 == sourcePtr->fLen) )
{ //qtss_printf("NULL string in FindDelimeter \n");
break;
}
// skip past any delimeters
while ( (*charOffset != 0) && (charCount <= sourcePtr->fLen) )
{ foundChar = strchr(findChars, *charOffset);
if (NULL == foundChar) break; // found non delimeter char
charOffset ++; charCount ++;
}
char *theChar = charOffset; // start past delimeters
while ( (*theChar != 0) && (charCount <= sourcePtr->fLen) )
{
foundChar = strchr(findChars, *theChar);
if (NULL != foundChar) break; // found delimeter
charCount++;
theChar++;
}
if (NULL == foundChar) break; // we didn't find a delimeter;
if (NULL != resultStringPtr)
{ UInt32 theLen = ((PointerSizedInt) theChar - (PointerSizedInt)charOffset);
resultStringPtr->SetString(charOffset, theLen); // start is charOffset
if (theLen == 0) break;
}
result = true;
} while (false);
if (!result)
resultStringPtr->SetString(NULL, 0); // start is charOffset
return result;
}
int SimpleParser::CountDelimeters( SimpleString *sourcePtr, char *delimeters)
{
short count = 0;
if (sourcePtr && delimeters)
{
SimpleString currentString = *sourcePtr;
currentString.fLen = 0;
while (GetNextThing(sourcePtr,&currentString, delimeters, &currentString))
{ count ++;
}
}
return count;
}
bool SimpleParser::GetWord( SimpleString *sourcePtr, SimpleString *resultStringPtr)
{
bool result = false;
char delimeter[] = " :/"; // space or colon or /
result = FindDelimeter(sourcePtr, delimeter,resultStringPtr);
return result;
}
bool SimpleParser::GetLine(SimpleString *sourcePtr, SimpleString *resultStringPtr)
{
bool result = false;
char delimeter[] = "\r\n";
result = FindDelimeter(sourcePtr, delimeter,resultStringPtr);
return result;
}
bool SimpleParser::GetNextThing(SimpleString *sourcePtr, SimpleString *currentPtr, char *findChars, SimpleString *resultStringPtr)
{
bool result = false;
do
{
if (NULL == sourcePtr) break;
if (NULL == currentPtr) break;
if (NULL == findChars) break;
if ( (PointerSizedInt) currentPtr->fTheString < (PointerSizedInt) sourcePtr->fTheString)
break;
if (NULL == sourcePtr->fTheString)
{ //qtss_printf("NULL sourcePtr->fTheString in GetNextThing \n");
break;
}
if (NULL == currentPtr->fTheString)
{ //qtss_printf("NULL currentPtr->fTheString in GetNextThing \n");
break;
}
PointerSizedInt endSource = (PointerSizedInt) &sourcePtr->fTheString[sourcePtr->fLen];
PointerSizedInt endCurrent = (PointerSizedInt) &currentPtr->fTheString[currentPtr->fLen];
if (endCurrent > endSource) break;
SimpleString tempSource(NULL);
UInt32 searchLen = endSource - endCurrent;
tempSource.SetString(&currentPtr->fTheString[currentPtr->fLen], searchLen); // step past the end of current with remaining length
result = FindDelimeter(&tempSource, findChars,resultStringPtr);
} while (false);
return result;
}
bool SimpleParser::GetNextWord( SimpleString *sourcePtr, SimpleString *currentWord, SimpleString *resultStringPtr)
{
bool result = false;
char *findChars = sWordDelimeters;//
result = GetNextThing(sourcePtr,currentWord, findChars, resultStringPtr);
return result;
}
bool SimpleParser::GetNextLine( SimpleString *sourcePtr, SimpleString *currentLine, SimpleString *resultStringPtr)
{
bool result = false;
char *findChars = sLineDelimeters;//"\r\n";
result = GetNextThing(sourcePtr,currentLine, findChars, resultStringPtr);
return result;
}

View file

@ -0,0 +1,96 @@
/*
*
* @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@
*
*/
#ifndef SimpleParser_H
#define SimpleParser_H
#include "OSHeaders.h"
class SimpleString {
public:
SInt32 fLen;
char *fTheString;
SimpleString(char *theString = NULL);
void Init();
void SetString(char *theString, SInt32 len);
SInt32 GetString(char *theString, SInt32 len);
SInt32 GetInt();
void Print();
};
class SimpleParser {
protected:
SimpleString fSource;
public:
SimpleParser() : fSource(NULL) {} ;
SimpleParser(SimpleString *source) : fSource(*source) {} ;
~SimpleParser() {};
static char sWordDelimeters[];
static char sLineDelimeters[];
void SetSource(SimpleString *source) {fSource = *source;};
static int CountDelimeters( SimpleString *source, char *delimeters);
static bool Compare(SimpleString *str1, SimpleString*str2, bool caseSensitive);
bool Compare(SimpleString *str1Ptr, char *str, bool caseSensitive)
{
if (str == NULL) return false;
SimpleString string(str);
return Compare(str1Ptr, &string, caseSensitive);
}
static bool FindString( SimpleString *source, SimpleString *find, SimpleString *resultString);
static bool FindNextString( SimpleString *sourcePtr, SimpleString *currentPtr, SimpleString *findPtr, SimpleString *resultStringPtr);
static bool GetString( SimpleString *source, SimpleString *find, SimpleString *resultString);
static bool FindDelimeter( SimpleString *source, char *delimeter, SimpleString *resultString);
static bool GetLine( SimpleString *sourcePtr, SimpleString *resultStringPtr);
static bool GetWord( SimpleString *sourcePtr, SimpleString *resultStringPtr);
static bool GetNextThing( SimpleString *sourcePtr, SimpleString *currentPtr, char *findChars, SimpleString *resultStringPtr);
static bool GetNextLine( SimpleString *sourcePtr, SimpleString *currentLine, SimpleString *resultStringPtr);
static bool GetNextWord( SimpleString *sourcePtr, SimpleString *currentWord, SimpleString *resultStringPtr);
};
#endif

View file

@ -0,0 +1,139 @@
/*
*
* @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@
*
*/
#ifndef playlist_array_H
#define playlist_array_H
// ************************
//
// TEMPLATE ARRAYLIST
//
// ************************
template <class T> class ArrayList
{
public:
T *fDataArray;
short fSize;
short fCurrent;
ArrayList()
{ fDataArray = NULL;
fSize = 0;
fCurrent = 0;
}
~ArrayList()
{ delete [] fDataArray;
};
T *SetSize(short size)
{ if (fDataArray != NULL) delete [] fDataArray;
fDataArray = new T[size];
if (fDataArray)
{ fSize = size;
}
return fDataArray;
}
T *Get()
{
T *resultPtr = NULL;
if (fDataArray != NULL)
{
if ( (fCurrent >= 0) && (fCurrent < fSize ) )
{ resultPtr = &fDataArray[fCurrent];
}
}
return resultPtr;
}
T *OffsetPos(short offset)
{
T *resultPtr = NULL;
do
{
if (fDataArray == NULL) break;
short temp = fCurrent + offset;
if (temp < 0)
{
fCurrent = 0; // peg at begin and return NULL
break;
}
if (temp < fSize)
{
resultPtr = &fDataArray[temp];
fCurrent = temp;
break;
}
fCurrent = fSize -1; // peg at end and return NULL
} while (false);
return resultPtr;
}
T *SetPos(short current)
{
T *resultPtr = NULL;
do
{
if (fDataArray == NULL) break;
if (current < 0)
{
fCurrent = 0; // peg at begin and return NULL
break;
}
if (current < fSize)
{
resultPtr = &fDataArray[current];
fCurrent = current;
break;
}
fCurrent = fSize -1; // peg at end and return NULL
} while (false);
return resultPtr;
}
short GetPos() { return fCurrent; };
T *Next() { return OffsetPos(1); };
T *Begin() { return SetPos(0); };
short Size() { return fSize;};
};
#endif

View file

@ -0,0 +1,765 @@
/*
*
* @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@
*
*/
#include "playlist_broadcaster.h"
#include "OS.h"
#include "OSThread.h"
#include "BroadcasterSession.h"
#include <string.h>
QTFileBroadcaster::QTFileBroadcaster()
{
fRTPFilePtr = NULL;
fMovieSDPParser = NULL;
fBasePort = 0;
fDebug = false;
fDeepDebug = false;
fQuitImmediatePtr = NULL;
// transmit time trackers
fLastTransmitTime = 0.0;
fStreamStartTime = 0;
fMovieStartTime = 0;
fMovieEndTime = 0;
fMovieIntervalTime = 0;
fMovieTimeDiffMilli = 0;
fMovieStart = false;
fSendTimeOffset = 0.0;
fMovieDuration = 0.0;
fMovieTracks = 0;
fMappedMovieTracks = 0;
fNumMoviesPlayed = 0;
fPlay = true;
fSend = true;
fBroadcastDefPtr = NULL;
// current movie parameters parsed from SDP
::strcpy(fCurrentMovieName, "-");
::strcpy(fCurrentMovieCopyright, "-");
::strcpy(fCurrentMovieComment, "-");
::strcpy(fCurrentMovieAuthor, "-");
::strcpy(fCurrentMovieArtist, "-");
::strcpy(fCurrentMovieAlbum, "-");
}
QTFileBroadcaster::~QTFileBroadcaster()
{
LogFileClose();
if (fRTPFilePtr != NULL)
{ delete fRTPFilePtr;
}
}
int QTFileBroadcaster::SetUp(PLBroadcastDef *broadcastDefPtr, bool *quitImmediatePtr)
{
int result = -1;
int numStreams = 0;
fQuitImmediatePtr = quitImmediatePtr;
PlayListUtils::Initialize();
do
{
if (! broadcastDefPtr)
{ result = eParam; break; };
if (!broadcastDefPtr->mSDPFile || 0 == broadcastDefPtr->mSDPFile[0] )
{ result = eSDPFileInvalidName; break; };
int nameLen = strlen(broadcastDefPtr->mSDPFile);
if (nameLen > 255)
{ result = eSDPFileInvalidName; break; };
if (0 == nameLen)
{ result = eSDPFileInvalidName; break; };
if (broadcastDefPtr->mTheSession)
{ if (!broadcastDefPtr->mDestSDPFile)
{ result = eNetworkSDPFileNameInvalidMissing; break; };
if (!broadcastDefPtr->mDestSDPFile[0])
{ result = eNetworkSDPFileNameInvalidMissing; break; };
if (!::strcmp(broadcastDefPtr->mDestSDPFile, "no_name"))
{ result = eNetworkSDPFileNameInvalidMissing; break; };
// if ('/' == broadcastDefPtr->mDestSDPFile[0])
// { result = eNetworkSDPFileNameInvalidBadPath; break; };
}
result = fStreamSDPParser.ReadSDP(broadcastDefPtr->mSDPFile);
if (result != 0)
{ if (result < 0) { result = eSDPFileNotFound; break; };
if (result > 0) { result = eSDPFileInvalid; break; };
}
fBroadcastDefPtr = broadcastDefPtr;
if (broadcastDefPtr->mTheSession == NULL)
{ if (!broadcastDefPtr->mBasePort) { result = eSDPFileNoPorts; break; };
int portLen = strlen(broadcastDefPtr->mBasePort);
if (0 == portLen) { result = eDescriptionInvalidDestPort; break; };
if (portLen > 5 ) { result = eDescriptionInvalidDestPort; break; };
int basePort = atoi(broadcastDefPtr->mBasePort);
if ( basePort > 65531 ) { result = eDescriptionInvalidDestPort; break; };
if ( basePort < 5004 ) { result = eDescriptionInvalidDestPort; break; };
}
numStreams = fStreamSDPParser.GetNumTracks();
if (numStreams == 0) { result = eSDPFileNoMedia; break; };
UDPSocketPair *socketArrayPtr = fSocketlist.SetSize(numStreams);
if (socketArrayPtr == NULL) { result = eMem; break; };
// Bind SDP file defined ports to active stream ports
{
UInt16 streamIndex = 0;
UInt16 rtpPort = 0;
UInt16 rtcpPort = 0;
TypeMap* mediaTypePtr;
char sdpIPAddress[32];
SimpleString* ipStringPtr = fStreamSDPParser.GetIPString();
if ( (NULL == ipStringPtr) || (ipStringPtr->fLen >= 32) )
{
result = eSDPFileInvalid;
break;
}
memcpy(sdpIPAddress,ipStringPtr->fTheString,ipStringPtr->fLen);
sdpIPAddress[ipStringPtr->fLen] = '\0';
UDPSocketPair *aSocketPair = fSocketlist.Begin();
Bool16 setupUDP = true;
while (aSocketPair != NULL)
{
mediaTypePtr = fStreamSDPParser.fSDPMediaList.SetPos(streamIndex);
if (mediaTypePtr == NULL)
{ result = eSDPFileInvalid;
break;
}
if (broadcastDefPtr->mTheSession != NULL)
{
mediaTypePtr->fPort = broadcastDefPtr->mTheSession->GetStreamDestPort(streamIndex);
//qtss_printf("QTFileBroadcaster::SetUp streamIndex=%u port=%d\n",streamIndex,mediaTypePtr->fPort);
if (BroadcasterSession::kTCPTransportType == broadcastDefPtr->mTheSession->GetTransportType())
{ aSocketPair->SetRTSPSession(broadcastDefPtr->mTheSession, (UInt8) streamIndex * 2);
setupUDP = false;
}
else
{ setupUDP = true;
}
}
if (setupUDP)
{
SInt16 ttl = (SInt16) atoi(broadcastDefPtr->mTTL);
if ( ( ttl > 255 ) || ( ttl < 1 ) )
{ result = eSDPFileInvalidTTL; break;
};
if (mediaTypePtr->fPort == 0)
{
result = eSDPFileInvalidPort;
break;
}
rtpPort = mediaTypePtr->fPort;
rtcpPort = rtpPort + 1;
result = aSocketPair->OpenAndBind(rtpPort,rtcpPort,sdpIPAddress);
if (result != 0)
{
result = eFailedBind;
break;
}
(void) aSocketPair->SetMultiCastOptions(ttl);
}
aSocketPair = fSocketlist.Next();
streamIndex++;
}
if (result != 0)
break;
}
MediaStream *mediaArrayPtr = fMediaStreamList.SetSize(numStreams);
if (mediaArrayPtr == NULL)
{
result = eMem;
break;
}
for (int i = 0; i < numStreams; i ++)
{ UDPSocketPair *socketPairPtr = fSocketlist.SetPos(i);
MediaStream *mediaStreamPtr = fMediaStreamList.SetPos(i);
TypeMap *streamMediaTypePtr = fStreamSDPParser.fSDPMediaList.SetPos(i);
if (socketPairPtr && mediaStreamPtr && streamMediaTypePtr)
{
mediaStreamPtr->fData.fSocketPair = socketPairPtr;
streamMediaTypePtr->fMediaStreamPtr = mediaStreamPtr;
mediaStreamPtr->fData.fStreamMediaTypePtr = streamMediaTypePtr;
}
else
{
result = eMem;
break;
}
}
fMediaStreamList.SetUpStreamSSRCs();
fStreamStartTime = PlayListUtils::Milliseconds();
fMediaStreamList.StreamStarted(fStreamStartTime);
result = 0;
LogFileOpen();
} while (false);
return result;
}
PayLoad * QTFileBroadcaster::FindPayLoad(short id, ArrayList<PayLoad> *PayLoadListPtr)
{
PayLoad *thePayLoadPtr = PayLoadListPtr->Begin();
while (thePayLoadPtr)
{
if (thePayLoadPtr->payloadID == id)
break;
thePayLoadPtr = PayLoadListPtr->Next();
}
return thePayLoadPtr;
}
bool QTFileBroadcaster::CompareRTPMaps(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr, short moviePayLoadID)
{
bool found = false;
do
{
PayLoad *moviePayLoadPtr = FindPayLoad(moviePayLoadID, &movieMediaTypePtr->fPayLoadTypes);
if (!moviePayLoadPtr) break;
PayLoad *streamPayLoadPtr = streamMediaTypePtr->fPayLoadTypes.Begin();
while (streamPayLoadPtr)
{
if (moviePayLoadPtr->timeScale == streamPayLoadPtr->timeScale)
{ found = SimpleParser::Compare(&moviePayLoadPtr->payLoadString,&streamPayLoadPtr->payLoadString, false );
}
if (found)
{ moviePayLoadPtr->payloadID = streamPayLoadPtr->payloadID; // map movie ID to match stream id
break;
}
streamPayLoadPtr = streamMediaTypePtr->fPayLoadTypes.Next();
}
} while (false);
return found;
}
bool QTFileBroadcaster::CompareMediaTypes(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr)
{
bool found = false;
found = SimpleParser::Compare(&movieMediaTypePtr->fTheTypeStr,&streamMediaTypePtr->fTheTypeStr, false);
if (found)
{
found = false;
short *movieIDPtr = movieMediaTypePtr->fPayLoads.Begin();
while (movieIDPtr && !found)
{
short *streamIDPtr = streamMediaTypePtr->fPayLoads.Begin();
while (streamIDPtr && !found)
{
if (*movieIDPtr >= 96)
found = CompareRTPMaps(movieMediaTypePtr, streamMediaTypePtr, *movieIDPtr);
else
found = (*streamIDPtr == *movieIDPtr) ? true : false;
streamIDPtr = streamMediaTypePtr->fPayLoads.Next();
}
movieIDPtr = movieMediaTypePtr->fPayLoads.Next();
}
}
return found;
}
int QTFileBroadcaster::MapMovieToStream()
{
int result = -1;
bool matches = false;
ArrayList<bool> map;
bool *isMappedPtr;
int masterPos = 0;
int mappedTracks = 0;
map.SetSize(fStreamSDPParser.fSDPMediaList.Size());
isMappedPtr = map.Begin();
while (isMappedPtr)
{ *isMappedPtr = false;
isMappedPtr = map.Next();
}
TypeMap *movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Begin();
while (movieMediaTypePtr)
{
TypeMap *streamMediaTypePtr = fStreamSDPParser.fSDPMediaList.Begin();
while (streamMediaTypePtr)
{
matches = CompareMediaTypes(movieMediaTypePtr, streamMediaTypePtr);
if (matches)
{
masterPos = fStreamSDPParser.fSDPMediaList.GetPos();
isMappedPtr = map.SetPos(masterPos);
if (isMappedPtr == NULL)
break;
if (false == *isMappedPtr)
{
movieMediaTypePtr->fMediaStreamPtr = streamMediaTypePtr->fMediaStreamPtr;
*isMappedPtr = true;
mappedTracks++;
break;
}
}
streamMediaTypePtr = fStreamSDPParser.fSDPMediaList.Next();
}
movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Next();
}
result = mappedTracks;
return result;
}
UInt32 QTFileBroadcaster::GetSDPTracks(QTRTPFile *newRTPFilePtr)
{
char* sdpBuffer;
int bufferLen = 0;
UInt32 result = 0;
sdpBuffer = newRTPFilePtr->GetSDPFile(&bufferLen);
fMovieSDPParser->ParseSDP(sdpBuffer);
result = fMovieSDPParser->GetNumTracks();
return result;
}
int QTFileBroadcaster::AddTrackAndStream(QTRTPFile *newRTPFilePtr)
{
TypeMap* movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Begin();
UInt32 trackID;
char* cookie;
int err = -1;
while (movieMediaTypePtr)
{
if (movieMediaTypePtr->fMediaStreamPtr != NULL)
{
trackID = movieMediaTypePtr->fTrackID;
if (trackID == 0) break;
movieMediaTypePtr->fMediaStreamPtr->fData.fMovieMediaTypePtr = movieMediaTypePtr;
movieMediaTypePtr->fMediaStreamPtr->fData.fRTPFilePtr = newRTPFilePtr;
movieMediaTypePtr->fMediaStreamPtr->fSend = fSend;
cookie = (char *) movieMediaTypePtr->fMediaStreamPtr;
err = newRTPFilePtr->AddTrack(trackID, false);
if (err != 0)
break;
newRTPFilePtr->SetTrackCookies(trackID, cookie, 0);
newRTPFilePtr->SetTrackSSRC(trackID, (UInt32) 0); // set later
err = newRTPFilePtr->Seek(0.0);
if (err != QTRTPFile::errNoError)
break;
}
movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Next();
}
return err;
}
int QTFileBroadcaster::SetUpAMovie(char *theMovieFileName)
{
int err = -1;
QTRTPFile *newRTPFilePtr = NULL;
do {
fMovieTracks = 0;
fMappedMovieTracks = 0;
if (fMovieSDPParser != NULL) delete fMovieSDPParser;
if (fRTPFilePtr != NULL) delete fRTPFilePtr;
fMovieSDPParser = NULL;
fRTPFilePtr = NULL;
if (!theMovieFileName) { err = eMovieFileInvalidName; break; }
int nameLen = strlen(theMovieFileName);
if (nameLen > 255) { err = eMovieFileInvalidName; break; }
if (0 == nameLen) { err = eMovieFileInvalidName; break; }
fMovieSDPParser = new SDPFileParser;
if (NULL == fMovieSDPParser) { err = eMem; break;}
newRTPFilePtr = new QTRTPFile();
if (NULL == newRTPFilePtr) { err = eMem; break;}
QTRTPFile::ErrorCode result = newRTPFilePtr->Initialize(theMovieFileName);
err = EvalErrorCode(result);
if (err) break;
fMovieTracks = GetSDPTracks(newRTPFilePtr);
if (fMovieTracks < 1) { err = eMovieFileNoHintedTracks; break; }
fMappedMovieTracks = MapMovieToStream();
if (fMappedMovieTracks < 1) { err = eMovieFileNoSDPMatches; break; }
err = AddTrackAndStream(newRTPFilePtr);
if (err != 0) { err = eMovieFileInvalid; break; }
} while (false);
if (err)
{ if (newRTPFilePtr)
delete newRTPFilePtr;
newRTPFilePtr = NULL;
}
fRTPFilePtr = newRTPFilePtr;
return err;
}
void QTFileBroadcaster::MilliSleep(SInt32 sleepTimeMilli)
{
if (sleepTimeMilli > 0)
{
#if __solaris__
struct timeval tv;
::memset(&tv,0,sizeof(tv));
tv.tv_usec = sleepTimeMilli * 1000;
::select(0,NULL,NULL,NULL,&tv);
#else
OSThread::Sleep( (UInt32) sleepTimeMilli);
#endif
}
}
Float64 QTFileBroadcaster::Sleep(Float64 transmitTimeMilli)
{
Float64 sleepTime;
Float64 timeToSend;
Float64 currentTime = (Float64) PlayListUtils::Milliseconds();
if (fMovieStart)
{
fMovieStart = false;
}
timeToSend = fMovieStartTime + transmitTimeMilli;
sleepTime = timeToSend - currentTime;
const Float64 maxSleepIntervalMilli = 100.0;
const Float64 minSleepIntervalMilli = 1.0;
Float64 intervalTime = sleepTime;
SInt32 sleepMilli = 0;
if (intervalTime > maxSleepIntervalMilli)
{ while (intervalTime >= maxSleepIntervalMilli)
{
intervalTime -= maxSleepIntervalMilli;
sleepMilli = (SInt32) maxSleepIntervalMilli;
MilliSleep(sleepMilli);
fMediaStreamList.UpdateSenderReportsOnStreams();
//qtss_printf("sleepIntervalMilli %u \n",sleepMilli);
}
}
if (intervalTime >= minSleepIntervalMilli)
{ sleepMilli = (SInt32) intervalTime;
MilliSleep(sleepMilli);
//qtss_printf("sleepMilli %u \n",sleepMilli);
}
fMediaStreamList.UpdateSenderReportsOnStreams();
return sleepTime;
}
/* changed by emil@popwire.com (see relaod.txt for info) */
int QTFileBroadcaster::Play(char *mTimeFile)
/* ***************************************************** */
{
SInt16 err = 0;
Float64 transmitTime = 0;
MediaStream *theStreamPtr = NULL;
RTpPacket rtpPacket;
unsigned int sleptTime;
SInt32 movieStartOffset = 0; //z
Bool16 negativeTime = false;
fMovieDuration = fRTPFilePtr->GetMovieDuration();
fSendTimeOffset = 0.0;
fMovieStart = true;
fNumMoviesPlayed ++;
if (fMovieEndTime > 0) // take into account the movie load time as well as the last movie early end.
{ UInt64 timeNow = PlayListUtils::Milliseconds();
fMovieIntervalTime = timeNow - fMovieEndTime;
SInt32 earlySleepTimeMilli = (SInt32)(fMovieTimeDiffMilli - fMovieIntervalTime);
earlySleepTimeMilli -= 40; // Don't sleep the entire time we need some time to execute or else we will be late
if (earlySleepTimeMilli > 0)
{ OSThread::Sleep( earlySleepTimeMilli);
}
}
fMovieStartTime = PlayListUtils::Milliseconds();
fMediaStreamList.MovieStarted(fMovieStartTime);
/* changed by emil@popwire.com (see relaod.txt for info) */
if(mTimeFile!=NULL)
{
FILE *fTimeFile = NULL;
struct timeval start, dur, end;
struct tm tm_start, tm_dur, tm_end, timeResult;
memset (&start,0, sizeof(start));
SInt64 timenow = OS::Milliseconds();
start.tv_sec = (SInt32) OS::TimeMilli_To_UnixTimeSecs(timenow);
start.tv_usec = (SInt32) ((OS::TimeMilli_To_UnixTimeMilli(timenow) - (start.tv_sec * 1000)) * 1000);
dur.tv_sec = (SInt32)fMovieDuration;
dur.tv_usec = (SInt32)((fMovieDuration - dur.tv_sec) * 1000000);
end.tv_sec = start.tv_sec + dur.tv_sec + (SInt32)((start.tv_usec + dur.tv_usec) / 1000000);
end.tv_usec = (start.tv_usec + dur.tv_usec) % 1000000;
time_t startSecs = start.tv_sec;
time_t endSecs = end.tv_sec;
memcpy(&tm_start, qtss_localtime(&startSecs, &timeResult), sizeof(struct tm));
memcpy(&tm_end, qtss_localtime(&endSecs, &timeResult), sizeof(struct tm));
tm_dur.tm_hour = dur.tv_sec / 3600;
tm_dur.tm_min = (dur.tv_sec % 3600) / 60;
tm_dur.tm_sec = (dur.tv_sec % 3600) % 60;
// initialize all current movie parameters to unkown ("-").
::strcpy(fCurrentMovieName, "-");
::strcpy(fCurrentMovieCopyright, "-");
::strcpy(fCurrentMovieComment, "-");
::strcpy(fCurrentMovieAuthor, "-");
::strcpy(fCurrentMovieArtist, "-");
::strcpy(fCurrentMovieAlbum, "-");
/* save start time, stop time and length of currently playing song to .current file */
fTimeFile = fopen(mTimeFile, "a");
if(fTimeFile)
{
SimpleString *theQTTextPtr = fMovieSDPParser->fQTTextLines.Begin();
while (theQTTextPtr != NULL)
{
char tmp[256];
::memcpy(tmp, theQTTextPtr->fTheString, theQTTextPtr->fLen);
tmp[theQTTextPtr->fLen] = 0;
// if this SDP parameter is needed for logging then cache it here so
// we can log it later.
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-nam:")!=NULL)
::strcpy(fCurrentMovieName, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-cpy:")!=NULL)
::strcpy(fCurrentMovieCopyright, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-cmt:")!=NULL)
::strcpy(fCurrentMovieComment, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-aut:")!=NULL)
::strcpy(fCurrentMovieAuthor, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-ART:")!=NULL)
::strcpy(fCurrentMovieArtist, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-alb:")!=NULL)
::strcpy(fCurrentMovieAlbum, &tmp[16]);
fwrite(theQTTextPtr->fTheString,theQTTextPtr->fLen, sizeof(char),fTimeFile);
qtss_fprintf(fTimeFile,"\n");
theQTTextPtr = fMovieSDPParser->fQTTextLines.Next();
}
time_t startTime = (time_t) start.tv_sec;
time_t endTime = (time_t) end.tv_sec;
char buffer[kTimeStrSize];
char *timestringStart = qtss_ctime(&startTime, buffer, sizeof(buffer));
qtss_fprintf(fTimeFile,"b=%02d:%02d:%02d:%06d %"_S32BITARG_" %s", (int) tm_start.tm_hour, (int) tm_start.tm_min, (int) tm_start.tm_sec, (int)start.tv_usec, (SInt32) startTime, timestringStart);
char *timestringEnd = qtss_ctime(&endTime, buffer, sizeof(buffer));
qtss_fprintf(fTimeFile,"e=%02d:%02d:%02d:%06d %"_S32BITARG_" %s", (int)tm_end.tm_hour, (int) tm_end.tm_min,(int) tm_end.tm_sec, (int) end.tv_usec,(SInt32) endTime, timestringEnd);
qtss_fprintf(fTimeFile,"d=%02d:%02d:%02d:%06d %d \n", (int) tm_dur.tm_hour, (int) tm_dur.tm_min,(int) tm_dur.tm_sec, (int) dur.tv_usec, (int)dur.tv_sec);
fclose(fTimeFile);
}
}
while (true)
{
if (fQuitImmediatePtr && *fQuitImmediatePtr){err = 0; break; } // quit now not an error
if (fBroadcastDefPtr->mTheSession)
{ UInt32 thePacketQLen = 0;
thePacketQLen = fBroadcastDefPtr->mTheSession->GetPacketQLen();
SInt64 maxSleep = PlayListUtils::Milliseconds() + 1000;
if (thePacketQLen > eMaxPacketQLen)
{ //qtss_printf("PacketQ too big = %"_U32BITARG_" \n", (UInt32) thePacketQLen);
while ( (eMaxPacketQLen/2) < fBroadcastDefPtr->mTheSession->GetPacketQLen())
{ this->SleepInterval(100.0);
if (maxSleep < PlayListUtils::Milliseconds())
break;
}
//qtss_printf("PacketQ after sleep = %"_U32BITARG_" \n", (UInt32) fBroadcastDefPtr->mTheSession->GetPacketQLen());
continue;
}
}
transmitTime = fRTPFilePtr->GetNextPacket(&rtpPacket.fThePacket, &rtpPacket.fLength);
theStreamPtr = (MediaStream*)fRTPFilePtr->GetLastPacketTrack()->Cookie1;
err = fRTPFilePtr->Error();
if (err != QTRTPFile::errNoError) {err = eMovieFileInvalid; break; } // error getting packet
if (NULL == rtpPacket.fThePacket) {err = 0; break; } // end of movie not an error
if (NULL == theStreamPtr) {err = eMovieFileInvalid; break; }// an error
transmitTime *= (Float64) PlayListUtils::eMilli; // convert to milliseconds
if (transmitTime < 0.0 && negativeTime == false) // Deal with negative transmission times
{ movieStartOffset += (SInt32) (transmitTime / 15.0);
negativeTime = true;
}
sleptTime = (unsigned int) Sleep(transmitTime);
err = theStreamPtr->Send(&rtpPacket);
if (err != 0) { break; }
err = fMediaStreamList.UpdateStreams();
if (err != 0) { break; }
if ( (fBroadcastDefPtr != NULL)
&& (fBroadcastDefPtr->mTheSession != NULL)
&& (fBroadcastDefPtr->mTheSession->GetReasonForDying() != BroadcasterSession::kDiedNormally)
)
{ break; }
};
fMovieEndTime = (SInt64) PlayListUtils::Milliseconds();
fMediaStreamList.MovieEnded(fMovieEndTime);
// see if the movie duration is greater than the time it took to send the packets.
// the difference is a delay that we insert before playing the next movie.
SInt64 playDurationMilli = (SInt64) fMovieEndTime - (SInt64) fMovieStartTime;
fMovieTimeDiffMilli = ((SInt64) ( (Float64) fMovieDuration * (Float64) PlayListUtils::eMilli)) - (SInt64) playDurationMilli;
fMovieTimeDiffMilli-= (movieStartOffset/2);
return err;
}
/* changed by emil@popwire.com (see relaod.txt for info) */
int QTFileBroadcaster::PlayMovie(char *movieFileName, char *currentFile)
/* ***************************************************** */
{
int err = eMovieFileInvalidName;
if (movieFileName != NULL)
{
err = SetUpAMovie(movieFileName);
if (!err && fPlay)
/* changed by emil@popwire.com (see relaod.txt for info) */
{ err = Play(currentFile);
/* ***************************************************** */
}
}
return err;
}
int QTFileBroadcaster::EvalErrorCode(QTRTPFile::ErrorCode err)
{
int result = eNoErr;
switch( err )
{
case QTRTPFile::errNoError:
break;
case QTRTPFile::errFileNotFound:
result = eMovieFileNotFound;
break;
case QTRTPFile::errNoHintTracks:
result = eMovieFileNoHintedTracks;
break;
case QTRTPFile::errInvalidQuickTimeFile:
result = eMovieFileInvalid;
break;
case QTRTPFile::errInternalError:
result = eInternalError;
break;
default:
result = eInternalError;
}
return result;
}

View file

@ -0,0 +1,168 @@
/*
*
* @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@
*
*/
/* contributions by emil@popwire.com
*/
#ifndef playlist_broadcaster_H
#define playlist_broadcaster_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#include "OSHeaders.h"
#include "playlist_utils.h"
#include "playlist_elements.h"
#include "playlist_lists.h"
#include "playlist_parsers.h"
#include "QTRTPFile.h"
#include "PLBroadcastDef.h"
#ifndef __Win32__
#include <sys/types.h>
#include <fcntl.h>
#endif
static PlayListUtils gUtils;
class QTFileBroadcaster
{
protected:
QTRTPFile *fRTPFilePtr ;
SDPFileParser fStreamSDPParser;
SDPFileParser *fMovieSDPParser;
SocketList fSocketlist;
MediaStreamList fMediaStreamList;
int fBasePort;
bool fDebug;
bool fDeepDebug;
bool *fQuitImmediatePtr;
// transmit time trackers
Float64 fLastTransmitTime;
SInt64 fStreamStartTime;
SInt64 fMovieStartTime;
SInt64 fMovieEndTime;
SInt64 fMovieIntervalTime;
SInt64 fMovieTimeDiffMilli;
bool fMovieStart;
Float64 fSendTimeOffset;
Float64 fMovieDuration;
int fMovieTracks;
int fMappedMovieTracks;
UInt64 fNumMoviesPlayed;
PayLoad * FindPayLoad(short id, ArrayList<PayLoad> *PayLoadListPtr);
bool CompareRTPMaps(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr, short id);
bool CompareMediaTypes(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr);
UInt32 GetSDPTracks(QTRTPFile *newRTPFilePtr);
int SetUpAMovie(char *movieFileName);
int AddTrackAndStream(QTRTPFile *newRTPFilePtr);
int MapMovieToStream();
int Play(char *mTimeFile);
Float64 SleepInterval(Float64 sleepTime) { return Sleep( (Float64) (PlayListUtils::Milliseconds() - fMovieStartTime) + sleepTime); };
Float64 Sleep(Float64 transmitTime);
void SetDebug(bool debug) {fDebug = debug;};
void SetDeepDebug(bool debug) {fDeepDebug = debug;};
PLBroadcastDef *fBroadcastDefPtr;
public:
QTFileBroadcaster();
~QTFileBroadcaster();
static int EvalErrorCode(QTRTPFile::ErrorCode err);
int SetUp(PLBroadcastDef *broadcastDefPtr, bool *quitImmediatePtr);
int PlayMovie(char *movieFileName, char *currentFile);
int GetMovieTrackCount() { return fMovieTracks; };
int GetMappedMovieTrackCount() { return fMappedMovieTracks; };
void MilliSleep(SInt32 sleepTimeMilli);
bool fPlay;
bool fSend;
enum { eClientBufferSecs = 0,
eMaxPacketQLen = 200
};
enum ErrorID
{ // General errors
eNoErr = 0
,eParam
,eMem
,eInternalError
,eFailedBind
// Setup Errors
,eNoAvailableSockets
,eSDPFileNotFound
,eSDPDestAddrInvalid
,eSDPFileInvalid
,eSDPFileNoMedia
,eSDPFileNoPorts
,eSDPFileInvalidPort
,eSDPFileInvalidName
,eSDPFileInvalidTTL
// eMem also
// Play Errors,
,eMovieFileNotFound
,eMovieFileNoHintedTracks
,eMovieFileNoSDPMatches
,eMovieFileInvalid
,eMovieFileInvalidName
,eNetworkConnectionError
,eNetworkRequestError
,eNetworkConnectionStopped
,eNetworkAuthorization
,eNetworkNotSupported
,eNetworkSDPFileNameInvalidMissing
,eNetworkSDPFileNameInvalidBadPath
,eNetworkConnectionFailed
,eDescriptionInvalidDestPort
};
char fCurrentMovieName[256];
char fCurrentMovieCopyright[256];
char fCurrentMovieComment[256];
char fCurrentMovieAuthor[256];
char fCurrentMovieArtist[256];
char fCurrentMovieAlbum[256];
private:
};
#endif //playlist_broadcaster_H

View file

@ -0,0 +1,874 @@
/*
*
* @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@
*
*/
#include "playlist_elements.h"
#include "playlist_utils.h"
#include "OS.h"
#include "SocketUtils.h"
#ifndef __Win32__
#include <unistd.h>
#endif
// ************************
//
// MediaStream
//
// ************************
#define DROP_RTCP_TEST 0
#define DROPCOUNT 1// drop count RTCPs
MediaStream::MediaStream(void)
{
memset( (char *)&fData, '\0', sizeof(fData));
fSend = true;
fData.fSenderReportReady = true;
}
MediaStream::~MediaStream()
{
if (fData.fSoundDescriptionBuffer) delete[] fData.fSoundDescriptionBuffer;
}
UInt32 MediaStream::GetACName(char* ioCNameBuffer)
{
//clear out the whole buffer
::memset(ioCNameBuffer, 0, kMaxCNameLen);
//cName identifier
ioCNameBuffer[0] = 1;
//Unique cname is constructed from the base name and the current time
qtss_sprintf(&ioCNameBuffer[2], " %s%"_64BITARG_"d", "QTSS", OS::Milliseconds() / 1000);
UInt32 cNameLen = ::strlen(&ioCNameBuffer[2]);
//2nd byte of CName should be length
ioCNameBuffer[1] = (UInt8) cNameLen ;//doesn't count indicator or length byte
cNameLen += 2; // add the identifier and len bytes to the result len
//pad length to a 4 byte boundary
UInt32 padLength = cNameLen % 4;
if (padLength > 0)
cNameLen += 4 - padLength;
return cNameLen;
}
void MediaStream::TestAndIncSoundDescriptor(RTpPacket *packetPtr)
{ // currently not executed
SInt16 test = 0;
do
{
if (!fData.fIsSoundStream) break;
if (!packetPtr->HasSoundDescription()) break;
if (!fData.fSoundDescriptionBuffer) break;
SoundDescription *packetSDPtr = NULL;
SoundDescription *savedSDPtr = (SoundDescription *) fData.fSoundDescriptionBuffer;
(void) packetPtr->GetSoundDescriptionRef(&packetSDPtr);
SInt32 descSize = packetPtr->fSoundDescriptionLen;
if (descSize == 0) break;
if (descSize > eMaxSoundDescriptionSize) break;
if (fData.fSavedSoundDescSize == descSize)
{ test = ::memcmp(packetSDPtr, fData.fSoundDescriptionBuffer, descSize);
}
else test = 1; // they are different sizes so it is a new sample description
if (test != 0) // they are different
{ ::memcpy(savedSDPtr, packetSDPtr, descSize);
fData.fSavedSoundDescSize = descSize;
fData.fSavedDataRefIndex ++ ; // it is different than saved so change the index
}
packetSDPtr->dataRefIndex = htons(fData.fSavedDataRefIndex);
} while (false);
}
void MediaStream::UpdatePacketInStream(RTpPacket *packetPtr)
{
UInt32 curSSRC = 0;
UInt32 curRTpTimeStamp = 0;
UInt16 curRTpSequenceNumber = 0;
UInt32 newRTpTimeStamp = 0;
UInt16 newRTpSequenceNumber = 0;
UInt32 newSSRC = 0;
unsigned char curPayload;
unsigned char newPayload;
packetPtr->GetHeaderInfo(&curRTpTimeStamp, &curRTpSequenceNumber, &curSSRC, &curPayload);
newSSRC = fData.fInitSSRC;
MapToStream(curRTpTimeStamp, curRTpSequenceNumber, curPayload, &newRTpTimeStamp, &newRTpSequenceNumber, &newPayload);
if (fData.fIsVideoStream) { LogStr("video "); }
if (fData.fIsSoundStream) { LogStr("audio "); }
packetPtr->SetHeaderInfo(newRTpTimeStamp, newRTpSequenceNumber,newSSRC,newPayload);
//TestAndIncSoundDescriptor(packetPtr); // put in to track QuickTime format sound descriptors and flag change in sample types
}
void MediaStream::MapToStream(UInt32 curRTpTimeStamp, UInt16 curRTpSequenceNumber, unsigned char curPayload, UInt32 *outRTpTimeStampPtr, UInt16 *outRTpSequenceNumberPtr, unsigned char *outPayloadPtr)
{
if (fData.fNewMovieStarted == true) // this is the first packet in a new movie
{
fData.fNewMovieStarted = false;
}
fData.fCurStreamRTpSequenceNumber++; // the stream sequence number
UInt64 curSequenceNumber = (UInt64) fData.fCurStreamRTpSequenceNumber + (UInt64) fData.fSeqRandomOffset;
UInt64 curTimeStamp = (UInt64) curRTpTimeStamp + (UInt64) fData.fMediaStartOffsetMediaScale + (UInt64) fData.fRTpRandomOffset;
UInt32 outTime = (UInt32) ( (UInt64) curTimeStamp & (UInt64) 0xFFFFFFFF );
UInt16 outSeq = (UInt16) ( (UInt64) curSequenceNumber & (UInt64) 0xFFFF );
unsigned char outPayload = curPayload;
Assert (fData.fMovieMediaTypePtr != NULL);// should always be valid
PayLoad *firstPayLoadPtr = (fData.fMovieMediaTypePtr)->fPayLoadTypes.Begin(); // potential problem; assumes first payload per track is this payload
if (firstPayLoadPtr)
{
outPayload = (unsigned char) ( 0x7F & firstPayLoadPtr->payloadID);
outPayload |= (curPayload & 0x80);// the movie payload marker
}
// qtss_printf("MediaStream::MapToStream outTime = %"_U32BITARG_"\n", outTime);
// qtss_printf("MediaStream::MapToStream calculated time = %"_U32BITARG_"\n",(UInt32) curTimeInScale);
if (outRTpTimeStampPtr) *outRTpTimeStampPtr = outTime;
if (outRTpSequenceNumberPtr) *outRTpSequenceNumberPtr = outSeq;
if (outPayloadPtr) *outPayloadPtr = outPayload;
}
void MediaStream::BuildStaticRTCpReport()
{
char theTempCName[kMaxCNameLen];
UInt32 cNameLen = GetACName(theTempCName);
//write the SR & SDES headers
UInt32* theSRWriter = (UInt32*)&fData.fSenderReportBuffer;
*theSRWriter = htonl(0x80c80006);
theSRWriter += 7;
//SDES length is the length of the CName, plus 2 32bit words
*theSRWriter = htonl(0x81ca0000 + (cNameLen >> 2) + 1);
::memcpy(&fData.fSenderReportBuffer[kSenderReportSizeInBytes], theTempCName, cNameLen);
fData.fSenderReportSize = kSenderReportSizeInBytes + cNameLen;
}
void MediaStream::InitIfAudio()
{
if (fData.fStreamMediaTypePtr)
{
SimpleString audioStr("audio");
fData.fIsSoundStream = SimpleParser::Compare(&audioStr, &(fData.fStreamMediaTypePtr->fTheTypeStr), false );
if (fData.fIsSoundStream)
{
fData.fSoundDescriptionBuffer = new char[eMaxSoundDescriptionSize];
::memset(fData.fSoundDescriptionBuffer, 0, eMaxSoundDescriptionSize );
}
else
{
SimpleString videoStr("video");
fData.fIsVideoStream = SimpleParser::Compare(&videoStr, &(fData.fStreamMediaTypePtr->fTheTypeStr), false );
}
}
}
void MediaStream::StreamStart(SInt64 startTime)
{
fData.fStreamStartTime = startTime;
fData.fMovieEndTime = startTime;
fData.fLastSenderReportTime = 0;
//for RTCp SRs, we also need to store the play time in NTP
// fData.fNTPPlayTime = OS::TimeMilli_To_1900Fixed64Secs(startTime);
fData.fNTPPlayTime = PlayListUtils::TimeMilli_To_1900Fixed64Secs(startTime);
fData.fCurStreamRTpSequenceNumber = 0;
fData.fMovieStartOffset = 0;
fData.fNewStreamStarted = true;
fData.fSeqRandomOffset = PlayListUtils::Random();
fData.fRTpRandomOffset = PlayListUtils::Random();
// fData.fSeqRandomOffset = -1000; // test roll over
// fData.fRTpRandomOffset = -100000; // test roll over
InitIfAudio();
//Build a static RTCp sender report (this way, only the info that changes
//on the fly will have to be written)
BuildStaticRTCpReport();
}
void MediaStream::MovieStart(SInt64 startTime)
{
fData.fNewMovieStarted = true;
fData.fMovieStartTime = startTime;
if (fData.fMovieMediaTypePtr && fData.fRTPFilePtr)
{ UInt32 trackID = fData.fMovieMediaTypePtr->fTrackID;
fData.fMovieMediaTypePtr->fTimeScale = fData.fRTPFilePtr->GetTrackTimeScale(trackID);
UInt64 lastMovieduration = (UInt64) ( (Float64) (fData.fLastMovieDurationSecs * (Float64) PlayListUtils::eMilli) ) ; // add the length of the last movie
fData.fMovieStartOffset += lastMovieduration;
if (fData.fNewStreamStarted)
{ fData.fNewStreamStarted = false;
fData.fMovieEndTime = startTime; // first movie in stream has 0 movieInterval time.
}
Float64 mediaOffSet = (Float64) (SInt64)fData.fMovieStartOffset / (Float64) PlayListUtils::eMilli; // convert to float seconds
mediaOffSet = mediaOffSet * (Float64) fData.fMovieMediaTypePtr->fTimeScale; // mediaOffset in media time scale
fData.fMediaStartOffsetMediaScale = (UInt64) mediaOffSet; // convert float time units to UInt64
fData.fLastMovieDurationSecs = fData.fRTPFilePtr->GetMovieDuration();
}
}
void MediaStream::MovieEnd(SInt64 endTime)
{
fData.fMovieEndTime = endTime;
fData.fMovieMediaTypePtr = NULL;
fData.fRTPFilePtr = NULL;
}
SInt16 MediaStream::Accounting(RTpPacket *packetPtr)
{
SInt16 result = -1;
fData.fBytesSent += packetPtr->fLength;
fData.fPacketsSent ++;
UInt32 lastTime = fData.fTimeStamp;
unsigned char payload;
packetPtr->GetHeaderInfo(&fData.fTimeStamp, &fData.fLastSequenceNumber, &fData.fSsrc, &payload);
fData.fLastTimeStampOffset = fData.fTimeStamp - lastTime;
result = 0;
return result;
}
SInt16 MediaStream::Send(RTpPacket *packetPtr)
{
SInt16 result = -1;
do
{
if (fData.fMovieMediaTypePtr == NULL) break;
UpdatePacketInStream(packetPtr);
result = Accounting(packetPtr);
if (result) break;
if (fSend)
{ result = fData.fSocketPair->SendRTp(packetPtr->fThePacket, packetPtr->fLength);
}
}
while (false);
return result;
}
void MediaStream::ReceiveOnPorts()
{
fData.fSocketPair->RecvRTp(fData.fPortRTpReadBuff.fReadBuffer, ReceiveBuffer::kReadBufferSize, &fData.fPortRTpReadBuff.fReceiveLen);
fData.fSocketPair->RecvRTCp(fData.fPortRTCpReadBuff.fReadBuffer, ReceiveBuffer::kReadBufferSize, &fData.fPortRTCpReadBuff.fReceiveLen);
}
#if DROP_RTCP_TEST
static int numRTCPPackets = 0;
static int numStartDropPackets = 0;
#endif
int MediaStream::UpdateSenderReport(SInt64 theTime)
{
if (NULL == fData.fMovieMediaTypePtr)
return 0;
int result = 0;
SInt64 timeToSend = fData.fLastSenderReportTime + (kSenderReportIntervalInSecs * PlayListUtils::eMilli);
#if DROP_RTCP_TEST
if (theTime > timeToSend )
{
if (fData.fIsSoundStream)
{ numRTCPPackets ++;
if ( (numRTCPPackets <= numStartDropPackets + DROPCOUNT) )
{ qtss_printf("skip sound RTCP #%d time=%qd\n",numRTCPPackets, theTime / PlayListUtils::eMilli);
fData.fLastSenderReportTime = theTime;
return 0;
}
else
{ qtss_printf("send sound RTCP #%d time=%qd\n",numRTCPPackets, theTime / PlayListUtils::eMilli);
numStartDropPackets = numRTCPPackets;
}
}
}
#endif
if (theTime > timeToSend)
{
fData.fLastSenderReportTime = theTime;
UInt32* theReport = (UInt32*) fData.fSenderReportBuffer;
theReport++;
*theReport = htonl(fData.fSsrc);
theReport++;
SInt64* theNTPTimestampP = (SInt64*)theReport;
*theNTPTimestampP = OS::HostToNetworkSInt64(fData.fNTPPlayTime +
PlayListUtils::TimeMilli_To_Fixed64Secs(theTime - fData.fStreamStartTime));
theReport += 2;
*theReport = htonl(fData.fTimeStamp);
Float64 curTimeInScale = (Float64) (SInt64) PlayListUtils::Milliseconds() / (Float64) PlayListUtils::eMilli; // convert to float seconds
curTimeInScale = curTimeInScale * (Float64) fData.fMovieMediaTypePtr->fTimeScale; // curTime in media time scale
curTimeInScale +=(Float64) fData.fRTpRandomOffset;
curTimeInScale = (UInt32) ( (UInt64) curTimeInScale & (UInt64) 0xFFFFFFFF );
//qtss_printf("MediaStream::UpdateSenderReport RTCP timestamp = %"_U32BITARG_"\n",(UInt32) curTimeInScale);
*theReport = htonl((UInt32) curTimeInScale);
theReport++;
fData.fPacketCount = (UInt32) fData.fPacketsSent;
*theReport = htonl(fData.fPacketCount);
theReport++;
fData.fByteCount = (UInt32) fData.fBytesSent;
*theReport = htonl(fData.fByteCount);
theReport += 2;
*theReport = htonl(fData.fSsrc);
LogStr("Sender Report\n");
LogUInt("NTP ",(UInt32) ((*theNTPTimestampP) >> 32)," ");
LogUInt(" ",(UInt32) ((*theNTPTimestampP) & 0xFFFFFFFF), "\n" );
LogUInt("time stamp = ", fData.fTimeStamp, "\n");
LogInt("SSRC = ", fData.fSsrc, "\n");
LogUInt("Packets sent = ", fData.fPacketCount, "\n");
LogUInt("Bytes sent = ", fData.fByteCount, "\n");
LogBuffer();
result = fData.fSocketPair->SendRTCp(fData.fSenderReportBuffer, fData.fSenderReportSize);
}
return result;
}
// ************************
//
// UDPSOCKETPAIR
//
// ************************
void UDPSocketPair::Close()
{
if (fMultiCastJoined)
this->LeaveMulticast();
#ifdef __Win32__
if (fSocketRTp != 0) ::closesocket(fSocketRTp);
if (fSocketRTCp != 0) ::closesocket(fSocketRTCp);
#else
if (fSocketRTp != 0) ::close(fSocketRTp);
if (fSocketRTCp != 0) ::close(fSocketRTCp);
#endif
fSocketRTp = 0;
fSocketRTCp = 0;
}
SInt16 UDPSocketPair::Open()
{
SInt16 result = 0;
do
{
Close();
fSocketRTp = ::socket(PF_INET, SOCK_DGRAM, 0);
if (fSocketRTp == kInvalidSocket)
{ result = kInvalidSocket;
break;
}
fSocketRTCp = ::socket(PF_INET, SOCK_DGRAM, 0);
if (fSocketRTCp == kInvalidSocket)
{ result = kInvalidSocket;
break;
}
#ifdef __Win32__
u_long one = 1;
(void)::ioctlsocket(fSocketRTp, FIONBIO, &one);
(void)::ioctlsocket(fSocketRTCp, FIONBIO, &one);
#else
int flag;
int val;
flag = ::fcntl(fSocketRTp, F_GETFL, 0);
val = ::fcntl(fSocketRTp, F_SETFL, flag | O_NONBLOCK);
if( val < 0 ) { result = -1; break; }
flag = ::fcntl(fSocketRTCp, F_GETFL, 0);
val = ::fcntl(fSocketRTCp, F_SETFL, flag | O_NONBLOCK);
if( val < 0 ) { result = -1; break; }
#endif
} while (false);
if (result != 0)
{ if (fSocketRTp != 0) ::close(fSocketRTp);
if (fSocketRTCp != 0) ::close(fSocketRTCp);
fSocketRTp = 0;
fSocketRTCp = 0;
}
return result;
}
void UDPSocketPair::InitPorts(UInt32 addr)
{
::memset(&fLocalAddrRTp, 0, sizeof(fLocalAddrRTp));
fLocalAddrRTp.sin_family = PF_INET;
fLocalAddrRTp.sin_port = htons(0);
fLocalAddrRTp.sin_addr.s_addr = htonl(addr);
::memset(&fLocalAddrRTCp, 0, sizeof(fLocalAddrRTCp));
fLocalAddrRTCp.sin_family = PF_INET;
fLocalAddrRTCp.sin_port = htons(0);
fLocalAddrRTCp.sin_addr.s_addr = htonl(addr);
::memset(&fDestAddrRTp, 0, sizeof(fDestAddrRTp));
fDestAddrRTp.sin_family = PF_INET;
fDestAddrRTp.sin_port = htons(0);
fDestAddrRTp.sin_addr.s_addr = htonl(addr);
::memset(&fDestAddrRTCp, 0, sizeof(fDestAddrRTCp));
fDestAddrRTCp.sin_family = PF_INET;
fDestAddrRTCp.sin_port = htons(0);
fDestAddrRTCp.sin_addr.s_addr = htonl(addr);
}
SInt16 UDPSocketPair::Bind(UInt32 addr)
{
int err = -1;
if ( (fSocketRTp == kInvalidSocket) || (fSocketRTCp == kInvalidSocket) )
return -1;
InitPorts(addr);
UInt32 PortRTp = eSourcePortStart;
UInt32 PortRTCp = PortRTp + 1; // keep them together for clarity
for (int count = eSourcePortStart; count < eSourcePortRange; count ++)
{
PortRTp = count;
Assert( (PortRTp & 1) == 0); // must be even
count += 1;
PortRTCp = count;
Assert( (PortRTCp & 1) == 1);// must be odd and one more than rtp port
fLocalAddrRTp.sin_port = htons( (UInt16) PortRTp);
fLocalAddrRTCp.sin_port = htons( (UInt16) PortRTCp);
//qtss_printf("Attempting to bind to rtp port %d \n",PortRTp);
err = ::bind(fSocketRTp, (sockaddr *)&fLocalAddrRTp, sizeof(fLocalAddrRTp));
if (err != 0)
{
//qtss_printf("UDPSocketPair::Bind Error binding to rtp port %d \n",PortRTp);
InitPorts(addr);
continue;
}
err = ::bind(fSocketRTCp, (sockaddr *)&fLocalAddrRTCp, sizeof(fLocalAddrRTCp));
if (err != 0)
{
//qtss_printf("UDPSocketPair::Bind Error binding to rtcp port %d \n",PortRTp);
Close();
Open();
InitPorts(addr);
continue;
}
if (err == 0)
{
//qtss_printf("Bound to rtp port = %d, rtcp port = %d \n",PortRTp, PortRTCp);
fState |= kBound;
break;
}
}
return err;
}
SInt16 UDPSocketPair::SendTo(int socket, sockaddr *destAddrPtr, char* inBuffer, UInt32 inLength )
{
SInt16 result = -1;
do
{
if (inBuffer == NULL) break;
if (destAddrPtr == NULL) break;
if (socket == kInvalidSocket) break;
//qtss_printf("Sending data to %d. Addr = %d inLength = %d\n", ntohs(theAddr->sin_port), ntohl(theAddr->sin_addr.s_addr), inLength);
::sendto(socket, inBuffer, inLength, 0, destAddrPtr, sizeof(sockaddr));
result = 0;
} while (false);
//if (result != 0) qtss_printf("UDP SENDTO ERROR!\n");
return result;
}
SInt16 UDPSocketPair::SendRTp(char* inBuffer, UInt32 inLength)
{
if (fBroadcasterSession != NULL)
{ OSMutexLocker locker(fBroadcasterSession->GetMutex());
return (SInt16) fBroadcasterSession->SendPacket(inBuffer,inLength,fChannel);
}
else
return SendTo(fSocketRTp, (sockaddr*)&fDestAddrRTp, inBuffer, inLength );
}
SInt16 UDPSocketPair::SendRTCp(char* inBuffer, UInt32 inLength)
{
if (fBroadcasterSession != NULL)
{ OSMutexLocker locker(fBroadcasterSession->GetMutex());
return (SInt16) fBroadcasterSession->SendPacket(inBuffer,inLength,fChannel+1);
}
else
return SendTo(fSocketRTCp, (sockaddr*)&fDestAddrRTCp, inBuffer, inLength );
}
SInt16 UDPSocketPair::SetDestination (char *destAddress,UInt16 destPortRTp, UInt16 destPortRTCp)
{
SInt16 result = -1;
if (destAddress != NULL)
{ UInt32 netAddress = inet_addr(destAddress);
fDestAddrRTp = fLocalAddrRTp;
fDestAddrRTp.sin_port = htons(destPortRTp);
fDestAddrRTp.sin_addr.s_addr = netAddress;
fDestAddrRTCp = fLocalAddrRTCp;
fDestAddrRTCp.sin_port = htons(destPortRTCp);
fDestAddrRTCp.sin_addr.s_addr = netAddress;
fIsMultiCast = SocketUtils::IsMulticastIPAddr(ntohl(netAddress));
result = 0;
}
return result;
}
SInt16 UDPSocketPair::SetMulticastInterface()
{
// set the outgoing interface for multicast datagrams on this socket
in_addr theLocalAddr;
::memset(&theLocalAddr, 0, sizeof(theLocalAddr));
theLocalAddr.s_addr = fLocalAddrRTp.sin_addr.s_addr;
int err = setsockopt(fSocketRTp, IPPROTO_IP, IP_MULTICAST_IF, (char*)&theLocalAddr, sizeof(theLocalAddr));
return err;
}
SInt16 UDPSocketPair::JoinMulticast()
{
int err = 0;
UInt32 localAddr = fLocalAddrRTp.sin_addr.s_addr; // Already in network byte order
#if __solaris__
if( localAddr == htonl(INADDR_ANY) )
localAddr = htonl(SocketUtils::GetIPAddr(0));
#endif
struct ip_mreq theMulti;
::memset(&theMulti, 0, sizeof(theMulti));
theMulti.imr_multiaddr.s_addr = fDestAddrRTp.sin_addr.s_addr;
theMulti.imr_interface.s_addr = localAddr;
err = setsockopt(fSocketRTp, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
(void) setsockopt(fSocketRTCp, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
if (err == 0)
fMultiCastJoined = true;
return err;
}
SInt16 UDPSocketPair::SetTTL(SInt16 timeToLive)
{
// set the ttl
int nOptVal = (int)timeToLive;
int err = 0;
err = setsockopt(fSocketRTp, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
if (err != 0) return err;
err = setsockopt(fSocketRTCp, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
return err;
}
SInt16 UDPSocketPair::LeaveMulticast()
{
UInt32 localAddr = fLocalAddrRTp.sin_addr.s_addr; // Already in network byte order
#if __solaris__
if( localAddr == htonl(INADDR_ANY) )
localAddr = htonl(SocketUtils::GetIPAddr(0));
#endif
struct ip_mreq theMulti;
::memset(&theMulti, 0, sizeof(theMulti));
theMulti.imr_multiaddr.s_addr = fDestAddrRTp.sin_addr.s_addr;
theMulti.imr_interface.s_addr = localAddr;
int err = setsockopt(fSocketRTp, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
(void) setsockopt(fSocketRTCp, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
return err;
}
SInt16 UDPSocketPair::RecvFrom(sockaddr *RecvRTpddrPtr, int socket, char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
{
SInt16 result = -1;
do
{
if (ioBuffer == NULL) break;
if (RecvRTpddrPtr == NULL) break;
if (socket == kInvalidSocket) break;
sockaddr_in theAddr;
#if __Win32__ || __osf__ || __sgi__ || __hpux__
int addrLen = sizeof(theAddr);
#else
socklen_t addrLen = sizeof(theAddr);
#endif
SInt32 theRecvLen = ::recvfrom(socket, ioBuffer, inBufLen, 0, (sockaddr*)&theAddr, &addrLen);
if (theRecvLen == -1) break;
if (outRecvLen) *outRecvLen = (UInt32)theRecvLen;
} while (false);
return result;
}
SInt16 UDPSocketPair::RecvRTp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
{
return RecvFrom( (sockaddr *)&fDestAddrRTp, fSocketRTp, ioBuffer, inBufLen, outRecvLen);
}
SInt16 UDPSocketPair::RecvRTCp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
{
return RecvFrom( (sockaddr *)&fDestAddrRTCp, fSocketRTCp, ioBuffer, inBufLen, outRecvLen);
}
SInt16 UDPSocketPair::SetMultiCastOptions(SInt16 ttl)
{
SInt16 err = 0;
if (this->fIsMultiCast) do// set by SetDestination
{
err = this->SetTTL(ttl);
WarnV(err == 0 , "failed to set ttl");
if (err != 0) break;
err = this->SetMulticastInterface();
WarnV(err == 0 , "failed to set multicast socket option");
if (err != 0) break;
err = this->JoinMulticast();
WarnV(err == 0 , "failed to join multicast");
if (err != 0) break;
} while (false);
return err;
}
SInt16 UDPSocketPair::OpenAndBind( UInt16 rtpPort,UInt16 rtcpPort,char *destAddress)
{
SInt16 err = -1;
do
{
err = this->Open();
if (err != 0) break;
err = this->Bind(INADDR_ANY);
if (err != 0) break;
err = this->SetDestination (destAddress, rtpPort, rtcpPort);
if (err != 0) break;
} while (false);
if (err)
{
this->Close();
}
return err;
};
// ************************
//
// RTpPacket
//
// ************************
SInt16 RTpPacket::GetSoundDescriptionRef(SoundDescription **soundDescriptionPtr)
{
SInt16 result = -1;
if (fThePacket && soundDescriptionPtr)
{
SInt32 minSoundLength = sizeof(SoundHeader) + sizeof(SoundDescription) + kRTpHeaderSize;
if ( fLength >= minSoundLength )
{
char *offsetPtr = fThePacket + kRTpHeaderSize + sizeof(SoundHeader);
*soundDescriptionPtr = (SoundDescription *) offsetPtr;
SInt32 descSize = ntohl( (**soundDescriptionPtr).descSize);
fSoundDescriptionLen = descSize;
result = 0;
}
}
return result;
}
bool RTpPacket::HasSoundDescription()
{
bool result = false;
if (fThePacket)
{
// WritePacketToLog(fThePacket, fLength);
SInt32 minSoundLength = sizeof(SoundHeader) + sizeof(SoundDescription) + kRTpHeaderSize;
if (fLength >= minSoundLength )
{
char *offsetPtr = fThePacket + kRTpHeaderSize;
SoundHeader* testHeaderPtr = (SoundHeader*) offsetPtr;
do
{
if (testHeaderPtr->bytes[0] != 0x17) break;
if (testHeaderPtr->sndtype[0] != 's') break;
if (testHeaderPtr->sndtype[1] != 'o') break;
if (testHeaderPtr->sndtype[2] != 'u') break;
if (testHeaderPtr->sndtype[3] != 'n') break;
fHasSoundDescription = result = true;
} while (false);
}
if (result)
{
LogStr("has sound description soun\n");
}
PrintLogBuffer(true);
}
return result;
}
SInt16 RTpPacket::GetHeaderInfo(UInt32 *timeStampPtr, UInt16 *sequencePtr,UInt32 *SSRCPtr, unsigned char*payloadTypeAndMarkPtr)
{
SInt16 result = -1;
unsigned char *header8Ptr = (unsigned char *) fThePacket;
UInt16* header16Ptr = (UInt16*)fThePacket;
UInt32* header32Ptr = (UInt32*)fThePacket;
if (fThePacket && timeStampPtr && sequencePtr && SSRCPtr && payloadTypeAndMarkPtr)
{
*payloadTypeAndMarkPtr = header8Ptr[cPayloadType];
*sequencePtr = ntohs(header16Ptr[cSequenceNumber]);
*timeStampPtr = ntohl(header32Ptr[cTimeStamp]);
*SSRCPtr = ntohl(header32Ptr[cSSRC]);
result = 0;
}
return result;
}
SInt16 RTpPacket::SetHeaderInfo(UInt32 timeStamp, UInt16 sequence, UInt32 SSRC, unsigned char payloadTypeAndMark)
{
SInt16 result = -1;
unsigned char *header8Ptr = (unsigned char *) fThePacket;
UInt16* header16Ptr = (UInt16*)fThePacket;
UInt32* header32Ptr = (UInt32*)fThePacket;
if (fThePacket)
{
LogInt("sequence = ", sequence, " ");
LogUInt("time = ", timeStamp, " ");
// LogUInt("old payload = ",( UInt32 ) (header8Ptr[cPayloadType] & 0x7F)," ");
LogUInt("payload = ",( UInt32 ) (payloadTypeAndMark & 0x7F) ," ");
// LogUInt("old marker = ", ( UInt32 ) (header8Ptr[cPayloadType] & 0x80) ," ");
// LogUInt("marker = ", ( UInt32 ) (payloadTypeAndMark & 0x80) ," ");
LogUInt("ssrc = ", SSRC, "\n");
header8Ptr[cPayloadType] = payloadTypeAndMark;
header16Ptr[cSequenceNumber] = htons(sequence);
header32Ptr[cTimeStamp] = htonl(timeStamp);
header32Ptr[cSSRC] = htonl(SSRC);
result = 0;
LogBuffer();
}
return result;
}

View file

@ -0,0 +1,327 @@
/*
*
* @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@
*
*/
#ifndef playlist_elements_H
#define playlist_elements_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif
#include "playlist_array.h"
#include "OSHeaders.h"
#include "playlist_SimpleParse.h"
#include "QTRTPFile.h"
#include "BroadcasterSession.h"
class MediaStream;
struct SoundDescription {
SInt32 descSize; /* total size of SoundDescription including extra data */
SInt32 dataFormat; /* sound format */
SInt32 resvd1; /* reserved for apple use. set to zero */
SInt16 resvd2; /* reserved for apple use. set to zero */
SInt16 dataRefIndex;
SInt16 version; /* which version is this data */
SInt16 revlevel; /* what version of that codec did this */
SInt32 vendor; /* whose codec compressed this data */
SInt16 numChannels; /* number of channels of sound */
SInt16 sampleSize; /* number of bits per sample */
SInt16 compressionID; /* unused. set to zero. */
SInt16 packetSize; /* unused. set to zero. */
UInt32 sampleRate; /* sample rate sound is captured at */
};
class PayLoad {
public:
PayLoad(void) : payloadID(0), timeScale(1) {};
int payloadID;
SimpleString payLoadString;
UInt32 timeScale;
};
class TypeMap {
public:
TypeMap(void) : fMediaStreamPtr(0), fTrackID(0), fPort(0), fTimeScale(1) {};
~TypeMap() { } ;
MediaStream *fMediaStreamPtr;
int fTrackID;
int fPort;
UInt32 fTimeScale;
SimpleString fTheTypeStr;
SimpleString fProtocolStr;
ArrayList<PayLoad> fPayLoadTypes;
ArrayList<SInt16> fPayLoads;
};
class RTpPacket
{
struct SoundHeader {
char bytes[4];
SInt32 skip1;
char sndtype[4];
SInt32 skip2;
char test[4];
};
public:
enum { kRTpHeaderSize = 12 };
char *fThePacket;
int fLength;
bool fHasSoundDescription;
SInt32 fSoundDescriptionLen;
RTpPacket() : fThePacket(NULL), fLength(0), fHasSoundDescription(false), fSoundDescriptionLen(0) {};
void SetPacketData(char *thePacket, int length) {fThePacket = thePacket; fLength = length; };
SInt16 SetHeaderInfo( UInt32 timeStamp, UInt16 sequence,UInt32 SSRC,unsigned char payloadType);
SInt16 GetHeaderInfo( UInt32 *timeStampPtr, UInt16 *sequencePtr,UInt32 *SSRCPtr,unsigned char*payloadType);
bool HasSoundDescription();
SInt16 GetSoundDescriptionRef(SoundDescription **soundDescriptionPtr);
protected:
enum { cSequenceNumber = 1, cTimeStamp = 1, cSSRC = 2, cPayloadType = 1};
};
class UDPSocketPair
{
public:
enum
{
kBound = 1L << 0,
kConnected = 1L << 1
};
enum { eBindMaxTries = 100,
eSourcePortStart = 49152, // rtp + rtcp
eSourcePortRange = 65535 // 49152,49153 - 65534,65535
};
enum
{
kInvalidSocket = -1, //int
kPortRTCpufSizeInBytes = 8, //UInt32
kMaxIPAddrSizeInBytes = 20 //UInt32
};
int fMaxBindAttempts;
int fState;
int fSocketRTp;
struct sockaddr_in fLocalAddrRTp;
struct sockaddr_in fDestAddrRTp;
int fSocketRTCp;
struct sockaddr_in fLocalAddrRTCp;
struct sockaddr_in fDestAddrRTCp;
BroadcasterSession *fBroadcasterSession;
UInt8 fChannel;
Bool16 fIsMultiCast;
Bool16 fMultiCastJoined;
UDPSocketPair() : fMaxBindAttempts(eBindMaxTries),
fState(0),
fSocketRTp(0),
fSocketRTCp(0),
fBroadcasterSession(NULL),
fChannel(0),
fIsMultiCast(false),
fMultiCastJoined(false)
{};
~UDPSocketPair() { Close(); };
SInt16 Open();
void Close();
void InitPorts(UInt32 addr);
SInt16 Bind(UInt32 addr);
SInt16 OpenAndBind( UInt16 rtpPort,UInt16 rtcpPort,char *destAddress);
SInt16 SetDestination (char *destAddress,UInt16 destPortRTp, UInt16 destPortRTCp);
SInt16 SetTTL(SInt16 timeToLive);
SInt16 JoinMulticast();
SInt16 LeaveMulticast();
SInt16 SetMulticastInterface();
SInt16 SetMultiCastOptions(SInt16 ttl);
SInt16 SendTo(int socket, sockaddr *destAddrPtr, char* inBuffer, UInt32 inLength );
SInt16 SendRTp(char* inBuffer, UInt32 inLength);
SInt16 SendRTCp(char* inBuffer, UInt32 inLength);
SInt16 RecvFrom(sockaddr *recvAddrPtr, int socket, char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
SInt16 RecvRTp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
SInt16 RecvRTCp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
void SetRTSPSession(BroadcasterSession *theSession,UInt8 channel) {fBroadcasterSession = theSession, fChannel=channel;}
};
class ReceiveBuffer
{
public:
enum { kReadBufferSize = 256 }; //UInt32
char fReadBuffer[kReadBufferSize];
UInt32 fReceiveLen;
};
class MediaStream
{
protected:
int SendRTp(RTpPacket *packet);
int CalcRTCps();
int SendRTCp_SenderReport();
static UInt32 GetACName(char* ioCNameBuffer);
void MapToStream(UInt32 curRTpTimeStamp, UInt16 curRTpSequenceNumber, unsigned char curPayload, UInt32 *outRTpTimeStampPtr, UInt16 *outRTpSequenceNumberPtr, unsigned char *outPayloadPtr);
void UpdatePacketInStream(RTpPacket *packetPtr);
SInt16 Accounting(RTpPacket *packetPtr);
void BuildStaticRTCpReport();
void InitIfAudio();
void TestAndIncSoundDescriptor(RTpPacket *packetPtr);
public:
enum { kMaxCNameLen = 20 }; //UInt32
enum { eMaxSoundDescriptionSize = 1024};
enum {
kSenderReportSizeInBytes = 36, //UInt32
kMaxRTCpPacketSizeInBytes = 1024, //All are UInt32s
kMaxSsrcSizeInBytes = 25,
kSenderReportIntervalInSecs = 5
};
enum {
eSocketNotOpen,
eSocketFailed
};
struct MemberData {
ReceiveBuffer fPortRTpReadBuff;
ReceiveBuffer fPortRTCpReadBuff;
UInt64 fRTCpTimer;
SInt16 fState;
UInt64 fBytesSent;
UInt64 fPacketsSent;
SInt64 fStreamStartTime;
SInt64 fNTPPlayTime;
char fSenderReportBuffer[kSenderReportSizeInBytes + kMaxCNameLen];
UInt32 fSenderReportSize;
//who am i sending to?
UInt16 fRemoteRTpPort;
UInt16 fRemoteRTCpPort;
//RTCp stuff
SInt64 fLastSenderReportTime;
UInt32 fPacketCount;
UInt32 fByteCount;
Bool16 fSenderReportReady;
UInt32 fLastTimeStamp;
// current RTP packet info
UInt32 fLastTimeStampOffset;
UInt32 fTimeStamp;
UInt32 fSsrc;
UInt16 fLastSequenceNumber;
UInt32 fInitSSRC; // initial SSRC
UInt64 fCurStreamRTpSequenceNumber; // now
TypeMap *fStreamMediaTypePtr;
TypeMap *fMovieMediaTypePtr;
SInt64 fMovieStartTime;
SInt64 fMovieEndTime;
Float64 fLastMovieDurationSecs;
UInt64 fMediaStartOffsetMediaScale;
UInt64 fMovieStartOffset;
UInt32 fSeqRandomOffset;
UInt32 fRTpRandomOffset;
bool fNewMovieStarted;
bool fNewStreamStarted;
bool fIsSoundStream;
bool fIsVideoStream;
char *fSoundDescriptionBuffer;
SInt32 fSavedSoundDescSize;
SInt16 fSavedDataRefIndex;
UDPSocketPair *fSocketPair;
QTRTPFile *fRTPFilePtr;
};
MemberData fData;
bool fSend;
~MediaStream();
MediaStream();
char* GetRTCpSR() { return fData.fSenderReportBuffer; }
UInt32 GetRTCpSRLen() { return fData.fSenderReportSize; }
SInt64 GetPlayTime() { return fData.fStreamStartTime; }
SInt64 GetNTPPlayTime() { return fData.fNTPPlayTime; }
SInt16 Send(RTpPacket *packetPtr);
void ReceiveOnPorts();
int UpdateSenderReport(SInt64 theTime);
void StreamStart(SInt64 startTime);
void MovieStart(SInt64 startTime);
void MovieEnd(SInt64 endTime);
};
#endif // playlist_elements_H

View file

@ -0,0 +1,115 @@
/*
*
* @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@
*
*/
#include "playlist_lists.h"
#include "OS.h"
#include "playlist_utils.h"
// ************************
//
// MEDIA STREAM LIST
//
// ************************
void MediaStreamList::SetUpStreamSSRCs()
{
UInt32 ssrc;
MediaStream* setMediaStreamPtr;
MediaStream* aMediaStreamPtr;
bool found_duplicate;
for (int i = 0; i < Size(); i++)
{
setMediaStreamPtr = SetPos(i);
if (setMediaStreamPtr != NULL) do
{
ssrc = PlayListUtils::Random() + ( (UInt32) OS::Milliseconds() ); // get a new ssrc
aMediaStreamPtr = Begin(); // start at the beginning of the stream list
found_duplicate = false; // default is don't loop
while (aMediaStreamPtr != NULL) //check all the streams for a duplicate
{
if (aMediaStreamPtr->fData.fInitSSRC == ssrc) // it is a duplicate
{ found_duplicate = true; // set to loop: try a new ssrc
break;
}
aMediaStreamPtr = Next(); // keep checking for a duplicate
}
if (!found_duplicate) // no duplicates found so keep this ssrc
setMediaStreamPtr->fData.fInitSSRC = ssrc;
} while (found_duplicate); // we have a duplicate ssrc so find another one
}
}
void MediaStreamList::StreamStarted(SInt64 startTime)
{
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->StreamStart(startTime);
}
}
void MediaStreamList::MovieStarted(SInt64 startTime)
{
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->MovieStart(startTime);
}
}
void MediaStreamList::MovieEnded(SInt64 endTime)
{
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->MovieEnd(endTime);
}
}
SInt16 MediaStreamList::UpdateStreams()
{
SInt16 err = 0;
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->ReceiveOnPorts();
};
return err;
}
void MediaStreamList::UpdateSenderReportsOnStreams()
{
SInt64 theTime = PlayListUtils::Milliseconds();
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
(void) theStreamPtr->UpdateSenderReport(theTime);
};
}

View file

@ -0,0 +1,91 @@
/*
*
* @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@
*
*/
#ifndef playlist_lists_H
#define playlist_lists_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/types.h>
#include <fcntl.h>
#endif
#include "OSHeaders.h"
#include "playlist_array.h"
#include "playlist_elements.h"
#include "playlist_utils.h"
// ************************
//
// SOCKET LIST
//
// ************************
class SocketList : public ArrayList<UDPSocketPair> {
};
// ************************
//
// MEDIA STREAM LIST
//
// ************************
class MediaStreamList : public ArrayList<MediaStream> {
protected:
public:
SInt16 UpdateStreams();
void UpdateSenderReportsOnStreams();
void SetUpStreamSSRCs();
void StreamStarted(SInt64 startTime);
void MovieStarted(SInt64 startTime);
void MovieEnded(SInt64 endTime);
};
// ************************
//
// SDP MEDIA LIST
//
// ************************
class SDPMediaList : public ArrayList<TypeMap> {
};
#endif //playlist_lists_H

View file

@ -0,0 +1,540 @@
/*
*
* @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@
*
*/
#include "playlist_parsers.h"
char* SDPFileParser::sMediaTag = "m";
char* SDPFileParser::sAttributeTag = "a";
char* SDPFileParser::sConnectionTag = "c";
SDPFileParser::~SDPFileParser()
{
if (fSDPBuff)
{ delete[] fSDPBuff;
fSDPBuff = NULL;
}
}
bool SDPFileParser::IsCommented(SimpleString *theString)
{
if ( NULL == theString) return false;
if ( theString->fLen == 0) return false;
if ( theString->fTheString[0] == '#' ) return true; // It's commented if the first non-white char is #
return false;
}
int TextLine::Parse (SimpleString *textStrPtr)
{
short count = 0;
do
{
if (!textStrPtr) break;
count = CountDelimeters(textStrPtr,sWordDelimeters);
if (count < 1) break;
fWords.SetSize(count);
fSource = *textStrPtr;
SimpleString *listStringPtr = fWords.Begin();
SimpleString currentString;
currentString.SetString(textStrPtr->fTheString, 0);
for ( short i = 0; i < count; i ++)
{ GetNextThing(textStrPtr,&currentString, sWordDelimeters, &currentString);
*listStringPtr = currentString;
listStringPtr++;
}
} while (false);
return count;
}
int LineAndWordsParser::Parse (SimpleString *textStrPtr)
{
short count = 0;
do
{
if (!textStrPtr) break;
count = CountDelimeters(textStrPtr,sLineDelimeters);
if (count < 1) break;
fLines.SetSize(count);
fSource = *textStrPtr;
TextLine *listStringPtr = fLines.Begin();
SimpleString currentString;
currentString.SetString(textStrPtr->fTheString, 0);
for ( short i = 0; i < count; i ++)
{ GetNextThing(textStrPtr,&currentString, sLineDelimeters, &currentString);
listStringPtr->Parse(&currentString);
listStringPtr++;
}
} while (false);
return count;
}
short SDPFileParser::CountQTTextLines()
{
short numlines = 0;
TextLine *theLinePtr = fParser.fLines.Begin();
while (theLinePtr)
{ if (GetQTTextFromLine(theLinePtr))
numlines ++;
theLinePtr = fParser.fLines.Next();
};
return numlines;
}
short SDPFileParser::CountMediaEntries()
{
bool commented = false;
bool isEqual = false;
short numTracks = 0;
TextLine *theLinePtr = fParser.fLines.Begin();
SimpleString *firstWordPtr;
while (theLinePtr)
{
do
{ firstWordPtr = theLinePtr->fWords.Begin();
if (!firstWordPtr) break;
commented = IsCommented(firstWordPtr);
if (commented) break;
isEqual = Compare(firstWordPtr, SDPFileParser::sMediaTag, true);
if (!isEqual) break;
numTracks ++;
} while (false);
theLinePtr = fParser.fLines.Next();
};
return numTracks;
}
short SDPFileParser::CountRTPMapEntries()
{
short startPos = fParser.fLines.GetPos();
short result = 0;
TextLine *theLinePtr = fParser.fLines.Get();
SimpleString mapString("rtpmap");
SimpleString *aWordPtr;
bool isEqual;
while (theLinePtr)
{
aWordPtr = theLinePtr->fWords.Begin();
if (aWordPtr)
{
isEqual = Compare(aWordPtr, SDPFileParser::sAttributeTag, true);
if (isEqual) // see if this attribute is a rtpmap line
{
aWordPtr = theLinePtr->fWords.SetPos(1);
isEqual = Compare(aWordPtr, &mapString, false);
if (isEqual) result ++;
}
else // could be a comment or some other attribute
{ isEqual = Compare(aWordPtr, SDPFileParser::sMediaTag, true);
if (isEqual) break; // its another media line so stop
}
}
theLinePtr = fParser.fLines.Next();
};
fParser.fLines.SetPos(startPos);
return result;
}
void SDPFileParser::GetPayLoadsFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr)
{
short count = 0;
if (theLinePtr == NULL || theTypeMapPtr == NULL)
return;
SimpleString *aWordPtr = theLinePtr->fWords.SetPos(5);// get protocol ID str
while (aWordPtr)
{ count ++;
aWordPtr = theLinePtr->fWords.Next();// get next protocol ID str
}
theTypeMapPtr->fPayLoads.SetSize(count);
short* idPtr = theTypeMapPtr->fPayLoads.Begin();// get protocol ID ref
aWordPtr = theLinePtr->fWords.SetPos(5);// get protocol ID str
while (aWordPtr && idPtr)
{
*idPtr = (short) aWordPtr->GetInt();
aWordPtr = theLinePtr->fWords.Next();// get next protocol ID str
idPtr = theTypeMapPtr->fPayLoads.Next();// get next protocol ID ref
}
}
bool SDPFileParser::GetQTTextFromLine(TextLine *theLinePtr)
{
//a=x-qt-text-cpy:xxxxx
//a=x-qt-text-nam:xxxxxx
//a=x-qt-text-inf:xxxxxxx
bool result = false;
SimpleString *aWordPtr;
char *xString ="a=x-qt-text";
do
{
aWordPtr = theLinePtr->fWords.Begin();
if (!aWordPtr) break;
bool isEqual = (0 == strncmp(aWordPtr->fTheString, xString,strlen(xString) ) ) ? true: false;
if (!isEqual) break;
result = true;
} while (false);
return result;
}
bool SDPFileParser::GetMediaFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr)
{
bool result = false;
SimpleString *aWordPtr;
do
{
aWordPtr = theLinePtr->fWords.Begin();
if (!aWordPtr) break;
bool isEqual = Compare(aWordPtr, SDPFileParser::sMediaTag, true);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(1);// get type
if (!aWordPtr) break;
theTypeMapPtr->fTheTypeStr = *aWordPtr;
aWordPtr = theLinePtr->fWords.SetPos(2);// get movie port
if (!aWordPtr) break;
theTypeMapPtr->fPort = aWordPtr->GetInt();
aWordPtr = theLinePtr->fWords.SetPos(3);// get protocol
if (!aWordPtr) break;
theTypeMapPtr->fProtocolStr = *aWordPtr;
GetPayLoadsFromLine(theLinePtr, theTypeMapPtr);
result = true;
} while (false);
return result;
}
bool SDPFileParser::GetRTPMap(TextLine *theLinePtr,PayLoad *payloadPtr)
{
bool lineOK = false;
SimpleString *aWordPtr;
SimpleString mapString("rtpmap");
do
{
if (!theLinePtr || !payloadPtr) break;
aWordPtr = theLinePtr->fWords.SetPos(1); // the attribute name
if (!aWordPtr) break;
if (!Compare(aWordPtr, &mapString, false))
break;
aWordPtr = theLinePtr->fWords.Next(); // the Payload ID
if (!aWordPtr) break;
payloadPtr->payloadID = aWordPtr->GetInt();
aWordPtr = theLinePtr->fWords.Next(); // the Payload type string
if (!aWordPtr) break;
payloadPtr->payLoadString = *aWordPtr;
payloadPtr->timeScale = 0;
aWordPtr = theLinePtr->fWords.Next(); // the Payload timeScale
if (aWordPtr)
payloadPtr->timeScale = aWordPtr->GetInt();
lineOK = true;
} while (false);
return lineOK;
}
TextLine *SDPFileParser::GetRTPMapLines(TextLine *theLinePtr,TypeMap *theTypeMapPtr)
{
do
{
if (!theLinePtr || !theTypeMapPtr) break;
short numAttributes = CountRTPMapEntries();
theTypeMapPtr->fPayLoadTypes.SetSize(numAttributes);
PayLoad *payloadPtr = theTypeMapPtr->fPayLoadTypes.Begin();
while( theLinePtr && payloadPtr && (numAttributes > 0) )
{
bool haveMAP = GetRTPMap(theLinePtr,payloadPtr);
if (haveMAP)
{ numAttributes --;
payloadPtr = theTypeMapPtr->fPayLoadTypes.Next(); //skip to next payload entry
}
theLinePtr = fParser.fLines.Next(); // skip to next line
if(theLinePtr == NULL || Compare(theLinePtr->fWords.Begin(), SDPFileParser::sMediaTag, true)) //stop checking if this is a new media line
break;
}
} while (false);
return theLinePtr;
}
TextLine * SDPFileParser::GetTrackID(TextLine *theLinePtr,TypeMap *theTypeMapPtr)
{
SimpleString *aFieldPtr;
SimpleString *aWordPtr;
Bool16 foundID = false;
while(theLinePtr && !foundID)
{
if(Compare(theLinePtr->fWords.Begin(), SDPFileParser::sMediaTag, true)) //stop checking if this is a new media line
break;
do
{
SimpleString controlString("control");
aFieldPtr = theLinePtr->fWords.Begin();
if (!aFieldPtr) break;
bool isEqual = Compare(aFieldPtr, SDPFileParser::sAttributeTag, true);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(1);
if (!aWordPtr) break;
isEqual = Compare(aWordPtr, &controlString, false);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(3);
if (!aWordPtr) break;
theTypeMapPtr->fTrackID = aWordPtr->GetInt();
foundID = true;
} while (false);
theLinePtr = fParser.fLines.Next();
}
return theLinePtr;
}
bool SDPFileParser::ParseIPString(TextLine *theLinePtr)
{
bool result = false;
SimpleString *aWordPtr;
do
{
SimpleString ipIDString("IP4");
aWordPtr = theLinePtr->fWords.Begin();
if (!aWordPtr) break;
bool isEqual = Compare(aWordPtr,SDPFileParser::sConnectionTag, true);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(2);
if (!aWordPtr) break;
isEqual = Compare(aWordPtr, &ipIDString, false);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(3);
if (!aWordPtr) break;
fIPAddressString.SetString(aWordPtr->fTheString, aWordPtr->fLen);
result = true;
} while (false);
return result;
}
SInt32 SDPFileParser::ParseSDP(char *theBuff)
{
SInt32 result = 0;
bool found = false;
SimpleString source(theBuff);
fSource.SetString( theBuff, strlen(theBuff) );
fParser.Parse(&source);
// Test parse
#if 0
qtss_printf("-----------------------------------------------------\n");
char tempString[256];
TextLine *theLine = fParser.fLines.Begin();
while (theLine)
{ SimpleString *theWord = theLine->fWords.Begin();
while (theWord)
{ theWord->GetString(tempString,256);
qtss_printf(tempString);
theWord = theLine->fWords.Next();
if (theWord) qtss_printf(" _ ");
}
theLine = fParser.fLines.Next();
qtss_printf("\n");
}
// exit (0);
#endif
fNumQTTextLines = CountQTTextLines();
fQTTextLines.SetSize( (SInt16) fNumQTTextLines);
SimpleString *theQTTextPtr = fQTTextLines.Begin();
fNumTracks = CountMediaEntries();
fSDPMediaList.SetSize((SInt16) fNumTracks);
TextLine *theLinePtr = fParser.fLines.Begin();
TypeMap *theTypeMapPtr = fSDPMediaList.Begin();
bool foundIP = false;
while (theLinePtr && theTypeMapPtr)
{
if (foundIP == false)
{ foundIP = ParseIPString(theLinePtr);
}
if (theQTTextPtr && GetQTTextFromLine(theLinePtr))
{ SimpleString *srcLinePtr = theLinePtr->fWords.Begin();
theQTTextPtr->SetString(srcLinePtr->fTheString, strcspn(srcLinePtr->fTheString, "\r\n") );
theQTTextPtr = fQTTextLines.Next();
}
found = GetMediaFromLine(theLinePtr, theTypeMapPtr);
if (found)
{
theLinePtr = fParser.fLines.Next();
if (!theLinePtr) break; // no more lines to process
int startLine = fParser.fLines.GetPos();
theLinePtr = fParser.fLines.SetPos(startLine);
(void) GetRTPMapLines(theLinePtr,theTypeMapPtr);
theLinePtr = fParser.fLines.SetPos(startLine);
(void) GetTrackID(theLinePtr,theTypeMapPtr);
theLinePtr = fParser.fLines.SetPos(startLine);
theTypeMapPtr = fSDPMediaList.Next();
continue;
}
theLinePtr = fParser.fLines.Next();
}
return result;
}
SInt32 SDPFileParser::ReadSDP(char *filename)
{
int result = -1;
SInt32 bytes= 0;
FILE *f = NULL;
if (fSDPBuff != NULL)
{ delete[] fSDPBuff;
fSDPBuff = NULL;
}
do
{
f = ::fopen(filename, "r");
if (f == NULL) break;
result = 1;
result = ::fseek(f, 0, SEEK_SET);
if (result != 0) break;
fSDPBuff = new char[cMaxBytes + 1];
if (NULL == fSDPBuff) break;
fSDPBuff[cMaxBytes] = 0;
bytes = ::fread(fSDPBuff, sizeof(char), cMaxBytes, f);
if (bytes < 1) break;
fSDPBuff[bytes] = 0;
result = ParseSDP(fSDPBuff);
if (result != 0) break;
result = 0;
} while (false);
if (f != NULL)
{ ::fclose (f);
f = NULL;
}
return result;
}

View file

@ -0,0 +1,109 @@
/*
*
* @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@
*
*/
#ifndef playlist_parsers_H
#define playlist_parsers_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "playlist_elements.h"
#include "OSHeaders.h"
#include "playlist_SimpleParse.h"
#include "playlist_utils.h"
#include "playlist_lists.h"
#ifndef __Win32__
#include <sys/types.h>
#endif
class TextLine : public SimpleParser
{
public:
ArrayList<SimpleString> fWords;
int Parse (SimpleString *textStrPtr);
};
class LineAndWordsParser : public SimpleParser
{
public:
ArrayList<TextLine> fLines;
int Parse (SimpleString *textStrPtr);
};
class SDPFileParser : SimpleParser
{
public:
SDPFileParser(void) : fNumTracks(0), fSDPBuff(NULL) {}
~SDPFileParser(void);
SInt32 ReadSDP(char *theFile);
SInt32 ParseSDP(char *theBuff) ;
SInt32 GetNumTracks() {return fNumTracks;} ;
bool IsCommented(SimpleString *aLine);
TextLine* GetRTPMapLines(TextLine *theLinePtr,TypeMap *theTypeMapPtr);
bool GetRTPMap(TextLine *theLinePtr,PayLoad *payloadPtr);
bool GetMediaFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr);
void GetPayLoadsFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr);
TextLine* GetTrackID(TextLine *theLinePtr,TypeMap *theTypeMapPtr);
bool ParseIPString(TextLine *theLinePtr);
SimpleString* GetIPString() { return &fIPAddressString; };
ArrayList<SimpleString> fQTTextLines;
SInt32 GetNumQTTextLines() {return fNumQTTextLines;} ;
bool GetQTTextFromLine(TextLine *theLinePtr);
SDPMediaList fSDPMediaList;
protected:
UInt32 TimeScaleLookUp(int payLoadID, SimpleString *typeStringPtr);
short CountMediaEntries() ;
short CountRTPMapEntries() ;
short CountQTTextLines();
UInt32 fNumQTTextLines;
UInt32 fNumTracks;
LineAndWordsParser fParser;
SimpleString fIPAddressString;
private:
enum { cMaxBytes = 4096}; // maximum accepted sdp file size
static char* sMediaTag;
static char* sAttributeTag;
static char* sConnectionTag;
char *fSDPBuff;
};
#endif //playlist_parsers_H

View file

@ -0,0 +1,60 @@
/*
*
* @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@
*
*/
/*
*
* History:
* 26-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Made the header c++ friendly.
*
* 23-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Created.
*/
#ifndef _TIMESTAMP_H_
#define _TIMESTAMP_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Get a 64 bit timestamp */
extern SInt64 timestamp(void);
struct timescale {
SInt64 tsc_numerator;
SInt64 tsc_denominator;
};
/*
* Get numerator and denominator to convert value returned
* by timestamp() to microseconds
*/
extern void utimescale(struct timescale *tscp);
#ifdef __cplusplus
}
#endif
#endif /* _TIMESTAMP_H_ */

View file

@ -0,0 +1,255 @@
/*
*
* @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@
*
*/
#include "playlist_utils.h"
#include "OS.h"
#if Log_Enabled
enum {gBuffSize = 532, gBuffMaxStr = 512};
enum {switchEntries, switchTime, switchBytes};
enum {gLogMaxBytes = 100000};
enum {gLogMaxEntries = 1000};
enum {gLogMaxMilliSecs = 3 * 60 * 1000};
static int gLogSwitchSetting = switchEntries;
static SInt32 gLogEntries = 0;
static SInt64 gLogTimeStart = 0;
static SInt32 gLogNumBytes = 0;
static gLogNumPackets = 0;
static char gTempStr[256];
static FILE *gLogFile_1 = 0;
static FILE *gLogFile_2 = 0;
static FILE *gLogFileCurrent = 0;
static int gFileNum = 1;
static bool gLogStarted = false;
static char gLogBuff[gBuffSize];
static int gBuffUsed = 0;
void LogFileOpen(void)
{
if (!gLogFile_1 && !gLogFile_2)
{ gLogFile_1 = fopen("logfile_1.txt","w");
gLogFileCurrent = gLogFile_1;
*gLogBuff = 0;
gLogTimeStart = PlayListUtils::Milliseconds();
gLogStarted = true;
gLogEntries = 0;
gLogTimeStart = 0;
gLogNumBytes = 0;
gLogNumPackets = 0;
gFileNum = 1;
gBuffUsed = 0;
}
}
void LogFileClose(void)
{
fclose(gLogFile_1);
fclose(gLogFile_2);
gLogFileCurrent = gLogFile_1 = gLogFile_2 = 0;
}
bool TimeToSwitch(int len)
{
bool timeToSwitch = false;
if (!gLogStarted) return timeToSwitch;
switch( gLogSwitchSetting )
{
case switchEntries:
if (gLogEntries >= gLogMaxEntries)
{ timeToSwitch = true;
gLogEntries = 1;
}
else
gLogEntries ++;
break;
case switchTime:
{ SInt64 timeNow = PlayListUtils::Milliseconds();
SInt64 timeThisFile = timeNow - gLogTimeStart;
if ( timeThisFile > gLogMaxMilliSecs )
{ timeToSwitch = true;
gLogTimeStart = timeNow;
}
}
break;
case switchBytes:
if (gLogNumBytes > gLogMaxBytes)
{ timeToSwitch = true;
gLogNumBytes = 0;
}
gLogNumBytes += len;
break;
};
return timeToSwitch;
}
void WriteToLog(void *data, int len)
{
if (gLogFileCurrent && data && len)
{
bool timetoswitch = TimeToSwitch(len);
if ( timetoswitch )
{
if (gFileNum == 1)
{
if (gLogFile_1) fclose(gLogFile_1);
gLogFile_1 = 0;
gLogFile_2 = fopen("logfile_2.txt","w");
gFileNum = 2;
gLogFileCurrent = gLogFile_2;
fseek(gLogFileCurrent , 0, SEEK_SET);
}
else
{
if (gLogFile_2) fclose(gLogFile_2);
gLogFile_2 = 0;
gLogFile_1 = fopen("logfile_1.txt","w");
gFileNum = 1;
gLogFileCurrent = gLogFile_1;
fseek(gLogFileCurrent , 0, SEEK_SET);
}
}
fwrite(data, sizeof(char), len, gLogFileCurrent);
fflush(gLogFileCurrent);
}
}
void WritePacketToLog(void *data, int len)
{
gLogNumPackets ++;
LogUInt("Packet:", (UInt32) gLogNumPackets,"\n");
LogBuffer();
WriteToLog(data, len);
}
void WritToBuffer(void *data, int len)
{
if (data )
{
if (len >= gBuffSize)
len = gBuffSize -1;
memcpy (gLogBuff, (char *) data, len);
gLogBuff[gBuffSize] = 0;
}
gBuffUsed = len;
}
void LogBuffer(void)
{
WriteToLog(gLogBuff, strlen(gLogBuff) );
*gLogBuff =0;
gBuffUsed = strlen(gLogBuff);
}
void PrintLogBuffer(bool log)
{
qtss_printf(gLogBuff);
if (log) LogBuffer();
*gLogBuff =0;
gBuffUsed = strlen(gLogBuff);
}
void LogNum(char *str1,char *str2,char *str3)
{
int size = strlen(str1) + strlen(str2) + strlen(str3);
if ( size < gBuffMaxStr )
qtss_sprintf(gLogBuff, "%s%s%s%s",gLogBuff, str1, str2,str3);
gBuffUsed = strlen(gLogBuff);
}
void LogFloat(char *str, float num, char *str2)
{
qtss_sprintf(gTempStr,"%f",num);
LogNum(str,gTempStr,str2);
}
void LogInt(char *str, SInt32 num, char *str2)
{
qtss_sprintf(gTempStr,"%"_S32BITARG_"",num);
LogNum(str,gTempStr,str2);
}
void LogUInt (char *str, UInt32 num, char *str2)
{
qtss_sprintf(gTempStr,"%"_U32BITARG_"",num);
LogNum(str,gTempStr,str2);
}
void LogStr(char *str)
{
*gLogBuff = 0;
int size = strlen(str) + gBuffUsed;
if ( size <= gBuffMaxStr )
qtss_sprintf(gLogBuff, "%s%s",gLogBuff, str);
gBuffUsed = strlen(gLogBuff);
}
#endif
SInt64 PlayListUtils::sInitialMsecOffset = 0;
UInt32 PlayListUtils::sRandomNum = 0;
void PlayListUtils::Initialize()
{
if (sInitialMsecOffset != 0) return;
sInitialMsecOffset = OS::Milliseconds(); //Milliseconds uses sInitialMsec to make a 0 offset millisecond so this assignment is valid only once.
//qtss_printf("sInitialMsecOffset =%qd\n",sInitialMsecOffset);
::srand( (UInt16) OS::UnixTime_Secs() );
sRandomNum = ::rand();
}
PlayListUtils::PlayListUtils()
{
}
UInt32 PlayListUtils::Random()
{
UInt32 seed = 1664525L * sRandomNum + 1013904223L; //1013904223 is prime .. Knuth D.E.
::srand( seed );
sRandomNum = ::rand();
return sRandomNum;
}

View file

@ -0,0 +1,101 @@
/*
*
* @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@
*
*/
#ifndef playlist_utils_H
#define playlist_utils_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif
#include "OSHeaders.h"
#include "OS.h"
#define Log_Enabled 0
#if Log_Enabled
void LogFileOpen(void);
void LogFileClose(void);
bool TimeToSwitch(int len);
void WriteToLog(void *data, int len);
void WritePacketToLog(void *data, int len);
void WritToBuffer(void *data, int len);
void LogBuffer(void);
void PrintLogBuffer(bool log);
void LogNum(void);
void LogFloat(char *str, float num, char *str2= "\0");
void LogInt(char *str, SInt32 num, char *str2= "\0");
void LogUInt (char *str, UInt32 num, char *str2 = "\0");
void LogStr(char *str);
#else
#define LogFileOpen()
#define LogFileClose()
#define TimeToSwitch(len)
#define WriteToLog(data,len)
#define WritePacketToLog(data,len)
#define WritToBuffer(data, len)
#define LogBuffer()
#define PrintLogBuffer(log)
#define LogFloat(str,num,str2)
#define LogInt(str,num,str2)
#define LogUInt(str,num,str2)
#define LogStr(str)
#define LogNum()
#endif
#define kFixed64 ( (UInt64) 1 << 32)
class PlayListUtils
{
public:
PlayListUtils();
enum {eMicro = 1000000, eMilli = 1000};
static SInt64 sInitialMsecOffset;
static UInt32 sRandomNum;
static void InitRandom() {};
static void Initialize();
static UInt32 Random();
static SInt64 Milliseconds() {return OS::Milliseconds() - sInitialMsecOffset;};
static SInt64 TimeMilli_To_1900Fixed64Secs(SInt64 inMilliseconds) { return OS::TimeMilli_To_1900Fixed64Secs(OS::TimeMilli_To_UnixTimeMilli(sInitialMsecOffset + inMilliseconds)); }
static SInt64 TimeMilli_To_Fixed64Secs(SInt64 inMilliseconds) { return OS::TimeMilli_To_Fixed64Secs(inMilliseconds); }
};
#endif //playlist_utils_H

View file

@ -0,0 +1,352 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @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@
*/
/* tailor.h -- target dependent definitions
* Copyright (C) 1992-1993 Jean-loup Gailly.
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, see the file COPYING.
*/
/* The target dependent definitions should be defined here only.
* The target dependent functions should be defined in tailor.c.
*/
/* $Id: tailor.h,v 1.1 2006/01/05 13:20:36 murata Exp $ */
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if defined(__OS2__) && !defined(OS2)
# define OS2
#endif
#if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */
# undef MSDOS
#endif
#ifdef MSDOS
# ifdef __GNUC__
/* DJGPP version 1.09+ on MS-DOS.
* The DJGPP 1.09 stat() function must be upgraded before gzip will
* fully work.
* No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
* implies DIRENT.
*/
# define near
# else
# define MAXSEG_64K
# ifdef __TURBOC__
# define NO_OFF_T
# ifdef __BORLANDC__
# define DIRENT
# else
# define NO_UTIME
# endif
# else /* MSC */
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# endif
# endif
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 128
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# define NO_SIZE_CHECK
# define casemap(c) tolow(c) /* Force file names to lower case */
# include <io.h>
# define OS_CODE 0x00
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# if !defined(NO_ASM) && !defined(ASMV)
# define ASMV
# endif
#else
# define near
#endif
#ifdef OS2
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 260
# ifdef OS2FAT
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define casemap(c) tolow(c)
# endif
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# include <io.h>
# define OS_CODE 0x06
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# ifdef _MSC_VER
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define MAXSEG_64K
# undef near
# define near _near
# endif
# ifdef __EMX__
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define DIRENT
# define EXPAND(argc,argv) \
{_response(&argc, &argv); _wildcard(&argc, &argv);}
# endif
# ifdef __BORLANDC__
# define DIRENT
# endif
# ifdef __ZTC__
# define NO_DIR
# define NO_UTIME_H
# include <dos.h>
# define EXPAND(argc,argv) \
{response_expand(&argc, &argv);}
# endif
#endif
#ifdef WIN32 /* Windows NT */
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 260
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# include <io.h>
# include <malloc.h>
# ifdef NTFAT
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define casemap(c) tolow(c) /* Force file names to lower case */
# endif
# define OS_CODE 0x0b
#endif
#ifdef MSDOS
# ifdef __TURBOC__
# include <alloc.h>
# define DYN_ALLOC
/* Turbo C 2.0 does not accept static allocations of large arrays */
void * fcalloc (unsigned items, unsigned size);
void fcfree (void *ptr);
# else /* MSC */
# include <malloc.h>
# define fcalloc(nitems,itemsize) halloc((SInt32)(nitems),(itemsize))
# define fcfree(ptr) hfree(ptr)
# endif
#else
# ifdef MAXSEG_64K
# define fcalloc(items,size) calloc((items),(size))
# else
# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
# endif
# define fcfree(ptr) free(ptr)
#endif
#if defined(VAXC) || defined(VMS)
# define PATH_SEP ']'
# define PATH_SEP2 ':'
# define SUFFIX_SEP ';'
# define NO_MULTIPLE_DOTS
# define Z_SUFFIX "-gz"
# define RECORD_IO 1
# define casemap(c) tolow(c)
# define OS_CODE 0x02
# define OPTIONS_VAR "GZIP_OPT"
# define STDC_HEADERS
# define NO_UTIME
# define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
# include <file.h>
# define unlink delete
# ifdef VAXC
# define NO_FCNTL_H
# include <unixio.h>
# endif
#endif
#ifdef AMIGA
# define PATH_SEP2 ':'
# define STDC_HEADERS
# define OS_CODE 0x01
# define ASMV
# ifdef __GNUC__
# define DIRENT
# define HAVE_UNISTD_H
# else /* SASC */
# define NO_STDIN_FSTAT
# define SYSDIR
# define NO_SYMLINK
# define NO_CHOWN
# define NO_FCNTL_H
# include <fcntl.h> /* for read() and write() */
# define direct dirent
extern void _expand_args(int *argc, char ***argv);
# define EXPAND(argc,argv) _expand_args(&argc,&argv);
# undef O_BINARY /* disable useless --ascii option */
# endif
#endif
#if defined(ATARI) || defined(atarist)
# ifndef STDC_HEADERS
# define STDC_HEADERS
# define HAVE_UNISTD_H
# define DIRENT
# endif
# define ASMV
# define OS_CODE 0x05
# ifdef TOSFS
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 128
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define NO_CHOWN
# define casemap(c) tolow(c) /* Force file names to lower case */
# define NO_SYMLINK
# endif
#endif
#ifdef MACOS
# define PATH_SEP ':'
# define DYN_ALLOC
# define PROTO
# define NO_STDIN_FSTAT
# define NO_CHOWN
# define NO_UTIME
# define chmod(file, mode) (0)
# define OPEN(name, flags, mode) open(name, flags)
# define OS_CODE 0x07
# ifdef MPW
# define isatty(fd) ((fd) <= 2)
# endif
#endif
#ifdef __50SERIES /* Prime/PRIMOS */
# define PATH_SEP '>'
# define STDC_HEADERS
# define NO_MEMORY_H
# define NO_UTIME_H
# define NO_UTIME
# define NO_CHOWN
# define NO_STDIN_FSTAT
# define NO_SIZE_CHECK
# define NO_SYMLINK
# define RECORD_IO 1
# define casemap(c) tolow(c) /* Force file names to lower case */
# define put_char(c) put_byte((c) & 0x7F)
# define get_char(c) ascii2pascii(get_byte())
# define OS_CODE 0x0F /* temporary, subject to change */
# ifdef SIGTERM
# undef SIGTERM /* We don't want a signal handler for SIGTERM */
# endif
#endif
#if defined(pyr) && !defined(NOMEMCPY) /* Pyramid */
# define NOMEMCPY /* problem with overlapping copies */
#endif
#ifdef TOPS20
# define OS_CODE 0x0a
#endif
#ifndef unix
# define NO_ST_INO /* don't rely on inode numbers */
#endif
/* Common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif
#ifndef PATH_SEP
# define PATH_SEP '/'
#endif
#ifndef casemap
# define casemap(c) (c)
#endif
#ifndef OPTIONS_VAR
# define OPTIONS_VAR "GZIP"
#endif
#ifndef Z_SUFFIX
# define Z_SUFFIX ".gz"
#endif
#ifdef MAX_EXT_CHARS
# define MAX_SUFFIX MAX_EXT_CHARS
#else
# define MAX_SUFFIX 30
#endif
#ifndef MAKE_LEGAL_NAME
# ifdef NO_MULTIPLE_DOTS
# define MAKE_LEGAL_NAME(name) make_simple_name(name)
# else
# define MAKE_LEGAL_NAME(name)
# endif
#endif
#ifndef MIN_PART
# define MIN_PART 3
/* keep at least MIN_PART chars between dots in a file name. */
#endif
#ifndef EXPAND
# define EXPAND(argc,argv)
#endif
#ifndef RECORD_IO
# define RECORD_IO 0
#endif
#ifndef SET_BINARY_MODE
# define SET_BINARY_MODE(fd)
#endif
#ifndef OPEN
# define OPEN(name, flags, mode) open(name, flags, mode)
#endif
#ifndef get_char
# define get_char() get_byte()
#endif
#ifndef put_char
# define put_char(c) put_byte(c)
#endif

View file

@ -0,0 +1,394 @@
/*
*
* @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: FilePrefsSource.cpp
Contains: Implements object defined in FilePrefsSource.h.
Written by: Chris LeCroy
*/
#include "FilePrefsSource.h"
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "MyAssert.h"
#include "OSMemory.h"
#include "ConfParser.h"
const int kMaxLineLen = 2048;
const int kMaxValLen = 1024;
class KeyValuePair
{
public:
char* GetValue() { return fValue; }
private:
friend class FilePrefsSource;
KeyValuePair(const char* inKey, const char* inValue, KeyValuePair* inNext);
~KeyValuePair();
char* fKey;
char* fValue;
KeyValuePair* fNext;
void ResetValue(const char* inValue);
};
KeyValuePair::KeyValuePair(const char* inKey, const char* inValue, KeyValuePair* inNext) :
fKey(NULL),
fValue(NULL),
fNext(NULL)
{
fKey = NEW char[::strlen(inKey)+1];
::strcpy(fKey, inKey);
fValue = NEW char[::strlen(inValue)+1];
::strcpy(fValue, inValue);
fNext = inNext;
}
KeyValuePair::~KeyValuePair()
{
delete [] fKey;
delete [] fValue;
}
void KeyValuePair::ResetValue(const char* inValue)
{
delete [] fValue;
fValue = NEW char[::strlen(inValue)+1];
::strcpy(fValue, inValue);
}
FilePrefsSource::FilePrefsSource( Bool16 allowDuplicates)
: fKeyValueList(NULL),
fNumKeys(0),
fAllowDuplicates(allowDuplicates)
{
}
FilePrefsSource::~FilePrefsSource()
{
while (fKeyValueList != NULL)
{
KeyValuePair* keyValue = fKeyValueList;
fKeyValueList = fKeyValueList->fNext;
delete keyValue;
}
}
int FilePrefsSource::GetValue(const char* inKey, char* ioValue)
{
return (this->FindValue(inKey, ioValue) != NULL);
}
int FilePrefsSource::GetValueByIndex(const char* inKey, UInt32 inIndex, char* ioValue)
{
KeyValuePair* thePair = this->FindValue(inKey, ioValue, inIndex);
if (thePair == NULL)
return false;
return true;
/*
char* valuePtr = thePair->fValue;
//this function makes the assumption that fValue doesn't start with whitespace
Assert(*valuePtr != '\t');
Assert(*valuePtr != ' ');
for (UInt32 count = 0; ((count < inIndex) && (valuePtr != '\0')); count++)
{
//go through all the "words" on this line (delimited by whitespace)
//until we hit the one specified by inIndex
//we aren't at the proper word yet, so skip...
while ((*valuePtr != ' ') && (*valuePtr != '\t') && (*valuePtr != '\0'))
valuePtr++;
//skip over all the whitespace between words
while ((*valuePtr == ' ') || (*valuePtr == '\t'))
valuePtr++;
}
//We've exhausted the data on this line before getting to our pref,
//so return an error.
if (*valuePtr == '\0')
return false;
//if we are here, then valuePtr is pointing to the beginning of the right word
while ((*valuePtr != ' ') && (*valuePtr != '\t') && (*valuePtr != '\0'))
*ioValue++ = *valuePtr++;
*ioValue = '\0';
return true;
*/
}
char* FilePrefsSource::GetValueAtIndex(UInt32 inIndex)
{
// Iterate through the queue until we have the right entry
KeyValuePair* thePair = fKeyValueList;
while ((thePair != NULL) && (inIndex-- > 0))
thePair = thePair->fNext;
if (thePair != NULL)
return thePair->fValue;
return NULL;
}
char* FilePrefsSource::GetKeyAtIndex(UInt32 inIndex)
{
// Iterate through the queue until we have the right entry
KeyValuePair* thePair = fKeyValueList;
while ((thePair != NULL) && (inIndex-- > 0))
thePair = thePair->fNext;
if (thePair != NULL)
return thePair->fKey;
return NULL;
}
void FilePrefsSource::SetValue(const char* inKey, const char* inValue)
{
KeyValuePair* keyValue = NULL;
// If the key/value already exists update the value.
// If duplicate keys are allowed, however, add a new entry regardless
if ((!fAllowDuplicates) && ((keyValue = this->FindValue(inKey, NULL)) != NULL))
{
keyValue->ResetValue(inValue);
}
else
{
fKeyValueList = NEW KeyValuePair(inKey, inValue, fKeyValueList);
fNumKeys++;
}
}
Bool16 FilePrefsSource::FilePrefsConfigSetter( const char* paramName, const char* paramValue[], void* userData )
{
/*
static callback routine for ParseConfigFile
*/
int valueIndex = 0;
FilePrefsSource *theFilePrefs = (FilePrefsSource*)userData;
Assert( theFilePrefs );
Assert( paramName );
// Assert( paramValue[0] );
// multiple values are passed in the paramValue array as distinct strs
while ( paramValue[valueIndex] != NULL )
{
//qtss_printf("Adding config setting <key=\"%s\", value=\"%s\">\n", paramName, paramValue[valueIndex] );
theFilePrefs->SetValue(paramName, paramValue[valueIndex] );
valueIndex++;
}
return false; // always succeeds
}
int FilePrefsSource::InitFromConfigFile(const char* configFilePath)
{
/*
load config from specified file. return non-zero
in the event of significant error(s).
*/
return ::ParseConfigFile( true, configFilePath, FilePrefsConfigSetter, this );
/*
int err = 0;
char bufLine[kMaxLineLen];
char key[kMaxValLen];
char value[kMaxLineLen];
FILE* fileDesc = ::fopen( configFilePath, "r");
if (fileDesc == NULL)
{
// report some problem here...
err = OSThread::GetErrno();
Assert( err );
}
else
{
while (fgets(bufLine, sizeof(bufLine) - 1, fileDesc) != NULL)
{
if (bufLine[0] != '#' && bufLine[0] != '\0')
{
int i = 0;
int n = 0;
while ( bufLine[i] == ' ' || bufLine[i] == '\t')
{ ++i;}
n = 0;
while ( bufLine[i] != ' ' &&
bufLine[i] != '\t' &&
bufLine[i] != '\n' &&
bufLine[i] != '\r' &&
bufLine[i] != '\0' &&
n < (kMaxLineLen - 1) )
{
key[n++] = bufLine[i++];
}
key[n] = '\0';
while (bufLine[i] == ' ' || bufLine[i] == '\t')
{++i;}
n = 0;
while ((bufLine[i] != '\n') && (bufLine[i] != '\0') &&
(bufLine[i] != '\r') && (n < kMaxLineLen - 1))
{
value[n++] = bufLine[i++];
}
value[n] = '\0';
if (key[0] != '#' && key[0] != '\0' && value[0] != '\0')
{
qtss_printf("Adding config setting <key=\"%s\", value=\"%s\">\n", key, value);
this->SetValue(key, value);
}
else
{
//assert(false);
}
}
}
int closeErr = ::fclose(fileDesc);
Assert(closeErr == 0);
}
return err;
*/
}
void FilePrefsSource::DeleteValue(const char* inKey)
{
KeyValuePair* keyValue = fKeyValueList;
KeyValuePair* prevKeyValue = NULL;
while (keyValue != NULL)
{
if (::strcmp(inKey, keyValue->fKey) == 0)
{
if (prevKeyValue != NULL)
{
prevKeyValue->fNext = keyValue->fNext;
delete keyValue;
}
else
{
fKeyValueList = prevKeyValue;
}
return;
}
prevKeyValue = keyValue;
keyValue = keyValue->fNext;
}
}
void FilePrefsSource::WriteToConfigFile(const char* configFilePath)
{
int err = 0;
FILE* fileDesc = ::fopen( configFilePath, "w");
if (fileDesc != NULL)
{
err = ::fseek(fileDesc, 0, SEEK_END);
Assert(err == 0);
KeyValuePair* keyValue = fKeyValueList;
while (keyValue != NULL)
{
(void)qtss_fprintf(fileDesc, "%s %s\n\n", keyValue->fKey, keyValue->fValue);
keyValue = keyValue->fNext;
}
err = ::fclose(fileDesc);
Assert(err == 0);
}
}
KeyValuePair* FilePrefsSource::FindValue(const char* inKey, char* ioValue, UInt32 index )
{
KeyValuePair *keyValue = fKeyValueList;
UInt32 foundIndex = 0;
if ( ioValue != NULL)
ioValue[0] = '\0';
while (keyValue != NULL)
{
if (::strcmp(inKey, keyValue->fKey) == 0)
{
if ( foundIndex == index )
{
if (ioValue != NULL)
::strcpy(ioValue, keyValue->fValue);
return keyValue;
}
foundIndex++;
}
keyValue = keyValue->fNext;
}
return NULL;
}

View file

@ -0,0 +1,76 @@
/*
*
* @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: FilePrefsSource.h
Contains: Implements the PrefsSource interface, getting the prefs from a file.
Written by: Chris LeCroy
*/
#ifndef __FILEPREFSSOURCE_H__
#define __FILEPREFSSOURCE_H__
#include "PrefsSource.h"
#include "OSHeaders.h"
class KeyValuePair; //only used in the implementation
class FilePrefsSource : public PrefsSource
{
public:
FilePrefsSource( Bool16 allowDuplicates = false );
virtual ~FilePrefsSource();
virtual int GetValue(const char* inKey, char* ioValue);
virtual int GetValueByIndex(const char* inKey, UInt32 inIndex, char* ioValue);
// Allows caller to iterate over all the values in the file.
char* GetValueAtIndex(UInt32 inIndex);
char* GetKeyAtIndex(UInt32 inIndex);
UInt32 GetNumKeys() { return fNumKeys; }
int InitFromConfigFile(const char* configFilePath);
void WriteToConfigFile(const char* configFilePath);
void SetValue(const char* inKey, const char* inValue);
void DeleteValue(const char* inKey);
private:
static Bool16 FilePrefsConfigSetter( const char* paramName, const char* paramValue[], void* userData );
KeyValuePair* FindValue(const char* inKey, char* ioValue, UInt32 index = 0);
KeyValuePair* fKeyValueList;
UInt32 fNumKeys;
Bool16 fAllowDuplicates;
};
#endif //__FILEPREFSSOURCE_H__

View file

@ -0,0 +1,54 @@
/*
*
* @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: PrefsSource.h
Contains: Defines an abstract common interface for extracting prefs
from some data source. Very general, low level
Written by: Denis Serenyi
Change History (most recent first):
*/
#ifndef __PREFSSOURCE_H__
#define __PREFSSOURCE_H__
#include "OSHeaders.h"
class PrefsSource
{
public:
virtual int GetValue(const char* inKey, char* ioValue) = 0;
virtual int GetValueByIndex(const char* inKey, UInt32 inIndex, char* ioValue) = 0;
virtual ~PrefsSource(){};
};
#endif

View file

@ -0,0 +1,692 @@
/*
*
* @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@
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef __Win32__
#include <unistd.h>
#endif
#include "XMLParser.h"
#include "OSMemory.h"
XMLParser::XMLParser( char* inPath, DTDVerifier* verifier)
: fRootTag(NULL), fFilePath(NULL)
{
StrPtrLen thePath(inPath);
fFilePath = thePath.GetAsCString();
fFile.Set(inPath);
fVerifier = verifier;
}
XMLParser::~XMLParser()
{
if (fRootTag)
delete fRootTag;
delete [] fFilePath;
}
Bool16 XMLParser::ParseFile(char* errorBuffer, int errorBufferSize)
{
if (fRootTag != NULL)
{
delete fRootTag; // flush old data
fRootTag = NULL;
}
fFile.Set(fFilePath);
if (errorBufferSize < 500) errorBuffer = NULL; // Just a hack to avoid checking everywhere
if ((fFile.GetLength() == 0) || fFile.IsDir())
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "Couldn't read xml file");
return false; // we don't have a valid file;
}
char* fileData = NEW char[ (SInt32) (fFile.GetLength() + 1)];
UInt32 theLengthRead = 0;
fFile.Read(0, fileData, (UInt32) fFile.GetLength(), &theLengthRead);
StrPtrLen theDataPtr(fileData, theLengthRead);
StringParser theParser(&theDataPtr);
fRootTag = NEW XMLTag();
Bool16 result = fRootTag->ParseTag(&theParser, fVerifier, errorBuffer, errorBufferSize);
if (!result)
{
// got error parsing file
delete fRootTag;
fRootTag = NULL;
}
delete fileData;
fFile.Close();
return result;
}
Bool16 XMLParser::DoesFileExist()
{
Bool16 itExists = false;
fFile.Set(fFilePath);
if ((fFile.GetLength() > 0) && (!fFile.IsDir()))
itExists = true;
fFile.Close();
return itExists;
}
Bool16 XMLParser::DoesFileExistAsDirectory()
{
Bool16 itExists = false;
fFile.Set(fFilePath);
if (fFile.IsDir())
itExists = true;
fFile.Close();
return itExists;
}
Bool16 XMLParser::CanWriteFile()
{
//
// First check if it exists for reading
FILE* theFile = ::fopen(fFilePath, "r");
if (theFile == NULL)
return true;
::fclose(theFile);
//
// File exists for reading, check if we can write it
theFile = ::fopen(fFilePath, "a");
if (theFile == NULL)
return false;
//
// We can read and write
::fclose(theFile);
return true;
}
void XMLParser::SetRootTag(XMLTag* tag)
{
if (fRootTag != NULL)
delete fRootTag;
fRootTag = tag;
}
void XMLParser::WriteToFile(char** fileHeader)
{
char theBuffer[8192];
ResizeableStringFormatter formatter(theBuffer, 8192);
//
// Write the file header
for (UInt32 a = 0; fileHeader[a] != NULL; a++)
{
formatter.Put(fileHeader[a]);
formatter.Put(kEOLString);
}
if (fRootTag)
fRootTag->FormatData(&formatter, 0);
//
// New libC code. This seems to work better on Win32
formatter.PutTerminator();
FILE* theFile = ::fopen(fFilePath, "w");
if (theFile == NULL)
return;
qtss_fprintf(theFile, "%s", formatter.GetBufPtr());
::fclose(theFile);
#if __MacOSX__
(void) ::chown(fFilePath,76,80);//owner qtss, group admin
#endif
#ifndef __Win32__
::chmod(fFilePath, S_IRUSR | S_IWUSR | S_IRGRP );
#endif
}
UInt8 XMLTag::sNonNameMask[] =
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //0-9
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //10-19
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //20-29
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //30-39
1, 1, 1, 1, 1, 0, 0, 1, 0, 0, //40-49 '.' and '-' are name chars
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //50-59 ':' is a name char
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //60-69 //stop on every character except a letter or number
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
0, 1, 1, 1, 1, 0, 1, 0, 0, 0, //90-99 '_' is a name char
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, //120-129
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //130-139
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //140-149
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //150-159
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //160-169
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //170-179
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //180-189
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //190-199
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //200-209
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //210-219
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //220-229
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //230-239
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //240-249
1, 1, 1, 1, 1, 1 //250-255
};
XMLTag::XMLTag() :
fTag(NULL),
fValue(NULL),
fElem(NULL)
{ fElem = this;
}
XMLTag::XMLTag(char* tagName) :
fTag(NULL),
fValue(NULL),
fElem(NULL)
{ fElem = this;
StrPtrLen temp(tagName);
fTag = temp.GetAsCString();
}
XMLTag::~XMLTag()
{
if (fTag)
delete fTag;
if (fValue)
delete fValue;
OSQueueElem* elem;
while ((elem = fAttributes.DeQueue()) != NULL)
{
XMLAttribute* attr = (XMLAttribute*)elem->GetEnclosingObject();
delete attr;
}
while ((elem = fEmbeddedTags.DeQueue()) != NULL)
{
XMLTag* tag = (XMLTag*)elem->GetEnclosingObject();
delete tag;
}
if (fElem.IsMemberOfAnyQueue())
fElem.InQueue()->Remove(&fElem); // remove from parent tag
}
void XMLTag::ConsumeIfComment(StringParser* parser)
{
if ((parser->GetDataRemaining() > 2) && ((*parser)[1] == '-') && ((*parser)[2] == '-'))
{
// this is a comment, so skip to end of comment
parser->ConsumeLength(NULL, 2); // skip '--'
// look for -->
while((parser->GetDataRemaining() > 2) && ((parser->PeekFast() != '-') ||
((*parser)[1] != '-') || ((*parser)[2] != '>')))
{
if (parser->PeekFast() == '-') parser->ConsumeLength(NULL, 1);
parser->ConsumeUntil(NULL, '-');
}
if (parser->GetDataRemaining() > 2) parser->ConsumeLength(NULL, 3); // consume -->
}
}
bool XMLTag::ParseTag(StringParser* parser, DTDVerifier* verifier, char* errorBuffer, int errorBufferSize)
{
while (true)
{
if (!parser->GetThru(NULL, '<'))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "Couldn't find a valid tag");
return false; // couldn't find beginning of tag
}
char c = parser->PeekFast();
if (c == '/')
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "End tag with no begin tag on line %d", parser->GetCurrentLineNumber());
return false; // we shouldn't be seeing a close tag here
}
if ((c != '!') && (c != '?'))
break; // this should be the beginning of a regular tag
ConsumeIfComment(parser);
// otherwise this is a processing instruction or a c-data, so look for the next tag
}
int tagStartLine = parser->GetCurrentLineNumber();
StrPtrLen temp;
parser->ConsumeUntil(&temp, sNonNameMask);
if (temp.Len == 0)
{
if (errorBuffer != NULL)
{
if (parser->GetDataRemaining() == 0)
qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber());
else
qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber());
}
return false; // bad file
}
fTag = temp.GetAsCString();
parser->ConsumeWhitespace();
while ((parser->PeekFast() != '>') && (parser->PeekFast() != '/'))
{
// we must have an attribute value for this tag
XMLAttribute* attr = new XMLAttribute;
fAttributes.EnQueue(&attr->fElem);
parser->ConsumeUntil(&temp, sNonNameMask);
if (temp.Len == 0)
{
if (errorBuffer != NULL)
{
if (parser->GetDataRemaining() == 0)
qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber());
else
qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber());
}
return false; // bad file
}
attr->fAttrName = temp.GetAsCString();
if (!parser->Expect('='))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"Missing '=' after attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
if (!parser->Expect('"'))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
parser->ConsumeUntil(&temp, '"');
attr->fAttrValue = temp.GetAsCString();
if (!parser->Expect('"'))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
if (verifier && !verifier->IsValidAttributeName(fTag, attr->fAttrName))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s not allowed in tag %s on line %d", attr->fAttrName, fTag, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
if (verifier && !verifier->IsValidAttributeValue(fTag, attr->fAttrName, attr->fAttrValue))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"Bad value for attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
parser->ConsumeWhitespace();
}
if (parser->PeekFast() == '/')
{
// this is an empty element tag, i.e. no contents or end tag (e.g <TAG attr="value" />
parser->Expect('/');
if (!parser->Expect('>'))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"'>' must follow '/' on line %d", parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
return true; // we're done with this tag
}
if (!parser->Expect('>'))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"Bad format for tag <%s> on line %d", fTag, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
while(true)
{
parser->ConsumeUntil(&temp, '<'); // this is either value or whitespace
if (parser->GetDataRemaining() < 4)
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "Reached end of file without end for tag <%s> declared on line %d", fTag, tagStartLine);
return false;
}
if ((*parser)[1] == '/')
{
// we'll only assign a value if there were no embedded tags
if (fEmbeddedTags.GetLength() == 0 && (!verifier || verifier->CanHaveValue(fTag)))
fValue = temp.GetAsCString();
else
{
// otherwise this needs to have been just whitespace
StringParser tempParser(&temp);
tempParser.ConsumeWhitespace();
if (tempParser.GetDataRemaining() > 0)
{
if (errorBuffer)
{
if (fEmbeddedTags.GetLength() > 0)
qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected text outside of tag on line %d", tagStartLine);
else
qtss_snprintf(errorBuffer, errorBufferSize, "Tag <%s> on line %d not allowed to have data", fTag, tagStartLine);
}
}
}
break; // we're all done with this tag
}
if (((*parser)[1] != '!') && ((*parser)[1] != '?'))
{
// this must be the beginning of an embedded tag
XMLTag* tag = NEW XMLTag();
fEmbeddedTags.EnQueue(&tag->fElem);
if (!tag->ParseTag(parser, verifier, errorBuffer, errorBufferSize))
return false;
if (verifier && !verifier->IsValidSubtag(fTag, tag->GetTagName()))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize, "Tag %s not allowed in tag %s on line %d", tag->GetTagName(), fTag, parser->GetCurrentLineNumber());
return false; // bad attribute specification
}
}
else
{
parser->ConsumeLength(NULL, 1); // skip '<'
ConsumeIfComment(parser);
}
}
parser->ConsumeLength(NULL, 2); // skip '</'
parser->ConsumeUntil(&temp, sNonNameMask);
if (!temp.Equal(fTag))
{
char* newTag = temp.GetAsCString();
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"End tag </%s> on line %d doesn't match tag <%s> declared on line %d", newTag, parser->GetCurrentLineNumber(),fTag, tagStartLine);
delete newTag;
return false; // bad attribute specification
}
if (!parser->GetThru(NULL, '>'))
{
if (errorBuffer != NULL)
qtss_snprintf(errorBuffer, errorBufferSize,"Couldn't find end of tag <%s> declared on line %d", fTag, tagStartLine);
return false; // bad attribute specification
}
return true;
}
char* XMLTag::GetAttributeValue(const char* attrName)
{
for (OSQueueIter iter(&fAttributes); !iter.IsDone(); iter.Next())
{
XMLAttribute* attr = (XMLAttribute*)iter.GetCurrent()->GetEnclosingObject();
if (!strcmp(attr->fAttrName, attrName))
return attr->fAttrValue;
}
return NULL;
}
XMLTag* XMLTag::GetEmbeddedTag(const UInt32 index)
{
if (fEmbeddedTags.GetLength() <= index)
return NULL;
OSQueueIter iter(&fEmbeddedTags);
for (UInt32 i = 0; i < index; i++)
{
iter.Next();
}
OSQueueElem* result = iter.GetCurrent();
return (XMLTag*)result->GetEnclosingObject();
}
XMLTag* XMLTag::GetEmbeddedTagByName(const char* tagName, const UInt32 index)
{
if (fEmbeddedTags.GetLength() <= index)
return NULL;
XMLTag* result = NULL;
UInt32 curIndex = 0;
for (OSQueueIter iter(&fEmbeddedTags); !iter.IsDone(); iter.Next())
{
XMLTag* temp = (XMLTag*)iter.GetCurrent()->GetEnclosingObject();
if (!strcmp(temp->GetTagName(), tagName))
{
if (curIndex == index)
{
result = temp;
break;
}
curIndex++;
}
}
return result;
}
XMLTag* XMLTag::GetEmbeddedTagByAttr(const char* attrName, const char* attrValue, const UInt32 index)
{
if (fEmbeddedTags.GetLength() <= index)
return NULL;
XMLTag* result = NULL;
UInt32 curIndex = 0;
for (OSQueueIter iter(&fEmbeddedTags); !iter.IsDone(); iter.Next())
{
XMLTag* temp = (XMLTag*)iter.GetCurrent()->GetEnclosingObject();
if ((temp->GetAttributeValue(attrName) != NULL) && (!strcmp(temp->GetAttributeValue(attrName), attrValue)))
{
if (curIndex == index)
{
result = temp;
break;
}
curIndex++;
}
}
return result;
}
XMLTag* XMLTag::GetEmbeddedTagByNameAndAttr(const char* tagName, const char* attrName, const char* attrValue, const UInt32 index)
{
if (fEmbeddedTags.GetLength() <= index)
return NULL;
XMLTag* result = NULL;
UInt32 curIndex = 0;
for (OSQueueIter iter(&fEmbeddedTags); !iter.IsDone(); iter.Next())
{
XMLTag* temp = (XMLTag*)iter.GetCurrent()->GetEnclosingObject();
if (!strcmp(temp->GetTagName(), tagName) && (temp->GetAttributeValue(attrName) != NULL) &&
(!strcmp(temp->GetAttributeValue(attrName), attrValue)))
{
if (curIndex == index)
{
result = temp;
break;
}
curIndex++;
}
}
return result;
}
void XMLTag::AddAttribute( char* attrName, char* attrValue)
{
XMLAttribute* attr = NEW XMLAttribute;
StrPtrLen temp(attrName);
attr->fAttrName = temp.GetAsCString();
temp.Set(attrValue);
attr->fAttrValue = temp.GetAsCString();
fAttributes.EnQueue(&attr->fElem);
}
void XMLTag::RemoveAttribute(char* attrName)
{
for (OSQueueIter iter(&fAttributes); !iter.IsDone(); iter.Next())
{
XMLAttribute* attr = (XMLAttribute*)iter.GetCurrent()->GetEnclosingObject();
if (!strcmp(attr->fAttrName, attrName))
{
fAttributes.Remove(&attr->fElem);
delete attr;
return;
}
}
}
void XMLTag::AddEmbeddedTag(XMLTag* tag)
{
fEmbeddedTags.EnQueue(&tag->fElem);
}
void XMLTag::RemoveEmbeddedTag(XMLTag* tag)
{
fEmbeddedTags.Remove(&tag->fElem);
}
void XMLTag::SetTagName( char* name)
{
Assert (name != NULL); // can't have a tag without a name!
if (fTag != NULL)
delete fTag;
StrPtrLen temp(name);
fTag = temp.GetAsCString();
}
void XMLTag::SetValue( char* value)
{
if (fEmbeddedTags.GetLength() > 0)
return; // can't have a value with embedded tags
if (fValue != NULL)
delete fValue;
if (value == NULL)
fValue = NULL;
else
{
StrPtrLen temp(value);
fValue = temp.GetAsCString();
}
}
void XMLTag::FormatData(ResizeableStringFormatter* formatter, UInt32 indent)
{
for (UInt32 i=0; i<indent; i++) formatter->PutChar('\t');
formatter->PutChar('<');
formatter->Put(fTag);
if (fAttributes.GetLength() > 0)
{
formatter->PutChar(' ');
for (OSQueueIter iter(&fAttributes); !iter.IsDone(); iter.Next())
{
XMLAttribute* attr = (XMLAttribute*)iter.GetCurrent()->GetEnclosingObject();
formatter->Put(attr->fAttrName);
formatter->Put("=\"");
formatter->Put(attr->fAttrValue);
formatter->Put("\" ");
}
}
formatter->PutChar('>');
if (fEmbeddedTags.GetLength() == 0)
{
if (fValue > 0)
formatter->Put(fValue);
}
else
{
formatter->Put(kEOLString);
for (OSQueueIter iter(&fEmbeddedTags); !iter.IsDone(); iter.Next())
{
XMLTag* current = (XMLTag*)iter.GetCurrent()->GetEnclosingObject();
current->FormatData(formatter, indent + 1);
}
for (UInt32 i=0; i<indent; i++) formatter->PutChar('\t');
}
formatter->Put("</");
formatter->Put(fTag);
formatter->PutChar('>');
formatter->Put(kEOLString);
}
XMLAttribute::XMLAttribute()
: fAttrName(NULL),
fAttrValue(NULL)
{ fElem = this;
}
XMLAttribute::~XMLAttribute()
{
if (fAttrName)
delete fAttrName;
if (fAttrValue)
delete fAttrValue;
}

126
PrefsSourceLib/XMLParser.h Normal file
View file

@ -0,0 +1,126 @@
/*
*
* @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@
*
*/
#ifndef __XMLParser_h__
#define __XMLParser_h__
#include "StringParser.h"
#include "OSQueue.h"
#include "OSFileSource.h"
#include "ResizeableStringFormatter.h"
class DTDVerifier
{
public:
virtual bool IsValidSubtag(char* tagName, char* subTagName) = 0;
virtual bool IsValidAttributeName(char* tagName, char* attrName) = 0;
virtual bool IsValidAttributeValue(char* tagName, char* attrName, char* attrValue) = 0;
virtual char* GetRequiredAttribute(char* tagName, int index) = 0;
virtual bool CanHaveValue(char* tagName) = 0;
virtual ~DTDVerifier(){};
};
class XMLTag
{
public:
XMLTag();
XMLTag(char* tagName);
~XMLTag();
bool ParseTag(StringParser* parser, DTDVerifier* verifier, char* errorBuffer = NULL, int errorBufferSize = 0);
char* GetAttributeValue(const char* attrName);
char* GetValue() { return fValue; }
char* GetTagName() { return fTag; }
UInt32 GetNumEmbeddedTags() { return fEmbeddedTags.GetLength(); }
XMLTag* GetEmbeddedTag(const UInt32 index = 0);
XMLTag* GetEmbeddedTagByName(const char* tagName, const UInt32 index = 0);
XMLTag* GetEmbeddedTagByAttr(const char* attrName, const char* attrValue, const UInt32 index = 0);
XMLTag* GetEmbeddedTagByNameAndAttr(const char* tagName, const char* attrName, const char* attrValue, const UInt32 index = 0);
void AddAttribute(char* attrName, char* attrValue);
void RemoveAttribute(char* attrName);
void AddEmbeddedTag(XMLTag* tag);
void RemoveEmbeddedTag(XMLTag* tag);
void SetTagName( char* name);
void SetValue( char* value);
void FormatData(ResizeableStringFormatter* formatter, UInt32 indent);
private:
void ConsumeIfComment(StringParser* parser);
char* fTag;
char* fValue;
OSQueue fAttributes;
OSQueue fEmbeddedTags;
OSQueueElem fElem;
static UInt8 sNonNameMask[]; // stop when you hit a word
};
class XMLAttribute
{
public:
XMLAttribute();
~XMLAttribute();
char* fAttrName;
char* fAttrValue;
OSQueueElem fElem;
};
class XMLParser
{
public:
XMLParser( char* inPath, DTDVerifier* verifier = NULL);
~XMLParser();
// Check for existence, man.
Bool16 DoesFileExist();
Bool16 DoesFileExistAsDirectory();
Bool16 CanWriteFile();
Bool16 ParseFile(char* errorBuffer = NULL, int errorBufferSize = 0);
XMLTag* GetRootTag() { return fRootTag; }
void SetRootTag(XMLTag* tag);
void WriteToFile(char** fileHeader);
private:
XMLTag* fRootTag;
OSFileSource fFile;
char* fFilePath;
DTDVerifier* fVerifier;
};
#endif

View file

@ -0,0 +1,410 @@
/*
*
* @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: XMLPrefsParser.cpp
Contains: Prototype implementation of XMLPrefsParser object.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef __Win32__
#include <unistd.h>
#endif
#include "XMLPrefsParser.h"
#include "OSMemory.h"
#include "OSHeaders.h"
static const UInt32 kPrefArrayMinSize = 20;
static char* kMainTag = "CONFIGURATION";
static char* kServer = "SERVER";
static char* kModule = "MODULE";
static char* kPref = "PREF";
static char* kListPref = "LIST-PREF";
static char* kEmptyObject = "EMPTY-OBJECT";
static char* kObject = "OBJECT";
static char* kObjectList = "LIST-OBJECT";
static char* kValue = "VALUE";
static char* kNameAttr = "NAME";
static char* kTypeAttr = "TYPE";
static char* kFileHeader[] =
{
"<?xml version =\"1.0\"?>",
"<!-- The Document Type Definition (DTD) for the file -->",
"<!DOCTYPE CONFIGURATION [",
"<!ELEMENT CONFIGURATION (SERVER, MODULE*)>",
"<!ELEMENT SERVER (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
"<!ELEMENT MODULE (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
"<!ATTLIST MODULE",
"\tNAME CDATA #REQUIRED>",
"<!ELEMENT PREF (#PCDATA)>",
"<!ATTLIST PREF",
"\tNAME CDATA #REQUIRED",
"\tTYPE (UInt8|SInt8|UInt16|SInt16|UInt32|SInt32|UInt64|SInt64|Float32|Float64|Bool16|Bool8|char) \"char\">",
"<!ELEMENT LIST-PREF (VALUE*)>",
"<!ELEMENT VALUE (#PCDATA)>",
"<!ATTLIST LIST-PREF",
"\tNAME CDATA #REQUIRED",
"\tTYPE (UInt8|SInt8|UInt16|SInt16|UInt32|SInt32|UInt64|SInt64|Float32|Float64|Bool16|Bool8|char) \"char\">",
"<!ELEMENT OBJECT (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
"<!ATTLIST OBJECT",
"\tNAME CDATA #REQUIRED>",
"<!ELEMENT LIST-OBJECT (OBJECT-VALUE*)>",
"<!ELEMENT OBJECT-VALUE (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
"<!ATTLIST LIST-OBJECT",
"\tNAME CDATA #REQUIRED>",
"]>",
NULL
};
XMLPrefsParser::XMLPrefsParser(char* inPath)
: XMLParser(inPath)
{}
XMLPrefsParser::~XMLPrefsParser()
{}
ContainerRef XMLPrefsParser::GetConfigurationTag()
{
ContainerRef result = GetRootTag();
if (result == NULL)
{
result = new XMLTag(kMainTag);
SetRootTag(result);
}
return result;
}
ContainerRef XMLPrefsParser::GetRefForModule(char* inModuleName, Bool16 create)
{
if (inModuleName == NULL)
return GetRefForServer();
ContainerRef result = GetConfigurationTag()->GetEmbeddedTagByNameAndAttr(kModule, kNameAttr, inModuleName);
if (result == NULL)
{
result = new XMLTag(kModule);
result->AddAttribute( kNameAttr, (char*)inModuleName);
GetRootTag()->AddEmbeddedTag(result);
}
return result;
}
ContainerRef XMLPrefsParser::GetRefForServer()
{
ContainerRef result = GetConfigurationTag()->GetEmbeddedTagByName(kServer);
if (result == NULL)
{
result = new XMLTag(kServer);
GetRootTag()->AddEmbeddedTag(result);
}
return result;
}
UInt32 XMLPrefsParser::GetNumPrefValues(ContainerRef pref)
{
if (!strcmp(pref->GetTagName(), kPref))
{
if (pref->GetValue() == NULL)
return 0;
else
return 1;
}
else if (!strcmp(pref->GetTagName(), kObject))
return 1;
else if (!strcmp(pref->GetTagName(), kEmptyObject))
return 0;
return pref->GetNumEmbeddedTags(); // it must be a list
}
UInt32 XMLPrefsParser::GetNumPrefsByContainer(ContainerRef container)
{
return container->GetNumEmbeddedTags();
}
char* XMLPrefsParser::GetPrefValueByIndex(ContainerRef container, const UInt32 inPrefsIndex, const UInt32 inValueIndex,
char** outPrefName, char** outDataType)
{
if (outPrefName != NULL)
*outPrefName = NULL;
if (outPrefName != NULL)
*outDataType = NULL;
XMLTag* pref = container->GetEmbeddedTag(inPrefsIndex);
if (pref == NULL)
return NULL;
return GetPrefValueByRef(pref, inValueIndex, outPrefName, outDataType);
}
char* XMLPrefsParser::GetPrefValueByRef(ContainerRef pref, const UInt32 inValueIndex,
char** outPrefName, char** outDataType)
{
if (outPrefName != NULL)
*outPrefName = pref->GetAttributeValue(kNameAttr);
if (outDataType != NULL)
{
*outDataType = pref->GetAttributeValue(kTypeAttr);
if (*outDataType == NULL)
*outDataType = "CharArray";
}
if (!strcmp(pref->GetTagName(), kPref))
{
if (inValueIndex > 0)
return NULL;
else
return pref->GetValue();
}
if (!strcmp(pref->GetTagName(), kListPref))
{
XMLTag* value = pref->GetEmbeddedTag(inValueIndex);
if (value != NULL)
return value->GetValue();
}
if (!strcmp(pref->GetTagName(), kObject) || !strcmp(pref->GetTagName(), kObjectList))
*outDataType = "QTSS_Object";
return NULL;
}
ContainerRef XMLPrefsParser::GetObjectValue(ContainerRef pref, const UInt32 inValueIndex)
{
if (!strcmp(pref->GetTagName(), kObject) && (inValueIndex == 0))
return pref;
if (!strcmp(pref->GetTagName(), kObjectList))
return pref->GetEmbeddedTag(inValueIndex);
return NULL;
}
ContainerRef XMLPrefsParser::GetPrefRefByName( ContainerRef container,
const char* inPrefName)
{
return container->GetEmbeddedTagByAttr(kNameAttr, inPrefName);
}
ContainerRef XMLPrefsParser::GetPrefRefByIndex( ContainerRef container,
const UInt32 inPrefsIndex)
{
return container->GetEmbeddedTag(inPrefsIndex);
}
ContainerRef XMLPrefsParser::AddPref( ContainerRef container, char* inPrefName,
char* inPrefDataType )
{
XMLTag* pref = container->GetEmbeddedTagByAttr(kNameAttr, inPrefName);
if (pref != NULL)
return pref; // it already exists
pref = NEW XMLTag(kPref); // start it out as a pref
pref->AddAttribute(kNameAttr, inPrefName);
if (!strcmp(inPrefDataType, "QTSS_Object"))
pref->SetTagName(kEmptyObject);
else if (strcmp(inPrefDataType, "CharArray"))
pref->AddAttribute(kTypeAttr, (char*)inPrefDataType);
container->AddEmbeddedTag(pref);
return pref;
}
void XMLPrefsParser::AddPrefValue( ContainerRef pref, char* inNewValue)
{
if (!strcmp(pref->GetTagName(), kPref)) // is this a PREF tag
{
if (pref->GetValue() == NULL)
{
// easy case, no existing value, so just add a vlue
pref->SetValue(inNewValue);
return;
}
else
{
// it already has a value, so change the pref to be a list pref and go to code below
char* firstValue = pref->GetValue();
XMLTag* value = NEW XMLTag(kValue);
value->SetValue(firstValue);
pref->SetTagName(kListPref);
pref->SetValue(NULL);
pref->AddEmbeddedTag(value);
}
}
// we want to fall through from second case above, so this isn't an else
if (!strcmp(pref->GetTagName(), kListPref))
{
XMLTag* value = NEW XMLTag(kValue);
value->SetValue(inNewValue);
pref->AddEmbeddedTag(value);
}
}
void XMLPrefsParser::AddNewObject( ContainerRef pref )
{
if (!strcmp(pref->GetTagName(), kEmptyObject))
{
// just flag that this is now a real object instead of a placeholder
pref->SetTagName(kObject);
return;
}
if (!strcmp(pref->GetTagName(), kObject))
{
// change the object to be an object list and go to code below
XMLTag* subObject = NEW XMLTag(kObject);
XMLTag* objectPref;
// copy all this objects tags into the new listed object
while((objectPref = pref->GetEmbeddedTag()) != NULL)
{
pref->RemoveEmbeddedTag(objectPref);
subObject->AddEmbeddedTag(objectPref);
}
pref->SetTagName(kObjectList);
pref->AddEmbeddedTag(subObject);
}
// we want to fall through from second case above, so this isn't an else
if (!strcmp(pref->GetTagName(), kObjectList))
{
XMLTag* subObject = NEW XMLTag(kObject);
pref->AddEmbeddedTag(subObject);
}
}
void XMLPrefsParser::ChangePrefType( ContainerRef pref, char* inNewPrefDataType)
{
pref->RemoveAttribute(kTypeAttr); // remove it if it exists
if (strcmp(inNewPrefDataType, "CharArray"))
pref->AddAttribute(kTypeAttr, inNewPrefDataType);
}
void XMLPrefsParser::SetPrefValue( ContainerRef pref, const UInt32 inValueIndex,
char* inNewValue)
{
UInt32 numValues = GetNumPrefValues(pref);
if (((numValues == 0) || (numValues == 1)) && (inValueIndex == 0))
{
pref->SetValue(inNewValue);
}
else if (inValueIndex == numValues) // this is an additional value
AddPrefValue(pref, inNewValue);
else
{
XMLTag* value = pref->GetEmbeddedTag(inValueIndex);
if (value != NULL)
value->SetValue(inNewValue);
}
}
void XMLPrefsParser::RemovePrefValue( ContainerRef pref, const UInt32 inValueIndex)
{
UInt32 numValues = GetNumPrefValues(pref);
if (inValueIndex >= numValues)
return;
if (numValues == 1)
{
delete pref; // just remove the whole pref
}
else if (numValues == 2)
{
XMLTag* value = pref->GetEmbeddedTag(inValueIndex); // get the one we're removing
delete value; // delete it
value = pref->GetEmbeddedTag(0); // get the remaining tag index always 0 for 2 vals
pref->RemoveEmbeddedTag(value); // pull it out of the parent
if (!strcmp(pref->GetTagName(), kObjectList))
{
pref->SetTagName(kObject); // set it back to a simple pref
// move all this objects tags into the parent
XMLTag* objectPref;
while((objectPref = value->GetEmbeddedTag()) != NULL)
{
value->RemoveEmbeddedTag(objectPref);
pref->AddEmbeddedTag(objectPref);
}
}
else
{
char* temp = value->GetValue();
pref->SetTagName(kPref); // set it back to a simple pref
pref->SetValue(temp);
}
delete value; // get rid of the other one
}
else
{
XMLTag* value = pref->GetEmbeddedTag(inValueIndex);
if (value)
delete value;
}
}
void XMLPrefsParser::RemovePref( ContainerRef pref )
{
delete pref;
}
int XMLPrefsParser::Parse()
{
char error[500];
if (!ParseFile(error, sizeof(error)))
{
qtss_printf("%s\n", error);
return -1;
}
// the above routine checks that it's a valid XML file, we should check that
// all the tags conform to our prefs format
return 0;
}
int XMLPrefsParser::WritePrefsFile()
{
GetConfigurationTag(); // force it to be created if it doesn't exist
WriteToFile(kFileHeader);
return 0;
}

View file

@ -0,0 +1,122 @@
/*
*
* @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: XMLPrefsParser.h
Contains: A generic interface for pulling prefs.
*/
#ifndef __XML_PREFS_PARSER__
#define __XML_PREFS_PARSER__
#include "OSFileSource.h"
#include "OSQueue.h"
#include "StringParser.h"
#include "XMLParser.h"
typedef XMLTag* ContainerRef;
class XMLPrefsParser : public XMLParser
{
public:
XMLPrefsParser(char* inPath);
~XMLPrefsParser();
//
// Check for existence, man.
//
// PARSE & WRITE THE FILE. Returns true if there was an error
int Parse();
// Completely replaces old prefs file. Returns true if there was an error
int WritePrefsFile();
//
// ACCESSORS
ContainerRef GetRefForModule( char* inModuleName, Bool16 create = true);
ContainerRef GetRefForServer();
//
// Returns the number of pref values for the pref at this index
UInt32 GetNumPrefValues(ContainerRef pref);
//
// Returns the number of prefs associated with this given module
UInt32 GetNumPrefsByContainer(ContainerRef container);
//
// Returns the pref value at the specfied location
char* GetPrefValueByIndex(ContainerRef container, const UInt32 inPrefsIndex, const UInt32 inValueIndex,
char** outPrefName, char** outDataType);
char* GetPrefValueByRef(ContainerRef pref, const UInt32 inValueIndex,
char** outPrefName, char** outDataType);
ContainerRef GetObjectValue(ContainerRef pref, const UInt32 inValueIndex);
ContainerRef GetPrefRefByName( ContainerRef container,
const char* inPrefName);
ContainerRef GetPrefRefByIndex( ContainerRef container,
const UInt32 inPrefsIndex);
//
// MODIFIERS
//
// Creates a new pref. Returns the index of that pref. If pref already
// exists, returns existing index.
ContainerRef AddPref( ContainerRef container, char* inPrefName, char* inPrefDataType );
void ChangePrefType( ContainerRef pref, char* inNewPrefDataType);
void AddNewObject( ContainerRef pref );
void AddPrefValue( ContainerRef pref, char* inNewValue);
//
// If this value index does not exist yet, and it is one higher than
// the highest one, this function implictly adds the new value.
void SetPrefValue( ContainerRef pref, const UInt32 inValueIndex,
char* inNewValue);
//
// Removes the pref entirely if # of values drops to 0
void RemovePrefValue( ContainerRef pref, const UInt32 inValueIndex);
void RemovePref( ContainerRef pref );
private:
XMLTag* GetConfigurationTag();
};
#endif //__XML_PREFS_PARSER__

View file

@ -0,0 +1,154 @@
/*
*
* @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@
*
*/
/*
* get_opt.c
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(mac)
#include <types.h>
#endif
int get_opt(int argc, char *argv[], char *optList);
char *optarg = NULL;
char *whatOption = NULL;
int currentOpt = 0;
int optind = 1;
extern char gOptionsChar;
/* compareOptionString takes an option parameter with the following format:
* -REQuired : the characters in CAPS are required to match.
*/
static int compareOptionString(char *option, char *compareit) {
int i, l1, l2;
l1 = strlen(option);
l2 = strlen(compareit);
for (i=0; i<l2; i++) {
if (option[i] == '\0')
return -1; /* option < compareit */
if (tolower(option[i]) == tolower(compareit[i])) {
}
else {
if (option[i] > compareit[i])
return 1; /* option > compareit */
else
return -1; /* option < compareit */
}
}
/* if we got here, all of the characters in compareit are in option. */
/* now we've got to check if there are any more required characters. */
if (l1 > l2) { /* only need to check if option is longer than compareit */
if (option[l2] == toupper(option[l2]))
return 1; /* there was an additional character[s] needed. */
}
/* if we got here, then all is hunky dory and we got the required stuff. */
return 0;
}
int get_opt(int argc, char *argv[], char *optList) {
char option[256];
int l, i, c, opt;
currentOpt = optind;
optind++;
if (currentOpt >= argc) {
return EOF;
}
optarg = NULL;
whatOption = argv[currentOpt];
if (whatOption[0] != gOptionsChar) {
optarg = whatOption;
return 0;
}
l = strlen(optList);
i = 1;
c = 0;
opt = 1;
option[c++] = gOptionsChar;
while (i<=l) {
if (optList[i] == gOptionsChar) {
option[c++] = '\0';
// if (strncasecmp(option, whatOption, strlen(whatOption)) == 0)
if (compareOptionString(option, whatOption) == 0)
// return opt;
return option[1];
c = 1; // reset option string to '-' since we've just seen it
opt++; // check next option
}
else if (optList[i] == ':') {
option[c++] = '\0';
// if (strncasecmp(option, whatOption, strlen(whatOption)) == 0) {
if (compareOptionString(option, whatOption) == 0) {
currentOpt++; optind++;
optarg = argv[currentOpt];
// return opt;
return option[1];
}
c = 1; // reset option string to '-'
opt++; // check next option
i++; // pass over the :
if (optList[i] == gOptionsChar) {
; // this is where we want to be
}
else if (optList[i] == '\0') {
// return EOF; // this was the last option to check
return 0; // this was the last option to check
}
else {
fprintf(stderr, "Malformed getopt string '%s': character %d is '%c' was expecting %c\n", optList, i, optList[i], gOptionsChar);
return 0;
}
}
else if (optList[i] == '\0') {
option[c++] = '\0';
// if (strncasecmp(option, whatOption, strlen(whatOption)) == 0) {
if (compareOptionString(option, whatOption) == 0) {
// return opt;
return option[1];
}
optarg = argv[currentOpt];
// return EOF; // didn't find anything, return EOF
return 0; // didn't find anything, return EOF
}
else {
option[c++] = optList[i];
}
i++;
}
optarg = argv[currentOpt];
return 0;
}

View file

@ -0,0 +1,42 @@
/*
*
* @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@
*
*/
/*
* get_opt.h
*
*/
#ifndef __GETOPT_H__
#define __GETOPT_H__
extern char *optarg;
extern char *whatOption;
extern int currentOpt;
extern int optind;
int get_opt(int argc, char *argv[], char *optList);
#endif

1983
StreamingProxy.tproj/proxy.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,167 @@
/*
*
* @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@
*
*/
/*
* proxy.h
*
*
*/
#ifndef __PROXY_H__
#define __PROXY_H__
#include "shared_udp.h"
/**********************************************/
enum {
stIdle,
stError,
stRecvClientCommand,
stWaitingForIPAddress,
stParseClientCommand,
stSendClientResponse,
stServerTransactionSend,
stServerTransactionRecv,
stClientShutdown,
stServerShutdown,
stBadServerName,
stCantConnectToServer,
stDone
}; // rtsp session states
enum {
ttNone,
ttDescribe,
ttSetup,
ttPlay,
ttPause,
ttStop,
ttTeardown,
ttOptions,
ttAnnounce,
ttRedirect,
ttGetParameter,
ttSetParameter
}; // rtsp command types
enum {
kPermissionDenied,
kTooManyUsers,
kServerNotFound,
kUnknownError
}; // refusal type
typedef struct {
char *cmd;
int type;
} t_cmd_map;
#define MAX_TRACKS 32
typedef struct {
int ID;
shok *RTP_S2P;
shok *RTCP_S2P;
shok *RTP_P2C;
shok *RTCP_P2C;
int ClientRTPPort;
int ServerRTPPort;
trans_pb RTP_S2C_tpb;
trans_pb RTCP_S2C_tpb;
trans_pb RTCP_C2S_tpb;
} track_info;
/* This size will fit nicely in a standard ethernet frame */
#define RTSP_SESSION_BUF_SIZE 4096
typedef struct rtsp_session {
struct rtsp_session *next;
int die;
int newSession;
int client_skt;
int client_ip;
char *server_address;
int server_skt;
int server_interface_addr;
int client_interface_addr;
int server_ip;
int server_port;
int server_skt_pending_connection;
int state;
int transaction_type;
char *sessionID;
int cur_trk;
int numTracks;
track_info trk[MAX_TRACKS];
char cinbuf[RTSP_SESSION_BUF_SIZE];
int amtInClientInBuffer;
char coutbuf[RTSP_SESSION_BUF_SIZE];
int amtInClientOutBuffer;
char sinbuf[RTSP_SESSION_BUF_SIZE];
int amtInServerInBuffer;
char soutbuf[RTSP_SESSION_BUF_SIZE];
int amtInServerOutBuffer;
int totalContentLength;
int haveParsedServerReplyHeaders;
int contentLength;
char* responseBodyP;
int tempIP;
} rtsp_session;
typedef struct subnet_allow {
struct subnet_allow *next;
int ip;
int range;
} subnet_allow;
typedef struct rtsp_listener {
struct rtsp_listener *next;
int port;
int skt;
} rtsp_listener;
/**********************************************/
int service_listeners();
int service_sessions();
void add_rtsp_port_listener(int address,int port);
void cleanup_listeners(void);
void answer_new_connection(rtsp_listener *listener);
void add_session(rtsp_session *session);
void remove_session(rtsp_session *session);
rtsp_session *new_session(void);
void cleanup_sessions(void);
void cleanup_session(rtsp_session *session);
void service_session(rtsp_session *session);
void service_session_rtp(rtsp_session *session);
void read_config(void);
void add_allow_subnet(int ip, int range);
bool allow_ip(int ip);
void send_rtsp_error(int skt, int refusal);
#endif // __PROXY_H__

View file

@ -0,0 +1,166 @@
/*
*
* @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@
*
*/
/*
* proxy_plat.h
*
*
*/
#ifndef _PLAT_H_
#define _PLAT_H_
/**********************************************/
#define bool char
#if !defined(mac)
#define true 1
#define false 0
#endif
#if !defined(WIN32)
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#endif
/**********************************************/
#if defined(WIN32)
#define EACCES WSAEACCES
#define EINTR WSAEINTR
#define EAGAIN WSAEWOULDBLOCK /* good enough? */
#define EPIPE WSAESHUTDOWN /* good enough? */
#define ENOTCONN WSAENOTCONN
#define ECONNRESET WSAECONNRESET
#define EISCONN WSAEISCONN
#define EINPROGRESS WSAEINPROGRESS
#define EALREADY WSAEALREADY
#include "WINSOCK.H"
#elif defined(mac)
#define EACCES kEACCESErr
#define EPIPE kEPIPEErr
#define EINTR kEINTRErr
#define EAGAIN kEAGAINErr
#define ENOTCONN kENOTCONNErr
#define ECONNRESET kECONNRESETErr
#define EISCONN kEISCONNErr
#define EINPROGRESS kEINPROGRESSErr
#define EALREADY kEALREADYErr
#endif
/**********************************************/
#define MSEC_PER_SEC 1000
#define USEC_PER_SEC 1000000
#define USEC_PER_MSEC 1000
#define timer_sub(ntime,subtime,eqtime) \
if ((subtime).tv_usec > (ntime).tv_usec) { \
(eqtime).tv_sec = ((ntime).tv_sec - 1) - (subtime).tv_sec; \
(eqtime).tv_usec = (ntime).tv_usec + USEC_PER_SEC - \
(subtime).tv_usec; \
} \
else { \
(eqtime).tv_sec = (ntime).tv_sec - (subtime).tv_sec; \
(eqtime).tv_usec = (ntime).tv_usec - (subtime).tv_usec; \
}
extern char *gConfigFilePath;
extern char *gOptionsString;
extern char gOptionsChar;
typedef struct stats_chunk {
unsigned long elapsedSeconds;
unsigned long bpsReceived;
unsigned long bpsSent;
unsigned long ppsReceived;
unsigned long ppsSent;
unsigned long totalPacketsReceived;
unsigned long totalPacketsSent;
unsigned long numClients;
unsigned long numPorts;
float percentLostPackets;
} stats_chunk;
void daemonize(void);
int init_network(void);
int term_network(void);
int init_ui(void);
int service_ui(int sleep_ticks);
void sleep_milliseconds(int ms);
time_t microseconds();
#define kPENDING_ADDRESS -2
int name_to_ip_num(char *name, int *ip_num, int async);
int get_remote_address(int skt, int *port);
int get_local_address(int skt, int *port);
int get_local_ip_address(void);
bool isReadable(int fd);
bool isWritable(int fd);
int new_socket_udp(void);
int new_socket_tcp(int is_listener);
void close_socket(int skt);
void set_socket_reuse_address(int skt);
void set_socket_max_buf(int skt);
void make_socket_nonblocking(int skt);
int bind_socket_to_address(int skt, int address, int port, int is_listener);
int listen_to_socket(int skt);
int call_is_waiting(int skt, int *incoming_skt);
int accept_connection(int from, int *to);
int get_interface_addr(int skt);
#if DO_ASYNC
pascal void conn_finished_proc(void* contextPtr, OTEventCode code, OTResult /*result*/, void* /*cookie*/);
int connect_to_address(void *context, OTNotifyProcPtr proc, int skt, int address, int port);
#else
int connect_to_address(int skt, int address, int port);
#endif
int tcp_data_ready(int skt);
int recv_udp(int skt, char *buf, int amt, int *fromAddress, int *fromPort);
int send_udp(int skt, char *buf, int amt, int address, int port);
int recv_tcp(int skt, char *buf, int amt);
int send_tcp(int skt, char *buf, int amt);
// int make_udp_port_pair(int *socket1, int *socket2);
int GetLastSocketError(int skt);
void DoStats(stats_chunk *stats);
#if defined(mac) || defined(WIN32)
extern char gLastErrorString[256];
#define ErrorString(a) sprintf(gLastErrorString, a)
#define ErrorString1(a,b) sprintf(gLastErrorString, a, b)
#define ErrorStringS(a,b) sprintf(gLastErrorString, a, b)
#define DebugString(a) printf(a "\n")
#define DebugString1(a,b) printf(a "\n", b)
#define DebugStringS(a,b) printf(a "\n", b)
#else
void ErrorString(char *string);
void ErrorString1(char *string, int d);
void ErrorStringS(char *string, char *arg);
#define DebugString(a) printf(a "\n")
#define DebugString1(a,b) printf(a "\n", b)
#define DebugStringS(a,b) printf(a "\n", b)
#endif
#endif // _PLAT_H_

View file

@ -0,0 +1,579 @@
/*
*
* @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@
*
*/
/*
proxy_unix.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/resource.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "util.h"
#include "proxy_plat.h"
#if USE_THREAD
#include "pthread.h"
#endif
#include "../defaultPaths.h"
char *gConfigFilePath = DEFAULTPATHS_ETC_DIR "streamingproxy.conf";
char *gOptionsString = "-c:-p:-d-D-v-h-s-x-i:";
char gOptionsChar = '-';
extern int gMaxPorts;
extern float gDropPercent;
/**********************************************/
int init_network()
{
return 0;
}
/**********************************************/
#define kKILL_THREAD -3
int term_network()
{
int send = kKILL_THREAD;
name_to_ip_num("", &send, true);
return 0;
}
/**********************************************/
typedef struct ghpb_rec {
char name[256];
int *result;
} ghpb_rec, *ghpb;
#if USE_THREAD
void *gethostthread(void *param)
{
struct hostent *hent;
ghpb pb = (ghpb)param;
int id;
pthread_t tid;
int tryCount = 0;
if (*pb->result == kKILL_THREAD)
exit(0);
tid = pthread_self();
again:
hent = gethostbyname(pb->name);
if (hent == NULL) do
{
tryCount ++;
if (h_errno == TRY_AGAIN)
{ if (tryCount < 10)
goto again;
else
return 0;
}
*pb->result = -1;
pthread_exit(NULL);
} while(0);
id = ntohl(((struct in_addr *)(hent->h_addr_list[0]))->s_addr);
*pb->result = id;
free(pb);
pthread_exit(NULL);
return NULL;
}
#endif
/**********************************************/
int name_to_ip_num(char *name, int *ip, int async)
{
int ret;
struct in_addr addr;
int tryAgain = 0;
#if USE_THREAD
ghpb pb = NULL;
pthread_t tid;
#endif
struct hostent *hent;
if (check_IP_cache(name, &ret) != -1)
{
*ip = ret;
return 0;
}
#if USE_THREAD
if (async)
{
*ip = kPENDING_ADDRESS;
pb = (ghpb)malloc(sizeof(ghpb_rec));
strcpy(pb->name, name);
pb->result = ip;
pthread_create(&tid, NULL, gethostthread, (void*)pb);
pthread_detach(tid);
return 1;
}
#endif
again:
tryAgain ++;
if ( inet_aton( name, &addr ) )
{ *ip = ntohl( addr.s_addr );
add_to_IP_cache(name, *ip );
return 0;
}
hent = gethostbyname(name);
if (hent == NULL) {
if (h_errno == TRY_AGAIN)
if (tryAgain < 10)
goto again;
add_to_IP_cache(name, -1);
return -1;
}
*ip = ntohl(((struct in_addr *) (hent->h_addr_list[0]))->s_addr);
add_to_IP_cache(name, *ip);
return 0;
}
/**********************************************/
int get_remote_address(int skt, int *port)
{
#if !defined(sparc) && !defined(SGI) && !defined(WIN32)
unsigned
#endif
int nAddrSize = sizeof(struct sockaddr_in);
struct sockaddr_in remAddr;
int status;
remAddr.sin_addr.s_addr = INADDR_ANY;
status = getpeername(skt, (struct sockaddr*)&remAddr, &nAddrSize);
if (status >= 0)
{
if (port)
*port = ntohs(remAddr.sin_port);
return ntohl(remAddr.sin_addr.s_addr);
}
return -1;
}
/**********************************************/
int get_local_address(int skt, int *port) {
#if !defined(sparc) && !defined(SGI) && !defined(WIN32)
unsigned
#endif
int nAddrSize = sizeof(struct sockaddr_in);
struct sockaddr_in remAddr;
int status;
remAddr.sin_addr.s_addr = INADDR_ANY;
status = getsockname(skt, (struct sockaddr*)&remAddr, &nAddrSize);
if (status >= 0)
{
if (port)
*port = ntohs(remAddr.sin_port);
return ntohl(remAddr.sin_addr.s_addr);
}
return -1;
}
/**********************************************/
static int __local_ip_address = -1;
int get_local_ip_address()
{
char buf[256];
struct hostent *hent;
int tryCount = 0;
if (__local_ip_address != -1)
return __local_ip_address;
if (gethostname(buf, 256) < 0)
return -1;
again:
tryCount ++;
hent = gethostbyname(buf);
if (hent == NULL)
{ if (h_errno == TRY_AGAIN)
{ if (tryCount < 10)
{
goto again;
}
else
{
return 0;
}
}
return -1;
}
__local_ip_address = ntohl(((struct in_addr *)hent->h_addr)->s_addr);
return __local_ip_address;
}
/**********************************************/
void make_socket_nonblocking(int socket)
{
int flag;
flag = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flag | O_NONBLOCK);
}
/**********************************************/
void sleep_milliseconds(int ms)
{
struct timeval tv;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms - (tv.tv_sec * 1000) ) * 1000;
select(0, NULL, NULL, NULL, &tv);
}
/**********************************************/
time_t microseconds()
{
static bool us_initted = false;
static struct timeval us_time_zero;
struct timeval tv, t;
struct timezone tz;
gettimeofday(&tv, &tz);
if (us_initted == false)
{
us_initted = true;
us_time_zero = tv;
return 0;
}
else
{
timer_sub(tv, us_time_zero, t);
return (t.tv_sec * USEC_PER_SEC + t.tv_usec);
}
}
/**********************************************/
bool isReadable(int fd)
{
/* causes crash fd_set is wrong size if num users > 255
// not needed anyway
fd_set set;
struct timeval tv;
int err;
if (fd == INVALID_SOCKET)
return false;
tv.tv_sec = 0; tv.tv_usec = 0;
FD_ZERO(&set);
FD_SET(fd, &set);
err = select(fd+1, &set, NULL, NULL, &tv);
if (err > 0)
if (FD_ISSET(fd, &set))
return true;
return false;
*/
return true;
}
/**********************************************/
bool isWritable(int fd)
{
/* causes crash fd_set is wrong size if num users > 255
// not needed anyway
fd_set set;
struct timeval tv;
int err;
if (fd == INVALID_SOCKET)
return false;
tv.tv_sec = 0; tv.tv_usec = 0;
FD_ZERO(&set);
FD_SET(fd, &set);
err = select(fd+1, NULL, &set, NULL, &tv);
if (err > 0)
if (FD_ISSET(fd, &set))
return true;
return false;
*/
return true;
}
/**********************************************/
int new_socket_udp(void)
{
int ret;
ret = socket(PF_INET, SOCK_DGRAM, 0);
gMaxPorts++;
set_socket_max_buf(ret);
return ret;
}
/**********************************************/
int new_socket_tcp(int is_listener)
{
int ret;
ret = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
gMaxPorts++;
return ret;
}
/**********************************************/
void set_socket_reuse_address(int skt)
{
int i = 1;
setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof(i));
}
/**********************************************/
void set_socket_max_buf(int skt)
{
int i = 1;
unsigned int len;
len = sizeof(i);
getsockopt(skt, SOL_SOCKET, SO_SNDBUF, (char*)&i, &len);
/*fprintf(stderr, "sndbuf for socket %d was %d\n", skt, i);*/
i *= 2;
setsockopt(skt, SOL_SOCKET, SO_SNDBUF, (char*)&i, len);
getsockopt(skt, SOL_SOCKET, SO_SNDBUF, (char*)&i, &len);
/*fprintf(stderr, "sndbuf for socket %d is now %d\n", skt, i);*/
getsockopt(skt, SOL_SOCKET, SO_RCVBUF, (char*)&i, &len);
/*fprintf(stderr, "rcvbuf for socket %d was %d\n", skt, i);*/
i *= 2;
setsockopt(skt, SOL_SOCKET, SO_RCVBUF, (char*)&i, len);
getsockopt(skt, SOL_SOCKET, SO_RCVBUF, (char*)&i, &len);
/*fprintf(stderr, "rcvbuf for socket %d is now %d\n", skt, i);*/
}
/**********************************************/
int bind_socket_to_address(int skt, int address, int port, int is_listener)
{
struct sockaddr_in sin;
if (address == -1)
address = INADDR_ANY;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(address);
return bind(skt, (struct sockaddr*)&sin, sizeof(sin));
}
/**********************************************/
void close_socket(int skt)
{
if (skt != INVALID_SOCKET)
{
gMaxPorts--;
close(skt);
}
}
/**********************************************/
int listen_to_socket(int skt)
{
return listen(skt, 5);
}
/**********************************************/
int call_is_waiting(int skt, int *incoming_skt)
{
int ret;
ret = isReadable(skt);
if (ret)
{
*incoming_skt = accept(skt, 0, 0);
if (*incoming_skt <= 0)
{
ret = 0;
}
else
gMaxPorts++;
}
return ret;
}
/**********************************************/
int accept_connection(int from, int *to)
{
// return accept(from, 0, 0);
return *to;
}
/**********************************************/
int connect_to_address(int skt, int address, int port)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(address);;
return connect(skt, (struct sockaddr*)&sin, sizeof(sin));
}
int get_interface_addr(int skt)
{
int err = 0;
struct sockaddr_in localAddr;
unsigned int len = sizeof(localAddr);
memset(&localAddr, 0, sizeof(localAddr));
err = getsockname(skt, (struct sockaddr*)&localAddr, &len);
return ntohl(localAddr.sin_addr.s_addr);
}
/**********************************************/
int recv_udp(int socket, char *buf, int amt, int *fromip, int *fromport)
{
struct sockaddr_in sin;
int ret;
unsigned int len;
len = sizeof(sin);
memset(&sin, 0, sizeof(sin));
ret = recvfrom(socket, buf, (size_t) amt, 0, (struct sockaddr*)&sin, &len);
if (ret != -1) {
if (fromip)
*fromip = ntohl(sin.sin_addr.s_addr);
if (fromport)
*fromport = ntohs(sin.sin_port);
}
return ret;
}
/**********************************************/
int send_udp(int skt, char *buf, int amt, int address, int port)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(address);
return sendto(skt, buf, (size_t) amt, 0, (struct sockaddr*)&sin, sizeof(sin));
}
/**********************************************/
int recv_tcp(int socket, char *buf, int amt)
{
return read(socket, buf, (size_t) amt);
}
/**********************************************/
int send_tcp(int socket, char *buf, int amt)
{
return write(socket, buf, (size_t) amt);
}
/**********************************************/
int GetLastSocketError(int skt)
{
return errno;
}
/**********************************************/
int init_ui()
{
return 0;
}
/**********************************************/
int service_ui(int sleep_time)
{
return 0;
}
/**********************************************/
void DoStats(stats_chunk *stats)
{
printf("\033[2J\033[H");
printf("Elapsed Time (seconds) : %lu\n", stats->elapsedSeconds);
printf("Number of clients : %lu\n", stats->numClients);
printf("bps Received : %lu\n", stats->bpsReceived);
printf("bps Sent : %lu\n", stats->bpsSent);
printf("Total Packets Received : %lu\n", stats->totalPacketsReceived);
printf("Total Packets Sent : %lu\n", stats->totalPacketsSent);
printf("pps Received : %lu\n", stats->ppsReceived);
printf("pps Sent : %lu\n", stats->ppsSent);
printf("number of ports used : %lu\n", stats->numPorts);
printf("packet loss percent : %f\n", stats->percentLostPackets);
printf("force drop percent : %f\n",gDropPercent);
}
/**********************************************/
void ErrorString(char *string)
{
fprintf(stderr, string);
}
/**********************************************/
void ErrorString1(char *string, int d)
{
fprintf(stderr, string, d);
}
/**********************************************/
void ErrorStringS(char *string, char *arg)
{
fprintf(stderr, string, arg);
}
void daemonize()
{
switch (fork()) {
case -1: /* error */
fprintf(stderr, "can't daemonize!\n");
case 0: /* child */
break;
default: /* parent */
exit(0);
}
}

View file

@ -0,0 +1,474 @@
/*
*
* @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: shared_udp.c
Contains: UDP Sockets implementation with shared ports
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#if defined(unix)
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/resource.h>
#include <signal.h>
#include <sys/signal.h>
#include <sys/socket.h>
#elif defined(win32)
#include "WINSOCK.H"
#include "regex.h"
#elif defined(mac)
#include <MacTypes.h>
#include "OpenTransport.h"
#endif
#include "shared_udp.h"
#include "proxy_plat.h"
#if DEBUG
#define DEBUGPRINT(x) printf x
#else
#define DEBUGPRINT(x)
#endif
/**********************************************/
shok *gShokList = NULL;
/**********************************************/
ipList *find_ip_in_list(ipList *list, int ip)
{
ipList *cur = list;
DEBUGPRINT(( "-- -- looking for IP %x in IP list\n", ip));
while (cur) {
DEBUGPRINT(("-- -- vs. %x\n", cur->ip));
if (cur->ip == ip) {
DEBUGPRINT(("-- -- FOUND\n"));
return cur;
}
cur = cur->next;
}
DEBUGPRINT(("-- -- NOT FOUND\n"));
return NULL;
}
/**********************************************/
int add_ip_to_list(ipList **list, int ip)
{
ipList *newEl;
newEl = (ipList*)malloc(sizeof(ipList));
if (!newEl)
return false;
newEl->ip = ip;
newEl->what_to_do = NULL;
newEl->what_to_do_it_with = NULL;
newEl->next = *list;
*list = newEl;
return true;
}
/**********************************************/
int remove_ip_from_list(ipList **list, int ip)
{
ipList *last, *theEl = *list;
if (theEl->ip == ip) {
*list = theEl->next;
free(theEl);
return true;
}
last = theEl;
theEl = theEl->next;
while (theEl) {
if (theEl->ip == ip) {
last->next = theEl->next;
free(theEl);
return true;
}
last = theEl;
theEl = theEl->next;
}
return false;
}
/**********************************************/
shok *find_available_shok(int fromIP, int toIP, int withSib)
{
shok *cur = gShokList;
while (cur) {
DEBUGPRINT(("-- looking for IP %x in shok %p\n", toIP, cur));
if (find_ip_in_list(cur->ips, toIP) == NULL) {
if (withSib) {
DEBUGPRINT(("-- looking for IP %x in SIB shok %p\n", toIP, cur->sib));
if (find_ip_in_list(cur->sib->ips, toIP) == NULL)
return cur;
}
else
return cur;
}
cur = cur->next;
}
return NULL;
}
/**********************************************/
int add_ips_to_shok(shok *theShok, int fromIP, int toIP, int withSib)
{
add_ip_to_list(&(theShok->ips), toIP);
if (withSib)
add_ip_to_list(&(theShok->sib->ips), toIP);
return 1;
}
/**********************************************/
static int gUDPPortMin = 4000;
static int gUDPPortMax = 65536;
#define sInvalidPort -1
static int gNextPort = sInvalidPort;
void set_udp_port_min_and_max(int min, int max)
{
gUDPPortMin = min;
gUDPPortMax = max;
if (gUDPPortMin & 0x1)
gUDPPortMin++;
}
/**********************************************/
int remove_shok(shok *theShok, int withSib)
{
shok *cur = NULL, *last;
cur = gShokList;
if (cur == theShok) {
gShokList = cur->next;
goto doSib;
}
last = cur;
cur = cur->next;
while (cur) {
if (cur == theShok) {
last->next = cur->next;
goto doSib;
}
last = cur;
cur = cur->next;
}
return false;
doSib:
if (cur->sib)
cur->sib->sib = NULL;
if (withSib && cur->sib)
remove_shok(cur->sib, false);
{
ipList *ipn, *ipl = cur->ips;
while (ipl) {
ipn = ipl->next;
free(ipn);
ipl = ipn;
}
}
close_socket(cur->socket);
free(cur);
return true;
}
/**********************************************/
void remove_shok_ref(shok *theShok, int fromIP, int toIP, int withSib)
{
remove_ip_from_list(&(theShok->ips), toIP);
if (withSib)
remove_ip_from_list(&(theShok->sib->ips), toIP);
if (theShok->sib->ips == NULL)
remove_shok(theShok->sib, false);
if (theShok->ips == NULL)
remove_shok(theShok, false);
}
/**********************************************/
shok *make_new_shok(int fromIP, int toIP, int withSib)
{
shok *theShok1 = NULL, *theShok2 = NULL;
int skt1 = INVALID_SOCKET, skt2 = INVALID_SOCKET;
int port1 = sInvalidPort;
int port2 = sInvalidPort;
theShok1 = (shok*)malloc(sizeof(shok));
if (!theShok1)
goto bail_error;
if (withSib) {
theShok2 = (shok*)malloc(sizeof(shok));
if (!theShok2)
goto bail_error;
}
if (gNextPort == -1)
gNextPort = gUDPPortMin;
retry:
if ((skt1 = new_socket_udp()) == SOCKET_ERROR)
goto bail_error;
if (skt1 == 0) {
if (GetLastSocketError(skt1) == EINPROGRESS || GetLastSocketError(skt1) == EAGAIN)
goto retry;
else
goto bail_error;
}
do {
if ((gNextPort & 0x1) && withSib)
gNextPort++;
if (gNextPort > gUDPPortMax)
gNextPort = gUDPPortMin;
} while (bind_socket_to_address(skt1, fromIP, port1 = gNextPort++, false) != 0);
if (withSib) {
retry_rtcp:
if ((skt2 = new_socket_udp()) == SOCKET_ERROR)
goto bail_error;
if (skt2 == 0) {
if (GetLastSocketError(skt2) == EINPROGRESS || GetLastSocketError(skt2) == EAGAIN)
goto retry_rtcp;
else
goto bail_error;
}
if (bind_socket_to_address(skt2, fromIP, port2 = gNextPort++, false) != 0) {
close_socket(skt1);
close_socket(skt2);
skt1 = INVALID_SOCKET;
skt2 = INVALID_SOCKET;
goto retry;
}
}
make_socket_nonblocking(skt1);
theShok1->socket = skt1;
theShok1->port = port1;
theShok1->ips = NULL;
if (withSib) {
make_socket_nonblocking(skt2);
theShok2->socket = skt2;
theShok2->port = port2;
theShok2->ips = NULL;
theShok2->sib = theShok1;
theShok1->sib = theShok2;
theShok1->next = theShok2;
theShok2->next = gShokList;
}
else {
theShok1->sib = NULL;
theShok1->next = gShokList;
}
add_ips_to_shok(theShok1, fromIP, toIP, withSib);
gShokList = theShok1;
return theShok1;
bail_error:
printf("make_new_shok bail_error\n");
close_socket(skt1);
close_socket(skt2);
if (theShok1 != NULL)
free(theShok1);
if (theShok2 != NULL)
free(theShok2);
return NULL;
}
/**********************************************/
int make_udp_port_pair(int fromIP, int toIP, shok **rtpSocket, shok **rtcpSocket)
{
shok *theShok;
DEBUGPRINT(("MAKE_UDP_PORT_PAIR from %x to %x\n", fromIP, toIP));
DEBUGPRINT(("looking for available shok\n"));
if ((theShok = find_available_shok(fromIP, toIP, true)) != NULL) {
DEBUGPRINT(("found available shok : SOCKET [%d] PORT [%d]\n", theShok->socket, theShok->port));
add_ips_to_shok(theShok, fromIP, toIP, true);
}
else {
theShok = make_new_shok(fromIP, toIP, true);
DEBUGPRINT(("couldn't find shok - made new one : SOCKET [%d] PORT [%d]\n", theShok->socket, theShok->port));
}
if (theShok && theShok->sib) {
*rtpSocket = theShok;
*rtcpSocket = theShok->sib;
return 1;
}
else
return -1;
}
/**********************************************/
int upon_receipt_from(shok *theShok, int fromIP, do_routine doThis, void *withThis)
{
ipList *listEl;
DEBUGPRINT(( "UPON_RECEIPT_FROM %x do routine %p\n", fromIP, doThis));
listEl = find_ip_in_list(theShok->ips, fromIP);
if (!listEl)
return -1;
listEl->what_to_do = doThis;
listEl->what_to_do_it_with = withThis;
return 0;
}
/**********************************************/
extern int gNeedsService;
extern unsigned long gPacketsReceived;
extern unsigned long gPacketsSent;
extern unsigned long gBytesReceived;
extern unsigned long gBytesSent;
extern float gDropPercent;
extern unsigned long gDropDelta;
/**********************************************/
int service_shoks()
{
shok *cur;
char buf[2048];
cur = gShokList;
while (cur) {
do_routine doit;
int ret, fromPort, fromIP;
again:
doit = NULL;
ret = recv_udp(cur->socket, buf, 2048, &fromIP, &fromPort);
if (ret > 0) {
ipList *ipl = NULL;
DEBUGPRINT(("Got %d bytes for %x on port %d on socket %d\n", ret, fromIP, fromPort, cur->socket));
gBytesReceived += ret;
gPacketsReceived++;
ipl = find_ip_in_list(cur->ips, fromIP);
if (ipl)
doit = ipl->what_to_do;
if (doit && ipl) {
gNeedsService++;
ret = (*doit)(ipl->what_to_do_it_with, buf, ret);
if (ret == -1) {
// what to do about termination, etc.
DEBUGPRINT(("put returns error %d\n", errno));
}
else if (ret == 0) {
// client/server whatever died
if (((trans_pb*)ipl->what_to_do_it_with)->status)
*(((trans_pb*)ipl->what_to_do_it_with)->status) = 1;
DEBUGPRINT(("client/server died\n"));
}
// what to do about incomplete packet transmission
}
goto again;
}
else if (ret < 0) {
if (errno != 11)
DEBUGPRINT(("recv_udp returns errno %d\n", errno));
// what to do about termination, etc.
}
cur = cur->next;
}
return 0;
}
/**********************************************/
int transfer_data(void *refCon, char *buf, int bufSize)
{
trans_pb *tpb = (trans_pb*)refCon;
int ret;
int isRTCP = 0;
if (!tpb)
return -1;
if (strstr(tpb->socketName,"RTCP"))
{ //printf("shared_udp.c transfer_data %s\n",tpb->socketName);
isRTCP = 1;
}
tpb->packetCount++;
if (gDropPercent > 0.0 )
{ int packetDropped = 0;
//printf("transfer_data tpb->nextDropPacket=%qd tpb->packetCount=%qd\n",tpb->nextDropPacket, tpb->packetCount);
if (tpb->packetCount == tpb->nextDropPacket)
{ tpb->droppedPacketCount ++;
tpb->nextDropPacket = 0;
//printf("transfer_data tpb->droppedPacketCount=%qd tpb->packetCount=%qd\n",tpb->droppedPacketCount, tpb->packetCount);
packetDropped = 1;
}
if (tpb->nextDropPacket == 0)
{
int offset = 0;
if (gDropPercent <= 50.0)
offset = 100.0 / gDropPercent; // drop the percent packet
else if (gDropPercent < 100.0 )
offset = 1 + ( ( (rand() % 49) <= ( gDropPercent - 47.0) ) ? 0 : 1);// drop random 1 to 2 packets 1 == next packet or 100% 2== every other 50%
else
offset = 1; // 100% = drop next packet
tpb->nextDropPacket = tpb->packetCount + offset;
}
if (packetDropped)
return bufSize;
}
ret = send_udp(tpb->send_from->socket, buf, bufSize, tpb->send_to_ip, tpb->send_to_port);
DEBUGPRINT(("Sent %d bytes to %x on port %d on socket %d\n",
ret, tpb->send_to_ip, tpb->send_to_port, tpb->send_from->socket));
if (ret > 0)
{ gBytesSent += ret;
gPacketsSent++;
}
return ret;
}

View file

@ -0,0 +1,84 @@
/*
*
* @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: shared_udp.h
Contains: udp sockets implementation with shared ports
*/
#ifndef __SHARED_UDP_H__
#define __SHARED_UDP_H__
#define MAX_SOCKET_NAME 32
/**********************************************/
typedef int (*do_routine)(void * refCon, char *buf, int bufSize);
typedef struct ipList {
struct ipList *next;
int ip;
do_routine what_to_do;
void *what_to_do_it_with;
} ipList;
typedef struct shok {
struct shok *next;
int socket;
int port;
ipList *ips;
struct shok *sib; // sibling - rtcp or rtp
} shok;
typedef struct trans_pb {
int *status; // set to 1 when needs to die
shok *send_from;
int send_to_ip;
int send_to_port;
long long int packetSendCount;
long long int nextDropPacket;
long long int droppedPacketCount;
long long int packetCount;
char socketName[MAX_SOCKET_NAME];
} trans_pb;
/**********************************************/
ipList *find_ip_in_list(ipList *list, int ip);
int add_ip_to_list(ipList **list, int ip);
int remove_ip_from_list(ipList **list, int ip);
shok *find_available_shok(int fromIP, int toIP, int withSib);
int add_ips_to_shok(shok *theShok, int fromIP, int toIP, int withSib);
void set_udp_port_min_and_max(int min, int max);
int remove_shok(shok *theShok, int withSib);
void remove_shok_ref(shok *theShok, int fromIP, int toIP, int withSib);
shok *make_new_shok(int fromIP, int toIP, int withSib);
int make_udp_port_pair(int fromIP, int toIP, shok **rtpSocket, shok **rtcpSocket);
int upon_receipt_from(shok *theShok, int fromIP, do_routine doThis, void *withThis);
int service_shoks();
int transfer_data(void *refCon, char *buf, int bufSize);
#endif // __SHARED_UDP_H__

273
StreamingProxy.tproj/util.c Normal file
View file

@ -0,0 +1,273 @@
/*
*
* @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@
*
*/
/*
* util.c
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <assert.h>
#include "util.h"
static char to_lower(int c);
/**********************************************/
static char ip_string_buffer[20];
char *ip_to_string(int ip) {
sprintf(ip_string_buffer, "%d.%d.%d.%d",
(ip & 0xff000000) >> 24, (ip & 0x00ff0000) >> 16,
(ip & 0x0000ff00) >> 8, (ip & 0x000000ff));
return ip_string_buffer;
}
/**********************************************/
static char to_lower(int c)
{
if (c >= 'A' && c <= 'Z')
return ((c - 'A') + 'a');
return c;
}
/**********************************************/
char *str_dup(char *str)
{
char *ret;
ret = (char*)malloc(strlen(str)+1);
strcpy(ret, str);
return ret;
}
/**********************************************/
int str_casecmp(char *str1, char *str2)
{
int ret;
ret = *str1 - *str2;
while (*str1 && *str2 && ((ret = *str1++ - *str2++) == 0))
;
return ret;
}
/**********************************************/
int strn_casecmp(char *str1, char *str2, int l)
{
int ret;
ret = to_lower( (char) *str1) - to_lower((char) *str2);
while (l-- && to_lower(*str1) && to_lower(*str2) && ((ret = to_lower(*str1++) - to_lower(*str2++)) == 0))
;
return ret;
}
/*
grab a full line from input
put into strBuff as 0 terminated
must maintain the exact eol that the
input string has.
return next position.
*/
char* get_line_str( char* strBuff, char *input, int buffSize)
{
char *p = input;
int sawEOLChar = 0;
assert( strBuff != NULL && input != NULL && buffSize > 0);
memset(strBuff, 0, (size_t) buffSize);
while( *p )
{
assert( buffSize > 0 );
if ( *p == '\r' || *p == '\n' )
{ // grab all eol chars
sawEOLChar = 1;
*strBuff = *p;
strBuff++;
buffSize--;
}
else if ( sawEOLChar )
{
// we saw eol char(s) and now this is not one
// that means we're done
break;
}
else
{
// grab all line chars
*strBuff = *p;
strBuff++;
buffSize--;
}
p++;
}
*strBuff = 0;
// we're not going to change the contents
// of input, but the caller may have the right too.
return (char*)p;
}
/**********************************************
subdivide a string along the delimeter
points in delim
return the next start point in stringp
return the current string start;
*/
char *str_sep(char **stringp, char *delim)
{
int j, dl, i, sl;
char *newstring, *ret;
if (*stringp == NULL)
return NULL;
dl = strlen(delim);
sl = strlen(*stringp);
newstring = NULL;
ret = *stringp;
for (i=0; i<sl; i++)
{
for (j=0; j<dl; j++)
{
if ((*stringp)[i] == delim[j])
{
(*stringp)[i] = '\0';
newstring = &((*stringp)[i+1]);
i = sl; j = dl;
}
}
}
*stringp = newstring;
return ret;
}
/**********************************************/
typedef struct t_ip_cache {
struct t_ip_cache *next;
char *name;
int ip;
} t_ip_cache;
static t_ip_cache *gIPcache = NULL;
int check_IP_cache(char *name, int *ip)
{
t_ip_cache *cur = gIPcache;
while (cur) {
if (str_casecmp(name, cur->name) == 0) {
*ip = cur->ip;
return 0;
}
cur = cur->next;
}
return -1;
}
/**********************************************/
int add_to_IP_cache(char *name, int ip)
{
t_ip_cache *cur;
cur = (t_ip_cache*)malloc(sizeof(t_ip_cache));
if (cur == NULL)
return -1;
cur->ip = ip;
cur->name = malloc(strlen(name) + 1);
strcpy(cur->name, name);
cur->next = gIPcache;
gIPcache = cur;
return 0;
}
/**********************************************/
int inet_aton_(char *s, int *retval)
{
int i, l, x, el[4], ret, good = 1;
x = 0, ret = 0;
l = strlen(s);
el[0] = 0;
for (i=0; i<l; i++) {
if (s[i] == '.') {
x++;
if (x > 3) {
good = 0;
break;
}
el[x] = 0;
}
else if (s[i] >= '0' && s[i] <= '9') {
el[x] *= 10;
el[x] += s[i] - '0';
}
else
good = 0;
}
switch (x) {
case 3:
ret = ( ((el[0] << 24) & 0xff000000) |
((el[1] << 16) & 0x00ff0000) |
((el[2] << 8 ) & 0x0000ff00) |
(el[3] & 0x000000ff) );
break;
case 2:
ret = ( ((el[0] << 24) & 0xff000000) |
((el[1] << 16) & 0x00ff0000) |
(el[2] & 0x0000ffff) );
break;
case 1:
ret = (((el[0] << 24) & 0xff000000) |
(el[1] & 0x00ffffff) );
break;
case 0:
ret = el[0];
break;
}
*retval = ret;
return good;
}

View file

@ -0,0 +1,42 @@
/*
*
* @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@
*
*/
/*
* util.h
*
*
*/
/**********************************************/
char *ip_to_string(int ip);
int inet_aton_(char *s, int *retval);
char *str_sep(char **stringp, char *delim);
char *str_dup(char *str);
int str_casecmp(char *str1, char *str2);
int strn_casecmp(char *str1, char *str2, int l);
int check_IP_cache(char *name, int *ip);
int add_to_IP_cache(char *name, int ip);
char* get_line_str( char* strBuff, char *input, int buffSize );

68
defaultPaths.h Normal file
View file

@ -0,0 +1,68 @@
/*
*
* @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@
*
*/
/*
* defaultPaths.h - define the default paths to hardcode into the executables
*
* IMPORTANT NOTE : The trailering directory separators are required on all
* DEFAULTPATHS_*_DIR* defines
*
* Contributed by: Peter Bray
*/
#ifdef __Win32__
# define DEFAULTPATHS_DIRECTORY_SEPARATOR "\\"
# define DEFAULTPATHS_ETC_DIR "c:\\Program Files\\Darwin Streaming Server\\"
# define DEFAULTPATHS_ETC_DIR_OLD "c:\\Program Files\\Darwin Streaming Server\\"
# define DEFAULTPATHS_SSM_DIR "c:\\Program Files\\Darwin Streaming Server\\QTSSModules\\"
# define DEFAULTPATHS_LOG_DIR "c:\\Program Files\\Darwin Streaming Server\\Logs\\"
# define DEFAULTPATHS_MOVIES_DIR "c:\\Program Files\\Darwin Streaming Server\\Movies\\"
# define DEFAULTPATHS_PID_FILE ""
# define DEFAULTPATHS_PID_DIR ""
#elif __MacOSX__
# define DEFAULTPATHS_DIRECTORY_SEPARATOR "/"
# define DEFAULTPATHS_ETC_DIR "/Library/QuickTimeStreaming/Config/"
# define DEFAULTPATHS_ETC_DIR_OLD "/etc/"
# define DEFAULTPATHS_SSM_DIR "/Library/QuickTimeStreaming/Modules/"
# define DEFAULTPATHS_LOG_DIR "/Library/QuickTimeStreaming/Logs/"
# define DEFAULTPATHS_MOVIES_DIR "/Library/QuickTimeStreaming/Movies/"
# define DEFAULTPATHS_PID_DIR "/var/run/"
#else
# define DEFAULTPATHS_DIRECTORY_SEPARATOR "/"
# define DEFAULTPATHS_ETC_DIR "/etc/streaming/"
# define DEFAULTPATHS_ETC_DIR_OLD "/etc/"
# define DEFAULTPATHS_SSM_DIR "/usr/local/sbin/StreamingServerModules/"
# define DEFAULTPATHS_LOG_DIR "/var/streaming/logs/"
# define DEFAULTPATHS_MOVIES_DIR "/usr/local/movies/"
# define DEFAULTPATHS_PID_DIR "/var/run/"
#endif

41
revision.h Normal file
View file

@ -0,0 +1,41 @@
/*
*
* @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@
*
*/
/* revision.h -- define the version number
*/
// Use no http/rtsp tspecial chars in kVersionString and kBuildString defines
// tspecials = ()<>@,;:\/"[]?=
#define kVersionString "6.0.3"
#define kBuildString "526.3"
// Use kCommentString for seed or other release info
// Do not use '(' or ')' in the kCommentString
// form = token1/info; token2/info;
// example "Release/public seed 1; Event/Big Event; state/half-baked"
#define kCommentString "Release/Darwin Streaming Server; State/Development; "

BIN
sample.mp3 Normal file

Binary file not shown.

BIN
sample_100kbit.mov Normal file

Binary file not shown.

BIN
sample_100kbit.mp4 Normal file

Binary file not shown.

BIN
sample_300kbit.mov Normal file

Binary file not shown.

BIN
sample_300kbit.mp4 Normal file

Binary file not shown.

BIN
sample_h264_100kbit.mp4 Normal file

Binary file not shown.

BIN
sample_h264_1mbit.mp4 Normal file

Binary file not shown.

BIN
sample_h264_300kbit.mp4 Normal file

Binary file not shown.