/*++ Copyright (c) 1994 Microsoft Corporation Module Name: svcinfo.cxx Abstract: contains class implementation of service location classes. Author: Madan Appiah (madana) 15-May-1995 Environment: User Mode - Win32 Revision History: --*/ #include DWORD EMBED_SERVICE_INFO::ComputeServiceInfoSize( LPINET_SERVICE_INFO ServiceInfo ) /*++ Routine Description: This private member function computes the size of the embedded service info buffer. Arguments: ServiceInfo : pointer to a service info structure. Return Value: size of the embedded service info buffer. --*/ { DWORD Size; DWORD NumBindings; LPINET_BIND_INFO BindingsInfo; DWORD i; DWORD ServiceCommentLen; if( ServiceInfo->ServiceComment != NULL) { ServiceCommentLen = ROUND_UP_COUNT( (strlen(ServiceInfo->ServiceComment) + 1) * sizeof(CHAR), ALIGN_DWORD); } else { ServiceCommentLen = ROUND_UP_COUNT( 1, ALIGN_DWORD ); } Size = sizeof(ULONGLONG) + // service mask sizeof(INET_SERVICE_STATE) + // service state ServiceCommentLen + // service comment sizeof(DWORD); // NumBindings NumBindings = ServiceInfo->Bindings.NumBindings; BindingsInfo = ServiceInfo->Bindings.BindingsInfo; if( NumBindings != 0 ) { TcpsvcsDbgAssert( BindingsInfo != NULL ) for( i = 0; i < NumBindings; i++ ) { Size += sizeof(DWORD); if( BindingsInfo[i].Length != 0 ) { Size += ROUND_UP_COUNT(BindingsInfo[i].Length, ALIGN_DWORD); TcpsvcsDbgAssert( BindingsInfo[i].BindData != NULL ); } } } return( Size ); } VOID EMBED_SERVICE_INFO::CopyServiceInfo( LPINET_SERVICE_INFO ServiceInfo ) /*++ Routine Description: This private member function copies service info to the embedded service info buffer. Arguments: ServiceInfo : pointer to a service info structure. Return Value: NONE. --*/ { DWORD NumBindings; LPINET_BIND_INFO BindingsInfo; DWORD i; LPBYTE EndofBuffer; LPBYTE BufferPtr; NumBindings = ServiceInfo->Bindings.NumBindings; BindingsInfo = ServiceInfo->Bindings.BindingsInfo; BufferPtr = _ServiceInfoBuffer; EndofBuffer = _ServiceInfoBuffer + _ServiceInfoLength; // // copy header. // *(ULONGLONG UNALIGNED *)BufferPtr = ServiceInfo->ServiceMask; _ServiceMask = (ULONGLONG UNALIGNED *)BufferPtr; BufferPtr += sizeof(ULONGLONG); *(INET_SERVICE_STATE *)BufferPtr = ServiceInfo->ServiceState; _ServiceState = (INET_SERVICE_STATE *)BufferPtr; BufferPtr += sizeof(INET_SERVICE_STATE); // // copy service comment. // DWORD CommentLen; if( ServiceInfo->ServiceComment != NULL) { CommentLen = ROUND_UP_COUNT( (strlen(ServiceInfo->ServiceComment) + 1) * sizeof(CHAR), ALIGN_DWORD); } else { CommentLen = ROUND_UP_COUNT( 1, ALIGN_DWORD ); } TcpsvcsDbgAssert( (BufferPtr + CommentLen) < EndofBuffer ); if( ServiceInfo->ServiceComment != NULL) { strcpy( (LPSTR)BufferPtr, ServiceInfo->ServiceComment ); } else { *(LPSTR)BufferPtr = '\0'; } BufferPtr += CommentLen; *(DWORD *)BufferPtr = ServiceInfo->Bindings.NumBindings; BufferPtr += sizeof(DWORD); // // copy bindings. // if( NumBindings != 0 ) { for( i = 0; i < NumBindings; i++ ) { TcpsvcsDbgAssert( BufferPtr < EndofBuffer ); *(DWORD *)BufferPtr = BindingsInfo[i].Length; BufferPtr += sizeof(DWORD); if( BindingsInfo[i].Length != 0 ) { memcpy( BufferPtr, BindingsInfo[i].BindData, BindingsInfo[i].Length ); BufferPtr += ROUND_UP_COUNT( BindingsInfo[i].Length, ALIGN_DWORD ); } } } TcpsvcsDbgAssert( BufferPtr == EndofBuffer ); return; } EMBED_SERVICE_INFO::EMBED_SERVICE_INFO( LPINET_SERVICE_INFO ServiceInfo ) /*++ Routine Description: This function constructs an embedded service info object. Note : embedded service info buffer layout : dword 1 : ServiceMask 2 : ServiceState 3 : NumBindings 4 : Binding1 Length 5 : Binding1 6 : .. 7 : .. 8 : .. 9 : Binding2 Length 10 : Binding2 11 : .. 12 : .. Arguments: ServiceInfo : pointer to a service info structure. Return Value: NONE. --*/ { DWORD Size; // // initialize the object elements. // INITIALIZE_CRITICAL_SECTION( &_ServiceObjCritSect ); _ServiceInfoLength = 0; _ServiceInfoBuffer = NULL; _AllottedBufferSize = 0; _ServiceState = NULL; _ServiceComment = NULL; _ServiceMask = NULL; TcpsvcsDbgAssert( ServiceInfo != NULL ); if( ServiceInfo == NULL ) { _Status = ERROR_INVALID_PARAMETER; return; } // // compute the embedded buffer length. // Size = ComputeServiceInfoSize( ServiceInfo ); TcpsvcsDbgAssert( Size != 0 ); // // allocate memory. // _ServiceInfoBuffer = (LPBYTE) SvclocHeap->Alloc( Size ); if( _ServiceInfoBuffer == NULL ) { _Status = ERROR_NOT_ENOUGH_MEMORY; return; } _ServiceInfoLength = Size; _AllottedBufferSize = Size; // // copy service info. // CopyServiceInfo( ServiceInfo ); _Status = ERROR_SUCCESS; return; } EMBED_SERVICE_INFO::EMBED_SERVICE_INFO( LPBYTE InfoBuffer, DWORD InfoBufferLength ) /*++ Routine Description: This function constructs an embedded service info object from a given embedded buffer. Arguments: InfoBuffer : pointer to a embedded buffer. InfoBufferLength : length of the embedded buffer. Return Value: NONE. --*/ { TcpsvcsDbgAssert( InfoBuffer != NULL ); TcpsvcsDbgAssert( InfoBufferLength != 0 ); INITIALIZE_CRITICAL_SECTION( &_ServiceObjCritSect ); _ServiceInfoLength = InfoBufferLength; _ServiceInfoBuffer = InfoBuffer; _AllottedBufferSize = 0; _ServiceMask = (ULONGLONG UNALIGNED *)InfoBuffer; _ServiceState = (INET_SERVICE_STATE *)(InfoBuffer + sizeof(ULONGLONG)); _ServiceComment = (LPSTR) (InfoBuffer + sizeof(ULONGLONG) + sizeof(INET_SERVICE_STATE) ); _Status = ERROR_SUCCESS; } EMBED_SERVICE_INFO::~EMBED_SERVICE_INFO( VOID ) /*++ Routine Description: This function destructs a embedded service info object. Arguments: NONE. Return Value: NONE. --*/ { if( _AllottedBufferSize != 0 ) { TcpsvcsDbgAssert( _ServiceInfoBuffer != NULL ); SvclocHeap->Free( _ServiceInfoBuffer ); } #if DBG _ServiceInfoLength = 0; _ServiceInfoBuffer = NULL; _AllottedBufferSize = 0; _ServiceState = NULL; _ServiceComment = NULL; _ServiceMask = NULL; #endif // DBG DeleteCriticalSection( &_ServiceObjCritSect ); _Status = ERROR_SUCCESS; return; } DWORD EMBED_SERVICE_INFO::SetServiceInfo( LPINET_SERVICE_INFO ServiceInfo ) /*++ Routine Description: This member function sets the new service info to the embedded service info buffer. Arguments: ServiceInfo : pointer to a service info structure. Return Value: Windows error code. --*/ { DWORD Size; TcpsvcsDbgAssert( ServiceInfo != NULL ); LockServiceObj(); if( ServiceInfo == NULL ) { UnlockServiceObj(); return( ERROR_INVALID_PARAMETER ); } // // compute the size of the new service info buffer. // Size = ComputeServiceInfoSize( ServiceInfo ) ; TcpsvcsDbgAssert( Size != 0 ); if( Size > _AllottedBufferSize ) { LPBYTE NewServiceInfoBuffer; // // free the old buffer and reallocate a new one. // NewServiceInfoBuffer = (LPBYTE) SvclocHeap->Alloc( Size ); if( NewServiceInfoBuffer == NULL ) { UnlockServiceObj(); return( ERROR_NOT_ENOUGH_MEMORY ); } SvclocHeap->Free( _ServiceInfoBuffer ); _ServiceInfoBuffer = NewServiceInfoBuffer; _AllottedBufferSize = Size; } _ServiceInfoLength = Size; // // now copy buffer. // CopyServiceInfo( ServiceInfo ); UnlockServiceObj(); return( ERROR_SUCCESS ); } DWORD EMBED_SERVICE_INFO::GetServiceInfo( LPINET_SERVICE_INFO *ServiceInfo ) /*++ Routine Description: This member function allocates memory for service info structure and copies service info from embedded service info buffer. Arguments: ServiceInfo : pointer to a location where the server info structure pointer is returned. The caller should free the structure after use. Return Value: Windows error code. --*/ { DWORD Error; LPBYTE BufferPtr = _ServiceInfoBuffer; LPBYTE EndBufferPtr = _ServiceInfoBuffer + _ServiceInfoLength; DWORD NumBindings; DWORD i; LPINET_SERVICE_INFO LocalServiceInfo = NULL; LockServiceObj(); // // allocate memory for the service info structure. // LocalServiceInfo = (LPINET_SERVICE_INFO) SvclocHeap->Alloc( sizeof( INET_SERVICE_INFO ) ); if( LocalServiceInfo == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // copy main structure first. // LocalServiceInfo->ServiceMask = *(ULONGLONG UNALIGNED *)BufferPtr; BufferPtr += sizeof(ULONGLONG); LocalServiceInfo->ServiceState = *(INET_SERVICE_STATE *)BufferPtr; BufferPtr += sizeof(INET_SERVICE_STATE); // // allocate memory for the service comment. // DWORD CommentLen; CommentLen = ROUND_UP_COUNT( (strlen((LPSTR)BufferPtr) + 1) * sizeof(CHAR), ALIGN_DWORD ); LocalServiceInfo->ServiceComment = (LPSTR) SvclocHeap->Alloc( CommentLen ); if( LocalServiceInfo->ServiceComment == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // copy service comment. // strcpy( LocalServiceInfo->ServiceComment, (LPSTR)BufferPtr ); BufferPtr += CommentLen; NumBindings = *(DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); LocalServiceInfo->Bindings.NumBindings = 0; LocalServiceInfo->Bindings.BindingsInfo = NULL; if( NumBindings != 0 ) { LPINET_BIND_INFO Bindings; // // allocate memory for bindingsinfo array. // Bindings = (LPINET_BIND_INFO) SvclocHeap->Alloc( sizeof( INET_BIND_INFO ) * NumBindings ); if( Bindings == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } LocalServiceInfo->Bindings.BindingsInfo = Bindings; for( i = 0; i < NumBindings; i++ ) { LPBYTE BindData; TcpsvcsDbgAssert( BufferPtr < EndBufferPtr ); Bindings[i].Length = *(DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); // // allocate memory for the bind data. // BindData = (LPBYTE)SvclocHeap->Alloc( Bindings[i].Length ); if( BindData == NULL ) { // // free the bindings structure memory only if NumBindings // is zero, otherwise it will be freed later on along // with some other memory blocks. // if( LocalServiceInfo->Bindings.NumBindings == 0 ) { if( LocalServiceInfo->Bindings.BindingsInfo != NULL ) { SvclocHeap->Free( LocalServiceInfo->Bindings.BindingsInfo ); LocalServiceInfo->Bindings.BindingsInfo = NULL; } } Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // copy bind data. // memcpy( BindData, BufferPtr, Bindings[i].Length ); BufferPtr += ROUND_UP_COUNT( Bindings[i].Length, ALIGN_DWORD ); // // successfully copied one more bind data. // Bindings[i].BindData = BindData; LocalServiceInfo->Bindings.NumBindings++; } } // // all done. // *ServiceInfo = LocalServiceInfo; LocalServiceInfo = NULL; Error = ERROR_SUCCESS; Cleanup: if( LocalServiceInfo != NULL ) { FreeServiceInfo( LocalServiceInfo ); } UnlockServiceObj(); return( Error ); } /*---------------------------------------------------------------------*/ BOOL EMBED_SERVER_INFO::IsServiceEntryExist( ULONGLONG ServiceMask, LPEMBED_SERVICE_ENTRY *ServiceEntry ) /*++ Routine Description: This private member function looks up a service entry in the service list. Arguments: ServiceMask : mask of the service to look at. ServiceEntry : pointer to location where the service entry pointer is returned if found. Return Value: TRUE : if the service entry is found in the service list. FALSE : otherwise. --*/ { PLIST_ENTRY SList; LPEMBED_SERVICE_ENTRY SEntry; ULONGLONG SMask; // // Scan service list. // for( SList = _ServicesList.Flink; SList != &_ServicesList; SList = SList->Flink ) { SEntry = (LPEMBED_SERVICE_ENTRY)SList; // // Get Service Mask. // SMask = (SEntry->ServiceObject)->GetServiceMask(); if( SMask == ServiceMask ) { // // found the service entry. // *ServiceEntry = SEntry; return( TRUE ); } } return( FALSE ); } EMBED_SERVER_INFO::EMBED_SERVER_INFO( WORD MajorVersion, WORD MinorVersion, LPSTR ServerName ) /*++ Routine Description: This member function constructs a server info object. Arguments: MajorVersion : major version number of the server software. MinorVersion : minor version number of the server software. ServerName : computer name of the server. Return Value: None. --*/ { DWORD Size; LPBYTE BufferPtr; DWORD ServerNameLen; // // init object fields. // INITIALIZE_CRITICAL_SECTION( &_ServerObjCritSect ); _ServerInfoLength = 0; _ServerInfoBuffer = NULL; _AllottedBufferSize = 0; _VersionNum = NULL; _ServerLoad = NULL; _ServicesMask = NULL; _ServerName = NULL; _NumServices = NULL; InitializeListHead( &_ServicesList ); // // compute Server Info Size. // ServerNameLen = ROUND_UP_COUNT( (strlen(ServerName) + 1) * sizeof(CHAR), ALIGN_DWORD); Size = sizeof(INET_VERSION_NUM) + // for version number ServerNameLen + // for server name sizeof(DWORD) + // for load factor sizeof(ULONGLONG) + // for services mask. sizeof(DWORD); // for number of services. _ServerInfoBuffer = (LPBYTE)SvclocHeap->Alloc( Size ); if( _ServerInfoBuffer == NULL ) { _Status = ERROR_NOT_ENOUGH_MEMORY; return; } _ServerInfoLength = Size; _AllottedBufferSize = Size; BufferPtr = _ServerInfoBuffer; ((INET_VERSION_NUM *)BufferPtr)->Version.Major = MajorVersion; ((INET_VERSION_NUM *)BufferPtr)->Version.Minor = MinorVersion; _VersionNum = (INET_VERSION_NUM *)BufferPtr; BufferPtr += sizeof(INET_VERSION_NUM); strcpy( (LPSTR)BufferPtr, ServerName ); _ServerName = (LPSTR)BufferPtr; BufferPtr += ServerNameLen; *(DWORD *)BufferPtr = 0; // load factor _ServerLoad = (DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); *(ULONGLONG UNALIGNED *)BufferPtr = 0; // services mask; _ServicesMask = (ULONGLONG UNALIGNED *)BufferPtr; BufferPtr += sizeof(ULONGLONG); *(DWORD *)BufferPtr = 0; // num services. _NumServices = (DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); TcpsvcsDbgAssert( BufferPtr == (_ServerInfoBuffer + _ServerInfoLength) ); _Status = ERROR_SUCCESS; return; } EMBED_SERVER_INFO::EMBED_SERVER_INFO( LPBYTE ResponseBuffer, DWORD ResponseBufferLength ) /*++ Routine Description: This member function constructs a server info object from embedded server info buffer (received from the server). Arguments: ResponseBuffer : pointer to the embedded server info buffer. ResponseBufferLength : length of the above buffer. Return Value: --*/ { LPBYTE BufferPtr; DWORD ServerNameLen; DWORD nServices; DWORD i; INITIALIZE_CRITICAL_SECTION( &_ServerObjCritSect ); // // set object fields. // BufferPtr = _ServerInfoBuffer = ResponseBuffer; _VersionNum = (INET_VERSION_NUM *)BufferPtr; BufferPtr += sizeof(INET_VERSION_NUM); // skip version number. _ServerName = (LPSTR)BufferPtr; ServerNameLen = ROUND_UP_COUNT( (strlen((LPSTR)BufferPtr) + 1) * sizeof(CHAR), ALIGN_DWORD); BufferPtr += ServerNameLen; _ServerLoad = (DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); _ServicesMask = (ULONGLONG UNALIGNED *)BufferPtr; BufferPtr += sizeof(ULONGLONG); _NumServices = (DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); _ServerInfoLength = DIFF(BufferPtr - _ServerInfoBuffer); _AllottedBufferSize = 0; nServices = *_NumServices; InitializeListHead( &_ServicesList ); // // now make service objects. // for( i = 0; i < nServices; i++) { DWORD ServiceBufferLength; LPSERVICE_OBJECT ServiceObject; DWORD ObjStatus; LPEMBED_SERVICE_ENTRY ServiceEntry; ServiceBufferLength = *(DWORD * )BufferPtr; BufferPtr += sizeof(DWORD); // // make another service object. // ServiceObject = new EMBED_SERVICE_INFO( BufferPtr, ServiceBufferLength ); if( ServiceObject == NULL ) { _Status = ERROR_NOT_ENOUGH_MEMORY; return; } ObjStatus = ServiceObject->GetStatus(); if( ObjStatus != ERROR_SUCCESS ) { _Status = ObjStatus; delete ServiceObject; return; } // // allocate space for a new service entry. // ServiceEntry = (LPEMBED_SERVICE_ENTRY) SvclocHeap->Alloc( sizeof(EMBED_SERVICE_ENTRY) ); if( ServiceEntry == NULL ) { _Status = ERROR_NOT_ENOUGH_MEMORY; delete ServiceObject; return; } ServiceEntry->ServiceObject = ServiceObject; // // add this new entry to the list. // InsertTailList( &_ServicesList, &ServiceEntry->NextEntry ); // // point to the next service record. // BufferPtr += ServiceBufferLength; } _Status = ERROR_SUCCESS; return; } EMBED_SERVER_INFO::~EMBED_SERVER_INFO( VOID ) /*++ Routine Description: This member function destructs a server info object. Arguments: NONE. Return Value: NONE. --*/ { // // delete all service objects first. // while( !IsListEmpty( &_ServicesList ) ) { LPEMBED_SERVICE_ENTRY ServiceEntry; // // remove an entry from the tail of the list. // ServiceEntry = (LPEMBED_SERVICE_ENTRY)RemoveTailList( &_ServicesList ); // // delete service object. // delete ServiceEntry->ServiceObject; // // free the entry memory. // SvclocHeap->Free( ServiceEntry ); } // // free up server info buffer. // if( _AllottedBufferSize != 0 ) { TcpsvcsDbgAssert( _ServerInfoBuffer != NULL ); SvclocHeap->Free( _ServerInfoBuffer ); } #if DBG _ServerInfoLength = 0; _ServerInfoBuffer = NULL; _AllottedBufferSize = 0; _VersionNum = NULL; _ServerLoad = NULL; _ServicesMask = NULL; _ServerName = NULL; _NumServices = NULL; #endif // DBG DeleteCriticalSection( &_ServerObjCritSect ); _Status = ERROR_SUCCESS; return; } DWORD EMBED_SERVER_INFO::AddService ( LPINET_SERVICE_INFO ServiceInfo ) /*++ Routine Description: This member function adds or replaces a service info object to the server info object. Arguments: ServiceInfo : pointer to the service info structure. Return Value: Windows Error Code. --*/ { DWORD Error; LPSERVICE_OBJECT ServiceObj; LPEMBED_SERVICE_ENTRY ServiceEntry = NULL; ULONGLONG SMask; LockServerObj(); SMask = ServiceInfo->ServiceMask; if( IsServiceEntryExist( SMask, &ServiceEntry ) ) { // // this service already exists, so just update the content. // TcpsvcsDbgAssert( ServiceEntry != NULL ); TcpsvcsDbgAssert( (*_ServicesMask & SMask) == SMask ); // // set service info. // Error = (ServiceEntry->ServiceObject)->SetServiceInfo( ServiceInfo ); UnlockServerObj(); return( Error ); } // // new entry. // TcpsvcsDbgAssert( (*_ServicesMask & SMask) == 0 ); // // make a service object. // ServiceObj = new EMBED_SERVICE_INFO( ServiceInfo ); if( ServiceObj == NULL ) { UnlockServerObj(); return( ERROR_NOT_ENOUGH_MEMORY ); } Error = ServiceObj->GetStatus(); if( Error != ERROR_SUCCESS ) { delete ServiceObj; UnlockServerObj(); return( Error ); } // // allocate memory for the new service entry. // ServiceEntry = (LPEMBED_SERVICE_ENTRY) SvclocHeap->Alloc( sizeof(EMBED_SERVICE_ENTRY) ); if( ServiceEntry == NULL ) { delete ServiceObj; UnlockServerObj(); return( ERROR_NOT_ENOUGH_MEMORY ); } ServiceEntry->ServiceObject = ServiceObj; // // Adjust parameters. // *_ServicesMask |= SMask; (*_NumServices)++; // // add this entry to the service list. // InsertTailList(&_ServicesList, &ServiceEntry->NextEntry); UnlockServerObj(); return( ERROR_SUCCESS ); } DWORD EMBED_SERVER_INFO::RemoveService( ULONGLONG SMask ) /*++ Routine Description: This member function removes a service info object from the server info object. Arguments: SMask : Service mask of the service to be removed from the server object. Return Value: Windows Error Code. --*/ { LPEMBED_SERVICE_ENTRY ServiceEntry = NULL; LockServerObj(); // // check the service is in the service list. // if( IsServiceEntryExist( SMask, &ServiceEntry ) == FALSE ) { TcpsvcsDbgAssert( (*_ServicesMask & SMask) == 0); UnlockServerObj(); return( ERROR_SERVICE_NOT_FOUND ); } TcpsvcsDbgAssert( ServiceEntry != NULL ); TcpsvcsDbgAssert( *_ServicesMask & SMask ); // // adjust parameters. // *_ServicesMask &= ~SMask; (*_NumServices)--; // // remove entry from list. // RemoveEntryList( &ServiceEntry->NextEntry ); // // delete service object. // delete ServiceEntry->ServiceObject; // // free entry memory. // SvclocHeap->Free( ServiceEntry ); UnlockServerObj(); return( ERROR_SUCCESS ); } DWORD EMBED_SERVER_INFO::SetServiceState( ULONGLONG SMask, INET_SERVICE_STATE ServiceState ) /*++ Routine Description: This member function sets the state of a service. Arguments: SMask : Service Mask of the service whose state to be set. ServiceState : New state of the service. Return Value: None. --*/ { LPEMBED_SERVICE_ENTRY ServiceEntry = NULL; LockServerObj(); // // check the service is in the service list. // if( IsServiceEntryExist( SMask, &ServiceEntry ) == FALSE ) { TcpsvcsDbgAssert( (*_ServicesMask & SMask) == 0); UnlockServerObj(); return( ERROR_SERVICE_NOT_FOUND ); } TcpsvcsDbgAssert( ServiceEntry != NULL ); TcpsvcsDbgAssert( *_ServicesMask & SMask ); // // set service state. // (ServiceEntry->ServiceObject)->SetServiceState( ServiceState ); UnlockServerObj(); return( ERROR_SUCCESS ); } DWORD EMBED_SERVER_INFO::ComputeResponseLength( VOID ) /*++ Routine Description: This member function computes the length of the response message (containing server info and all services info in the embedded formatted) sent to a client. Arguments: None. Return Value: Length of the response. --*/ { DWORD Size = 0; PLIST_ENTRY SList; LPEMBED_SERVICE_ENTRY SEntry; LockServerObj(); // // Compute response length of the services. // for( SList = _ServicesList.Flink; SList != &_ServicesList; SList = SList->Flink ) { SEntry = (LPEMBED_SERVICE_ENTRY)SList; // // Get Service info buffer size. // Size += (SEntry->ServiceObject)->GetServiceInfoLength(); Size += sizeof(DWORD); // for service length info itself. } // // server info size. // Size += _ServerInfoLength; UnlockServerObj(); return( Size ); } DWORD EMBED_SERVER_INFO::MakeResponseMessage( LPBYTE MessageBuffer, DWORD BufferLength ) /*++ Routine Description: This member function builds a response message sent to a client. Arguments: MessageBuffer : pointer to a buffer where the response message is built. BufferLength : length of the message. Return Value: Windows Error Code. --*/ { LPBYTE BufferPtr = MessageBuffer; LPBYTE EndBufferPtr = MessageBuffer + BufferLength; LPEMBED_SERVICE_ENTRY SEntry; ULONGLONG SMask; DWORD Error; DWORD RequiredBufferLength; PLIST_ENTRY SList; LockServerObj(); RequiredBufferLength = ComputeResponseLength(); if( RequiredBufferLength > BufferLength ) { UnlockServerObj(); return( ERROR_INSUFFICIENT_BUFFER ); } // // copy server info first. // memcpy( BufferPtr, _ServerInfoBuffer, _ServerInfoLength ); BufferPtr += _ServerInfoLength; // // copy all service info buffers. // for( SList = _ServicesList.Flink; SList != &_ServicesList; SList = SList->Flink ) { DWORD *_ServiceInfoLength; TcpsvcsDbgAssert( BufferPtr < EndBufferPtr ); _ServiceInfoLength = (DWORD *)BufferPtr; BufferPtr += sizeof(DWORD); SEntry = (LPEMBED_SERVICE_ENTRY)SList; // // Get Service Mask. // Error = (SEntry->ServiceObject)->GetServiceInfoBuffer( BufferPtr, DIFF(EndBufferPtr - BufferPtr), _ServiceInfoLength ); if( Error != ERROR_SUCCESS ) { UnlockServerObj(); return( Error ); } BufferPtr += *_ServiceInfoLength; } UnlockServerObj(); return( ERROR_SUCCESS ); } DWORD EMBED_SERVER_INFO::GetServerInfo( LPINET_SERVER_INFO *ServerInfo ) /*++ Routine Description: This member function retrieves the server info structure. Arguments: ServerInfo : pointer to a location where the pointer to the server info structure is returned. The member function allots memory for the structure, the caller should free the mmeory after use. Return Value: Windows Error Code. --*/ { DWORD Error; LPINET_SERVER_INFO LocalServerInfo = NULL; LPINET_SERVICE_INFO *ServicesInfoArray = NULL; PLIST_ENTRY SList; DWORD i; LockServerObj(); // // allocate memory for the server info structure. // LocalServerInfo = (LPINET_SERVER_INFO)SvclocHeap->Alloc(sizeof(INET_SERVER_INFO) ); if( LocalServerInfo == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // initialize all fields. // memset( LocalServerInfo, 0x0, sizeof(INET_SERVER_INFO) ); // // fill in the fields. // // // server info field is fill by some one else !! // leave it empty for now. // LocalServerInfo->ServerAddress.Length = 0; LocalServerInfo->ServerAddress.BindData = NULL; LocalServerInfo->VersionNum = *_VersionNum; // // alloc memory for the server name. // LocalServerInfo->ServerName = (LPSTR) SvclocHeap->Alloc( (strlen(_ServerName) + 1) * sizeof(CHAR) ); if( LocalServerInfo->ServerName == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } strcpy( LocalServerInfo->ServerName, _ServerName ); LocalServerInfo->LoadFactor = *_ServerLoad; LocalServerInfo->ServicesMask = *_ServicesMask; LocalServerInfo->Services.NumServices = 0; LocalServerInfo->Services.Services = NULL; // // allocate memory for the service struct. array pointers. // ServicesInfoArray = (LPINET_SERVICE_INFO *) SvclocHeap->Alloc( (*_NumServices) * sizeof(LPINET_SERVICE_INFO ) ); if(ServicesInfoArray == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } memset( ServicesInfoArray, 0x0, (*_NumServices) * sizeof(LPINET_SERVICE_INFO) ); // // now get services info. // for ( SList = _ServicesList.Flink, i = 0; (SList != &_ServicesList) && (i < *_NumServices); SList = SList->Flink, i++ ) { LPSERVICE_OBJECT SObj; SObj = ((LPEMBED_SERVICE_ENTRY)SList)->ServiceObject; Error = SObj->GetServiceInfo( &ServicesInfoArray[i] ); if( Error != ERROR_SUCCESS ) { goto Cleanup; } } TcpsvcsDbgAssert( i <= (*_NumServices) ); LocalServerInfo->Services.NumServices = i; LocalServerInfo->Services.Services = ServicesInfoArray; ServicesInfoArray = NULL; *ServerInfo = LocalServerInfo; LocalServerInfo = NULL; Error = ERROR_SUCCESS; Cleanup: if( Error != ERROR_SUCCESS ) { // // Cleanup allotted data. // if( ServicesInfoArray != NULL ) { for ( i = 0; i < (*_NumServices) && ServicesInfoArray[i] != NULL; i++) { FreeServiceInfo( ServicesInfoArray[i] ); } SvclocHeap->Free( ServicesInfoArray ); } if( LocalServerInfo != NULL ) { if( LocalServerInfo->ServerName != NULL ) { SvclocHeap->Free( LocalServerInfo->ServerName ); } SvclocHeap->Free( LocalServerInfo ); } } UnlockServerObj(); return( Error ); }