#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mslp_sd.h"
#include "slp.h"
#include "mslp.h"
#include "mslpd_store.h"
#include "mslp_dat.h"
#include "mslpd.h"
#include "ServiceInfo.h"
#include "SLPDefines.h"
#include "SLPComm.h"
#pragma mark -
#pragma mark - ServiceInfo
#pragma mark -
unsigned long ServiceInfo::mLatestAssignedSIRefNum = 0L;
ServiceInfo::ServiceInfo()
{
mSIRefNum = ++mLatestAssignedSIRefNum;
mNumInterestedParties = 1; mScope = NULL;
mAttributeList = NULL;
mURL = NULL;
mURLRef = NULL;
mServiceType = NULL;
mTimeOfFirstRegistration = 1;
mTimeOfLastRegistrationUpdate = 1;
mTimeOfExpiration = 1; mTimeToRegister = (UInt32)-1;
mIPRegisteredFrom = 0;
mSelfPtr = this;
}
ServiceInfo::~ServiceInfo()
{
if ( mAttributeList != NULL )
{
free( mAttributeList );
mAttributeList = NULL;
}
if ( mScope )
{
free( mScope );
mScope = NULL;
}
if ( mURL != NULL )
{
free( mURL );
mURL = NULL;
}
if ( mURLRef )
{
::CFRelease( mURLRef );
mURLRef = NULL;
}
if ( mServiceType )
{
free( mServiceType );
mServiceType = NULL;
}
}
#pragma mark -
#pragma mark public:
Boolean ServiceInfo::operator==( ServiceInfo& infoToCompare )
{
Boolean urlsAreEqual = false;
Boolean scopesAreEqual = false;
if ( mURL && infoToCompare.mURL )
urlsAreEqual = ( ::strcmp( mURL, infoToCompare.mURL ) == 0 );
if ( urlsAreEqual )
if ( mScope && infoToCompare.mScope )
scopesAreEqual = ( ::strcmp( mScope, infoToCompare.mScope ) == 0 );
return scopesAreEqual;
}
Boolean ServiceInfo::operator>( ServiceInfo& infoToCompare )
{
Boolean urlIsGreater = false;
int compareValue = 0;
if ( mURL && infoToCompare.mURL )
compareValue = ( ::strcmp( mURL, infoToCompare.mURL ) > 0 );
if ( compareValue == 0 && mScope && infoToCompare.mScope )
urlIsGreater = ( ::strcmp( mScope, infoToCompare.mScope ) > 0 );
else
urlIsGreater = compareValue > 0;
return urlIsGreater;
}
void ServiceInfo::AddInterest( void )
{
mNumInterestedParties++;
}
void ServiceInfo::RemoveInterest( void )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( mNumInterestedParties );
#endif
if ( !mNumInterestedParties )
return;
mNumInterestedParties--;
if ( mNumInterestedParties == 0 )
{
delete this;
}
}
#pragma mark -
Boolean ServiceInfo::IsTimeToReRegister( void )
{
Boolean itsTime = false;
UInt32 curTime = 0;
curTime = GetCurrentTime();
if ( curTime > mTimeToRegister )
itsTime = true;
return itsTime;
}
Boolean ServiceInfo::IsTimeToExpire( void )
{
Boolean itsTime = false;
UInt32 curTime = 0;
curTime = GetCurrentTime();
if ( curTime > mTimeOfExpiration )
itsTime = true;
return itsTime;
}
void ServiceInfo::UpdateLastRegistrationTimeStamp( void )
{
UInt32 curTime;
curTime = GetCurrentTime();
SetTimeOfLastRegistrationUpdate( curTime );
mTimeOfExpiration = curTime + mLifeTime;
mTimeToRegister = curTime + ((mLifeTime*80)/100); }
#pragma mark -
void ServiceInfo::SetURL( const char* url, UInt16 urlLen )
{
if ( mURL != NULL )
free( mURL );
if ( url )
{
mURL = (char*)malloc( urlLen + 1 );
::memcpy( mURL, url, urlLen );
mURL[urlLen] = '\0';
if ( mURLRef )
::CFRelease( mURLRef );
mURLRef = ::CFStringCreateWithCString( NULL, mURL, kCFStringEncodingUTF8 );
}
else
mURL = NULL;
}
void ServiceInfo::SetServiceType( const char* serviceType, UInt16 serviceTypeLen )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( serviceType );
#endif
if ( !serviceType )
return;
if ( mServiceType )
free( mServiceType );
mServiceType = (char*)malloc( serviceTypeLen + 1 );
::memcpy( mServiceType, serviceType, serviceTypeLen );
mServiceType[serviceTypeLen] = '\0';
}
char* ServiceInfo::PtrToServiceType( UInt16* serviceTypeLen )
{
if ( mServiceType == NULL )
*serviceTypeLen = 0;
else
*serviceTypeLen = ::strlen( mServiceType );
return mServiceType;
}
void ServiceInfo::SetScope( const char* scope, UInt16 scopeLen )
{
if ( mScope )
free( mScope );
mScope = (char*)malloc( scopeLen + 1 );
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( mScope );
#endif
if ( !mScope )
return;
::memcpy( mScope, scope, scopeLen );
mScope[scopeLen] = '\0';
}
void ServiceInfo::AddAttribute( const char* attribute, UInt16 attributeLen )
{
if ( attribute != NULL && *attribute != '\0' && attributeLen > 0 )
{
size_t newLength = attributeLen;
if ( mAttributeList )
newLength += ::strlen( mAttributeList );
if ( mAttributeList != NULL )
newLength += 1;
char* newList = (char*)malloc( newLength +1 );
if ( mAttributeList != NULL )
{
::strcpy( newList, mAttributeList );
::strcat( newList, "," );
free( mAttributeList );
}
else
newList[0] = '\0';
::strncat( newList, attribute, attributeLen );
mAttributeList = newList;
}
}
void ServiceInfo::RemoveAllAttributes( void )
{
if ( mAttributeList != NULL )
{
free( mAttributeList );
mAttributeList = NULL;
}
}
Boolean ServiceInfo::URLMatches( char* url, UInt16 urlLen )
{
Boolean match = false;
if ( urlLen > 0 && mURL )
match = ( ::memcmp( url, mURL, (urlLen > strlen(mURL))?urlLen:strlen(mURL) ) == 0 );
return match;
}
Boolean ServiceInfo::ServiceTypeMatches( char* serviceType, UInt16 serviceTypeLen )
{
Boolean match = false;
if ( serviceTypeLen > 0 && mURL )
match = ( ::memcmp( serviceType, mURL, serviceTypeLen ) == 0 && mURL[serviceTypeLen] == ':' );
return match;
}
Boolean ServiceInfo::ScopeMatches( char* scope )
{
Boolean match = false;
if ( scope )
match = ScopeMatches( scope, ::strlen( scope ) );
return match;
}
Boolean ServiceInfo::ScopeMatches( char* scope, UInt16 scopeLen )
{
Boolean scopeMatch = false;
if ( mScope && scope )
{
if ( ::memcmp( scope, mScope, (scopeLen>::strlen(mScope))?scopeLen:strlen(mScope) ) == 0 )
scopeMatch = true;
}
return scopeMatch;
}
#pragma mark -
#pragma mark еее ServiceInfoComparator еее
#pragma mark -
#ifdef USE_SERVICE_INFO_COMPARATOR
ServiceInfoComparator::ServiceInfoComparator()
{
}
ServiceInfoComparator::~ServiceInfoComparator()
{
}
SInt32 ServiceInfoComparator::Compare(
const void* inItemOne,
const void* inItemTwo,
UInt32 inSizeOne,
UInt32 inSizeTwo) const
{
SInt32 compareValue;
ServiceInfo* itemOne = (*(ServiceInfo**)inItemOne);
ServiceInfo* itemTwo = (*(ServiceInfo**)inItemTwo);
UInt16 itemOneServiceTypeLen, itemTwoServiceTypeLen;
Boolean compareFinished = false;
compareValue = ::memcmp( itemOne->PtrToServiceType( &itemOneServiceTypeLen ), itemTwo->PtrToServiceType( &itemTwoServiceTypeLen ), max(itemOneServiceTypeLen,itemTwoServiceTypeLen) );
if ( compareValue == 0 )
{
compareValue = ::strcmp( itemOne->GetURLPtr(), itemTwo->GetURLPtr() );
}
return compareValue;
}
Boolean ServiceInfoComparator::IsEqualTo(
const void* inItemOne,
const void* inItemTwo,
UInt32 inSizeOne,
UInt32 inSizeTwo) const
{
return (Compare(inItemOne, inItemTwo, inSizeOne, inSizeTwo) == 0);
}
#endif // #ifdef USE_SERVICE_INFO_COMPARATOR
#pragma mark -
#pragma mark some helper functions
OSStatus MakeSLPServiceInfoNotificationBuffer( SLPdMessageType messageType, ServiceInfo* service, UInt32* dataBufferLen, char** dataBuffer );
OSStatus MakeSLPServiceInfoAddedNotificationBuffer( ServiceInfo* service, UInt32* dataBufferLen, char** dataBuffer )
{
return MakeSLPServiceInfoNotificationBuffer( kSLPRegisterURL, service, dataBufferLen, dataBuffer );
}
OSStatus MakeSLPServiceInfoRemovedNotificationBuffer( ServiceInfo* service, UInt32* dataBufferLen, char** dataBuffer )
{
return MakeSLPServiceInfoNotificationBuffer( kSLPDeregisterURL, service, dataBufferLen, dataBuffer );
}
OSStatus MakeSLPServiceInfoNotificationBuffer( SLPdMessageType messageType, ServiceInfo* service, UInt32* dataBufferLen, char** dataBuffer )
{
char* curPtr = NULL;
char* url = service->GetURLPtr();
char* serviceType = NULL;
char* scope = service->GetScope();
char* attribute = service->GetAttributeList();
UInt32 urlLen = 0;
UInt32 serviceTypeLen = 0;
UInt32 scopeLen = 0;
UInt32 attributeLen = 0;
LifeTime lifeTime = service->GetLifeTime();
UInt32 timeOfFirstRegistration = service->GetTimeOfFirstRegistration();
UInt32 timeOfExpiration = service->GetTimeOfExpiration();
UInt32 timeOfLastRegistration = service->GetTimeOfLastRegistrationUpdate();
UInt32 ipAddressRegisteredFrom = service->GetIPAddressRegisteredFrom();
OSStatus status = noErr;
if ( !url || !scope )
status = -1;
if ( !status )
{
urlLen = strlen(url);
serviceType = service->PtrToServiceType(&(UInt16)serviceTypeLen);
if ( serviceType )
serviceTypeLen = strlen( serviceType );
scopeLen = strlen(scope);
attributeLen = service->GetAttributeListLen();
*dataBufferLen = sizeof(SLPdMessageHeader)
+ sizeof(LifeTime) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + urlLen + sizeof(UInt32) + serviceTypeLen + sizeof(UInt32) + scopeLen + sizeof(UInt32) + attributeLen + sizeof(UInt32);
(*dataBuffer) = (char*)::malloc( *dataBufferLen );
}
if ( dataBuffer )
{
SLPdMessageHeader* header = (SLPdMessageHeader*)(*dataBuffer);
header->messageType = messageType;
header->messageLength = *dataBufferLen;
header->messageStatus = 0;
curPtr = (char*)header + sizeof(SLPdMessageHeader);
::memcpy( curPtr, &lifeTime, sizeof(LifeTime) );
curPtr += sizeof(LifeTime);
::memcpy( curPtr, &timeOfFirstRegistration, sizeof(UInt32) );
curPtr += sizeof(UInt32);
::memcpy( curPtr, &timeOfExpiration, sizeof(UInt32) );
curPtr += sizeof(UInt32);
::memcpy( curPtr, &ipAddressRegisteredFrom, sizeof(UInt32) );
curPtr += sizeof(UInt32);
::memcpy( curPtr, &urlLen, sizeof(UInt32) );
curPtr += sizeof(UInt32);
::memcpy( curPtr, url, urlLen );
curPtr += urlLen;
::memcpy( curPtr, &serviceTypeLen, sizeof(UInt32) );
curPtr += sizeof(UInt32);
::memcpy( curPtr, serviceType, serviceTypeLen );
curPtr += serviceTypeLen;
::memcpy( curPtr, &scopeLen, sizeof(UInt32) );
curPtr += sizeof(UInt32);
::memcpy( curPtr, scope, scopeLen );
curPtr += scopeLen;
::memcpy( curPtr, &attributeLen, sizeof(UInt32) );
curPtr += sizeof(UInt32);
if ( attribute )
{
::memcpy( curPtr, attribute, attributeLen );
curPtr += attributeLen;
}
::memcpy( curPtr, &timeOfLastRegistration, sizeof(UInt32) );
}
else
{
*dataBuffer = NULL;
*dataBufferLen = 0;
}
return status;
}
const UInt32 kMinServiceInfoDataBufferSize = sizeof(SLPdMessageHeader)
+ sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32);
OSStatus MakeServiceInfoFromNotificationBuffer( char* dataBuffer, UInt32 dataBufferLen, ServiceInfo** newServiceInfo )
{
OSStatus status = noErr;
if ( dataBuffer && dataBufferLen > kMinServiceInfoDataBufferSize )
{
char* curPtr;
UInt32 curDataLen;
ServiceInfo* newSI = new ServiceInfo();
curPtr = dataBuffer + sizeof(SLPdMessageHeader);
newSI->SetLifeTime( *((LifeTime*)curPtr) );
curPtr += sizeof(LifeTime);
newSI->SetTimeOfFirstRegistration( *((UInt32*)curPtr) );
curPtr += sizeof(UInt32);
newSI->SetTimeOfExpiration( *((UInt32*)curPtr) );
curPtr += sizeof(UInt32);
newSI->SetIPAddressRegisteredFrom( *((UInt32*)curPtr) );
curPtr += sizeof(UInt32);
curDataLen = *((UInt32*)curPtr);
curPtr += sizeof(UInt32);
newSI->SetURL( curPtr, curDataLen );
curPtr += curDataLen;
curDataLen = *((UInt32*)curPtr);
curPtr += sizeof(UInt32);
newSI->SetServiceType( curPtr, curDataLen );
curPtr += curDataLen;
curDataLen = *((UInt32*)curPtr);
curPtr += sizeof(UInt32);
newSI->SetScope( curPtr, curDataLen );
curPtr += curDataLen;
curDataLen = *((UInt32*)curPtr);
curPtr += sizeof(UInt32);
newSI->AddAttribute( curPtr, curDataLen );
if ( dataBufferLen > (curPtr - dataBuffer) + curDataLen ) {
curPtr += curDataLen;
newSI->SetTimeOfLastRegistrationUpdate( *((UInt32*)curPtr) );
}
*newServiceInfo = newSI;
}
else
status = -1;
return status;
}
void CopyXIDFromRequestToCachedReply( ServiceLocationHeader* serviceReply, ServiceLocationHeader* originialRequest )
{
*((UInt16*)&(serviceReply->byte11)) = *((UInt16*)&(originialRequest->byte11)); }
SLPReturnError CreateNewServiceInfo( unsigned short lifeTime,
const char* serviceURL,
UInt16 serviceURLLen,
const char* serviceType,
UInt16 serviceTypeLen,
const char* scope,
UInt16 scopeLen,
const char* attributes,
UInt16 attributesLen,
long ipRegisteredFrom,
ServiceInfo** newServiceInfo )
{
SLPReturnError error = NO_ERROR;
*newServiceInfo = new ServiceInfo();
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( *newServiceInfo );
#endif
if ( !*newServiceInfo )
return INTERNAL_ERROR;
(*newServiceInfo)->SetLifeTime( lifeTime );
(*newServiceInfo)->SetURL( serviceURL, serviceURLLen );
(*newServiceInfo)->SetServiceType( serviceType, serviceTypeLen );
(*newServiceInfo)->SetScope( scope, scopeLen );
(*newServiceInfo)->AddAttribute( attributes, attributesLen );
(*newServiceInfo)->SetIPAddressRegisteredFrom( ipRegisteredFrom );
(*newServiceInfo)->SetTimeOfFirstRegistration( GetCurrentTime() );
(*newServiceInfo)->UpdateLastRegistrationTimeStamp();
return error;
}
SLPReturnError ParseOutServiceRequest( const char* buffer,
UInt16 length,
const char** serviceTypePtr,
UInt16* serviceTypeLen,
const char** scopeListPtr,
UInt16* scopeListLen,
const char** predicateListPtr,
UInt16* predicateListLen )
{
const char* curPtr = buffer + GETHEADERLEN( buffer ); UInt16 prListLen, slpSPILen;
SLPReturnError error = NO_ERROR;
prListLen = *((UInt16*)curPtr);
curPtr += prListLen + sizeof( prListLen );
*serviceTypeLen = *((UInt16*)curPtr);
curPtr += sizeof( *serviceTypeLen );
*serviceTypePtr = curPtr;
curPtr += *serviceTypeLen;
*scopeListLen = *((UInt16*)curPtr);
curPtr += sizeof( *scopeListLen );
*scopeListPtr = curPtr;
curPtr += *scopeListLen;
*predicateListLen = *((UInt16*)curPtr);
curPtr += sizeof( *predicateListLen );
*predicateListPtr = curPtr;
curPtr += *predicateListLen;
slpSPILen = *((UInt16*)curPtr);
curPtr += sizeof( slpSPILen );
curPtr += slpSPILen;
if ( curPtr > buffer+length )
error = PARSE_ERROR;
return error;
}
Boolean TestForRegStylePacket( const char* buffer )
{
Boolean isRegStylePacket = false;
if ( GETFUN( buffer ) == SRVREG )
isRegStylePacket = true;
else if ( *(buffer + GETHEADERLEN( buffer )) == '\0' && *((short*)(buffer + GETHEADERLEN( buffer ) + 1)) == 10800 )
isRegStylePacket = true;
return isRegStylePacket;
}
SLPReturnError ParseOutRegDereg( const char* buffer,
UInt16 length,
UInt16* lifeTime,
const char** serviceURL,
UInt16* serviceURLLen,
const char** serviceTypePtr,
UInt16* serviceTypeLen,
const char** scopeListPtr,
UInt16* scopeListLen,
const char** attributesPtr,
UInt16* attributesLen )
{
SLPReturnError error = PARSE_ERROR;
Boolean isRegStylePacket = TestForRegStylePacket( buffer );
if ( buffer && ( GETFUN( buffer ) == SRVREG || isRegStylePacket ) )
{
const char* curPtr = buffer + GETHEADERLEN( buffer ); const char* eofRegPtr = NULL;
UInt16 messageLength = GETLEN( buffer );
UInt16 slpSPILen, authBlockLen;
UInt16 i;
UInt8 numAuths;
if ( isRegStylePacket && GETFUN( buffer ) != SRVREG )
SLP_LOG( SLP_LOG_DEBUG, "Converting a deregistration packet from a Mac OS 9.1 -> 10.1 machine" );
if ( messageLength > length )
{
SLP_LOG( SLP_LOG_ERR, "ParseOutRegDereg (SRVREG), message's length (%ld) says its longer than the message (%ld) itself!", messageLength, length );
return PARSE_ERROR;
}
else if ( messageLength != length )
{
SLP_LOG( SLP_LOG_ERR, "ParseOutRegDereg (SRVREG), message's length (%ld) says its different than the message (%ld) itself!", messageLength, length );
return PARSE_ERROR;
}
error = NO_ERROR;
eofRegPtr = buffer + messageLength;
curPtr++;
*lifeTime = *((UInt16*)curPtr);
curPtr += 2;
*serviceURLLen = *((UInt16*)curPtr);
curPtr += 2;
*serviceURL = curPtr;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR;
if ( error == NO_ERROR )
{
curPtr += *serviceURLLen;
numAuths = *curPtr;
curPtr++;
for ( i=0; i<numAuths; i++ )
{
slpSPILen = *((UInt16*)curPtr);
curPtr++;
curPtr += 2; authBlockLen = *((UInt16*)curPtr);
curPtr += authBlockLen;
curPtr -= 2; }
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
if ( error == NO_ERROR )
{
*serviceTypeLen = *((UInt16*)curPtr);
curPtr += 2;
*serviceTypePtr = curPtr;
curPtr += *serviceTypeLen;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
if ( error == NO_ERROR )
{
*scopeListLen = *((UInt16*)curPtr);
curPtr += 2;
*scopeListPtr = curPtr;
curPtr += *scopeListLen;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
if ( error == NO_ERROR )
{
*attributesLen = *((UInt16*)curPtr);
curPtr += 2;
*attributesPtr = curPtr;
curPtr += *attributesLen;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
}
else if ( GETFUN( buffer ) == SRVDEREG )
{
const char* curPtr = buffer + GETHEADERLEN( buffer ); const char* eofRegPtr = NULL;
UInt16 messageLength = GETLEN( buffer );
UInt16 slpSPILen, authBlockLen;
UInt16 i;
UInt8 numAuths;
SLP_LOG( SLP_LOG_DEBUG, "Parsing a correctly formed deregistration packet from a non Mac OS 9.1 -> 10.1 machine" );
if ( messageLength > length )
{
SLP_LOG( SLP_LOG_ERR, "ParseOutRegDereg (SRVDEREG), message's length (%ld) says its longer than the message (%ld) itself!", messageLength, length );
return PARSE_ERROR;
}
else if ( messageLength != length )
{
SLP_LOG( SLP_LOG_ERR, "ParseOutRegDereg (SRVDEREG), message's length (%ld) says its different than the message (%ld) itself!", messageLength, length );
return PARSE_ERROR;
}
error = NO_ERROR;
eofRegPtr = buffer + messageLength;
if ( error == NO_ERROR )
{
*scopeListLen = *((UInt16*)curPtr);
curPtr += 2;
*scopeListPtr = curPtr;
curPtr += *scopeListLen;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
curPtr += 3;
*serviceURLLen = *((UInt16*)curPtr);
curPtr += 2;
*serviceURL = curPtr;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR;
if ( error == NO_ERROR )
{
*serviceTypePtr = *serviceURL;
while ( memcmp( curPtr, ":/", 2 ) != 0 && curPtr < eofRegPtr )
curPtr++;
*serviceTypeLen = curPtr - *serviceTypePtr;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
if ( error == NO_ERROR )
{
curPtr = *serviceURL + *serviceURLLen;
numAuths = *curPtr;
curPtr++;
for ( i=0; i<numAuths; i++ )
{
slpSPILen = *((UInt16*)curPtr);
curPtr++;
curPtr += 2; authBlockLen = *((UInt16*)curPtr);
curPtr += authBlockLen;
curPtr -= 2; }
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
if ( error == NO_ERROR )
{
*attributesLen = *((UInt16*)curPtr);
curPtr += 2;
*attributesPtr = curPtr;
curPtr += *attributesLen;
if ( curPtr > eofRegPtr )
error = PARSE_ERROR; }
}
else
{
error = PARSE_ERROR;
SLP_LOG( SLP_LOG_MSG, "Parsing an incorrectly formed reg/dereg packet!" );
}
return error;
}