Add even more of the source

This should be about everything needed to build so far?
This commit is contained in:
Darren VanBuren 2017-03-07 17:14:16 -08:00
parent af3619d4fa
commit 849723c9cf
547 changed files with 149239 additions and 0 deletions

View file

@ -0,0 +1,251 @@
/*
*
* @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 "ConfParser.h"
#include "OSMemory.h"
#include "MyAssert.h"
#include "OSHeaders.h"
#include <stdlib.h>
#include "GetWord.h"
#include "Trim.h"
#include <string.h>
#include <stdio.h>
static Bool16 SampleConfigSetter( const char* paramName, const char* paramValue[], void* userData );
static void DisplayConfigErr( const char*fname, int lineCount, const char*lineBuff, const char *errMessage );
void TestParseConfigFile()
{
ParseConfigFile( false, "qtss.conf", SampleConfigSetter, NULL );
}
static Bool16 SampleConfigSetter( const char* paramName, const char* paramValue[], void* /*userData*/ )
{
qtss_printf( "param: %s", paramName );
int x = 0;
while ( paramValue[x] )
{
qtss_printf( " value(%"_S32BITARG_"): %s ", (SInt32)x, (char *) paramValue[x] );
x++;
}
qtss_printf( "\n" );
return false;
}
static void DisplayConfigErr( const char*fname, int lineCount, const char*lineBuff, const char *errMessage )
{
qtss_printf( "- Configuration file error:\n" );
if ( lineCount )
qtss_printf( " file: %s, line# %i\n", fname, lineCount );
else
qtss_printf( " file: %s\n", fname );
if ( lineBuff )
qtss_printf( " text: %s", lineBuff ); // lineBuff already includes a \n
if ( errMessage )
qtss_printf( " reason: %s\n", errMessage ); // lineBuff already includes a \n
}
int ParseConfigFile(
Bool16 allowNullValues
, const char* fname
, Bool16 (*ConfigSetter)( const char* paramName, const char* paramValue[], void* userData )
, void* userData )
{
int error = -1;
FILE *configFile;
int lineCount = 0;
Assert( fname );
Assert( ConfigSetter );
if (!fname) return error;
if (!ConfigSetter) return error;
configFile = fopen( fname, "r" );
// Assert( configFile );
if ( configFile )
{
SInt32 lineBuffSize = kConfParserMaxLineSize;
SInt32 wordBuffSize = kConfParserMaxParamSize;
char lineBuff[kConfParserMaxLineSize];
char wordBuff[kConfParserMaxParamSize];
char *next;
// debug assistance -- CW debugger won't display large char arrays as strings
//char* l = lineBuff;
//char* w = wordBuff;
do
{
next = lineBuff;
// get a line ( fgets adds \n+ 0x00 )
if ( fgets( lineBuff, lineBuffSize, configFile ) == NULL )
break;
lineCount++;
error = 0; // allow empty lines at beginning of file.
// trim the leading whitespace
next = TrimLeft( lineBuff );
if (*next)
{
if ( *next == '#' )
{
// it's a comment
// prabably do nothing in release version?
// qtss_printf( "comment: %s" , &lineBuff[1] );
error = 0;
}
else
{ char* param;
// grab the param name, quoted or not
if ( *next == '"' )
next = GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = GetWord( wordBuff, next, wordBuffSize );
Assert( *wordBuff );
param = NEW char[strlen( wordBuff ) + 1 ];
Assert( param );
if ( param )
{
const char* values[kConfParserMaxParamValues+1];
int maxValues = 0;
strcpy( param, wordBuff );
values[maxValues] = NULL;
while ( maxValues < kConfParserMaxParamValues && *next )
{
// ace
next = TrimLeft( next );
if (*next)
{
if ( *next == '"' )
next = GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = GetWord( wordBuff, next, wordBuffSize );
char* value = NEW char[strlen( wordBuff ) + 1 ];
Assert( value );
if ( value )
{
strcpy( value, wordBuff );
values[maxValues++] = value;
values[maxValues] = 0;
}
}
}
if ( (maxValues > 0 || allowNullValues) && !(*ConfigSetter)( param, values, userData ) )
error = 0;
else
{ error = -1;
if ( maxValues > 0 )
DisplayConfigErr( fname, lineCount, lineBuff, "Parameter could not be set." );
else
DisplayConfigErr( fname, lineCount, lineBuff, "No value to set." );
}
delete [] param;
maxValues = 0;
while ( values[maxValues] )
{ char** tempValues = (char**)values; // Need to do this to delete a const
delete [] tempValues[maxValues];
maxValues++;
}
}
}
}
} while ( feof( configFile ) == 0 && error == 0 );
(void)fclose( configFile );
}
// else
// {
// qtss_printf("Couldn't open config file at: %s\n", fname);
// }
return error;
}

View file

@ -0,0 +1,49 @@
#ifndef __ConfParser__
#define __ConfParser__
/*
*
* @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 "OSHeaders.h"
// the maximum size + 1 of a parameter
#define kConfParserMaxParamSize 512
// the maximum size + 1 of single line in the file
#define kConfParserMaxLineSize 1024
// the maximum number of values per config parameter
#define kConfParserMaxParamValues 10
void TestParseConfigFile();
int ParseConfigFile( Bool16 allowNullValues, const char* fname \
, Bool16 (*ConfigSetter)( const char* paramName, const char* paramValue[], void * userData ) \
, void* userData );
#endif

View file

@ -0,0 +1,159 @@
/*
*
* @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: DateTranslator.h
Contains: Efficient routines & data structures for converting from
RFC 1123 compliant date strings to local file system dates & vice versa.
*/
#include "DateTranslator.h"
#include <time.h>
#include "OSHeaders.h"
#include "OS.h"
#include "StringParser.h"
#include "StrPtrLen.h"
// If you assign values of 0 - 25 for all the letters, and sum up the values of
// the letters in each month, you get a table that looks like this. For instance,
// "Jul" = 9 + 20 + 11 = 40. The value of July in a C tm struct is 6, so position
// 40 = 6 in this array.
const UInt32 kMonthHashTable[] =
{
12, 12, 12, 12, 12, 12, 12, 12, 12, 11, // 0 - 9
1, 12, 12, 12, 12, 12, 12, 12, 12, 12, // 10 - 19
12, 12, 0, 12, 12, 12, 7, 12, 12, 2, // 20 - 29
12, 12, 3, 12, 12, 9, 4, 8, 12, 12, // 30 - 39
6, 12, 5, 12, 12, 12, 12, 12, 10, 12 // 40 - 49
};
const UInt32 kMonthHashTableSize = 49;
SInt64 DateTranslator::ParseDate(StrPtrLen* inDateString)
{
//SEE RFC 1123 for details on the date string format
//ex: Mon, 04 Nov 1996 21:42:17 GMT
// Parse the date buffer, filling out a tm struct
struct tm theDateStruct;
::memset(&theDateStruct, 0, sizeof(theDateStruct));
// All RFC 1123 dates are the same length.
if (inDateString->Len != DateBuffer::kDateBufferLen)
return 0;
StringParser theDateParser(inDateString);
// the day of the week is redundant... we can skip it!
theDateParser.ConsumeLength(NULL, 5);
// We are at the date now.
theDateStruct.tm_mday = theDateParser.ConsumeInteger(NULL);
theDateParser.ConsumeWhitespace();
// We are at the month now. Use our hand-crafted perfect hash table
// to get the right value to place in the tm struct
if (theDateParser.GetDataRemaining() < 4)
return 0;
UInt32 theIndex = ConvertCharToMonthTableIndex(theDateParser.GetCurrentPosition()[0]) +
ConvertCharToMonthTableIndex(theDateParser.GetCurrentPosition()[1]) +
ConvertCharToMonthTableIndex(theDateParser.GetCurrentPosition()[2]);
if (theIndex > kMonthHashTableSize)
return 0;
theDateStruct.tm_mon = kMonthHashTable[theIndex];
// If the month is illegal, return an error
if (theDateStruct.tm_mon >= 12)
return 0;
// Skip over the date
theDateParser.ConsumeLength(NULL, 4);
// Grab the year (years since 1900 is what the tm struct wants)
theDateStruct.tm_year = theDateParser.ConsumeInteger(NULL) - 1900;
theDateParser.ConsumeWhitespace();
// Now just grab hour, minute, second
theDateStruct.tm_hour = theDateParser.ConsumeInteger(NULL);
theDateStruct.tm_hour += OS::GetGMTOffset();
theDateParser.ConsumeLength(NULL, 1); //skip over ':'
theDateStruct.tm_min = theDateParser.ConsumeInteger(NULL);
theDateParser.ConsumeLength(NULL, 1); //skip over ':'
theDateStruct.tm_sec = theDateParser.ConsumeInteger(NULL);
// Ok, we've filled out the tm struct completely, now convert it to a time_t
time_t theTime = ::mktime(&theDateStruct);
return (SInt64)theTime * 1000; // convert to a time value in our timebase.
}
void DateTranslator::UpdateDateBuffer(DateBuffer* inDateBuffer, const SInt64& inDate, time_t gmtoffset)
{
if (inDateBuffer == NULL)
return;
struct tm* gmt = NULL;
struct tm timeResult;
if (inDate == 0)
{
time_t calendarTime = ::time(NULL) + gmtoffset;
gmt = ::qtss_gmtime(&calendarTime, &timeResult);
}
else
{
time_t convertedTime = (time_t)(inDate / (SInt64)1000) + gmtoffset ; // Convert from msec to sec
gmt = ::qtss_gmtime(&convertedTime, &timeResult);
}
Assert(gmt != NULL); //is it safe to assert this?
size_t size = 0;
if (0 == gmtoffset)
size = qtss_strftime( inDateBuffer->fDateBuffer, sizeof(inDateBuffer->fDateBuffer),
"%a, %d %b %Y %H:%M:%S GMT", gmt);
Assert(size == DateBuffer::kDateBufferLen);
}
void DateBuffer::InexactUpdate()
{
SInt64 theCurTime = OS::Milliseconds();
if ((fLastDateUpdate == 0) || ((fLastDateUpdate + kUpdateInterval) < theCurTime))
{
fLastDateUpdate = theCurTime;
this->Update(0);
}
}

View file

@ -0,0 +1,113 @@
/*
*
* @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: DateTranslator.h
Contains: Efficient routines & data structures for converting from
RFC 1123 compliant date strings to local file system dates & vice versa.
*/
#ifndef _DATE_TRANSLATOR_H_
#define _DATE_TRANSLATOR_H_
#include <ctype.h>
#include <time.h>
#include "StrPtrLen.h"
class DateBuffer;
class DateTranslator
{
public:
// this updates the DateBuffer to be the current date / time.
// If you wish to set the DateBuffer to a particular date, pass in that date.
// Dates should be in the OS.h compliant format
static void UpdateDateBuffer(DateBuffer* inDateBuffer, const SInt64& inDate, time_t gmtoffset = 0);
//Given an HTTP/1.1 compliant date string (in one of the three 1.1 formats)
//this returns an OS.h compliant date/time value.
static SInt64 ParseDate(StrPtrLen* inDateString);
private:
static UInt32 ConvertCharToMonthTableIndex(int inChar)
{
return (UInt32)(toupper(inChar) - 'A'); // Convert to a value between 0 - 25
}
};
class DateBuffer
{
public:
// This class provides no protection against being accessed from multiple threads
// simultaneously. Update & InexactUpdate rewrite the date buffer, so care should
// be taken to protect against simultaneous access.
DateBuffer() : fLastDateUpdate(0) { fDateBuffer[0] = 0; }
~DateBuffer() {}
//SEE RFC 1123 for details on the date string format
//ex: Mon, 04 Nov 1996 21:42:17 GMT
//RFC 1123 date strings are always of this length
enum
{
kDateBufferLen = 29
};
// Updates this date buffer to reflect the current time.
// If a date is provided, this updates the DateBuffer to be that date.
void Update(const SInt64& inDate) { DateTranslator::UpdateDateBuffer(this, inDate); }
// Updates this date buffer to reflect the current time, with a certain degree
// of inexactitude (the range of error is defined by the kUpdateInterval value)
void InexactUpdate();
//returns a NULL terminated C-string always of kHTTPDateLen length.
char *GetDateBuffer() { return fDateBuffer; }
private:
enum
{
kUpdateInterval = 60000 // Update every minute
};
//+1 for terminator +1 for padding
char fDateBuffer[kDateBufferLen + 2];
SInt64 fLastDateUpdate;
friend class DateTranslator;
};
#endif

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@
*
*/
#ifndef __DSS_STOPWATCH__
#define __DSS_STOPWATCH__
//#include "DssStopwatch.h"
#include "OS.h"
class DssEggtimer {
public:
enum { kDurationNeverExpire = -1 };
DssEggtimer( SInt64 inMilliseconds ) { fTimerDuration = inMilliseconds; Reset(); }
void OneShotSetTo( SInt64 inMilliseconds )
{
// set the egg timer to this time for one cycle.
// there after Reset will use fTimerDuration
fExpirationMilliseconds = OS::Milliseconds() + inMilliseconds;
}
void Reset()
{
//if ( fTimerDuration != (SInt64)kDurationNeverExpire )
fExpirationMilliseconds = OS::Milliseconds() + fTimerDuration;
}
void ResetTo(SInt64 inMilliseconds)
{
fTimerDuration = inMilliseconds;
this->Reset();
}
Bool16 Expired()
{
//if (fTimerDuration == (SInt64)kDurationNeverExpire )
// return false;
return fExpirationMilliseconds <= OS::Milliseconds();
}
SInt64 MaxDuration() { return fTimerDuration; }
private:
SInt64 fTimerDuration;
SInt64 fExpirationMilliseconds;
};
class DssMillisecondStopwatch {
public:
DssMillisecondStopwatch() :
fIsStarted(false)
, fTimerDuration(-1)
{}
;
void Start() { fStartedAt = OS::Milliseconds(); fIsStarted = true; }
void Stop() { fTimerDuration = OS::Milliseconds() - fStartedAt; }
SInt64 Duration() { return fTimerDuration; }
private:
Bool16 fIsStarted;
SInt64 fTimerDuration;
SInt64 fStartedAt;
};
class DssDurationTimer {
public:
DssDurationTimer() { fStartedAtMsec = OS::Milliseconds(); }
void Reset() { fStartedAtMsec = OS::Milliseconds(); }
void ResetToDuration( SInt64 inDurationInMsec ) { fStartedAtMsec = OS::Milliseconds() - inDurationInMsec; }
SInt64 DurationInMilliseconds() { return OS::Milliseconds() - fStartedAtMsec; }
SInt64 DurationInSeconds() { return (OS::Milliseconds() - fStartedAtMsec) / (SInt64)1000; }
private:
SInt64 fStartedAtMsec;
};
#endif

View file

@ -0,0 +1,283 @@
/*
*
* @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: EventContext.cpp
Contains: Impelments object in .h file
*/
#include "EventContext.h"
#include "OSThread.h"
#include "atomic.h"
#include <fcntl.h>
#include <errno.h>
#ifndef __Win32__
#include <unistd.h>
#endif
#if MACOSXEVENTQUEUE
#include "tempcalls.h" //includes MacOS X prototypes of event queue functions
#endif
#define EVENT_CONTEXT_DEBUG 0
#if EVENT_CONTEXT_DEBUG
#include "OS.h"
#endif
#ifdef __Win32__
unsigned int EventContext::sUniqueID = WM_USER; // See commentary in RequestEvent
#else
unsigned int EventContext::sUniqueID = 1;
#endif
EventContext::EventContext(int inFileDesc, EventThread* inThread)
: fFileDesc(inFileDesc),
fUniqueID(0),
fUniqueIDStr((char*)&fUniqueID, sizeof(fUniqueID)),
fEventThread(inThread),
fWatchEventCalled(false),
fAutoCleanup(true)
{}
void EventContext::InitNonBlocking(int inFileDesc)
{
fFileDesc = inFileDesc;
#ifdef __Win32__
u_long one = 1;
int err = ::ioctlsocket(fFileDesc, FIONBIO, &one);
#else
int flag = ::fcntl(fFileDesc, F_GETFL, 0);
int err = ::fcntl(fFileDesc, F_SETFL, flag | O_NONBLOCK);
#endif
AssertV(err == 0, OSThread::GetErrno());
}
void EventContext::Cleanup()
{
int err = 0;
if (fFileDesc != kInvalidFileDesc)
{
//if this object is registered in the table, unregister it now
if (fUniqueID > 0)
{
fEventThread->fRefTable.UnRegister(&fRef);
#if !MACOSXEVENTQUEUE
select_removeevent(fFileDesc);//The eventqueue / select shim requires this
#ifdef __Win32__
err = ::closesocket(fFileDesc);
#endif
#else
//On Linux (possibly other UNIX implementations) you MUST NOT close the fd before
//removing the fd from the select mask, and having the select function wake up
//to register this fact. If you close the fd first, bad things may happen, like
//the socket not getting unbound from the port & IP addr.
//
//So, what we do is have the select thread itself call close. This is triggered
//by calling removeevent.
err = ::close(fFileDesc);
#endif
}
else
#ifdef __Win32__
err = ::closesocket(fFileDesc);
#else
err = ::close(fFileDesc);
#endif
}
fFileDesc = kInvalidFileDesc;
fUniqueID = 0;
AssertV(err == 0, OSThread::GetErrno());//we don't really care if there was an error, but it's nice to know
}
void EventContext::SnarfEventContext( EventContext &fromContext )
{
//+ show that we called watchevent
// copy the unique id
// set our fUniqueIDStr to the unique id
// copy the eventreq
// find the old event object
// show us as the object in the fRefTable
// we take the OSRef from the old context, point it at our context
//
//TODO - this whole operation causes a race condition for Event posting
// way up the chain we need to disable event posting
// or copy the posted events afer this op completes
fromContext.fFileDesc = kInvalidFileDesc;
fWatchEventCalled = fromContext.fWatchEventCalled;
fUniqueID = fromContext.fUniqueID;
fUniqueIDStr.Set((char*)&fUniqueID, sizeof(fUniqueID)),
::memcpy( &fEventReq, &fromContext.fEventReq, sizeof( struct eventreq ) );
fRef.Set( fUniqueIDStr, this );
fEventThread->fRefTable.Swap(&fRef);
fEventThread->fRefTable.UnRegister(&fromContext.fRef);
}
void EventContext::RequestEvent(int theMask)
{
#if DEBUG
fModwatched = true;
#endif
//
// The first time this function gets called, we're supposed to
// call watchevent. Each subsequent time, call modwatch. That's
// the way the MacOS X event queue works.
if (fWatchEventCalled)
{
fEventReq.er_eventbits = theMask;
#if MACOSXEVENTQUEUE
if (modwatch(&fEventReq, theMask) != 0)
#else
if (select_modwatch(&fEventReq, theMask) != 0)
#endif
AssertV(false, OSThread::GetErrno());
}
else
{
//allocate a Unique ID for this socket, and add it to the ref table
#ifdef __Win32__
//
// Kind of a hack. On Win32, the way that we pass around the unique ID is
// by making it the message ID of our Win32 message (see win32ev.cpp).
// Messages must be >= WM_USER. Hence this code to restrict the numberspace
// of our UniqueIDs.
if (!compare_and_store(8192, WM_USER, &sUniqueID)) // Fix 2466667: message IDs above a
fUniqueID = (PointerSizedInt)atomic_add(&sUniqueID, 1); // level are ignored, so wrap at 8192
else
fUniqueID = (PointerSizedInt)WM_USER;
#else
if (!compare_and_store(10000000, 1, &sUniqueID))
fUniqueID = (PointerSizedInt)atomic_add(&sUniqueID, 1);
else
fUniqueID = 1;
#endif
fRef.Set(fUniqueIDStr, this);
fEventThread->fRefTable.Register(&fRef);
//fill out the eventreq data structure
::memset( &fEventReq, '\0', sizeof(fEventReq));
fEventReq.er_type = EV_FD;
fEventReq.er_handle = fFileDesc;
fEventReq.er_eventbits = theMask;
fEventReq.er_data = (void*)fUniqueID;
fWatchEventCalled = true;
#if MACOSXEVENTQUEUE
if (watchevent(&fEventReq, theMask) != 0)
#else
if (select_watchevent(&fEventReq, theMask) != 0)
#endif
//this should never fail, but if it does, cleanup.
AssertV(false, OSThread::GetErrno());
}
}
void EventThread::Entry()
{
struct eventreq theCurrentEvent;
::memset( &theCurrentEvent, '\0', sizeof(theCurrentEvent) );
while (true)
{
int theErrno = EINTR;
while (theErrno == EINTR)
{
#if MACOSXEVENTQUEUE
int theReturnValue = waitevent(&theCurrentEvent, NULL);
#else
int theReturnValue = select_waitevent(&theCurrentEvent, NULL);
#endif
//Sort of a hack. In the POSIX version of the server, waitevent can return
//an actual POSIX errorcode.
if (theReturnValue >= 0)
theErrno = theReturnValue;
else
theErrno = OSThread::GetErrno();
}
AssertV(theErrno == 0, theErrno);
//ok, there's data waiting on this socket. Send a wakeup.
if (theCurrentEvent.er_data != NULL)
{
//The cookie in this event is an ObjectID. Resolve that objectID into
//a pointer.
StrPtrLen idStr((char*)&theCurrentEvent.er_data, sizeof(theCurrentEvent.er_data));
OSRef* ref = fRefTable.Resolve(&idStr);
if (ref != NULL)
{
EventContext* theContext = (EventContext*)ref->GetObject();
#if DEBUG
theContext->fModwatched = false;
#endif
theContext->ProcessEvent(theCurrentEvent.er_eventbits);
fRefTable.Release(ref);
}
}
#if EVENT_CONTEXT_DEBUG
SInt64 yieldStart = OS::Milliseconds();
#endif
this->ThreadYield();
#if EVENT_CONTEXT_DEBUG
SInt64 yieldDur = OS::Milliseconds() - yieldStart;
static SInt64 numZeroYields;
if ( yieldDur > 1 )
{
qtss_printf( "EventThread time in OSTHread::Yield %i, numZeroYields %i\n", (SInt32)yieldDur, (SInt32)numZeroYields );
numZeroYields = 0;
}
else
numZeroYields++;
#endif
}
}

View file

@ -0,0 +1,180 @@
/*
*
* @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: EventContext.h
Contains: An event context provides the intelligence to take an event
generated from a UNIX file descriptor (usually EV_RE or EV_WR)
and signal a Task.
*/
#ifndef __EVENT_CONTEXT_H__
#define __EVENT_CONTEXT_H__
#include "OSThread.h"
#include "Task.h"
#include "OSRef.h"
#if MACOSXEVENTQUEUE
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
#include <sys/ev.h>
#else
#include "ev.h"
#endif
#else
#include "ev.h"
#endif
//enable to trace event context execution and the task associated with the context
#define EVENTCONTEXT_DEBUG 0
class EventThread;
class EventContext
{
public:
//
// Constructor. Pass in the EventThread you would like to receive
// events for this context, and the fd that this context applies to
EventContext(int inFileDesc, EventThread* inThread);
virtual ~EventContext() { if (fAutoCleanup) this->Cleanup(); }
//
// InitNonBlocking
//
// Sets inFileDesc to be non-blocking. Once this is called, the
// EventContext object "owns" the file descriptor, and will close it
// when Cleanup is called. This is necessary because of some weird
// select() behavior. DON'T CALL CLOSE ON THE FD ONCE THIS IS CALLED!!!!
void InitNonBlocking(int inFileDesc);
//
// Cleanup. Will be called by the destructor, but can be called earlier
void Cleanup();
//
// Arms this EventContext. Pass in the events you would like to receive
void RequestEvent(int theMask = EV_RE);
//
// Provide the task you would like to be notified
void SetTask(Task* inTask)
{
fTask = inTask;
if (EVENTCONTEXT_DEBUG)
{
if (fTask== NULL)
qtss_printf("EventContext::SetTask context=%p task= NULL\n", (void *) this);
else
qtss_printf("EventContext::SetTask context=%p task= %p name=%s\n",(void *) this,(void *) fTask, fTask->fTaskName);
}
}
// when the HTTP Proxy tunnels takes over a TCPSocket, we need to maintain this context too
void SnarfEventContext( EventContext &fromContext );
// Don't cleanup this socket automatically
void DontAutoCleanup() { fAutoCleanup = false; }
// Direct access to the FD is not recommended, but is needed for modules
// that want to use the Socket classes and need to request events on the fd.
int GetSocketFD() { return fFileDesc; }
enum
{
kInvalidFileDesc = -1 //int
};
protected:
//
// ProcessEvent
//
// When an event occurs on this file descriptor, this function
// will get called. Default behavior is to Signal the associated
// task, but that behavior may be altered / overridden.
//
// Currently, we always generate a Task::kReadEvent
virtual void ProcessEvent(int /*eventBits*/)
{
if (EVENTCONTEXT_DEBUG)
{
if (fTask== NULL)
qtss_printf("EventContext::ProcessEvent context=%p task=NULL\n",(void *) this);
else
qtss_printf("EventContext::ProcessEvent context=%p task=%p TaskName=%s\n",(void *)this,(void *) fTask, fTask->fTaskName);
}
if (fTask != NULL)
fTask->Signal(Task::kReadEvent);
}
int fFileDesc;
private:
struct eventreq fEventReq;
OSRef fRef;
PointerSizedInt fUniqueID;
StrPtrLen fUniqueIDStr;
EventThread* fEventThread;
Bool16 fWatchEventCalled;
int fEventBits;
Bool16 fAutoCleanup;
Task* fTask;
#if DEBUG
Bool16 fModwatched;
#endif
static unsigned int sUniqueID;
friend class EventThread;
};
class EventThread : public OSThread
{
public:
EventThread() : OSThread() {}
virtual ~EventThread() {}
private:
virtual void Entry();
OSRefTable fRefTable;
friend class EventContext;
};
#endif //__EVENT_CONTEXT_H__

View file

@ -0,0 +1,40 @@
/*
*
* @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 __FastCopyMacros__
#define __FastCopyMacros__
#define COPY_BYTE( dest, src ) ( *((char*)(dest)) = *((char*)(src)) )
#define COPY_WORD( dest, src ) ( *((SInt16*)(dest)) = *((SInt16*)(src)) )
#define COPY_LONG_WORD( dest, src ) ( *((SInt32*)(dest)) = *((SInt32*)(src)) )
#define COPY_LONG_LONG_WORD( dest, src ) ( *((SInt64*)(dest)) = *((SInt64**)(src)) )
#define MOVE_BYTE( dest, src ) ( dest = *((char*)(src)) )
#define MOVE_WORD( dest, src ) ( dest = *((SInt16*)(src)) )
#define MOVE_LONG_WORD( dest, src ) ( dest = *((SInt32*)(src)) )
#define MOVE_LONG_LONG_WORD( dest, src ) ( dest = *((SInt64**)(src)) )
#endif

View file

@ -0,0 +1,102 @@
/*
*
* @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 "GetWord.h"
char* GetWord( char* toWordPtr, char* fromStrPtr, SInt32 limit )
{
// get a word from a string
// copy result into toWordPtr, return one past end of the
// word, limit is max for toWordPtr
// fromStrPtr
// trim any leading white space
while ( (unsigned char)*fromStrPtr <= 0x20 && *fromStrPtr )
fromStrPtr++;
// copy until we find more white space
while ( limit && (unsigned char)*fromStrPtr > 0x20 && *fromStrPtr )
{
*toWordPtr++ = *fromStrPtr++;
limit--;
}
*toWordPtr = 0x00;
return (char *) fromStrPtr;
}
char * GetQuotedWord( char* toWordPtr, char* fromStrPtr, SInt32 limit )
{
// get a quote encoded word from a string
// make include white space
int lastWasQuote = 0;
// trim any leading white space
while ( ( (unsigned char)*fromStrPtr <= 0x20 ) && *fromStrPtr )
fromStrPtr++;
if ( (unsigned char)*fromStrPtr == '"' )
{ // must lead with quote sign after white space
fromStrPtr++;
// copy until we find the last single quote
while ( limit && *fromStrPtr )
{
if ( (unsigned char)*fromStrPtr == '"' )
{
if ( lastWasQuote )
{
*toWordPtr++ = '"';
lastWasQuote = 0;
limit--;
}
else
lastWasQuote = 1;
}
else
{
if ( !lastWasQuote )
{ *toWordPtr++ = *fromStrPtr;
limit--;
}
else // we're done, hit a quote by itself
break;
}
// consume the char we read
fromStrPtr++;
}
}
*toWordPtr = 0x00;
return (char *) fromStrPtr;
}

View file

@ -0,0 +1,43 @@
/*
*
* @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 __getword__
#define __getword__
#ifdef __cplusplus
extern "C" {
#endif
#include "OSHeaders.h"
char* GetWord( char* toWordPtr, char* fromStrPtr, SInt32 limit );
char* GetQuotedWord( char* toWordPtr, char* fromStrPtr, SInt32 limit );
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,124 @@
/*
*
* @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: IdleTask.cpp
Contains: IdleTasks are identical to normal tasks (see task.h) with one exception:
You can schedule them for timeouts. If you call SetIdleTimer
on one, after the time has elapsed the task object will receive an
OS_IDLE event.
*/
#include "IdleTask.h"
#include "OSMemory.h"
#include "OS.h"
//IDLETASKTHREAD IMPLEMENTATION:
IdleTaskThread* IdleTask::sIdleThread = NULL;
void IdleTaskThread::SetIdleTimer(IdleTask *activeObj, SInt64 msec)
{
//note: OSHeap doesn't support a random remove, so this function
//won't change the timeout value if there is already one set
if (activeObj->fIdleElem.IsMemberOfAnyHeap())
return;
activeObj->fIdleElem.SetValue(OS::Milliseconds() + msec);
{
OSMutexLocker locker(&fHeapMutex);
fIdleHeap.Insert(&activeObj->fIdleElem);
}
fHeapCond.Signal();
}
void IdleTaskThread::CancelTimeout(IdleTask* idleObj)
{
Assert(idleObj != NULL);
OSMutexLocker locker(&fHeapMutex);
fIdleHeap.Remove(&idleObj->fIdleElem);
}
void
IdleTaskThread::Entry()
{
OSMutexLocker locker(&fHeapMutex);
while (true)
{
//if there are no events to process, block.
if (fIdleHeap.CurrentHeapSize() == 0)
fHeapCond.Wait(&fHeapMutex);
SInt64 msec = OS::Milliseconds();
//pop elements out of the heap as long as their timeout time has arrived
while ((fIdleHeap.CurrentHeapSize() > 0) && (fIdleHeap.PeekMin()->GetValue() <= msec))
{
IdleTask* elem = (IdleTask*)fIdleHeap.ExtractMin()->GetEnclosingObject();
Assert(elem != NULL);
elem->Signal(Task::kIdleEvent);
}
//we are done sending idle events. If there is a lowest tick count, then
//we need to sleep until that time.
if (fIdleHeap.CurrentHeapSize() > 0)
{
SInt64 timeoutTime = fIdleHeap.PeekMin()->GetValue();
//because sleep takes a 32 bit number
timeoutTime -= msec;
Assert(timeoutTime > 0);
UInt32 smallTime = (UInt32)timeoutTime;
fHeapCond.Wait(&fHeapMutex, smallTime);
}
}
}
void IdleTask::Initialize()
{
if (sIdleThread == NULL)
{
sIdleThread = NEW IdleTaskThread();
sIdleThread->Start();
}
}
IdleTask::~IdleTask()
{
//clean up stuff used by idle thread routines
Assert(sIdleThread != NULL);
OSMutexLocker locker(&sIdleThread->fHeapMutex);
//Check to see if there is a pending timeout. If so, get this object
//out of the heap
if (fIdleElem.IsMemberOfAnyHeap())
sIdleThread->CancelTimeout(this);
}

View file

@ -0,0 +1,108 @@
/*
*
* @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: IdleTask.h
Contains: IdleTasks are identical to normal tasks (see task.h) with one exception:
You can schedule them for timeouts. If you call SetIdleTimer
on one, after the time has elapsed the task object will receive an
OS_IDLE event.
*/
#ifndef _IDLETASK_H_
#define _IDLETASK_H_
#include "Task.h"
#include "OSThread.h"
#include "OSHeap.h"
#include "OSMutex.h"
#include "OSCond.h"
class IdleTask;
//merely a private implementation detail of IdleTask
class IdleTaskThread : private OSThread
{
private:
IdleTaskThread() : OSThread(), fHeapMutex() {}
virtual ~IdleTaskThread() { Assert(fIdleHeap.CurrentHeapSize() == 0); }
void SetIdleTimer(IdleTask *idleObj, SInt64 msec);
void CancelTimeout(IdleTask *idleObj);
virtual void Entry();
OSHeap fIdleHeap;
OSMutex fHeapMutex;
OSCond fHeapCond;
friend class IdleTask;
};
class IdleTask : public Task
{
public:
//Call Initialize before using this class
static void Initialize();
IdleTask() : Task(), fIdleElem() { this->SetTaskName("IdleTask"); fIdleElem.SetEnclosingObject(this); }
//This object does a "best effort" of making sure a timeout isn't
//pending for an object being deleted. In other words, if there is
//a timeout pending, and the destructor is called, things will get cleaned
//up. But callers must ensure that SetIdleTimer isn't called at the same
//time as the destructor, or all hell will break loose.
virtual ~IdleTask();
//SetIdleTimer:
//This object will receive an OS_IDLE event in the following number of milliseconds.
//Only one timeout can be outstanding, if there is already a timeout scheduled, this
//does nothing.
void SetIdleTimer(SInt64 msec) { sIdleThread->SetIdleTimer(this, msec); }
//CancelTimeout
//If there is a pending timeout for this object, this function cancels it.
//If there is no pending timeout, this function does nothing.
//Currently not supported because OSHeap doesn't support random remove
void CancelTimeout() { sIdleThread->CancelTimeout(this); }
private:
OSHeapElem fIdleElem;
//there is only one idle thread shared by all idle tasks.
static IdleTaskThread* sIdleThread;
friend class IdleTaskThread;
};
#endif

View file

@ -0,0 +1,110 @@
/*
*
* @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 "MakeDir.h"
#include "PathDelimiter.h"
#if (! __MACOS__)
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef __solaris__
#include <sys/sysctl.h>
#endif
#include <sys/time.h>
#else
#include "BogusDefs.h"
#endif
#include <string.h>
#include <stdlib.h>
#include "SafeStdLib.h"
int MakeDir(const char* inPath, int mode)
{
struct stat theStatBuffer;
if (stat(inPath, &theStatBuffer) == -1)
{
//this directory doesn't exist, so let's try to create it
if (mkdir(inPath, mode) == -1)
return -1; //€- (QTSS_ErrorCode)OSThread::GetErrno();
}
else if (!S_ISDIR(theStatBuffer.st_mode))
return -1; //€- QTSS_FileExists;//there is a file at this point in the path!
//directory exists
return 0; //€- QTSS_NoErr;
}
int RecursiveMakeDir(const char* inPath, int mode)
{
//PL_ASSERT(inPath != NULL);
char pathCopy[256];
char* thePathTraverser = pathCopy;
int theErr;
char oldChar;
if ( strlen( inPath ) > 255 )
return -1;
//iterate through the path, replacing kPathDelimiterChar with '\0' as we go
strcpy( pathCopy, inPath );
//skip over the first / in the path.
if (*thePathTraverser == kPathDelimiterChar )
thePathTraverser++;
while (*thePathTraverser != '\0')
{
if (*thePathTraverser == kPathDelimiterChar)
{
//we've found a filename divider. Now that we have a complete
//filename, see if this partial path exists.
//make the partial path into a C string
// mkdir does not like a trailing '/'
oldChar = *thePathTraverser;
*thePathTraverser = '\0';
theErr = MakeDir(pathCopy, mode);
//there is a directory here. Just continue in our traversal
*thePathTraverser = oldChar;
if (theErr)
return theErr;
}
thePathTraverser++;
}
//need to create the last directory in the path
return MakeDir(inPath, mode);
}

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 __makedir__
#define __makedir__
#if (! __MACOS__)
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef __solaris__ || __hpux__
#include <sys/sysctl.h>
#endif
#include <sys/time.h>
#else
#include "BogusDefs.h"
#endif
#ifndef S_IRWXU
#define S_IRWXU 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
int MakeDir( const char* path, int mode );
int RecursiveMakeDir( const char*inPath, int mode);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,50 @@
/*
*
* @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 "MyAssert.h"
#include "OSHeaders.h"
#include "SafeStdLib.h"
static AssertLogger* sLogger = NULL;
void SetAssertLogger(AssertLogger* theLogger)
{
sLogger = theLogger;
}
void MyAssert(char *inMessage)
{
if (sLogger != NULL)
sLogger->LogAssert(inMessage);
else
{
qtss_printf("%s\n", inMessage);
#if __Win32__
DebugBreak();
#else
(*(SInt32*)0) = 0;
#endif
}
}

View file

@ -0,0 +1,94 @@
/*
*
* @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 _MYASSERT_H_
#define _MYASSERT_H_
#include <stdio.h>
#include "SafeStdLib.h"
#ifdef __cplusplus
class AssertLogger
{
public:
// An interface so the MyAssert function can write a message
virtual void LogAssert(char* inMessage) = 0;
virtual ~AssertLogger(){};
};
// If a logger is provided, asserts will be logged. Otherwise, asserts will cause a bus error
void SetAssertLogger(AssertLogger* theLogger);
#endif
#if ASSERT
void MyAssert(char *s);
#define kAssertBuffSize 256
#define Assert(condition) { \
\
if (!(condition)) \
{ \
char s[kAssertBuffSize]; \
s[kAssertBuffSize -1] = 0; \
qtss_snprintf (s,kAssertBuffSize -1, "_Assert: %s, %d",__FILE__, __LINE__ ); \
MyAssert(s); \
} }
#define AssertV(condition,errNo) { \
if (!(condition)) \
{ \
char s[kAssertBuffSize]; \
s[kAssertBuffSize -1] = 0; \
qtss_snprintf( s,kAssertBuffSize -1, "_AssertV: %s, %d (%d)",__FILE__, __LINE__, errNo ); \
MyAssert(s); \
} }
#define Warn(condition) { \
if (!(condition)) \
qtss_printf( "_Warn: %s, %d\n",__FILE__, __LINE__ ); }
#define WarnV(condition,msg) { \
if (!(condition)) \
qtss_printf ("_WarnV: %s, %d (%s)\n",__FILE__, __LINE__, msg ); }
#define WarnVE(condition,msg,err) { \
if (!(condition)) \
{ char buffer[kAssertBuffSize]; \
buffer[kAssertBuffSize -1] = 0; \
qtss_printf ("_WarnV: %s, %d (%s, %s [err=%d])\n",__FILE__, __LINE__, msg, qtss_strerror(err,buffer,sizeof(buffer) -1), err ); \
} }
#else
#define Assert(condition) ((void) 0)
#define AssertV(condition,errNo) ((void) 0)
#define Warn(condition) ((void) 0)
#define WarnV(condition,msg) ((void) 0)
#endif
#endif //_MY_ASSERT_H_

470
CommonUtilitiesLib/OS.cpp Normal file
View file

@ -0,0 +1,470 @@
/*
*
* @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: OS.cpp
Contains: OS utility functions
*/
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <math.h>
#ifndef __Win32__
#include <sys/time.h>
#endif
#ifdef __sgi__
#include <unistd.h>
#endif
#include "OS.h"
#include "OSThread.h"
#include "MyAssert.h"
#include "OSFileSource.h"
#if __MacOSX__
#ifndef __COREFOUNDATION__
#include <CoreFoundation/CoreFoundation.h>
//extern "C" { void Microseconds (UnsignedWide *microTickCount); }
#endif
#endif
#if (__FreeBSD__ || __MacOSX__)
#include <sys/sysctl.h>
#endif
#if (__solaris__ || __linux__ || __linuxppc__)
#include "StringParser.h"
#endif
#if __sgi__
#include <sys/systeminfo.h>
#endif
double OS::sDivisor = 0;
double OS::sMicroDivisor = 0;
SInt64 OS::sMsecSince1970 = 0;
SInt64 OS::sMsecSince1900 = 0;
SInt64 OS::sInitialMsec = 0;
SInt64 OS::sWrapTime = 0;
SInt64 OS::sCompareWrap = 0;
SInt64 OS::sLastTimeMilli = 0;
OSMutex OS::sStdLibOSMutex;
#if DEBUG || __Win32__
#include "OSMutex.h"
#include "OSMemory.h"
static OSMutex* sLastMillisMutex = NULL;
#endif
void OS::Initialize()
{
Assert (sInitialMsec == 0); // do only once
if (sInitialMsec != 0) return;
::tzset();
//setup t0 value for msec since 1900
//t.tv_sec is number of seconds since Jan 1, 1970. Convert to seconds since 1900
SInt64 the1900Sec = (SInt64) (24 * 60 * 60) * (SInt64) ((70 * 365) + 17) ;
sMsecSince1900 = the1900Sec * 1000;
sWrapTime = (SInt64) 0x00000001 << 32;
sCompareWrap = (SInt64) 0xffffffff << 32;
sLastTimeMilli = 0;
sInitialMsec = OS::Milliseconds(); //Milliseconds uses sInitialMsec so this assignment is valid only once.
sMsecSince1970 = ::time(NULL); // POSIX time always returns seconds since 1970
sMsecSince1970 *= 1000; // Convert to msec
#if DEBUG || __Win32__
sLastMillisMutex = NEW OSMutex();
#endif
}
SInt64 OS::Milliseconds()
{
/*
#if __MacOSX__
#if DEBUG
OSMutexLocker locker(sLastMillisMutex);
#endif
UnsignedWide theMicros;
::Microseconds(&theMicros);
SInt64 scalarMicros = theMicros.hi;
scalarMicros <<= 32;
scalarMicros += theMicros.lo;
scalarMicros = ((scalarMicros / 1000) - sInitialMsec) + sMsecSince1970; // convert to msec
#if DEBUG
static SInt64 sLastMillis = 0;
//Assert(scalarMicros >= sLastMillis); // currently this fails on dual processor machines
sLastMillis = scalarMicros;
#endif
return scalarMicros;
*/
#if __Win32__
OSMutexLocker locker(sLastMillisMutex);
// curTimeMilli = timeGetTime() + ((sLastTimeMilli/ 2^32) * 2^32)
// using binary & to reduce it to one operation from two
// sCompareWrap and sWrapTime are constants that are never changed
// sLastTimeMilli is updated with the curTimeMilli after each call to this function
SInt64 curTimeMilli = (UInt32) ::timeGetTime() + (sLastTimeMilli & sCompareWrap);
if((curTimeMilli - sLastTimeMilli) < 0)
{
curTimeMilli += sWrapTime;
}
sLastTimeMilli = curTimeMilli;
// For debugging purposes
//SInt64 tempCurMsec = (curTimeMilli - sInitialMsec) + sMsecSince1970;
//SInt32 tempCurSec = tempCurMsec / 1000;
//char buffer[kTimeStrSize];
//qtss_printf("OS::MilliSeconds current time = %s\n", qtss_ctime(&tempCurSec, buffer, sizeof(buffer)));
return (curTimeMilli - sInitialMsec) + sMsecSince1970; // convert to application time
#else
struct timeval t;
int theErr = ::gettimeofday(&t, NULL);
Assert(theErr == 0);
SInt64 curTime;
curTime = t.tv_sec;
curTime *= 1000; // sec -> msec
curTime += t.tv_usec / 1000; // usec -> msec
return (curTime - sInitialMsec) + sMsecSince1970;
#endif
}
SInt64 OS::Microseconds()
{
/*
#if __MacOSX__
UnsignedWide theMicros;
::Microseconds(&theMicros);
SInt64 theMillis = theMicros.hi;
theMillis <<= 32;
theMillis += theMicros.lo;
return theMillis;
*/
#if __Win32__
SInt64 curTime = (SInt64) ::timeGetTime(); // system time in milliseconds
curTime -= sInitialMsec; // convert to application time
curTime *= 1000; // convert to microseconds
return curTime;
#else
struct timeval t;
int theErr = ::gettimeofday(&t, NULL);
Assert(theErr == 0);
SInt64 curTime;
curTime = t.tv_sec;
curTime *= 1000000; // sec -> usec
curTime += t.tv_usec;
return curTime - (sInitialMsec * 1000);
#endif
}
SInt32 OS::GetGMTOffset()
{
#ifdef __Win32__
TIME_ZONE_INFORMATION tzInfo;
DWORD theErr = ::GetTimeZoneInformation(&tzInfo);
if (theErr == TIME_ZONE_ID_INVALID)
return 0;
return ((tzInfo.Bias / 60) * -1);
#else
time_t clock;
struct tm *tmptr= localtime(&clock);
if (tmptr == NULL)
return 0;
return tmptr->tm_gmtoff / 3600;//convert seconds to hours before or after GMT
#endif
}
SInt64 OS::HostToNetworkSInt64(SInt64 hostOrdered)
{
#if BIGENDIAN
return hostOrdered;
#else
return (SInt64) ( (UInt64) (hostOrdered << 56) | (UInt64) (((UInt64) 0x00ff0000 << 32) & (hostOrdered << 40))
| (UInt64) ( ((UInt64) 0x0000ff00 << 32) & (hostOrdered << 24)) | (UInt64) (((UInt64) 0x000000ff << 32) & (hostOrdered << 8))
| (UInt64) ( ((UInt64) 0x00ff0000 << 8) & (hostOrdered >> 8)) | (UInt64) ((UInt64) 0x00ff0000 & (hostOrdered >> 24))
| (UInt64) ( (UInt64) 0x0000ff00 & (hostOrdered >> 40)) | (UInt64) ((UInt64) 0x00ff & (hostOrdered >> 56)) );
#endif
}
SInt64 OS::NetworkToHostSInt64(SInt64 networkOrdered)
{
#if BIGENDIAN
return networkOrdered;
#else
return (SInt64) ( (UInt64) (networkOrdered << 56) | (UInt64) (((UInt64) 0x00ff0000 << 32) & (networkOrdered << 40))
| (UInt64) ( ((UInt64) 0x0000ff00 << 32) & (networkOrdered << 24)) | (UInt64) (((UInt64) 0x000000ff << 32) & (networkOrdered << 8))
| (UInt64) ( ((UInt64) 0x00ff0000 << 8) & (networkOrdered >> 8)) | (UInt64) ((UInt64) 0x00ff0000 & (networkOrdered >> 24))
| (UInt64) ( (UInt64) 0x0000ff00 & (networkOrdered >> 40)) | (UInt64) ((UInt64) 0x00ff & (networkOrdered >> 56)) );
#endif
}
OS_Error OS::MakeDir(char *inPath)
{
struct stat theStatBuffer;
if (::stat(inPath, &theStatBuffer) == -1)
{
//this directory doesn't exist, so let's try to create it
#ifdef __Win32__
if (::mkdir(inPath) == -1)
#else
if (::mkdir(inPath, S_IRWXU) == -1)
#endif
return (OS_Error)OSThread::GetErrno();
}
#ifdef __Win32__
else if (!(theStatBuffer.st_mode & _S_IFDIR)) // MSVC++ doesn't define the S_ISDIR macro
return EEXIST; // there is a file at this point in the path!
#else
else if (!S_ISDIR(theStatBuffer.st_mode))
return EEXIST;//there is a file at this point in the path!
#endif
//directory exists
return OS_NoErr;
}
OS_Error OS::RecursiveMakeDir(char *inPath)
{
Assert(inPath != NULL);
//iterate through the path, replacing '/' with '\0' as we go
char *thePathTraverser = inPath;
//skip over the first / in the path.
if (*thePathTraverser == kPathDelimiterChar)
thePathTraverser++;
while (*thePathTraverser != '\0')
{
if (*thePathTraverser == kPathDelimiterChar)
{
//we've found a filename divider. Now that we have a complete
//filename, see if this partial path exists.
//make the partial path into a C string
*thePathTraverser = '\0';
OS_Error theErr = MakeDir(inPath);
//there is a directory here. Just continue in our traversal
*thePathTraverser = kPathDelimiterChar;
if (theErr != OS_NoErr)
return theErr;
}
thePathTraverser++;
}
//need to create the last directory in the path
return MakeDir(inPath);
}
Bool16 OS::ThreadSafe()
{
#if (__MacOSX__) // check for version 7 or greater for thread safe stdlib
char releaseStr[32] = "";
size_t strLen = sizeof(releaseStr);
int mib[2];
mib[0] = CTL_KERN;
mib[1] = KERN_OSRELEASE;
UInt32 majorVers = 0;
int err = sysctl(mib,2, releaseStr, &strLen, NULL,0);
if (err == 0)
{
StrPtrLen rStr(releaseStr,strLen);
char* endMajor = rStr.FindString(".");
if (endMajor != NULL) // truncate to an int value.
*endMajor = 0;
if (::strlen(releaseStr) > 0) //convert to an int
::sscanf(releaseStr, "%"_U32BITARG_"", &majorVers);
}
if (majorVers < 7) // less than OS X Panther 10.3
return false; // force 1 worker thread because < 10.3 means std c lib is not thread safe.
#endif
return true;
}
UInt32 OS::GetNumProcessors()
{
#if (__Win32__)
SYSTEM_INFO theSystemInfo;
::GetSystemInfo(&theSystemInfo);
return (UInt32)theSystemInfo.dwNumberOfProcessors;
#endif
#if (__MacOSX__ || __FreeBSD__)
int numCPUs = 1;
size_t len = sizeof(numCPUs);
int mib[2];
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
(void) ::sysctl(mib,2,&numCPUs,&len,NULL,0);
if (numCPUs < 1)
numCPUs = 1;
return (UInt32) numCPUs;
#endif
#if(__linux__ || __linuxppc__)
char cpuBuffer[8192] = "";
StrPtrLen cpuInfoBuf(cpuBuffer, sizeof(cpuBuffer));
FILE *cpuFile = ::fopen( "/proc/cpuinfo", "r" );
if (cpuFile)
{ cpuInfoBuf.Len = ::fread(cpuInfoBuf.Ptr, sizeof(char), cpuInfoBuf.Len, cpuFile);
::fclose(cpuFile);
}
StringParser cpuInfoFileParser(&cpuInfoBuf);
StrPtrLen line;
StrPtrLen word;
UInt32 numCPUs = 0;
while( cpuInfoFileParser.GetDataRemaining() != 0 )
{
cpuInfoFileParser.GetThruEOL(&line); // Read each line
StringParser lineParser(&line);
lineParser.ConsumeWhitespace(); //skip over leading whitespace
if (lineParser.GetDataRemaining() == 0) // must be an empty line
continue;
lineParser.ConsumeUntilWhitespace(&word);
if ( word.Equal("processor") ) // found a processor as first word in line
{ numCPUs ++;
}
}
if (numCPUs == 0)
numCPUs = 1;
return numCPUs;
#endif
#if(__solaris__)
{
UInt32 numCPUs = 0;
char linebuff[512] = "";
StrPtrLen line(linebuff, sizeof(linebuff));
StrPtrLen word;
FILE *p = ::popen("uname -X","r");
while((::fgets(linebuff, sizeof(linebuff -1), p)) > 0)
{
StringParser lineParser(&line);
lineParser.ConsumeWhitespace(); //skip over leading whitespace
if (lineParser.GetDataRemaining() == 0) // must be an empty line
continue;
lineParser.ConsumeUntilWhitespace(&word);
if ( word.Equal("NumCPU")) // found a tag as first word in line
{
lineParser.GetThru(NULL,'=');
lineParser.ConsumeWhitespace(); //skip over leading whitespace
lineParser.ConsumeUntilWhitespace(&word); //read the number of cpus
if (word.Len > 0)
::sscanf(word.Ptr, "%"_U32BITARG_"", &numCPUs);
break;
}
}
if (numCPUs == 0)
numCPUs = 1;
::pclose(p);
return numCPUs;
}
#endif
#if(__sgi__)
UInt32 numCPUs = 0;
numCPUs = sysconf(_SC_NPROC_ONLN);
return numCPUs;
#endif
return 1;
}
//CISCO provided fix for integer + fractional fixed64.
SInt64 OS::TimeMilli_To_Fixed64Secs(SInt64 inMilliseconds)
{
SInt64 result = inMilliseconds / 1000; // The result is in lower bits.
result <<= 32; // shift it to higher 32 bits
// Take the remainder (rem = inMilliseconds%1000) and multiply by
// 2**32, divide by 1000, effectively this gives (rem/1000) as a
// binary fraction.
double p = ldexp((double)(inMilliseconds%1000), +32) / 1000.;
UInt32 frac = (UInt32)p;
result |= frac;
return result;
}

144
CommonUtilitiesLib/OS.h Normal file
View file

@ -0,0 +1,144 @@
/*
*
* @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: OS.h
Contains: OS utility functions. Memory allocation, time, etc.
*/
#ifndef _OS_H_
#define _OS_H_
#include "OSHeaders.h"
#include "OSMutex.h"
#include <string.h>
class OS
{
public:
//call this before calling anything else
static void Initialize();
static SInt32 Min(SInt32 a, SInt32 b) { if (a < b) return a; return b; }
//
// Milliseconds always returns milliseconds since Jan 1, 1970 GMT.
// This basically makes it the same as a POSIX time_t value, except
// in msec, not seconds. To convert to a time_t, divide by 1000.
static SInt64 Milliseconds();
static SInt64 Microseconds();
// Some processors (MIPS, Sparc) cannot handle non word aligned memory
// accesses. So, we need to provide functions to safely get at non-word
// aligned memory.
static inline UInt32 GetUInt32FromMemory(UInt32* inP);
//because the OS doesn't seem to have these functions
static SInt64 HostToNetworkSInt64(SInt64 hostOrdered);
static SInt64 NetworkToHostSInt64(SInt64 networkOrdered);
static SInt64 TimeMilli_To_Fixed64Secs(SInt64 inMilliseconds); //new CISCO provided implementation
//disable: calculates integer value only { return (SInt64) ( (Float64) inMilliseconds / 1000) * ((SInt64) 1 << 32 ) ; }
static SInt64 Fixed64Secs_To_TimeMilli(SInt64 inFixed64Secs)
{ UInt64 value = (UInt64) inFixed64Secs; return (value >> 32) * 1000 + (((value % ((UInt64) 1 << 32)) * 1000) >> 32); }
//This converts the local time (from OS::Milliseconds) to NTP time.
static SInt64 TimeMilli_To_1900Fixed64Secs(SInt64 inMilliseconds)
{ return TimeMilli_To_Fixed64Secs(sMsecSince1900) + TimeMilli_To_Fixed64Secs(inMilliseconds); }
static SInt64 TimeMilli_To_UnixTimeMilli(SInt64 inMilliseconds)
{ return inMilliseconds; }
static time_t TimeMilli_To_UnixTimeSecs(SInt64 inMilliseconds)
{ return (time_t) ( (SInt64) TimeMilli_To_UnixTimeMilli(inMilliseconds) / (SInt64) 1000); }
static time_t UnixTime_Secs(void) // Seconds since 1970
{ return TimeMilli_To_UnixTimeSecs(Milliseconds()); }
static time_t Time1900Fixed64Secs_To_UnixTimeSecs(SInt64 in1900Fixed64Secs)
{ return (time_t)( (SInt64) ((SInt64) ( in1900Fixed64Secs - TimeMilli_To_Fixed64Secs(sMsecSince1900) ) / ((SInt64) 1 << 32) ) ); }
static SInt64 Time1900Fixed64Secs_To_TimeMilli(SInt64 in1900Fixed64Secs)
{ return ( (SInt64) ( (Float64) ((SInt64) in1900Fixed64Secs - (SInt64) TimeMilli_To_Fixed64Secs(sMsecSince1900) ) / (Float64) ((SInt64) 1 << 32) ) * 1000) ; }
// Returns the offset in hours between local time and GMT (or UTC) time.
static SInt32 GetGMTOffset();
//Both these functions return QTSS_NoErr, QTSS_FileExists, or POSIX errorcode
//Makes whatever directories in this path that don't exist yet
static OS_Error RecursiveMakeDir(char *inPath);
//Makes the directory at the end of this path
static OS_Error MakeDir(char *inPath);
// Discovery of how many processors are on this machine
static UInt32 GetNumProcessors();
// CPU Load
static Float32 GetCurrentCPULoadPercent();
// Mutex for StdLib calls
static OSMutex* GetStdLibMutex() { return &sStdLibOSMutex; }
static SInt64 InitialMSec() { return sInitialMsec; }
static Float32 StartTimeMilli_Float() { return (Float32) ( (Float64) ( (SInt64) OS::Milliseconds() - (SInt64) OS::InitialMSec()) / (Float64) 1000.0 ); }
static SInt64 StartTimeMilli_Int() { return (OS::Milliseconds() - OS::InitialMSec()); }
static Bool16 ThreadSafe();
private:
static double sDivisor;
static double sMicroDivisor;
static SInt64 sMsecSince1900;
static SInt64 sMsecSince1970;
static SInt64 sInitialMsec;
static SInt32 sMemoryErr;
static void SetDivisor();
static SInt64 sWrapTime;
static SInt64 sCompareWrap;
static SInt64 sLastTimeMilli;
static OSMutex sStdLibOSMutex;
};
inline UInt32 OS::GetUInt32FromMemory(UInt32* inP)
{
#if ALLOW_NON_WORD_ALIGN_ACCESS
return *inP;
#else
char* tempPtr = (char*)inP;
UInt32 temp = 0;
::memcpy(&temp, tempPtr, sizeof(UInt32));
return temp;
#endif
}
#endif

View file

@ -0,0 +1,88 @@
/*
*
* @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: OSArrayObjectDeleter.h
Contains: Auto object for deleting arrays.
*/
#ifndef __OS_ARRAY_OBJECT_DELETER_H__
#define __OS_ARRAY_OBJECT_DELETER_H__
#include "MyAssert.h"
template <class T>
class OSArrayObjectDeleter
{
public:
OSArrayObjectDeleter() : fT(NULL) {}
OSArrayObjectDeleter(T* victim) : fT(victim) {}
~OSArrayObjectDeleter() { 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;
};
template <class T>
class OSPtrDeleter
{
public:
OSPtrDeleter() : fT(NULL) {}
OSPtrDeleter(T* victim) : fT(victim) {}
~OSPtrDeleter() { delete fT; }
void ClearObject() { fT = NULL; }
void SetObject(T* victim)
{ Assert(fT == NULL);
fT = victim;
}
private:
T* fT;
};
typedef OSArrayObjectDeleter<char*> OSCharPointerArrayDeleter;
typedef OSArrayObjectDeleter<char> OSCharArrayDeleter;
#endif //__OS_OBJECT_ARRAY_DELETER_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@
*
*/
/*
File: OSBufferPool.cpp
Contains: Fast access to fixed size buffers.
Written By: Denis Serenyi
*/
#include "OSBufferPool.h"
#include "OSMemory.h"
void* OSBufferPool::Get()
{
OSMutexLocker locker(&fMutex);
if (fQueue.GetLength() == 0)
{
fTotNumBuffers++;
char* theNewBuf = NEW char[fBufSize + sizeof(OSQueueElem)];
//
// We need to construct a Queue Element, but we don't actually need
// to use it in this function, so to avoid a compiler warning just
// don't assign the result to anything.
(void)new (theNewBuf) OSQueueElem(theNewBuf + sizeof(OSQueueElem));
return theNewBuf + sizeof(OSQueueElem);
}
return fQueue.DeQueue()->GetEnclosingObject();
}
void OSBufferPool::Put(void* inBuffer)
{
OSMutexLocker locker(&fMutex);
fQueue.EnQueue((OSQueueElem*)((char*)inBuffer - sizeof(OSQueueElem)));
}

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: OSBufferPool.h
Contains: Fast access to fixed size buffers.
Written By: Denis Serenyi
*/
#ifndef __OS_BUFFER_POOL_H__
#define __OS_BUFFER_POOL_H__
#include "OSQueue.h"
#include "OSMutex.h"
class OSBufferPool
{
public:
OSBufferPool(UInt32 inBufferSize) : fBufSize(inBufferSize), fTotNumBuffers(0) {}
//
// This object currently *does not* clean up for itself when
// you destruct it!
~OSBufferPool() {}
//
// ACCESSORS
UInt32 GetTotalNumBuffers() { return fTotNumBuffers; }
UInt32 GetNumAvailableBuffers() { return fQueue.GetLength(); }
//
// All these functions are thread-safe
//
// Gets a buffer out of the pool. This buffer must be replaced
// by calling Put when you are done with it.
void* Get();
//
// Returns a buffer retreived by Get back to the pool.
void Put(void* inBuffer);
private:
OSMutex fMutex;
OSQueue fQueue;
UInt32 fBufSize;
UInt32 fTotNumBuffers;
};
#endif //__OS_BUFFER_POOL_H__

View file

@ -0,0 +1,153 @@
/*
*
* @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: OSCodeFragment.cpp
Contains: Implementation of object defined in OSCodeFragment.h
*/
#include <stdlib.h>
#include "SafeStdLib.h"
#include <stdio.h>
#include "MyAssert.h"
#if __Win32__
// Win32 includes here
#elif __MacOSX__
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFBundle.h>
#else
#include <dlfcn.h>
#endif
#include "OSCodeFragment.h"
void OSCodeFragment::Initialize()
{
// does nothing...should do any CFM initialization here
}
OSCodeFragment::OSCodeFragment(const char* inPath)
: fFragmentP(NULL)
{
#if defined(HPUX) || defined(HPUX10)
shl_t handle;
fFragmentP = shl_load(inPath, BIND_IMMEDIATE|BIND_VERBOSE|BIND_NOSTART, 0L);
#elif defined(OSF1) ||\
(defined(__FreeBSD_version) && (__FreeBSD_version >= 220000))
fFragmentP = dlopen((char *)inPath, RTLD_NOW | RTLD_GLOBAL);
#elif defined(__FreeBSD__)
fFragmentP = dlopen(inPath, RTLD_NOW);
#elif defined(__sgi__)
fFragmentP = dlopen(inPath, RTLD_NOW); // not sure this should be either RTLD_NOW or RTLD_LAZY
#elif defined(__Win32__)
fFragmentP = ::LoadLibrary(inPath);
#elif defined(__MacOSX__)
CFStringRef theString = CFStringCreateWithCString( kCFAllocatorDefault, inPath, kCFStringEncodingASCII);
//
// In MacOSX, our "fragments" are CF bundles, which are really
// directories, so our paths are paths to a directory
CFURLRef bundleURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
theString,
kCFURLPOSIXPathStyle,
true);
//
// I figure CF is safe about having NULL passed
// into its functions (if fBundle failed to get created).
// So, I won't worry about error checking myself
fFragmentP = CFBundleCreate( kCFAllocatorDefault, bundleURL );
Boolean success = false;
if (fFragmentP != NULL)
success = CFBundleLoadExecutable( fFragmentP );
if (!success && fFragmentP != NULL)
{
CFRelease( fFragmentP );
fFragmentP = NULL;
}
CFRelease(bundleURL);
CFRelease(theString);
#else
fFragmentP = dlopen(inPath, RTLD_NOW | RTLD_GLOBAL);
//fprintf (stderr, "%s\n", dlerror());
#endif
}
OSCodeFragment::~OSCodeFragment()
{
if (fFragmentP == NULL)
return;
#if defined(HPUX) || defined(HPUX10)
shl_unload((shl_t)fFragmentP);
#elif defined(__Win32__)
BOOL theErr = ::FreeLibrary(fFragmentP);
Assert(theErr);
#elif defined(__MacOSX__)
CFBundleUnloadExecutable( fFragmentP );
CFRelease( fFragmentP );
#else
dlclose(fFragmentP);
#endif
}
void* OSCodeFragment::GetSymbol(const char* inSymbolName)
{
if (fFragmentP == NULL)
return NULL;
#if defined(HPUX) || defined(HPUX10)
void *symaddr = NULL;
int status;
errno = 0;
status = shl_findsym((shl_t *)&fFragmentP, symname, TYPE_PROCEDURE, &symaddr);
if (status == -1 && errno == 0) /* try TYPE_DATA instead */
status = shl_findsym((shl_t *)&fFragmentP, inSymbolName, TYPE_DATA, &symaddr);
return (status == -1 ? NULL : symaddr);
#elif defined(DLSYM_NEEDS_UNDERSCORE)
char *symbol = (char*)malloc(sizeof(char)*(strlen(inSymbolName)+2));
void *retval;
qtss_sprintf(symbol, "_%s", inSymbolName);
retval = dlsym(fFragmentP, symbol);
free(symbol);
return retval;
#elif defined(__Win32__)
return ::GetProcAddress(fFragmentP, inSymbolName);
#elif defined(__MacOSX__)
CFStringRef theString = CFStringCreateWithCString( kCFAllocatorDefault, inSymbolName, kCFStringEncodingASCII);
void* theSymbol = (void*)CFBundleGetFunctionPointerForName( fFragmentP, theString );
CFRelease(theString);
return theSymbol;
#else
return dlsym(fFragmentP, inSymbolName);
#endif
}

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@
*
*/
/*
File: OSDynamicLoader.h
Contains: OS abstraction for loading code fragments.
*/
#ifndef _OS_CODEFRAGMENT_H_
#define _OS_CODEFRAGMENT_H_
#include <stdlib.h>
#include "SafeStdLib.h"
#include "OSHeaders.h"
#ifdef __MacOSX__
#include <CoreFoundation/CFBundle.h>
#endif
class OSCodeFragment
{
public:
static void Initialize();
OSCodeFragment(const char* inPath);
~OSCodeFragment();
Bool16 IsValid() { return (fFragmentP != NULL); }
void* GetSymbol(const char* inSymbolName);
private:
#ifdef __Win32__
HMODULE fFragmentP;
#elif __MacOSX__
CFBundleRef fFragmentP;
#else
void* fFragmentP;
#endif
};
#endif//_OS_CODEFRAGMENT_H_

View file

@ -0,0 +1,119 @@
/*
*
* @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: OSCond.cpp
Contains: Implementation of OSCond class
*/
#include "OSCond.h"
#include "OSMutex.h"
#include "OSThread.h"
#include "MyAssert.h"
#if __PTHREADS_MUTEXES__
#include <sys/time.h>
#endif
OSCond::OSCond()
{
#ifdef __Win32__
fCondition = ::CreateEvent(NULL, FALSE, FALSE, NULL);
Assert(fCondition != NULL);
#elif __PTHREADS_MUTEXES__
#if __MacOSX__
int ret = pthread_cond_init(&fCondition, NULL);
Assert(ret == 0);
#else
pthread_condattr_t cond_attr;
pthread_condattr_init(&cond_attr);
int ret = pthread_cond_init(&fCondition, &cond_attr);
Assert(ret == 0);
#endif
#else
fCondition = mycondition_alloc();
Assert(fCondition != NULL);
#endif
}
OSCond::~OSCond()
{
#ifdef __Win32__
BOOL theErr = ::CloseHandle(fCondition);
Assert(theErr == TRUE);
#elif __PTHREADS_MUTEXES__
pthread_cond_destroy(&fCondition);
#else
Assert(fCondition != NULL);
mycondition_free(fCondition);
#endif
}
#if __PTHREADS_MUTEXES__
void OSCond::TimedWait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs)
{
struct timespec ts;
struct timeval tv;
struct timezone tz;
int sec, usec;
//These platforms do refcounting manually, and wait will release the mutex,
// so we need to update the counts here
inMutex->fHolderCount--;
inMutex->fHolder = 0;
if (inTimeoutInMilSecs == 0)
(void)pthread_cond_wait(&fCondition, &inMutex->fMutex);
else
{
gettimeofday(&tv, &tz);
sec = inTimeoutInMilSecs / 1000;
inTimeoutInMilSecs = inTimeoutInMilSecs - (sec * 1000);
Assert(inTimeoutInMilSecs < 1000);
usec = inTimeoutInMilSecs * 1000;
Assert(tv.tv_usec < 1000000);
ts.tv_sec = tv.tv_sec + sec;
ts.tv_nsec = (tv.tv_usec + usec) * 1000;
Assert(ts.tv_nsec < 2000000000);
if(ts.tv_nsec > 999999999)
{
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
(void)pthread_cond_timedwait(&fCondition, &inMutex->fMutex, &ts);
}
inMutex->fHolderCount++;
inMutex->fHolder = pthread_self();
}
#endif

129
CommonUtilitiesLib/OSCond.h Normal file
View file

@ -0,0 +1,129 @@
/*
*
* @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: OSCond.h
Contains: A simple condition variable abstraction
*/
#ifndef _OSCOND_H_
#define _OSCOND_H_
#ifndef __Win32__
#if __PTHREADS_MUTEXES__
#include <pthread.h>
#else
#include "mycondition.h"
#endif
#endif
#include "OSMutex.h"
#include "MyAssert.h"
class OSCond
{
public:
OSCond();
~OSCond();
inline void Signal();
inline void Wait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs = 0);
inline void Broadcast();
private:
#ifdef __Win32__
HANDLE fCondition;
UInt32 fWaitCount;
#elif __PTHREADS_MUTEXES__
pthread_cond_t fCondition;
void TimedWait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs);
#else
mycondition_t fCondition;
#endif
};
inline void OSCond::Wait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs)
{
#ifdef __Win32__
DWORD theTimeout = INFINITE;
if (inTimeoutInMilSecs > 0)
theTimeout = inTimeoutInMilSecs;
inMutex->Unlock();
fWaitCount++;
DWORD theErr = ::WaitForSingleObject(fCondition, theTimeout);
fWaitCount--;
Assert((theErr == WAIT_OBJECT_0) || (theErr == WAIT_TIMEOUT));
inMutex->Lock();
#elif __PTHREADS_MUTEXES__
this->TimedWait(inMutex, inTimeoutInMilSecs);
#else
Assert(fCondition != NULL);
mycondition_wait(fCondition, inMutex->fMutex, inTimeoutInMilSecs);
#endif
}
inline void OSCond::Signal()
{
#ifdef __Win32__
BOOL theErr = ::SetEvent(fCondition);
Assert(theErr == TRUE);
#elif __PTHREADS_MUTEXES__
pthread_cond_signal(&fCondition);
#else
Assert(fCondition != NULL);
mycondition_signal(fCondition);
#endif
}
inline void OSCond::Broadcast()
{
#ifdef __Win32__
//
// There doesn't seem like any more elegant way to
// implement Broadcast using events in Win32.
// This will work, it may generate spurious wakeups,
// but condition variables are allowed to generate
// spurious wakeups
UInt32 waitCount = fWaitCount;
for (UInt32 x = 0; x < waitCount; x++)
{
BOOL theErr = ::SetEvent(fCondition);
Assert(theErr == TRUE);
}
#elif __PTHREADS_MUTEXES__
pthread_cond_broadcast(&fCondition);
#else
Assert(fCondition != NULL);
mycondition_broadcast(fCondition);
#endif
}
#endif //_OSCOND_H_

View file

@ -0,0 +1,633 @@
/*
*
* @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: osfile.cpp
Contains: simple file abstraction
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#ifndef __Win32__
#include <unistd.h>
#endif
#include "OSFileSource.h"
#include "OSMemory.h"
#include "OSThread.h"
#include "OS.h"
#include "OSQueue.h"
#include "OSHeaders.h"
#define FILE_SOURCE_DEBUG 0
#define FILE_SOURCE_BUFFTEST 0
#define TEST_TIME 0
#if TEST_TIME
static SInt64 startTime = 0;
static SInt64 durationTime = 0;
static SInt32 sReadCount = 0;
static SInt32 sByteCount = 0;
static Bool16 sMovie = false;
#endif
#if READ_LOG
extern UInt32 xTrackID;
void OSFileSource::SetLog(const char *inPath)
{
fFilePath[0] =0;
::strcpy(fFilePath,inPath);
if (fFile != -1 && fFileLog == NULL)
{
::strcat(fFilePath,inPath);
::strcat(fFilePath,".readlog");
fFileLog = ::fopen(fFilePath,"w+");
if (fFileLog && IsValid())
{ qtss_fprintf(fFileLog, "%s","QTFILE_READ_LOG\n");
qtss_fprintf(fFileLog, "size: %qu\n",GetLength());
qtss_printf("OSFileSource::SetLog=%s\n",fFilePath);
}
::fclose(fFileLog);
}
}
#else
void OSFileSource::SetLog(const char *inPath)
{
#if FILE_SOURCE_DEBUG
qtss_printf("OSFileSource::SetLog=%s\n",inPath);
#endif
}
#endif
FileBlockBuffer::~FileBlockBuffer(void)
{
if (fDataBuffer != NULL)
{
Assert (fDataBuffer[fBufferSize] == 0);
#if FILE_SOURCE_DEBUG
::memset( (char *)fDataBuffer,0, fBufferSize);
qtss_printf("FileBlockBuffer::~FileBlockBuffer delete %"_U32BITARG_" this=%"_U32BITARG_"\n",fDataBuffer, this);
#endif
delete fDataBuffer;
fDataBuffer = NULL;
fArrayIndex = -1;
}
else
Assert(false);
}
void FileBlockBuffer::AllocateBuffer(UInt32 buffSize)
{
fBufferSize = buffSize;
fDataBuffer = NEW char[buffSize + 1];
fDataBuffer[buffSize] = 0;
#if FILE_SOURCE_DEBUG
this->CleanBuffer();
qtss_printf("FileBlockBuffer::FileBlockBuffer allocate buff ptr =%"_U32BITARG_" len=%"_U32BITARG_" this=%"_U32BITARG_"\n",fDataBuffer,buffSize,this);
#endif
}
void FileBlockBuffer::TestBuffer(void)
{
#if FILE_SOURCE_BUFFTEST
if (fDataBuffer != NULL)
Assert (fDataBuffer[fBufferSize] == 0);
#endif
}
void FileBlockPool::MarkUsed(FileBlockBuffer* inBuffPtr)
{
if (NULL == inBuffPtr)
return;
if (fQueue.GetTail() != inBuffPtr->GetQElem()) // Least Recently Used tail is last accessed
{
fQueue.Remove(inBuffPtr->GetQElem());
fQueue.EnQueue(inBuffPtr->GetQElem()); // put on tail
}
}
FileBlockBuffer *FileBlockPool::GetBufferElement(UInt32 bufferSizeBytes)
{
FileBlockBuffer* theNewBuf = NULL;
if ( fNumCurrentBuffers < fMaxBuffers)
{
#if FILE_SOURCE_DEBUG
qtss_printf("FileBlockPool::GetBufferElement NEW element fNumCurrentBuffers=%"_U32BITARG_" fMaxBuffers=%"_U32BITARG_" fBufferUnitSizeBytes=%"_U32BITARG_" bufferSizeBytes=%"_U32BITARG_"\n",fNumCurrentBuffers,fMaxBuffers,fBufferUnitSizeBytes,bufferSizeBytes);
#endif
theNewBuf = NEW FileBlockBuffer();
theNewBuf->AllocateBuffer(bufferSizeBytes);
fNumCurrentBuffers++;
theNewBuf->fQElem.SetEnclosingObject(theNewBuf);
fQueue.EnQueue(theNewBuf->GetQElem()); // put on tail
Assert(theNewBuf != NULL);
return theNewBuf;
}
OSQueueElem *theElem = fQueue.DeQueue(); // get head
Assert(theElem != NULL);
if (theElem == NULL)
return NULL;
theNewBuf = (FileBlockBuffer*) theElem->GetEnclosingObject();
Assert(theNewBuf != NULL);
//qtss_printf("FileBlockPool::GetBufferElement reuse buffer theNewBuf=%"_U32BITARG_" fDataBuffer=%"_U32BITARG_" fArrayIndex=%"_S32BITARG_"\n",theNewBuf,theNewBuf->fDataBuffer,theNewBuf->fArrayIndex);
return theNewBuf;
}
void FileBlockPool::DeleteBlockPool(void)
{
FileBlockBuffer *buffer = NULL;
OSQueueElem* theElem = fQueue.DeQueue();
while (theElem != NULL)
{ buffer = (FileBlockBuffer *) theElem->GetEnclosingObject();
delete buffer;
theElem = fQueue.DeQueue();
}
fMaxBuffers = 1;
fNumCurrentBuffers = 0;
fBufferUnitSizeBytes = kBufferUnitSize;
}
FileBlockPool::~FileBlockPool(void)
{
this->DeleteBlockPool();
}
void FileMap::AllocateBufferMap(UInt32 inUnitSizeInK, UInt32 inNumBuffSizeUnits, UInt32 inBufferIncCount, UInt32 inMaxBitRateBuffSizeInBlocks, UInt64 fileLen, UInt32 inBitRate)
{
if (fFileMapArray != NULL && fNumBuffSizeUnits == inNumBuffSizeUnits && inBufferIncCount == fBlockPool.GetMaxBuffers())
return;
if( inUnitSizeInK < 1 )
inUnitSizeInK = 1;
fBlockPool.SetBufferUnitSize(inUnitSizeInK);
if (inBitRate == 0) // just use the maximum possible size
inBitRate = inMaxBitRateBuffSizeInBlocks * fBlockPool.GetBufferUnitSizeBytes();
if (inNumBuffSizeUnits == 0) // calculate the buffer size ourselves
{
inNumBuffSizeUnits = inBitRate / fBlockPool.GetBufferUnitSizeBytes();
if( inNumBuffSizeUnits > inMaxBitRateBuffSizeInBlocks) // max is 8 * buffUnit Size (32k) = 256K
{ inNumBuffSizeUnits = inMaxBitRateBuffSizeInBlocks;
}
} //else the inNumBuffSizeUnits is explicitly defined so just use that value
if( inNumBuffSizeUnits < 1 )
inNumBuffSizeUnits = 1;
this->DeleteMap();
fBlockPool.DeleteBlockPool();
fNumBuffSizeUnits = inNumBuffSizeUnits;
fDataBufferSize = fBlockPool.GetBufferUnitSizeBytes() * inNumBuffSizeUnits;
fBlockPool.SetMaxBuffers(inBufferIncCount);
fBlockPool.SetBuffIncValue(inBufferIncCount);
fMapArraySize = (fileLen / fDataBufferSize) + 1;
fFileMapArray = NEW FileBlockBuffer *[ (SInt32) (fMapArraySize + 1) ];
this->Clean(); // required because fFileMapArray's array is used to store buffer pointers.
#if FILE_SOURCE_DEBUG
qtss_printf("FileMap::AllocateBufferMap shared buffers fFileMapArray=%"_U32BITARG_" fDataBufferSize= %"_U32BITARG_" fMapArraySize=%"_U32BITARG_" fileLen=%qu \n",fFileMapArray, fDataBufferSize, fMapArraySize,fileLen);
#endif
}
void FileMap::DeleteOldBuffs()
{
while (fBlockPool.GetNumCurrentBuffers() > fBlockPool.GetMaxBuffers()) // delete any old buffers
{
FileBlockBuffer *theElem = fBlockPool.GetBufferElement(fDataBufferSize);
fFileMapArray[theElem->fArrayIndex] = NULL;
delete theElem;
fBlockPool.DecCurBuffers();
}
}
char *FileMap::GetBuffer(SInt64 buffIndex, Bool16 *outFillBuff)
{
Assert(outFillBuff != NULL);
*outFillBuff = true; // we are re-using or just created a buff
this->DeleteOldBuffs();
Assert(buffIndex < (SInt32) fMapArraySize);
FileBlockBuffer *theElem = fFileMapArray[buffIndex];
if ( NULL == theElem)
{
#if FILE_SOURCE_DEBUG
qtss_printf("FileMap::GetBuffer call fBlockPool.GetBufferElement(); buffIndex=%"_S32BITARG_"\n",buffIndex);
#endif
theElem = fBlockPool.GetBufferElement(fDataBufferSize);
Assert(theElem);
}
fBlockPool.MarkUsed(theElem); // must happen here after getting a pre-allocated or used buffer.
if (theElem->fArrayIndex == buffIndex) // found a pre-allocated and filled buffer
{
#if FILE_SOURCE_DEBUG
//qtss_printf("FileMap::GetBuffer pre-allocated buff buffIndex=%"_S32BITARG_"\n",buffIndex);
#endif
*outFillBuff = false;
return theElem->fDataBuffer;
}
if (theElem->fArrayIndex >= 0)
{
fFileMapArray[theElem->fArrayIndex] = NULL; // reset the old map location
}
fFileMapArray[buffIndex] = theElem; // a new buffer
theElem->fArrayIndex = buffIndex; // record the index
#if FILE_SOURCE_DEBUG
theElem->CleanBuffer();
#endif
return theElem->fDataBuffer;
}
void FileMap::Clean(void)
{
if (fFileMapArray != NULL)
::memset( (char *)fFileMapArray,0, (SInt32) (sizeof(FileBlockBuffer *) * fMapArraySize) );
}
void FileMap::DeleteMap(void)
{
if (NULL == fFileMapArray)
return;
#if FILE_SOURCE_DEBUG
qtss_printf("FileMap::DeleteMap fFileMapArray=%"_U32BITARG_" fMapArraySize=%"_S32BITARG_" \n",fFileMapArray, fMapArraySize);
this->Clean();
#endif
delete fFileMapArray;
fFileMapArray = NULL;
}
void OSFileSource::Set(const char *inPath)
{
Close();
#if __Win32__
fFile = open(inPath, O_RDONLY | O_BINARY);
#elif __linux__
fFile = open(inPath, O_RDONLY | O_LARGEFILE);
#else
fFile = open(inPath, O_RDONLY);
#endif
if (fFile != -1)
{
struct stat buf;
::memset(&buf,sizeof(buf),0);
if (::fstat(fFile, &buf) >= 0)
{
fLength = buf.st_size;
fModDate = buf.st_mtime;
if (fModDate < 0)
fModDate = 0;
#ifdef __Win32__
fIsDir = buf.st_mode & _S_IFDIR;
#else
fIsDir = S_ISDIR(buf.st_mode);
#endif
this->SetLog(inPath);
}
else
this->Close();
}
}
void OSFileSource::Advise(UInt64 , UInt32 )
{
// does nothing on platforms other than MacOSXServer
}
OS_Error OSFileSource::FillBuffer(char* ioBuffer, char *buffStart, SInt32 buffIndex)
{
UInt32 buffSize = fFileMap.GetMaxBufSize();
UInt64 startPos = (UInt64) buffIndex * (UInt64) buffSize;
UInt32 readLen = 0;
OS_Error theErr = this->ReadFromPos(startPos, buffStart, buffSize, &readLen);
fFileMap.SetIndexBuffFillSize(buffIndex, readLen);
fFileMap.TestBuffer(buffIndex);
return theErr;
}
#if FILE_SOURCE_BUFFTEST
static SInt32 sBuffCount = 1;
#endif
OS_Error OSFileSource::Read(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen)
{
if ( ( !fFileMap.Initialized() )
|| ( !fCacheEnabled )
|| ( fFileMap.GetBuffIndex(inPosition+inLength) > fFileMap.GetMaxBuffIndex() )
)
return this->ReadFromPos(inPosition, inBuffer, inLength, outRcvLen);
return this->ReadFromCache(inPosition, inBuffer, inLength, outRcvLen);
}
OS_Error OSFileSource::ReadFromCache(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen)
{
OSMutexLocker locker(&fMutex);
if (!fFileMap.Initialized() || !fCacheEnabled)
{ Assert(0);
}
Assert(outRcvLen != NULL);
*outRcvLen = 0;
if (inPosition >= fLength) // eof
return OS_NoErr;
SInt64 buffIndex = fFileMap.GetBuffIndex(inPosition);
SInt64 buffSize = 0;
SInt64 maxBuffSize = fFileMap.GetMaxBufSize();
SInt64 endIndex = fFileMap.GetBuffIndex(inPosition+inLength);
SInt64 maxIndex = fFileMap.GetMaxBuffIndex();
SInt64 buffPos = inPosition - fFileMap.GetBuffOffset(buffIndex);
SInt64 buffOffsetLen = 0;
char *buffStart = NULL;
SInt64 buffCopyLen = inLength;
SInt64 bytesToCopy = inLength;
char *buffOut = (char*)inBuffer;
Bool16 fillBuff = true;
char *buffOffset = NULL;
#if FILE_SOURCE_BUFFTEST
char testBuff[inLength + 1];
buffOut = (char*)testBuff;
sBuffCount ++;
::memset(inBuffer,0,inLength);
::memset(testBuff,0,inLength);
#endif
if (buffIndex > endIndex || endIndex > maxIndex)
{
#if FILE_SOURCE_DEBUG
qtss_printf("OSFileSource::ReadFromCache bad index: buffIndex=%"_S32BITARG_" endIndex=%"_S32BITARG_" maxIndex=%"_S32BITARG_"\n",buffIndex,endIndex,maxIndex);
qtss_printf("OSFileSource::ReadFromCache inPosition =%qu buffSize = %"_U32BITARG_" index=%"_S32BITARG_"\n",inPosition, fFileMap.GetMaxBufSize(),buffIndex);
#endif
Assert(0);
}
while (buffIndex <= endIndex && buffIndex <= maxIndex)
{
#if FILE_SOURCE_DEBUG
qtss_printf("OSFileSource::ReadFromCache inPosition =%qu buffSize = %"_U32BITARG_" index=%"_S32BITARG_"\n",inPosition, fFileMap.GetMaxBufSize(),buffIndex);
#endif
buffStart = fFileMap.GetBuffer(buffIndex, &fillBuff);
Assert(buffStart != NULL);
if (fillBuff)
{
OS_Error theErr = this->FillBuffer( (char *) inBuffer, (char *) buffStart, (SInt32) buffIndex);
if (theErr != OS_NoErr)
return theErr;
}
buffSize = fFileMap.GetBuffSize(buffIndex);
buffOffset = &buffStart[buffPos];
if ( (buffPos == 0) &&
(bytesToCopy <= maxBuffSize) &&
(buffSize < bytesToCopy)
) // that's all there is in the file
{
#if FILE_SOURCE_DEBUG
qtss_printf("OSFileSource::ReadFromCache end of file reached buffIndex=%"_U32BITARG_" buffSize = %"_S32BITARG_" bytesToCopy=%"_U32BITARG_"\n",buffIndex, buffSize,bytesToCopy);
#endif
Assert(buffSize <= (SInt64) kUInt32_Max);
::memcpy(buffOut,buffOffset,(UInt32) buffSize);
*outRcvLen += (UInt32) buffSize;
break;
}
buffOffsetLen = buffSize - buffPos;
if (buffCopyLen >= buffOffsetLen)
buffCopyLen = buffOffsetLen;
Assert(buffCopyLen <= buffSize);
::memcpy(buffOut,buffOffset, (UInt32) buffCopyLen);
buffOut += buffCopyLen;
*outRcvLen += (UInt32) buffCopyLen;
bytesToCopy -= buffCopyLen;
Assert(bytesToCopy >= 0);
buffCopyLen = bytesToCopy;
buffPos = 0;
buffIndex ++;
}
#if FILE_SOURCE_DEBUG
//qtss_printf("OSFileSource::ReadFromCache inLength= %"_U32BITARG_" *outRcvLen=%"_U32BITARG_"\n",inLength, *outRcvLen);
#endif
#if FILE_SOURCE_BUFFTEST
{ UInt32 outLen = 0;
OS_Error theErr = this->ReadFromPos(inPosition, inBuffer, inLength, &outLen);
Assert(*outRcvLen == outLen);
if (*outRcvLen != outLen)
qtss_printf("OSFileSource::ReadFromCache *outRcvLen != outLen *outRcvLen=%"_U32BITARG_" outLen=%"_U32BITARG_"\n",*outRcvLen,outLen);
for (int i = 0; i < inLength; i++)
{ if ( ((char*)inBuffer)[i] != testBuff[i])
{ qtss_printf("OSFileSource::ReadFromCache byte pos %d of %"_U32BITARG_" failed len=%"_U32BITARG_" inPosition=%qu sBuffCount=%"_S32BITARG_"\n",i,inLength,outLen,inPosition,sBuffCount);
break;
}
}
}
#endif
return OS_NoErr;
}
OS_Error OSFileSource::ReadFromDisk(void* inBuffer, UInt32 inLength, UInt32* outRcvLen)
{
#if FILE_SOURCE_BUFFTEST
qtss_printf("OSFileSource::Read inLength=%"_U32BITARG_" fFile=%d\n",inLength,fFile);
#endif
#if __Win32__
if (_lseeki64(fFile, fPosition, SEEK_SET) == -1)
return OSThread::GetErrno();
#else
if (lseek(fFile, fPosition, SEEK_SET) == -1)
return OSThread::GetErrno();
#endif
int rcvLen = ::read(fFile, (char*)inBuffer, inLength);
if (rcvLen == -1)
return OSThread::GetErrno();
if (outRcvLen != NULL)
*outRcvLen = rcvLen;
fPosition += rcvLen;
fReadPos = fPosition;
return OS_NoErr;
}
OS_Error OSFileSource::ReadFromPos(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen)
{
#if TEST_TIME
{
startTime = OS::Milliseconds();
sReadCount++;
if (outRcvLen)
*outRcvLen = 0;
qtss_printf("OSFileSource::Read sReadCount = %"_S32BITARG_" totalbytes=%"_S32BITARG_" readsize=%"_U32BITARG_"\n",sReadCount,sByteCount,inLength);
}
#endif
this->Seek(inPosition);
OS_Error err = this->ReadFromDisk(inBuffer,inLength,outRcvLen);
#if READ_LOG
if (fFileLog)
{ fFileLog = ::fopen(fFilePath,"a");
if (fFileLog)
{ qtss_fprintf(fFileLog, "read: %qu %"_U32BITARG_" %"_U32BITARG_"\n",inPosition, *outRcvLen, xTrackID);
::fclose(fFileLog);
}
}
#endif
#if TEST_TIME
{
durationTime += OS::Milliseconds() - startTime;
sByteCount += *outRcvLen;
}
#endif
return err;
}
void OSFileSource::SetTrackID(UInt32 trackID)
{
#if READ_LOG
fTrackID = trackID;
// qtss_printf("OSFileSource::SetTrackID = %"_U32BITARG_" this=%"_U32BITARG_"\n",fTrackID,(UInt32) this);
#endif
}
void OSFileSource::Close()
{
if ((fFile != -1) && (fShouldClose))
{ ::close(fFile);
#if READ_LOG
if ( 0 && fFileLog != NULL )
{ ::fclose(fFileLog);
fFileLog = NULL;
fFilePath[0] =0;
}
#endif
}
fFile = -1;
fModDate = 0;
fLength = 0;
fPosition = 0;
fReadPos = 0;
#if TEST_TIME
if (fShouldClose)
{ sMovie = 0;
// qtss_printf("OSFileSource::Close sReadCount = %"_S32BITARG_" totalbytes=%"_S32BITARG_"\n",sReadCount,sByteCount);
// qtss_printf("OSFileSource::Close durationTime = %qd\n",durationTime);
}
#endif
}

View file

@ -0,0 +1,234 @@
/*
*
* @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: osfilesource.h
Contains: simple file abstraction. This file abstraction is ONLY to be
used for files intended for serving
*/
#ifndef __OSFILE_H_
#define __OSFILE_H_
#include <stdio.h>
#include <time.h>
#include "OSHeaders.h"
#include "StrPtrLen.h"
#include "OSQueue.h"
#define READ_LOG 0
class FileBlockBuffer
{
public:
FileBlockBuffer(): fArrayIndex(-1),fBufferSize(0),fBufferFillSize(0),fDataBuffer(NULL),fDummy(0){}
~FileBlockBuffer(void);
void AllocateBuffer(UInt32 buffSize);
void TestBuffer(void);
void CleanBuffer() { ::memset(fDataBuffer,0, fBufferSize); }
void SetFillSize(UInt32 fillSize) {fBufferFillSize = fillSize;}
UInt32 GetFillSize(void) { return fBufferFillSize;}
OSQueueElem *GetQElem() { return &fQElem; }
SInt64 fArrayIndex;
UInt32 fBufferSize;
UInt32 fBufferFillSize;
char *fDataBuffer;
OSQueueElem fQElem;
UInt32 fDummy;
};
class FileBlockPool
{
enum {
kDataBufferUnitSizeExp = 15,// base 2 exponent
kBufferUnitSize = (1 << kDataBufferUnitSizeExp ) // 32Kbytes
};
public:
FileBlockPool(void) : fMaxBuffers(1), fNumCurrentBuffers(0), fBufferUnitSizeBytes(kBufferUnitSize){}
~FileBlockPool(void);
void SetMaxBuffers(UInt32 maxBuffers) { if (maxBuffers > 0) fMaxBuffers = maxBuffers; }
void SetBuffIncValue(UInt32 bufferInc) { if (bufferInc > 0) fBufferInc = bufferInc;}
void IncMaxBuffers(void) { fMaxBuffers += fBufferInc; }
void DecMaxBuffers(void) { if (fMaxBuffers > fBufferInc) fMaxBuffers-= fBufferInc; }
void DecCurBuffers(void) { if (fNumCurrentBuffers > 0) fNumCurrentBuffers--; }
void SetBufferUnitSize (UInt32 inUnitSizeInK) { fBufferUnitSizeBytes = inUnitSizeInK * 1024; }
UInt32 GetBufferUnitSizeBytes() { return fBufferUnitSizeBytes; }
UInt32 GetMaxBuffers(void) { return fMaxBuffers; }
UInt32 GetIncBuffers() { return fBufferInc; }
UInt32 GetNumCurrentBuffers(void) { return fNumCurrentBuffers; }
void DeleteBlockPool();
FileBlockBuffer* GetBufferElement(UInt32 bufferSizeBytes);
void MarkUsed(FileBlockBuffer* inBuffPtr);
private:
OSQueue fQueue;
UInt32 fMaxBuffers;
UInt32 fNumCurrentBuffers;
UInt32 fBufferInc;
UInt32 fBufferUnitSizeBytes;
UInt32 fBufferDataSizeBytes;
};
class FileMap
{
public:
FileMap(void):fFileMapArray(NULL),fDataBufferSize(0),fMapArraySize(0),fNumBuffSizeUnits(0) {}
~FileMap(void) {fFileMapArray = NULL;}
void AllocateBufferMap(UInt32 inUnitSizeInK, UInt32 inNumBuffSizeUnits, UInt32 inBufferIncCount, UInt32 inMaxBitRateBuffSizeInBlocks, UInt64 fileLen, UInt32 inBitRate);
char* GetBuffer(SInt64 bufIndex, Bool16 *outIsEmptyBuff);
void TestBuffer(SInt32 bufIndex) {Assert (bufIndex >= 0); fFileMapArray[bufIndex]->TestBuffer();};
void SetIndexBuffFillSize(SInt32 bufIndex, UInt32 fillSize) { Assert (bufIndex >= 0); fFileMapArray[bufIndex]->SetFillSize(fillSize);}
UInt32 GetMaxBufSize(void) {return fDataBufferSize;}
UInt32 GetBuffSize(SInt64 bufIndex) { Assert (bufIndex >= 0); return fFileMapArray[bufIndex]->GetFillSize(); }
UInt32 GetIncBuffers(void) { return fBlockPool.GetIncBuffers(); }
void IncMaxBuffers() {fBlockPool.IncMaxBuffers(); }
void DecMaxBuffers() {fBlockPool.DecMaxBuffers(); }
Bool16 Initialized() { return fFileMapArray == NULL ? false : true; }
void Clean(void);
void DeleteMap(void);
void DeleteOldBuffs(void);
SInt64 GetBuffIndex(UInt64 inPosition) { return inPosition / this->GetMaxBufSize(); }
SInt64 GetMaxBuffIndex() { Assert(fMapArraySize > 0); return fMapArraySize -1; }
UInt64 GetBuffOffset(SInt64 bufIndex) { return (UInt64) (bufIndex * this->GetMaxBufSize() ); }
FileBlockPool fBlockPool;
FileBlockBuffer** fFileMapArray;
private:
UInt32 fDataBufferSize;
SInt64 fMapArraySize;
UInt32 fNumBuffSizeUnits;
};
class OSFileSource
{
public:
OSFileSource() : fFile(-1), fLength(0), fPosition(0), fReadPos(0), fShouldClose(true), fIsDir(false), fCacheEnabled(false)
{
#if READ_LOG
fFileLog = NULL;
fTrackID = 0;
fFilePath[0]=0;
#endif
}
OSFileSource(const char *inPath) : fFile(-1), fLength(0), fPosition(0), fReadPos(0), fShouldClose(true), fIsDir(false),fCacheEnabled(false)
{
Set(inPath);
#if READ_LOG
fFileLog = NULL;
fTrackID = 0;
fFilePath[0]=0;
#endif
}
~OSFileSource() { Close(); fFileMap.DeleteMap();}
//Sets this object to reference this file
void Set(const char *inPath);
// Call this if you don't want Close or the destructor to close the fd
void DontCloseFD() { fShouldClose = false; }
//Advise: this advises the OS that we are going to be reading soon from the
//following position in the file
void Advise(UInt64 advisePos, UInt32 adviseAmt);
OS_Error Read(void* inBuffer, UInt32 inLength, UInt32* outRcvLen = NULL)
{ return ReadFromDisk(inBuffer, inLength, outRcvLen);
}
OS_Error Read(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen = NULL);
OS_Error ReadFromDisk(void* inBuffer, UInt32 inLength, UInt32* outRcvLen = NULL);
OS_Error ReadFromCache(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen = NULL);
OS_Error ReadFromPos(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen = NULL);
void EnableFileCache(Bool16 enabled) {OSMutexLocker locker(&fMutex); fCacheEnabled = enabled; }
Bool16 GetCacheEnabled() { return fCacheEnabled; }
void AllocateFileCache(UInt32 inUnitSizeInK = 32, UInt32 bufferSizeUnits = 0, UInt32 incBuffers = 1, UInt32 inMaxBitRateBuffSizeInBlocks = 8, UInt32 inBitRate = 32768)
{ fFileMap.AllocateBufferMap(inUnitSizeInK, bufferSizeUnits,incBuffers, inMaxBitRateBuffSizeInBlocks, fLength, inBitRate);
}
void IncMaxBuffers() {OSMutexLocker locker(&fMutex); fFileMap.IncMaxBuffers(); }
void DecMaxBuffers() {OSMutexLocker locker(&fMutex); fFileMap.DecMaxBuffers(); }
OS_Error FillBuffer(char* ioBuffer, char *buffStart, SInt32 bufIndex);
void Close();
time_t GetModDate() { return fModDate; }
UInt64 GetLength() { return fLength; }
UInt64 GetCurOffset() { return fPosition; }
void Seek(SInt64 newPosition) { fPosition = newPosition; }
Bool16 IsValid() { return fFile != -1; }
Bool16 IsDir() { return fIsDir; }
// For async I/O purposes
int GetFD() { return fFile; }
void SetTrackID(UInt32 trackID);
// So that close won't do anything
void ResetFD() { fFile=-1; }
void SetLog(const char *inPath);
private:
int fFile;
UInt64 fLength;
UInt64 fPosition;
UInt64 fReadPos;
Bool16 fShouldClose;
Bool16 fIsDir;
time_t fModDate;
OSMutex fMutex;
FileMap fFileMap;
Bool16 fCacheEnabled;
#if READ_LOG
FILE* fFileLog;
char fFilePath[1024];
UInt32 fTrackID;
#endif
};
#endif //__OSFILE_H_

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@
*
*/
/*
File: OSHashTable.h
Contains: Defines a template class for hash tables.
*/
#ifndef _OSHASHTABLE_H_
#define _OSHASHTABLE_H_
#include "MyAssert.h"
#include "OSHeaders.h"
/*
T must have a fNextHashEntry field, and key(T) must returns the key of type K.
K must have a method GetHashKey() that returns an UInt32 bit hash value.
Will the hash table can contain duplicate keys, the Map function will return only the first one.
*/
template<class T, class K>
class OSHashTable {
public:
OSHashTable( UInt32 size )
{
fHashTable = new ( T*[size] );
Assert( fHashTable );
memset( fHashTable, 0, sizeof(T*) * size );
fSize = size;
// Determine whether the hash size is a power of 2
// if not set the mask to zero, otherwise we can
// use the mask which is faster for ComputeIndex
fMask = fSize - 1;
if ((fMask & fSize) != 0)
fMask = 0;
fNumEntries = 0;
}
~OSHashTable()
{
delete [] fHashTable;
}
void Add( T* entry ) {
Assert( entry->fNextHashEntry == NULL );
K key( entry );
UInt32 theIndex = ComputeIndex( key.GetHashKey() );
entry->fNextHashEntry = fHashTable[ theIndex ];
fHashTable[ theIndex ] = entry;
fNumEntries++;
}
void Remove( T* entry )
{
K key( entry );
UInt32 theIndex = ComputeIndex( key.GetHashKey() );
T* elem = fHashTable[ theIndex ];
T* last = NULL;
while (elem && elem != entry) {
last = elem;
elem = elem->fNextHashEntry;
}
if ( elem ) // sometimes remove is called 2x ( swap, then un register )
{
Assert(elem);
if (last)
last->fNextHashEntry = elem->fNextHashEntry;
else
fHashTable[ theIndex ] = elem->fNextHashEntry;
elem->fNextHashEntry = NULL;
fNumEntries--;
}
}
T* Map( K* key )
{
UInt32 theIndex = ComputeIndex( key->GetHashKey() );
T* elem = fHashTable[ theIndex ];
while (elem) {
K elemKey( elem );
if (elemKey == *key)
break;
elem = elem->fNextHashEntry;
}
return elem;
}
UInt64 GetNumEntries() { return fNumEntries; }
UInt32 GetTableSize() { return fSize; }
T* GetTableEntry( int i ) { return fHashTable[i]; }
private:
T** fHashTable;
UInt32 fSize;
UInt32 fMask;
UInt64 fNumEntries;
UInt32 ComputeIndex( UInt32 hashKey )
{
if (fMask)
return( hashKey & fMask );
else
return( hashKey % fSize );
}
};
template<class T, class K>
class OSHashTableIter {
public:
OSHashTableIter( OSHashTable<T,K>* table )
{
fHashTable = table;
First();
}
void First()
{
for (fIndex = 0; fIndex < fHashTable->GetTableSize(); fIndex++) {
fCurrent = fHashTable->GetTableEntry( fIndex );
if (fCurrent)
break;
}
}
void Next()
{
fCurrent = fCurrent->fNextHashEntry;
if (!fCurrent) {
for (fIndex = fIndex + 1; fIndex < fHashTable->GetTableSize(); fIndex++) {
fCurrent = fHashTable->GetTableEntry( fIndex );
if (fCurrent)
break;
}
}
}
Bool16 IsDone()
{
return( fCurrent == NULL );
}
T* GetCurrent() { return fCurrent; }
private:
OSHashTable<T,K>* fHashTable;
T* fCurrent;
UInt32 fIndex;
};
#endif //_OSHASHTABLE_H_

View file

@ -0,0 +1,35 @@
#include "OSHeaders.h"
#if __linux__
// OpenBSD strlcpy implementation to allow usage of it while on Linux.
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif

View file

@ -0,0 +1,562 @@
/*
*
* @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 OSHeaders_H
#define OSHeaders_H
#include <limits.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* Platform-specific components */
#if __MacOSX__
/* Defines */
#define _64BITARG_ "ll"
#define _S64BITARG_ "lld"
#define _U64BITARG_ "llu"
#if __LP64__
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#define _SPOINTERSIZEARG_ _S64BITARG_
#define _UPOINTERSIZEARG_ _U64BITARG_
#else
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#define _SPOINTERSIZEARG_ _S32BITARG_
#define _UPOINTERSIZEARG_ _U32BITARG_
#endif
/* paths */
#define kEOLString "\n"
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
/* Includes */
#include <sys/types.h>
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
#include "/System/Library/Frameworks/CoreServices.framework/Headers/../Frameworks/CarbonCore.framework/Headers/MacTypes.h"
#define kSInt16_Max (SInt16) SHRT_MAX
#define kUInt16_Max (UInt16) USHRT_MAX
#define kSInt32_Max (SInt32) LONG_MAX
#define kUInt32_Max (UInt32) ULONG_MAX
#define kSInt64_Max (SInt64) LONG_LONG_MAX
#define kUInt64_Max (UInt64) ULONG_LONG_MAX
#if 0 // old defs we are now using MacTypes.h
/* Typedefs */
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned int UInt32;
typedef signed int SInt32;
typedef signed long long SInt64;
typedef unsigned long long UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt32 FourCharCode;
typedef FourCharCode OSType;
#endif
typedef signed long PointerSizedInt;
typedef unsigned long PointerSizedUInt;
typedef UInt16 Bool16;
typedef UInt8 Bool8;
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#elif __linux__ || __linuxppc__ || __FreeBSD__
/* Defines */
#define _64BITARG_ "q"
#define _S64BITARG_ "lld"
#define _U64BITARG_ "llu"
#if __LP64__
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#else
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#endif
#define _SPOINTERSIZEARG_ _S64BITARG_
#define _UPOINTERSIZEARG_ _U64BITARG_
/* paths */
#define kEOLString "\n"
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
/* Includes */
#include <sys/types.h>
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
/* Typedefs */
typedef signed long PointerSizedInt;
typedef unsigned long PointerSizedUInt;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned int UInt32;
typedef signed int SInt32;
typedef signed long SInt64;
typedef unsigned long UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt16 Bool16;
typedef UInt8 Bool8;
/* Define max values of our custom typedefs */
#define kSInt16_Max (SInt16) SHRT_MAX
#define kUInt16_Max (UInt16) USHRT_MAX
#define kSInt32_Max (SInt32) INT_MAX
#define kUInt32_Max (UInt32) UINT_MAX
#define kSInt64_Max (SInt64) LONG_MAX
#define kUInt64_Max (UInt64) ULONG_MAX
typedef unsigned int FourCharCode;
typedef FourCharCode OSType;
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#if __linux__
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
#elif __Win32__
/* Defines */
#define _64BITARG_ "I64"
#define _S64BITARG_ "I64d"
#define _U64BITARG_ "I64u"
#if __LP64__
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#else
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#endif
/* paths */
#define kEOLString "\r\n"
#define kPathDelimiterString "\\"
#define kPathDelimiterChar '\\'
#define kPartialPathBeginsWithDelimiter 0
#define crypt(buf, salt) ((char*)buf)
/* Includes */
#include <windows.h>
#include <winsock2.h>
#include <mswsock.h>
#include <process.h>
#include <ws2tcpip.h>
#include <io.h>
#include <direct.h>
#include <errno.h>
#define R_OK 0
#define W_OK 1
// POSIX errorcodes
#define ENOTCONN 1002
#define EADDRINUSE 1004
#define EINPROGRESS 1007
#define ENOBUFS 1008
#define EADDRNOTAVAIL 1009
// Winsock does not use iovecs
struct iovec {
u_long iov_len; // this is not the POSIX definition, it is rather defined to be
char FAR* iov_base; // equivalent to a WSABUF for easy integration into Win32
};
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
/* Typedefs */
typedef signed long PointerSizedInt;
typedef unsigned long PointerSizedUInt;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned long UInt32;
typedef signed long SInt32;
typedef LONGLONG SInt64;
typedef ULONGLONG UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt16 Bool16;
typedef UInt8 Bool8;
typedef unsigned long FourCharCode;
typedef FourCharCode OSType;
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#define kSInt16_Max USHRT_MAX
#define kUInt16_Max USHRT_MAX
#define kSInt32_Max LONG_MAX
#define kUInt32_Max ULONG_MAX
#undef kSInt64_Max
#define kSInt64_Max 9223372036854775807i64
#undef kUInt64_Max
#define kUInt64_Max (kSInt64_Max * 2ULL + 1)
#elif __sgi__
/* Defines */
#define _64BITARG_ "ll"
#define _S64BITARG_ "lld"
#define _U64BITARG_ "llu"
#if __LP64__
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#else
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#endif
/* paths */
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
#define kEOLString "\n"
/* Includes */
#include <sys/types.h>
#include <netinet/in.h>
#include <pthread.h>
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
/* Typedefs */
typedef unsigned char boolean;
#define true 1
#define false 0
typedef signed long PointerSizedInt;
typedef unsigned long PointerSizedUInt;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned long UInt32;
typedef signed long SInt32;
typedef signed long long SInt64;
typedef unsigned long long UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt16 Bool16;
typedef unsigned long FourCharCode;
typedef FourCharCode OSType;
/* Nulled-out new() for use without memory debugging */
/* #define NEW(t,c,v) new c v
#define NEW_ARRAY(t,c,n) new c[n] */
#define thread_t pthread_t
#define cthread_errno() errno
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#elif defined(sun) // && defined(sparc)
/* Defines */
#define _64BITARG_ "ll"
#define _S64BITARG_ "Ild"
#define _U64BITARG_ "llu"
#if __LP64__
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#else
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#endif
/* paths */
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
#define kEOLString "\n"
/* Includes */
#include <sys/types.h>
#include <sys/byteorder.h>
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
/* Typedefs */
//typedef unsigned char Bool16;
//#define true 1
//#define false 0
typedef signed long PointerSizedInt;
typedef unsigned long PointerSizedUInt;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned long UInt32;
typedef signed long SInt32;
typedef signed long long SInt64;
typedef unsigned long long UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt16 Bool16;
typedef UInt8 Bool8;
typedef unsigned long FourCharCode;
typedef FourCharCode OSType;
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#elif defined(__hpux__)
/* Defines */
#define _64BITARG_ "ll"
#define _S64BITARG_ "Ild"
#define _U64BITARG_ "llu"
#if __LP64__
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#else
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#endif
/* paths */
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
#define kEOLString "\n"
/* Includes */
#include <sys/types.h>
#include <sys/byteorder.h>
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
/* Typedefs */
//typedef unsigned char Bool16;
//#define true 1
//#define false 0
typedef signed long PointerSizedInt;
typedef unsigned long PointerSizedUInt;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned long UInt32;
typedef signed long SInt32;
typedef signed long long SInt64;
typedef unsigned long long UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt16 Bool16;
typedef UInt8 Bool8;
typedef unsigned long FourCharCode;
typedef FourCharCode OSType;
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#elif defined(__osf__)
/* Defines */
#define _64BITARG_ "l"
#define _S64BITARG_ "ld"
#define _U64BITARG_ "lu"
#if __LP64__
#define _S32BITARG_ "ld"
#define _U32BITARG_ "lu"
#else
#define _S32BITARG_ "d"
#define _U32BITARG_ "u"
#endif
/* paths */
#define kEOLString "\n"
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
/* Includes */
#include <sys/types.h>
#include <machine/endian.h>
/* Constants */
#define QT_TIME_TO_LOCAL_TIME (-2082844800)
#define QT_PATH_SEPARATOR '/'
/* Typedefs */
typedef unsigned long PointerSizedInt;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned int UInt32;
typedef signed int SInt32;
typedef signed long SInt64;
typedef unsigned long UInt64;
typedef float Float32;
typedef double Float64;
typedef UInt16 Bool16;
typedef UInt8 Bool8;
typedef unsigned int FourCharCode;
typedef FourCharCode OSType;
#ifdef FOUR_CHARS_TO_INT
#error Conflicting Macro "FOUR_CHARS_TO_INT"
#endif
#define FOUR_CHARS_TO_INT( c1, c2, c3, c4 ) ( c1 << 24 | c2 << 16 | c3 << 8 | c4 )
#ifdef TW0_CHARS_TO_INT
#error Conflicting Macro "TW0_CHARS_TO_INT"
#endif
#define TW0_CHARS_TO_INT( c1, c2 ) ( c1 << 8 | c2 )
#endif
typedef SInt32 OS_Error;
enum
{
OS_NoErr = (OS_Error) 0,
OS_BadURLFormat = (OS_Error) -100,
OS_NotEnoughSpace = (OS_Error) -101
};
#include "../PlatformHeader.h"
#endif /* OSHeaders_H */

View file

@ -0,0 +1,421 @@
/*
*
* @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: OSHeap.cpp
Contains: Implements a heap
*/
#include <string.h>
#include "OSHeap.h"
#include "OSMemory.h"
OSHeap::OSHeap(UInt32 inStartSize)
: fFreeIndex(1)
{
if (inStartSize < 2)
fArraySize = 2;
else
fArraySize = inStartSize;
fHeap = NEW OSHeapElem*[fArraySize];
}
void OSHeap::Insert(OSHeapElem* inElem)
{
Assert(inElem != NULL);
if ((fHeap == NULL) || (fFreeIndex == fArraySize))
{
fArraySize *= 2;
OSHeapElem** tempArray = NEW OSHeapElem*[fArraySize];
if ((fHeap != NULL) && (fFreeIndex > 1))
memcpy(tempArray, fHeap, sizeof(OSHeapElem*) * fFreeIndex);
delete [] fHeap;
fHeap = tempArray;
}
Assert(fHeap != NULL);
Assert(inElem->fCurrentHeap == NULL);
Assert(fArraySize > fFreeIndex);
#if _OSHEAP_TESTING_
SanityCheck(1);
#endif
//insert the element into the last leaf of the tree
fHeap[fFreeIndex] = inElem;
//bubble the new element up to its proper place in the heap
//start at the last leaf of the tree
UInt32 swapPos = fFreeIndex;
while (swapPos > 1)
{
//move up the chain until we get to the root, bubbling this new element
//to its proper place in the tree
UInt32 nextSwapPos = swapPos >> 1;
//if this child is greater than it's parent, we need to do the old
//switcheroo
if (fHeap[swapPos]->fValue < fHeap[nextSwapPos]->fValue)
{
OSHeapElem* temp = fHeap[swapPos];
fHeap[swapPos] = fHeap[nextSwapPos];
fHeap[nextSwapPos] = temp;
swapPos = nextSwapPos;
}
else
//if not, we are done!
break;
}
inElem->fCurrentHeap = this;
fFreeIndex++;
}
OSHeapElem* OSHeap::Extract(UInt32 inIndex)
{
if ((fHeap == NULL) || (fFreeIndex <= inIndex))
return NULL;
#if _OSHEAP_TESTING_
SanityCheck(1);
#endif
//store a reference to the element we want to extract
OSHeapElem* victim = fHeap[inIndex];
Assert(victim->fCurrentHeap == this);
victim->fCurrentHeap = NULL;
//but now we need to preserve this heuristic. We do this by taking
//the last leaf, putting it at the empty position, then heapifying that chain
fHeap[inIndex] = fHeap[fFreeIndex - 1];
fFreeIndex--;
//The following is an implementation of the Heapify algorithm (CLR 7.1 pp 143)
//The gist is that this new item at the top of the heap needs to be bubbled down
//until it is bigger than its two children, therefore maintaining the heap property.
UInt32 parent = inIndex;
while (parent < fFreeIndex)
{
//which is bigger? parent or left child?
UInt32 greatest = parent;
UInt32 leftChild = parent * 2;
if ((leftChild < fFreeIndex) && (fHeap[leftChild]->fValue < fHeap[parent]->fValue))
greatest = leftChild;
//which is bigger? the biggest so far or the right child?
UInt32 rightChild = (parent * 2) + 1;
if ((rightChild < fFreeIndex) && (fHeap[rightChild]->fValue < fHeap[greatest]->fValue))
greatest = rightChild;
//if the parent is in fact bigger than its two children, we have bubbled
//this element down far enough
if (greatest == parent)
break;
//parent is not bigger than at least one of its two children, so swap the parent
//with the largest item.
OSHeapElem* temp = fHeap[parent];
fHeap[parent] = fHeap[greatest];
fHeap[greatest] = temp;
//now heapify the remaining chain
parent = greatest;
}
return victim;
}
OSHeapElem* OSHeap::Remove(OSHeapElem* elem)
{
if ((fHeap == NULL) || (fFreeIndex == 1))
return NULL;
#if _OSHEAP_TESTING_
SanityCheck(1);
#endif
//first attempt to locate this element in the heap
UInt32 theIndex = 1;
for ( ; theIndex < fFreeIndex; theIndex++)
if (elem == fHeap[theIndex])
break;
//either we've found it, or this is a bogus element
if (theIndex == fFreeIndex)
return NULL;
return Extract(theIndex);
}
#if _OSHEAP_TESTING_
void OSHeap::SanityCheck(UInt32 root)
{
//make sure root is greater than both its children. Do so recursively
if (root < fFreeIndex)
{
if ((root * 2) < fFreeIndex)
{
Assert(fHeap[root]->fValue <= fHeap[root * 2]->fValue);
SanityCheck(root * 2);
}
if (((root * 2) + 1) < fFreeIndex)
{
Assert(fHeap[root]->fValue <= fHeap[(root * 2) + 1]->fValue);
SanityCheck((root * 2) + 1);
}
}
}
Bool16 OSHeap::Test()
{
OSHeap victim(2);
OSHeapElem elem1;
OSHeapElem elem2;
OSHeapElem elem3;
OSHeapElem elem4;
OSHeapElem elem5;
OSHeapElem elem6;
OSHeapElem elem7;
OSHeapElem elem8;
OSHeapElem elem9;
OSHeapElem* max = victim.ExtractMin();
if (max != NULL)
return false;
elem1.SetValue(100);
victim.Insert(&elem1);
max = victim.ExtractMin();
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != NULL)
return false;
elem1.SetValue(100);
elem2.SetValue(80);
victim.Insert(&elem1);
victim.Insert(&elem2);
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != NULL)
return false;
victim.Insert(&elem2);
victim.Insert(&elem1);
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
elem3.SetValue(70);
elem4.SetValue(60);
victim.Insert(&elem3);
victim.Insert(&elem1);
victim.Insert(&elem2);
victim.Insert(&elem4);
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.ExtractMin();
if (max != &elem3)
return false;
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
elem5.SetValue(50);
elem6.SetValue(40);
elem7.SetValue(30);
elem8.SetValue(20);
elem9.SetValue(10);
victim.Insert(&elem5);
victim.Insert(&elem3);
victim.Insert(&elem1);
max = victim.ExtractMin();
if (max != &elem5)
return false;
victim.Insert(&elem4);
victim.Insert(&elem2);
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.ExtractMin();
if (max != &elem3)
return false;
victim.Insert(&elem2);
max = victim.ExtractMin();
if (max != &elem2)
return false;
victim.Insert(&elem2);
victim.Insert(&elem6);
max = victim.ExtractMin();
if (max != &elem6)
return false;
victim.Insert(&elem6);
victim.Insert(&elem3);
victim.Insert(&elem4);
victim.Insert(&elem5);
max = victim.ExtractMin();
if (max != &elem6)
return false;
max = victim.ExtractMin();
if (max != &elem5)
return false;
victim.Insert(&elem8);
max = victim.ExtractMin();
if (max != &elem8)
return false;
max = victim.ExtractMin();
if (max != &elem4)
return false;
victim.Insert(&elem5);
victim.Insert(&elem4);
victim.Insert(&elem9);
victim.Insert(&elem7);
victim.Insert(&elem8);
victim.Insert(&elem6);
max = victim.ExtractMin();
if (max != &elem9)
return false;
max = victim.ExtractMin();
if (max != &elem8)
return false;
max = victim.ExtractMin();
if (max != &elem7)
return false;
max = victim.ExtractMin();
if (max != &elem6)
return false;
max = victim.ExtractMin();
if (max != &elem5)
return false;
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.ExtractMin();
if (max != &elem3)
return false;
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != NULL)
return false;
victim.Insert(&elem1);
victim.Insert(&elem2);
victim.Insert(&elem3);
victim.Insert(&elem4);
victim.Insert(&elem5);
victim.Insert(&elem6);
victim.Insert(&elem7);
victim.Insert(&elem8);
victim.Insert(&elem9);
max = victim.Remove(&elem7);
if (max != &elem7)
return false;
max = victim.Remove(&elem9);
if (max != &elem9)
return false;
max = victim.ExtractMin();
if (max != &elem8)
return false;
max = victim.Remove(&elem2);
if (max != &elem2)
return false;
max = victim.Remove(&elem2);
if (max != NULL)
return false;
max = victim.Remove(&elem8);
if (max != NULL)
return false;
max = victim.Remove(&elem5);
if (max != &elem5)
return false;
max = victim.Remove(&elem6);
if (max != &elem6)
return false;
max = victim.Remove(&elem1);
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.Remove(&elem1);
if (max != NULL)
return false;
return true;
}
#endif

112
CommonUtilitiesLib/OSHeap.h Normal file
View file

@ -0,0 +1,112 @@
/*
*
* @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: OSHeap.h
Contains: Implements a heap
*/
#ifndef _OSHEAP_H_
#define _OSHEAP_H_
#define _OSHEAP_TESTING_ 0
#include "OSCond.h"
class OSHeapElem;
class OSHeap
{
public:
enum
{
kDefaultStartSize = 1024 //UInt32
};
OSHeap(UInt32 inStartSize = kDefaultStartSize);
~OSHeap() { if (fHeap != NULL) delete fHeap; }
//ACCESSORS
UInt32 CurrentHeapSize() { return fFreeIndex - 1; }
OSHeapElem* PeekMin() { if (CurrentHeapSize() > 0) return fHeap[1]; return NULL; }
//MODIFIERS
//These are the two primary operations supported by the heap
//abstract data type. both run in log(n) time.
void Insert(OSHeapElem* inElem);
OSHeapElem* ExtractMin() { return Extract(1); }
//removes specified element from the heap
OSHeapElem* Remove(OSHeapElem* elem);
#if _OSHEAP_TESTING_
//returns true if it passed the test, false otherwise
static Bool16 Test();
#endif
private:
OSHeapElem* Extract(UInt32 index);
#if _OSHEAP_TESTING_
//verifies that the heap is in fact a heap
void SanityCheck(UInt32 root);
#endif
OSHeapElem** fHeap;
UInt32 fFreeIndex;
UInt32 fArraySize;
};
class OSHeapElem
{
public:
OSHeapElem(void* enclosingObject = NULL)
: fValue(0), fEnclosingObject(enclosingObject), fCurrentHeap(NULL) {}
~OSHeapElem() {}
//This data structure emphasizes performance over extensibility
//If it were properly object-oriented, the compare routine would
//be virtual. However, to avoid the use of v-functions in this data
//structure, I am assuming that the objects are compared using a 64 bit number.
//
void SetValue(SInt64 newValue) { fValue = newValue; }
SInt64 GetValue() { return fValue; }
void* GetEnclosingObject() { return fEnclosingObject; }
void SetEnclosingObject(void* obj) { fEnclosingObject = obj; }
Bool16 IsMemberOfAnyHeap() { return fCurrentHeap != NULL; }
private:
SInt64 fValue;
void* fEnclosingObject;
OSHeap* fCurrentHeap;
friend class OSHeap;
};
#endif //_OSHEAP_H_

View file

@ -0,0 +1,146 @@
/*
*
* @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: OSMemory.h
Contains: Prototypes for overridden new & delete, definition of OSMemory
class which implements some memory leak debugging features.
*/
#ifndef __OS_MEMORY_H__
#define __OS_MEMORY_H__
#include "OSHeaders.h"
#include "OSQueue.h"
#include "OSMutex.h"
class OSMemory
{
public:
#if MEMORY_DEBUGGING
//If memory debugging is on, clients can get access to data structures that give
//memory status.
static OSQueue* GetTagQueue() { return &sTagQueue; }
static OSMutex* GetTagQueueMutex() { return &sMutex; }
static UInt32 GetAllocatedMemory() { return sAllocatedBytes; }
static void* DebugNew(size_t size, char* inFile, int inLine, Bool16 sizeCheck);
static void DebugDelete(void *mem);
static Bool16 MemoryDebuggingTest();
static void ValidateMemoryQueue();
enum
{
kMaxFileNameSize = 48
};
struct TagElem
{
OSQueueElem elem;
char fileName[kMaxFileNameSize];
int line;
UInt32 tagSize; //how big are objects of this type?
UInt32 totMemory; //how much do they currently occupy
UInt32 numObjects;//how many are there currently?
};
#endif
// Provides non-debugging behaviour for new and delete
static void* New(size_t inSize);
static void Delete(void* inMemory);
//When memory allocation fails, the server just exits. This sets the code
//the server exits with
static void SetMemoryError(SInt32 inErr);
#if MEMORY_DEBUGGING
private:
struct MemoryDebugging
{
OSQueueElem elem;
TagElem* tagElem;
UInt32 size;
};
static OSQueue sMemoryQueue;
static OSQueue sTagQueue;
static UInt32 sAllocatedBytes;
static OSMutex sMutex;
#endif
};
// NEW MACRO
// When memory debugging is on, this macro transparently uses the memory debugging
// overridden version of the new operator. When memory debugging is off, it just compiles
// down to the standard new.
#if MEMORY_DEBUGGING
#ifdef NEW
#error Conflicting Macro "NEW"
#endif
#define NEW new (__FILE__, __LINE__)
#else
#ifdef NEW
#error Conflicting Macro "NEW"
#endif
#define NEW new
#endif
//
// PLACEMENT NEW OPERATOR
inline void* operator new(size_t, void* ptr) { return ptr;}
#if MEMORY_DEBUGGING
// These versions of the new operator with extra arguments provide memory debugging
// features.
void* operator new(size_t s, char* inFile, int inLine);
void* operator new[](size_t s, char* inFile, int inLine);
#endif
// When memory debugging is not on, these are overridden so that if new fails,
// the process will exit.
void* operator new (size_t s);
void* operator new[](size_t s);
void operator delete(void* mem);
void operator delete[](void* mem);
#endif //__OS_MEMORY_H__

View file

@ -0,0 +1,158 @@
/*
*
* @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: OSMutex.cpp
Contains: Platform - independent mutex header. The implementation of this object
is platform - specific. Each platform must define an independent
QTSSMutex.h & QTSSMutex.cpp file.
This file is for Mac OS X Server only
*/
#include "OSMutex.h"
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
// Private globals
#if __PTHREADS_MUTEXES__
static pthread_mutexattr_t *sMutexAttr=NULL;
static void MutexAttrInit();
#if __solaris__
static pthread_once_t sMutexAttrInit = {PTHREAD_ONCE_INIT};
#else
static pthread_once_t sMutexAttrInit = PTHREAD_ONCE_INIT;
#endif
#endif
OSMutex::OSMutex()
{
#ifdef __Win32__
::InitializeCriticalSection(&fMutex);
fHolder = 0;
fHolderCount = 0;
#elif __PTHREADS_MUTEXES__
(void)pthread_once(&sMutexAttrInit, MutexAttrInit);
(void)pthread_mutex_init(&fMutex, sMutexAttr);
fHolder = 0;
fHolderCount = 0;
#else
fMutex = mymutex_alloc();
#endif
}
#if __PTHREADS_MUTEXES__
void MutexAttrInit()
{
sMutexAttr = (pthread_mutexattr_t*)malloc(sizeof(pthread_mutexattr_t));
::memset(sMutexAttr, 0, sizeof(pthread_mutexattr_t));
pthread_mutexattr_init(sMutexAttr);
}
#endif
OSMutex::~OSMutex()
{
#ifdef __Win32__
::DeleteCriticalSection(&fMutex);
#elif __PTHREADS_MUTEXES__
pthread_mutex_destroy(&fMutex);
#else
mymutex_free(fMutex);
#endif
}
#if __PTHREADS_MUTEXES__ || __Win32__
void OSMutex::RecursiveLock()
{
// We already have this mutex. Just refcount and return
if (OSThread::GetCurrentThreadID() == fHolder)
{
fHolderCount++;
return;
}
#ifdef __Win32__
::EnterCriticalSection(&fMutex);
#else
(void)pthread_mutex_lock(&fMutex);
#endif
Assert(fHolder == 0);
fHolder = OSThread::GetCurrentThreadID();
fHolderCount++;
Assert(fHolderCount == 1);
}
void OSMutex::RecursiveUnlock()
{
if (OSThread::GetCurrentThreadID() != fHolder)
return;
Assert(fHolderCount > 0);
fHolderCount--;
if (fHolderCount == 0)
{
fHolder = 0;
#ifdef __Win32__
::LeaveCriticalSection(&fMutex);
#else
pthread_mutex_unlock(&fMutex);
#endif
}
}
Bool16 OSMutex::RecursiveTryLock()
{
// We already have this mutex. Just refcount and return
if (OSThread::GetCurrentThreadID() == fHolder)
{
fHolderCount++;
return true;
}
#ifdef __Win32__
Bool16 theErr = (Bool16)::TryEnterCriticalSection(&fMutex); // Return values of this function match our API
if (!theErr)
return theErr;
#else
int theErr = pthread_mutex_trylock(&fMutex);
if (theErr != 0)
{
Assert(theErr == EBUSY);
return false;
}
#endif
Assert(fHolder == 0);
fHolder = OSThread::GetCurrentThreadID();
fHolderCount++;
Assert(fHolderCount == 1);
return true;
}
#endif //__PTHREADS_MUTEXES__ || __Win32__

View file

@ -0,0 +1,147 @@
/*
*
* @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: OSMutex.h
Contains: Platform - independent mutex header. The implementation of this object
is platform - specific. Each platform must define an independent
OSMutex.h & OSMutex.cpp file.
This file is for Mac OS X Server only
*/
#ifndef _OSMUTEX_H_
#define _OSMUTEX_H_
#include <stdlib.h>
#include "SafeStdLib.h"
#ifndef __Win32__
#include <sys/errno.h>
#if __PTHREADS_MUTEXES__
#if __MacOSX__
#ifndef _POSIX_PTHREAD_H
#include <pthread.h>
#endif
#else
#include <pthread.h>
#endif
#include <unistd.h>
#else
#include "mymutex.h"
#endif
#endif
#include "OSHeaders.h"
#include "OSThread.h"
#include "MyAssert.h"
class OSCond;
class OSMutex
{
public:
OSMutex();
~OSMutex();
inline void Lock();
inline void Unlock();
// Returns true on successful grab of the lock, false on failure
inline Bool16 TryLock();
private:
#ifdef __Win32__
CRITICAL_SECTION fMutex;
DWORD fHolder;
UInt32 fHolderCount;
#elif !__PTHREADS_MUTEXES__
mymutex_t fMutex;
#else
pthread_mutex_t fMutex;
// These two platforms don't implement pthreads recursive mutexes, so
// we have to do it manually
pthread_t fHolder;
UInt32 fHolderCount;
#endif
#if __PTHREADS_MUTEXES__ || __Win32__
void RecursiveLock();
void RecursiveUnlock();
Bool16 RecursiveTryLock();
#endif
friend class OSCond;
};
class OSMutexLocker
{
public:
OSMutexLocker(OSMutex *inMutexP) : fMutex(inMutexP) { if (fMutex != NULL) fMutex->Lock(); }
~OSMutexLocker() { if (fMutex != NULL) fMutex->Unlock(); }
void Lock() { if (fMutex != NULL) fMutex->Lock(); }
void Unlock() { if (fMutex != NULL) fMutex->Unlock(); }
private:
OSMutex* fMutex;
};
void OSMutex::Lock()
{
#if __PTHREADS_MUTEXES__ || __Win32__
this->RecursiveLock();
#else
mymutex_lock(fMutex);
#endif //!__PTHREADS__
}
void OSMutex::Unlock()
{
#if __PTHREADS_MUTEXES__ || __Win32__
this->RecursiveUnlock();
#else
mymutex_unlock(fMutex);
#endif //!__PTHREADS__
}
Bool16 OSMutex::TryLock()
{
#if __PTHREADS_MUTEXES__ || __Win32__
return this->RecursiveTryLock();
#else
return (Bool16)mymutex_try_lock(fMutex);
#endif //!__PTHREADS__
}
#endif //_OSMUTEX_H_

View file

@ -0,0 +1,182 @@
/*
*
* @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: OSMutex.cpp
Contains:
*/
#include "OSMutexRW.h"
#include "OSMutex.h"
#include "OSCond.h"
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#if DEBUGMUTEXRW
int OSMutexRW::fCount = 0;
int OSMutexRW::fMaxCount =0;
#endif
#if DEBUGMUTEXRW
void OSMutexRW::CountConflict(int i)
{
fCount += i;
if (i == -1) qtss_printf("Num Conflicts: %d\n", fMaxCount);
if (fCount > fMaxCount)
fMaxCount = fCount;
}
#endif
void OSMutexRW::LockRead()
{
OSMutexLocker locker(&fInternalLock);
#if DEBUGMUTEXRW
if (fState != 0)
{ qtss_printf("LockRead(conflict) fState = %d active readers = %d, waiting writers = %d, waiting readers=%d\n",fState, fActiveReaders, fWriteWaiters, fReadWaiters);
CountConflict(1);
}
#endif
AddReadWaiter();
while ( ActiveWriter() // active writer so wait
|| WaitingWriters() // reader must wait for write waiters
)
{
fReadersCond.Wait(&fInternalLock,OSMutexRW::eMaxWait);
}
RemoveReadWaiter();
AddActiveReader(); // add 1 to active readers
fActiveReaders = fState;
#if DEBUGMUTEXRW
// qtss_printf("LockRead(conflict) fState = %d active readers = %d, waiting writers = %d, waiting readers=%d\n",fState, fActiveReaders, fWriteWaiters, fReadWaiters);
#endif
}
void OSMutexRW::LockWrite()
{
OSMutexLocker locker(&fInternalLock);
AddWriteWaiter(); // 1 writer queued
#if DEBUGMUTEXRW
if (Active())
{ qtss_printf("LockWrite(conflict) state = %d active readers = %d, waiting writers = %d, waiting readers=%d\n", fState, fActiveReaders, fWriteWaiters, fReadWaiters);
CountConflict(1);
}
qtss_printf("LockWrite 'waiting' fState = %d locked active readers = %d, waiting writers = %d, waiting readers=%d\n",fState, fActiveReaders, fReadWaiters, fWriteWaiters);
#endif
while (ActiveReaders()) // active readers
{
fWritersCond.Wait(&fInternalLock,OSMutexRW::eMaxWait);
}
RemoveWriteWaiter(); // remove from waiting writers
SetState(OSMutexRW::eActiveWriterState); // this is the active writer
fActiveReaders = fState;
#if DEBUGMUTEXRW
// qtss_printf("LockWrite 'locked' fState = %d locked active readers = %d, waiting writers = %d, waiting readers=%d\n",fState, fActiveReaders, fReadWaiters, fWriteWaiters);
#endif
}
void OSMutexRW::Unlock()
{
OSMutexLocker locker(&fInternalLock);
#if DEBUGMUTEXRW
// qtss_printf("Unlock active readers = %d, waiting writers = %d, waiting readers=%d\n", fActiveReaders, fReadWaiters, fWriteWaiters);
#endif
if (ActiveWriter())
{
SetState(OSMutexRW::eNoWriterState); // this was the active writer
if (WaitingWriters()) // there are waiting writers
{ fWritersCond.Signal();
}
else
{ fReadersCond.Broadcast();
}
#if DEBUGMUTEXRW
qtss_printf("Unlock(writer) active readers = %d, waiting writers = %d, waiting readers=%d\n", fActiveReaders, fReadWaiters, fWriteWaiters);
#endif
}
else
{
RemoveActiveReader(); // this was a reader
if (!ActiveReaders()) // no active readers
{ SetState(OSMutexRW::eNoWriterState); // this was the active writer now no actives threads
fWritersCond.Signal();
}
}
fActiveReaders = fState;
}
// Returns true on successful grab of the lock, false on failure
int OSMutexRW::TryLockWrite()
{
int status = EBUSY;
OSMutexLocker locker(&fInternalLock);
if ( !Active() && !WaitingWriters()) // no writers, no readers, no waiting writers
{
this->LockWrite();
status = 0;
}
return status;
}
int OSMutexRW::TryLockRead()
{
int status = EBUSY;
OSMutexLocker locker(&fInternalLock);
if ( !ActiveWriter() && !WaitingWriters() ) // no current writers but other readers ok
{
this->LockRead();
status = 0;
}
return status;
}

View file

@ -0,0 +1,135 @@
/*
*
* @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: OSMutexRW.h
Contains:
*/
#ifndef _OSMUTEXRW_H_
#define _OSMUTEXRW_H_
#include <stdlib.h>
#include "SafeStdLib.h"
#include "OSHeaders.h"
#include "OSThread.h"
#include "MyAssert.h"
#include "OSMutex.h"
#include "OSQueue.h"
#define DEBUGMUTEXRW 0
class OSMutexRW
{
public:
OSMutexRW(): fState(0), fWriteWaiters(0),fReadWaiters(0),fActiveReaders(0) {} ;
void LockRead();
void LockWrite();
void Unlock();
// Returns 0 on success, EBUSY on failure
int TryLockWrite();
int TryLockRead();
private:
enum {eMaxWait = 0x0FFFFFFF, eMultiThreadCondition = true, };
enum {eActiveWriterState = -1, eNoWriterState = 0 };
OSMutex fInternalLock; // the internal lock
OSCond fReadersCond; // the waiting readers
OSCond fWritersCond; // the waiting writers
int fState; // -1:writer,0:free,>0:readers
int fWriteWaiters; // number of waiting writers
int fReadWaiters; // number of waiting readers
int fActiveReaders; // number of active readers = fState >= 0;
inline void AdjustState(int i) { fState += i; };
inline void AdjustWriteWaiters(int i) { fWriteWaiters += i; };
inline void AdjustReadWaiters(int i) { fReadWaiters += i; };
inline void SetState(int i) { fState = i; };
inline void SetWriteWaiters(int i) { fWriteWaiters = i; };
inline void SetReadWaiters(int i) { fReadWaiters = i; };
inline void AddWriteWaiter() { AdjustWriteWaiters(1); };
inline void RemoveWriteWaiter() { AdjustWriteWaiters(-1); };
inline void AddReadWaiter() { AdjustReadWaiters(1); };
inline void RemoveReadWaiter() { AdjustReadWaiters(-1); };
inline void AddActiveReader() { AdjustState(1); };
inline void RemoveActiveReader() { AdjustState(-1); };
inline Bool16 WaitingWriters() {return (Bool16) (fWriteWaiters > 0) ; }
inline Bool16 WaitingReaders() {return (Bool16) (fReadWaiters > 0) ;}
inline Bool16 Active() {return (Bool16) (fState != 0) ;}
inline Bool16 ActiveReaders() {return (Bool16) (fState > 0) ;}
inline Bool16 ActiveWriter() {return (Bool16) (fState < 0) ;} // only one
#if DEBUGMUTEXRW
static int fCount, fMaxCount;
static OSMutex sCountMutex;
void CountConflict(int i);
#endif
};
class OSMutexReadWriteLocker
{
public:
OSMutexReadWriteLocker(OSMutexRW *inMutexPtr): fRWMutexPtr(inMutexPtr) {};
~OSMutexReadWriteLocker() { if (fRWMutexPtr != NULL) fRWMutexPtr->Unlock(); }
void UnLock() { if (fRWMutexPtr != NULL) fRWMutexPtr->Unlock(); }
void SetMutex(OSMutexRW *mutexPtr) {fRWMutexPtr = mutexPtr;}
OSMutexRW* fRWMutexPtr;
};
class OSMutexReadLocker: public OSMutexReadWriteLocker
{
public:
OSMutexReadLocker(OSMutexRW *inMutexPtr) : OSMutexReadWriteLocker(inMutexPtr) { if (OSMutexReadWriteLocker::fRWMutexPtr != NULL) OSMutexReadWriteLocker::fRWMutexPtr->LockRead(); }
void Lock() { if (OSMutexReadWriteLocker::fRWMutexPtr != NULL) OSMutexReadWriteLocker::fRWMutexPtr->LockRead(); }
};
class OSMutexWriteLocker: public OSMutexReadWriteLocker
{
public:
OSMutexWriteLocker(OSMutexRW *inMutexPtr) : OSMutexReadWriteLocker(inMutexPtr) { if (OSMutexReadWriteLocker::fRWMutexPtr != NULL) OSMutexReadWriteLocker::fRWMutexPtr->LockWrite(); }
void Lock() { if (OSMutexReadWriteLocker::fRWMutexPtr != NULL) OSMutexReadWriteLocker::fRWMutexPtr->LockWrite(); }
};
#endif //_OSMUTEX_H_

View file

@ -0,0 +1,262 @@
/*
*
* @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: OSQueue.cpp
Contains: implements OSQueue class
*/
#include "OSQueue.h"
OSQueue::OSQueue() : fLength(0)
{
fSentinel.fNext = &fSentinel;
fSentinel.fPrev = &fSentinel;
}
void OSQueue::EnQueue(OSQueueElem* elem)
{
Assert(elem != NULL);
if (elem->fQueue == this)
return;
Assert(elem->fQueue == NULL);
elem->fNext = fSentinel.fNext;
elem->fPrev = &fSentinel;
elem->fQueue = this;
fSentinel.fNext->fPrev = elem;
fSentinel.fNext = elem;
fLength++;
}
OSQueueElem* OSQueue::DeQueue()
{
if (fLength > 0)
{
OSQueueElem* elem = fSentinel.fPrev;
Assert(fSentinel.fPrev != &fSentinel);
elem->fPrev->fNext = &fSentinel;
fSentinel.fPrev = elem->fPrev;
elem->fQueue = NULL;
fLength--;
return elem;
}
else
return NULL;
}
void OSQueue::Remove(OSQueueElem* elem)
{
Assert(elem != NULL);
Assert(elem != &fSentinel);
if (elem->fQueue == this)
{
elem->fNext->fPrev = elem->fPrev;
elem->fPrev->fNext = elem->fNext;
elem->fQueue = NULL;
fLength--;
}
}
#if OSQUEUETESTING
Bool16 OSQueue::Test()
{
OSQueue theVictim;
void *x = (void*)1;
OSQueueElem theElem1(x);
x = (void*)2;
OSQueueElem theElem2(x);
x = (void*)3;
OSQueueElem theElem3(x);
if (theVictim.GetHead() != NULL)
return false;
if (theVictim.GetTail() != NULL)
return false;
theVictim.EnQueue(&theElem1);
if (theVictim.GetHead() != &theElem1)
return false;
if (theVictim.GetTail() != &theElem1)
return false;
OSQueueElem* theElem = theVictim.DeQueue();
if (theElem != &theElem1)
return false;
if (theVictim.GetHead() != NULL)
return false;
if (theVictim.GetTail() != NULL)
return false;
theVictim.EnQueue(&theElem1);
theVictim.EnQueue(&theElem2);
if (theVictim.GetHead() != &theElem1)
return false;
if (theVictim.GetTail() != &theElem2)
return false;
theElem = theVictim.DeQueue();
if (theElem != &theElem1)
return false;
if (theVictim.GetHead() != &theElem2)
return false;
if (theVictim.GetTail() != &theElem2)
return false;
theElem = theVictim.DeQueue();
if (theElem != &theElem2)
return false;
theVictim.EnQueue(&theElem1);
theVictim.EnQueue(&theElem2);
theVictim.EnQueue(&theElem3);
if (theVictim.GetHead() != &theElem1)
return false;
if (theVictim.GetTail() != &theElem3)
return false;
theElem = theVictim.DeQueue();
if (theElem != &theElem1)
return false;
if (theVictim.GetHead() != &theElem2)
return false;
if (theVictim.GetTail() != &theElem3)
return false;
theElem = theVictim.DeQueue();
if (theElem != &theElem2)
return false;
if (theVictim.GetHead() != &theElem3)
return false;
if (theVictim.GetTail() != &theElem3)
return false;
theElem = theVictim.DeQueue();
if (theElem != &theElem3)
return false;
theVictim.EnQueue(&theElem1);
theVictim.EnQueue(&theElem2);
theVictim.EnQueue(&theElem3);
OSQueueIter theIterVictim(&theVictim);
if (theIterVictim.IsDone())
return false;
if (theIterVictim.GetCurrent() != &theElem3)
return false;
theIterVictim.Next();
if (theIterVictim.IsDone())
return false;
if (theIterVictim.GetCurrent() != &theElem2)
return false;
theIterVictim.Next();
if (theIterVictim.IsDone())
return false;
if (theIterVictim.GetCurrent() != &theElem1)
return false;
theIterVictim.Next();
if (!theIterVictim.IsDone())
return false;
if (theIterVictim.GetCurrent() != NULL)
return false;
theVictim.Remove(&theElem1);
if (theVictim.GetHead() != &theElem2)
return false;
if (theVictim.GetTail() != &theElem3)
return false;
theVictim.Remove(&theElem1);
if (theVictim.GetHead() != &theElem2)
return false;
if (theVictim.GetTail() != &theElem3)
return false;
theVictim.Remove(&theElem3);
if (theVictim.GetHead() != &theElem2)
return false;
if (theVictim.GetTail() != &theElem2)
return false;
return true;
}
#endif
void OSQueueIter::Next()
{
if (fCurrentElemP == fQueueP->GetTail())
fCurrentElemP = NULL;
else
fCurrentElemP = fCurrentElemP->Prev();
}
OSQueueElem* OSQueue_Blocking::DeQueueBlocking(OSThread* inCurThread, SInt32 inTimeoutInMilSecs)
{
OSMutexLocker theLocker(&fMutex);
#ifdef __Win32_
if (fQueue.GetLength() == 0)
{ fCond.Wait(&fMutex, inTimeoutInMilSecs);
return NULL;
}
#else
if (fQueue.GetLength() == 0)
fCond.Wait(&fMutex, inTimeoutInMilSecs);
#endif
OSQueueElem* retval = fQueue.DeQueue();
return retval;
}
OSQueueElem* OSQueue_Blocking::DeQueue()
{
OSMutexLocker theLocker(&fMutex);
OSQueueElem* retval = fQueue.DeQueue();
return retval;
}
void OSQueue_Blocking::EnQueue(OSQueueElem* obj)
{
{
OSMutexLocker theLocker(&fMutex);
fQueue.EnQueue(obj);
}
fCond.Signal();
}

View file

@ -0,0 +1,151 @@
/*
*
* @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: OSQueue.h
Contains: implements OSQueue class
*/
#ifndef _OSQUEUE_H_
#define _OSQUEUE_H_
#include "MyAssert.h"
#include "OSHeaders.h"
#include "OSMutex.h"
#include "OSCond.h"
#include "OSThread.h"
#define OSQUEUETESTING 0
class OSQueue;
class OSQueueElem {
public:
OSQueueElem(void* enclosingObject = NULL) : fNext(NULL), fPrev(NULL), fQueue(NULL),
fEnclosingObject(enclosingObject) {}
virtual ~OSQueueElem() { Assert(fQueue == NULL); }
Bool16 IsMember(const OSQueue& queue) { return (&queue == fQueue); }
Bool16 IsMemberOfAnyQueue() { return fQueue != NULL; }
void* GetEnclosingObject() { return fEnclosingObject; }
void SetEnclosingObject(void* obj) { fEnclosingObject = obj; }
OSQueueElem* Next() { return fNext; }
OSQueueElem* Prev() { return fPrev; }
OSQueue* InQueue() { return fQueue; }
inline void Remove();
private:
OSQueueElem* fNext;
OSQueueElem* fPrev;
OSQueue * fQueue;
void* fEnclosingObject;
friend class OSQueue;
};
class OSQueue {
public:
OSQueue();
~OSQueue() {}
void EnQueue(OSQueueElem* object);
OSQueueElem* DeQueue();
OSQueueElem* GetHead() { if (fLength > 0) return fSentinel.fPrev; return NULL; }
OSQueueElem* GetTail() { if (fLength > 0) return fSentinel.fNext; return NULL; }
UInt32 GetLength() { return fLength; }
void Remove(OSQueueElem* object);
#if OSQUEUETESTING
static Bool16 Test();
#endif
protected:
OSQueueElem fSentinel;
UInt32 fLength;
};
class OSQueueIter
{
public:
OSQueueIter(OSQueue* inQueue) : fQueueP(inQueue), fCurrentElemP(inQueue->GetHead()) {}
OSQueueIter(OSQueue* inQueue, OSQueueElem* startElemP ) : fQueueP(inQueue)
{
if ( startElemP )
{ Assert( startElemP->IsMember(*inQueue ) );
fCurrentElemP = startElemP;
}
else
fCurrentElemP = NULL;
}
~OSQueueIter() {}
void Reset() { fCurrentElemP = fQueueP->GetHead(); }
OSQueueElem* GetCurrent() { return fCurrentElemP; }
void Next();
Bool16 IsDone() { return fCurrentElemP == NULL; }
private:
OSQueue* fQueueP;
OSQueueElem* fCurrentElemP;
};
class OSQueue_Blocking
{
public:
OSQueue_Blocking() {}
~OSQueue_Blocking() {}
OSQueueElem* DeQueueBlocking(OSThread* inCurThread, SInt32 inTimeoutInMilSecs);
OSQueueElem* DeQueue();//will not block
void EnQueue(OSQueueElem* obj);
OSCond* GetCond() { return &fCond; }
OSQueue* GetQueue() { return &fQueue; }
private:
OSCond fCond;
OSMutex fMutex;
OSQueue fQueue;
};
void OSQueueElem::Remove()
{
if (fQueue != NULL)
fQueue->Remove(this);
}
#endif //_OSQUEUE_H_

View file

@ -0,0 +1,197 @@
/*
*
* @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: OSRef.cpp
Contains: Implementation of OSRef class.
*/
#include "OSRef.h"
#include <errno.h>
UInt32 OSRefTableUtils::HashString(StrPtrLen* inString)
{
Assert(inString != NULL);
Assert(inString->Ptr != NULL);
Assert(inString->Len > 0);
if (inString == NULL || inString->Len == 0 || inString->Ptr == NULL)
return 0;
//make sure to convert to unsigned here, as there may be binary
//data in this string
UInt8* theData = (UInt8*)inString->Ptr;
//divide by 4 and take the characters at quarter points in the string,
//use those as the basis for the hash value
UInt32 quarterLen = inString->Len >> 2;
return (inString->Len * (theData[0] + theData[quarterLen] +
theData[quarterLen * 2] + theData[quarterLen * 3] +
theData[inString->Len - 1]));
}
OS_Error OSRefTable::Register(OSRef* inRef)
{
Assert(inRef != NULL);
if (inRef == NULL)
return EPERM;
#if DEBUG
Assert(!inRef->fInATable);
#endif
Assert(inRef->fRefCount == 0);
Assert(inRef->fString.Ptr != NULL);
Assert(inRef->fString.Len != 0);
OSMutexLocker locker(&fMutex);
if (inRef->fString.Ptr == NULL || inRef->fString.Len == 0)
{ //printf("OSRefTable::Register inRef is invalid \n");
return EPERM;
}
// Check for a duplicate. In this function, if there is a duplicate,
// return an error, don't resolve the duplicate
OSRefKey key(&inRef->fString);
OSRef* duplicateRef = fTable.Map(&key);
if (duplicateRef != NULL)
return EPERM;
// There is no duplicate, so add this ref into the table
#if DEBUG
inRef->fInATable = true;
#endif
fTable.Add(inRef);
return OS_NoErr;
}
OSRef* OSRefTable::RegisterOrResolve(OSRef* inRef)
{
Assert(inRef != NULL);
#if DEBUG
Assert(!inRef->fInATable);
#endif
Assert(inRef->fRefCount == 0);
OSMutexLocker locker(&fMutex);
// Check for a duplicate. If there is one, resolve it and return it to the caller
OSRef* duplicateRef = this->Resolve(&inRef->fString);
if (duplicateRef != NULL)
return duplicateRef;
// There is no duplicate, so add this ref into the table
#if DEBUG
inRef->fInATable = true;
#endif
fTable.Add(inRef);
return NULL;
}
void OSRefTable::UnRegister(OSRef* ref, UInt32 refCount)
{
Assert(ref != NULL);
OSMutexLocker locker(&fMutex);
//make sure that no one else is using the object
while (ref->fRefCount > refCount)
ref->fCond.Wait(&fMutex);
#if DEBUG
OSRefKey key(&ref->fString);
if (ref->fInATable)
Assert(fTable.Map(&key) != NULL);
ref->fInATable = false;
#endif
//ok, we now definitely have no one else using this object, so
//remove it from the table
fTable.Remove(ref);
}
Bool16 OSRefTable::TryUnRegister(OSRef* ref, UInt32 refCount)
{
OSMutexLocker locker(&fMutex);
if (ref->fRefCount > refCount)
return false;
// At this point, this is guarenteed not to block, because
// we've already checked that the refCount is low.
this->UnRegister(ref, refCount);
return true;
}
OSRef* OSRefTable::Resolve(StrPtrLen* inUniqueID)
{
Assert(inUniqueID != NULL);
OSRefKey key(inUniqueID);
//this must be done atomically wrt the table
OSMutexLocker locker(&fMutex);
OSRef* ref = fTable.Map(&key);
if (ref != NULL)
{
ref->fRefCount++;
Assert(ref->fRefCount > 0);
}
return ref;
}
void OSRefTable::Release(OSRef* ref)
{
Assert(ref != NULL);
OSMutexLocker locker(&fMutex);
ref->fRefCount--;
// fRefCount is a UInt32 and QTSS should never run into
// a ref greater than 16 * 64K, so this assert just checks to
// be sure that we have not decremented the ref less than zero.
Assert( ref->fRefCount < 1048576L );
//make sure to wakeup anyone who may be waiting for this resource to be released
ref->fCond.Signal();
}
void OSRefTable::Swap(OSRef* newRef)
{
Assert(newRef != NULL);
OSMutexLocker locker(&fMutex);
OSRefKey key(&newRef->fString);
OSRef* oldRef = fTable.Map(&key);
if (oldRef != NULL)
{
fTable.Remove(oldRef);
fTable.Add(newRef);
#if DEBUG
newRef->fInATable = true;
oldRef->fInATable = false;
oldRef->fSwapCalled = true;
#endif
}
else
Assert(0);
}

258
CommonUtilitiesLib/OSRef.h Normal file
View file

@ -0,0 +1,258 @@
/*
*
* @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: OSRef.h
Contains: Class supports creating unique string IDs to object pointers. A grouping
of an object and its string ID may be stored in an OSRefTable, and the
associated object pointer can be looked up by string ID.
Refs can only be removed from the table when no one is using the ref,
therefore allowing clients to arbitrate access to objects in a preemptive,
multithreaded environment.
*/
#ifndef _OSREF_H_
#define _OSREF_H_
#include "StrPtrLen.h"
#include "OSHashTable.h"
#include "OSCond.h"
class OSRefKey;
class OSRefTableUtils
{
private:
static UInt32 HashString(StrPtrLen* inString);
friend class OSRef;
friend class OSRefKey;
};
class OSRef
{
public:
OSRef() : fObjectP(NULL), fRefCount(0), fNextHashEntry(NULL)
{
#if DEBUG
fInATable = false;
fSwapCalled = false;
#endif
}
OSRef(const StrPtrLen &inString, void* inObjectP)
: fRefCount(0), fNextHashEntry(NULL)
{ Set(inString, inObjectP); }
~OSRef() {}
void Set(const StrPtrLen& inString, void* inObjectP)
{
#if DEBUG
fInATable = false;
fSwapCalled = false;
#endif
fString = inString; fObjectP = inObjectP;
fHashValue = OSRefTableUtils::HashString(&fString);
}
#if DEBUG
Bool16 IsInTable() { return fInATable; }
#endif
void** GetObjectPtr() { return &fObjectP; }
void* GetObject() { return fObjectP; }
UInt32 GetRefCount() { return fRefCount; }
StrPtrLen *GetString() { return &fString; }
private:
//value
void* fObjectP;
//key
StrPtrLen fString;
//refcounting
UInt32 fRefCount;
#if DEBUG
Bool16 fInATable;
Bool16 fSwapCalled;
#endif
OSCond fCond;//to block threads waiting for this ref.
UInt32 fHashValue;
OSRef* fNextHashEntry;
friend class OSRefKey;
friend class OSHashTable<OSRef, OSRefKey>;
friend class OSHashTableIter<OSRef, OSRefKey>;
friend class OSRefTable;
};
class OSRefKey
{
public:
//CONSTRUCTOR / DESTRUCTOR:
OSRefKey(StrPtrLen* inStringP)
: fStringP(inStringP)
{ fHashValue = OSRefTableUtils::HashString(inStringP); }
~OSRefKey() {}
//ACCESSORS:
StrPtrLen* GetString() { return fStringP; }
private:
//PRIVATE ACCESSORS:
SInt32 GetHashKey() { return fHashValue; }
//these functions are only used by the hash table itself. This constructor
//will break the "Set" functions.
OSRefKey(OSRef *elem) : fStringP(&elem->fString),
fHashValue(elem->fHashValue) {}
friend int operator ==(const OSRefKey &key1, const OSRefKey &key2)
{
if (key1.fStringP->Equal(*key2.fStringP))
return true;
return false;
}
//data:
StrPtrLen *fStringP;
UInt32 fHashValue;
friend class OSHashTable<OSRef, OSRefKey>;
};
typedef OSHashTable<OSRef, OSRefKey> OSRefHashTable;
typedef OSHashTableIter<OSRef, OSRefKey> OSRefHashTableIter;
class OSRefTable
{
public:
enum
{
kDefaultTableSize = 1193 //UInt32
};
//tableSize doesn't indicate the max number of Refs that can be added
//(it's unlimited), but is rather just how big to make the hash table
OSRefTable(UInt32 tableSize = kDefaultTableSize) : fTable(tableSize), fMutex() {}
~OSRefTable() {}
//Allows access to the mutex in case you need to lock the table down
//between operations
OSMutex* GetMutex() { return &fMutex; }
OSRefHashTable* GetHashTable() { return &fTable; }
//Registers a Ref in the table. Once the Ref is in, clients may resolve
//the ref by using its string ID. You must setup the Ref before passing it
//in here, ie., setup the string and object pointers
//This function will succeed unless the string identifier is not unique,
//in which case it will return QTSS_DupName
//This function is atomic wrt this ref table.
OS_Error Register(OSRef* ref);
// RegisterOrResolve
// If the ID of the input ref is unique, this function is equivalent to
// Register, and returns NULL.
// If there is a duplicate ID already in the map, this funcion
// leave it, resolves it, and returns it.
OSRef* RegisterOrResolve(OSRef* inRef);
//This function may block. You can only remove a Ref from the table
//when the refCount drops to the level specified. If several threads have
//the ref currently, the calling thread will wait until the other threads
//stop using the ref (by calling Release, below)
//This function is atomic wrt this ref table.
void UnRegister(OSRef* ref, UInt32 refCount = 0);
// Same as UnRegister, but guarenteed not to block. Will return
// true if ref was sucessfully unregistered, false otherwise
Bool16 TryUnRegister(OSRef* ref, UInt32 refCount = 0);
//Resolve. This function uses the provided key string to identify and grab
//the Ref keyed by that string. Once the Ref is resolved, it is safe to use
//(it cannot be removed from the Ref table) until you call Release. Because
//of that, you MUST call release in a timely manner, and be aware of potential
//deadlocks because you now own a resource being contended over.
//This function is atomic wrt this ref table.
OSRef* Resolve(StrPtrLen* inString);
//Release. Release a Ref, and drops its refCount. After calling this, the
//Ref is no longer safe to use, as it may be removed from the ref table.
void Release(OSRef* inRef);
// Swap. This atomically removes any existing Ref in the table with the new
// ref's ID, and replaces it with this new Ref. If there is no matching Ref
// already in the table, this function does nothing.
//
// Be aware that this creates a situation where clients may have a Ref resolved
// that is no longer in the table. The old Ref must STILL be UnRegistered normally.
// Once Swap completes sucessfully, clients that call resolve on the ID will get
// the new OSRef object.
void Swap(OSRef* newRef);
UInt32 GetNumRefsInTable() { UInt64 result = fTable.GetNumEntries(); Assert(result < kUInt32_Max); return (UInt32) result; }
private:
//all this object needs to do its job is an atomic hashtable
OSRefHashTable fTable;
OSMutex fMutex;
};
class OSRefReleaser
{
public:
OSRefReleaser(OSRefTable* inTable, OSRef* inRef) : fOSRefTable(inTable), fOSRef(inRef) {}
~OSRefReleaser() { fOSRefTable->Release(fOSRef); }
OSRef* GetRef() { return fOSRef; }
private:
OSRefTable* fOSRefTable;
OSRef* fOSRef;
};
#endif //_OSREF_H_

View file

@ -0,0 +1,347 @@
/*
*
* @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: OSThread.cpp
Contains: Thread abstraction implementation
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifdef __MacOSX__
#include <mach/mach_types.h>
#include <mach/mach_time.h>
#endif
#ifndef __Win32__
#if __PTHREADS__
#include <pthread.h>
#if USE_THR_YIELD
#include <thread.h>
#endif
#else
#include <mach/mach.h>
#include <mach/cthreads.h>
#endif
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#endif
#include "OSThread.h"
#include "MyAssert.h"
#ifdef __sgi__
#include <time.h>
#endif
//
// OSThread.cp
//
void* OSThread::sMainThreadData = NULL;
#ifdef __Win32__
DWORD OSThread::sThreadStorageIndex = 0;
#elif __PTHREADS__
pthread_key_t OSThread::gMainKey = 0;
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
pthread_attr_t OSThread::sThreadAttr;
#endif
#endif
char OSThread::sUser[128]= "";
char OSThread::sGroup[128]= "";
#if __linux__ || __MacOSX__
Bool16 OSThread::sWrapSleep = true;
#endif
void OSThread::Initialize()
{
#ifdef __Win32__
sThreadStorageIndex = ::TlsAlloc();
Assert(sThreadStorageIndex >= 0);
#elif __PTHREADS__
pthread_key_create(&OSThread::gMainKey, NULL);
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
//
// Added for Solaris...
pthread_attr_init(&sThreadAttr);
/* Indicate we want system scheduling contention scope. This
thread is permanently "bound" to an LWP */
pthread_attr_setscope(&sThreadAttr, PTHREAD_SCOPE_SYSTEM);
#endif
#endif
}
OSThread::OSThread()
: fStopRequested(false),
fJoined(false),
fThreadData(NULL)
{
}
OSThread::~OSThread()
{
this->StopAndWaitForThread();
}
void OSThread::Start()
{
#ifdef __Win32__
unsigned int theId = 0; // We don't care about the identifier
fThreadID = (HANDLE)_beginthreadex( NULL, // Inherit security
0, // Inherit stack size
_Entry, // Entry function
(void*)this, // Entry arg
0, // Begin executing immediately
&theId );
Assert(fThreadID != NULL);
#elif __PTHREADS__
pthread_attr_t* theAttrP;
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
//theAttrP = &sThreadAttr;
theAttrP = 0;
#else
theAttrP = NULL;
#endif
int err = pthread_create((pthread_t*)&fThreadID, theAttrP, _Entry, (void*)this);
Assert(err == 0);
#else
fThreadID = (UInt32)cthread_fork((cthread_fn_t)_Entry, (any_t)this);
#endif
}
void OSThread::StopAndWaitForThread()
{
fStopRequested = true;
if (!fJoined)
Join();
}
void OSThread::Join()
{
// What we're trying to do is allow the thread we want to delete to complete
// running. So we wait for it to stop.
Assert(!fJoined);
fJoined = true;
#ifdef __Win32__
DWORD theErr = ::WaitForSingleObject(fThreadID, INFINITE);
Assert(theErr == WAIT_OBJECT_0);
#elif __PTHREADS__
void *retVal;
pthread_join((pthread_t)fThreadID, &retVal);
#else
cthread_join((cthread_t)fThreadID);
#endif
}
void OSThread::ThreadYield()
{
// on platforms who's threading is not pre-emptive yield
// to another thread
#if THREADING_IS_COOPERATIVE
#if __PTHREADS__
#if USE_THR_YIELD
thr_yield();
#else
sched_yield();
#endif
#endif
#endif
}
#include "OS.h"
void OSThread::Sleep(UInt32 inMsec)
{
#ifdef __Win32__
::Sleep(inMsec);
#elif __linux__ || __MacOSX__
if (inMsec == 0)
return;
SInt64 startTime = OS::Milliseconds();
SInt64 timeLeft = inMsec;
SInt64 timeSlept = 0;
UInt64 utimeLeft = 0;
do { // loop in case we leave the sleep early
//qtss_printf("OSThread::Sleep time slept= %qd request sleep=%qd\n",timeSlept, timeLeft);
timeLeft = inMsec - timeSlept;
if (timeLeft < 1)
break;
utimeLeft = timeLeft * 1000;
//qtss_printf("OSThread::Sleep usleep=%qd\n", utimeLeft);
::usleep(utimeLeft);
timeSlept = (OS::Milliseconds() - startTime);
if (timeSlept < 0) // system time set backwards
break;
} while (timeSlept < inMsec);
//qtss_printf("total sleep = %qd request sleep=%"_U32BITARG_"\n", timeSlept,inMsec);
#elif defined(__osf__) || defined(__hpux__)
if (inMsec < 1000)
::usleep(inMsec * 1000); // useconds must be less than 1,000,000
else
::sleep((inMsec + 500) / 1000); // round to the nearest whole second
#elif defined(__sgi__)
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = inMsec * 1000000;
nanosleep(&ts, 0);
#else
::usleep(inMsec * 1000);
#endif
}
#ifdef __Win32__
unsigned int WINAPI OSThread::_Entry(LPVOID inThread)
#else
void* OSThread::_Entry(void *inThread) //static
#endif
{
OSThread* theThread = (OSThread*)inThread;
#ifdef __Win32__
BOOL theErr = ::TlsSetValue(sThreadStorageIndex, theThread);
Assert(theErr == TRUE);
#elif __PTHREADS__
theThread->fThreadID = (pthread_t)pthread_self();
pthread_setspecific(OSThread::gMainKey, theThread);
#else
theThread->fThreadID = (UInt32)cthread_self();
cthread_set_data(cthread_self(), (any_t)theThread);
#endif
theThread->SwitchPersonality();
//
// Run the thread
theThread->Entry();
return NULL;
}
Bool16 OSThread::SwitchPersonality()
{
#if __linux__
if (::strlen(sGroup) > 0)
{
struct group* gr = ::getgrnam(sGroup);
if (gr == NULL || ::setgid(gr->gr_gid) == -1)
{
//qtss_printf("thread %"_U32BITARG_" setgid to group=%s FAILED \n", (UInt32) this, sGroup);
return false;
}
//qtss_printf("thread %"_U32BITARG_" setgid to group=%s \n", (UInt32) this, sGroup);
}
if (::strlen(sUser) > 0)
{
struct passwd* pw = ::getpwnam(sUser);
if (pw == NULL || ::setuid(pw->pw_uid) == -1)
{
//qtss_printf("thread %"_U32BITARG_" setuid to user=%s FAILED \n", (UInt32) this, sUser);
return false;
}
//qtss_printf("thread %"_U32BITARG_" setuid to user=%s \n", (UInt32) this, sUser);
}
#endif
return true;
}
OSThread* OSThread::GetCurrent()
{
#ifdef __Win32__
return (OSThread *)::TlsGetValue(sThreadStorageIndex);
#elif __PTHREADS__
return (OSThread *)pthread_getspecific(OSThread::gMainKey);
#else
return (OSThread*)cthread_data(cthread_self());
#endif
}
#ifdef __Win32__
int OSThread::GetErrno()
{
int winErr = ::GetLastError();
// Convert to a POSIX errorcode. The *major* assumption is that
// the meaning of these codes is 1-1 and each Winsock, etc, etc
// function is equivalent in errors to the POSIX standard. This is
// a big assumption, but the server only checks for a small subset of
// the real errors, on only a small number of functions, so this is probably ok.
switch (winErr)
{
case ERROR_FILE_NOT_FOUND: return ENOENT;
case ERROR_PATH_NOT_FOUND: return ENOENT;
case WSAEINTR: return EINTR;
case WSAENETRESET: return EPIPE;
case WSAENOTCONN: return ENOTCONN;
case WSAEWOULDBLOCK:return EAGAIN;
case WSAECONNRESET: return EPIPE;
case WSAEADDRINUSE: return EADDRINUSE;
case WSAEMFILE: return EMFILE;
case WSAEINPROGRESS:return EINPROGRESS;
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
case WSAECONNABORTED: return EPIPE;
case 0: return 0;
default: return ENOTCONN;
}
}
#endif

View file

@ -0,0 +1,172 @@
/*
*
* @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: OSThread.h
Contains: A thread abstraction
*/
// OSThread.h
#ifndef __OSTHREAD__
#define __OSTHREAD__
#ifndef __Win32__
#if __PTHREADS__
#if __solaris__ || __sgi__ || __hpux__
#include <errno.h>
#else
#include <sys/errno.h>
#endif
#include <pthread.h>
#else
#include <mach/mach.h>
#include <mach/cthreads.h>
#endif
#endif
#include "OSHeaders.h"
#include "DateTranslator.h"
class OSThread
{
public:
//
// Call before calling any other OSThread function
static void Initialize();
OSThread();
virtual ~OSThread();
//
// Derived classes must implement their own entry function
virtual void Entry() = 0;
void Start();
static void ThreadYield();
static void Sleep(UInt32 inMsec);
void Join();
void SendStopRequest() { fStopRequested = true; }
Bool16 IsStopRequested() { return fStopRequested; }
void StopAndWaitForThread();
void* GetThreadData() { return fThreadData; }
void SetThreadData(void* inThreadData) { fThreadData = inThreadData; }
// As a convienence to higher levels, each thread has its own date buffer
DateBuffer* GetDateBuffer() { return &fDateBuffer; }
static void* GetMainThreadData() { return sMainThreadData; }
static void SetMainThreadData(void* inData) { sMainThreadData = inData; }
static void SetUser(char *user) {::strncpy(sUser,user, sizeof(sUser) -1); sUser[sizeof(sUser) -1]=0;}
static void SetGroup(char *group) {::strncpy(sGroup,group, sizeof(sGroup) -1); sGroup[sizeof(sGroup) -1]=0;}
static void SetPersonality(char *user, char* group) { SetUser(user); SetGroup(group); };
Bool16 SwitchPersonality();
#if DEBUG
UInt32 GetNumLocksHeld() { return 0; }
void IncrementLocksHeld() {}
void DecrementLocksHeld() {}
#endif
#if __linux__ || __MacOSX__
static void WrapSleep( Bool16 wrapSleep) {sWrapSleep = wrapSleep; }
#endif
#ifdef __Win32__
static int GetErrno();
static DWORD GetCurrentThreadID() { return ::GetCurrentThreadId(); }
#elif __PTHREADS__
static int GetErrno() { return errno; }
static pthread_t GetCurrentThreadID() { return ::pthread_self(); }
#else
static int GetErrno() { return cthread_errno(); }
static cthread_t GetCurrentThreadID() { return cthread_self(); }
#endif
static OSThread* GetCurrent();
private:
#ifdef __Win32__
static DWORD sThreadStorageIndex;
#elif __PTHREADS__
static pthread_key_t gMainKey;
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
static pthread_attr_t sThreadAttr;
#endif
#endif
static char sUser[128];
static char sGroup[128];
Bool16 fStopRequested;
Bool16 fJoined;
#ifdef __Win32__
HANDLE fThreadID;
#elif __PTHREADS__
pthread_t fThreadID;
#else
UInt32 fThreadID;
#endif
void* fThreadData;
DateBuffer fDateBuffer;
static void* sMainThreadData;
#ifdef __Win32__
static unsigned int WINAPI _Entry(LPVOID inThread);
#else
static void* _Entry(void* inThread);
#endif
#if __linux__ || __MacOSX__
static Bool16 sWrapSleep;
#endif
};
class OSThreadDataSetter
{
public:
OSThreadDataSetter(void* inInitialValue, void* inFinalValue) : fFinalValue(inFinalValue)
{ OSThread::GetCurrent()->SetThreadData(inInitialValue); }
~OSThreadDataSetter() { OSThread::GetCurrent()->SetThreadData(fFinalValue); }
private:
void* fFinalValue;
};
#endif

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@
*
*/
#ifndef __pldoublelinkedlist__
#define __pldoublelinkedlist__
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include "OSHeaders.h"
#include "MyAssert.h"
#ifndef __PLDoubleLinkedListDEBUG__
#define __PLDoubleLinkedListDEBUG__ 0
#endif
template <class T> class PLDoubleLinkedList;
template <class S> class PLDoubleLinkedListNode
{
friend class PLDoubleLinkedList <S>;
public:
PLDoubleLinkedListNode( S* element )
{
// the node takes ownership of "element"
fElement = element;
fNext = NULL;
fPrev = NULL;
}
virtual ~PLDoubleLinkedListNode()
{
#if __PLDoubleLinkedListDEBUG__
Assert( fPrev == NULL && fNext == NULL );
#endif
delete fElement;
}
S* fElement;
protected:
PLDoubleLinkedListNode *fNext;
PLDoubleLinkedListNode *fPrev;
};
template <class T> class PLDoubleLinkedList
{
public:
PLDoubleLinkedList()
{
fHead = NULL;
fTail = NULL;
fNumNodes = 0;
}
virtual ~PLDoubleLinkedList()
{
ClearList();
}
#if __PLDoubleLinkedListDEBUG__
void ValidateLinks()
{
PLDoubleLinkedListNode<T> *nextNode;
Assert( fHead == NULL || fHead->fPrev == NULL );
Assert( fTail == NULL || fTail->fNext == NULL );
if ( fTail == fHead && fTail != NULL )
{
Assert( fTail->fPrev == NULL && fTail->fNext == NULL );
}
if ( fHead )
{
Assert( fTail != NULL );
}
if ( fTail )
{
Assert( fHead != NULL );
}
if ( fTail && fTail->fPrev )
Assert( fTail->fPrev->fNext == fTail );
if ( fHead && fHead->fNext )
Assert( fHead->fNext->fPrev == fHead );
nextNode = fHead;
while ( nextNode )
{
Assert( fHead == nextNode || nextNode->fPrev->fNext == nextNode );
Assert( fTail == nextNode || nextNode->fNext->fPrev == nextNode );
if ( !nextNode->fNext )
Assert( fTail == nextNode );
nextNode = nextNode->fNext;
}
nextNode = fTail;
while ( nextNode )
{
Assert( fHead == nextNode || nextNode->fPrev->fNext == nextNode );
Assert( fTail == nextNode || nextNode->fNext->fPrev == nextNode );
if ( !nextNode->fPrev )
Assert( fHead == nextNode );
nextNode = nextNode->fPrev;
}
}
#endif // __PLDoubleLinkedListDEBUG__
PLDoubleLinkedListNode<T> * GetFirst() { return fHead; };
void AddNodeToTail(PLDoubleLinkedListNode<T> *node)
{
#if __PLDoubleLinkedListDEBUG__
// must not be associated with another list
Assert( node->fPrev == NULL && node->fNext == NULL );
#endif
if ( fTail )
fTail->fNext = node;
node->fPrev = fTail;
node->fNext = NULL;
fTail = node;
if ( !fHead )
fHead = node;
fNumNodes++;
#if __PLDoubleLinkedListDEBUG__
ValidateLinks();
#endif
}
void AddNode(PLDoubleLinkedListNode<T> *node )
{
#if __PLDoubleLinkedListDEBUG__
// must not be associated with another list
Assert( node->fPrev == NULL && node->fNext == NULL );
#endif
if ( fHead )
fHead->fPrev = node;
node->fPrev = NULL;
node->fNext = fHead;
fHead = node;
if ( !fTail )
fTail = node;
fNumNodes++;
#if __PLDoubleLinkedListDEBUG__
ValidateLinks();
#endif
}
void RemoveNode(PLDoubleLinkedListNode<T> *node)
{
#if __PLDoubleLinkedListDEBUG__
// must be associated with this list
Assert( fHead == node || node->fPrev->fNext == node );
// must be associated with this list
Assert( fTail == node || node->fNext->fPrev == node );
#endif
if ( fHead == node)
fHead = node->fNext;
else
node->fPrev->fNext = node->fNext;
if ( fTail == node)
fTail = node->fPrev;
else
node->fNext->fPrev = node->fPrev;
node->fPrev = NULL;
node->fNext = NULL;
fNumNodes--;
#if __PLDoubleLinkedListDEBUG__
ValidateLinks();
#endif
}
PLDoubleLinkedListNode<T> *ForEachUntil( bool (*doFunc)( PLDoubleLinkedListNode<T> *node, void *userData), void *userData )
{
PLDoubleLinkedListNode<T> *nextElement, *curElement;
bool stopIteration = false;
curElement = fHead;
while ( curElement && !stopIteration )
{
nextElement = curElement->fNext;
stopIteration = (*doFunc)( curElement, userData);
if ( !stopIteration )
curElement = nextElement;
}
return curElement;
}
void ForEach( void (*doFunc)( PLDoubleLinkedListNode<T> *node, void *userData), void *userData )
{
PLDoubleLinkedListNode<T> *nextElement, *curElement;
curElement = fHead;
while ( curElement )
{
nextElement = curElement->fNext;
(*doFunc)( curElement, userData);
curElement = nextElement;
}
}
void ClearList()
{
ForEach( DoClearList, this );
}
PLDoubleLinkedListNode<T> *GetNthNode( int nodeIndex )
{
return ForEachUntil( CompareIndexToZero, &nodeIndex );
}
UInt32 GetNumNodes() { return fNumNodes; }
protected:
static bool CompareIndexToZero( PLDoubleLinkedListNode<T> *, void * nodeIndex ) // (node, nodeIndex)
{
int val = *(int*)nodeIndex;
if ( val == 0 )
return true;
*(int*)nodeIndex = val -1;
return false;
}
static void DoClearList( PLDoubleLinkedListNode<T> *node, void * listPtr )
{
PLDoubleLinkedList<T> *list = (PLDoubleLinkedList<T> *)listPtr;
list->RemoveNode( node );
delete node;
}
PLDoubleLinkedListNode<T> *fHead;
PLDoubleLinkedListNode<T> *fTail;
UInt32 fNumNodes;
};
#endif

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@
*
*/
#ifndef __pathdelimiter__
#define __pathdelimiter__
#if __MACOS__
#define kPathDelimiterString ":"
#define kPathDelimiterChar ':'
#define kPartialPathBeginsWithDelimiter 1
#else
#define kPathDelimiterString "/"
#define kPathDelimiterChar '/'
#define kPartialPathBeginsWithDelimiter 0
#endif
#endif

View file

@ -0,0 +1,264 @@
/*
*
* @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 "QueryParamList.h"
#include "StringParser.h"
#include "OSMemory.h"
#include <string.h>
#include <stdlib.h>
#include "SafeStdLib.h"
QueryParamList::QueryParamList( StrPtrLen* querySPL )
{
// ctor from StrPtrLen
fNameValueQueryParamlist = NEW PLDoubleLinkedList<QueryParamListElement>;
this->BulidList( querySPL );
}
QueryParamList::QueryParamList( char* queryString )
{
// ctor from char*
StrPtrLen querySPL( queryString );
fNameValueQueryParamlist = NEW PLDoubleLinkedList<QueryParamListElement>;
this->BulidList( &querySPL );
}
void QueryParamList::BulidList( StrPtrLen* querySPL )
{
// parse the string and build the name/value list from the tokens.
// the string is a 'form' encoded query string ( see rfc - 1808 )
StringParser queryParser( querySPL );
while ( queryParser.GetDataRemaining() > 0 )
{
StrPtrLen theCGIParamName;
StrPtrLen theCGIParamValue;
queryParser.ConsumeUntil(&theCGIParamName, '='); // leaves "=..." in cgiParser, puts item keywd in theCGIParamName
if ( queryParser.GetDataRemaining() > 1 )
{
queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '='
queryParser.ConsumeUntil(&theCGIParamValue, '&'); // our value will end by here...
AddNameValuePairToList( theCGIParamName.GetAsCString(), theCGIParamValue.GetAsCString() );
queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '='
}
}
}
static void PrintNameAndValue( PLDoubleLinkedListNode<QueryParamListElement> *node, void *userData )
{
// used by QueryParamList::PrintAll
QueryParamListElement* nvPair = node->fElement;
qtss_printf( "qpl: %s, name %s, val %s\n", (char*)userData, nvPair->mName, nvPair->mValue );
}
void QueryParamList::PrintAll( char *idString )
{
// print name and value of each item in the list, print each pair preceded by "idString"
fNameValueQueryParamlist->ForEach( PrintNameAndValue, idString );
}
static bool CompareStrToName( PLDoubleLinkedListNode<QueryParamListElement> *node, void *userData )
{
/*
make a case insenstitive comparison between "node" name and the userData
used by QueryParamList::DoFindCGIValueForParam
*/
QueryParamListElement* nvPair = node->fElement;
StrPtrLen name( nvPair->mName );
if ( name.EqualIgnoreCase( (char*)userData, strlen( (char*)userData ) ) )
return true;
return false;
}
const char *QueryParamList::DoFindCGIValueForParam( char *name )
{
/*
return the first value where the paramter name matches "name"
use case insenstitive comparison
*/
PLDoubleLinkedListNode<QueryParamListElement>* node;
node = fNameValueQueryParamlist->ForEachUntil( CompareStrToName, name );
if ( node != NULL )
{
QueryParamListElement* nvPair = (QueryParamListElement*)node->fElement;
return nvPair->mValue;
}
return NULL;
}
void QueryParamList::AddNameValuePairToList( char* name, char* value )
{
// add the name/value pair to the by creating the holder struct
// then adding that as the element in the linked list
PLDoubleLinkedListNode<QueryParamListElement>* nvNode;
QueryParamListElement* nvPair;
this->DecodeArg( name );
this->DecodeArg( value );
nvPair = NEW QueryParamListElement( name, value );
// create a node to hold the pair
nvNode = NEW PLDoubleLinkedListNode<QueryParamListElement> ( nvPair );
// add it to the list
fNameValueQueryParamlist->AddNode( nvNode );
}
void QueryParamList::DecodeArg( char *ioCodedPtr )
{
// perform In-Place &hex and + to space decoding of the parameter
// on input, ioCodedPtr mau contain encoded text, on exit ioCodedPtr will be plain text
// on % decoding errors, the
if ( !ioCodedPtr )
return;
char* destPtr;
char* curChar;
short lineState = kLastWasText;
char hexBuff[32];
destPtr = curChar = ioCodedPtr;
while( *curChar )
{
switch( lineState )
{
case kRcvHexDigitOne:
if ( IsHex( *curChar ) )
{
hexBuff[3] = *curChar;
hexBuff[4] = 0;
*destPtr++ = (char)::strtoul( hexBuff, NULL, 0 );
}
else
{ // not a valid encoding
*destPtr++ = '%'; // put back the pct sign
*destPtr++ = hexBuff[2]; // put back the first digit too.
*destPtr++ = *curChar; // and this one!
}
lineState = kLastWasText;
break;
case kLastWasText:
if ( *curChar == '%' )
lineState = kPctEscape;
else
{
if ( *curChar == '+' )
*destPtr++ = ' ';
else
*destPtr++ = *curChar;
}
break;
case kPctEscape:
if ( *curChar == '%' )
{
*destPtr++ = '%';
lineState = kLastWasText;
}
else
{
if ( IsHex( *curChar ) )
{
hexBuff[0] = '0';
hexBuff[1] = 'x';
hexBuff[2] = *curChar;
lineState = kRcvHexDigitOne;
}
else
{
*destPtr++ = '%'; // put back the pct sign
*destPtr++ = *curChar; // and this one!
lineState = kLastWasText;
}
}
break;
}
curChar++;
}
*destPtr = *curChar;
}
Bool16 QueryParamList::IsHex( char c )
{
// return true if char c is a valid hexidecimal digit
// false otherwise.
if ( c >= '0' && c <= '9' )
return true;
if ( c >= 'A' && c <= 'F' )
return true;
if ( c >= 'a' && c <= 'f' )
return true;
return false;
}

View file

@ -0,0 +1,100 @@
/*
*
* @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: QueryParamList.cpp
Contains: Implementation of QueryParamList class
The QueryParamList class is used to parse and build a searchable list
of name/value pairs from a RFC1808 QueryString that has been encoded
using the html 'form encoding' rules.
*/
#ifndef __query_param_list__
#define __query_param_list__
//#include "QueryParamList.h"
#include "PLDoubleLinkedList.h"
#include "StrPtrLen.h"
class QueryParamListElement {
public:
QueryParamListElement( char* name, char* value )
{
mName = name;
mValue = value;
}
virtual ~QueryParamListElement()
{
delete [] mName;
delete [] mValue;
}
char *mName;
char *mValue;
};
class QueryParamList
{
public:
QueryParamList( char* queryString );
QueryParamList( StrPtrLen* querySPL );
~QueryParamList() { delete fNameValueQueryParamlist; }
void AddNameValuePairToList( char* name, char* value );
const char *DoFindCGIValueForParam( char *name );
void PrintAll( char *idString );
protected:
void BulidList( StrPtrLen* querySPL );
void DecodeArg( char *ioCodedPtr );
enum {
// escaping states
kLastWasText
, kPctEscape
, kRcvHexDigitOne
};
Bool16 IsHex( char c );
PLDoubleLinkedList<QueryParamListElement> *fNameValueQueryParamlist;
};
#endif

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: ResizeableStringFormatter.cpp
Contains: Implements object defined in ResizeableStringFormatter.h
*/
#include "ResizeableStringFormatter.h"
#include "OSMemory.h"
Bool16 ResizeableStringFormatter::BufferIsFull(char* inBuffer, UInt32 inBufferLen)
{
//allocate a buffer twice as big as the old one, and copy over the contents
UInt32 theNewBufferSize = this->GetTotalBufferSize() * 2;
if (theNewBufferSize == 0)
theNewBufferSize = 64;
char* theNewBuffer = NEW char[theNewBufferSize];
::memcpy(theNewBuffer, inBuffer, inBufferLen);
//if the old buffer was dynamically allocated also, we'd better delete it.
if (inBuffer != fOriginalBuffer)
delete [] inBuffer;
fStartPut = theNewBuffer;
fCurrentPut = theNewBuffer + inBufferLen;
fEndPut = theNewBuffer + theNewBufferSize;
return true;
}

View file

@ -0,0 +1,63 @@
/*
*
* @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: ResizeableStringFormatter.h
Contains: Derived from StringFormatter, this transparently grows the
output buffer if the original buffer is too small to hold all
the data being placed in it
*/
#ifndef __RESIZEABLE_STRING_FORMATTER_H__
#define __RESIZEABLE_STRING_FORMATTER_H__
#include "StringFormatter.h"
class ResizeableStringFormatter : public StringFormatter
{
public:
// Pass in inBuffer=NULL and inBufSize=0 to dynamically allocate the initial buffer.
ResizeableStringFormatter(char* inBuffer = NULL, UInt32 inBufSize = 0)
: StringFormatter(inBuffer, inBufSize), fOriginalBuffer(inBuffer) {}
//If we've been forced to increase the buffer size, fStartPut WILL be a dynamically allocated
//buffer, and it WON'T be equal to fOriginalBuffer (obviously).
virtual ~ResizeableStringFormatter() { if (fStartPut != fOriginalBuffer) delete [] fStartPut; }
private:
// This function will get called by StringFormatter if the current
// output buffer is full. This object allocates a buffer that's twice
// as big as the old one.
virtual Bool16 BufferIsFull(char* inBuffer, UInt32 inBufferLen);
char* fOriginalBuffer;
};
#endif //__RESIZEABLE_STRING_FORMATTER_H__

View file

@ -0,0 +1,370 @@
/*
*
* @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 "SDPUtils.h"
#include "OS.h"
#include "StrPtrLen.h"
#include "ResizeableStringFormatter.h"
#include "StringParser.h"
#include "ResizeableStringFormatter.h"
#include "StringParser.h"
#include "OSMemory.h"
SInt32 SDPContainer::AddHeaderLine (StrPtrLen *theLinePtr)
{
Assert(theLinePtr);
UInt32 thisLine = fNumUsedLines;
Assert(fNumUsedLines < fNumSDPLines);
fSDPLineArray[thisLine].Set(theLinePtr->Ptr, theLinePtr->Len);
fNumUsedLines++;
if (fNumUsedLines == fNumSDPLines)
{
SDPLine *tempSDPLineArray = NEW SDPLine[fNumSDPLines * 2];
for (int i = 0; i < fNumSDPLines; i++)
{
tempSDPLineArray[i].Set(fSDPLineArray[i].Ptr,fSDPLineArray[i].Len);
}
delete [] fSDPLineArray;
fSDPLineArray = tempSDPLineArray;
fNumSDPLines = (fNumUsedLines * 2);
}
return thisLine;
}
SInt32 SDPContainer::FindHeaderLineType(char id, SInt32 start)
{
SInt32 theIndex = -1;
if (start >= fNumUsedLines || start < 0)
return -1;
for (int i = start; i < fNumUsedLines; i++)
{ if (fSDPLineArray[i].GetHeaderType() == id)
{ theIndex = i;
fCurrentLine = theIndex;
break;
}
}
return theIndex;
}
SDPLine* SDPContainer::GetNextLine()
{
if (fCurrentLine < fNumUsedLines)
{ fCurrentLine ++;
return &fSDPLineArray[fCurrentLine];
}
return NULL;
}
SDPLine* SDPContainer::GetLine(SInt32 lineIndex)
{
if (lineIndex > -1 && lineIndex < fNumUsedLines)
{ return &fSDPLineArray[lineIndex];
}
return NULL;
}
void SDPContainer::SetLine(SInt32 index)
{
if (index > -1 && index < fNumUsedLines)
{ fCurrentLine = index;
}
else
Assert(0);
}
void SDPContainer::Parse()
{
char* validChars = "vosiuepcbtrzkam";
char nameValueSeparator = '=';
Bool16 valid = true;
StringParser sdpParser(&fSDPBuffer);
StrPtrLen line;
StrPtrLen fieldName;
StrPtrLen space;
Bool16 foundLine = false;
while ( sdpParser.GetDataRemaining() != 0 )
{
foundLine = sdpParser.GetThruEOL(&line); // Read each line
if (!foundLine)
{ break;
}
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 == '\0')
continue; //skip over blank lines
fFieldStr[ (UInt8)firstChar] = firstChar;
switch (firstChar)
{
case 'v': fReqLines |= kV;
break;
case 's': fReqLines |= kS ;
break;
case 't': fReqLines |= kT ;
break;
case 'o': fReqLines |= kO ;
break;
}
lineParser.ConsumeUntil(&fieldName, nameValueSeparator);
if ((fieldName.Len != 1) || (::strchr(validChars, fieldName.Ptr[0]) == NULL))
{
valid = false; // line doesn't begin with one of the valid characters followed by an "="
break;
}
if (!lineParser.Expect(nameValueSeparator))
{
valid = false; // line doesn't have the "=" after the first char
break;
}
lineParser.ConsumeUntil(&space, StringParser::sWhitespaceMask);
if (space.Len != 0)
{
valid = false; // line has whitespace after the "="
break;
}
AddHeaderLine(&line);
}
if (fNumUsedLines == 0) // didn't add any lines
{ valid = false;
}
fValid = valid;
}
void SDPContainer::Initialize()
{
fCurrentLine = 0;
fNumUsedLines = 0;
delete [] fSDPLineArray;
fSDPLineArray = NEW SDPLine[fNumSDPLines];
fValid = false;
fReqLines = 0;
::memset(fFieldStr, sizeof(fFieldStr), 0);
}
Bool16 SDPContainer::SetSDPBuffer(char *sdpBuffer)
{
Initialize();
if (sdpBuffer != NULL)
{ fSDPBuffer.Set(sdpBuffer);
Parse();
}
return IsSDPBufferValid();
}
Bool16 SDPContainer::SetSDPBuffer(StrPtrLen *sdpBufferPtr)
{
Initialize();
if (sdpBufferPtr != NULL)
{ fSDPBuffer.Set(sdpBufferPtr->Ptr, sdpBufferPtr->Len);
Parse();
}
return IsSDPBufferValid();
}
void SDPContainer::PrintLine(SInt32 lineIndex)
{
StrPtrLen *printLinePtr = GetLine(lineIndex);
if (printLinePtr)
{ printLinePtr->PrintStr();
qtss_printf("\n");
}
}
void SDPContainer::PrintAllLines()
{
if (fNumUsedLines > 0)
{ for (int i = 0; i < fNumUsedLines; i++)
PrintLine(i);
}
else
qtss_printf("SDPContainer::PrintAllLines no lines\n");
}
Bool16 SDPLineSorter::ValidateSessionHeader(StrPtrLen *theHeaderLinePtr)
{
if (NULL == theHeaderLinePtr || 0 == theHeaderLinePtr->Len || NULL== theHeaderLinePtr->Ptr)
return false;
// check for a duplicate range line.
StrPtrLen currentSessionHeader(fSDPSessionHeaders.GetBufPtr(), fSDPSessionHeaders.GetBytesWritten());
if ( 'a' == theHeaderLinePtr->Ptr[0] && theHeaderLinePtr->FindString("a=range") && currentSessionHeader.FindString("a=range"))
{
return false;
}
return true;
}
char SDPLineSorter::sSessionOrderedLines[] = "vosiuepcbtrzka"; // chars are order dependent: declared by rfc 2327
char SDPLineSorter::sessionSingleLines[] = "vtosiuepcbzk"; // return only 1 of each of these session field types
StrPtrLen SDPLineSorter::sEOL("\r\n");
StrPtrLen SDPLineSorter::sMaxBandwidthTag("b=AS:");
SDPLineSorter::SDPLineSorter(SDPContainer *rawSDPContainerPtr, Float32 adjustMediaBandwidthPercent, SDPContainer *insertMediaLinesArray) : fSessionLineCount(0),fSDPSessionHeaders(NULL,0), fSDPMediaHeaders(NULL,0)
{
Assert(rawSDPContainerPtr != NULL);
if (NULL == rawSDPContainerPtr)
return;
StrPtrLen theSDPData(rawSDPContainerPtr->fSDPBuffer.Ptr,rawSDPContainerPtr->fSDPBuffer.Len);
StrPtrLen *theMediaStart = rawSDPContainerPtr->GetLine(rawSDPContainerPtr->FindHeaderLineType('m',0));
if (theMediaStart && theMediaStart->Ptr && theSDPData.Ptr)
{
UInt32 mediaLen = theSDPData.Len - (UInt32) (theMediaStart->Ptr - theSDPData.Ptr);
char *mediaStartPtr= theMediaStart->Ptr;
fMediaHeaders.Set(mediaStartPtr,mediaLen);
StringParser sdpParser(&fMediaHeaders);
SDPLine sdpLine;
Bool16 foundLine = false;
Bool16 newMediaSection = true;
SDPLine *insertLine = NULL;
while (sdpParser.GetDataRemaining() > 0)
{
foundLine = sdpParser.GetThruEOL(&sdpLine);
if (!foundLine)
{ break;
}
if (sdpLine.GetHeaderType() == 'm' )
newMediaSection = true;
if (insertMediaLinesArray && newMediaSection && (sdpLine.GetHeaderType() == 'a') )
{
newMediaSection = false;
for (insertLine = insertMediaLinesArray->GetLine(0); insertLine ; insertLine = insertMediaLinesArray->GetNextLine() )
fSDPMediaHeaders.Put(*insertLine);
}
if ( ( 'b' == sdpLine.GetHeaderType()) && (1.0 != adjustMediaBandwidthPercent) )
{
StringParser bLineParser(&sdpLine);
bLineParser.ConsumeUntilDigit();
UInt32 bandwidth = (UInt32) (.5 + (adjustMediaBandwidthPercent * (Float32) bLineParser.ConsumeInteger() ) );
if (bandwidth < 1)
bandwidth = 1;
char bandwidthStr[10];
qtss_snprintf(bandwidthStr,sizeof(bandwidthStr) -1, "%"_U32BITARG_"", bandwidth);
bandwidthStr[sizeof(bandwidthStr) -1] = 0;
fSDPMediaHeaders.Put(sMaxBandwidthTag);
fSDPMediaHeaders.Put(bandwidthStr);
}
else
fSDPMediaHeaders.Put(sdpLine);
fSDPMediaHeaders.Put(SDPLineSorter::sEOL);
}
fMediaHeaders.Set(fSDPMediaHeaders.GetBufPtr(),fSDPMediaHeaders.GetBytesWritten());
}
fSessionLineCount = rawSDPContainerPtr->FindHeaderLineType('m',0);
if (fSessionLineCount < 0) // didn't find it use the whole buffer
{ fSessionLineCount = rawSDPContainerPtr->GetNumLines();
}
for (SInt16 sessionLineIndex = 0; sessionLineIndex < fSessionLineCount; sessionLineIndex++)
fSessionSDPContainer.AddHeaderLine( (StrPtrLen *) rawSDPContainerPtr->GetLine(sessionLineIndex));
//qtss_printf("\nSession raw Lines:\n"); fSessionSDPContainer.PrintAllLines();
SInt16 numHeaderTypes = sizeof(SDPLineSorter::sSessionOrderedLines) -1;
Bool16 addLine = true;
for (SInt16 fieldTypeIndex = 0; fieldTypeIndex < numHeaderTypes; fieldTypeIndex ++)
{
SInt32 lineIndex = fSessionSDPContainer.FindHeaderLineType(SDPLineSorter::sSessionOrderedLines[fieldTypeIndex], 0);
StrPtrLen *theHeaderLinePtr = fSessionSDPContainer.GetLine(lineIndex);
while (theHeaderLinePtr != NULL)
{
addLine = this->ValidateSessionHeader(theHeaderLinePtr);
if (addLine)
{
fSDPSessionHeaders.Put(*theHeaderLinePtr);
fSDPSessionHeaders.Put(SDPLineSorter::sEOL);
}
if (NULL != ::strchr(sessionSingleLines, theHeaderLinePtr->Ptr[0] ) ) // allow 1 of this type: use first found
break; // move on to next line type
lineIndex = fSessionSDPContainer.FindHeaderLineType(SDPLineSorter::sSessionOrderedLines[fieldTypeIndex], lineIndex + 1);
theHeaderLinePtr = fSessionSDPContainer.GetLine(lineIndex);
}
}
fSessionHeaders.Set(fSDPSessionHeaders.GetBufPtr(),fSDPSessionHeaders.GetBytesWritten());
}
char* SDPLineSorter::GetSortedSDPCopy()
{
char* fullbuffCopy = NEW char[fSessionHeaders.Len + fMediaHeaders.Len + 2];
SInt32 buffPos = 0;
memcpy(&fullbuffCopy[buffPos], fSessionHeaders.Ptr,fSessionHeaders.Len);
buffPos += fSessionHeaders.Len;
memcpy(&fullbuffCopy[buffPos], fMediaHeaders.Ptr,fMediaHeaders.Len);
buffPos += fMediaHeaders.Len;
fullbuffCopy[buffPos] = 0;
return fullbuffCopy;
}

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@
*
*/
/*
File: SDPUtils.h
Contains: Some static routines for dealing with SDPs
*/
#ifndef __SDPUtilsH__
#define __SDPUtilsH__
#include "OS.h"
#include "StrPtrLen.h"
#include "ResizeableStringFormatter.h"
#include "StringParser.h"
#include "OSMemory.h"
class SDPLine : public StrPtrLen
{
public:
SDPLine() {}
virtual ~SDPLine() {}
char GetHeaderType() {if (Ptr && Len) return this->Ptr[0]; return 0;}
};
class SDPContainer
{
enum { kBaseLines = 20, kLineTypeArraySize = 256};
enum {
kVPos = 0,
kSPos,
kTPos,
kOPos
};
enum {
kV = 1 << kVPos,
kS = 1 << kSPos,
kT = 1 << kTPos,
kO = 1 << kOPos,
kAllReq = kV | kS | kT | kO
};
public:
SDPContainer(UInt32 numStrPtrs = SDPContainer::kBaseLines) :
fNumSDPLines(numStrPtrs),
fSDPLineArray(NULL)
{
Initialize();
}
~SDPContainer() {delete [] fSDPLineArray;}
void Initialize();
SInt32 AddHeaderLine (StrPtrLen *theLinePtr);
SInt32 FindHeaderLineType(char id, SInt32 start);
SDPLine* GetNextLine();
SDPLine* GetLine(SInt32 lineIndex);
void SetLine(SInt32 index);
void Parse();
Bool16 SetSDPBuffer(char *sdpBuffer);
Bool16 SetSDPBuffer(StrPtrLen *sdpBufferPtr);
Bool16 IsSDPBufferValid() {return fValid;}
Bool16 HasReqLines() { return (Bool16) (fReqLines == kAllReq) ; }
Bool16 HasLineType( char lineType ) { return (Bool16) (lineType == fFieldStr[ (UInt8) lineType]) ; }
char* GetReqLinesArray;
void PrintLine(SInt32 lineIndex);
void PrintAllLines();
SInt32 GetNumLines() { return fNumUsedLines; }
SInt32 fCurrentLine;
SInt32 fNumSDPLines;
SInt32 fNumUsedLines;
SDPLine* fSDPLineArray;
Bool16 fValid;
StrPtrLen fSDPBuffer;
UInt16 fReqLines;
char fFieldStr[kLineTypeArraySize]; //
char* fLineSearchTypeArray;
};
class SDPLineSorter {
public:
SDPLineSorter(): fSessionLineCount(0),fSDPSessionHeaders(NULL,0), fSDPMediaHeaders(NULL,0) {};
SDPLineSorter(SDPContainer *rawSDPContainerPtr, Float32 adjustMediaBandwidthPercent = 1.0, SDPContainer *insertMediaLinesArray = NULL);
StrPtrLen* GetSessionHeaders() { return &fSessionHeaders; }
StrPtrLen* GetMediaHeaders() { return &fMediaHeaders; }
char* GetSortedSDPCopy();
Bool16 ValidateSessionHeader(StrPtrLen *theHeaderLinePtr);
StrPtrLen fullSDPBuffSPL;
SInt32 fSessionLineCount;
SDPContainer fSessionSDPContainer;
ResizeableStringFormatter fSDPSessionHeaders;
ResizeableStringFormatter fSDPMediaHeaders;
StrPtrLen fSessionHeaders;
StrPtrLen fMediaHeaders;
static char sSessionOrderedLines[];// = "vosiuepcbtrzka"; // chars are order dependent: declared by rfc 2327
static char sessionSingleLines[];// = "vosiuepcbzk"; // return only 1 of each of these session field types
static StrPtrLen sEOL;
static StrPtrLen sMaxBandwidthTag;
};
#endif

View file

@ -0,0 +1,227 @@
/*
*
* @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@
*
*/
/*
* SVector.h
*
* An simple, non-exception safe implementation of vector
*/
#ifndef _SVECTOR_H_
#define _SVECTOR_H_
#include"OSHeaders.h"
#include"OSMemory.h"
//T must be default and copy constructable; does not have to be assignable
template<class T>
class SVector
{
public:
explicit SVector(UInt32 newCapacity = 0)
: fCapacity(0), fSize(0), fData(NULL)
{
reserve(newCapacity);
}
SVector(const SVector &rhs)
: fCapacity(0), fSize(0), fData(NULL)
{
reserve(rhs.size());
fSize = rhs.size();
for(UInt32 i = 0; i < rhs.size(); ++i)
NEW(fData + i) T(rhs[i]);
}
~SVector()
{
clear();
operator delete[](fData);
}
SVector &operator=(const SVector &rhs)
{
clear();
reserve(rhs.size());
fSize = rhs.size();
for(UInt32 i = 0; i < rhs.size(); ++i)
NEW(fData + i) T(rhs[i]);
return *this;
}
T &operator[](UInt32 i) const { return fData[i]; }
T &front() const { return fData[0]; }
T &back() const { return fData[fSize - 1]; }
T *begin() const { return fData; }
T *end() const { return fData + fSize; }
//Returns searchEnd if target is not found; uses == for equality comparison
UInt32 find(UInt32 searchStart, UInt32 searchEnd, const T &target) { return find<EqualOp>(searchStart, searchEnd, target); }
//Allows you to specify an equality comparison functor
template<class Eq>
UInt32 find(UInt32 searchStart, UInt32 searchEnd, const T &target, Eq eq = Eq())
{
UInt32 i = searchStart;
for(; i < searchEnd; ++i)
if (eq(target, fData[i]))
break;
return i;
}
//returns size() if the element is not found
UInt32 find(const T &target) { return find<EqualOp>(target); }
template<class Eq>
UInt32 find(const T &target, Eq eq = Eq()) { return find(0, size(), target, eq); }
//Doubles the capacity as needed
void push_back(const T &newItem)
{
reserve(fSize + 1);
NEW (fData + fSize) T(newItem);
fSize++;
}
void pop_back() { fData[--fSize].~T(); }
void swap(SVector &rhs)
{
UInt32 tmpCapacity = fCapacity;
UInt32 tmpSize = fSize;
T *tmpData = fData;
fCapacity = rhs.fCapacity;
fSize = rhs.fSize;
fData = rhs.fData;
rhs.fCapacity = tmpCapacity;
rhs.fSize = tmpSize;
rhs.fData = tmpData;
}
void insert(UInt32 position, const T &newItem) { insert(position, 1, newItem); }
void insert(UInt32 position, UInt32 count, const T &newItem)
{
reserve(fSize + count);
for(UInt32 i = fSize; i > position; --i)
{
NEW (fData + i - 1 + count) T(fData[i - 1]);
fData[i - 1].~T();
}
for(UInt32 i = position; i < position + count; ++i)
NEW (fData + i) T(newItem);
fSize += count;
}
//can accept count of 0 - which results in a NOP
void erase(UInt32 position, UInt32 count = 1)
{
if(count == 0)
return;
for(UInt32 i = position; i < position + count; ++i)
fData[i].~T();
for(UInt32 i = position + count; i < fSize; ++i)
{
NEW (fData + i - count) T(fData[i]);
fData[i].~T();
}
fSize -= count;
}
//Removes 1 element by swapping it with the last item.
void swap_erase(UInt32 position)
{
fData[position].~T();
if (position < --fSize)
{
NEW(fData + position) T(fData[fSize]);
fData[fSize].~T();
}
}
Bool16 empty() const { return fSize == 0; }
UInt32 capacity() const { return fCapacity; }
UInt32 size() const { return fSize; }
void clear() { resize(0); }
//unlike clear(), this will free the memories
void wipe()
{
this->~SVector();
fCapacity = fSize = 0;
fData = NULL;
}
//Doubles the capacity on a reallocation to preserve linear time semantics
void reserve(UInt32 newCapacity)
{
if (newCapacity > fCapacity)
{
UInt32 targetCapacity = fCapacity == 0 ? 4 : fCapacity;
while(targetCapacity < newCapacity)
targetCapacity *= 2;
reserveImpl(targetCapacity);
}
}
void resize(UInt32 newSize, const T &newItem = T())
{
if (newSize > fSize)
{
reserve(newSize);
for(UInt32 i = fSize; i < newSize; ++i)
NEW(fData + i) T(newItem);
}
else if (newSize < fSize)
{
for(UInt32 i = newSize; i < fSize; ++i)
fData[i].~T();
}
fSize = newSize;
}
private:
void reserveImpl(UInt32 newCapacity)
{
T *newData = static_cast<T *>(operator new[](sizeof(T) * newCapacity));
fCapacity = newCapacity;
for(UInt32 i = 0; i < fSize; ++i)
NEW (newData + i) T(fData[i]);
operator delete[](fData);
fData = newData;
}
UInt32 fCapacity;
UInt32 fSize;
T *fData;
struct EqualOp
{
bool operator()(const T &left, const T &right) { return left == right; }
};
};
#endif //_SVECTOR_H_

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: SafeStdLib.h
Contains: Thread safe std lib calls
*/
#ifndef _INTERNAL_STDLIB_H_
#define _INTERNAL_STDLIB_H_
#include <time.h>
#include "OSHeaders.h"
#define kTimeStrSize 32
#define kErrorStrSize 256
extern int qtss_maxprintf(const char *fmt, ...);
extern void qtss_setmaxprintfcharsinK(UInt32 newMaxCharsInK);
extern UInt32 qtss_getmaxprintfcharsinK();
#ifndef USE_DEFAULT_STD_LIB
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __USE_MAX_PRINTF__
#define qtss_printf qtss_maxprintf
#else
extern int qtss_printf(const char *fmt, ...);
#endif
extern int qtss_sprintf(char *buffer, const char *fmt,...);
extern int qtss_fprintf(FILE *file, const char *fmt, ...);
extern int qtss_snprintf(char *str, size_t size, const char *format, ...);
extern size_t qtss_strftime(char *buf, size_t maxsize, const char *format, const struct tm *timeptr);
// These calls return the pointer passed into the call as the result.
extern char *qtss_strerror(int errnum, char* buffer, int buffLen);
extern char *qtss_ctime(const time_t *timep, char* buffer, int buffLen);
extern char *qtss_asctime(const struct tm *timeptr, char* buffer, int buffLen);
extern struct tm *qtss_gmtime (const time_t *, struct tm *result);
extern struct tm *qtss_localtime (const time_t *, struct tm *result);
#ifdef __cplusplus
}
#endif
#else //USE_DEFAULT_STD_LIB
#define qtss_sprintf sprintf
#define qtss_fprintf fprintf
#ifdef __USE_MAX_PRINTF__
#define qtss_printf qtss_maxprintf
#else
#define qtss_printf printf
#endif
#if __Win32__
#define qtss_snprintf _snprintf
#else
#define qtss_snprintf snprintf
#endif
#define qtss_strftime strftime
// Use our calls for the following.
// These calls return the pointer passed into the call as the result.
extern char *qtss_strerror(int errnum, char* buffer, int buffLen);
extern char *qtss_ctime(const time_t *timep, char* buffer, int buffLen);
extern char *qtss_asctime(const struct tm *timeptr, char* buffer, int buffLen);
extern struct tm *qtss_gmtime (const time_t *, struct tm *result);
extern struct tm *qtss_localtime (const time_t *, struct tm *result);
#endif //USE_DEFAULT_STD_LIB
#endif //_INTERNAL_STDLIB_H_

View file

@ -0,0 +1,391 @@
/*
*
* @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: Socket.cpp
Contains: implements Socket class
*/
#include <string.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <unistd.h>
#include <netinet/tcp.h>
#endif
#include <errno.h>
#include "Socket.h"
#include "SocketUtils.h"
#include "OSMemory.h"
#ifdef USE_NETLOG
#include <netlog.h>
#else
#if defined(__Win32__) || defined(__sgi__) || defined(__osf__) || defined(__hpux__)
typedef int socklen_t; // missing from some platform includes
#endif
#endif
EventThread* Socket::sEventThread = NULL;
Socket::Socket(Task *notifytask, UInt32 inSocketType)
: EventContext(EventContext::kInvalidFileDesc, sEventThread),
fState(inSocketType),
fLocalAddrStrPtr(NULL),
fLocalDNSStrPtr(NULL),
fPortStr(fPortBuffer, kPortBufSizeInBytes)
{
fLocalAddr.sin_addr.s_addr = 0;
fLocalAddr.sin_port = 0;
fDestAddr.sin_addr.s_addr = 0;
fDestAddr.sin_port = 0;
this->SetTask(notifytask);
#if SOCKET_DEBUG
fLocalAddrStr.Set(fLocalAddrBuffer,sizeof(fLocalAddrBuffer));
#endif
}
OS_Error Socket::Open(int theType)
{
Assert(fFileDesc == EventContext::kInvalidFileDesc);
fFileDesc = ::socket(PF_INET, theType, 0);
if (fFileDesc == EventContext::kInvalidFileDesc)
return (OS_Error)OSThread::GetErrno();
//
// Setup this socket's event context
if (fState & kNonBlockingSocketType)
this->InitNonBlocking(fFileDesc);
return OS_NoErr;
}
void Socket::ReuseAddr()
{
int one = 1;
int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(int));
Assert(err == 0);
}
void Socket::NoDelay()
{
int one = 1;
int err = ::setsockopt(fFileDesc, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int));
Assert(err == 0);
}
void Socket::KeepAlive()
{
int one = 1;
int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(int));
Assert(err == 0);
}
void Socket::SetSocketBufSize(UInt32 inNewSize)
{
#if SOCKET_DEBUG
int value;
int buffSize = sizeof(value);
int error = ::getsockopt(fFileDesc, SOL_SOCKET, SO_SNDBUF, (void*)&value, (socklen_t*)&buffSize);
#endif
int bufSize = inNewSize;
int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, sizeof(int));
AssertV(err == 0, OSThread::GetErrno());
#if SOCKET_DEBUG
int setValue;
error = ::getsockopt(fFileDesc, SOL_SOCKET, SO_SNDBUF, (void*)&setValue, (socklen_t*)&buffSize);
qtss_printf("Socket::SetSocketBufSize ");
if (fState & kBound)
{ if (NULL != this->GetLocalAddrStr())
this->GetLocalAddrStr()->PrintStr(":");
if (NULL != this->GetLocalPortStr())
this->GetLocalPortStr()->PrintStr(" ");
}
else
qtss_printf("unbound ");
qtss_printf("socket=%d old SO_SNDBUF =%d inNewSize=%d setValue=%d\n", (int) fFileDesc, value, bufSize, setValue);
#endif
}
OS_Error Socket::SetSocketRcvBufSize(UInt32 inNewSize)
{
#if SOCKET_DEBUG
int value;
int buffSize = sizeof(value);
int error = ::getsockopt(fFileDesc, SOL_SOCKET, SO_RCVBUF, (void*)&value, (socklen_t*)&buffSize);
#endif
int bufSize = inNewSize;
int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_RCVBUF, (char*)&bufSize, sizeof(int));
#if SOCKET_DEBUG
int setValue;
error = ::getsockopt(fFileDesc, SOL_SOCKET, SO_RCVBUF, (void*)&setValue, (socklen_t*)&buffSize);
qtss_printf("Socket::SetSocketRcvBufSize ");
if (fState & kBound)
{ if (NULL != this->GetLocalAddrStr())
this->GetLocalAddrStr()->PrintStr(":");
if (NULL != this->GetLocalPortStr())
this->GetLocalPortStr()->PrintStr(" ");
}
else
qtss_printf("unbound ");
qtss_printf("socket=%d old SO_RCVBUF =%d inNewSize=%d setValue=%d\n",(int) fFileDesc, value, bufSize, setValue);
#endif
if (err == -1)
return OSThread::GetErrno();
return OS_NoErr;
}
OS_Error Socket::Bind(UInt32 addr, UInt16 port, UInt16 test)
{
socklen_t len = sizeof(fLocalAddr);
::memset(&fLocalAddr, 0, sizeof(fLocalAddr));
fLocalAddr.sin_family = AF_INET;
fLocalAddr.sin_port = htons(port);
fLocalAddr.sin_addr.s_addr = htonl(addr);
int err;
#if 0
if (test) // pick some ports or conditions to return an error on.
{
if (6971 == port)
{
fLocalAddr.sin_port = 0;
fLocalAddr.sin_addr.s_addr = 0;
return EINVAL;
}
else
{
err = ::bind(fFileDesc, (sockaddr *)&fLocalAddr, sizeof(fLocalAddr));
}
}
else
#endif
err = ::bind(fFileDesc, (sockaddr *)&fLocalAddr, sizeof(fLocalAddr));
if (err == -1)
{
fLocalAddr.sin_port = 0;
fLocalAddr.sin_addr.s_addr = 0;
return (OS_Error)OSThread::GetErrno();
}
else ::getsockname(fFileDesc, (sockaddr *)&fLocalAddr, &len); // get the kernel to fill in unspecified values
fState |= kBound;
return OS_NoErr;
}
StrPtrLen* Socket::GetLocalAddrStr()
{
//Use the array of IP addr strings to locate the string formatted version
//of this IP address.
if (fLocalAddrStrPtr == NULL)
{
for (UInt32 x = 0; x < SocketUtils::GetNumIPAddrs(); x++)
{
if (SocketUtils::GetIPAddr(x) == ntohl(fLocalAddr.sin_addr.s_addr))
{
fLocalAddrStrPtr = SocketUtils::GetIPAddrStr(x);
break;
}
}
}
#if SOCKET_DEBUG
if (fLocalAddrStrPtr == NULL)
{ // shouldn't happen but no match so it was probably a failed socket connection or accept. addr is probably 0.
fLocalAddrBuffer[0]=0;
fLocalAddrStrPtr = &fLocalAddrStr;
struct in_addr theAddr;
theAddr.s_addr =ntohl(fLocalAddr.sin_addr.s_addr);
SocketUtils::ConvertAddrToString(theAddr, &fLocalAddrStr);
printf("Socket::GetLocalAddrStr Search IPs failed, numIPs=%d\n",SocketUtils::GetNumIPAddrs());
for (UInt32 x = 0; x < SocketUtils::GetNumIPAddrs(); x++)
{ printf("ip[%"_U32BITARG_"]=",x); SocketUtils::GetIPAddrStr(x)->PrintStr("\n");
}
printf("this ip = %d = ",theAddr.s_addr); fLocalAddrStrPtr->PrintStr("\n");
if (theAddr.s_addr == 0 || fLocalAddrBuffer[0] == 0)
fLocalAddrStrPtr = NULL; // so the caller can test for failure
}
#endif
Assert(fLocalAddrStrPtr != NULL);
return fLocalAddrStrPtr;
}
StrPtrLen* Socket::GetLocalDNSStr()
{
//Do the same thing as the above function, but for DNS names
Assert(fLocalAddr.sin_addr.s_addr != INADDR_ANY);
if (fLocalDNSStrPtr == NULL)
{
for (UInt32 x = 0; x < SocketUtils::GetNumIPAddrs(); x++)
{
if (SocketUtils::GetIPAddr(x) == ntohl(fLocalAddr.sin_addr.s_addr))
{
fLocalDNSStrPtr = SocketUtils::GetDNSNameStr(x);
break;
}
}
}
//if we weren't able to get this DNS name, make the DNS name the same as the IP addr str.
if (fLocalDNSStrPtr == NULL)
fLocalDNSStrPtr = this->GetLocalAddrStr();
Assert(fLocalDNSStrPtr != NULL);
return fLocalDNSStrPtr;
}
StrPtrLen* Socket::GetLocalPortStr()
{
if (fPortStr.Len == kPortBufSizeInBytes)
{
int temp = ntohs(fLocalAddr.sin_port);
qtss_sprintf(fPortBuffer, "%d", temp);
fPortStr.Len = ::strlen(fPortBuffer);
}
return &fPortStr;
}
OS_Error Socket::Send(const char* inData, const UInt32 inLength, UInt32* outLengthSent)
{
Assert(inData != NULL);
if (!(fState & kConnected))
return (OS_Error)ENOTCONN;
int err;
do {
err = ::send(fFileDesc, inData, inLength, 0);//flags??
} while((err == -1) && (OSThread::GetErrno() == EINTR));
if (err == -1)
{
//Are there any errors that can happen if the client is connected?
//Yes... EAGAIN. Means the socket is now flow-controleld
int theErr = OSThread::GetErrno();
if ((theErr != EAGAIN) && (this->IsConnected()))
fState ^= kConnected;//turn off connected state flag
return (OS_Error)theErr;
}
*outLengthSent = err;
return OS_NoErr;
}
OS_Error Socket::WriteV(const struct iovec* iov, const UInt32 numIOvecs, UInt32* outLenSent)
{
Assert(iov != NULL);
if (!(fState & kConnected))
return (OS_Error)ENOTCONN;
int err;
do {
#ifdef __Win32__
DWORD theBytesSent = 0;
err = ::WSASend(fFileDesc, (LPWSABUF)iov, numIOvecs, &theBytesSent, 0, NULL, NULL);
if (err == 0)
err = theBytesSent;
#else
err = ::writev(fFileDesc, iov, numIOvecs);//flags??
#endif
} while((err == -1) && (OSThread::GetErrno() == EINTR));
if (err == -1)
{
// Are there any errors that can happen if the client is connected?
// Yes... EAGAIN. Means the socket is now flow-controleld
int theErr = OSThread::GetErrno();
if ((theErr != EAGAIN) && (this->IsConnected()))
fState ^= kConnected;//turn off connected state flag
return (OS_Error)theErr;
}
if (outLenSent != NULL)
*outLenSent = (UInt32)err;
return OS_NoErr;
}
OS_Error Socket::Read(void *buffer, const UInt32 length, UInt32 *outRecvLenP)
{
Assert(outRecvLenP != NULL);
Assert(buffer != NULL);
if (!(fState & kConnected))
return (OS_Error)ENOTCONN;
//int theRecvLen = ::recv(fFileDesc, buffer, length, 0);//flags??
int theRecvLen;
do {
theRecvLen = ::recv(fFileDesc, (char*)buffer, length, 0);//flags??
} while((theRecvLen == -1) && (OSThread::GetErrno() == EINTR));
if (theRecvLen == -1)
{
// Are there any errors that can happen if the client is connected?
// Yes... EAGAIN. Means the socket is now flow-controleld
int theErr = OSThread::GetErrno();
if ((theErr != EAGAIN) && (this->IsConnected()))
fState ^= kConnected;//turn off connected state flag
return (OS_Error)theErr;
}
//if we get 0 bytes back from read, that means the client has disconnected.
//Note that and return the proper error to the caller
else if (theRecvLen == 0)
{
fState ^= kConnected;
return (OS_Error)ENOTCONN;
}
Assert(theRecvLen > 0);
*outRecvLenP = (UInt32)theRecvLen;
return OS_NoErr;
}

160
CommonUtilitiesLib/Socket.h Normal file
View file

@ -0,0 +1,160 @@
/*
*
* @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: Socket.h
Contains: Provides a simple, object oriented socket abstraction, also
hides the details of socket event handling. Sockets can post
events (such as S_DATA, S_CONNECTIONCLOSED) to Tasks.
*/
#ifndef __SOCKET_H__
#define __SOCKET_H__
#ifndef __Win32__
#include <netinet/in.h>
#endif
#include "EventContext.h"
#include "ev.h"
#define SOCKET_DEBUG 1
//#define SOCKET_DEBUG 0
class Socket : public EventContext
{
public:
enum
{
// Pass this in on socket constructors to specify whether the
// socket should be non-blocking or blocking
kNonBlockingSocketType = 1
};
// This class provides a global event thread.
static void Initialize() { sEventThread = new EventThread(); }
static void StartThread() { sEventThread->Start(); }
static EventThread* GetEventThread() { return sEventThread; }
//Binds the socket to the following address.
//Returns: QTSS_FileNotOpen, QTSS_NoErr, or POSIX errorcode.
OS_Error Bind(UInt32 addr, UInt16 port,Bool16 test = false);
//The same. but in reverse
void Unbind();
void ReuseAddr();
void NoDelay();
void KeepAlive();
void SetSocketBufSize(UInt32 inNewSize);
//
// Returns an error if the socket buffer size is too big
OS_Error SetSocketRcvBufSize(UInt32 inNewSize);
//Send
//Returns: QTSS_FileNotOpen, QTSS_NoErr, or POSIX errorcode.
OS_Error Send(const char* inData, const UInt32 inLength, UInt32* outLengthSent);
//Read
//Reads some data.
//Returns: QTSS_FileNotOpen, QTSS_NoErr, or POSIX errorcode.
OS_Error Read(void *buffer, const UInt32 length, UInt32 *rcvLen);
//WriteV: same as send, but takes an iovec
//Returns: QTSS_FileNotOpen, QTSS_NoErr, or POSIX errorcode.
OS_Error WriteV(const struct iovec* iov, const UInt32 numIOvecs, UInt32* outLengthSent);
//You can query for the socket's state
Bool16 IsConnected() { return (Bool16) (fState & kConnected); }
Bool16 IsBound() { return (Bool16) (fState & kBound); }
//If the socket is bound, you may find out to which addr it is bound
UInt32 GetLocalAddr() { return ntohl(fLocalAddr.sin_addr.s_addr); }
UInt16 GetLocalPort() { return ntohs(fLocalAddr.sin_port); }
StrPtrLen* GetLocalAddrStr();
StrPtrLen* GetLocalPortStr();
StrPtrLen* GetLocalDNSStr();
enum
{
kMaxNumSockets = 4096 //UInt32
};
protected:
//TCPSocket takes an optional task object which will get notified when
//certain events happen on this socket. Those events are:
//
//S_DATA: Data is currently available on the socket.
//S_CONNECTIONCLOSING: Client is closing the connection. No longer necessary
// to call Close or Disconnect, Snd & Rcv will fail.
Socket(Task *notifytask, UInt32 inSocketType);
virtual ~Socket() {}
//returns QTSS_NoErr, or appropriate posix error
OS_Error Open(int theType);
UInt32 fState;
enum
{
kPortBufSizeInBytes = 8, //UInt32
kMaxIPAddrSizeInBytes = 20 //UInt32
};
#if SOCKET_DEBUG
StrPtrLen fLocalAddrStr;
char fLocalAddrBuffer[kMaxIPAddrSizeInBytes];
#endif
//address information (available if bound)
//these are always stored in network order. Conver
struct sockaddr_in fLocalAddr;
struct sockaddr_in fDestAddr;
StrPtrLen* fLocalAddrStrPtr;
StrPtrLen* fLocalDNSStrPtr;
char fPortBuffer[kPortBufSizeInBytes];
StrPtrLen fPortStr;
//State flags. Be careful when changing these values, as subclasses add their own
enum
{
kBound = 0x0004,
kConnected = 0x0008
};
static EventThread* sEventThread;
};
#endif // __SOCKET_H__

View file

@ -0,0 +1,605 @@
/*
*
* @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: SocketUtils.cpp
Contains: Implements utility functions defined in SocketUtils.h
*/
#include <string.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#if __FreeBSD__
#include <ifaddrs.h>
#endif
#include <unistd.h>
#include <sys/utsname.h>
#if __solaris__
#include <sys/sockio.h>
#endif
#endif
#include "SocketUtils.h"
#ifdef SIOCGIFNUM
#define USE_SIOCGIFNUM 1
#endif
#ifdef TRUCLUSTER /* Tru64 Cluster Alias support */
#include <clua/clua.h>
#include <sys/clu.h>
static clua_status_t (*clua_getaliasaddress_vector) (struct sockaddr *, int *);
static char *(*clua_error_vector) (clua_status_t);
#define clua_getaliasaddress (*clua_getaliasaddress_vector)
#define clua_error (*clua_error_vector)
struct clucall_vector clua_vectors[] = {
{ "clua_getaliasaddress", &clua_getaliasaddress_vector },
{ "clua_error", &clua_error_vector },
{ NULL, NULL } /* END OF LIST */
};
#endif /* TRUCLUSTER */
UInt32 SocketUtils::sNumIPAddrs = 0;
SocketUtils::IPAddrInfo* SocketUtils::sIPAddrInfoArray = NULL;
OSMutex SocketUtils::sMutex;
#if __FreeBSD__
//Complete rewrite for FreeBSD.
//The non-FreeBSD version really needs to be rewritten - it's a bit of a mess...
void SocketUtils::Initialize(Bool16 lookupDNSName)
{
struct ifaddrs* ifap;
struct ifaddrs* currentifap;
struct sockaddr_in* sockaddr;
int result = 0;
result = getifaddrs(&ifap);
//Count them first
currentifap = ifap;
while( currentifap != NULL )
{
sockaddr = (struct sockaddr_in*)currentifap->ifa_addr;
if (sockaddr->sin_family == AF_INET)
sNumIPAddrs++;
currentifap = currentifap->ifa_next;
}
//allocate the IPAddrInfo array. Unfortunately we can't allocate this
//array the proper way due to a GCC bug
UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs];
::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs);
sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem;
int addrArrayIndex = 0;
currentifap = ifap;
while( currentifap != NULL )
{
sockaddr = (struct sockaddr_in*)currentifap->ifa_addr;
if (sockaddr->sin_family == AF_INET)
{
char* theAddrStr = ::inet_ntoa(sockaddr->sin_addr);
//store the IP addr
sIPAddrInfoArray[addrArrayIndex].fIPAddr = ntohl(sockaddr->sin_addr.s_addr);
//store the IP addr as a string
sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Len + 2];
::strcpy(sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Ptr, theAddrStr);
struct hostent* theDNSName = NULL;
if (lookupDNSName) //convert this addr to a dns name, and store it
{ theDNSName = ::gethostbyaddr((char *)&sockaddr->sin_addr, sizeof(sockaddr->sin_addr), AF_INET);
}
if (theDNSName != NULL)
{
sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr, theDNSName->h_name);
}
else
{
//if we failed to look up the DNS name, just store the IP addr as a string
sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Len = sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Len;
sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Ptr);
}
addrArrayIndex++;
}
currentifap = currentifap->ifa_next;
}
}
#else //__FreeBSD__
//Version for all non-FreeBSD platforms.
void SocketUtils::Initialize(Bool16 lookupDNSName)
{
#if defined(__Win32__) || defined(USE_SIOCGIFNUM)
int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (tempSocket == -1)
return;
#ifdef __Win32__
static const UInt32 kMaxAddrBufferSize = 2048;
char inBuffer[kMaxAddrBufferSize];
char outBuffer[kMaxAddrBufferSize];
UInt32 theReturnedSize = 0;
//
// Use the WSAIoctl function call to get a list of IP addresses
int theErr = ::WSAIoctl( tempSocket, SIO_GET_INTERFACE_LIST,
inBuffer, kMaxAddrBufferSize,
outBuffer, kMaxAddrBufferSize,
&theReturnedSize,
NULL,
NULL);
Assert(theErr == 0);
if (theErr != 0)
return;
Assert((theReturnedSize % sizeof(INTERFACE_INFO)) == 0);
LPINTERFACE_INFO addrListP = (LPINTERFACE_INFO)&outBuffer[0];
sNumIPAddrs = theReturnedSize / sizeof(INTERFACE_INFO);
#else
#if defined(USE_SIOCGIFNUM)
if (::ioctl(tempSocket, SIOCGIFNUM, (char*)&sNumIPAddrs) == -1)
{
#ifdef MAXIFS
sNumIPAddrs = MAXIFS;
#else
sNumIPAddrs = 64;
#endif
}
#else
#error
#endif
struct ifconf ifc;
::memset(&ifc,0,sizeof(ifc));
ifc.ifc_len = sNumIPAddrs * sizeof(struct ifreq);
ifc.ifc_buf = (caddr_t)new struct ifreq[sNumIPAddrs];
Assert(ifc.ifc_buf != NULL);
::memset(ifc.ifc_buf, '\0', ifc.ifc_len);
int theErr = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
Assert(theErr == 0);
if (theErr != 0)
return;
struct ifreq* ifr = (struct ifreq*)ifc.ifc_buf;
#endif
//allocate the IPAddrInfo array. Unfortunately we can't allocate this
//array the proper way due to a GCC bug
UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs];
::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs);
sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem;
//for (UInt32 addrCount = 0; addrCount < sNumIPAddrs; addrCount++)
UInt32 currentIndex = 0;
for (UInt32 theIfCount = sNumIPAddrs, addrCount = 0;
addrCount < theIfCount; addrCount++)
{
#ifdef __Win32__
// We *should* count the loopback interface as a valid interface.
//if (addrListP[addrCount].iiFlags & IFF_LOOPBACK)
//{
// Don't count loopback addrs
// sNumIPAddrs--;
// continue;
//}
//if (addrListP[addrCount].iiFlags & IFF_LOOPBACK)
// if (lookupDNSName) // The playlist broadcaster doesn't care
// Assert(addrCount > 0); // If the loopback interface is interface 0, we've got problems
struct sockaddr_in* theAddr = (struct sockaddr_in*)&addrListP[addrCount].iiAddress;
#elif defined(USE_SIOCGIFNUM)
if (ifr[addrCount].ifr_addr.sa_family != AF_INET)
{
sNumIPAddrs--;
continue;
}
struct ifreq ifrf;
::memset(&ifrf,0,sizeof(ifrf));
::strncpy(ifrf.ifr_name, ifr[addrCount].ifr_name, sizeof(ifrf.ifr_name));
theErr = ::ioctl(tempSocket, SIOCGIFFLAGS, (char *) &ifrf);
Assert(theErr != -1);
#ifndef __solaris__
/* Skip things which aren't interesting */
if ((ifrf.ifr_flags & IFF_UP) == 0 ||
(ifrf.ifr_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0)
{
sNumIPAddrs--;
continue;
}
if (ifrf.ifr_flags & IFF_LOOPBACK)
{
Assert(addrCount > 0); // If the loopback interface is interface 0, we've got problems
}
#endif
struct sockaddr_in* theAddr = (struct sockaddr_in*)&ifr[addrCount].ifr_addr;
#if 0
puts(ifr[addrCount].ifr_name);
#endif
#else
#error
#endif
char* theAddrStr = ::inet_ntoa(theAddr->sin_addr);
//store the IP addr
sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(theAddr->sin_addr.s_addr);
//store the IP addr as a string
sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr);
struct hostent* theDNSName = NULL;
if (lookupDNSName) //convert this addr to a dns name, and store it
{ theDNSName = ::gethostbyaddr((char *)&theAddr->sin_addr, sizeof(theAddr->sin_addr), AF_INET);
}
if (theDNSName != NULL)
{
sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name);
}
else
{
//if we failed to look up the DNS name, just store the IP addr as a string
sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len;
sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr);
}
//move onto the next array index
currentIndex++;
}
#ifdef __Win32__
::closesocket(tempSocket);
#elif defined(USE_SIOCGIFNUM)
delete[] ifc.ifc_buf;
::close(tempSocket);
#else
#error
#endif
#else // !__Win32__
//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;
struct ifconf ifc;
::memset(&ifc,0,sizeof(ifc));
struct ifreq* ifr;
char buffer[kMaxAddrBufferSize];
int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (tempSocket == -1)
return;
ifc.ifc_len = kMaxAddrBufferSize;
ifc.ifc_buf = buffer;
#if __linux__ || __linuxppc__ || __solaris__ || __MacOSX__ || __sgi__ || __osf__
int err = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
#elif __FreeBSD__
int err = ::ioctl(tempSocket, OSIOCGIFCONF, (char*)&ifc);
#else
#error
#endif
if (err == -1)
return;
#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;
//walk through the list of IP addrs twice. Once to find out how many,
//the second time to actually grab their information
char* ifReqIter = NULL;
sNumIPAddrs = 0;
for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
{
ifr = (struct ifreq*)ifReqIter;
if (!SocketUtils::IncrementIfReqIter(&ifReqIter, ifr))
return;
// Some platforms have lo as the first interface, so we have code to
// work around this problem below
//if (::strncmp(ifr->ifr_name, "lo", 2) == 0)
// Assert(sNumIPAddrs > 0); // If the loopback interface is interface 0, we've got problems
//Only count interfaces in the AF_INET family.
if (ifr->ifr_addr.sa_family == AF_INET)
sNumIPAddrs++;
}
#ifdef TRUCLUSTER
int clusterAliases = 0;
if (clu_is_member())
{
/* loading the vector table */
if (clua_getaliasaddress_vector == NULL)
{
clucall_stat clustat;
struct sockaddr_in sin;
clustat = clucall_load("libclua.so", clua_vectors);
int context = 0;
clua_status_t addr_err;
if (clua_getaliasaddress_vector != NULL)
while ( (addr_err = clua_getaliasaddress
((struct sockaddr*)&sin, &context)) == CLUA_SUCCESS )
{
sNumIPAddrs++;
clusterAliases++;
}
}
}
#endif // TRUCLUSTER
//allocate the IPAddrInfo array. Unfortunately we can't allocate this
//array the proper way due to a GCC bug
UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs];
::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs);
sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem;
//Now extract all the necessary information about each interface
//and put it into the array
UInt32 currentIndex = 0;
#ifdef TRUCLUSTER
// Do these cluster aliases first so they'll be first in the list
if (clusterAliases > 0)
{
int context = 0;
struct sockaddr_in sin;
clua_status_t addr_err;
while ( (addr_err = clua_getaliasaddress ((struct sockaddr*)&sin, &context)) == CLUA_SUCCESS )
{
char* theAddrStr = ::inet_ntoa(sin.sin_addr);
//store the IP addr
sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(sin.sin_addr.s_addr);
//store the IP addr as a string
sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr);
//convert this addr to a dns name, and store it
struct hostent* theDNSName = ::gethostbyaddr((char *)&sin.sin_addr,
sizeof(sin.sin_addr), AF_INET);
if (theDNSName != NULL)
{
sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name);
}
else
{
//if we failed to look up the DNS name, just store the IP addr as a string
sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len;
sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr);
}
currentIndex++;
}
}
#endif // TRUCLUSTER
for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
{
ifr = (struct ifreq*)ifReqIter;
if (!SocketUtils::IncrementIfReqIter(&ifReqIter, ifr))
{
Assert(0);//we should have already detected this error
return;
}
//Only count interfaces in the AF_INET family
if (ifr->ifr_addr.sa_family == AF_INET)
{
struct sockaddr_in* addrPtr = (struct sockaddr_in*)&ifr->ifr_addr;
char* theAddrStr = ::inet_ntoa(addrPtr->sin_addr);
//store the IP addr
sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(addrPtr->sin_addr.s_addr);
//store the IP addr as a string
sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr);
struct hostent* theDNSName = NULL;
if (lookupDNSName) //convert this addr to a dns name, and store it
{ theDNSName = ::gethostbyaddr((char *)&addrPtr->sin_addr, sizeof(addrPtr->sin_addr), AF_INET);
}
if (theDNSName != NULL)
{
sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name);
}
else
{
//if we failed to look up the DNS name, just store the IP addr as a string
sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len;
sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr);
}
//move onto the next array index
currentIndex++;
}
}
Assert(currentIndex == sNumIPAddrs);
#endif
//
// If LocalHost is the first element in the array, switch it to be the second.
// The first element is supposed to be the "default" interface on the machine,
// which should really always be en0.
if ((sNumIPAddrs > 1) && (::strcmp(sIPAddrInfoArray[0].fIPAddrStr.Ptr, "127.0.0.1") == 0))
{
UInt32 tempIP = sIPAddrInfoArray[1].fIPAddr;
sIPAddrInfoArray[1].fIPAddr = sIPAddrInfoArray[0].fIPAddr;
sIPAddrInfoArray[0].fIPAddr = tempIP;
StrPtrLen tempIPStr(sIPAddrInfoArray[1].fIPAddrStr);
sIPAddrInfoArray[1].fIPAddrStr = sIPAddrInfoArray[0].fIPAddrStr;
sIPAddrInfoArray[0].fIPAddrStr = tempIPStr;
StrPtrLen tempDNSStr(sIPAddrInfoArray[1].fDNSNameStr);
sIPAddrInfoArray[1].fDNSNameStr = sIPAddrInfoArray[0].fDNSNameStr;
sIPAddrInfoArray[0].fDNSNameStr = tempDNSStr;
}
}
#endif //__FreeBSD__
#ifndef __Win32__
Bool16 SocketUtils::IncrementIfReqIter(char** inIfReqIter, ifreq* ifr)
{
//returns true if successful, false otherwise
#if __MacOSX__
*inIfReqIter += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
//if the length of the addr is 0, use the family to determine
//what the addr size is
if (ifr->ifr_addr.sa_len == 0)
#else
*inIfReqIter += sizeof(ifr->ifr_name) + 0;
#endif
{
switch (ifr->ifr_addr.sa_family)
{
case AF_INET:
*inIfReqIter += sizeof(struct sockaddr_in);
break;
default:
*inIfReqIter += sizeof(struct sockaddr);
// Assert(0);
// sNumIPAddrs = 0;
// return false;
}
}
return true;
}
#endif
Bool16 SocketUtils::IsMulticastIPAddr(UInt32 inAddress)
{
return ((inAddress>>8) & 0x00f00000) == 0x00e00000; // multicast addresses == "class D" == 0xExxxxxxx == 1,1,1,0,<28 bits>
}
Bool16 SocketUtils::IsLocalIPAddr(UInt32 inAddress)
{
for (UInt32 x = 0; x < sNumIPAddrs; x++)
if (sIPAddrInfoArray[x].fIPAddr == inAddress)
return true;
return false;
}
void SocketUtils::ConvertAddrToString(const struct in_addr& theAddr, StrPtrLen* ioStr)
{
//re-entrant version of code below
//inet_ntop(AF_INET, &theAddr, ioStr->Ptr, ioStr->Len);
//ioStr->Len = ::strlen(ioStr->Ptr);
sMutex.Lock();
char* addr = inet_ntoa(theAddr);
strcpy(ioStr->Ptr, addr);
ioStr->Len = ::strlen(ioStr->Ptr);
sMutex.Unlock();
}
UInt32 SocketUtils::ConvertStringToAddr(const char* inAddrStr)
{
if (inAddrStr == NULL)
return 0;
return ntohl(::inet_addr(inAddrStr));
}

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: SocketUtils.h
Contains: Some static routines for dealing with networking
*/
#ifndef __SOCKETUTILS_H__
#define __SOCKETUTILS_H__
#ifndef __Win32__
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#endif
#include "ev.h"
#include "OSHeaders.h"
#include "MyAssert.h"
#include "StrPtrLen.h"
#include "OSMutex.h"
#ifdef __solaris__
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff /* -1 return from inet_addr */
#endif
#endif
class SocketUtils
{
public:
// Call initialize before using any socket functions.
// (pass true for lookupDNSName if you want the hostname
// looked up via DNS during initialization -- %%sfu)
static void Initialize(Bool16 lookupDNSName = true);
//static utility routines
static Bool16 IsMulticastIPAddr(UInt32 inAddress);
static Bool16 IsLocalIPAddr(UInt32 inAddress);
//This function converts an integer IP address to a dotted-decimal string.
//This function is NOT THREAD SAFE!!!
static void ConvertAddrToString(const struct in_addr& theAddr, StrPtrLen* outAddr);
// This function converts a dotted-decimal string IP address to a UInt32
static UInt32 ConvertStringToAddr(const char* inAddr);
//You can get at all the IP addrs and DNS names on this machine this way
static UInt32 GetNumIPAddrs() { return sNumIPAddrs; }
static inline UInt32 GetIPAddr(UInt32 inAddrIndex);
static inline StrPtrLen* GetIPAddrStr(UInt32 inAddrIndex);
static inline StrPtrLen* GetDNSNameStr(UInt32 inDNSIndex);
private:
//Utility function used by Initialize
#ifndef __Win32__
static Bool16 IncrementIfReqIter(char** inIfReqIter, ifreq* ifr);
#endif
//For storing relevent information about each IP interface
struct IPAddrInfo
{
UInt32 fIPAddr;
StrPtrLen fIPAddrStr;
StrPtrLen fDNSNameStr;
};
static IPAddrInfo* sIPAddrInfoArray;
static UInt32 sNumIPAddrs;
static OSMutex sMutex;
};
inline UInt32 SocketUtils::GetIPAddr(UInt32 inAddrIndex)
{
Assert(sIPAddrInfoArray != NULL);
Assert(inAddrIndex < sNumIPAddrs);
return sIPAddrInfoArray[inAddrIndex].fIPAddr;
}
inline StrPtrLen* SocketUtils::GetIPAddrStr(UInt32 inAddrIndex)
{
Assert(sIPAddrInfoArray != NULL);
Assert(inAddrIndex < sNumIPAddrs);
return &sIPAddrInfoArray[inAddrIndex].fIPAddrStr;
}
inline StrPtrLen* SocketUtils::GetDNSNameStr(UInt32 inDNSIndex)
{
Assert(sIPAddrInfoArray != NULL);
Assert(inDNSIndex < sNumIPAddrs);
return &sIPAddrInfoArray[inDNSIndex].fDNSNameStr;
}
#endif // __SOCKETUTILS_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: StopWatch.h
Contains: classes for stopwatch timers
*/
#include "OS.h"
class MilliSecondStopWatch {
public:
MilliSecondStopWatch () { fStartedAt = -1; fStoppedAt = -1; }
void Start() { fStartedAt = OS::Milliseconds(); }
void Stop() { fStoppedAt = OS::Milliseconds(); }
SInt64 Duration() { return fStoppedAt - fStartedAt; }
private:
SInt64 fStartedAt;
SInt64 fStoppedAt;
};
class MicroSecondStopWatch {
public:
MicroSecondStopWatch () { fStartedAt = -1; fStoppedAt = -1; }
void Start() { fStartedAt = OS::Microseconds(); }
void Stop() { fStoppedAt = OS::Microseconds(); }
SInt64 Duration() { return fStoppedAt - fStartedAt; }
private:
SInt64 fStartedAt;
SInt64 fStoppedAt;
};

View file

@ -0,0 +1,565 @@
/*
*
* @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: StrPtrLen.cpp
Contains: Implementation of class defined in StrPtrLen.h.
*/
#include <ctype.h>
#include "StrPtrLen.h"
#include "MyAssert.h"
#include "OS.h"
#include "OSMemory.h"
UInt8 StrPtrLen::sCaseInsensitiveMask[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, //0-9
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10-19
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, //20-29
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, //30-39
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, //40-49
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, //50-59
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, //60-69 //stop on every character except a letter
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, //70-79
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, //80-89
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, //90-99
100, 101, 102, 103, 104, 105, 106, 107, 108, 109, //100-109
110, 111, 112, 113, 114, 115, 116, 117, 118, 119, //110-119
120, 121, 122, 123, 124, 125, 126, 127, 128, 129 //120-129
};
UInt8 StrPtrLen::sNonPrintChars[] =
{
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, //0-9 // stop
0, 1, 1, 0, 1, 1, 1, 1, 1, 1, //10-19 //'\r' & '\n' are not stop conditions
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //20-29
1, 1, 0, 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, 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
};
char* StrPtrLen::GetAsCString() const
{
// convert to a "NEW'd" zero terminated char array
// caler is reponsible for the newly allocated memory
char *theString = NEW char[Len+1];
if ( Ptr && Len > 0 )
::memcpy( theString, Ptr, Len );
theString[Len] = 0;
return theString;
}
Bool16 StrPtrLen::Equal(const StrPtrLen &compare) const
{
if (NULL == compare.Ptr && NULL == Ptr )
return true;
if ((NULL == compare.Ptr) || (NULL == Ptr))
return false;
if ((compare.Len == Len) && (memcmp(compare.Ptr, Ptr, Len) == 0))
return true;
else
return false;
}
Bool16 StrPtrLen::Equal(const char* compare) const
{
if (NULL == compare && NULL == Ptr )
return true;
if ((NULL == compare) || (NULL == Ptr))
return false;
if ((::strlen(compare) == Len) && (memcmp(compare, Ptr, Len) == 0))
return true;
else
return false;
}
Bool16 StrPtrLen::NumEqualIgnoreCase(const char* compare, const UInt32 len) const
{
// compare thru the first "len: bytes
Assert(compare != NULL);
if (len <= Len)
{
for (UInt32 x = 0; x < len; x++)
if (sCaseInsensitiveMask[ (UInt8) Ptr[x]] != sCaseInsensitiveMask[(UInt8) compare[x]])
return false;
return true;
}
return false;
}
Bool16 StrPtrLen::EqualIgnoreCase(const char* compare, const UInt32 len) const
{
Assert(compare != NULL);
if (len == Len)
{
for (UInt32 x = 0; x < len; x++)
if (sCaseInsensitiveMask[(UInt8) Ptr[x]] != sCaseInsensitiveMask[(UInt8) compare[x]])
return false;
return true;
}
return false;
}
char *StrPtrLen::FindStringCase(char *queryCharStr, StrPtrLen *resultStr, Bool16 caseSensitive) const
{
// Be careful about exiting this method from the middle. This routine deletes allocated memory at the end.
//
if (resultStr)
resultStr->Set(NULL,0);
Assert (NULL != queryCharStr);
if (NULL == queryCharStr) return NULL;
if (NULL == Ptr) return NULL;
if (0 == Len) return NULL;
StrPtrLen queryStr(queryCharStr);
char *editSource = NULL;
char *resultChar = NULL;
char lastSourceChar = Ptr[Len -1];
if (lastSourceChar != 0) // need to modify for termination.
{ editSource = NEW char[Len + 1]; // Ptr could be a static string so make a copy
::memcpy( editSource, Ptr, Len );
editSource[Len] = 0; // this won't work on static strings so we are modifing a new string here
}
char *queryString = queryCharStr;
char *dupSourceString = NULL;
char *dupQueryString = NULL;
char *sourceString = Ptr;
UInt32 foundLen = 0;
if (editSource != NULL) // a copy of the source ptr and len 0 terminated
sourceString = editSource;
if (!caseSensitive)
{ dupSourceString = ::strdup(sourceString);
dupQueryString = ::strdup(queryCharStr);
if (dupSourceString && dupQueryString)
{ sourceString = StrPtrLen(dupSourceString).ToUpper();
queryString = StrPtrLen(dupQueryString).ToUpper();
resultChar = ::strstr(sourceString,queryString);
::free(dupSourceString);
::free(dupQueryString);
}
}
else
{ resultChar = ::strstr(sourceString,queryString);
}
if (resultChar != NULL) // get the start offset
{ foundLen = resultChar - sourceString;
resultChar = Ptr + foundLen; // return a pointer in the source buffer
if (resultChar > (Ptr + Len)) // make sure it is in the buffer
resultChar = NULL;
}
if (editSource != NULL)
delete [] editSource;
if (resultStr != NULL && resultChar != NULL)
resultStr->Set(resultChar,queryStr.Len);
#if STRPTRLENTESTING
qtss_printf("StrPtrLen::FindStringCase found string=%s\n",resultChar);
#endif
return resultChar;
}
UInt32 StrPtrLen::RemoveWhitespace()
{
if (Ptr == NULL || Len == 0)
return 0;
char *EndPtr = Ptr + Len; // one past last char
char *destPtr = Ptr;
char *srcPtr = Ptr;
Len = 0;
while (srcPtr < EndPtr)
{
if (*srcPtr != ' ' && *srcPtr != '\t')
{
if (srcPtr != destPtr)
*destPtr = *srcPtr;
destPtr++;
Len ++;
}
srcPtr ++;
}
return Len;
}
UInt32 StrPtrLen::TrimLeadingWhitespace()
{
if (Ptr == NULL || Len == 0)
return 0;
char *EndPtr = Ptr + Len; //one past last char
while (Ptr < EndPtr)
{
if (*Ptr != ' ' && *Ptr != '\t')
break;
Ptr += 1;
Len -= 1;
}
return Len;
}
UInt32 StrPtrLen::TrimTrailingWhitespace()
{
if (Ptr == NULL || Len == 0)
return 0;
char *theCharPtr = Ptr + (Len - 1); // last char
while (theCharPtr >= Ptr)
{
if (*theCharPtr != ' ' && *theCharPtr != '\t')
break;
theCharPtr -= 1;
Len -= 1;
}
return Len;
}
void StrPtrLen::PrintStr()
{
char *thestr = GetAsCString();
UInt32 i = 0;
for (; i < Len; i ++)
{
if (StrPtrLen::sNonPrintChars[(UInt8) Ptr[i]])
{ thestr[i] = 0;
break;
}
}
if (thestr != NULL)
{
qtss_printf(thestr);
delete thestr;
}
}
void StrPtrLen::PrintStr(char *appendStr)
{
StrPtrLen::PrintStr();
if (appendStr != NULL)
qtss_printf(appendStr);
}
void StrPtrLen::PrintStr(char* prependStr, char *appendStr)
{
if (prependStr != NULL)
qtss_printf(prependStr);
StrPtrLen::PrintStr();
if (appendStr != NULL)
qtss_printf(appendStr);
}
void StrPtrLen::PrintStrEOL(char* stopStr, char *appendStr)
{
char *thestr = GetAsCString();
SInt32 i = 0;
for (; i < (SInt32) Len; i ++)
{
if (StrPtrLen::sNonPrintChars[(UInt8) Ptr[i]])
{ thestr[i] = 0;
break;
}
}
for (i = 0; thestr[i] != 0 ; i ++)
{
if (thestr[i] == '%' && thestr[i+1] != '%' )
{ thestr[i] = '$';
}
}
SInt32 stopLen = 0;
if (stopStr != NULL)
stopLen = ::strlen(stopStr);
if (stopLen > 0 && stopLen <= i)
{
char* stopPtr = ::strstr(thestr, stopStr);
if (stopPtr != NULL)
{ stopPtr += stopLen;
*stopPtr = 0;
i = stopPtr - thestr;
}
}
char * theStrLine = thestr;
char * nextLine = NULL;
char * theChar = NULL;
static char *cr="\\r";
static char *lf="\\n\n";
SInt32 tempLen = i;
for (i = 0; i < tempLen; i ++)
{
if (theStrLine[i] == '\r')
{ theChar = cr;
theStrLine[i] = 0;
nextLine = &theStrLine[i+1];
}
else if (theStrLine[i] == '\n')
{ theChar = lf;
theStrLine[i] = 0;
nextLine = &theStrLine[i+1];
}
if (nextLine != NULL)
{
qtss_printf(theStrLine);
qtss_printf(theChar);
theStrLine = nextLine;
nextLine = NULL;
tempLen -= (i+1);
i = -1;
}
}
qtss_printf(theStrLine);
delete thestr;
if (appendStr != NULL)
qtss_printf(appendStr);
}
#if STRPTRLENTESTING
Bool16 StrPtrLen::Test()
{
static char* test1 = "2347.;.][';[;]abcdefghijklmnopqrstuvwxyz#%#$$#";
static char* test2 = "2347.;.][';[;]ABCDEFGHIJKLMNOPQRSTUVWXYZ#%#$$#";
static char* test3 = "Content-Type:";
static char* test4 = "cONTent-TYPe:";
static char* test5 = "cONTnnt-TYPe:";
static char* test6 = "cONTent-TY";
static char* test7 = "ontent-Type:";
static char* test8 = "ONTent-TYPe:";
static char* test9 = "-TYPe:";
static char* test10 = ":";
StrPtrLen theVictim1(test1, strlen(test1));
if (!theVictim1.EqualIgnoreCase(test2, strlen(test2)))
return false;
if (theVictim1.EqualIgnoreCase(test3, strlen(test3)))
return false;
if (!theVictim1.EqualIgnoreCase(test1, strlen(test1)))
return false;
StrPtrLen theVictim2(test3, strlen(test3));
if (!theVictim2.EqualIgnoreCase(test4, strlen(test4)))
return false;
if (theVictim2.EqualIgnoreCase(test5, strlen(test5)))
return false;
if (theVictim2.EqualIgnoreCase(test6, strlen(test6)))
return false;
StrPtrLen outResultStr;
if (!theVictim1.FindStringIgnoreCase(test2, &outResultStr))
return false;
if (theVictim1.FindStringIgnoreCase(test3, &outResultStr))
return false;
if (!theVictim1.FindStringIgnoreCase(test1, &outResultStr))
return false;
if (!theVictim2.FindStringIgnoreCase(test4))
return false;
if (theVictim2.FindStringIgnoreCase(test5))
return false;
if (!theVictim2.FindStringIgnoreCase(test6))
return false;
if (!theVictim2.FindStringIgnoreCase(test7))
return false;
if (!theVictim2.FindStringIgnoreCase(test8))
return false;
if (!theVictim2.FindStringIgnoreCase(test9))
return false;
if (!theVictim2.FindStringIgnoreCase(test10))
return false;
if (theVictim1.FindString(test2, &outResultStr))
return false;
if (theVictim1.FindString(test3, &outResultStr))
return false;
if (!theVictim1.FindString(test1, &outResultStr))
return false;
if (theVictim2.FindString(test4))
return false;
if (theVictim2.FindString(test5))
return false;
if (theVictim2.FindString(test6))
return false;
if (!theVictim2.FindString(test7))
return false;
if (theVictim2.FindString(test8))
return false;
if (theVictim2.FindString(test9))
return false;
if (!theVictim2.FindString(test10))
return false;
StrPtrLen query;
query.Set(test2);
if (theVictim1.FindString(query, &outResultStr))
return false;
if (outResultStr.Len > 0)
return false;
if (outResultStr.Ptr != NULL)
return false;
query.Set(test3);
if (theVictim1.FindString(query, &outResultStr))
return false;
if (outResultStr.Len > 0)
return false;
if (outResultStr.Ptr != NULL)
return false;
query.Set(test1);
if (!theVictim1.FindString(query, &outResultStr))
return false;
if (!outResultStr.Equal(query))
return false;
query.Set(test4);
if (query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test5);
if (query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test6);
if (query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test7);
if (!query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test8);
if (query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test9);
if (query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test10);
if (!query.Equal(theVictim2.FindString(query)))
return false;
query.Set(test10);
if (!query.Equal(theVictim2.FindString(query)))
return false;
StrPtrLen partialStaticSource(test1,5);
query.Set("abcd");
if (query.Equal(partialStaticSource.FindString(query)))
return false;
query.Set("47");
if (query.Equal(partialStaticSource.FindString(query))) // success = !equal because the char str is longer than len
return false;
if (query.FindString(partialStaticSource.FindString(query))) // success = !found because the 0 term src is not in query
return false;
partialStaticSource.FindString(query,&outResultStr);
if (!outResultStr.Equal(query)) // success =found the result Ptr and Len is the same as the query
return false;
return true;
}
#endif

View file

@ -0,0 +1,146 @@
/*
*
* @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: StrPtrLen.h
Contains: Definition of class that tracks a string ptr and a length.
Note: this is NOT a string container class! It is a string PTR container
class. It therefore does not copy the string and store it internally. If
you deallocate the string to which this object points to, and continue
to use it, you will be in deep doo-doo.
It is also non-encapsulating, basically a struct with some simple methods.
*/
#ifndef __STRPTRLEN_H__
#define __STRPTRLEN_H__
#include <string.h>
#include "OSHeaders.h"
#include <ctype.h>
#include "MyAssert.h"
#include "SafeStdLib.h"
#define STRPTRLENTESTING 0
class StrPtrLen
{
public:
//CONSTRUCTORS/DESTRUCTOR
//These are so tiny they can all be inlined
StrPtrLen() : Ptr(NULL), Len(0) {}
StrPtrLen(char* sp) : Ptr(sp), Len(sp != NULL ? strlen(sp) : 0) {}
StrPtrLen(char *sp, UInt32 len) : Ptr(sp), Len(len) {}
virtual ~StrPtrLen() {}
//OPERATORS:
Bool16 Equal(const StrPtrLen &compare) const;
Bool16 EqualIgnoreCase(const char* compare, const UInt32 len) const;
Bool16 EqualIgnoreCase(const StrPtrLen &compare) const { return EqualIgnoreCase(compare.Ptr, compare.Len); }
Bool16 Equal(const char* compare) const;
Bool16 NumEqualIgnoreCase(const char* compare, const UInt32 len) const;
void Delete() { delete [] Ptr; Ptr = NULL; Len = 0; }
char *ToUpper() { for (UInt32 x = 0; x < Len ; x++) Ptr[x] = toupper (Ptr[x]); return Ptr;}
char *FindStringCase(char *queryCharStr, StrPtrLen *resultStr, Bool16 caseSensitive) const;
char *FindString(StrPtrLen *queryStr, StrPtrLen *outResultStr) { Assert(queryStr != NULL); Assert(queryStr->Ptr != NULL); Assert(0 == queryStr->Ptr[queryStr->Len]);
return FindStringCase(queryStr->Ptr, outResultStr,true);
}
char *FindStringIgnoreCase(StrPtrLen *queryStr, StrPtrLen *outResultStr) { Assert(queryStr != NULL); Assert(queryStr->Ptr != NULL); Assert(0 == queryStr->Ptr[queryStr->Len]);
return FindStringCase(queryStr->Ptr, outResultStr,false);
}
char *FindString(StrPtrLen *queryStr) { Assert(queryStr != NULL); Assert(queryStr->Ptr != NULL); Assert(0 == queryStr->Ptr[queryStr->Len]);
return FindStringCase(queryStr->Ptr, NULL,true);
}
char *FindStringIgnoreCase(StrPtrLen *queryStr) { Assert(queryStr != NULL); Assert(queryStr->Ptr != NULL); Assert(0 == queryStr->Ptr[queryStr->Len]);
return FindStringCase(queryStr->Ptr, NULL,false);
}
char *FindString(char *queryCharStr) { return FindStringCase(queryCharStr, NULL,true); }
char *FindStringIgnoreCase(char *queryCharStr) { return FindStringCase(queryCharStr, NULL,false); }
char *FindString(char *queryCharStr, StrPtrLen *outResultStr) { return FindStringCase(queryCharStr, outResultStr,true); }
char *FindStringIgnoreCase(char *queryCharStr, StrPtrLen *outResultStr) { return FindStringCase(queryCharStr, outResultStr,false); }
char *FindString(StrPtrLen &query, StrPtrLen *outResultStr) { return FindString( &query, outResultStr); }
char *FindStringIgnoreCase(StrPtrLen &query, StrPtrLen *outResultStr) { return FindStringIgnoreCase( &query, outResultStr); }
char *FindString(StrPtrLen &query) { return FindString( &query); }
char *FindStringIgnoreCase(StrPtrLen &query) { return FindStringIgnoreCase( &query); }
StrPtrLen& operator=(const StrPtrLen& newStr) { Ptr = newStr.Ptr; Len = newStr.Len;
return *this; }
char operator[](int i) { /*Assert(i<Len);i*/ return Ptr[i]; }
void Set(char* inPtr, UInt32 inLen) { Ptr = inPtr; Len = inLen; }
void Set(char* inPtr) { Ptr = inPtr; Len = (inPtr) ? ::strlen(inPtr) : 0; }
//This is a non-encapsulating interface. The class allows you to access its
//data.
char* Ptr;
UInt32 Len;
// convert to a "NEW'd" zero terminated char array
char* GetAsCString() const;
void PrintStr();
void PrintStr(char *appendStr);
void PrintStr(char* prependStr, char *appendStr);
void PrintStrEOL(char* stopStr = NULL, char *appendStr = NULL); //replace chars x0A and x0D with \r and \n
//Utility function
UInt32 TrimTrailingWhitespace();
UInt32 TrimLeadingWhitespace();
UInt32 RemoveWhitespace();
void TrimWhitespace() { TrimLeadingWhitespace(); TrimTrailingWhitespace(); }
#if STRPTRLENTESTING
static Bool16 Test();
#endif
private:
static UInt8 sCaseInsensitiveMask[];
static UInt8 sNonPrintChars[];
};
class StrPtrLenDel : public StrPtrLen
{
public:
StrPtrLenDel() : StrPtrLen() {}
StrPtrLenDel(char* sp) : StrPtrLen(sp) {}
StrPtrLenDel(char *sp, UInt32 len) : StrPtrLen(sp,len) {}
~StrPtrLenDel() { Delete(); }
};
#endif // __STRPTRLEN_H__

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@
*
*/
/*
File: StringFormatter.cpp
Contains: Implementation of StringFormatter class.
*/
#include <string.h>
#include <stdarg.h>
#include "StringFormatter.h"
#include "MyAssert.h"
char* StringFormatter::sEOL = "\r\n";
UInt32 StringFormatter::sEOLLen = 2;
void StringFormatter::Put(const SInt32 num)
{
char buff[32];
qtss_sprintf(buff, "%"_S32BITARG_"", num);
Put(buff);
}
void StringFormatter::Put(char* buffer, UInt32 bufferSize)
{
//optimization for writing 1 character
if((bufferSize == 1) && (fCurrentPut != fEndPut)) {
*(fCurrentPut++) = *buffer;
fBytesWritten++;
return;
}
//loop until the input buffer size is smaller than the space in the output
//buffer. Call BufferIsFull at each pass through the loop
UInt32 spaceLeft = this->GetSpaceLeft();
UInt32 spaceInBuffer = spaceLeft - 1;
UInt32 resizedSpaceLeft = 0;
while ( (spaceInBuffer < bufferSize) || (spaceLeft == 0) ) // too big for destination
{
if (spaceLeft > 0)
{
//copy as much as possible; truncating the result
::memcpy(fCurrentPut, buffer, spaceInBuffer);
fCurrentPut += spaceInBuffer;
fBytesWritten += spaceInBuffer;
buffer += spaceInBuffer;
bufferSize -= spaceInBuffer;
}
this->BufferIsFull(fStartPut, this->GetCurrentOffset()); // resize buffer
resizedSpaceLeft = this->GetSpaceLeft();
if (spaceLeft == resizedSpaceLeft) // couldn't resize, nothing left to do
{
return; // done. There is either nothing to do or nothing we can do because the BufferIsFull
}
spaceLeft = resizedSpaceLeft;
spaceInBuffer = spaceLeft - 1;
}
//copy the remaining chunk into the buffer
::memcpy(fCurrentPut, buffer, bufferSize);
fCurrentPut += bufferSize;
fBytesWritten += bufferSize;
}
//Puts a printf-style formatted string; except that the NUL terminator is not written. If the buffer is too small, returns false and does not
//Alter the buffer. Will not count the '\0' terminator as among the bytes written
Bool16 StringFormatter::PutFmtStr(const char *fmt, ...)
{
Assert(fmt != NULL);
va_list args;
for(;;)
{
va_start(args,fmt);
int length = ::vsnprintf(fCurrentPut, this->GetSpaceLeft(), fmt, args);
va_end(args);
if (length < 0)
return false;
if (static_cast<UInt32>(length) >= this->GetSpaceLeft()) //was not able to write all the output
{
if (this->BufferIsFull(fStartPut, this->GetCurrentOffset()))
continue;
//can only output a portion of the string
UInt32 bytesWritten = fEndPut - fCurrentPut - 1; //We don't want to include the NUL terminator
fBytesWritten += bytesWritten;
fCurrentPut += bytesWritten;
return false;
}
else
{
fBytesWritten += length;
fCurrentPut += length;
}
return true;
}
}

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@
*
*/
/*
File: StringFormatter.h
Contains: Utility class for formatting text to a buffer.
Construct object with a buffer, then call one
of many Put methods to write into that buffer.
*/
#ifndef __STRINGFORMATTER_H__
#define __STRINGFORMATTER_H__
#include <string.h>
#include "StrPtrLen.h"
#include "MyAssert.h"
//Use a class like the ResizeableStringFormatter if you want a buffer that will dynamically grow
class StringFormatter
{
public:
//pass in a buffer and length for writing
StringFormatter(char *buffer, UInt32 length) : fCurrentPut(buffer),
fStartPut(buffer),
fEndPut(buffer + length),
fBytesWritten(0) {}
StringFormatter(StrPtrLen &buffer) : fCurrentPut(buffer.Ptr),
fStartPut(buffer.Ptr),
fEndPut(buffer.Ptr + buffer.Len),
fBytesWritten(0) {}
virtual ~StringFormatter() {}
void Set(char *buffer, UInt32 length) { fCurrentPut = buffer;
fStartPut = buffer;
fEndPut = buffer + length;
fBytesWritten= 0;
}
//"erases" all data in the output stream save this number
void Reset(UInt32 inNumBytesToLeave = 0)
{ fCurrentPut = fStartPut + inNumBytesToLeave; }
//Object does no bounds checking on the buffer. That is your responsibility!
//Put truncates to the buffer size
void Put(const SInt32 num);
void Put(char* buffer, UInt32 bufferSize);
void Put(char* str) { Put(str, strlen(str)); }
void Put(const StrPtrLen &str) { Put(str.Ptr, str.Len); }
void PutSpace() { PutChar(' '); }
void PutEOL() { Put(sEOL, sEOLLen); }
void PutChar(char c) { Put(&c, 1); }
void PutTerminator() { PutChar('\0'); }
//Writes a printf style formatted string
Bool16 PutFmtStr(const char *fmt, ...);
//the number of characters in the buffer
inline UInt32 GetCurrentOffset();
inline UInt32 GetSpaceLeft();
inline UInt32 GetTotalBufferSize();
char* GetCurrentPtr() { return fCurrentPut; }
char* GetBufPtr() { return fStartPut; }
// Counts total bytes that have been written to this buffer (increments
// even when the buffer gets reset)
void ResetBytesWritten() { fBytesWritten = 0; }
UInt32 GetBytesWritten() { return fBytesWritten; }
inline void PutFilePath(StrPtrLen *inPath, StrPtrLen *inFileName);
inline void PutFilePath(char *inPath, char *inFileName);
//Return a NEW'd copy of the buffer as a C string
char *GetAsCString()
{
StrPtrLen str(fStartPut, this->GetCurrentOffset());
return str.GetAsCString();
}
protected:
//If you fill up the StringFormatter buffer, this function will get called. By
//default, the function simply returns false. But derived objects can clear out the data,
//reset the buffer, and then returns true.
//Use the ResizeableStringFormatter if you want a buffer that will dynamically grow.
//Returns true if the buffer has been resized.
virtual Bool16 BufferIsFull(char* /*inBuffer*/, UInt32 /*inBufferLen*/) { return false; }
char* fCurrentPut;
char* fStartPut;
char* fEndPut;
// A way of keeping count of how many bytes have been written total
UInt32 fBytesWritten;
static char* sEOL;
static UInt32 sEOLLen;
};
inline UInt32 StringFormatter::GetCurrentOffset()
{
Assert(fCurrentPut >= fStartPut);
return (UInt32)(fCurrentPut - fStartPut);
}
inline UInt32 StringFormatter::GetSpaceLeft()
{
Assert(fEndPut >= fCurrentPut);
return (UInt32)(fEndPut - fCurrentPut);
}
inline UInt32 StringFormatter::GetTotalBufferSize()
{
Assert(fEndPut >= fStartPut);
return (UInt32)(fEndPut - fStartPut);
}
inline void StringFormatter::PutFilePath(StrPtrLen *inPath, StrPtrLen *inFileName)
{
if (inPath != NULL && inPath->Len > 0)
{
Put(inPath->Ptr, inPath->Len);
if (kPathDelimiterChar != inPath->Ptr[inPath->Len -1] )
Put(kPathDelimiterString);
}
if (inFileName != NULL && inFileName->Len > 0)
Put(inFileName->Ptr, inFileName->Len);
}
inline void StringFormatter::PutFilePath(char *inPath, char *inFileName)
{
StrPtrLen pathStr(inPath);
StrPtrLen fileStr(inFileName);
PutFilePath(&pathStr,&fileStr);
}
#endif // __STRINGFORMATTER_H__

View file

@ -0,0 +1,510 @@
/*
*
* @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: StringParser.cpp
Contains: Implementation of StringParser class.
*/
#include "StringParser.h"
UInt8 StringParser::sNonWordMask[] =
{
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, 1, 1, 1, 1, //40-49 - is a word
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //50-59
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //60-69 //stop on every character except a letter
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 word
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
};
UInt8 StringParser::sWordMask[] =
{
// Inverse of the above
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10-19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30-39
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, //40-49 - is a word
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-59
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, //60-69 //stop on every character except a letter
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //70-79
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //80-89
1, 0, 0, 0, 0, 1, 0, 1, 1, 1, //90-99 _ is a word
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //100-109
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //110-119
1, 1, 1, 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
};
UInt8 StringParser::sDigitMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10-19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30-39
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, //40-49 //stop on every character except a number
1, 1, 1, 1, 1, 1, 1, 1, 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
};
UInt8 StringParser::sEOLMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-9
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, 0, 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
};
UInt8 StringParser::sWhitespaceMask[] =
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, //0-9 // stop on '\t'
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, //10-19 // '\r', \v', '\f' & '\n'
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //20-29
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, //30-39 // ' '
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //40-49
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //50-59
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //60-69
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //70-79
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //80-89
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //90-99
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //100-109
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //110-119
1, 1, 1, 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
};
UInt8 StringParser::sEOLWhitespaceMask[] =
{
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, 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
};
UInt8 StringParser::sEOLWhitespaceQueryMask[] =
{
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, 0, 1, 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
};
void StringParser::ConsumeUntil(StrPtrLen* outString, char inStop)
{
if (this->ParserIsEmpty(outString))
return;
char *originalStartGet = fStartGet;
while ((fStartGet < fEndGet) && (*fStartGet != inStop))
AdvanceMark();
if (outString != NULL)
{
outString->Ptr = originalStartGet;
outString->Len = fStartGet - originalStartGet;
}
}
void StringParser::ConsumeUntil(StrPtrLen* outString, UInt8 *inMask)
{
if (this->ParserIsEmpty(outString))
return;
char *originalStartGet = fStartGet;
while ((fStartGet < fEndGet) && (!inMask[(unsigned char) (*fStartGet)]))//make sure inMask is indexed with an unsigned char
AdvanceMark();
if (outString != NULL)
{
outString->Ptr = originalStartGet;
outString->Len = fStartGet - originalStartGet;
}
}
void StringParser::ConsumeLength(StrPtrLen* spl, SInt32 inLength)
{
if (this->ParserIsEmpty(spl))
return;
//sanity check to make sure we aren't being told to run off the end of the
//buffer
if ((fEndGet - fStartGet) < inLength)
inLength = fEndGet - fStartGet;
if (spl != NULL)
{
spl->Ptr = fStartGet;
spl->Len = inLength;
}
if (inLength > 0)
{
for (short i=0; i<inLength; i++)
AdvanceMark();
}
else
fStartGet += inLength; // ***may mess up line number if we back up too much
}
UInt32 StringParser::ConsumeInteger(StrPtrLen* outString)
{
if (this->ParserIsEmpty(outString))
return 0;
UInt32 theValue = 0;
char *originalStartGet = fStartGet;
while ((fStartGet < fEndGet) && (*fStartGet >= '0') && (*fStartGet <= '9'))
{
theValue = (theValue * 10) + (*fStartGet - '0');
AdvanceMark();
}
if (outString != NULL)
{
outString->Ptr = originalStartGet;
outString->Len = fStartGet - originalStartGet;
}
return theValue;
}
Float32 StringParser::ConsumeFloat()
{
if (this->ParserIsEmpty(NULL))
return 0.0;
Float32 theFloat = 0;
while ((fStartGet < fEndGet) && (*fStartGet >= '0') && (*fStartGet <= '9'))
{
theFloat = (theFloat * 10) + (*fStartGet - '0');
AdvanceMark();
}
if ((fStartGet < fEndGet) && (*fStartGet == '.'))
AdvanceMark();
Float32 multiplier = (Float32) .1;
while ((fStartGet < fEndGet) && (*fStartGet >= '0') && (*fStartGet <= '9'))
{
theFloat += (multiplier * (*fStartGet - '0'));
multiplier *= (Float32).1;
AdvanceMark();
}
return theFloat;
}
Float32 StringParser::ConsumeNPT()
{
if (this->ParserIsEmpty(NULL))
return 0.0;
Float32 valArray[4] = {0, 0, 0, 0};
Float32 divArray[4] = {1, 1, 1, 1};
UInt32 valType = 0; // 0 == npt-sec, 1 == npt-hhmmss
UInt32 index;
for (index = 0; index < 4; index ++)
{
while ((fStartGet < fEndGet) && (*fStartGet >= '0') && (*fStartGet <= '9'))
{
valArray[index] = (valArray[index] * 10) + (*fStartGet - '0');
divArray[index] *= 10;
AdvanceMark();
}
if (fStartGet >= fEndGet || valType == 0 && index >= 1)
break;
if (*fStartGet == '.' && valType == 0 && index == 0)
;
else if (*fStartGet == ':' && index < 2)
valType = 1;
else if (*fStartGet == '.' && index == 2)
;
else
break;
AdvanceMark();
}
if (valType == 0)
return valArray[0] + (valArray[1] / divArray[1]);
else
return (valArray[0] * 3600) + (valArray[1] * 60) + valArray[2] + (valArray[3] / divArray[3]);
}
Bool16 StringParser::Expect(char stopChar)
{
if (this->ParserIsEmpty(NULL))
return false;
if (fStartGet >= fEndGet)
return false;
if(*fStartGet != stopChar)
return false;
else
{
AdvanceMark();
return true;
}
}
Bool16 StringParser::ExpectEOL()
{
if (this->ParserIsEmpty(NULL))
return false;
//This function processes all legal forms of HTTP / RTSP eols.
//They are: \r (alone), \n (alone), \r\n
Bool16 retVal = false;
if ((fStartGet < fEndGet) && ((*fStartGet == '\r') || (*fStartGet == '\n')))
{
retVal = true;
AdvanceMark();
//check for a \r\n, which is the most common EOL sequence.
if ((fStartGet < fEndGet) && ((*(fStartGet - 1) == '\r') && (*fStartGet == '\n')))
AdvanceMark();
}
return retVal;
}
void StringParser::ConsumeEOL(StrPtrLen* outString)
{
if (this->ParserIsEmpty(outString))
return;
//This function processes all legal forms of HTTP / RTSP eols.
//They are: \r (alone), \n (alone), \r\n
char *originalStartGet = fStartGet;
if ((fStartGet < fEndGet) && ((*fStartGet == '\r') || (*fStartGet == '\n')))
{
AdvanceMark();
//check for a \r\n, which is the most common EOL sequence.
if ((fStartGet < fEndGet) && ((*(fStartGet - 1) == '\r') && (*fStartGet == '\n')))
AdvanceMark();
}
if (outString != NULL)
{
outString->Ptr = originalStartGet;
outString->Len = fStartGet - originalStartGet;
}
}
void StringParser::UnQuote(StrPtrLen* outString)
{
// If a string is contained within double or single quotes
// then UnQuote() will remove them. - [sfu]
// sanity check
if (outString->Ptr == NULL || outString->Len < 2)
return;
// remove begining quote if it's there.
if (outString->Ptr[0] == '"' || outString->Ptr[0] == '\'')
{
outString->Ptr++; outString->Len--;
}
// remove ending quote if it's there.
if ( outString->Ptr[outString->Len-1] == '"' ||
outString->Ptr[outString->Len-1] == '\'' )
{
outString->Len--;
}
}
void StringParser::AdvanceMark()
{
if (this->ParserIsEmpty(NULL))
return;
if ((*fStartGet == '\n') || ((*fStartGet == '\r') && (fStartGet[1] != '\n')))
{
// we are progressing beyond a line boundary (don't count \r\n twice)
fCurLineNumber++;
}
fStartGet++;
}
#if STRINGPARSERTESTING
Bool16 StringParser::Test()
{
static char* string1 = "RTSP 200 OK\r\nContent-Type: MeowMix\r\n\t \n3450";
StrPtrLen theString(string1, strlen(string1));
StringParser victim(&theString);
StrPtrLen rtsp;
SInt32 theInt = victim.ConsumeInteger();
if (theInt != 0)
return false;
victim.ConsumeWord(&rtsp);
if ((rtsp.len != 4) && (strncmp(rtsp.Ptr, "RTSP", 4) != 0))
return false;
victim.ConsumeWhiteSpace();
theInt = victim.ConsumeInteger();
if (theInt != 200)
return false;
return true;
}
#endif

View file

@ -0,0 +1,189 @@
/*
*
* @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: StringParser.h
Contains: A couple of handy utilities for parsing a stream.
*/
#ifndef __STRINGPARSER_H__
#define __STRINGPARSER_H__
#include "StrPtrLen.h"
#include "MyAssert.h"
#define STRINGPARSERTESTING 0
class StringParser
{
public:
StringParser(StrPtrLen *inStream)
: fStartGet(inStream == NULL ? NULL : inStream->Ptr),
fEndGet(inStream == NULL ? NULL : inStream->Ptr + inStream->Len),
fCurLineNumber(1),
fStream(inStream) {}
~StringParser() {}
// Built-in masks for common stop conditions
static UInt8 sDigitMask[]; // stop when you hit a digit
static UInt8 sWordMask[]; // stop when you hit a word
static UInt8 sEOLMask[]; // stop when you hit an eol
static UInt8 sEOLWhitespaceMask[]; // stop when you hit an EOL or whitespace
static UInt8 sEOLWhitespaceQueryMask[]; // stop when you hit an EOL, ? or whitespace
static UInt8 sWhitespaceMask[]; // skip over whitespace
//GetBuffer:
//Returns a pointer to the string object
StrPtrLen* GetStream() { return fStream; }
//Expect:
//These functions consume the given token/word if it is in the stream.
//If not, they return false.
//In all other situations, true is returned.
//NOTE: if these functions return an error, the object goes into a state where
//it cannot be guarenteed to function correctly.
Bool16 Expect(char stopChar);
Bool16 ExpectEOL();
//Returns the next word
void ConsumeWord(StrPtrLen* outString = NULL)
{ ConsumeUntil(outString, sNonWordMask); }
//Returns all the data before inStopChar
void ConsumeUntil(StrPtrLen* outString, char inStopChar);
//Returns whatever integer is currently in the stream
UInt32 ConsumeInteger(StrPtrLen* outString = NULL);
Float32 ConsumeFloat();
Float32 ConsumeNPT();
//Keeps on going until non-whitespace
void ConsumeWhitespace()
{ ConsumeUntil(NULL, sWhitespaceMask); }
//Assumes 'stop' is a 255-char array of booleans. Set this array
//to a mask of what the stop characters are. true means stop character.
//You may also pass in one of the many prepackaged masks defined above.
void ConsumeUntil(StrPtrLen* spl, UInt8 *stop);
//+ rt 8.19.99
//returns whatever is avaliable until non-whitespace
void ConsumeUntilWhitespace(StrPtrLen* spl = NULL)
{ ConsumeUntil( spl, sEOLWhitespaceMask); }
void ConsumeUntilDigit(StrPtrLen* spl = NULL)
{ ConsumeUntil( spl, sDigitMask); }
void ConsumeLength(StrPtrLen* spl, SInt32 numBytes);
void ConsumeEOL(StrPtrLen* outString);
//GetThru:
//Works very similar to ConsumeUntil except that it moves past the stop token,
//and if it can't find the stop token it returns false
inline Bool16 GetThru(StrPtrLen* spl, char stop);
inline Bool16 GetThruEOL(StrPtrLen* spl);
inline Bool16 ParserIsEmpty(StrPtrLen* outString);
//Returns the current character, doesn't move past it.
inline char PeekFast() { if (fStartGet) return *fStartGet; else return '\0'; }
char operator[](int i) { Assert((fStartGet+i) < fEndGet);return fStartGet[i]; }
//Returns some info about the stream
UInt32 GetDataParsedLen()
{ Assert(fStartGet >= fStream->Ptr); return (UInt32)(fStartGet - fStream->Ptr); }
UInt32 GetDataReceivedLen()
{ Assert(fEndGet >= fStream->Ptr); return (UInt32)(fEndGet - fStream->Ptr); }
UInt32 GetDataRemaining()
{ Assert(fEndGet >= fStartGet); return (UInt32)(fEndGet - fStartGet); }
char* GetCurrentPosition() { return fStartGet; }
int GetCurrentLineNumber() { return fCurLineNumber; }
// A utility for extracting quotes from the start and end of a parsed
// string. (Warning: Do not call this method if you allocated your own
// pointer for the Ptr field of the StrPtrLen class.) - [sfu]
//
// Not sure why this utility is here and not in the StrPtrLen class - [jm]
static void UnQuote(StrPtrLen* outString);
#if STRINGPARSERTESTING
static Bool16 Test();
#endif
private:
void AdvanceMark();
//built in masks for some common stop conditions
static UInt8 sNonWordMask[];
char* fStartGet;
char* fEndGet;
int fCurLineNumber;
StrPtrLen* fStream;
};
Bool16 StringParser::GetThru(StrPtrLen* outString, char inStopChar)
{
ConsumeUntil(outString, inStopChar);
return Expect(inStopChar);
}
Bool16 StringParser::GetThruEOL(StrPtrLen* outString)
{
ConsumeUntil(outString, sEOLMask);
return ExpectEOL();
}
Bool16 StringParser::ParserIsEmpty(StrPtrLen* outString)
{
if (NULL == fStartGet || NULL == fEndGet)
{
if (NULL != outString)
{ outString->Ptr = NULL;
outString->Len = 0;
}
return true;
}
Assert(fStartGet <= fEndGet);
return false; // parser ok to parse
}
#endif // __STRINGPARSER_H__

View file

@ -0,0 +1,281 @@
/*
*
* @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: StringTranslator.cpp
Contains: implements StringTranslator class
*/
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "StringTranslator.h"
#include "MyAssert.h"
#include "SafeStdLib.h"
#include <errno.h>
SInt32 StringTranslator::DecodeURL(const char* inSrc, SInt32 inSrcLen, char* ioDest, SInt32 inDestLen)
{
// return the number of chars written to ioDest
// or OS_BadURLFormat in the case of any error.
// inSrcLen must be > inSrcLen and the first character must be a '/'
if ( inSrcLen <= 0 || *inSrc != '/' )
return OS_BadURLFormat;
//Assert(*inSrc == '/'); //For the purposes of '..' stripping, we assume first char is a /
SInt32 theLengthWritten = 0;
int tempChar = 0;
int numDotChars = 0;
Bool16 inQuery = false;
while (inSrcLen > 0)
{
if (theLengthWritten == inDestLen)
return OS_NotEnoughSpace;
if (*inSrc == '?')
inQuery = true;
if (*inSrc == '%')
{
if (inSrcLen < 3)
return OS_BadURLFormat;
//if there is a special character in this URL, extract it
char tempbuff[3];
inSrc++;
if (!isxdigit(*inSrc))
return OS_BadURLFormat;
tempbuff[0] = *inSrc;
inSrc++;
if (!isxdigit(*inSrc))
return OS_BadURLFormat;
tempbuff[1] = *inSrc;
inSrc++;
tempbuff[2] = '\0';
sscanf(tempbuff, "%x", &tempChar);
Assert(tempChar < 256);
inSrcLen -= 3;
}
else if (*inSrc == '\0')
return OS_BadURLFormat;
else
{
// Any normal character just gets copied into the destination buffer
tempChar = *inSrc;
inSrcLen--;
inSrc++;
}
if (!inQuery) // don't do seperator parsing or .. parsing in query
{
//
// If we are in a file system that uses a character besides '/' as a
// path delimiter, we should not allow this character to appear in the URL.
// In URLs, only '/' has control meaning.
if ((tempChar == kPathDelimiterChar) && (kPathDelimiterChar != '/'))
return OS_BadURLFormat;
// Check to see if this character is a path delimiter ('/')
// If so, we need to further check whether backup is required due to
// dot chars that need to be stripped
if ((tempChar == '/') && (numDotChars <= 2) && (numDotChars > 0))
{
Assert(theLengthWritten > numDotChars);
ioDest -= (numDotChars + 1);
theLengthWritten -= (numDotChars + 1);
}
*ioDest = tempChar;
// Note that because we are doing this dotchar check here, we catch dotchars
// even if they were encoded to begin with.
// If this is a . , check to see if it's one of those cases where we need to track
// how many '.'s in a row we've gotten, for stripping out later on
if (*ioDest == '.')
{
Assert(theLengthWritten > 0);//first char is always '/', right?
if ((numDotChars == 0) && (*(ioDest - 1) == '/'))
numDotChars++;
else if ((numDotChars > 0) && (*(ioDest - 1) == '.'))
numDotChars++;
}
// If this isn't a dot char, we don't care at all, reset this value to 0.
else
numDotChars = 0;
}
else
*ioDest = tempChar;
theLengthWritten++;
ioDest++;
}
// Before returning, "strip" any trailing "." or ".." by adjusting "theLengthWritten
// accordingly
if (numDotChars <= 2)
theLengthWritten -= numDotChars;
return theLengthWritten;
}
SInt32 StringTranslator::EncodeURL(const char* inSrc, SInt32 inSrcLen, char* ioDest, SInt32 inDestLen)
{
// return the number of chars written to ioDest
SInt32 theLengthWritten = 0;
while (inSrcLen > 0)
{
if (theLengthWritten == inDestLen)
return OS_NotEnoughSpace;
//
// Always encode 8-bit characters
if ((unsigned char)*inSrc > 127)
{
if (inDestLen - theLengthWritten < 3)
return OS_NotEnoughSpace;
qtss_sprintf(ioDest,"%%%X",(unsigned char)*inSrc);
ioDest += 3;
theLengthWritten += 3;
inSrc++;
inSrcLen--;
continue;
}
//
// Only encode certain 7-bit characters
switch (*inSrc)
{
// This is the URL RFC list of illegal characters.
case (' '):
case ('\r'):
case ('\n'):
case ('\t'):
case ('<'):
case ('>'):
case ('#'):
case ('%'):
case ('{'):
case ('}'):
case ('|'):
case ('\\'):
case ('^'):
case ('~'):
case ('['):
case (']'):
case ('`'):
case (';'):
// case ('/'): // this isn't really an illegal character, it's legitimatly used as a seperator in the url
case ('?'):
case ('@'):
case ('='):
case ('&'):
case ('$'):
case ('"'):
{
if ((inDestLen - theLengthWritten) < 3)
return OS_NotEnoughSpace;
qtss_sprintf(ioDest,"%%%X",(int)*inSrc);
ioDest += 3;
theLengthWritten += 3;
break;
}
default:
{
*ioDest = *inSrc;
ioDest++;
theLengthWritten++;
}
}
inSrc++;
inSrcLen--;
}
return theLengthWritten;
}
void StringTranslator::DecodePath(char* inSrc, UInt32 inSrcLen)
{
for (UInt32 x = 0; x < inSrcLen; x++)
if (inSrc[x] == '/')
inSrc[x] = kPathDelimiterChar;
}
#if STRINGTRANSLATORTESTING
Bool16 StringTranslator::Test()
{
//static char* test1 = "/%5D%3f%7eAveryweird%7C/and/long/path/ya/%5d%3F%7eAveryweird%7C/and/long/p%40/ya/%5D%3F%7EAveryweird%7C/and/long/path/ya/%5D%3F%7EAveryweird%7C/and/long/path/ya/%2560%2526a%20strange%3B%23%3D%25filename"
static char dest[1000];
static char* test1 = "/Hello%23%20 I want%28don't%29";
SInt32 err = DecodeURL(test1, strlen(test1), dest, 1000);
if (err != 22)
return false;
if (strcmp(dest, "/Hello# I want(don't)") != 0)
return false;
err = DecodeURL(test1, 15, dest, 1000);
if (err != 11)
return false;
if (strncmp(dest, "/Hello# I ", 11) != 0)
return false;
err = DecodeURL(test1, 50, dest, 1000);
if (err != OS_BadURLFormat)
return false;
if (strncmp(dest, "/Hello# I want(don't)", 22) != 0)
if (strcmp(dest, "/Hello# I want(don't)") != 0)
return false;
err = DecodeURL(test1, strlen(test1), dest, 20);
if (err != OS_BadURLFormat)
return false;
static char* test2 = "/THis%2h is a bad %28 URL!";
err = DecodeURL(test2, strlen(test2), dest, 1000);
if (err != OS_BadURLFormat)
return false;
static char* test3 = "/...whoa/../is./meeee%3e/./";
static char* test4 = "/I want/to/sleep/..";
static char* test5 = "/ve....rr/tire.././../..";
static char* test6 = "/../beginnings/and/.";
static char* test7 = "/../begin/%2e./../nin/%2e/gs/an/%2e%2e/fklf/%2e%2e./dfds%2e/%2e%2e/d/.%2e";
err = DecodeURL(test3, strlen(test3), dest, 1000);
err = DecodeURL(test4, strlen(test4), dest, 1000);
err = DecodeURL(test5, strlen(test5), dest, 1000);
err = DecodeURL(test6, strlen(test6), dest, 1000);
err = DecodeURL(test7, strlen(test7), dest, 1000);
return true;
}
#endif

View file

@ -0,0 +1,79 @@
/*
*
* @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@
*
*/
/*
Contains: Static utilities for translating strings from one encoding scheme to
another. For example, routines for encoding and decoding URLs
*/
#ifndef __STRINGTRANSLATOR_H__
#define __STRINGTRANSLATOR_H__
#include "OSHeaders.h"
#define STRINGTRANSLATORTESTING 0
class StringTranslator
{
public:
//DecodeURL:
//
// This function does 2 things: Decodes % encoded characters in URLs, and strips out
// any ".." or "." complete filenames from the URL. Writes the result into ioDest.
//
//If successful, returns the length of the destination string.
//If failure, returns an OS errorcode: OS_BadURLFormat, OS_NotEnoughSpace
static SInt32 DecodeURL(const char* inSrc, SInt32 inSrcLen, char* ioDest, SInt32 inDestLen);
//EncodeURL:
//
// This function takes a character string and % encodes any special URL characters.
// In general, the output buffer will be longer than the input buffer, so caller should
// be aware of that.
//
//If successful, returns the length of the destination string.
//If failure, returns an QTSS errorcode: OS_NotEnoughSpace
//
// If function returns E2BIG, ioDest will be valid, but will contain
// only the portion of the URL that fit.
static SInt32 EncodeURL(const char* inSrc, SInt32 inSrcLen, char* ioDest, SInt32 inDestLen);
// DecodePath:
//
// This function converts "network" or "URL" path delimiters (the '/' char) to
// the path delimiter of the local file system. It does this conversion in place,
// so the old data will be overwritten
static void DecodePath(char* inSrc, UInt32 inSrcLen);
#if STRINGTRANSLATORTESTING
static Bool16 Test();
#endif
};
#endif // __STRINGTRANSLATOR_H__

View file

@ -0,0 +1,232 @@
/*
*
* @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: TCPListenerSocket.cpp
Contains: implements TCPListenerSocket class
*/
#ifndef __Win32__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#ifndef __Win32__
#include "QTSSModuleUtils.h"
#endif
#endif
#include <errno.h>
#include "TCPListenerSocket.h"
#include "Task.h"
OS_Error TCPListenerSocket::Listen(UInt32 queueLength)
{
if (fFileDesc == EventContext::kInvalidFileDesc)
return EBADF;
int err = ::listen(fFileDesc, queueLength);
if (err != 0)
return (OS_Error)OSThread::GetErrno();
return OS_NoErr;
}
OS_Error TCPListenerSocket::Initialize(UInt32 addr, UInt16 port)
{
OS_Error err = this->TCPSocket::Open();
if (0 == err) do
{
// set SO_REUSEADDR socket option before calling bind.
#ifndef __Win32__
// this causes problems on NT (multiple processes can bind simultaneously),
// so don't do it on NT.
this->ReuseAddr();
#endif
err = this->Bind(addr, port);
if (err != 0) break; // don't assert this is just a port already in use.
//
// Unfortunately we need to advertise a big buffer because our TCP sockets
// can be used for incoming broadcast data. This could force the server
// to run out of memory faster if it gets bogged down, but it is unavoidable.
this->SetSocketRcvBufSize(96 * 1024);
err = this->Listen(kListenQueueLength);
AssertV(err == 0, OSThread::GetErrno());
if (err != 0) break;
} while (false);
return err;
}
void TCPListenerSocket::ProcessEvent(int /*eventBits*/)
{
//we are executing on the same thread as every other
//socket, so whatever you do here has to be fast.
struct sockaddr_in addr;
#if __Win32__ || __osf__ || __sgi__ || __hpux__
int size = sizeof(addr);
#else
socklen_t size = sizeof(addr);
#endif
Task* theTask = NULL;
TCPSocket* theSocket = NULL;
//fSocket data member of TCPSocket.
int osSocket = accept(fFileDesc, (struct sockaddr*)&addr, &size);
//test osSocket = -1;
if (osSocket == -1)
{
//take a look at what this error is.
int acceptError = OSThread::GetErrno();
if (acceptError == EAGAIN)
{
//If it's EAGAIN, there's nothing on the listen queue right now,
//so modwatch and return
this->RequestEvent(EV_RE);
return;
}
//test acceptError = ENFILE;
//test acceptError = EINTR;
//test acceptError = ENOENT;
//if these error gets returned, we're out of file desciptors,
//the server is going to be failing on sockets, logs, qtgroups and qtuser auth file accesses and movie files. The server is not functional.
if (acceptError == EMFILE || acceptError == ENFILE)
{
#ifndef __Win32__
QTSSModuleUtils::LogErrorStr(qtssFatalVerbosity, "Out of File Descriptors. Set max connections lower and check for competing usage from other processes. Exiting.");
#endif
exit (EXIT_FAILURE);
}
else
{
char errStr[256];
errStr[sizeof(errStr) -1] = 0;
qtss_snprintf(errStr, sizeof(errStr) -1, "accept error = %d '%s' on socket. Clean up and continue.", acceptError, strerror(acceptError));
WarnV( (acceptError == 0), errStr);
theTask = this->GetSessionTask(&theSocket);
if (theTask == NULL)
{
close(osSocket);
}
else
{
theTask->Signal(Task::kKillEvent); // just clean up the task
}
if (theSocket)
theSocket->fState &= ~kConnected; // turn off connected state
return;
}
}
theTask = this->GetSessionTask(&theSocket);
if (theTask == NULL)
{ //this should be a disconnect. do an ioctl call?
close(osSocket);
if (theSocket)
theSocket->fState &= ~kConnected; // turn off connected state
}
else
{
Assert(osSocket != EventContext::kInvalidFileDesc);
//set options on the socket
//we are a server, always disable nagle algorithm
int one = 1;
int err = ::setsockopt(osSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int));
AssertV(err == 0, OSThread::GetErrno());
err = ::setsockopt(osSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(int));
AssertV(err == 0, OSThread::GetErrno());
int sndBufSize = 96L * 1024L;
err = ::setsockopt(osSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sndBufSize, sizeof(int));
AssertV(err == 0, OSThread::GetErrno());
//setup the socket. When there is data on the socket,
//theTask will get an kReadEvent event
theSocket->Set(osSocket, &addr);
theSocket->InitNonBlocking(osSocket);
theSocket->SetTask(theTask);
theSocket->RequestEvent(EV_RE);
theTask->SetThreadPicker(Task::GetBlockingTaskThreadPicker()); //The RTSP Task processing threads
}
if (fSleepBetweenAccepts)
{
// We are at our maximum supported sockets
// slow down so we have time to process the active ones (we will respond with errors or service).
// wake up and execute again after sleeping. The timer must be reset each time through
//qtss_printf("TCPListenerSocket slowing down\n");
this->SetIdleTimer(kTimeBetweenAcceptsInMsec); //sleep 1 second
}
else
{
// sleep until there is a read event outstanding (another client wants to connect)
//qtss_printf("TCPListenerSocket normal speed\n");
this->RequestEvent(EV_RE);
}
fOutOfDescriptors = false; // always false for now we don't properly handle this elsewhere in the code
}
SInt64 TCPListenerSocket::Run()
{
EventFlags events = this->GetEvents();
//
// ProcessEvent cannot be going on when this object gets deleted, because
// the resolve / release mechanism of EventContext will ensure this thread
// will block before destructing stuff.
if (events & Task::kKillEvent)
return -1;
//This function will get called when we have run out of file descriptors.
//All we need to do is check the listen queue to see if the situation has
//cleared up.
(void)this->GetEvents();
this->ProcessEvent(Task::kReadEvent);
return 0;
}

View file

@ -0,0 +1,87 @@
/*
*
* @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: TCPListenerSocket.h
Contains: A TCP listener socket. When a new connection comes in, the listener
attempts to assign the new connection to a socket object and a Task
object. Derived classes must implement a method of getting new
Task & socket objects
*/
#ifndef __TCPLISTENERSOCKET_H__
#define __TCPLISTENERSOCKET_H__
#include "TCPSocket.h"
#include "IdleTask.h"
class TCPListenerSocket : public TCPSocket, public IdleTask
{
public:
TCPListenerSocket() : TCPSocket(NULL, Socket::kNonBlockingSocketType), IdleTask(),
fAddr(0), fPort(0), fOutOfDescriptors(false), fSleepBetweenAccepts(false) {this->SetTaskName("TCPListenerSocket");}
virtual ~TCPListenerSocket() {}
//
// Send a TCPListenerObject a Kill event to delete it.
//addr = listening address. port = listening port. Automatically
//starts listening
OS_Error Initialize(UInt32 addr, UInt16 port);
//You can query the listener to see if it is failing to accept
//connections because the OS is out of descriptors.
Bool16 IsOutOfDescriptors() { return fOutOfDescriptors; }
void SlowDown() { fSleepBetweenAccepts = true; }
void RunNormal() { fSleepBetweenAccepts = false; }
//derived object must implement a way of getting tasks & sockets to this object
virtual Task* GetSessionTask(TCPSocket** outSocket) = 0;
virtual SInt64 Run();
private:
enum
{
kTimeBetweenAcceptsInMsec = 1000, //UInt32
kListenQueueLength = 128 //UInt32
};
virtual void ProcessEvent(int eventBits);
OS_Error Listen(UInt32 queueLength);
UInt32 fAddr;
UInt16 fPort;
Bool16 fOutOfDescriptors;
Bool16 fSleepBetweenAccepts;
};
#endif // __TCPLISTENERSOCKET_H__

View file

@ -0,0 +1,120 @@
/*
*
* @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: TCPSocket.cpp
Contains: implements TCPSocket class
*/
#ifndef __Win32__
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif
#include <errno.h>
#include "TCPSocket.h"
#include "SocketUtils.h"
#include "OS.h"
#ifdef USE_NETLOG
#include <netlog.h>
#endif
void TCPSocket::SnarfSocket( TCPSocket & fromSocket )
{
// take the connection away from the other socket
// and use it as our own.
Assert(fFileDesc == EventContext::kInvalidFileDesc);
this->Set( fromSocket.fFileDesc, &fromSocket.fRemoteAddr );
// clear the old socket so he doesn't close and the like
struct sockaddr_in remoteaddr;
::memset( &remoteaddr, 0, sizeof( remoteaddr ) );
fromSocket.Set( EventContext::kInvalidFileDesc, &remoteaddr );
// get the event context too
this->SnarfEventContext( fromSocket );
}
void TCPSocket::Set(int inSocket, struct sockaddr_in* remoteaddr)
{
fRemoteAddr = *remoteaddr;
fFileDesc = inSocket;
if ( inSocket != EventContext::kInvalidFileDesc )
{
//make sure to find out what IP address this connection is actually occuring on. That
//way, we can report correct information to clients asking what the connection's IP is
#if __Win32__ || __osf__ || __sgi__ || __hpux__
int len = sizeof(fLocalAddr);
#else
socklen_t len = sizeof(fLocalAddr);
#endif
int err = ::getsockname(fFileDesc, (struct sockaddr*)&fLocalAddr, &len);
AssertV(err == 0, OSThread::GetErrno());
fState |= kBound;
fState |= kConnected;
}
else
fState = 0;
}
StrPtrLen* TCPSocket::GetRemoteAddrStr()
{
if (fRemoteStr.Len == kIPAddrBufSize)
SocketUtils::ConvertAddrToString(fRemoteAddr.sin_addr, &fRemoteStr);
return &fRemoteStr;
}
OS_Error TCPSocket::Connect(UInt32 inRemoteAddr, UInt16 inRemotePort)
{
::memset(&fRemoteAddr, 0, sizeof(fRemoteAddr));
fRemoteAddr.sin_family = AF_INET; /* host byte order */
fRemoteAddr.sin_port = htons(inRemotePort); /* short, network byte order */
fRemoteAddr.sin_addr.s_addr = htonl(inRemoteAddr);
/* don't forget to error check the connect()! */
int err = ::connect(fFileDesc, (sockaddr *)&fRemoteAddr, sizeof(fRemoteAddr));
fState |= kConnected;
if (err == -1)
{
fRemoteAddr.sin_port = 0;
fRemoteAddr.sin_addr.s_addr = 0;
return (OS_Error)OSThread::GetErrno();
}
return OS_NoErr;
}

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@
*
*/
/*
File: TCPSocket.h
Contains: TCP socket object
*/
#ifndef __TCPSOCKET_H__
#define __TCPSOCKET_H__
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#ifndef __Win32__
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include "Socket.h"
#include "Task.h"
#include "StrPtrLen.h"
class TCPSocket : public Socket
{
public:
//TCPSocket takes an optional task object which will get notified when
//certain events happen on this socket. Those events are:
//
//S_DATA: Data is currently available on the socket.
//S_CONNECTIONCLOSING: Client is closing the connection. No longer necessary
// to call Close or Disconnect, Snd & Rcv will fail.
TCPSocket(Task *notifytask, UInt32 inSocketType)
: Socket(notifytask, inSocketType),
fRemoteStr(fRemoteBuffer, kIPAddrBufSize) {}
virtual ~TCPSocket() {}
//Open
OS_Error Open() { return Socket::Open(SOCK_STREAM); }
// Connect. Attempts to connect to the specified remote host. If this
// is a non-blocking socket, this function may return EINPROGRESS, in which
// case caller must wait for either an EV_RE or an EV_WR. You may call
// CheckAsyncConnect at any time, which will return OS_NoErr if the connect
// has completed, EINPROGRESS if it is still in progress, or an appropriate error
// if the connect failed.
OS_Error Connect(UInt32 inRemoteAddr, UInt16 inRemotePort);
//OS_Error CheckAsyncConnect();
// Basically a copy constructor for this object, also NULLs out the data
// in tcpSocket.
void SnarfSocket( TCPSocket & tcpSocket );
//ACCESSORS:
//Returns NULL if not currently available.
UInt32 GetRemoteAddr() { return ntohl(fRemoteAddr.sin_addr.s_addr); }
UInt16 GetRemotePort() { return ntohs(fRemoteAddr.sin_port); }
//This function is NOT thread safe!
StrPtrLen* GetRemoteAddrStr();
protected:
void Set(int inSocket, struct sockaddr_in* remoteaddr);
enum
{
kIPAddrBufSize = 20 //UInt32
};
struct sockaddr_in fRemoteAddr;
char fRemoteBuffer[kIPAddrBufSize];
StrPtrLen fRemoteStr;
friend class TCPListenerSocket;
};
#endif // __TCPSOCKET_H__

415
CommonUtilitiesLib/Task.cpp Normal file
View file

@ -0,0 +1,415 @@
/*
*
* @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: Task.cpp
Contains: implements Task class
*/
#include "Task.h"
#include "OS.h"
#include "OSMemory.h"
#include "atomic.h"
#include "OSMutexRW.h"
unsigned int Task::sShortTaskThreadPicker = 0;
unsigned int Task::sBlockingTaskThreadPicker = 0;
OSMutexRW TaskThreadPool::sMutexRW;
static char* sTaskStateStr="live_"; //Alive
Task::Task()
: fEvents(0), fUseThisThread(NULL),fDefaultThread(NULL), fWriteLock(false), fTimerHeapElem(), fTaskQueueElem(), pickerToUse(&Task::sShortTaskThreadPicker)
{
#if DEBUG
fInRunCount = 0;
#endif
this->SetTaskName("unknown");
fTaskQueueElem.SetEnclosingObject(this);
fTimerHeapElem.SetEnclosingObject(this);
}
void Task::SetTaskName(char* name)
{
if (name == NULL)
return;
::strncpy(fTaskName,sTaskStateStr,sizeof(fTaskName));
::strncat(fTaskName,name,sizeof(fTaskName));
fTaskName[sizeof(fTaskName) -1] = 0; //terminate in case it is longer than ftaskname.
}
Bool16 Task::Valid()
{
if ( (this->fTaskName == NULL)
|| (0 != ::strncmp(sTaskStateStr,this->fTaskName, 5))
)
{
if (TASK_DEBUG) qtss_printf(" Task::Valid Found invalid task = %p\n", (void *)this);
return false;
}
return true;
}
Task::EventFlags Task::GetEvents()
{
//Mask off every event currently in the mask except for the alive bit, of course,
//which should remain unaffected and unreported by this call.
EventFlags events = fEvents & kAliveOff;
(void)atomic_sub(&fEvents, events);
return events;
}
void Task::Signal(EventFlags events)
{
if (!this->Valid())
return;
//Fancy no mutex implementation. We atomically mask the new events into
//the event mask. Because atomic_or returns the old state of the mask,
//we only schedule this task once.
events |= kAlive;
EventFlags oldEvents = atomic_or(&fEvents, events);
if ((!(oldEvents & kAlive)) && (TaskThreadPool::sNumTaskThreads > 0))
{
if (fDefaultThread != NULL && fUseThisThread == NULL)
fUseThisThread = fDefaultThread;
if (fUseThisThread != NULL)
// Task needs to be placed on a particular thread.
{
if (TASK_DEBUG)
{
if (fTaskName[0] == 0) ::strcpy(fTaskName, " corrupt task");
qtss_printf("Task::Signal enque TaskName=%s fUseThisThread=%p q elem=%p enclosing=%p\n", fTaskName, (void *) fUseThisThread, (void *) &fTaskQueueElem, (void *) this);
if (TaskThreadPool::sTaskThreadArray[0] == fUseThisThread) qtss_printf("Task::Signal RTSP Thread running TaskName=%s \n", fTaskName);
}
fUseThisThread->fTaskQueue.EnQueue(&fTaskQueueElem);
}
else
{
//find a thread to put this task on
unsigned int theThreadIndex = atomic_add( (unsigned int *) pickerToUse, 1);
if (&Task::sShortTaskThreadPicker == pickerToUse)
{
theThreadIndex %= TaskThreadPool::sNumShortTaskThreads;
if (TASK_DEBUG) qtss_printf("Task::Signal enque TaskName=%s using Task::sShortTaskThreadPicker=%u numShortTaskThreads=%"_U32BITARG_" short task range=[0-%"_U32BITARG_"] thread index =%u \n",fTaskName, Task::sShortTaskThreadPicker, TaskThreadPool::sNumShortTaskThreads,TaskThreadPool::sNumShortTaskThreads -1, theThreadIndex);
}
else if (&Task::sBlockingTaskThreadPicker == pickerToUse)
{
theThreadIndex %= TaskThreadPool::sNumBlockingTaskThreads;
theThreadIndex += TaskThreadPool::sNumShortTaskThreads; //don't pick from lower non-blocking (short task) threads.
if (TASK_DEBUG) qtss_printf("Task::Signal enque TaskName=%s using Task::sBlockingTaskThreadPicker=%u numBlockingThreads=%"_U32BITARG_" blocking thread range=[%"_U32BITARG_"-%"_U32BITARG_"] thread index =%u \n",fTaskName, Task::sBlockingTaskThreadPicker, TaskThreadPool::sNumBlockingTaskThreads, TaskThreadPool::sNumShortTaskThreads, TaskThreadPool::sNumBlockingTaskThreads+TaskThreadPool::sNumShortTaskThreads-1, theThreadIndex);
}
else
{
if (TASK_DEBUG) if (fTaskName[0] == 0) ::strcpy(fTaskName, " corrupt task");
return;
}
if (TASK_DEBUG) if (fTaskName[0] == 0) ::strcpy(fTaskName, " corrupt task");
if (TASK_DEBUG) qtss_printf("Task::Signal enque TaskName=%s theThreadIndex=%u thread=%p q elem=%p enclosing=%p\n", fTaskName,theThreadIndex, (void *)TaskThreadPool::sTaskThreadArray[theThreadIndex],(void *) &fTaskQueueElem,(void *) this);
TaskThreadPool::sTaskThreadArray[theThreadIndex]->fTaskQueue.EnQueue(&fTaskQueueElem);
}
}
else
if (TASK_DEBUG) qtss_printf("Task::Signal sent to dead TaskName=%s q elem=%p enclosing=%p\n", fTaskName, (void *) &fTaskQueueElem, (void *) this);
}
void Task::GlobalUnlock()
{
if (this->fWriteLock)
{ this->fWriteLock = false;
TaskThreadPool::sMutexRW.Unlock();
}
}
void Task::SetThreadPicker(unsigned int* picker)
{
pickerToUse = picker;
Assert(pickerToUse != NULL);
if (TASK_DEBUG)
{
if (fTaskName[0] == 0) ::strcpy(fTaskName, " corrupt task");
if (&Task::sShortTaskThreadPicker == pickerToUse)
{
qtss_printf("Task::SetThreadPicker sShortTaskThreadPicker for task=%s\n", fTaskName);
}
else if (&Task::sBlockingTaskThreadPicker == pickerToUse)
{
qtss_printf("Task::SetThreadPicker sBlockingTaskThreadPicker for task=%s\n",fTaskName);
}
else
{ qtss_printf("Task::SetThreadPicker ERROR unknown picker for task=%s\n",fTaskName);
}
}
}
void TaskThread::Entry()
{
Task* theTask = NULL;
while (true)
{
theTask = this->WaitForTask();
//
// WaitForTask returns NULL when it is time to quit
if (theTask == NULL || false == theTask->Valid() )
return;
Bool16 doneProcessingEvent = false;
while (!doneProcessingEvent)
{
//If a task holds locks when it returns from its Run function,
//that would be catastrophic and certainly lead to a deadlock
#if DEBUG
Assert(this->GetNumLocksHeld() == 0);
Assert(theTask->fInRunCount == 0);
theTask->fInRunCount++;
#endif
theTask->fUseThisThread = NULL; // Each invocation of Run must independently
// request a specific thread.
SInt64 theTimeout = 0;
if (theTask->fWriteLock)
{
OSMutexWriteLocker mutexLocker(&TaskThreadPool::sMutexRW);
if (TASK_DEBUG) qtss_printf("TaskThread::Entry run global locked TaskName=%s CurMSec=%.3f thread=%p task=%p\n", theTask->fTaskName, OS::StartTimeMilli_Float() ,(void *) this,(void *) theTask);
theTimeout = theTask->Run();
theTask->fWriteLock = false;
}
else
{
OSMutexReadLocker mutexLocker(&TaskThreadPool::sMutexRW);
if (TASK_DEBUG) qtss_printf("TaskThread::Entry run TaskName=%s CurMSec=%.3f thread=%p task=%p\n", theTask->fTaskName, OS::StartTimeMilli_Float(), (void *) this,(void *) theTask);
theTimeout = theTask->Run();
}
#if DEBUG
Assert(this->GetNumLocksHeld() == 0);
theTask->fInRunCount--;
Assert(theTask->fInRunCount == 0);
#endif
if (theTimeout < 0)
{
if (TASK_DEBUG)
{
qtss_printf("TaskThread::Entry delete TaskName=%s CurMSec=%.3f thread=%p task=%p\n", theTask->fTaskName, OS::StartTimeMilli_Float(), (void *) this, (void *) theTask);
theTask->fUseThisThread = NULL;
if (NULL != fHeap.Remove(&theTask->fTimerHeapElem))
qtss_printf("TaskThread::Entry task still in heap before delete\n");
if (NULL != theTask->fTaskQueueElem.InQueue())
qtss_printf("TaskThread::Entry task still in queue before delete\n");
theTask->fTaskQueueElem.Remove();
if (theTask->fEvents &~ Task::kAlive)
qtss_printf ("TaskThread::Entry flags still set before delete\n");
(void)atomic_sub(&theTask->fEvents, 0);
::strncat (theTask->fTaskName, " deleted", sizeof(theTask->fTaskName) -1);
}
theTask->fTaskName[0] = 'D'; //mark as dead
delete theTask;
theTask = NULL;
doneProcessingEvent = true;
}
else if (theTimeout == 0)
{
//We want to make sure that 100% definitely the task's Run function WILL
//be invoked when another thread calls Signal. We also want to make sure
//that if an event sneaks in right as the task is returning from Run()
//(via Signal) that the Run function will be invoked again.
doneProcessingEvent = compare_and_store(Task::kAlive, 0, &theTask->fEvents);
if (doneProcessingEvent)
theTask = NULL;
}
else
{
//note that if we get here, we don't reset theTask, so it will get passed into
//WaitForTask
if (TASK_DEBUG) qtss_printf("TaskThread::Entry insert TaskName=%s in timer heap thread=%p elem=%p task=%p timeout=%.2f\n", theTask->fTaskName, (void *) this, (void *) &theTask->fTimerHeapElem,(void *) theTask, (float)theTimeout / (float) 1000);
theTask->fTimerHeapElem.SetValue(OS::Milliseconds() + theTimeout);
fHeap.Insert(&theTask->fTimerHeapElem);
(void)atomic_or(&theTask->fEvents, Task::kIdleEvent);
doneProcessingEvent = true;
}
#if TASK_DEBUG
SInt64 yieldStart = OS::Milliseconds();
#endif
this->ThreadYield();
#if TASK_DEBUG
SInt64 yieldDur = OS::Milliseconds() - yieldStart;
static SInt64 numZeroYields;
if ( yieldDur > 1 )
{
if (TASK_DEBUG) qtss_printf( "TaskThread::Entry time in Yield %qd, numZeroYields %qd \n", yieldDur, numZeroYields );
numZeroYields = 0;
}
else
numZeroYields++;
#endif
}
}
}
Task* TaskThread::WaitForTask()
{
while (true)
{
SInt64 theCurrentTime = OS::Milliseconds();
if ((fHeap.PeekMin() != NULL) && (fHeap.PeekMin()->GetValue() <= theCurrentTime))
{
if (TASK_DEBUG) qtss_printf("TaskThread::WaitForTask found timer-task=%s thread %p fHeap.CurrentHeapSize(%"_U32BITARG_") taskElem = %p enclose=%p\n",((Task*)fHeap.PeekMin()->GetEnclosingObject())->fTaskName, (void *) this, fHeap.CurrentHeapSize(), (void *) fHeap.PeekMin(), (void *) fHeap.PeekMin()->GetEnclosingObject());
return (Task*)fHeap.ExtractMin()->GetEnclosingObject();
}
//if there is an element waiting for a timeout, figure out how long we should wait.
SInt64 theTimeout = 0;
if (fHeap.PeekMin() != NULL)
theTimeout = fHeap.PeekMin()->GetValue() - theCurrentTime;
Assert(theTimeout >= 0);
//
// Make sure we can't go to sleep for some ridiculously short
// period of time
// Do not allow a timeout below 10 ms without first verifying reliable udp 1-2mbit live streams.
// Test with streamingserver.xml pref reliablUDP printfs enabled and look for packet loss and check client for buffer ahead recovery.
if (theTimeout < 10)
theTimeout = 10;
//wait...
OSQueueElem* theElem = fTaskQueue.DeQueueBlocking(this, (SInt32) theTimeout);
if (theElem != NULL)
{
if (TASK_DEBUG) qtss_printf("TaskThread::WaitForTask found signal-task=%s thread %p fTaskQueue.GetLength(%"_U32BITARG_") taskElem = %p enclose=%p\n", ((Task*)theElem->GetEnclosingObject())->fTaskName, (void *) this, fTaskQueue.GetQueue()->GetLength(), (void *) theElem, (void *)theElem->GetEnclosingObject() );
return (Task*)theElem->GetEnclosingObject();
}
//
// If we are supposed to stop, return NULL, which signals the caller to stop
if (OSThread::GetCurrent()->IsStopRequested())
return NULL;
}
}
TaskThread** TaskThreadPool::sTaskThreadArray = NULL;
UInt32 TaskThreadPool::sNumTaskThreads = 0;
UInt32 TaskThreadPool::sNumShortTaskThreads = 0;
UInt32 TaskThreadPool::sNumBlockingTaskThreads = 0;
Bool16 TaskThreadPool::AddThreads(UInt32 numToAdd)
{
Assert(sTaskThreadArray == NULL);
sTaskThreadArray = new TaskThread*[numToAdd];
for (UInt32 x = 0; x < numToAdd; x++)
{
sTaskThreadArray[x] = NEW TaskThread();
sTaskThreadArray[x]->Start();
if (TASK_DEBUG) qtss_printf("TaskThreadPool::AddThreads sTaskThreadArray[%"_U32BITARG_"]=%p\n",x, sTaskThreadArray[x]);
}
sNumTaskThreads = numToAdd;
if (0 == sNumShortTaskThreads)
sNumShortTaskThreads = numToAdd;
return true;
}
TaskThread* TaskThreadPool::GetThread(UInt32 index)
{
Assert(sTaskThreadArray != NULL);
if (index >= sNumTaskThreads)
return NULL;
return sTaskThreadArray[index];
}
void TaskThreadPool::RemoveThreads()
{
//Tell all the threads to stop
for (UInt32 x = 0; x < sNumTaskThreads; x++)
sTaskThreadArray[x]->SendStopRequest();
//Because any (or all) threads may be blocked on the queue, cycle through
//all the threads, signalling each one
for (UInt32 y = 0; y < sNumTaskThreads; y++)
sTaskThreadArray[y]->fTaskQueue.GetCond()->Signal();
//Ok, now wait for the selected threads to terminate, deleting them and removing
//them from the queue.
for (UInt32 z = 0; z < sNumTaskThreads; z++)
delete sTaskThreadArray[z];
sNumTaskThreads = 0;
}

222
CommonUtilitiesLib/Task.h Normal file
View file

@ -0,0 +1,222 @@
/*
*
* @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: Task.h
Contains: Tasks are objects that can be scheduled. To schedule a task, you call its
signal method, and pass in an event (events are bits and all events are defined
below).
Once Signal() is called, the task object will be scheduled. When it runs, its
Run() function will get called. In order to clear the event, the derived task
object must call GetEvents() (which returns the events that were sent).
Calling GetEvents() implicitly "clears" the events returned. All events must
be cleared before the Run() function returns, or Run() will be invoked again
immediately.
*/
#ifndef __TASK_H__
#define __TASK_H__
#include "OSQueue.h"
#include "OSHeap.h"
#include "OSThread.h"
#include "OSMutexRW.h"
#define TASK_DEBUG 0
class TaskThread;
class Task
{
public:
typedef unsigned int EventFlags;
//EVENTS
//here are all the events that can be sent to a task
enum
{
kKillEvent = 0x1 << 0x0, //these are all of type "EventFlags"
kIdleEvent = 0x1 << 0x1,
kStartEvent = 0x1 << 0x2,
kTimeoutEvent = 0x1 << 0x3,
//socket events
kReadEvent = 0x1 << 0x4, //All of type "EventFlags"
kWriteEvent = 0x1 << 0x5,
//update event
kUpdateEvent = 0x1 << 0x6
};
//CONSTRUCTOR / DESTRUCTOR
//You must assign priority at create time.
Task();
virtual ~Task() {}
//return:
// >0-> invoke me after this number of MilSecs with a kIdleEvent
// 0 don't reinvoke me at all.
//-1 delete me
//Suggested practice is that any task should be deleted by returning true from the
//Run function. That way, we know that the Task is not running at the time it is
//deleted. This object provides no protection against calling a method, such as Signal,
//at the same time the object is being deleted (because it can't really), so watch
//those dangling references!
virtual SInt64 Run() = 0;
//Send an event to this task.
void Signal(EventFlags eventFlags);
void GlobalUnlock();
Bool16 Valid(); // for debugging
char fTaskName[48];
void SetTaskName(char* name);
void SetDefaultThread(TaskThread* defaultThread) { fDefaultThread = defaultThread; }
void SetThreadPicker(unsigned int* picker);
static unsigned int* GetBlockingTaskThreadPicker() {return &sBlockingTaskThreadPicker; }
protected:
//Only the tasks themselves may find out what events they have received
EventFlags GetEvents();
// ForceSameThread
//
// A task, inside its run function, may want to ensure that the same task thread
// is used for subsequent calls to Run(). This may be the case if the task is holding
// a mutex between calls to run. By calling this function, the task ensures that the
// same task thread will be used for the next call to Run(). It only applies to the
// next call to run.
void ForceSameThread() {
fUseThisThread = (TaskThread*)OSThread::GetCurrent();
Assert(fUseThisThread != NULL);
if (TASK_DEBUG) if (fTaskName[0] == 0) ::strcpy(fTaskName, " corrupt task");
if (TASK_DEBUG) qtss_printf("Task::ForceSameThread fUseThisThread %p task %s enque elem=%p enclosing %p\n", (void*) fUseThisThread, fTaskName,(void *)&fTaskQueueElem, (void *)this);
}
SInt64 CallLocked() { ForceSameThread();
fWriteLock = true;
return (SInt64) 10; // minimum of 10 milliseconds between locks
}
private:
enum
{
kAlive = 0x80000000, //EventFlags, again
kAliveOff = 0x7fffffff
};
void SetTaskThread(TaskThread *thread);
EventFlags fEvents;
TaskThread* fUseThisThread;
TaskThread* fDefaultThread;
Bool16 fWriteLock;
#if DEBUG
//The whole premise of a task is that the Run function cannot be re-entered.
//This debugging variable ensures that that is always the case
volatile UInt32 fInRunCount;
#endif
//This could later be optimized by using a timing wheel instead of a heap,
//and that way we wouldn't need both a heap elem and a queue elem here (just queue elem)
OSHeapElem fTimerHeapElem;
OSQueueElem fTaskQueueElem;
unsigned int *pickerToUse;
//Variable used for assigning tasks to threads in a round-robin fashion
static unsigned int sShortTaskThreadPicker; //default picker
static unsigned int sBlockingTaskThreadPicker;
friend class TaskThread;
};
class TaskThread : public OSThread
{
public:
//Implementation detail: all tasks get run on TaskThreads.
TaskThread() : OSThread(), fTaskThreadPoolElem()
{fTaskThreadPoolElem.SetEnclosingObject(this);}
virtual ~TaskThread() { this->StopAndWaitForThread(); }
private:
enum
{
kMinWaitTimeInMilSecs = 10 //UInt32
};
virtual void Entry();
Task* WaitForTask();
OSQueueElem fTaskThreadPoolElem;
OSHeap fHeap;
OSQueue_Blocking fTaskQueue;
friend class Task;
friend class TaskThreadPool;
};
//Because task threads share a global queue of tasks to execute,
//there can only be one pool of task threads. That is why this object
//is static.
class TaskThreadPool {
public:
//Adds some threads to the pool
static Bool16 AddThreads(UInt32 numToAdd); // creates the threads: takes NumShortTaskThreads + NumBLockingThreads, sets num short task threads.
static void SwitchPersonality( char *user = NULL, char *group = NULL);
static void RemoveThreads();
static TaskThread* GetThread(UInt32 index);
static UInt32 GetNumThreads() { return sNumTaskThreads; }
static void SetNumShortTaskThreads(UInt32 numToAdd) { sNumShortTaskThreads = numToAdd; }
static void SetNumBlockingTaskThreads(UInt32 numToAdd) { sNumBlockingTaskThreads = numToAdd; }
private:
static TaskThread** sTaskThreadArray;
static UInt32 sNumTaskThreads;
static UInt32 sNumShortTaskThreads;
static UInt32 sNumBlockingTaskThreads;
static OSMutexRW sMutexRW;
friend class Task;
friend class TaskThread;
};
#endif

View file

@ -0,0 +1,116 @@
/*
*
* @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: TimeoutTask.cpp
Contains: Implementation of TimeoutTask
*/
#include "TimeoutTask.h"
#include "OSMemory.h"
TimeoutTaskThread* TimeoutTask::sThread = NULL;
void TimeoutTask::Initialize()
{
if (sThread == NULL)
{
sThread = NEW TimeoutTaskThread();
sThread->Signal(Task::kStartEvent);
}
}
TimeoutTask::TimeoutTask(Task* inTask, SInt64 inTimeoutInMilSecs)
: fTask(inTask), fQueueElem()
{
fQueueElem.SetEnclosingObject(this);
this->SetTimeout(inTimeoutInMilSecs);
if (NULL == inTask)
fTask = (Task *) this;
Assert(sThread != NULL); // this can happen if RunServer intializes tasks in the wrong order
OSMutexLocker locker(&sThread->fMutex);
sThread->fQueue.EnQueue(&fQueueElem);
}
TimeoutTask::~TimeoutTask()
{
OSMutexLocker locker(&sThread->fMutex);
sThread->fQueue.Remove(&fQueueElem);
}
void TimeoutTask::SetTimeout(SInt64 inTimeoutInMilSecs)
{
fTimeoutInMilSecs = inTimeoutInMilSecs;
if (inTimeoutInMilSecs == 0)
fTimeoutAtThisTime = 0;
else
fTimeoutAtThisTime = OS::Milliseconds() + fTimeoutInMilSecs;
}
SInt64 TimeoutTaskThread::Run()
{
//ok, check for timeouts now. Go through the whole queue
OSMutexLocker locker(&fMutex);
SInt64 curTime = OS::Milliseconds();
SInt64 intervalMilli = kIntervalSeconds * 1000;//always default to 60 seconds but adjust to smallest interval > 0
SInt64 taskInterval = intervalMilli;
for (OSQueueIter iter(&fQueue); !iter.IsDone(); iter.Next())
{
TimeoutTask* theTimeoutTask = (TimeoutTask*)iter.GetCurrent()->GetEnclosingObject();
//if it's time to time this task out, signal it
if ((theTimeoutTask->fTimeoutAtThisTime > 0) && (curTime >= theTimeoutTask->fTimeoutAtThisTime))
{
#if TIMEOUT_DEBUGGING
qtss_printf("TimeoutTask %"_S32BITARG_" timed out. Curtime = %"_64BITARG_"d, timeout time = %"_64BITARG_"d\n",(SInt32)theTimeoutTask, curTime, theTimeoutTask->fTimeoutAtThisTime);
#endif
theTimeoutTask->fTask->Signal(Task::kTimeoutEvent);
}
else
{
taskInterval = theTimeoutTask->fTimeoutAtThisTime - curTime;
if ( (taskInterval > 0) && (theTimeoutTask->fTimeoutInMilSecs > 0) && (intervalMilli > taskInterval) )
intervalMilli = taskInterval + 1000; // set timeout to 1 second past this task's timeout
#if TIMEOUT_DEBUGGING
qtss_printf("TimeoutTask %"_S32BITARG_" not being timed out. Curtime = %"_64BITARG_"d. timeout time = %"_64BITARG_"d\n", (SInt32)theTimeoutTask, curTime, theTimeoutTask->fTimeoutAtThisTime);
#endif
}
}
(void)this->GetEvents();//we must clear the event mask!
OSThread::ThreadYield();
#if TIMEOUT_DEBUGGING
qtss_printf ("TimeoutTaskThread::Run interval seconds= %"_S32BITARG_"\n", (SInt32) intervalMilli/1000);
#endif
return intervalMilli;//don't delete me!
}

View file

@ -0,0 +1,113 @@
/*
*
* @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: TimeoutTask.h
Contains: Just like a normal task, but can be scheduled for timeouts. Unlike
IdleTask, which is VERY aggressive about being on time, but high
overhead for maintaining the timing information, this is a low overhead,
low priority timing mechanism. Timeouts may not happen exactly when
they are supposed to, but who cares?
*/
#ifndef __TIMEOUTTASK_H__
#define __TIMEOUTTASK_H__
#include "StrPtrLen.h"
#include "IdleTask.h"
#include "OSThread.h"
#include "OSQueue.h"
#include "OSMutex.h"
#include "OS.h"
#define TIMEOUT_DEBUGGING 0 //messages to help debugging timeouts
class TimeoutTaskThread : public IdleTask
{
public:
//All timeout tasks get timed out from this thread
TimeoutTaskThread() : IdleTask(), fMutex() {this->SetTaskName("TimeoutTask");}
virtual ~TimeoutTaskThread(){}
private:
//this thread runs every minute and checks for timeouts
enum
{
kIntervalSeconds = 60 //UInt32
};
virtual SInt64 Run();
OSMutex fMutex;
OSQueue fQueue;
friend class TimeoutTask;
};
class TimeoutTask
{
//TimeoutTask is not a derived object off of Task, to add flexibility as
//to how this object can be utilitized
public:
//Call Initialize before using this class
static void Initialize();
//Pass in the task you'd like to send timeouts to.
//Also pass in the timeout you'd like to use. By default, the timeout is 0 (NEVER).
TimeoutTask(Task* inTask, SInt64 inTimeoutInMilSecs = 60);
~TimeoutTask();
//MODIFIERS
// Changes the timeout time, also refreshes the timeout
void SetTimeout(SInt64 inTimeoutInMilSecs);
// Specified task will get a Task::kTimeoutEvent if this
// function isn't called within the timeout period
void RefreshTimeout() { fTimeoutAtThisTime = OS::Milliseconds() + fTimeoutInMilSecs; Assert(fTimeoutAtThisTime > 0); }
void SetTask(Task* inTask) { fTask = inTask; }
private:
Task* fTask;
SInt64 fTimeoutAtThisTime;
SInt64 fTimeoutInMilSecs;
//for putting on our global queue of timeout tasks
OSQueueElem fQueueElem;
static TimeoutTaskThread* sThread;
friend class TimeoutTaskThread;
};
#endif //__TIMEOUTTASK_H__

35
CommonUtilitiesLib/Trim.c Normal file
View file

@ -0,0 +1,35 @@
#include "Trim.h"
/*
*
* @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@
*
*/
char* TrimLeft(char* fromStrPtr )
{
char* tmp = &fromStrPtr[0];
// trim any leading white space
while ( (*tmp <= ' ') && (*tmp != 0) )
tmp++;
return tmp;
}

44
CommonUtilitiesLib/Trim.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef __trim__
#define __trim__
/*
*
* @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
char* TrimLeft( char* fromStrPtr );
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,71 @@
/*
*
* @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: UDPDemuxer.cpp
Contains: Implements objects defined in UDPDemuxer.h
*/
#include "UDPDemuxer.h"
#include <errno.h>
OS_Error UDPDemuxer::RegisterTask(UInt32 inRemoteAddr, UInt16 inRemotePort,
UDPDemuxerTask *inTaskP)
{
Assert(NULL != inTaskP);
OSMutexLocker locker(&fMutex);
if (this->GetTask(inRemoteAddr, inRemotePort) != NULL)
return EPERM;
inTaskP->Set(inRemoteAddr, inRemotePort);
fHashTable.Add(inTaskP);
return OS_NoErr;
}
OS_Error UDPDemuxer::UnregisterTask(UInt32 inRemoteAddr, UInt16 inRemotePort,
UDPDemuxerTask *inTaskP)
{
OSMutexLocker locker(&fMutex);
//remove by executing a lookup based on key information
UDPDemuxerTask* theTask = this->GetTask(inRemoteAddr, inRemotePort);
if ((NULL != theTask) && (theTask == inTaskP))
{
fHashTable.Remove(theTask);
return OS_NoErr;
}
else
return EPERM;
}
UDPDemuxerTask* UDPDemuxer::GetTask(UInt32 inRemoteAddr, UInt16 inRemotePort)
{
UDPDemuxerKey theKey(inRemoteAddr, inRemotePort);
return fHashTable.Map(&theKey);
}

View file

@ -0,0 +1,176 @@
/*
*
* @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: UDPDemuxer.h
Contains: Provides a "Listener" socket for UDP. Blocks on a local IP & port,
waiting for data. When it gets data, it passes it off to a UDPDemuxerTask
object depending on where it came from.
*/
#ifndef __UDPDEMUXER_H__
#define __UDPDEMUXER_H__
#include "OSHashTable.h"
#include "OSMutex.h"
#include "StrPtrLen.h"
class Task;
class UDPDemuxerKey;
//IMPLEMENTATION ONLY:
//HASH TABLE CLASSES USED ONLY IN IMPLEMENTATION
class UDPDemuxerUtils
{
private:
static UInt32 ComputeHashValue(UInt32 inRemoteAddr, UInt16 inRemotePort)
{ return ((inRemoteAddr << 16) + inRemotePort); }
friend class UDPDemuxerTask;
friend class UDPDemuxerKey;
};
class UDPDemuxerTask
{
public:
UDPDemuxerTask()
: fRemoteAddr(0), fRemotePort(0),
fHashValue(0), fNextHashEntry(NULL) {}
virtual ~UDPDemuxerTask() {}
UInt32 GetRemoteAddr() { return fRemoteAddr; }
private:
void Set(UInt32 inRemoteAddr, UInt16 inRemotePort)
{ fRemoteAddr = inRemoteAddr; fRemotePort = inRemotePort;
fHashValue = UDPDemuxerUtils::ComputeHashValue(fRemoteAddr, fRemotePort);
}
//key values
UInt32 fRemoteAddr;
UInt16 fRemotePort;
//precomputed for performance
UInt32 fHashValue;
UDPDemuxerTask *fNextHashEntry;
friend class UDPDemuxerKey;
friend class UDPDemuxer;
friend class OSHashTable<UDPDemuxerTask,UDPDemuxerKey>;
};
class UDPDemuxerKey
{
private:
//CONSTRUCTOR / DESTRUCTOR:
UDPDemuxerKey(UInt32 inRemoteAddr, UInt16 inRemotePort)
: fRemoteAddr(inRemoteAddr), fRemotePort(inRemotePort)
{ fHashValue = UDPDemuxerUtils::ComputeHashValue(inRemoteAddr, inRemotePort); }
~UDPDemuxerKey() {}
private:
//PRIVATE ACCESSORS:
UInt32 GetHashKey() { return fHashValue; }
//these functions are only used by the hash table itself. This constructor
//will break the "Set" functions.
UDPDemuxerKey(UDPDemuxerTask *elem) : fRemoteAddr(elem->fRemoteAddr),
fRemotePort(elem->fRemotePort),
fHashValue(elem->fHashValue) {}
friend int operator ==(const UDPDemuxerKey &key1, const UDPDemuxerKey &key2) {
if ((key1.fRemoteAddr == key2.fRemoteAddr) &&
(key1.fRemotePort == key2.fRemotePort))
return true;
return false;
}
//data:
UInt32 fRemoteAddr;
UInt16 fRemotePort;
UInt32 fHashValue;
friend class OSHashTable<UDPDemuxerTask,UDPDemuxerKey>;
friend class UDPDemuxer;
};
//CLASSES USED ONLY IN IMPLEMENTATION
typedef OSHashTable<UDPDemuxerTask, UDPDemuxerKey> UDPDemuxerHashTable;
class UDPDemuxer
{
public:
UDPDemuxer() : fHashTable(kMaxHashTableSize), fMutex() {}
~UDPDemuxer() {}
//These functions grab the mutex and are therefore premptive safe
// Return values: OS_NoErr, or EPERM if there is already a task registered
// with this address combination
OS_Error RegisterTask(UInt32 inRemoteAddr, UInt16 inRemotePort,
UDPDemuxerTask *inTaskP);
// Return values: OS_NoErr, or EPERM if this task / address combination
// is not registered
OS_Error UnregisterTask(UInt32 inRemoteAddr, UInt16 inRemotePort,
UDPDemuxerTask *inTaskP);
//Assumes that parent has grabbed the mutex!
UDPDemuxerTask* GetTask(UInt32 inRemoteAddr, UInt16 inRemotePort);
Bool16 AddrInMap(UInt32 inRemoteAddr, UInt16 inRemotePort)
{ return (this->GetTask(inRemoteAddr, inRemotePort) != NULL); }
OSMutex* GetMutex() { return &fMutex; }
UDPDemuxerHashTable* GetHashTable() { return &fHashTable; }
private:
enum
{
kMaxHashTableSize = 2747//is this prime? it should be... //UInt32
};
UDPDemuxerHashTable fHashTable;
OSMutex fMutex;//this data structure is shared!
};
#endif // __UDPDEMUXER_H__

View file

@ -0,0 +1,176 @@
/*
*
* @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: UDPSocket.cpp
Contains: Implementation of object defined in UDPSocket.h.
*/
#ifndef __Win32__
#include <sys/types.h>
#include <sys/socket.h>
#if __solaris__
#include "SocketUtils.h"
#endif
#if NEED_SOCKETBITS
#if __GLIBC__ >= 2
#include <bits/socket.h>
#else
#include <socketbits.h>
#endif
#endif
#endif
#include <errno.h>
#include "UDPSocket.h"
#include "OSMemory.h"
#ifdef USE_NETLOG
#include <netlog.h>
#endif
UDPSocket::UDPSocket(Task* inTask, UInt32 inSocketType)
: Socket(inTask, inSocketType), fDemuxer(NULL)
{
if (inSocketType & kWantsDemuxer)
fDemuxer = NEW UDPDemuxer();
//setup msghdr
::memset(&fMsgAddr, 0, sizeof(fMsgAddr));
}
OS_Error
UDPSocket::SendTo(UInt32 inRemoteAddr, UInt16 inRemotePort, void* inBuffer, UInt32 inLength)
{
Assert(inBuffer != NULL);
struct sockaddr_in theRemoteAddr;
theRemoteAddr.sin_family = AF_INET;
theRemoteAddr.sin_port = htons(inRemotePort);
theRemoteAddr.sin_addr.s_addr = htonl(inRemoteAddr);
#ifdef __sgi__
int theErr = ::sendto(fFileDesc, inBuffer, inLength, 0, (sockaddr*)&theRemoteAddr, sizeof(theRemoteAddr));
#else
// Win32 says that inBuffer is a char*
int theErr = ::sendto(fFileDesc, (char*)inBuffer, inLength, 0, (sockaddr*)&theRemoteAddr, sizeof(theRemoteAddr));
#endif
if (theErr == -1)
return (OS_Error)OSThread::GetErrno();
return OS_NoErr;
}
OS_Error UDPSocket::RecvFrom(UInt32* outRemoteAddr, UInt16* outRemotePort,
void* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
{
Assert(outRecvLen != NULL);
Assert(outRemoteAddr != NULL);
Assert(outRemotePort != NULL);
#if __Win32__ || __osf__ || __sgi__ || __hpux__
int addrLen = sizeof(fMsgAddr);
#else
socklen_t addrLen = sizeof(fMsgAddr);
#endif
#ifdef __sgi__
SInt32 theRecvLen = ::recvfrom(fFileDesc, ioBuffer, inBufLen, 0, (sockaddr*)&fMsgAddr, &addrLen);
#else
// Win32 says that ioBuffer is a char*
SInt32 theRecvLen = ::recvfrom(fFileDesc, (char*)ioBuffer, inBufLen, 0, (sockaddr*)&fMsgAddr, &addrLen);
#endif
if (theRecvLen == -1)
return (OS_Error)OSThread::GetErrno();
*outRemoteAddr = ntohl(fMsgAddr.sin_addr.s_addr);
*outRemotePort = ntohs(fMsgAddr.sin_port);
Assert(theRecvLen >= 0);
*outRecvLen = (UInt32)theRecvLen;
return OS_NoErr;
}
OS_Error UDPSocket::JoinMulticast(UInt32 inRemoteAddr)
{
struct ip_mreq theMulti;
UInt32 localAddr = fLocalAddr.sin_addr.s_addr; // Already in network byte order
#if __solaris__
if( localAddr == htonl(INADDR_ANY) )
localAddr = htonl(SocketUtils::GetIPAddr(0));
#endif
theMulti.imr_multiaddr.s_addr = htonl(inRemoteAddr);
theMulti.imr_interface.s_addr = localAddr;
int err = setsockopt(fFileDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
//AssertV(err == 0, OSThread::GetErrno());
if (err == -1)
return (OS_Error)OSThread::GetErrno();
else
return OS_NoErr;
}
OS_Error UDPSocket::SetTtl(UInt16 timeToLive)
{
// set the ttl
u_char nOptVal = (u_char)timeToLive;//dms - stevens pp. 496. bsd implementations barf
//unless this is a u_char
int err = setsockopt(fFileDesc, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
if (err == -1)
return (OS_Error)OSThread::GetErrno();
else
return OS_NoErr;
}
OS_Error UDPSocket::SetMulticastInterface(UInt32 inLocalAddr)
{
// set the outgoing interface for multicast datagrams on this socket
in_addr theLocalAddr;
theLocalAddr.s_addr = inLocalAddr;
int err = setsockopt(fFileDesc, IPPROTO_IP, IP_MULTICAST_IF, (char*)&theLocalAddr, sizeof(theLocalAddr));
AssertV(err == 0, OSThread::GetErrno());
if (err == -1)
return (OS_Error)OSThread::GetErrno();
else
return OS_NoErr;
}
OS_Error UDPSocket::LeaveMulticast(UInt32 inRemoteAddr)
{
struct ip_mreq theMulti;
theMulti.imr_multiaddr.s_addr = htonl(inRemoteAddr);
theMulti.imr_interface.s_addr = htonl(fLocalAddr.sin_addr.s_addr);
int err = setsockopt(fFileDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
if (err == -1)
return (OS_Error)OSThread::GetErrno();
else
return OS_NoErr;
}

View file

@ -0,0 +1,88 @@
/*
*
* @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: UDPSocket.h
Contains: Adds additional Socket functionality specific to UDP.
*/
#ifndef __UDPSOCKET_H__
#define __UDPSOCKET_H__
#ifndef __Win32__
#include <sys/socket.h>
#include <sys/uio.h>
#endif
#include "Socket.h"
#include "UDPDemuxer.h"
class UDPSocket : public Socket
{
public:
//Another socket type flag (in addition to the ones defined in Socket.h).
//The value of this can't conflict with those!
enum
{
kWantsDemuxer = 0x0100 //UInt32
};
UDPSocket(Task* inTask, UInt32 inSocketType);
virtual ~UDPSocket() { if (fDemuxer != NULL) delete fDemuxer; }
//Open
OS_Error Open() { return Socket::Open(SOCK_DGRAM); }
OS_Error JoinMulticast(UInt32 inRemoteAddr);
OS_Error LeaveMulticast(UInt32 inRemoteAddr);
OS_Error SetTtl(UInt16 timeToLive);
OS_Error SetMulticastInterface(UInt32 inLocalAddr);
//returns an ERRNO
OS_Error SendTo(UInt32 inRemoteAddr, UInt16 inRemotePort,
void* inBuffer, UInt32 inLength);
OS_Error RecvFrom(UInt32* outRemoteAddr, UInt16* outRemotePort,
void* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
//A UDP socket may or may not have a demuxer associated with it. The demuxer
//is a data structure so the socket can associate incoming data with the proper
//task to process that data (based on source IP addr & port)
UDPDemuxer* GetDemuxer() { return fDemuxer; }
private:
UDPDemuxer* fDemuxer;
struct sockaddr_in fMsgAddr;
};
#endif // __UDPSOCKET_H__

View file

@ -0,0 +1,152 @@
/*
*
* @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: UDPSocketPool.cpp
Contains: Object that creates & maintains UDP socket pairs in a pool.
*/
#include "UDPSocketPool.h"
UDPSocketPair* UDPSocketPool::GetUDPSocketPair(UInt32 inIPAddr, UInt16 inPort,
UInt32 inSrcIPAddr, UInt16 inSrcPort)
{
OSMutexLocker locker(&fMutex);
if ((inSrcIPAddr != 0) || (inSrcPort != 0))
{
for (OSQueueIter qIter(&fUDPQueue); !qIter.IsDone(); qIter.Next())
{
//If we find a pair that is a) on the right IP address, and b) doesn't
//have this source IP & port in the demuxer already, we can return this pair
UDPSocketPair* theElem = (UDPSocketPair*)qIter.GetCurrent()->GetEnclosingObject();
if ((theElem->fSocketA->GetLocalAddr() == inIPAddr) &&
((inPort == 0) || (theElem->fSocketA->GetLocalPort() == inPort)))
{
//check to make sure this source IP & port is not already in the demuxer.
//If not, we can return this socket pair.
if ((theElem->fSocketB->GetDemuxer() == NULL) ||
((!theElem->fSocketB->GetDemuxer()->AddrInMap(0, 0)) &&
(!theElem->fSocketB->GetDemuxer()->AddrInMap(inSrcIPAddr, inSrcPort))))
{
theElem->fRefCount++;
return theElem;
}
//If port is specified, there is NO WAY a socket pair can exist that matches
//the criteria (because caller wants a specific ip & port combination)
else if (inPort != 0)
return NULL;
}
}
}
//if we get here, there is no pair already in the pool that matches the specified
//criteria, so we have to create a new pair.
return this->CreateUDPSocketPair(inIPAddr, inPort);
}
void UDPSocketPool::ReleaseUDPSocketPair(UDPSocketPair* inPair)
{
OSMutexLocker locker(&fMutex);
inPair->fRefCount--;
if (inPair->fRefCount == 0)
{
fUDPQueue.Remove(&inPair->fElem);
this->DestructUDPSocketPair(inPair);
}
}
UDPSocketPair* UDPSocketPool::CreateUDPSocketPair(UInt32 inAddr, UInt16 inPort)
{
//try to find an open pair of ports to bind these suckers tooo
OSMutexLocker locker(&fMutex);
UDPSocketPair* theElem = NULL;
Bool16 foundPair = false;
UInt16 curPort = kLowestUDPPort;
UInt16 stopPort = kHighestUDPPort -1; // prevent roll over when iterating over port nums
UInt16 socketBPort = kLowestUDPPort + 1;
//If port is 0, then the caller doesn't care what port # we bind this socket to.
//Otherwise, ONLY attempt to bind this socket to the specified port
if (inPort != 0)
curPort = inPort;
if (inPort != 0)
stopPort = inPort;
while ((!foundPair) && (curPort < kHighestUDPPort))
{
socketBPort = curPort +1; // make socket pairs adjacent to one another
theElem = ConstructUDPSocketPair();
Assert(theElem != NULL);
if (theElem->fSocketA->Open() != OS_NoErr)
{
this->DestructUDPSocketPair(theElem);
return NULL;
}
if (theElem->fSocketB->Open() != OS_NoErr)
{
this->DestructUDPSocketPair(theElem);
return NULL;
}
// Set socket options on these new sockets
this->SetUDPSocketOptions(theElem);
OS_Error theErr = theElem->fSocketA->Bind(inAddr, curPort);
if (theErr == OS_NoErr)
{ //qtss_printf("fSocketA->Bind ok on port%u\n", curPort);
theErr = theElem->fSocketB->Bind(inAddr, socketBPort);
if (theErr == OS_NoErr)
{ //qtss_printf("fSocketB->Bind ok on port%u\n", socketBPort);
foundPair = true;
fUDPQueue.EnQueue(&theElem->fElem);
theElem->fRefCount++;
return theElem;
}
//else qtss_printf("fSocketB->Bind failed on port%u\n", socketBPort);
}
//else qtss_printf("fSocketA->Bind failed on port%u\n", curPort);
//If we are looking to bind to a specific port set, and we couldn't then
//just break here.
if (inPort != 0)
break;
if (curPort >= stopPort) //test for stop condition
break;
curPort += 2; //try a higher port pair
this->DestructUDPSocketPair(theElem); //a bind failure
theElem = NULL;
}
//if we couldn't find a pair of sockets, make sure to clean up our mess
if (theElem != NULL)
this->DestructUDPSocketPair(theElem);
return NULL;
}

View file

@ -0,0 +1,114 @@
/*
*
* @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: UDPSocketPool.h
Contains: Object that creates & maintains UDP socket pairs in a pool.
*/
#ifndef __UDPSOCKETPOOL_H__
#define __UDPSOCKETPOOL_H__
#include "UDPDemuxer.h"
#include "UDPSocket.h"
#include "OSMutex.h"
#include "OSQueue.h"
class UDPSocketPair;
class UDPSocketPool
{
public:
UDPSocketPool() : fMutex() {}
virtual ~UDPSocketPool() {}
//Skanky access to member data
OSMutex* GetMutex() { return &fMutex; }
OSQueue* GetSocketQueue() { return &fUDPQueue; }
//Gets a UDP socket out of the pool.
//inIPAddr = IP address you'd like this pair to be bound to.
//inPort = port you'd like this pair to be bound to, or 0 if you don't care
//inSrcIPAddr = srcIP address of incoming packets for the demuxer.
//inSrcPort = src port of incoming packets for the demuxer.
//This may return NULL if no pair is available that meets the criteria.
UDPSocketPair* GetUDPSocketPair(UInt32 inIPAddr, UInt16 inPort,
UInt32 inSrcIPAddr, UInt16 inSrcPort);
//When done using a UDP socket pair retrieved via GetUDPSocketPair, you must
//call this function. Doing so tells the pool which UDP sockets are in use,
//keeping the number of UDP sockets allocated at a minimum.
void ReleaseUDPSocketPair(UDPSocketPair* inPair);
UDPSocketPair* CreateUDPSocketPair(UInt32 inAddr, UInt16 inPort);
protected:
//Because UDPSocket is a base class, and this pool class is intended to be
//a general purpose class for all types of UDP sockets (reflector, standard),
//there must be a virtual fuction for actually constructing the derived UDP sockets
virtual UDPSocketPair* ConstructUDPSocketPair() = 0;
virtual void DestructUDPSocketPair(UDPSocketPair* inPair) = 0;
virtual void SetUDPSocketOptions(UDPSocketPair* /*inPair*/) {}
private:
enum
{
kLowestUDPPort = 6970, //UInt16
kHighestUDPPort = 65535 //UInt16
};
OSQueue fUDPQueue;
OSMutex fMutex;
};
class UDPSocketPair
{
public:
UDPSocketPair(UDPSocket* inSocketA, UDPSocket* inSocketB)
: fSocketA(inSocketA), fSocketB(inSocketB), fRefCount(0), fElem() {fElem.SetEnclosingObject(this);}
~UDPSocketPair() {}
UDPSocket* GetSocketA() { return fSocketA; }
UDPSocket* GetSocketB() { return fSocketB; }
private:
UDPSocket* fSocketA;
UDPSocket* fSocketB;
UInt32 fRefCount;
OSQueueElem fElem;
friend class UDPSocketPool;
};
#endif // __UDPSOCKETPOOL_H__

View file

@ -0,0 +1,183 @@
/*
*
* @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: UserAgentParser.cpp
Contains: Parse the User-Agent: entry of an RTSP request.
*/
#include "StringParser.h"
#include "StringFormatter.h"
#include "StrPtrLen.h"
#include "UserAgentParser.h"
UserAgentParser::UserAgentFields UserAgentParser::sFieldIDs[] =
{ /* fAttrName, len, id */
{ "qtid", strlen("qtid"), eQtid },
{ "qtver", strlen("qtver"), eQtver },
{ "lang", strlen("lang"), eLang },
{ "os", strlen("os"), eOs },
{ "osver", strlen("osver"), eOsver },
{ "cpu", strlen("cpu"), eCpu }
};
UInt8 UserAgentParser::sEOLWhitespaceEqualMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 // \t is a stop
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 ' ' 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, 1, 0, 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
};
UInt8 UserAgentParser::sEOLSemicolonCloseParenMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 // \t is a stop
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, 0, 0, 0, 0, 0, 0, 0, 0, //30-39
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, //40-49 ')' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //50-59 ';' is a stop
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
};
void UserAgentParser::Parse(StrPtrLen *inStream)
{
StrPtrLen tempID;
StrPtrLen tempData;
StringParser parser(inStream);
StrPtrLen startFields;
memset(&fFieldData,0,sizeof(fFieldData) );
parser.ConsumeUntil(&startFields, '(' ); // search for '(' if not found does nothing
// parse through everything between the '(' and ')'.
while (startFields.Len != 0)
{
//stop when we reach an empty line.
tempID.Set(NULL,0);
tempData.Set(NULL,0);
parser.ConsumeLength(NULL, 1); // step past '(' or ';' if not found or at end of line does nothing
parser.ConsumeWhitespace(); // search for non-white space if not found does nothing
parser.ConsumeUntil(&tempID, sEOLWhitespaceEqualMask ); // search for end of id (whitespace or =)if not found does nothing
if (tempID.Len == 0) break;
parser.ConsumeUntil(NULL, '=' ); // find the '='
parser.ConsumeLength(NULL, 1); // step past if not found or at end of line does nothing
parser.ConsumeUntil(&tempData, sEOLSemicolonCloseParenMask ); // search for end of data if not found does nothing
if (tempData.Len == 0) break;
StrPtrLen testID;
UInt32 fieldID;
for (short testField = 0; testField < UserAgentParser::eNumAttributes; testField++)
{
testID.Set(sFieldIDs[testField].fFieldName,sFieldIDs[testField].fLen);
fieldID = sFieldIDs[testField].fID;
if ( (fFieldData[fieldID].fFound == false) && testID.Equal(tempID) )
{
fFieldData[fieldID].fData = tempData;
fFieldData[fieldID].fFound = true;
}
}
}
// If we parsed the OS field but not the OSVer field then check and see if
// the OS field contains the OS version. If it does copy it from there.
// (e.g. 'os=Mac%209.2.2' or 'os=Windows%20NT%204.0'.)
if (fFieldData[eOs].fFound && !fFieldData[eOsver].fFound)
{
UInt16 len = (UInt16)fFieldData[eOs].fData.Len;
char* cp = (char*)fFieldData[eOs].fData.Ptr;
// skip up to the blank space if it exists.
// (i.e. the blank is URL encoded as '%20')
while(*cp != '%')
{
len--;
if (*cp == '\0' || len == 0)
{
// no blank space...so we're all done.
return;
}
cp++;
}
// skip over the blank space.
cp += 3; len -= 3;
// the remaining string is the OS version.
fFieldData[eOsver].fData.Set(cp, len);
fFieldData[eOsver].fFound = true;
// and truncate the version from the OS field.
fFieldData[eOs].fData.Len -= len+3;
}
}

View file

@ -0,0 +1,92 @@
/*
*
* @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: UserAgentParser.h
Contains: API interface for parsing the user agent field received from RTSP clients.
Change History (most recent first):
*/
#ifndef _USERAGENTPARSER_H_
#define _USERAGENTPARSER_H_
#include "StringParser.h"
#include "StringFormatter.h"
#include "StrPtrLen.h"
class UserAgentParser
{
public:
enum{ eMaxAttributeSize = 60 };
struct UserAgentFields
{
char fFieldName[eMaxAttributeSize + 1];
UInt32 fLen;
UInt32 fID;
};
struct UserAgentData
{
StrPtrLen fData;
bool fFound;
};
enum
{ eQtid = 0,
eQtver = 1,
eLang = 2,
eOs = 3,
eOsver = 4,
eCpu = 5,
eNumAttributes = 6
};
static UserAgentFields sFieldIDs[];
static UInt8 sEOLWhitespaceEqualMask[];
static UInt8 sEOLSemicolonCloseParenMask[];
static UInt8 sWhitespaceMask[];
UserAgentData fFieldData[eNumAttributes];
void Parse(StrPtrLen *inStream);
StrPtrLen* GetUserID() { return &(fFieldData[eQtid].fData); };
StrPtrLen* GetUserVersion() { return &(fFieldData[eQtver].fData); };
StrPtrLen* GetUserLanguage() { return &(fFieldData[eLang].fData); };
StrPtrLen* GetrUserOS() { return &(fFieldData[eOs].fData); };
StrPtrLen* GetUserOSVersion() { return &(fFieldData[eOsver].fData); };
StrPtrLen* GetUserCPU() { return &(fFieldData[eCpu].fData); };
UserAgentParser (StrPtrLen *inStream) { if (inStream != NULL) Parse(inStream); }
};
#endif // _USERAGENTPARSER_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@
*
*/
#include "atomic.h"
#include "OSMutex.h"
static OSMutex sAtomicMutex;
unsigned int atomic_add(unsigned int *area, int val)
{
OSMutexLocker locker(&sAtomicMutex);
*area += val;
return *area;
}
unsigned int atomic_sub(unsigned int *area,int val)
{
return atomic_add(area,-val);
}
unsigned int atomic_or(unsigned int *area, unsigned int val)
{
unsigned int oldval;
OSMutexLocker locker(&sAtomicMutex);
oldval=*area;
*area = oldval | val;
return oldval;
}
unsigned int compare_and_store(unsigned int oval, unsigned int nval, unsigned int *area)
{
int rv;
OSMutexLocker locker(&sAtomicMutex);
if( oval == *area )
{
rv=1;
*area = nval;
}
else
rv=0;
return rv;
}

View file

@ -0,0 +1,97 @@
/*
*
* @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:
* 11-Feb-1999 Umesh Vaishampayan (umeshv@apple.com)
* Added atomic_or().
*
* 26-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Made the header c++ friendly.
*
* 12-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Changed simple_ to spin_ so as to coexist with cthreads till
* the merge to the system framework.
*
* 8-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Created from the kernel code to be in a dynamic shared library.
* Kernel code created by: Bill Angell (angell@apple.com)
*/
#ifndef _ATOMIC_H_
#define _ATOMIC_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Locking routines */
struct spin_lock { /* sizeof cache line */
unsigned int lock_data;
unsigned int pad[7];
};
typedef struct spin_lock *spin_lock_t;
extern void spin_lock_init(spin_lock_t);
extern void spin_lock_unlock(spin_lock_t);
extern unsigned int spin_lock_lock(spin_lock_t);
extern unsigned int spin_lock_bit(spin_lock_t, unsigned int bits);
extern unsigned int spin_unlock_bit(spin_lock_t, unsigned int bits);
extern unsigned int spin_lock_try(spin_lock_t);
extern unsigned int spin_lock_held(spin_lock_t);
/* Other atomic routines */
extern unsigned int compare_and_store(unsigned int oval,
unsigned int nval, unsigned int *area);
extern unsigned int atomic_add(unsigned int *area, int val);
extern unsigned int atomic_or(unsigned int *area, unsigned int mask);
extern unsigned int atomic_sub(unsigned int *area, int val);
extern void queue_atomic(unsigned int *anchor,
unsigned int *elem, unsigned int disp);
extern void queue_atomic_list(unsigned int *anchor,
unsigned int *first, unsigned int *last,
unsigned int disp);
extern unsigned int *dequeue_atomic(unsigned int *anchor, unsigned int disp);
#ifdef __cplusplus
}
#endif
#endif /* _ATOMIC_H_ */

209
CommonUtilitiesLib/base64.c Normal file
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@
*/
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
/* Base64 encoder/decoder. Originally Apache file ap_base64.c
*/
#include <string.h>
#include "base64.h"
/* aaaack but it's fast and const should make it shared text page. */
static const unsigned char pr2six[256] =
{
/* ASCII table */
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
int Base64decode_len(const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
return nbytesdecoded + 1;
}
int Base64decode(char *bufplain, const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register unsigned char *bufout;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
bufout = (unsigned char *) bufplain;
bufin = (const unsigned char *) bufcoded;
while (nprbytes > 4) {
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
/* Note: (nprbytes == 1) would be an error, so just ingore that case */
if (nprbytes > 1) {
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
}
if (nprbytes > 2) {
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
}
if (nprbytes > 3) {
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
}
*(bufout++) = '\0';
nbytesdecoded -= (4 - nprbytes) & 3;
return nbytesdecoded;
}
static const char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Base64encode_len(int len)
{
return ((len + 2) / 3 * 4) + 1;
}
int Base64encode(char *encoded, const char *string, int len)
{
int i;
char *p;
p = encoded;
for (i = 0; i < len - 2; i += 3) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2) |
((int) (string[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[string[i + 2] & 0x3F];
}
if (i < len) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1)) {
*p++ = basis_64[((string[i] & 0x3) << 4)];
*p++ = '=';
}
else {
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2)];
}
*p++ = '=';
}
*p++ = '\0';
return p - encoded;
}

101
CommonUtilitiesLib/base64.h Normal file
View file

@ -0,0 +1,101 @@
/*
* 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@
*/
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
#ifndef _BASE64_H_
#define _BASE64_H_
#ifdef __cplusplus
extern "C" {
#endif
int Base64encode_len(int len);
int Base64encode(char * coded_dst, const char *plain_src,int len_plain_src);
int Base64decode_len(const char * coded_src);
int Base64decode(char * plain_dst, const char *coded_src);
#ifdef __cplusplus
}
#endif
#endif //_BASE64_H_

View file

@ -0,0 +1,89 @@
/*
*
* @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@
*
*/
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <fcntl.h>
#include <unistd.h>
#include "daemon.h"
int daemon(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close (fd);
}
return (0);
}

View file

@ -0,0 +1,73 @@
/*
*
* @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@
*
*/
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _DAEMON_H_
#define _DAEMON_H_
#ifdef __cplusplus
extern "C" {
#endif
int daemon(int nochdir, int noclose);
#ifdef __cplusplus
}
#endif
#endif

475
CommonUtilitiesLib/ev.cpp Normal file
View file

@ -0,0 +1,475 @@
/*
*
* @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: ev.cpp
Contains: POSIX select implementation of MacOS X event queue functions.
*/
#if !MACOSXEVENTQUEUE
#define EV_DEBUGGING 0 //Enables a lot of printfs
#if SET_SELECT_SIZE
#ifndef FD_SETSIZE
#define FD_SETSIZE SET_SELECT_SIZE
#endif
#endif
#include <sys/time.h>
#include <sys/types.h>
#ifndef __MACOS__
#ifndef __hpux__
#include <sys/select.h>
#endif
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>
#include "ev.h"
#include "OS.h"
#include "OSHeaders.h"
#include "MyAssert.h"
#include "OSThread.h"
#include "OSMutex.h"
static fd_set sReadSet;
static fd_set sWriteSet;
static fd_set sReturnedReadSet;
static fd_set sReturnedWriteSet;
static void** sCookieArray = NULL;
static int* sFDsToCloseArray = NULL;
static int sPipes[2];
static int sCurrentFDPos = 0;
static int sMaxFDPos = 0;
static bool sInReadSet = true;
static int sNumFDsBackFromSelect = 0;
static UInt32 sNumFDsProcessed = 0;
static OSMutex sMaxFDPosMutex;
static bool selecthasdata();
static int constructeventreq(struct eventreq* req, int fd, int event);
void select_startevents()
{
FD_ZERO(&sReadSet);
FD_ZERO(&sWriteSet);
FD_ZERO(&sReturnedReadSet);
FD_ZERO(&sReturnedWriteSet);
//qtss_printf("FD_SETSIZE=%d sizeof(fd_set) * 8 ==%ld\n", FD_SETSIZE, sizeof(fd_set) * 8);
//We need to associate cookies (void*)'s with our file descriptors.
//We do so by storing cookies in this cookie array. Because an fd_set is
//a big array of bits, we should have as many entries in the array as
//there are bits in the fd set
sCookieArray = new void*[sizeof(fd_set) * 8];
::memset(sCookieArray, 0, sizeof(void *) * sizeof(fd_set) * 8);
//We need to close all fds from the select thread. Once an fd is passed into
//removeevent, its added to this array so it may be deleted from the select thread
sFDsToCloseArray = new int[sizeof(fd_set) * 8];
for (int i = 0; i < (int) (sizeof(fd_set) * 8); i++)
sFDsToCloseArray[i] = -1;
//We need to wakeup select when the masks have changed. In order to do this,
//we create a pipe that gets written to from modwatch, and read when select returns
int theErr = ::pipe((int*)&sPipes);
Assert(theErr == 0);
//Add the read end of the pipe to the read mask
FD_SET(sPipes[0], &sReadSet);
sMaxFDPos = sPipes[0];
}
int select_removeevent(int which)
{
{
//Manipulating sMaxFDPos is not pre-emptive safe, so we have to wrap it in a mutex
//I believe this is the only variable that is not preemptive safe....
OSMutexLocker locker(&sMaxFDPosMutex);
//Clear this fd out of both sets
FD_CLR(which, &sWriteSet);
FD_CLR(which, &sReadSet);
FD_CLR(which, &sReturnedReadSet);
FD_CLR(which, &sReturnedWriteSet);
sCookieArray[which] = NULL; // Clear out the cookie
if (which == sMaxFDPos)
{
//We've just deleted the highest numbered fd in our set,
//so we need to recompute what the highest one is.
while (!FD_ISSET(sMaxFDPos, &sReadSet) && !FD_ISSET(sMaxFDPos, &sWriteSet) &&
(sMaxFDPos > 0))
{
#if EV_DEBUGGING
qtss_printf("removeevent: reset MaxFDPos = %d to %d\n", sMaxFDPos , sMaxFDPos -1);
#endif
sMaxFDPos--;
}
}
//We also need to keep the mutex locked during any manipulation of the
//sFDsToCloseArray, because it's definitely not preemptive safe.
//put this fd into the fd's to close array, so that when select wakes up, it will
//close the fd
UInt32 theIndex = 0;
while ((sFDsToCloseArray[theIndex] != -1) && (theIndex < sizeof(fd_set) * 8))
theIndex++;
Assert(sFDsToCloseArray[theIndex] == -1);
sFDsToCloseArray[theIndex] = which;
#if EV_DEBUGGING
qtss_printf("removeevent: Disabled %d \n", which);
#endif
}
//write to the pipe so that select wakes up and registers the new mask
int theErr = ::write(sPipes[1], "p", 1);
Assert(theErr == 1);
return 0;
}
int select_watchevent(struct eventreq *req, int which)
{
return select_modwatch(req, which);
}
int select_modwatch(struct eventreq *req, int which)
{
{
//Manipulating sMaxFDPos is not pre-emptive safe, so we have to wrap it in a mutex
//I believe this is the only variable that is not preemptive safe....
OSMutexLocker locker(&sMaxFDPosMutex);
//Add or remove this fd from the specified sets
if (which & EV_RE)
{
#if EV_DEBUGGING
qtss_printf("modwatch: Enabling %d in readset\n", req->er_handle);
#endif
FD_SET(req->er_handle, &sReadSet);
}
else
{
#if EV_DEBUGGING
qtss_printf("modwatch: Disbling %d in readset\n", req->er_handle);
#endif
FD_CLR(req->er_handle, &sReadSet);
}
if (which & EV_WR)
{
#if EV_DEBUGGING
qtss_printf("modwatch: Enabling %d in writeset\n", req->er_handle);
#endif
FD_SET(req->er_handle, &sWriteSet);
}
else
{
#if EV_DEBUGGING
qtss_printf("modwatch: Disabling %d in writeset\n", req->er_handle);
#endif
FD_CLR(req->er_handle, &sWriteSet);
}
if (req->er_handle > sMaxFDPos)
sMaxFDPos = req->er_handle;
#if EV_DEBUGGING
qtss_printf("modwatch: MaxFDPos=%d\n", sMaxFDPos);
#endif
//
// Also, modifying the cookie is not preemptive safe. This must be
// done atomically wrt setting the fd in the set. Otherwise, it is
// possible to have a NULL cookie on a fd.
Assert(req->er_handle < (int)(sizeof(fd_set) * 8));
Assert(req->er_data != NULL);
sCookieArray[req->er_handle] = req->er_data;
}
//write to the pipe so that select wakes up and registers the new mask
int theErr = ::write(sPipes[1], "p", 1);
Assert(theErr == 1);
return 0;
}
int constructeventreq(struct eventreq* req, int fd, int event)
{
Assert(fd < (int)(sizeof(fd_set) * 8));
if (fd >=(int)(sizeof(fd_set) * 8) )
{
#if EV_DEBUGGING
qtss_printf("constructeventreq: invalid fd=%d\n", fd);
#endif
return 0;
}
req->er_handle = fd;
req->er_eventbits = event;
req->er_data = sCookieArray[fd];
sCurrentFDPos++;
sNumFDsProcessed++;
//don't want events on this fd until modwatch is called.
FD_CLR(fd, &sWriteSet);
FD_CLR(fd, &sReadSet);
return 0;
}
int select_waitevent(struct eventreq *req, void* /*onlyForMacOSX*/)
{
//Check to see if we still have some select descriptors to process
int theFDsProcessed = (int)sNumFDsProcessed;
bool isSet = false;
if (theFDsProcessed < sNumFDsBackFromSelect)
{
if (sInReadSet)
{
OSMutexLocker locker(&sMaxFDPosMutex);
#if EV_DEBUGGING
qtss_printf("waitevent: Looping through readset starting at %d\n", sCurrentFDPos);
#endif
while((!(isSet = FD_ISSET(sCurrentFDPos, &sReturnedReadSet))) && (sCurrentFDPos < sMaxFDPos))
sCurrentFDPos++;
if (isSet)
{
#if EV_DEBUGGING
qtss_printf("waitevent: Found an fd: %d in readset max=%d\n", sCurrentFDPos, sMaxFDPos);
#endif
FD_CLR(sCurrentFDPos, &sReturnedReadSet);
return constructeventreq(req, sCurrentFDPos, EV_RE);
}
else
{
#if EV_DEBUGGING
qtss_printf("waitevent: Stopping traverse of readset at %d\n", sCurrentFDPos);
#endif
sInReadSet = false;
sCurrentFDPos = 0;
}
}
if (!sInReadSet)
{
OSMutexLocker locker(&sMaxFDPosMutex);
#if EV_DEBUGGING
qtss_printf("waitevent: Looping through writeset starting at %d\n", sCurrentFDPos);
#endif
while((!(isSet = FD_ISSET(sCurrentFDPos, &sReturnedWriteSet))) && (sCurrentFDPos < sMaxFDPos))
sCurrentFDPos++;
if (isSet)
{
#if EV_DEBUGGING
qtss_printf("waitevent: Found an fd: %d in writeset\n", sCurrentFDPos);
#endif
FD_CLR(sCurrentFDPos, &sReturnedWriteSet);
return constructeventreq(req, sCurrentFDPos, EV_WR);
}
else
{
// This can happen if another thread calls select_removeevent at just the right
// time, setting sMaxFDPos lower than it was when select() was last called.
// Becase sMaxFDPos is used as the place to stop iterating over the read & write
// masks, setting it lower can cause file descriptors in the mask to get skipped.
// If they are skipped, that's ok, because those file descriptors were removed
// by select_removeevent anyway. We need to make sure to finish iterating over
// the masks and call select again, which is why we set sNumFDsProcessed
// artificially here.
sNumFDsProcessed = sNumFDsBackFromSelect;
Assert(sNumFDsBackFromSelect > 0);
}
}
}
if (sNumFDsProcessed > 0)
{
OSMutexLocker locker(&sMaxFDPosMutex);
#if DEBUG
//
// In a very bizarre circumstance (sMaxFDPos goes down & then back up again, these
// asserts could hit.
//
//for (int x = 0; x < sMaxFDPos; x++)
// Assert(!FD_ISSET(x, &sReturnedReadSet));
//for (int y = 0; y < sMaxFDPos; y++)
// Assert(!FD_ISSET(y, &sReturnedWriteSet));
#endif
#if EV_DEBUGGING
qtss_printf("waitevent: Finished with all fds in set. Stopped traverse of writeset at %d maxFD = %d\n", sCurrentFDPos,sMaxFDPos);
#endif
//We've just cycled through one select result. Re-init all the counting states
sNumFDsProcessed = 0;
sNumFDsBackFromSelect = 0;
sCurrentFDPos = 0;
sInReadSet = true;
}
while(!selecthasdata())
{
{
OSMutexLocker locker(&sMaxFDPosMutex);
//Prepare to call select. Preserve the read and write sets by copying their contents
//into the corresponding "returned" versions, and then pass those into select
::memcpy(&sReturnedReadSet, &sReadSet, sizeof(fd_set));
::memcpy(&sReturnedWriteSet, &sWriteSet, sizeof(fd_set));
}
SInt64 yieldDur = 0;
SInt64 yieldStart;
//Periodically time out the select call just in case we
//are deaf for some reason
// on platforw's where our threading is non-preemptive, just poll select
struct timeval tv;
tv.tv_usec = 0;
#if THREADING_IS_COOPERATIVE
tv.tv_sec = 0;
if ( yieldDur > 4 )
tv.tv_usec = 0;
else
tv.tv_usec = 5000;
#else
tv.tv_sec = 15;
#endif
#if EV_DEBUGGING
qtss_printf("waitevent: about to call select\n");
#endif
yieldStart = OS::Milliseconds();
OSThread::ThreadYield();
yieldDur = OS::Milliseconds() - yieldStart;
#if EV_DEBUGGING
static SInt64 numZeroYields;
if ( yieldDur > 1 )
{
qtss_printf( "select_waitevent time in OSThread::Yield() %i, numZeroYields %i\n", (SInt32)yieldDur, (SInt32)numZeroYields );
numZeroYields = 0;
}
else
numZeroYields++;
#endif
sNumFDsBackFromSelect = ::select(sMaxFDPos+1, &sReturnedReadSet, &sReturnedWriteSet, NULL, &tv);
#if EV_DEBUGGING
qtss_printf("waitevent: back from select. Result = %d\n", sNumFDsBackFromSelect);
#endif
}
if (sNumFDsBackFromSelect >= 0)
return EINTR; //either we've timed out or gotten some events. Either way, force caller
//to call waitevent again.
return sNumFDsBackFromSelect;
}
bool selecthasdata()
{
if (sNumFDsBackFromSelect < 0)
{
int err=OSThread::GetErrno();
#if EV_DEBUGGING
if (err == ENOENT)
{
qtss_printf("selectHasdata: found error ENOENT==2 \n");
}
#endif
if (
#if __solaris__
err == ENOENT || // this happens on Solaris when an HTTP fd is closed
#endif
err == EBADF || //this might happen if a fd is closed right before calling select
err == EINTR
) // this might happen if select gets interrupted
return false;
return true;//if there is an error from select, we want to make sure and return to the caller
}
if (sNumFDsBackFromSelect == 0)
return false;//if select returns 0, we've simply timed out, so recall select
if (FD_ISSET(sPipes[0], &sReturnedReadSet))
{
#if EV_DEBUGGING
qtss_printf("selecthasdata: Got some data on the pipe fd\n");
#endif
//we've gotten data on the pipe file descriptor. Clear the data.
// increasing the select buffer fixes a hanging problem when the Darwin server is under heavy load
// CISCO contribution
char theBuffer[4096];
(void)::read(sPipes[0], &theBuffer[0], 4096);
FD_CLR(sPipes[0], &sReturnedReadSet);
sNumFDsBackFromSelect--;
{
//Check the fds to close array, and if there are any in it, close those descriptors
OSMutexLocker locker(&sMaxFDPosMutex);
for (UInt32 theIndex = 0; ((sFDsToCloseArray[theIndex] != -1) && (theIndex < sizeof(fd_set) * 8)); theIndex++)
{
(void)::close(sFDsToCloseArray[theIndex]);
sFDsToCloseArray[theIndex] = -1;
}
}
}
Assert(!FD_ISSET(sPipes[0], &sReturnedWriteSet));
if (sNumFDsBackFromSelect == 0)
return false;//if the pipe file descriptor is the ONLY data we've gotten, recall select
else
return true;//we've gotten a real event, return that to the caller
}
#endif //!MACOSXEVENTQUEUE

93
CommonUtilitiesLib/ev.h Normal file
View file

@ -0,0 +1,93 @@
/*
*
* @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 _DSS_SYS_EV_H_
#define _DSS_SYS_EV_H_
#if !defined(__Win32__) && !defined(__solaris__) && !defined(__sgi__) && !defined(__osf__) && !defined(__hpux__)
#include <sys/queue.h>
#endif
#if MACOSXEVENTQUEUE
#include <sys/ev.h>
#else
struct eventreq {
int er_type;
#define EV_FD 1 // file descriptor
int er_handle;
void *er_data;
int er_rcnt;
int er_wcnt;
int er_ecnt;
int er_eventbits;
#define EV_RE 1
#define EV_WR 2
#define EV_EX 4
#define EV_RM 8
};
typedef struct eventreq *er_t;
#ifdef _KERNEL
#define EV_RBYTES 0x1
#define EV_WBYTES 0x2
#define EV_RWBYTES (EV_RBYTES|EV_WBYTES)
#define EV_RCLOSED 0x4
#define EV_RCONN 0x8
#define EV_ERRORS 0x10
#define EV_WCLOSED 0x20
#define EV_WCONN 0x40
#define EV_OOBD 0x80
#define EV_OOBM 0x100
struct eventqelt {
TAILQ_ENTRY(eventqelt) ee_slist;
TAILQ_ENTRY(eventqelt) ee_plist;
struct eventreq ee_req;
struct proc * ee_proc;
u_int ee_flags;
#define EV_QUEUED 1
u_int ee_eventmask;
struct socket *ee_sp;
};
#endif /* _KERNEL */
int select_watchevent(struct eventreq *req, int which);
int select_modwatch(struct eventreq *req, int which);
int select_waitevent(struct eventreq *req, void* onlyForMOSX);
void select_startevents();
int select_removeevent(int which);
#endif /* !MACOSXEVENTQUEUE */
#endif /* _DSS_SYS_EV_H_ */

255
CommonUtilitiesLib/getopt.c Normal file
View file

@ -0,0 +1,255 @@
/*
* 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@
*/
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#ifdef __Win32__
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#define OPTERRCOLON (1)
#define OPTERRNF (2)
#define OPTERRARG (3)
char *optarg;
int optreset = 0;
int optind = 1;
int opterr = 1;
int optopt;
static int
optiserr(int argc, char * const *argv, int oint, const char *optstr,
int optchr, int err)
{
if(opterr)
{
qtss_fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr+1);
switch(err)
{
case OPTERRCOLON:
qtss_fprintf(stderr, ": in flags\n");
break;
case OPTERRNF:
qtss_fprintf(stderr, "option not found %c\n", argv[oint][optchr]);
break;
case OPTERRARG:
qtss_fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]);
break;
default:
qtss_fprintf(stderr, "unknown\n");
break;
}
}
optopt = argv[oint][optchr];
return('?');
}
int
getopt(int argc, char* const *argv, const char *optstr)
{
static int optchr = 0;
static int dash = 0; /* have already seen the - */
char *cp;
if (optreset)
optreset = optchr = dash = 0;
if(optind >= argc)
return(EOF);
if(!dash && (argv[optind][0] != '-'))
return(EOF);
if(!dash && (argv[optind][0] == '-') && !argv[optind][1])
{
/*
* use to specify stdin. Need to let pgm process this and
* the following args
*/
return(EOF);
}
if((argv[optind][0] == '-') && (argv[optind][1] == '-'))
{
/* -- indicates end of args */
optind++;
return(EOF);
}
if(!dash)
{
assert((argv[optind][0] == '-') && argv[optind][1]);
dash = 1;
optchr = 1;
}
/* Check if the guy tries to do a -: kind of flag */
assert(dash);
if(argv[optind][optchr] == ':')
{
dash = 0;
optind++;
return(optiserr(argc, argv, optind-1, optstr, optchr, OPTERRCOLON));
}
if(!(cp = strchr(optstr, argv[optind][optchr])))
{
int errind = optind;
int errchr = optchr;
if(!argv[optind][optchr+1])
{
dash = 0;
optind++;
}
else
optchr++;
return(optiserr(argc, argv, errind, optstr, errchr, OPTERRNF));
}
if(cp[1] == ':')
{
dash = 0;
optind++;
if(optind == argc)
return(optiserr(argc, argv, optind-1, optstr, optchr, OPTERRARG));
optarg = argv[optind++];
return(*cp);
}
else
{
if(!argv[optind][optchr+1])
{
dash = 0;
optind++;
}
else
optchr++;
return(*cp);
}
assert(0);
return(0);
}
#ifdef TESTGETOPT
int
main (int argc, char **argv)
{
int c;
extern char *optarg;
extern int optind;
int aflg = 0;
int bflg = 0;
int errflg = 0;
char *ofile = NULL;
while ((c = getopt(argc, argv, "abo:")) != EOF)
switch (c) {
case 'a':
if (bflg)
errflg++;
else
aflg++;
break;
case 'b':
if (aflg)
errflg++;
else
bflg++;
break;
case 'o':
ofile = optarg;
(void)qtss_printf("ofile = %s\n", ofile);
break;
case '?':
errflg++;
}
if (errflg) {
(void)qtss_fprintf(stderr,
"usage: cmd [-a|-b] [-o <filename>] files...\n");
exit (2);
}
for ( ; optind < argc; optind++)
(void)qtss_printf("%s\n", argv[optind]);
return 0;
}
#endif /* TESTGETOPT */
#endif /* WIN32 */

105
CommonUtilitiesLib/getopt.h Normal file
View file

@ -0,0 +1,105 @@
/*
* 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@
*/
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#ifndef GETOPT_H
#define GETOPT_H
#ifdef __cplusplus
extern "C" {
#endif
//#ifdef __Win32__
extern char *optarg;
extern int optreset;
extern int optind;
extern int opterr;
extern int optopt;
int getopt(int argc, char* const *argv, const char *optstr);
//#endif /* WIN32 */
#ifdef __cplusplus
}
#endif
#endif /* GETOPT_H */

353
CommonUtilitiesLib/md5.c Normal file
View file

@ -0,0 +1,353 @@
/*
* 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@
*/
/* MD5.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/*
Note: Renamed the functions to avoid having same symbols in
the linked-in frameworks.
It is a hack to work around the problem.
*/
#include "md5.h"
#include <string.h>
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform (UInt32 state[4], unsigned char block[64]);
static void Encode (unsigned char *output, UInt32 *input, unsigned int len);
static void Decode (UInt32 *output, unsigned char *input, unsigned int len);
static void MD5_memcpy (UInt8 * output, UInt8 * input, size_t len);
static void MD5_memset (UInt8 * output, int value, size_t len);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UInt32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UInt32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UInt32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UInt32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
/* context */
void MD5_Init (MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
/* context input block length of input block*/
void MD5_Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UInt32)inputLen << 3))
< ((UInt32)inputLen << 3))
context->count[1]++;
context->count[1] += ((UInt32)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((UInt8 *)&context->buffer[index], (UInt8 *)input, (size_t) partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((UInt8 *)&context->buffer[index], (UInt8 *)&input[i],
(size_t) (inputLen-i) );
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
/* message digest context */
void MD5_Final (unsigned char digest[16], MD5_CTX *context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5_Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5_Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((UInt8 *)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (UInt32 state[4], unsigned char block[64])
{
UInt32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((UInt8 *)x, 0, sizeof (x));
}
/* Encodes input (UInt32) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (unsigned char *output, UInt32 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UInt32). Assumes len is
a multiple of 4.
*/
static void Decode (UInt32 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UInt32)input[j]) | (((UInt32)input[j+1]) << 8) |
(((UInt32)input[j+2]) << 16) | (((UInt32)input[j+3]) << 24);
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (UInt8 * output, UInt8 * input, size_t len)
{
/* unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
*/
memcpy(output, input, len);
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (UInt8 * output, int value, size_t len)
{
/* unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
*/
memset(output, value, len);
}

86
CommonUtilitiesLib/md5.h Normal file
View file

@ -0,0 +1,86 @@
/*
* 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@
*/
/* MD5.H - header file for MD5.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/*
Note: Renamed the functions to avoid having same symbols in
the linked-in frameworks.
It is a hack to work around the problem.
*/
#ifndef _MD5_H_
#define _MD5_H_
#include "OSHeaders.h"
#ifdef __cplusplus
extern "C" {
#endif
/* MD5 context. */
typedef struct {
UInt32 state[4]; /* state (ABCD) */
UInt32 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5_Init(MD5_CTX *context);
void MD5_Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen);
void MD5_Final(unsigned char digest[16], MD5_CTX *context);
#ifdef __cplusplus
}
#endif
#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: md5digest.cpp
Contains: Implements the function declared in md5digest.h
*/
#include "md5.h"
#include "md5digest.h"
#include "StrPtrLen.h"
#include <string.h>
#include "OSMemory.h"
static StrPtrLen sColon(":", 1);
static StrPtrLen sMD5Sess("md5-sess", 8);
static StrPtrLen sQopAuth("auth", 4);
static StrPtrLen sQopAuthInt("auth-int", 8);
// allocates memory for hashStr->Ptr
void HashToString(unsigned char aHash[kHashLen], StrPtrLen* hashStr){
UInt16 i;
UInt8 hexDigit;
// Allocating memory
char* str = NEW char[kHashHexLen+1];
str[kHashHexLen] = 0;
for(i = 0; i < kHashLen; i++) {
hexDigit = (aHash[i] >> 4) & 0xF;
str[i*2] = (hexDigit <= 9) ? (hexDigit + '0') : (hexDigit + 'a' - 10);
hexDigit = aHash[i] & 0xF;
str[i*2 + 1] = (hexDigit <= 9) ? (hexDigit + '0') : (hexDigit + 'a' - 10);
}
hashStr->Ptr = str;
hashStr->Len = kHashHexLen;
}
// allocates memory for hashA1Hex16Bit->Ptr
void CalcMD5HA1( StrPtrLen* userName,
StrPtrLen* realm,
StrPtrLen* userPassword,
StrPtrLen* hashA1Hex16Bit
)
{
// parameters must be valid pointers
// It is ok if parameter->Ptr is NULL as long as parameter->Len is 0
Assert(userName);
Assert(realm);
Assert(userPassword);
Assert(hashA1Hex16Bit);
Assert(hashA1Hex16Bit->Ptr == NULL); //This is the result. A Ptr here will be replaced. Value should be NULL.
MD5_CTX context;
unsigned char* aHash = NEW unsigned char[kHashLen];
// Calculate H(A1) for MD5
// where A1 for algorithm = "md5" or if nothing is specified is
// A1 = userName:realm:userPassword
MD5_Init(&context);
MD5_Update(&context, (unsigned char *)userName->Ptr, userName->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)realm->Ptr, realm->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)userPassword->Ptr, userPassword->Len);
MD5_Final(aHash, &context);
hashA1Hex16Bit->Ptr = (char *)aHash;
hashA1Hex16Bit->Len = kHashLen;
}
// allocates memory to hA1->Ptr
void CalcHA1( StrPtrLen* algorithm,
StrPtrLen* userName,
StrPtrLen* realm,
StrPtrLen* userPassword,
StrPtrLen* nonce,
StrPtrLen* cNonce,
StrPtrLen* hA1
)
{
// parameters must be valid pointers
// It is ok if parameter->Ptr is NULL as long as parameter->Len is 0
Assert(algorithm);
Assert(userName);
Assert(realm);
Assert(userPassword);
Assert(nonce);
Assert(cNonce);
Assert(hA1);
Assert(hA1->Ptr == NULL); //This is the result. A Ptr here will be replaced. Value should be NULL.
MD5_CTX context;
unsigned char aHash[kHashLen];
// Calculate H(A1)
// where A1 for algorithm = "md5" or if nothing is specified is
// A1 = userName:realm:userPassword
// and for algorithm = "md5-sess" is
// A1 = H(userName:realm:userPassword):nonce:cnonce
MD5_Init(&context);
MD5_Update(&context, (unsigned char *)userName->Ptr, userName->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)realm->Ptr, realm->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)userPassword->Ptr, userPassword->Len);
MD5_Final(aHash, &context);
if(algorithm->Equal(sMD5Sess)) {
MD5_Init(&context);
MD5_Update(&context, aHash, kHashLen);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)nonce->Ptr, nonce->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)cNonce->Ptr, cNonce->Len);
MD5_Final(aHash, &context);
}
HashToString(aHash, hA1);
}
// allocates memory to hA1->Ptr
void CalcHA1Md5Sess(StrPtrLen* hashA1Hex16Bit, StrPtrLen* nonce, StrPtrLen* cNonce, StrPtrLen* hA1)
{
// parameters must be valid pointers
// It is ok if parameter->Ptr is NULL as long as parameter->Len is 0
Assert(hashA1Hex16Bit);
Assert(hashA1Hex16Bit->Len == kHashLen);
Assert(nonce);
Assert(cNonce);
Assert(hA1);
Assert(hA1->Ptr == NULL); //This is the result. A Ptr here will be replaced. Value should be NULL.
MD5_CTX context;
unsigned char aHash[kHashLen];
MD5_Init(&context);
MD5_Update(&context, (unsigned char *)hashA1Hex16Bit->Ptr, kHashLen);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)nonce->Ptr, nonce->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)cNonce->Ptr, cNonce->Len);
MD5_Final(aHash, &context);
// allocates memory to hA1->Ptr
HashToString(aHash, hA1);
}
// allocates memory for requestDigest->Ptr
void CalcRequestDigest( StrPtrLen* hA1,
StrPtrLen* nonce,
StrPtrLen* nonceCount,
StrPtrLen* cNonce,
StrPtrLen* qop,
StrPtrLen* method,
StrPtrLen* digestUri,
StrPtrLen* hEntity,
StrPtrLen* requestDigest
)
{
// parameters must be valid pointers
// It is ok if parameter->Ptr is NULL as long as parameter->Len is 0
Assert(hA1);
Assert(nonce);
Assert(nonceCount);
Assert(cNonce);
Assert(qop);
Assert(method);
Assert(digestUri);
Assert(hEntity);
Assert(requestDigest);
Assert(requestDigest->Ptr == NULL); //This is the result. A Ptr here will be replaced. Value should be NULL.
unsigned char aHash[kHashLen], requestHash[kHashLen];
StrPtrLen hA2;
MD5_CTX context;
// H(data) = MD5(data)
// and KD(secret, data) = H(concat(secret, ":", data))
// Calculate H(A2)
// where A2 for qop="auth" or no qop is
// A2 = method:digestUri
// and for qop = "auth-int" is
// A2 = method:digestUri:H(entity-body)
MD5_Init(&context);
MD5_Update(&context, (unsigned char *)method->Ptr, method->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)digestUri->Ptr, digestUri->Len);
if(qop->Equal(sQopAuthInt)) {
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)hEntity->Ptr, hEntity->Len);
}
MD5_Final(aHash, &context);
// HashToString allocates memory for hA2...delete it after request-digest is created
HashToString(aHash, &hA2);
// Calculate request-digest
// where request-digest for qop="auth" or qop="auth-int" is
// request-digest = KD( H(A1), nonce:nonceCount:cNonce:qop:H(A2) )
// and if qop directive isn't present is
// request-digest = KD( H(A1), nonce:H(A2) )
MD5_Init(&context);
MD5_Update(&context, (unsigned char *)hA1->Ptr, hA1->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)nonce->Ptr, nonce->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
if(qop->Ptr != NULL) {
MD5_Update(&context, (unsigned char *)nonceCount->Ptr, nonceCount->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)cNonce->Ptr, cNonce->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
MD5_Update(&context, (unsigned char *)qop->Ptr, qop->Len);
MD5_Update(&context, (unsigned char *)sColon.Ptr, sColon.Len);
}
MD5_Update(&context, (unsigned char *)hA2.Ptr, hA2.Len);
MD5_Final(requestHash, &context);
HashToString(requestHash, requestDigest);
// Deleting memory allocated for hA2
delete [] hA2.Ptr;
}
/* From local_passwd.c (C) Regents of Univ. of California blah blah */
static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void to64(register char *s, register SInt32 v, register int n)
{
while (--n >= 0) {
*s++ = itoa64[v & 0x3f];
v >>= 6;
}
}
/*
* Define the Magic String prefix that identifies a password as being
* hashed using our algorithm.
*/
static char *dufr_id = "$dufr$";
// Doesn't allocate any memory. The size of the result buffer should be nbytes
void MD5Encode(char *pw, char *salt, char *result, int nbytes)
{
/*
* Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
* plus 4 for the '$' separators, plus the password hash itself.
* Let's leave a goodly amount of leeway.
*/
char passwd[120], *p;
char *sp, *ep;
unsigned char final[kHashLen];
int sl, pl, i;
MD5_CTX ctx, ctx1;
UInt32 l;
/*
* Refine the salt first. It's possible we were given an already-hashed
* string as the salt argument, so extract the actual salt value from it
* if so. Otherwise just use the string up to the first '$' as the salt.
*/
sp = salt;
//If it starts with the magic string, then skip that.
if (!strncmp(sp, dufr_id, strlen(dufr_id)))
{
sp += strlen(dufr_id);
}
//It stops at the first '$' or 8 chars, whichever comes first
for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++)
{
continue;
}
//Get the length of the true salt
sl = ep - sp;
//'Time to make the doughnuts..'
MD5_Init(&ctx);
//The password first, since that is what is most unknown
MD5_Update(&ctx, (unsigned char *)pw, strlen(pw));
//Then our magic string
MD5_Update(&ctx, (unsigned char *)dufr_id, strlen(dufr_id));
//Then the raw salt
MD5_Update(&ctx, (unsigned char *)sp, sl);
//Then just as many characters of the MD5(pw, salt, pw)
MD5_Init(&ctx1);
MD5_Update(&ctx1, (unsigned char *)pw, strlen(pw));
MD5_Update(&ctx1, (unsigned char *)sp, sl);
MD5_Update(&ctx1, (unsigned char *)pw, strlen(pw));
MD5_Final(final, &ctx1);
for (pl = strlen(pw); pl > 0; pl -= kHashLen)
{
MD5_Update(&ctx, (unsigned char *)final,(pl > kHashLen) ? kHashLen : pl);
}
//Don't leave anything around in vm they could use.
memset(final, 0, sizeof(final));
//Then something really weird...
for (i = strlen(pw); i != 0; i >>= 1)
{
if (i & 1) {
MD5_Update(&ctx, (unsigned char *)final, 1);
}
else {
MD5_Update(&ctx, (unsigned char *)pw, 1);
}
}
/*
* Now make the output string. We know our limitations, so we
* can use the string routines without bounds checking.
*/
strcpy(passwd, dufr_id);
strncat(passwd, sp, sl);
strcat(passwd, "$");
MD5_Final(final, &ctx);
/*
* And now, just to make sure things don't run too fast..
* On a 60 Mhz Pentium this takes 34 msec, so you would
* need 30 seconds to build a 1000 entry dictionary...
*/
for (i = 0; i < 1000; i++)
{
MD5_Init(&ctx1);
if (i & 1) {
MD5_Update(&ctx1, (unsigned char *)pw, strlen(pw));
}
else {
MD5_Update(&ctx1, final, kHashLen);
}
if (i % 3) {
MD5_Update(&ctx1, (unsigned char *)sp, sl);
}
if (i % 7) {
MD5_Update(&ctx1, (unsigned char *)pw, strlen(pw));
}
if (i & 1) {
MD5_Update(&ctx1, (unsigned char *)final, kHashLen);
}
else {
MD5_Update(&ctx1, (unsigned char *)pw, strlen(pw));
}
MD5_Final(final,&ctx1);
}
p = passwd + strlen(passwd);
l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
l = final[11] ; to64(p, l, 2); p += 2;
*p = '\0';
//Don't leave anything around in vm they could use.
memset(final, 0, sizeof(final));
strncpy(result, passwd, nbytes - 1);
}

View file

@ -0,0 +1,80 @@
/*
*
* @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: md5digest.h
Contains: Provides a function to calculate the md5 digest
given all the authentication parameters.
*/
#ifndef _MD5DIGEST_H_
#define _MD5DIGEST_H_
#include "StrPtrLen.h"
enum {
kHashHexLen = 32,
kHashLen = 16
};
// HashToString allocates memory for hashStr->Ptr
void HashToString(unsigned char aHash[kHashLen], StrPtrLen* hashStr);
// allocates memory for hashA1Hex16Bit->Ptr
void CalcMD5HA1(StrPtrLen* userName, StrPtrLen* realm, StrPtrLen* userPassword, StrPtrLen* hashA1Hex16Bit);
// allocates memory to hA1->Ptr
void CalcHA1( StrPtrLen* algorithm,
StrPtrLen* userName,
StrPtrLen* realm,
StrPtrLen* userPassword,
StrPtrLen* nonce,
StrPtrLen* cNonce,
StrPtrLen* hA1
);
// allocates memory to hA1->Ptr
void CalcHA1Md5Sess(StrPtrLen* hashA1Hex16Bit, StrPtrLen* nonce, StrPtrLen* cNonce, StrPtrLen* hA1);
// allocates memory for requestDigest->Ptr
void CalcRequestDigest( StrPtrLen* hA1,
StrPtrLen* nonce,
StrPtrLen* nonceCount,
StrPtrLen* cNonce,
StrPtrLen* qop,
StrPtrLen* method,
StrPtrLen* digestUri,
StrPtrLen* hEntity,
StrPtrLen* requestDigest
);
void to64(register char *s, register SInt32 v, register int n);
// Doesn't allocate any memory. The size of the result buffer should be nbytes
void MD5Encode( char *pw, char *salt, char *result, int nbytes);
#endif

View file

@ -0,0 +1,201 @@
/*
* 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@
*/
/*
File: mycondition.c
Contains: xxx put contents here xxx
Written by: Greg Vaughan
Writers:
(GV) Greg Vaughan
(CNR) Christopher Ryan
Change History (most recent first):
<5> 7/24/00 GV changed Carbon to CarbonCore for header include
<4> 1/6/00 GBV got rid of libatomic
<3> 12/8/99 CNR Use OSAssert.h
<2> 10/27/99 GBV update for beaker
To Do:
*/
#include "mycondition.h"
#include <stdlib.h>
#include "SafeStdLib.h"
#if __MacOSX__
#ifndef __CORESERVICES__
#include <CoreServices/CoreServices.h>
#endif
#endif
#include <mach/mach_error.h>
#include "MyAssert.h"
struct MyCondition
{
mach_port_t fWaitPort;
SInt32 fNumWaiting;
};
typedef struct MyCondition MyCondition;
MyCondition* MCAllocateCondition();
void MCDisposeCondition(MyCondition* theCondition);
void MCBroadcast(MyCondition* theCondition);
void MCSignal(MyCondition* theCondition);
void MCWait(MyCondition* theCondition, mymutex_t theMutex, int timeout);
void MCBlockThread(MyCondition* theCondition, int timeout);
void MCUnblockThread(MyCondition* theCondition);
mycondition_t mycondition_alloc()
{
return (mycondition_t)MCAllocateCondition();
}
void mycondition_free(mycondition_t theCondition_t)
{
MCDisposeCondition((MyCondition*)theCondition_t);
}
void mycondition_broadcast(mycondition_t theCondition_t)
{
MCBroadcast((MyCondition*)theCondition_t);
}
void mycondition_signal(mycondition_t theCondition_t)
{
MCSignal((MyCondition*)theCondition_t);
}
void mycondition_wait(mycondition_t theCondition_t, mymutex_t theMutex_t, int timeout)
{
MCWait((MyCondition*)theCondition_t, theMutex_t, timeout);
}
SInt32 sNumConds = 0;
MyCondition* MCAllocateCondition()
{
kern_return_t ret;
MyCondition* newCondition = (MyCondition*)malloc(sizeof(MyCondition));
if (newCondition == NULL)
{
Assert(newCondition != NULL);
return NULL;
}
newCondition->fNumWaiting = 0;
ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &newCondition->fWaitPort);
if (ret != KERN_SUCCESS)
{
Assert(0);
free(newCondition);
return NULL;
}
ret = mach_port_insert_right(mach_task_self(), newCondition->fWaitPort, newCondition->fWaitPort, MACH_MSG_TYPE_MAKE_SEND);
if (ret != KERN_SUCCESS)
{
Assert(0);
free(newCondition);
return NULL;
}
IncrementAtomic(&sNumConds);
return newCondition;
}
void MCDisposeCondition(MyCondition* theCondition)
{
kern_return_t ret = mach_port_destroy(mach_task_self(), theCondition->fWaitPort);
DecrementAtomic(&sNumConds);
Assert(ret == 0);
free(theCondition);
}
void MCBroadcast(MyCondition* theCondition)
{
int numToSignal = theCondition->fNumWaiting;
while (numToSignal > 0)
{
MCUnblockThread(theCondition);
numToSignal--;
}
}
void MCSignal(MyCondition* theCondition)
{
MCUnblockThread(theCondition);
}
void MCWait(MyCondition* theCondition, mymutex_t theMutex, int timeout)
{
mymutex_unlock(theMutex);
IncrementAtomic(&theCondition->fNumWaiting);
MCBlockThread(theCondition, timeout);
DecrementAtomic(&theCondition->fNumWaiting);
mymutex_lock(theMutex);
}
typedef struct {
mach_msg_header_t header;
mach_msg_trailer_t trailer;
} mHeader;
void MCBlockThread(MyCondition* theCondition, int timeout)
{
kern_return_t ret;
mHeader msg;
memset(&msg, 0, sizeof(msg));
if (timeout > 0)
ret = mach_msg(&msg.header,MACH_RCV_MSG | MACH_RCV_TIMEOUT,0, sizeof(msg),
theCondition->fWaitPort,timeout,MACH_PORT_NULL);
else
ret = mach_msg(&msg.header,MACH_RCV_MSG,0, sizeof(msg),
theCondition->fWaitPort,MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);
AssertV((ret < 1) || (ret > 2000), ret);
}
void MCUnblockThread(MyCondition* theCondition)
{
kern_return_t ret;
mHeader msg;
memset(&msg, 0, sizeof(msg));
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msg.header.msgh_size = sizeof msg - sizeof msg.trailer;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_remote_port = theCondition->fWaitPort;
msg.header.msgh_id = 0;
ret = mach_msg(&msg.header,MACH_SEND_MSG | MACH_SEND_TIMEOUT,msg.header.msgh_size,0,MACH_PORT_NULL,0,
MACH_PORT_NULL);
AssertV((ret < 1) || (ret > 2000), ret);
}

View file

@ -0,0 +1,64 @@
/*
* 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@
*/
/*
File: mycondition.h
Contains: xxx put contents here xxx
Written by: Greg Vaughan
Change History (most recent first):
<2> 10/27/99 GBV update for beaker
To Do:
*/
#ifndef _MYCONDITION_H_
#define _MYCONDITION_H_
#include <mach/mach.h>
#include <pthread.h>
#include "mymutex.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void* mycondition_t;
mycondition_t mycondition_alloc();
void mycondition_free(mycondition_t);
void mycondition_broadcast(mycondition_t);
void mycondition_signal(mycondition_t);
void mycondition_wait(mycondition_t, mymutex_t, int); //timeout as a msec offset from now (0 means no timeout)
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show more