#include "CMessaging.h"
#include "PrivateTypes.h"
#include "DSMutexSemaphore.h"
#include "DSTCPEndpoint.h"
#include "DirServicesTypes.h"
#include "DirServicesPriv.h"
#include "DirServicesConst.h"
#include "DirServicesUtils.h"
#include "DSUtils.h"
#ifdef SERVERINTERNAL
#include "DSCThread.h"
#include "CHandlers.h"
#include "CInternalDispatch.h"
#endif
#include <servers/bootstrap_defs.h> // for BOOTSTRAP_UNKNOWN_SERVICE
#include <mach/mach.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h> // for offsetof()
#include <unistd.h> // for sleep()
#include <syslog.h> // for syslog()
#include <ctype.h> // for isalpha()
extern pid_t gDaemonPID;
CMessaging::CMessaging ( CIPCVirtualClass *endPoint, int inTranslateMode ) : fLock("CMessaging::fLock")
{
fCommPort = endPoint;
fTranslateMode = inTranslateMode;
fMsgData = (sComData *)::calloc( 1, sizeof( sComData ) + kMaxFixedMsgData );
if ( fMsgData != nil )
{
fMsgData->fDataSize = kMaxFixedMsgData;
fMsgData->fDataLength = 0;
}
fServerVersion = 1; }
CMessaging::~CMessaging ( void )
{
DSFree(fMsgData);
}
SInt32 CMessaging::GetReplyMessage ( void )
{
#ifdef SERVERINTERNAL
return eDSNoErr; #else
return fCommPort->GetReplyMessage( &fMsgData );
#endif
}
SInt32 CMessaging::SendInlineMessage ( UInt32 inMsgType )
{
#ifdef SERVERINTERNAL
sComData *aMsgData = nil;
sComData *checkMsgData = nil;
CInternalDispatch *internalDispatch = CInternalDispatch::GetThreadInternalDispatch();
if ( internalDispatch != NULL )
{
aMsgData = internalDispatch->GetCurrentMessageBuffer();
}
else {
aMsgData = fMsgData;
}
if (aMsgData == nil) {
return(eDSInvalidContext);
}
checkMsgData = aMsgData;
CRequestHandler handler;
aMsgData->type.msgt_name = inMsgType;
aMsgData->type.msgt_translate = 0;
aMsgData->fPID = 0; aMsgData->fMachPort = 0;
handler.HandleRequest( &aMsgData );
if ( internalDispatch != NULL )
{
internalDispatch->SwapCurrentMessageBuffer( checkMsgData, aMsgData );
}
else {
fMsgData = aMsgData;
}
return eDSNoErr;
#else
fMsgData->type.msgt_name = inMsgType;
fMsgData->type.msgt_translate = fTranslateMode;
return fCommPort->SendMessage( fMsgData );
#endif
}
SInt32 CMessaging::Add_tDataBuff_ToMsg ( tDataBuffer *inBuff, eValueType inType )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
UInt32 offset = 0;
UInt32 length = 0;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetEmptyObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
pObj->type = inType; pObj->count = 1;
if ( inBuff != nil )
{
pObj->used = inBuff->fBufferLength;
pObj->length = inBuff->fBufferSize;
offset = pObj->offset;
length = pObj->length;
if (Grow( offset, length ))
{
aMsgData = GetMsgData();
}
::memcpy( (char *)aMsgData + offset, inBuff->fBufferData, inBuff->fBufferSize );
aMsgData->fDataLength += inBuff->fBufferSize;
}
else
{
pObj->length = 0;
}
}
return( result );
}
SInt32 CMessaging::Add_tDataList_ToMsg ( tDataList *inList, eValueType inType )
{
SInt32 result = eDSNoErr;
bool done = false;
UInt32 len = 0;
UInt32 offset = 0;
UInt32 length = 0;
tDataNodePtr pCurrNode = nil;
tDataBufferPriv *pPrivData = nil;
sObject *pObj = nil;
if ( inList != nil )
{
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetEmptyObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
pObj->type = inType; pObj->count = inList->fDataNodeCount;
pObj->length = ::dsGetDataLength( inList ) + (inList->fDataNodeCount * sizeof( UInt32 ));
offset = pObj->offset;
length = pObj->length;
if (Grow( offset, length ))
{
aMsgData = GetMsgData();
}
pCurrNode = inList->fDataListHead;
while ( !done )
{
pPrivData = (tDataBufferPriv *)pCurrNode;
len = pPrivData->fBufferLength; ::memcpy( (char *)aMsgData + offset, &len, 4 );
aMsgData->fDataLength += 4;
offset += 4;
::memcpy( (char *)aMsgData + offset, pPrivData->fBufferData, len );
aMsgData->fDataLength += len;
offset += len;
if ( pPrivData->fNextPtr == nil )
{
done = true;
}
else
{
pCurrNode = pPrivData->fNextPtr;
}
}
}
}
return( result );
}
SInt32 CMessaging::Add_Value_ToMsg ( UInt32 inValue, eValueType inType )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetEmptyObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
pObj->type = inType;
pObj->count = inValue;
pObj->length = 0;
}
return( result );
}
SInt32 CMessaging::Add_tAttrEntry_ToMsg ( tAttributeEntry *inData )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
UInt32 offset = 0;
UInt32 length = 0;
sComData *aMsgData= nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetEmptyObj( aMsgData, ktAttrValueEntry, &pObj );
if ( result == eDSNoErr )
{
pObj->type = ktAttrEntry;
pObj->count = 1;
if ( inData != nil )
{
pObj->length = sizeof( tAttributeEntry ) + inData->fAttributeSignature.fBufferSize;
offset = pObj->offset;
length = pObj->length;
if (Grow( offset, length ))
{
aMsgData = GetMsgData();
}
::memcpy( (char *)aMsgData + offset, inData, length );
aMsgData->fDataLength += length;
}
else
{
pObj->length = 0;
}
}
return( result );
}
SInt32 CMessaging::Add_tAttrValueEntry_ToMsg ( tAttributeValueEntry *inData )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
UInt32 offset = 0;
UInt32 length = 0;
sComData *aMsgData= nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetEmptyObj( aMsgData, ktAttrValueEntry, &pObj );
if ( result == eDSNoErr )
{
pObj->type = ktAttrValueEntry;
pObj->count = 1;
if ( inData != nil )
{
pObj->length = sizeof( tAttributeValueEntry ) + inData->fAttributeValueData.fBufferSize;
offset = pObj->offset;
length = pObj->length;
if (Grow( offset, length ))
{
aMsgData = GetMsgData();
}
::memcpy( (char *)aMsgData + offset, inData, length );
aMsgData->fDataLength += length;
}
else
{
pObj->count = 0;
pObj->length = 0;
}
}
return( result );
}
SInt32 CMessaging::Add_tRecordEntry_ToMsg ( tRecordEntry *inData )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
UInt32 offset = 0;
UInt32 length = 0;
sComData *aMsgData= nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetEmptyObj( aMsgData, ktRecordEntry, &pObj );
if ( result == eDSNoErr )
{
pObj->type = ktRecordEntry;
pObj->count = 1;
if ( inData != nil )
{
pObj->length = sizeof( tRecordEntry ) + inData->fRecordNameAndType.fBufferSize;
offset = pObj->offset;
length = pObj->length;
if (Grow( offset, length ))
{
aMsgData = GetMsgData();
}
::memcpy( (char *)aMsgData + offset, inData, length );
aMsgData->fDataLength += length;
}
else
{
pObj->length = 0;
}
}
return( result );
}
SInt32 CMessaging::Get_tDataBuff_FromMsg ( tDataBuffer **outBuff, eValueType inType )
{
SInt32 result = eDSNoErr;
UInt32 offset = 0;
UInt32 length = 0;
sObject *pObj = nil;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetThisObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
offset = pObj->offset;
length = pObj->length;
if ( length >= 0 )
{
if ( *outBuff == nil )
{
*outBuff = ::dsDataBufferAllocate( 0, length );
}
if ( *outBuff != nil )
{
::memset( (*outBuff)->fBufferData, 0, (*outBuff)->fBufferSize );
if ( (*outBuff)->fBufferSize >= pObj->length )
{
::memcpy( (*outBuff)->fBufferData, (char *)aMsgData + offset, length );
(*outBuff)->fBufferLength = pObj->used;
}
else
{ ::memcpy( (*outBuff)->fBufferData, (char *)aMsgData + offset, (*outBuff)->fBufferSize );
(*outBuff)->fBufferLength = pObj->used;
result = eDSBufferTooSmall;
}
}
else
{
result = eDSNullDataBuff;
}
}
}
return( result );
}
SInt32 CMessaging::Get_tDataList_FromMsg ( tDataList **outList, eValueType inType )
{
SInt32 siResult = eDSNoErr;
UInt32 offset = 0;
UInt32 length = 0;
UInt32 count = 0;
UInt32 cntr = 0;
sObject *pObj = nil;
tDataList *pOutList = nil;
char *tmpStr = nil;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
try
{
siResult = GetThisObj( aMsgData, inType, &pObj );
if ( siResult == eDSNoErr )
{
if ( outList != nil )
{
pOutList = ::dsDataListAllocate( 0 );
if ( pOutList != nil )
{
offset = pObj->offset;
count = pObj->count;
while ( cntr < count )
{
::memcpy( &length, (char *)aMsgData + offset, 4 );
offset += 4;
tmpStr = (char *) malloc( length + 1 );
if (tmpStr == nil) throw((SInt32)eMemoryAllocError);
memcpy( tmpStr, aMsgData + offset, length );
tmpStr[length] = '\0';
::dsAppendStringToListAlloc( 0, pOutList, tmpStr );
free(tmpStr);
offset += length;
cntr++;
}
*outList = pOutList;
}
else
{
siResult = eMemoryError;
}
}
else
{
siResult = eDSNullDataList;
}
}
}
catch( SInt32 err )
{
if ( pOutList != nil )
{
::dsDataListDeallocate( 0, pOutList );
free(pOutList);
*outList = nil;
}
siResult = err;
}
return( siResult );
}
SInt32 CMessaging::Get_Value_FromMsg ( UInt32 *outValue, eValueType inType )
{
UInt32 result = eDSNoErr;
sObject *pObj = nil;
sComData *aMsgData= nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetThisObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
*outValue = pObj->count;
}
return( result );
}
SInt32 CMessaging::Get_tAttrEntry_FromMsg ( tAttributeEntry **outAttrEntry, eValueType inType )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
tAttributeEntry *pAttrEntry = nil;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetThisObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
pAttrEntry = (tAttributeEntry *)::calloc( 1, pObj->length );
if ( pAttrEntry != nil )
{
::memcpy( pAttrEntry, (char *)aMsgData + pObj->offset, pObj->length );
*outAttrEntry = pAttrEntry;
}
else
{
result = eDSNullAttribute;
}
}
return( result );
}
SInt32 CMessaging::Get_tAttrValueEntry_FromMsg ( tAttributeValueEntry **outAttrValue,
eValueType inType )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
tAttributeValueEntry *pAttrValueEntry = nil;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetThisObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
pAttrValueEntry = (tAttributeValueEntry *)::calloc( 1, pObj->length );
if ( pAttrValueEntry != nil )
{
::memcpy( pAttrValueEntry, (char *)aMsgData + pObj->offset, pObj->length );
*outAttrValue = pAttrValueEntry;
}
else
{
result = eDSNullAttributeValue;
}
}
return( result );
}
SInt32 CMessaging::Get_tRecordEntry_FromMsg ( tRecordEntry **outRecEntry, eValueType inType )
{
SInt32 result = eDSNoErr;
sObject *pObj = nil;
tRecordEntry *pRecordEntry = nil;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if (aMsgData == nil) {
return(eDSInvalidContext);
}
result = GetThisObj( aMsgData, inType, &pObj );
if ( result == eDSNoErr )
{
pRecordEntry = (tRecordEntry *)::calloc( 1, pObj->length );
if ( pRecordEntry != nil )
{
::memcpy( pRecordEntry, (char *)aMsgData + pObj->offset, pObj->length );
*outRecEntry = pRecordEntry;
}
else
{
result = eDSNullRecEntryPtr;
}
}
return( result );
}
SInt32 CMessaging::GetEmptyObj ( sComData *inMsg, eValueType inType, sObject **outObj )
{
SInt32 siResult = eDSIndexNotFound;
UInt32 i;
for ( i = 0; i < 10; i++ )
{
if ( inMsg->obj[ i ].type == 0 )
{
*outObj = &inMsg->obj[ i ];
if ( i == 0 )
{
(*outObj)->offset = offsetof(struct sComData, data);
}
else
{
(*outObj)->offset = inMsg->obj[ i - 1 ].offset + inMsg->obj[ i - 1 ].length;
}
siResult = eDSNoErr;
break;
}
else if ( inMsg->obj[ i ].type == (UInt32)inType )
{
break;
}
}
return( siResult );
}
SInt32 CMessaging::GetThisObj ( sComData *inMsg, eValueType inType, sObject **outObj )
{
SInt32 siResult = eDSIndexNotFound;
UInt32 i;
for ( i = 0; i < 10; i++ )
{
if ( inMsg->obj[ i ].type == (UInt32)inType )
{
*outObj = &inMsg->obj[ i ];
siResult = eDSNoErr;
break;
}
}
return( siResult );
}
bool CMessaging::Grow ( UInt32 inOffset, UInt32 inSize )
{
UInt32 newSize = 0;
char *pNewPtr = nil;
UInt32 length = 0;
sComData *aMsgData = nil;
bool bGrown = false;
if ( inSize == 0 )
{
return(bGrown);
}
aMsgData = GetMsgData();
if (aMsgData != nil)
{
if ( (aMsgData->fDataLength + inSize) > aMsgData->fDataSize )
{
newSize = aMsgData->fDataSize;
while( newSize < (aMsgData->fDataLength + inSize) )
{
newSize += kMsgBlockSize;
}
length = aMsgData->fDataLength;
pNewPtr = (char *)::calloc( 1, sizeof( sComData ) + newSize );
if ( pNewPtr == nil )
{
throw( (SInt32)eMemoryAllocError );
}
::memcpy( pNewPtr, aMsgData, sizeof(sComData) + aMsgData->fDataLength );
#ifdef SERVERINTERNAL
CInternalDispatch *internalDispatch = CInternalDispatch::GetThreadInternalDispatch();
if ( internalDispatch != NULL )
{
internalDispatch->SwapCurrentMessageBuffer(aMsgData, (sComData *)pNewPtr);
}
else {
fMsgData = (sComData *)pNewPtr;
}
#else
fMsgData = (sComData *)pNewPtr;
#endif
::free( aMsgData );
aMsgData = nil;
aMsgData = (sComData *)pNewPtr;
pNewPtr = nil;
aMsgData->fDataSize = newSize;
aMsgData->fDataLength = length;
bGrown = true;
}
}
return(bGrown);
}
void CMessaging::Lock ( void )
{
#ifdef SERVERINTERNAL
CInternalDispatch *internalDispatch = CInternalDispatch::GetThreadInternalDispatch();
if ( internalDispatch != NULL )
{
internalDispatch->PushCurrentMessageBuffer();
}
else {
fLock.WaitLock();
}
#else
fLock.WaitLock();
#endif
}
void CMessaging::ResetMessageBlock( void )
{
if( fMsgData == NULL || kMaxFixedMsgData != fMsgData->fDataSize )
{
if ( fMsgData != NULL ) free( fMsgData );
fMsgData = (sComData *)::calloc( 1, sizeof( sComData ) + kMaxFixedMsgData );
if ( fMsgData != nil )
{
fMsgData->fDataSize = kMaxFixedMsgData;
fMsgData->fDataLength = 0;
}
}
}
void CMessaging::Unlock ( void )
{
#ifdef SERVERINTERNAL
CInternalDispatch *internalDispatch = CInternalDispatch::GetThreadInternalDispatch();
if (internalDispatch != NULL)
{
internalDispatch->PopCurrentMessageBuffer();
}
else {
ResetMessageBlock();
fLock.SignalLock();
}
#else
ResetMessageBlock();
fLock.SignalLock();
#endif
}
void CMessaging::ClearMessageBlock ( void )
{
UInt32 size = 0;
sComData *aMsgData = nil;
aMsgData = GetMsgData();
if ( aMsgData != nil )
{
size = aMsgData->fDataSize;
::memset( aMsgData, 0, sizeof( sComData ) );
aMsgData->fDataSize = size;
aMsgData->fDataLength = 0;
}
}
UInt32 CMessaging::GetServerVersion ( void )
{
return( fServerVersion );
}
void CMessaging::SetServerVersion ( UInt32 inServerVersion )
{
fServerVersion = inServerVersion;
}
sComData* CMessaging::GetMsgData ( void )
{
sComData *aMsgData = nil;
#ifdef SERVERINTERNAL
CInternalDispatch *internalDispatch = CInternalDispatch::GetThreadInternalDispatch();
if (internalDispatch != NULL)
{
aMsgData = internalDispatch->GetCurrentMessageBuffer();
}
else {
aMsgData = fMsgData;
}
#else
aMsgData = fMsgData;
#endif
return(aMsgData);
}
#ifdef SERVERINTERNAL
bool CMessaging::IsThreadUsingInternalDispatchBuffering( UInt32 inThreadSig )
{
bool isInternalDispatchThread = false;
switch( inThreadSig )
{
case DSCThread::kTSMigHandlerThread:
case DSCThread::kTSSearchPlugInHndlrThread:
case DSCThread::kTSTCPConnectionThread:
case DSCThread::kTSLauncherThread:
case DSCThread::kTSPlugInHndlrThread:
case DSCThread::kTSLibinfoQueueThread:
case DSCThread::kTSMemberdKernelHndlrThread:
case DSCThread::kTSPluginRunloopThread:
isInternalDispatchThread = true;
break;
default:
isInternalDispatchThread = false;
break;
}
return(isInternalDispatchThread);
} #endif