#include <stdio.h>
#include <string.h>
#include <sys/un.h>
#include "mslp_sd.h"
#include "slp.h"
#include "mslp.h"
#include "mslpd_store.h"
#include "mslp_dat.h"
#include "mslpd.h"
#include "mslpd_mask.h"
#include "mslpd_parse.h"
#include "slpipc.h"
#include "ServiceInfo.h"
#include "SLPRegistrar.h"
#include "SLPComm.h"
#include "CNSLTimingUtils.h"
#ifdef USE_SLPREGISTRAR
SLPRegistrar* gsSLPRegistrar = NULL;
int gTotalServices = 0;
void GetServiceTypeFromURL( const char* readPtr,
UInt32 theURLLength,
char* URLType );
SLPReturnError HandleRegDereg( SLPBoolean isReg, const char* pcInBuf, int iInSz, struct sockaddr_in* sinIn );
long GetStatelessBootTime( void )
{
return SLPRegistrar::TheSLPR()->GetStatelessBootTime();
}
long GetCurrentTime( void )
{
struct timeval curTime;
if ( gettimeofday( &curTime, NULL ) != 0 )
LOG_STD_ERROR_AND_RETURN( SLP_LOG_ERR, "call to gettimeofday returned error: %s", errno );
return curTime.tv_sec;
}
SLPReturnError HandleRegistration( const char* pcInBuf, int iInSz, struct sockaddr_in* sinIn )
{
return HandleRegDereg( SLP_TRUE, pcInBuf, iInSz, sinIn );
}
SLPReturnError HandleDeregistration( const char* pcInBuf, int iInSz, struct sockaddr_in* sinIn )
{
return HandleRegDereg( SLP_FALSE, pcInBuf, iInSz, sinIn );
}
SLPReturnError HandleRegDereg( SLPBoolean isReg, const char* pcInBuf, int iInSz, struct sockaddr_in* sinIn )
{
UInt16 lifeTime;
const char* serviceURL;
UInt16 serviceURLLen;
const char* serviceTypePtr;
UInt16 serviceTypeLen;
const char* scopeListPtr;
char scopeToRegIn[256] = {0};
UInt16 scopeListLen;
const char* attributesPtr;
UInt16 attributesLen;
ServiceInfo* newSI = NULL;
SLPReturnError error = ParseOutRegDereg( pcInBuf,
iInSz,
&lifeTime,
&serviceURL,
&serviceURLLen,
&serviceTypePtr,
&serviceTypeLen,
&scopeListPtr,
&scopeListLen,
&attributesPtr,
&attributesLen );
if ( error )
{
SLP_LOG( SLP_LOG_DROP, "Error in Parsing RegDereg header" );
}
if ( !error )
{
memcpy( scopeToRegIn, scopeListPtr, (scopeListLen<sizeof(scopeToRegIn))?scopeListLen:sizeof(scopeToRegIn)-1 );
if ( !list_intersection( SLPGetProperty("com.apple.slp.daScopeList"), scopeToRegIn ) )
{
char errorMsg[512];
error = SCOPE_NOT_SUPPORTED;
sprintf( errorMsg, "Service Agent: %s tried registering in an invalid scope (%s): %s", inet_ntoa(sinIn->sin_addr), scopeToRegIn, slperror(SLP_SCOPE_NOT_SUPPORTED) );
SLP_LOG( SLP_LOG_DA, errorMsg );
}
}
if ( !error )
{
error = CreateNewServiceInfo( lifeTime,
serviceURL,
serviceURLLen,
serviceTypePtr,
serviceTypeLen,
scopeListPtr,
scopeListLen,
attributesPtr,
attributesLen,
sinIn->sin_addr.s_addr,
&newSI );
if ( error )
SLP_LOG( SLP_LOG_ERR, "CreateNewServiceInfo returned error" );
}
if ( !error )
{
SLPRegistrar::Lock();
if ( isReg )
{
static int counter = 1;
SLP_LOG( SLP_LOG_MSG, "SLPRegistrar::TheSLPR()->RegisterService called for %dth time", counter++);
SLPRegistrar::TheSLPR()->RegisterService( newSI );
}
else
{
SLPRegistrar::TheSLPR()->DeregisterService( newSI );
}
newSI->RemoveInterest();
SLPRegistrar::Unlock();
}
return error;
}
SLPReturnError DAHandleRequest( SAState *psa, struct sockaddr_in* sinIn, SLPBoolean viaTCP, Slphdr *pslphdr, const char *pcInBuf,
int iInSz, char **ppcOutBuf, int *piOutSz, int *piGot )
{
int err;
SLPReturnError result = NO_ERROR;
SLPInternalError iErr = SLP_OK;
char* previousResponderList = NULL;
char* serviceType = NULL;
char* scopeList = NULL;
char* attributeList = NULL;
UInt16 serviceTypeLen = 0;
UInt16 scopeListLen = 0;
UInt16 attributeListLen = 0;
if ((err = srvrqst_in(pslphdr, pcInBuf, iInSz, &previousResponderList, &serviceType, &scopeList, &attributeList))<0)
{
SLP_LOG( SLP_LOG_DROP,"DAHandleRequest: drop request due to parse in error" );
}
else
{
SLP_LOG( SLP_LOG_DEBUG, "DAHandleRequest: calling SLPRegistrar::TheSLPR()->CreateReplyToServiceRequest" );
if ( !SDstrcasecmp(serviceType,"service:directory-agent") || !SDstrcasecmp(serviceType,"service:service-agent") )
{
if ( !SDstrcasecmp(serviceType,"service:directory-agent") )
{
if ( viaTCP )
SLP_LOG( SLP_LOG_DA, "received TCP service:directory-agent request from %s", inet_ntoa(sinIn->sin_addr) );
else
SLP_LOG( SLP_LOG_DA, "received service:directory-agent request from %s", inet_ntoa(sinIn->sin_addr) );
}
else
{
SLP_LOG( SLP_LOG_SR, "service:service-agent from %s", inet_ntoa(sinIn->sin_addr) );
}
iErr = (SLPInternalError)store_request( psa, viaTCP, pslphdr, pcInBuf, iInSz, ppcOutBuf, piOutSz, piGot);
if ( iErr )
result = InternalToReturnError( iErr );
}
else
{
SLP_LOG( SLP_LOG_SR, "service: %s request from %s", serviceType, inet_ntoa(sinIn->sin_addr) );
if ( serviceType )
serviceTypeLen = strlen( serviceType );
if ( scopeList )
scopeListLen = strlen( scopeList );
if ( attributeList )
attributeListLen = strlen( attributeList );
SLPRegistrar::Lock();
result = InternalToReturnError( SLPRegistrar::TheSLPR()->CreateReplyToServiceRequest(
viaTCP,
pslphdr,
pcInBuf,
iInSz,
serviceType,
serviceTypeLen,
scopeList,
scopeListLen,
attributeList,
attributeListLen,
ppcOutBuf,
piOutSz ) );
*piGot = 1;
SLPRegistrar::Unlock();
if ( !*ppcOutBuf )
SLP_LOG( SLP_LOG_ERR, "*ppcOutBuf is NULL after parsing request from %s", inet_ntoa(sinIn->sin_addr) );
else
SLP_LOG( SLP_LOG_MSG, "Sending back a %ld size message to %s", *piOutSz, inet_ntoa(sinIn->sin_addr) );
}
}
if (serviceType)
SLPFree((void*)serviceType);
if (previousResponderList)
SLPFree((void*)previousResponderList);
if (scopeList)
SLPFree((void*)scopeList);
if (attributeList)
SLPFree((void*)attributeList);
return result;
}
pthread_mutex_t SLPRegistrar::msObjectLock;
pthread_mutex_t SLPRegistrar::msSLPRLock;
Boolean gsLocksInitiailzed = false;
void TurnOnDA( void )
{
SLP_LOG( SLP_LOG_RADMIN, "Setting property: \"com.apple.slp.isDA\" to true" );
SLPSetProperty("com.apple.slp.isDA", "true");
if ( gsSLPRegistrar )
gsSLPRegistrar->SendRAdminSLPStarted();
}
void TurnOffDA( void )
{
SLP_LOG( SLP_LOG_RADMIN, "Setting property: \"com.apple.slp.isDA\" to false" );
SLPSetProperty("com.apple.slp.isDA", "false");
if ( gsSLPRegistrar )
gsSLPRegistrar->SendRAdminSLPStopped();
}
void InitSLPRegistrar( void )
{
if ( !gsSLPRegistrar )
{
gsSLPRegistrar = new SLPRegistrar();
gsSLPRegistrar->Initialize();
}
}
void TearDownSLPRegistrar( void )
{
if ( gsSLPRegistrar )
{
gsSLPRegistrar->SetStatelessBootTime( 0 ); gsSLPRegistrar->DoDeregisterAllServices();
}
}
void ResetStatelessBootTime( void )
{
if ( gsSLPRegistrar )
{
struct timeval currentTime;
struct timezone tz;
gettimeofday( ¤tTime, &tz );
gsSLPRegistrar->SetStatelessBootTime( currentTime.tv_sec ); }
}
CFStringRef SLPCliqueValueCopyDesctriptionCallback ( const void *value );
Boolean SLPCliqueValueEqualCallback ( const void *value1, const void *value2 );
void SLPCliqueHandlerFunction(const void *inKey, const void *inValue, void *inContext);
CFStringRef SLPServiceInfoCopyDesctriptionCallback ( const void *item );
Boolean SLPServiceInfoEqualCallback ( const void *item1, const void *item2 );
CFHashCode SLPServiceInfoHashCallback(const void *key);
void SLPServiceInfoHandlerFunction(const void *inValue, void *inContext);
CFStringRef SLPCliqueValueCopyDesctriptionCallback ( const void *value )
{
SLPClique* clique = (SLPClique*)value;
return clique->GetValueRef();
}
Boolean SLPCliqueValueEqualCallback ( const void *value1, const void *value2 )
{
SLPClique* clique1 = (SLPClique*)value1;
SLPClique* clique2 = (SLPClique*)value2;
return ( clique1 == clique2 || CFStringCompare( clique1->GetValueRef(), clique2->GetValueRef(), kCFCompareCaseInsensitive ) == kCFCompareEqualTo );
}
void SLPCliqueHandlerFunction(const void *inKey, const void *inValue, void *inContext)
{
SLPClique* curClique = (SLPClique*)inValue;
SLPCliqueHandlerContext* context = (SLPCliqueHandlerContext*)inContext;
switch ( context->message )
{
case kDeleteSelf:
delete curClique;
break;
case kDeleteCliquesMatchingScope:
if ( strcmp(curClique->CliqueScopePtr(), (char*)(context->dataPtr)) == 0 )
{
::CFDictionaryRemoveValue( context->dictionary, curClique->GetKeyRef() ); delete curClique;
}
break;
case kReportServicesToRAdmin:
curClique->ReportAllServicesToRAdmin();
break;
case kUpdateCache:
{
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar Updating Cache" );
if ( curClique->CacheIsDirty() )
{
SLPInternalError status = curClique->UpdateCachedReplyForClique();
if ( status == SLP_DA_BUSY_NOW )
{
SLP_LOG( SLP_LOG_MSG, "SLPRegistrar Updating Cache received a DA_BUSY_NOW error, will postpone update" );
}
}
}
break;
case kDoTimeCheckOnTTLs:
{
SLPServiceInfoHandlerContext context = {kDoTimeCheckOnTTLs, curClique};
::CFSetApplyFunction( curClique->GetSetOfServiceInfosRef(), SLPServiceInfoHandlerFunction, &context );
}
break;
};
}
#pragma mark еее Public Methods for SLPRegistrar еее
void SLPRegistrar::Lock( void )
{
pthread_mutex_lock( &SLPRegistrar::msObjectLock );
}
SLPRegistrar::SLPRegistrar()
{
mListOfSLPCliques = NULL;
mOneOrMoreCliquesNeedUpdating = false;
mLastTTLTimeCheck = 0;
mAlreadyReadRegFile = false;
mStatelessBootTime = 0;
mRAdminNotifier = NULL;
mSelfPtr = NULL;
}
SLPRegistrar::~SLPRegistrar()
{
SLPCliqueHandlerContext context = {mListOfSLPCliques, kDeleteSelf, this};
mSelfPtr = NULL;
Lock();
if ( mListOfSLPCliques )
{
::CFDictionaryApplyFunction( mListOfSLPCliques, SLPCliqueHandlerFunction, &context );
::CFDictionaryRemoveAllValues( mListOfSLPCliques );
::CFRelease( mListOfSLPCliques );
mListOfSLPCliques = NULL;
}
Unlock();
}
SLPRegistrar* SLPRegistrar::TheSLPR( void )
{
return gsSLPRegistrar;
}
void SLPRegistrar::Initialize( void )
{
if ( !gsLocksInitiailzed )
{
pthread_mutex_init( &msObjectLock, NULL );
pthread_mutex_init( &msSLPRLock, NULL );
gsLocksInitiailzed = true;
}
ResetStatelessBootTime();
CFDictionaryValueCallBacks valueCallBack;
valueCallBack.version = 0;
valueCallBack.retain = NULL;
valueCallBack.release = NULL;
valueCallBack.copyDescription = SLPCliqueValueCopyDesctriptionCallback;
valueCallBack.equal = SLPCliqueValueEqualCallback;
mListOfSLPCliques = ::CFDictionaryCreateMutable( NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &valueCallBack);
mSelfPtr = this;
}
#pragma mark -
void SLPRegistrar::EnableRAdminNotification( void )
{
SLPSetProperty( "com.apple.slp.RAdminNotificationsEnabled", "true" );
if ( !mRAdminNotifier )
{
mRAdminNotifier = new SLPRAdminNotifier();
if ( mRAdminNotifier )
{
mRAdminNotifier->Resume();
}
else
SLP_LOG( SLP_LOG_ERR, "SLPRegistrar couldn't create its Notifier Thread!" );
}
if ( mRAdminNotifier )
mRAdminNotifier->RepostAllRegisteredData();
}
Boolean SLPRegistrar::IsServiceAlreadyRegistered( ServiceInfo* service )
{
Boolean isAlreadyRegistered = false;
if ( service )
{
SLPClique* clique = FindClique( service );
if ( clique )
isAlreadyRegistered = clique->IsServiceInfoInClique( service );
}
return isAlreadyRegistered;
}
SLPInternalError SLPRegistrar::RegisterService( ServiceInfo* service )
{
SLPInternalError status = SLP_OK;
SLPClique* clique = NULL;
#ifdef USE_EXCEPTIONS
try
#endif
{
if ( service )
{
clique = FindClique( service );
if ( clique )
{
status = clique->AddServiceInfoToClique( service );
if ( !status )
mOneOrMoreCliquesNeedUpdating = true;
}
else
{
#ifdef USE_EXCEPTIONS
try
#endif
{
clique = new SLPClique();
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( clique );
#endif
if ( clique )
{
clique->Initialize( service );
::CFDictionaryAddValue( mListOfSLPCliques, clique->GetKeyRef(), clique );
status = clique->AddServiceInfoToClique( service );
if ( !status )
mOneOrMoreCliquesNeedUpdating = true;
}
}
#ifdef USE_EXCEPTIONS
catch ( int inErr )
{
status = (SLPInternalError)inErr;
if ( clique )
delete clique;
}
#endif
}
}
else
SLP_LOG( SLP_LOG_DA, "SLPRegistrar::RegisterService was passed a NULL service!");
}
#ifdef USE_EXCEPTIONS
catch ( int inErr )
{
status = (SLPInternalError)inErr;
}
#endif
return status;
}
SLPInternalError SLPRegistrar::DeregisterService( ServiceInfo* service )
{
SLPInternalError status = SLP_OK;
#ifdef USE_EXCEPTIONS
try
#endif
{
if ( service && service->SafeToUse() )
{
SLPClique* clique = FindClique( service );
if ( clique )
{
status = clique->RemoveServiceInfoFromClique( service );
if ( clique->GetSetOfServiceInfosRef() == NULL ) {
::CFDictionaryRemoveValue( mListOfSLPCliques, clique->GetKeyRef() );
delete clique;
}
}
else
status = SERVICE_NOT_REGISTERED;
}
}
#ifdef USE_EXCEPTIONS
catch ( int inErr )
{
SLP_LOG( SLP_LOG_ERR, "SLPRegistrar::DeregisterService Caught_ inErr: %ld", (SLPInternalError)inErr );
status = (SLPInternalError)inErr;
}
#endif
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::DeregisterService finished, returning status: %d", status );
return status;
}
SLPInternalError SLPRegistrar::RemoveScope( char* scope )
{
SLPCliqueHandlerContext context = {mListOfSLPCliques,kDeleteCliquesMatchingScope, scope};
SLPInternalError error = SLP_OK;
Lock();
if ( mListOfSLPCliques )
{
::CFDictionaryApplyFunction( mListOfSLPCliques, SLPCliqueHandlerFunction, &context );
}
if ( RAdminNotificationEnabled() )
{
SendRAdminDeletedScope( scope );
}
Unlock();
return error;
}
void SLPRegistrar::AddNotification( char* buffer, UInt32 bufSize )
{
if ( mRAdminNotifier )
mRAdminNotifier->AddNotificationToQueue( buffer, bufSize );
}
void SLPRegistrar::DoSendRAdminAllCurrentlyRegisteredServices( void )
{
if ( mRAdminNotifier )
mRAdminNotifier->RepostAllRegisteredData();
}
void SLPRegistrar::SendRAdminSLPStarted( void )
{
UInt32 dataSendBufferLen;
char* dataSendBuffer = NULL;
MakeSLPDAStatus( kSLPDARunning, &dataSendBufferLen, &dataSendBuffer );
AddNotification( dataSendBuffer, dataSendBufferLen ); }
void SLPRegistrar::SendRAdminSLPStopped( void )
{
UInt32 dataSendBufferLen;
char* dataSendBuffer = NULL;
MakeSLPDAStatus( kSLPDANotRunning, &dataSendBufferLen, &dataSendBuffer );
AddNotification( dataSendBuffer, dataSendBufferLen ); }
void SLPRegistrar::SendRAdminDeleteAllScopes( void )
{
char* pcScope = NULL;
const char* pcList = SLPGetProperty("com.apple.slp.daScopeList");
int offset=0;
char c;
while( (pcScope = get_next_string(",",pcList,&offset,&c)) )
{
mslplog( SLP_LOG_RADMIN, "SendRAdminDeleteAllScopes removing scope: ", pcScope );
RemoveScope( pcScope );
free(pcScope);
}
}
void SLPRegistrar::SendRAdminAllScopes( void )
{
char* pcScope = NULL;
const char* pcList = SLPGetProperty("com.apple.slp.daScopeList");
int offset=0;
char c;
while( (pcScope = get_next_string(",",pcList,&offset,&c)) )
{
SendRAdminAddedScope( pcScope );
free(pcScope);
}
}
void SLPRegistrar::SendRAdminAddedScope( const char* newScope )
{
UInt32 dataSendBufferLen = sizeof(SLPdMessageHeader) + strlen(newScope);
char* dataSendBuffer = (char*)malloc(dataSendBufferLen);
SLPdMessageHeader* header = (SLPdMessageHeader*)dataSendBuffer;
header->messageType = kSLPAddScope;
header->messageLength = dataSendBufferLen;
header->messageStatus = 0;
char* curPtr = (char*)header + sizeof(SLPdMessageHeader);
::memcpy( curPtr, newScope, strlen(newScope) );
AddNotification( dataSendBuffer, dataSendBufferLen ); }
void SLPRegistrar::SendRAdminDeletedScope( const char* oldScope )
{
UInt32 dataSendBufferLen = sizeof(SLPdMessageHeader) + strlen(oldScope);
char* dataSendBuffer = (char*)malloc(dataSendBufferLen);
SLPdMessageHeader* header = (SLPdMessageHeader*)(dataSendBuffer);
header->messageType = kSLPDeleteScope;
header->messageLength = dataSendBufferLen;
header->messageStatus = 0;
char* curPtr = (char*)header + sizeof(SLPdMessageHeader);
::memcpy( curPtr, oldScope, strlen(oldScope) );
AddNotification( dataSendBuffer, dataSendBufferLen ); }
void SLPRegistrar::SendRAdminAllCurrentlyRegisteredServices( void )
{
SLPCliqueHandlerContext context = {mListOfSLPCliques, kReportServicesToRAdmin, NULL};
Lock();
if ( mListOfSLPCliques )
::CFDictionaryApplyFunction( mListOfSLPCliques, SLPCliqueHandlerFunction, &context );
Unlock();
}
void SLPRegistrar::DoDeregisterAllServices( void )
{
if ( mRAdminNotifier )
mRAdminNotifier->DeregisterAllRegisteredData();
}
void SLPRegistrar::DeregisterAllServices( void )
{
SLPCliqueHandlerContext context = {mListOfSLPCliques, kDeleteSelf, NULL};
Lock();
if ( mListOfSLPCliques )
{
::CFDictionaryApplyFunction( mListOfSLPCliques, SLPCliqueHandlerFunction, &context );
::CFDictionaryRemoveAllValues( mListOfSLPCliques );
}
Unlock();
}
SLPInternalError SLPRegistrar::CreateReplyToServiceRequest(
SLPBoolean viaTCP,
Slphdr *pslphdr,
const char* originalHeader,
UInt16 originalHeaderLength,
char* serviceType,
UInt16 serviceTypeLen,
char* scopeList,
UInt16 scopeListLen,
char* attributeList,
UInt16 attributeListLen,
char** returnBuffer,
int *piOutSz )
{
SLPInternalError error = SLP_OK; UInt16 returnBufferLen;
char* tempPtr = NULL;
char* endPtr = NULL;
int iMTU = strtol(SLPGetProperty("net.slp.MTU"),&endPtr,10);
int iOverflow = 0;
SLPClique* matchingClique = NULL;
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::CreateReplyToServiceRequest called" );
matchingClique = FindClique( serviceType, serviceTypeLen, scopeList, scopeListLen, attributeList, attributeListLen );
if ( returnBuffer && matchingClique )
{
if ( matchingClique->CacheIsDirty() )
error = matchingClique->UpdateCachedReplyForClique();
if ( !error )
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::CreateReplyToServiceRequest(), Copying Cached Return Data" );
*piOutSz = matchingClique->GetCacheSize();
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::CreateReplyToServiceRequest for %s in %s, *piOutSz: %ld", serviceType, scopeList, *piOutSz );
if ( !viaTCP && *piOutSz > iMTU ) {
*piOutSz = GETHEADERLEN(originalHeader) + 4;
iOverflow = 1;
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::CreateReplyToServiceRequest(), sending back overflow message" );
}
if ( !error )
tempPtr = safe_malloc(*piOutSz, 0, 0);
if( !tempPtr )
error = SLP_PARAMETER_BAD;
if ( !error )
{
if ( iOverflow )
{
SETVER(tempPtr,2);
SETFUN(tempPtr,SRVRPLY);
SETLEN(tempPtr,*piOutSz);
SETLANG(tempPtr,pslphdr->h_pcLangTag);
SETFLAGS(tempPtr,OVERFLOWFLAG);
}
else
error = matchingClique->CopyCachedReturnData( tempPtr, matchingClique->GetCacheSize(), &returnBufferLen );
}
if ( !error )
SETXID(tempPtr, pslphdr->h_usXID );
if ( error )
LOG_SLP_ERROR_AND_RETURN( SLP_LOG_ERR, "SLPRegistrar::CreateReplyToServiceRequest, CopyCachedReturnData returned error", error );
if ( !error )
*returnBuffer = tempPtr;
}
else if ( returnBuffer )
{
error = SLP_OK;
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::CreateReplyToServiceRequest(), sending back empty result" );
*piOutSz = GETHEADERLEN(originalHeader) + 4;
tempPtr = safe_malloc(*piOutSz, 0, 0);
if ( tempPtr )
{
SETVER(tempPtr,2);
SETFUN(tempPtr,SRVRPLY);
SETLEN(tempPtr,*piOutSz);
SETLANG(tempPtr,pslphdr->h_pcLangTag);
}
else
error = SLP_PARAMETER_BAD;
*returnBuffer = tempPtr;
}
else
{
SLP_LOG( SLP_LOG_DEBUG, "SLPRegistrar::CreateReplyToServiceRequest, returnBuffer is NULL!" );
}
return error;
}
#pragma mark -
#pragma mark -
SLPClique* SLPRegistrar::FindClique( ServiceInfo* service )
{
UInt16 serviceTypeLen = strlen(service->PtrToServiceType( &serviceTypeLen ));
SLPClique* foundClique = FindClique( service->PtrToServiceType( &serviceTypeLen ), serviceTypeLen, service->GetScope(), service->GetScopeLen(), service->GetAttributeList(), service->GetAttributeListLen() );
return foundClique;
}
void SLPRegistrar::UpdateDirtyCaches( void )
{
#ifdef USE_EXCEPTIONS
try
#endif
{
SLPCliqueHandlerContext context = {mListOfSLPCliques, kUpdateCache, NULL};
Lock();
if ( mListOfSLPCliques && mOneOrMoreCliquesNeedUpdating )
{
::CFDictionaryApplyFunction( mListOfSLPCliques, SLPCliqueHandlerFunction, &context );
}
mOneOrMoreCliquesNeedUpdating = false;
Unlock();
}
#ifdef USE_EXCEPTIONS
catch ( int inErr )
{
SLP_LOG( SLP_LOG_DA, "SLPRegistrar::UpdateDirtyCaches Caught Err: %d", (SLPInternalError)inErr );
}
#endif
}
#ifdef DO_TIME_CHECKS_ON_TTLS
SLPInternalError SLPRegistrar::DoTimeCheckOnTTLs( void )
{
SLPInternalError status = SLP_OK;
if ( GetCurrentTime() > mLastTTLTimeCheck + kTimeBetweenTTLTimeChecks )
{
SLPCliqueHandlerContext context = {mListOfSLPCliques, kDoTimeCheckOnTTLs, NULL};
Lock();
if ( mListOfSLPCliques && mOneOrMoreCliquesNeedUpdating )
{
::CFDictionaryApplyFunction( mListOfSLPCliques, SLPCliqueHandlerFunction, &context );
}
Unlock();
mLastTTLTimeCheck = GetCurrentTime();
}
return status;
}
#endif //#ifdef DO_TIME_CHECKS_ON_TTLS
#pragma mark еее Protected Methods for SLPRegistrar еее
SLPClique* SLPRegistrar::FindClique( char* serviceType,
UInt16 serviceTypeLen,
char* scopeList,
UInt16 scopeListLen,
char* attributeList,
UInt16 attributeListLen )
{
SLPClique* curClique = NULL;
CFStringRef keyRef;
char keyString[512] = {0};
if ( mListOfSLPCliques )
{
memcpy( keyString, serviceType, serviceTypeLen );
memcpy( keyString+serviceTypeLen, "://", 3 );
memcpy( keyString+serviceTypeLen+3, scopeList, scopeListLen );
keyRef = ::CFStringCreateWithCString( kCFAllocatorDefault, keyString, kCFStringEncodingUTF8 );
if( keyRef )
{
if ( ::CFDictionaryGetCount( mListOfSLPCliques ) > 0 && ::CFDictionaryContainsKey( mListOfSLPCliques, keyRef ) )
curClique = (SLPClique*)::CFDictionaryGetValue( mListOfSLPCliques, keyRef );
else
{
SLP_LOG( SLP_LOG_DROP, "Unable to find SLPClique for request %s in %s. Dictionary count: %d", serviceType, scopeList, ::CFDictionaryGetCount( mListOfSLPCliques ) );
}
::CFRelease( keyRef );
}
}
return curClique;
}
#pragma mark -
CFStringRef SLPServiceInfoCopyDesctriptionCallback ( const void *item )
{
ServiceInfo* serviceInfo = (ServiceInfo*)item;
return serviceInfo->GetURLRef();
}
Boolean SLPServiceInfoEqualCallback ( const void *item1, const void *item2 )
{
ServiceInfo* serviceInfo1 = (ServiceInfo*)item1;
ServiceInfo* serviceInfo2 = (ServiceInfo*)item2;
return ( serviceInfo1 == serviceInfo2 || *serviceInfo1 == *serviceInfo2 );
}
#define HAVENT_TESTED_HASH_CALLBACK
CFHashCode SLPServiceInfoHashCallback(const void *key)
{
#ifdef HAVENT_TESTED_HASH_CALLBACK
return 2;
#elif
ServiceInfo* serviceInfo = (ServiceInfo*)key;
if ( serviceInfo->GetURLRef() )
return CFHash(serviceInfo->GetURLRef());
else
return 0;
#endif
}
void SLPServiceInfoHandlerFunction(const void *inValue, void *inContext)
{
ServiceInfo* curServiceInfo = (ServiceInfo*)inValue;
SLPServiceInfoHandlerContext* context = (SLPServiceInfoHandlerContext*)inContext;
SLPClique* clique = (SLPClique*)context->dataPtr;
switch ( context->message )
{
case kDeleteSelf:
clique->RemoveServiceInfoFromClique( curServiceInfo ); break;
case kUpdateCache:
clique->AddToCachedReply( curServiceInfo );
break;
case kReportServicesToRAdmin:
clique->NotifyRAdminOfChange( kServiceAdded, curServiceInfo );
break;
case kDoTimeCheckOnTTLs:
if ( AreWeADirectoryAgent() )
{
if ( curServiceInfo->IsTimeToExpire() )
{
SLP_LOG( SLP_LOG_EXP, "Service URL Expired: URL=%s, SCOPE= %s", curServiceInfo->GetURLPtr(), curServiceInfo->GetScope() );
clique->RemoveServiceInfoFromClique(curServiceInfo);
}
}
break;
default:
SLP_LOG( SLP_LOG_DEBUG, "SLPServiceInfoHandlerFunction - received unhandled message type!" );
break;
};
}
#pragma mark еее Public Methods for SLPClique еее
SLPClique::SLPClique()
{
mSelfPtr = NULL;
mSetOfServiceInfos = NULL;
mCliqueScope = NULL;
mCliqueServiceType = NULL;
mCachedReplyForClique = NULL;
mCacheSize = 0;
mLastRegDeregistrationTime = 0;
mIsCacheDirty = true;
mNotifyRAdminOfChanges = false;
mKeyRef = NULL;
}
SLPClique::~SLPClique()
{
if ( mSetOfServiceInfos )
{
SLPServiceInfoHandlerContext context = {kDeleteSelf, this};
::CFSetApplyFunction( mSetOfServiceInfos, SLPServiceInfoHandlerFunction, &context );
::CFSetRemoveAllValues( mSetOfServiceInfos );
::CFRelease( mSetOfServiceInfos );
mSetOfServiceInfos = NULL;
}
if ( mCliqueScope )
{
free( mCliqueScope );
mCliqueScope = NULL;
}
if ( mCliqueServiceType )
{
free( mCliqueServiceType );
mCliqueServiceType = NULL;
}
if ( mCachedReplyForClique )
{
free( mCachedReplyForClique );
mCachedReplyForClique = NULL;
}
if ( mKeyRef )
{
CFRelease( mKeyRef );
mKeyRef = NULL;
}
}
void SLPClique::IntitializeInternalParams( ServiceInfo* exampleSI )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( exampleSI );
try
#else
if ( !exampleSI || !exampleSI->GetScope() )
return;
#endif
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( exampleSI->GetScope() );
#endif
mCliqueScope = (char*)malloc( exampleSI->GetScopeLen()+1 ); #ifdef USE_EXCEPTIONS
ThrowIfNULL_( mCliqueScope );
#endif
if ( mCliqueScope )
{
::strcpy( mCliqueScope, exampleSI->GetScope() );
UInt16 serviceTypeLen;
char* serviceTypePtr = exampleSI->PtrToServiceType(&serviceTypeLen) ;
mCliqueServiceType = (char*)malloc( serviceTypeLen+1 );
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( mCliqueServiceType );
#endif
if ( mCliqueServiceType )
{
::memcpy( mCliqueServiceType, serviceTypePtr, serviceTypeLen );
mCliqueServiceType[serviceTypeLen] = '\0';
char keyString[512];
sprintf( keyString, "%s://%s", mCliqueServiceType, mCliqueScope );
mKeyRef = ::CFStringCreateWithCString( kCFAllocatorDefault, keyString, kCFStringEncodingUTF8 );
}
}
}
#ifdef USE_EXCEPTIONS
catch ( int inErr )
{
if ( mCliqueScope )
{
free( mCliqueScope );
mCliqueScope = NULL;
}
if ( mCliqueServiceType )
{
free( mCliqueServiceType );
mCliqueServiceType = NULL;
}
Throw_( inErr );
}
#endif
}
void SLPClique::Initialize( ServiceInfo* newService )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( newService );
#endif
if ( !newService )
return;
CFSetCallBacks callBack;
callBack.version = 0;
callBack.retain = NULL;
callBack.release = NULL;
callBack.copyDescription = SLPServiceInfoCopyDesctriptionCallback;
callBack.equal = SLPServiceInfoEqualCallback;
callBack.hash = SLPServiceInfoHashCallback;
mSetOfServiceInfos = ::CFSetCreateMutable( NULL, 0, &callBack );
IntitializeInternalParams( newService );
mSelfPtr = this;
}
#pragma mark -
Boolean SLPClique::IsServiceInfoOKToJoinClique( ServiceInfo* service )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( service );
ThrowIfNULL_( service->GetScope() );
#endif
if ( !service || !service->GetScope() )
return false;
UInt16 serviceTypeLen;
Boolean okToJoin = false;
if ( this->ServiceTypeMatchesClique( service->PtrToServiceType( &serviceTypeLen ), serviceTypeLen ) )
{
if ( this->ScopeMatchesClique( service->GetScope(), ::strlen( service->GetScope() ) ) ) {
okToJoin = true;
}
}
return okToJoin;
}
Boolean SLPClique::IsServiceInfoInClique( ServiceInfo* service )
{
Boolean serviceFound = false;
if ( mSetOfServiceInfos && service && ::CFSetGetCount( mSetOfServiceInfos ) > 0 )
serviceFound = ::CFSetContainsValue( mSetOfServiceInfos, service );
return serviceFound;
}
void SLPClique::NotifyRAdminOfChange( ChangeType type, ServiceInfo* service )
{
if ( SLPRegistrar::TheSLPR()->RAdminNotificationEnabled() && AreWeADirectoryAgent() )
{
char* dataSendBuffer = NULL;
UInt32 dataSendBufferLen = 0;
OSStatus status = noErr;
if ( type == kServiceAdded )
status = MakeSLPServiceInfoAddedNotificationBuffer( service, &dataSendBufferLen, &dataSendBuffer );
else
status = MakeSLPServiceInfoRemovedNotificationBuffer( service, &dataSendBufferLen, &dataSendBuffer );
SLPRegistrar::TheSLPR()->AddNotification( dataSendBuffer, dataSendBufferLen );
if ( status )
{
SLP_LOG( SLP_LOG_DROP, "Error notifing ServerAdmin of Service Change: %s", strerror(status) );
}
}
}
SLPInternalError SLPClique::AddServiceInfoToClique( ServiceInfo* service )
{
SLPInternalError status = SLP_OK;
ServiceInfo* siToNotifyWith = service;
if ( IsServiceInfoInClique( service ) )
{
status = SERVICE_ALREADY_REGISTERED;
siToNotifyWith = (ServiceInfo*)::CFSetGetValue( mSetOfServiceInfos, service );
}
else if ( mSetOfServiceInfos )
CFSetAddValue( mSetOfServiceInfos, service );
if ( !status )
{
SLP_LOG( SLP_LOG_REG, "New Service Registered, URL=%s. SCOPE=%s", service->GetURLPtr(), service->GetScope() );
SLP_LOG( SLP_LOG_MSG, "Total Services: %d", ++gTotalServices );
service->AddInterest();
mIsCacheDirty = true;
mLastRegDeregistrationTime = GetCurrentTime();
}
else
{
SLP_LOG( SLP_LOG_MSG, "Duplicate Service, update timestamp, URL=%s, SCOPE=%s", service->GetURLPtr(), service->GetScope() );
siToNotifyWith->UpdateLastRegistrationTimeStamp();
}
NotifyRAdminOfChange( kServiceAdded, siToNotifyWith );
return SLP_OK; }
SLPInternalError SLPClique::RemoveServiceInfoFromClique( ServiceInfo* service )
{
ServiceInfo* serviceInClique = NULL; SLPInternalError status = SLP_OK;
if ( IsServiceInfoInClique( service ) )
serviceInClique = (ServiceInfo*)::CFSetGetValue( mSetOfServiceInfos, service );
if ( serviceInClique )
{
::CFSetRemoveValue( mSetOfServiceInfos, serviceInClique );
{
SLP_LOG( SLP_LOG_REG, "Service Deregistered, URL=%s, SCOPE=%s", service->GetURLPtr(), service->GetScope() );
SLP_LOG( SLP_LOG_MSG, "Total Services: %d", --gTotalServices );
}
NotifyRAdminOfChange( kServiceRemoved, service );
serviceInClique->RemoveInterest();
mIsCacheDirty = true;
mLastRegDeregistrationTime = GetCurrentTime();
}
else
{
status = SERVICE_NOT_REGISTERED;
}
return status;
}
SLPInternalError SLPClique::UpdateRegisteredServiceTimeStamp( ServiceInfo* service )
{
SLPInternalError status = SERVICE_NOT_REGISTERED;
ServiceInfo* serviceInClique = NULL;
if ( IsServiceInfoInClique( service ) )
serviceInClique = (ServiceInfo*)::CFSetGetValue( mSetOfServiceInfos, service );
if ( serviceInClique )
{
serviceInClique->UpdateLastRegistrationTimeStamp();
status = SLP_OK;
}
else
{
SLP_LOG( SLP_LOG_DA, "SLPClique::UpdateRegisteredServiceTimeStamp couldn't find service to update!, URL=%s, SCOPE=%s", service->GetURLPtr(), service->GetScope() );
}
return status;
}
Boolean SLPClique::ServiceTypeMatchesClique( char* serviceType, UInt16 serviceTypeLen )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( mCliqueServiceType );
ThrowIfNULL_( serviceType );
#endif
if ( !mCliqueServiceType || !serviceType )
return false;
Boolean match = false;
if ( serviceTypeLen == ::strlen( mCliqueServiceType ) )
match = ( ::memcmp( mCliqueServiceType, serviceType, serviceTypeLen ) == 0 );
return match;
}
Boolean SLPClique::ScopeMatchesClique( char* scopePtr, UInt16 scopeLen )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( mCliqueScope );
ThrowIfNULL_( scopePtr );
#endif
if ( !mCliqueScope || !scopePtr )
return false;
Boolean match = false;
if ( scopeLen == ::strlen( mCliqueScope ) )
match = ( ::memcmp( mCliqueScope, scopePtr, scopeLen ) == 0 );
return match;
}
#pragma mark -
SLPInternalError SLPClique::UpdateCachedReplyForClique( ServiceInfo* addNewServiceInfo )
{
SLPInternalError error = SLP_OK;
if ( addNewServiceInfo )
{
{
SLP_LOG( SLP_LOG_DEBUG, "SLPClique::UpdateCachedReplyForClique is calling AddToServiceReply for clique: SCOPE=%s, TYPE=%s", mCliqueScope, mCliqueServiceType );
}
AddToServiceReply( mNeedToUseTCP, addNewServiceInfo, NULL, 0, error, &mCachedReplyForClique );
if ( error == SLP_REPLY_TOO_BIG_FOR_PROTOCOL )
{
error = SLP_OK;
mNeedToUseTCP = true;
AddToServiceReply( mNeedToUseTCP, addNewServiceInfo, NULL, 0, error, &mCachedReplyForClique ); }
}
else
{
{
SLP_LOG( SLP_LOG_DEBUG, "SLPClique::UpdateCachedReplyForClique is rebuilding its cached data for clique: SCOPE=%s, TYPE=%s", mCliqueScope, mCliqueServiceType );
}
if ( mCachedReplyForClique )
free( mCachedReplyForClique );
mCachedReplyForClique = NULL;
mNeedToUseTCP = false;
SLPServiceInfoHandlerContext context = {kUpdateCache, this};
::CFSetApplyFunction( mSetOfServiceInfos, SLPServiceInfoHandlerFunction, &context );
}
if ( mCachedReplyForClique )
mCacheSize = GETLEN( mCachedReplyForClique );
else
mCacheSize = 0;
if ( !error )
mIsCacheDirty = false;
return error;
}
void SLPClique::AddToCachedReply( ServiceInfo* curSI )
{
SLPInternalError error = SLP_OK;
AddToServiceReply( mNeedToUseTCP, curSI, NULL, 0, error, &mCachedReplyForClique );
if ( error == SLP_REPLY_TOO_BIG_FOR_PROTOCOL )
{
error = SLP_OK;
mNeedToUseTCP = true;
AddToServiceReply( mNeedToUseTCP, curSI, NULL, 0, error, &mCachedReplyForClique ); }
else if ( error )
mslplog( SLP_LOG_DEBUG, "ServiceAgent::UpdateCachedReplyForClique(), AddToServiceReply() returned:", strerror(error) );
}
UInt16 SLPClique::GetCacheSize()
{
return mCacheSize;
}
SLPInternalError SLPClique::GetPtrToCacheWithXIDFromCurrentRequest( char* buffer, UInt16 length, char** serviceReply, UInt16* replyLength )
{
SLPInternalError status = SLP_OK;
if ( !mIsCacheDirty )
{
CopyXIDFromRequestToCachedReply( (ServiceLocationHeader*)buffer, (ServiceLocationHeader*)mCachedReplyForClique );
*serviceReply = mCachedReplyForClique;
*replyLength = mCacheSize;
}
else
status = (SLPInternalError)DA_BUSY_NOW;
return status;
}
#pragma mark -
void SLPClique::ReportAllServicesToRAdmin( void )
{
SLPServiceInfoHandlerContext context = {kReportServicesToRAdmin, this};
if ( mSetOfServiceInfos )
::CFSetApplyFunction( mSetOfServiceInfos, SLPServiceInfoHandlerFunction, &context );
}
SLPInternalError SLPClique::CopyCachedReturnData( char* returnBuffer, UInt16 maxBufferLen, UInt16* returnBufLen )
{
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( returnBuffer );
ThrowIfNULL_( returnBufLen );
#endif
if ( !returnBuffer || !returnBufLen )
return SLP_INTERNAL_SYSTEM_ERROR;
SLPInternalError status = SLP_OK;
if ( mCacheSize <= maxBufferLen )
{
memcpy( returnBuffer, mCachedReplyForClique, mCacheSize );
*returnBufLen = mCacheSize;
}
else
{
*returnBufLen = GETHEADERLEN(mCachedReplyForClique)+4;
memcpy( returnBuffer, mCachedReplyForClique, *returnBufLen );
SETLEN( returnBuffer, *returnBufLen );
SETFLAGS( returnBuffer, OVERFLOWFLAG );
*((UInt16*)(returnBuffer+GETHEADERLEN(returnBuffer))) = 0; *((UInt16*)((char*)returnBuffer+GETHEADERLEN(returnBuffer)+2)) = 0; }
return status;
}
#pragma mark -
#pragma mark - еее SLPClique Protected Methods еее
#pragma mark -
#pragma mark Services in a file stuff
#pragma mark -
#pragma mark -
#pragma mark -
pthread_mutex_t SLPRAdminNotifier::mQueueLock;
CFStringRef SLPRAdminNotifierCopyDesctriptionCallback ( const void *item )
{
return kSLPRAdminNotificationSAFE_CFSTR;
}
Boolean SLPRAdminNotifierEqualCallback ( const void *item1, const void *item2 )
{
return item1 == item2;
}
SLPRAdminNotifier::SLPRAdminNotifier()
: DSLThread()
{
CFArrayCallBacks callBack;
LOG( SLP_LOG_NOTIFICATIONS, "SLPRAdminNotifier Created" );
callBack.version = 0;
callBack.retain = NULL;
callBack.release = NULL;
callBack.copyDescription = SLPRAdminNotifierCopyDesctriptionCallback;
callBack.equal = SLPRAdminNotifierEqualCallback;
mCanceled = false;
mNotificationsQueue = ::CFArrayCreateMutable ( NULL, 0, &callBack );
pthread_mutex_init( &mQueueLock, NULL );
mClearQueue = false;
mRepostAllScopes = false;
mRepostAllData = false;
mDeregisterAllData = false;
}
SLPRAdminNotifier::~SLPRAdminNotifier()
{
if ( mNotificationsQueue )
CFRelease( mNotificationsQueue );
mNotificationsQueue = NULL;
}
void SLPRAdminNotifier::Cancel( void )
{
mCanceled = true;
}
void* SLPRAdminNotifier::Run( void )
{
NotificationObject* notification = NULL;
while ( !mCanceled )
{
if ( mClearQueue )
{
QueueLock();
LOG( SLP_LOG_NOTIFICATIONS, "SLPRAdminNotifier clearing queue" );
mClearQueue = false;
::CFArrayRemoveAllValues( mNotificationsQueue );
QueueUnlock();
}
else if ( mRepostAllScopes )
{
mRepostAllScopes = false;
LOG( SLP_LOG_NOTIFICATIONS, "SLPRAdminNotifier reposting all scopes" );
SLPRegistrar::TheSLPR()->SendRAdminAllScopes();
}
else if ( mRepostAllData )
{
mRepostAllData = false;
LOG( SLP_LOG_NOTIFICATIONS, "SLPRAdminNotifier reposting all currently registered services" );
SLPRegistrar::TheSLPR()->SendRAdminAllScopes();
SLPRegistrar::TheSLPR()->SendRAdminAllCurrentlyRegisteredServices();
}
else if ( mDeregisterAllData )
{
mDeregisterAllData = false;
LOG( SLP_LOG_NOTIFICATIONS, "SLPRAdminNotifier deregistering all services" );
SLPRegistrar::TheSLPR()->DeregisterAllServices();
}
else
{
QueueLock();
if ( mNotificationsQueue && ::CFArrayGetCount( mNotificationsQueue ) > 0 )
{
notification = (NotificationObject*)::CFArrayGetValueAtIndex( mNotificationsQueue, 0 ); ::CFArrayRemoveValueAtIndex( mNotificationsQueue, 0 );
QueueUnlock();
}
else
{
QueueUnlock();
SmartSleep(1*USEC_PER_SEC);
}
if ( notification )
{
SLP_LOG( SLP_LOG_NOTIFICATIONS, "SLPRAdminNotifier Sending %s Notification to ServerAdmin", PrintableHeaderType(notification->data) );
SendNotification( notification );
delete notification;
notification = NULL;
}
}
}
return NULL;
}
void SLPRAdminNotifier::AddNotificationToQueue( char* buffer, UInt32 bufSize )
{
NotificationObject* newNotification = new NotificationObject( buffer, bufSize );
QueueLock();
if ( mNotificationsQueue )
{
::CFArrayAppendValue( mNotificationsQueue, newNotification );
SLP_LOG( SLP_LOG_DEBUG, "Notification Added to Queue" );
}
QueueUnlock();
}
void SLPRAdminNotifier::RepostAllRegisteredData( void )
{
ClearQueue();
RepostAllData();
}
void SLPRAdminNotifier::DeregisterAllRegisteredData( void )
{
DeregisterAllData();
}
void SLPRAdminNotifier::SendNotification( NotificationObject* notification )
{
char* ignoreReply = NULL;
UInt32 ignoreReplyLen = 0;
OSStatus status = noErr;
status = SendDataToSLPRAdmin( notification->data, notification->dataLen, &ignoreReply, &ignoreReplyLen );
if ( ignoreReply && ((SLPdMessageHeader*)ignoreReply)->messageStatus == kSLPTurnOffRAdminNotifications )
SLPRegistrar::TheSLPR()->DisableRAdminNotification();
if ( ignoreReply )
free( ignoreReply );
if ( status )
{
SLP_LOG( SLP_LOG_DROP, "Error notifing ServerAdmin of Service Change: %s", strerror(status) );
}
}
#pragma mark -
void AddToServiceReply( Boolean usingTCP, ServiceInfo* serviceInfo, char* requestHeader, UInt16 length, SLPInternalError& error, char** replyPtr )
{
#pragma unused( length)
char* siURL = NULL;
UInt16 siURLLen = 0;
char* newReply = NULL;
char* curPtr = NULL;
char* newReplyTemp = *replyPtr;
UInt32 replyLength, newReplyLength;
UInt16 xid;
if ( newReplyTemp == NULL )
{
if ( requestHeader )
replyLength = GETHEADERLEN(requestHeader)+4;
else
replyLength = HDRLEN+2+4;
newReplyTemp = (char*)malloc( replyLength );
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( newReplyTemp );
#endif
if ( !newReplyTemp )
return;
if ( requestHeader )
xid = GETXID( requestHeader );
else
xid = 0;
SETVER( newReplyTemp, SLP_VER );
SETFUN( newReplyTemp, SRVRPLY );
SETLEN( newReplyTemp, replyLength );
SETFLAGS( newReplyTemp, 0 );
SETXID( newReplyTemp, xid );
ServiceLocationHeader* header = (ServiceLocationHeader*)newReplyTemp;
*((UInt16*)&(header->byte13)) = 2;
*((UInt16*)&(header->byte15)) = *((UInt16*)"en");
*((UInt16*)(newReplyTemp+GETHEADERLEN(newReplyTemp))) = error; *((UInt16*)((char*)newReplyTemp+GETHEADERLEN(newReplyTemp)+2)) = 0; }
replyLength = GETLEN(newReplyTemp);
if ( serviceInfo )
{
siURL = serviceInfo->GetURLPtr();
siURLLen = strlen(siURL);
}
if ( serviceInfo )
{
UInt16 urlEntryLength = 1 + 2 + 2 + siURLLen + 1;
newReplyLength = replyLength + urlEntryLength;
}
else
newReplyLength = replyLength;
if ( newReplyLength > MAX_REPLY_LENGTH )
{
SLP_LOG( SLP_LOG_MSG, "Size of reply exceeds maximum allowed by SLP, some services will be ignored." );
return;
}
if ( !usingTCP )
{
char* endPtr = NULL;
if ( newReplyLength > (UInt32)strtol(SLPGetProperty("net.slp.MTU"),&endPtr,10) )
{
SETFLAGS(newReplyTemp, OVERFLOWFLAG);
error = SLP_REPLY_TOO_BIG_FOR_PROTOCOL;
return;
}
}
curPtr = newReplyTemp + GETHEADERLEN(newReplyTemp);
*((UInt16*)curPtr) = (UInt16)error;
curPtr += 2;
if ( !serviceInfo )
{
*((UInt16*)curPtr) = 0;
(*replyPtr) = newReplyTemp;
}
else
{
*((UInt16*)curPtr) += 1;
newReply = (char*)malloc( newReplyLength );
#ifdef USE_EXCEPTIONS
ThrowIfNULL_( newReply );
#endif
if (!newReply )
return;
::memcpy( newReply, newReplyTemp, replyLength );
free( newReplyTemp );
curPtr = newReply+replyLength;
*curPtr = 0; curPtr++;
*((UInt16*)curPtr) = serviceInfo->GetLifeTime(); curPtr += 2;
*((UInt16*)curPtr) = siURLLen; curPtr += 2;
if ( siURL )
::memcpy( curPtr, siURL, siURLLen );
curPtr += siURLLen;
*curPtr = 0;
SETLEN(newReply, newReplyLength);
(*replyPtr) = newReply;
}
}
#endif //#ifdef USE_SLPREGISTRAR