1053 lines
24 KiB
C++
1053 lines
24 KiB
C++
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
svcsrv.cxx
|
||
|
||
Abstract:
|
||
|
||
Contains server side code of service location protocol.
|
||
|
||
Author:
|
||
|
||
Madan Appiah (madana) 15-May-1995
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
Sean Woodward (t-seanwo) 26-October-1997 ADSI Update
|
||
|
||
--*/
|
||
|
||
#include <svcloc.hxx>
|
||
|
||
DWORD
|
||
MakeResponseBuffer(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets up the response buffer sent to the client.
|
||
|
||
Arguments:
|
||
|
||
NONE.
|
||
|
||
Return Value:
|
||
|
||
Windows Error Code.
|
||
|
||
--*/
|
||
{
|
||
DWORD ReqMsgLength;
|
||
|
||
//
|
||
// compute space required for all services info and server info.
|
||
//
|
||
|
||
ReqMsgLength = GlobalSrvInfoObj->ComputeResponseLength();
|
||
|
||
//
|
||
// add space for the head and tail.
|
||
//
|
||
|
||
ReqMsgLength += (
|
||
sizeof(DWORD) + // for message length.
|
||
sizeof(DWORD) + // for check sum
|
||
sizeof(DWORD)); // for termination dword.
|
||
|
||
if( ReqMsgLength <= GlobalSrvAllotedRespMsgLen ) {
|
||
|
||
//
|
||
// wipe of previous response buffer content.
|
||
//
|
||
|
||
TcpsvcsDbgAssert(
|
||
GlobalSrvRespMsgLength <=
|
||
GlobalSrvAllotedRespMsgLen );
|
||
|
||
memset( GlobalSrvRespMsg, 0x0, GlobalSrvRespMsgLength );
|
||
GlobalSrvRespMsgLength = ReqMsgLength;
|
||
}
|
||
else {
|
||
|
||
LPBYTE NewBuffer;
|
||
DWORD NewBufferLength;
|
||
|
||
NewBufferLength = (ReqMsgLength & ~(0x400 - 1)) + 0x400;
|
||
// ceil in KBytes
|
||
|
||
NewBuffer = (LPBYTE)SvclocHeap->Alloc( NewBufferLength );
|
||
|
||
if( NewBuffer == NULL ) {
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
//
|
||
// free old buffer.
|
||
//
|
||
|
||
SvclocHeap->Free( GlobalSrvRespMsg );
|
||
GlobalSrvRespMsg = NewBuffer;
|
||
GlobalSrvAllotedRespMsgLen = NewBufferLength;
|
||
GlobalSrvRespMsgLength = ReqMsgLength;
|
||
}
|
||
|
||
//
|
||
// copy server and services info.
|
||
//
|
||
|
||
DWORD Error;
|
||
|
||
Error = GlobalSrvInfoObj->MakeResponseMessage(
|
||
GlobalSrvRespMsg + sizeof(DWORD),
|
||
GlobalSrvRespMsgLength - 3 * sizeof(DWORD) );
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
GlobalSrvRespMsgLength = 0;
|
||
return( Error );
|
||
}
|
||
|
||
*(DWORD *)GlobalSrvRespMsg = GlobalSrvRespMsgLength;
|
||
|
||
LPBYTE EndMessageBuffer;
|
||
|
||
EndMessageBuffer = GlobalSrvRespMsg + GlobalSrvRespMsgLength;
|
||
|
||
//
|
||
// fill in check sum.
|
||
//
|
||
|
||
*(DWORD *)(EndMessageBuffer - 2 * sizeof(DWORD) ) =
|
||
ComputeCheckSum(
|
||
GlobalSrvRespMsg + sizeof(DWORD),
|
||
GlobalSrvRespMsgLength - 3 * sizeof(DWORD) );
|
||
|
||
*(DWORD *)(EndMessageBuffer - sizeof(DWORD) ) = 0xFFFFFFFF;
|
||
|
||
//
|
||
// DONE.
|
||
//
|
||
|
||
return( ERROR_SUCCESS );
|
||
}
|
||
|
||
DWORD
|
||
ServerRegisterAndListen(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function call registers the server and creates a thread to listen
|
||
to the discovery requests. Also it initializes the winsock data structures.
|
||
|
||
ASSUME : global data crit sect is locked.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
Windows Error Code.
|
||
|
||
--*/
|
||
{
|
||
DWORD Error;
|
||
SOCKET IpxSocket;
|
||
int SocketAddressLength;
|
||
|
||
SOCKADDR_IPX IpxSocketAddress;
|
||
SERVICE_INFOA ServiceInfo;
|
||
SERVICE_ADDRESSES ServiceAddresses;
|
||
PSERVICE_ADDRESS ServiceAddr;
|
||
DWORD StatusSetService;
|
||
|
||
CHAR SapSvcName[SAP_SERVICE_NAME_LEN + 1];
|
||
|
||
//
|
||
// init winsock.
|
||
//
|
||
|
||
if ( !GlobalWinsockStarted ) {
|
||
|
||
Error = WSAStartup( WS_VERSION_REQUIRED, &GlobalWinsockStartupData );
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
GlobalWinsockStarted = TRUE;
|
||
}
|
||
|
||
//
|
||
// cleanup global socket array.
|
||
//
|
||
|
||
memset( &GlobalSrvSockets, 0x0, sizeof(GlobalSrvSockets) );
|
||
|
||
//
|
||
// make IPX local socket address.
|
||
//
|
||
|
||
IpxSocket = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
||
|
||
if( IpxSocket == INVALID_SOCKET ) {
|
||
Error = WSAGetLastError();
|
||
goto NBRegister;
|
||
}
|
||
|
||
//
|
||
// make this socket non blocking.
|
||
//
|
||
|
||
DWORD Arg;
|
||
Arg = 1;
|
||
if( (ioctlsocket( IpxSocket, FIONBIO, &Arg )) == SOCKET_ERROR ) {
|
||
|
||
Error = WSAGetLastError();
|
||
closesocket( IpxSocket );
|
||
goto NBRegister;
|
||
}
|
||
|
||
//
|
||
// get socket address.
|
||
//
|
||
|
||
memset( &IpxSocketAddress, 0x0, sizeof(SOCKADDR_IPX) );
|
||
|
||
IpxSocketAddress.sa_family = PF_IPX;
|
||
|
||
if( bind(
|
||
IpxSocket,
|
||
(PSOCKADDR)&IpxSocketAddress,
|
||
sizeof(SOCKADDR_IPX) ) == SOCKET_ERROR ) {
|
||
|
||
Error = WSAGetLastError();
|
||
closesocket( IpxSocket );
|
||
goto NBRegister;
|
||
}
|
||
|
||
//
|
||
// now query address.
|
||
//
|
||
|
||
SocketAddressLength = sizeof( IpxSocketAddress );
|
||
|
||
if( getsockname(
|
||
IpxSocket,
|
||
(PSOCKADDR)&IpxSocketAddress,
|
||
&SocketAddressLength ) == SOCKET_ERROR ) {
|
||
|
||
Error = WSAGetLastError();
|
||
closesocket( IpxSocket );
|
||
goto NBRegister;
|
||
}
|
||
|
||
Error = MakeSapServiceName( SapSvcName, sizeof(SapSvcName) );
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
closesocket( IpxSocket );
|
||
goto NBRegister;
|
||
}
|
||
|
||
//
|
||
// prepare service address.
|
||
//
|
||
|
||
ServiceAddresses.dwAddressCount = 1;
|
||
ServiceAddr = &ServiceAddresses.Addresses[0];
|
||
|
||
ServiceAddr->dwAddressType = PF_IPX;
|
||
ServiceAddr->dwAddressFlags = 0;
|
||
ServiceAddr->dwAddressLength = SocketAddressLength;
|
||
ServiceAddr->dwPrincipalLength = 0;
|
||
ServiceAddr->lpAddress = (LPBYTE)&IpxSocketAddress;
|
||
ServiceAddr->lpPrincipal = NULL;
|
||
|
||
//
|
||
// prepare service info.
|
||
//
|
||
|
||
ServiceInfo.lpServiceType = &GlobalSapGuid;
|
||
ServiceInfo.lpServiceName = SapSvcName;
|
||
ServiceInfo.lpComment = NULL ;
|
||
ServiceInfo.lpLocale = 0;
|
||
ServiceInfo.dwDisplayHint = 0;
|
||
ServiceInfo.dwVersion =
|
||
MAKEWORD( INET_MAJOR_VERSION, INET_MINOR_VERSION ) ;
|
||
ServiceInfo.dwTime = 0; // ??
|
||
ServiceInfo.lpMachineName = GlobalComputerName;
|
||
ServiceInfo.lpServiceAddress = &ServiceAddresses;
|
||
ServiceInfo.ServiceSpecificInfo.pBlobData = 0;
|
||
ServiceInfo.ServiceSpecificInfo.cbSize = 0;
|
||
|
||
//
|
||
// register service info.
|
||
//
|
||
|
||
if( SetServiceA(
|
||
NS_SAP,
|
||
SERVICE_REGISTER,
|
||
0,
|
||
&ServiceInfo,
|
||
0,
|
||
&StatusSetService ) == SOCKET_ERROR ) {
|
||
|
||
Error = WSAGetLastError();
|
||
closesocket( IpxSocket );
|
||
goto NBRegister;
|
||
}
|
||
|
||
if( StatusSetService != ERROR_SUCCESS ) {
|
||
Error = StatusSetService;
|
||
closesocket( IpxSocket );
|
||
goto NBRegister;
|
||
}
|
||
|
||
GlobalRNRRegistered = TRUE;
|
||
|
||
//
|
||
// remember this Ipx socket in our global socket array.
|
||
//
|
||
|
||
FD_SET( IpxSocket, &GlobalSrvSockets );
|
||
Error = ERROR_SUCCESS;
|
||
|
||
NBRegister:
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"Ipx Registration failed, %ld.\n", Error ));
|
||
}
|
||
|
||
//
|
||
// now create sockets for NET BIOS 1C group name and UNIQUE server
|
||
// name.
|
||
//
|
||
|
||
SOCKADDR_NB NB1CSocketAddress;
|
||
SOCKADDR_NB NBUniqueSocketAddress;
|
||
SOCKET NBSocket;
|
||
|
||
memset( &NB1CSocketAddress, 0x0, sizeof(SOCKADDR_NB) );
|
||
NB1CSocketAddress.snb_family = AF_NETBIOS;
|
||
NB1CSocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
|
||
|
||
TcpsvcsDbgAssert(
|
||
sizeof(NB1CSocketAddress.snb_name) >=
|
||
NETBIOS_INET_GROUP_NAME_LEN );
|
||
|
||
memcpy(
|
||
NB1CSocketAddress.snb_name,
|
||
NETBIOS_INET_GROUP_NAME,
|
||
NETBIOS_INET_GROUP_NAME_LEN );
|
||
|
||
memset( &NBUniqueSocketAddress, 0x0, sizeof(SOCKADDR_NB) );
|
||
NBUniqueSocketAddress.snb_family = AF_NETBIOS;
|
||
NBUniqueSocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
|
||
TcpsvcsDbgAssert( GlobalComputerName[0] != '\0' );
|
||
|
||
MakeUniqueServerName(
|
||
(LPBYTE)NBUniqueSocketAddress.snb_name,
|
||
sizeof(NBUniqueSocketAddress.snb_name),
|
||
GlobalComputerName );
|
||
|
||
//
|
||
// enumurate lanas first.
|
||
//
|
||
|
||
LANA_ENUM Lanas;
|
||
|
||
if( GetEnumNBLana( &Lanas ) ) {
|
||
|
||
//
|
||
// try only the lanas that are returned.
|
||
//
|
||
|
||
TcpsvcsDbgAssert( Lanas.length > 0 );
|
||
|
||
DWORD i;
|
||
for( i = 0; i < Lanas.length; i++ ) {
|
||
|
||
//
|
||
// create a socket for this lana to bind with the IC name.
|
||
//
|
||
|
||
if ( MakeNBSocketForLana(
|
||
Lanas.lana[i],
|
||
(PSOCKADDR)&NB1CSocketAddress,
|
||
&NBSocket ) ) {
|
||
|
||
//
|
||
// add the sockets to our global list.
|
||
//
|
||
|
||
FD_SET( NBSocket, &GlobalSrvSockets );
|
||
}
|
||
|
||
//
|
||
// now create a socket for this lana to bind with the unique
|
||
// server name.
|
||
//
|
||
|
||
if ( MakeNBSocketForLana(
|
||
Lanas.lana[i],
|
||
(PSOCKADDR)&NBUniqueSocketAddress,
|
||
&NBSocket ) ) {
|
||
|
||
//
|
||
// add the sockets to our global list.
|
||
//
|
||
|
||
FD_SET( NBSocket, &GlobalSrvSockets );
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
|
||
UCHAR Lana;
|
||
|
||
//
|
||
// try all possible lanas and accept all valid lana sockets.
|
||
//
|
||
|
||
for( Lana = 0; Lana < MAX_LANA ; Lana-- ) {
|
||
|
||
//
|
||
// create a socket for this lana to bind with the IC name.
|
||
//
|
||
|
||
if ( MakeNBSocketForLana(
|
||
Lana,
|
||
(PSOCKADDR)&NB1CSocketAddress,
|
||
&NBSocket ) ) {
|
||
|
||
//
|
||
// add the sockets to our global list.
|
||
//
|
||
|
||
FD_SET( NBSocket, &GlobalSrvSockets );
|
||
}
|
||
|
||
//
|
||
// now create a socket for this lana to bind with the unique
|
||
// server name.
|
||
//
|
||
|
||
if ( MakeNBSocketForLana(
|
||
Lana,
|
||
(PSOCKADDR)&NBUniqueSocketAddress,
|
||
&NBSocket ) ) {
|
||
|
||
//
|
||
// add the sockets to our global list.
|
||
//
|
||
|
||
FD_SET( NBSocket, &GlobalSrvSockets );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// we should have at least one socket to listen on, otherwise,
|
||
// it is an error, return so.
|
||
//
|
||
|
||
if( GlobalSrvSockets.fd_count == 0 ) {
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS, "Failed to get any Lanas, Service locator disabled\n" ));
|
||
Error = ERROR_NO_NETWORK;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// create listen thread.
|
||
//
|
||
|
||
DWORD ThreadId;
|
||
|
||
GlobalSrvListenThreadHandle =
|
||
CreateThread(
|
||
NULL, // default security
|
||
0, // default stack size
|
||
(LPTHREAD_START_ROUTINE)SocketListenThread,
|
||
NULL, // no parameter
|
||
0, // creatation flag, no suspend
|
||
&ThreadId );
|
||
|
||
if( GlobalSrvListenThreadHandle == NULL ) {
|
||
Error = GetLastError();
|
||
goto Cleanup;
|
||
}
|
||
|
||
Error = ERROR_SUCCESS;
|
||
|
||
Cleanup:
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"ServerRegisterAndListen failed, %ld.\n", Error ));
|
||
|
||
//
|
||
// if we are not successful, cleanup
|
||
// before we return.
|
||
//
|
||
|
||
DWORD LocalError;
|
||
|
||
//
|
||
// The routine is expecting the global lock to be taken
|
||
//
|
||
|
||
LOCK_SVC_GLOBAL_DATA();
|
||
|
||
LocalError = ServerDeregisterAndStopListen();
|
||
|
||
UNLOCK_SVC_GLOBAL_DATA();
|
||
|
||
TcpsvcsDbgAssert( LocalError == ERROR_SUCCESS );
|
||
}
|
||
|
||
return( Error );
|
||
}
|
||
|
||
DWORD
|
||
ProcessSvclocQuery(
|
||
SOCKET ReceivedSocket,
|
||
LPBYTE ReceivedMessage,
|
||
DWORD ReceivedMessageLength,
|
||
struct sockaddr *SourcesAddress,
|
||
DWORD SourcesAddressLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function processes the query message and sends response to the
|
||
query.
|
||
|
||
The query message format.
|
||
|
||
1st DWORD : message length.
|
||
2nd DWORD : message version.
|
||
3rd DWORD : services mask the client interested in.
|
||
4th DWORD : client name
|
||
..
|
||
..
|
||
|
||
Last but one DWORD : check sum.
|
||
LAST DWORD : terminating DWORD 0xFFFFFFFF
|
||
|
||
Arguments:
|
||
|
||
ReceivedMessage - pointer to a message buffer.
|
||
|
||
ReceivedMessageLength - length of the above message.
|
||
|
||
SourcesAddress - address of the sender.
|
||
|
||
SourcesAddressLength - length of the above address.
|
||
|
||
Return Value:
|
||
|
||
Windows Error Code.
|
||
|
||
--*/
|
||
{
|
||
DWORD Error;
|
||
LPBYTE MessagePtr;
|
||
LPBYTE MessageEndPtr;
|
||
|
||
MessagePtr = ReceivedMessage;
|
||
MessageEndPtr = ReceivedMessage + ReceivedMessageLength;
|
||
|
||
//
|
||
// message length should be multiple of sizeof(DWORD).
|
||
//
|
||
|
||
if( ReceivedMessageLength % sizeof(DWORD) != 0 ) {
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
//
|
||
// message length should match.
|
||
//
|
||
|
||
DWORD MsgLength;
|
||
|
||
MsgLength = *(DWORD *)MessagePtr;
|
||
MessagePtr += sizeof(DWORD);
|
||
|
||
if( MsgLength != ReceivedMessageLength ) {
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
//
|
||
// message should terminate with 0xFFFFFFFF
|
||
//
|
||
|
||
if( *(DWORD *)(MessageEndPtr - sizeof(DWORD)) != 0xFFFFFFFF ) {
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
//
|
||
// verify checksum.
|
||
//
|
||
|
||
DWORD CheckSum;
|
||
|
||
CheckSum = ComputeCheckSum(
|
||
ReceivedMessage + sizeof(DWORD),
|
||
ReceivedMessageLength - (3 * sizeof(DWORD)) );
|
||
|
||
if( CheckSum != *(DWORD *)(MessageEndPtr - 2 * sizeof(DWORD)) ) {
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
#if 0
|
||
|
||
// IIS5.0: We want to respond to all server discovery messages
|
||
// since it is potentially useful to clients to find all versions
|
||
// of IIS. The server will send back a message specifying it's
|
||
// own version number and it is up to the client to determine
|
||
// if they want this server's information.
|
||
|
||
//
|
||
// validate version number.
|
||
//
|
||
|
||
INET_VERSION_NUM VersionNumber;
|
||
|
||
VersionNumber.VersionNumber = *(DWORD *)MessagePtr;
|
||
MessagePtr += sizeof(DWORD);
|
||
|
||
if( (VersionNumber.Version.Major != INET_MAJOR_VERSION) ||
|
||
(VersionNumber.Version.Minor != INET_MINOR_VERSION) ) {
|
||
|
||
//
|
||
// in future, we can apply different logic to reject messages with
|
||
// differnet version number.
|
||
//
|
||
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// get services mask.
|
||
//
|
||
|
||
ULONGLONG ServicesMask;
|
||
|
||
ServicesMask = *(ULONGLONG *)MessagePtr;
|
||
MessagePtr += sizeof(ULONGLONG);
|
||
|
||
//
|
||
// if we aren't supporting any of the clients requested services,
|
||
// ignore these message.
|
||
//
|
||
|
||
if( (ServicesMask & GlobalSrvInfoObj->GetServicesMask()) == 0) {
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
//
|
||
// retrieve the computer name from the message. currently
|
||
// it has been used just for debugging purpose. It can be used for
|
||
// something else in future.
|
||
//
|
||
|
||
LPSTR ClientComputerName;
|
||
LPSTR ComputerNamePtr;
|
||
|
||
ClientComputerName = (LPSTR)MessagePtr;
|
||
|
||
//
|
||
// validate computer name.
|
||
//
|
||
|
||
ComputerNamePtr = ClientComputerName;
|
||
while( (*ComputerNamePtr != '\0') &&
|
||
((LPBYTE)ComputerNamePtr < MessageEndPtr) ) {
|
||
ComputerNamePtr++;
|
||
}
|
||
|
||
if( (LPBYTE)ComputerNamePtr >= MessageEndPtr ) {
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
TcpsvcsDbgPrint((
|
||
DEBUG_SVCLOC_MESSAGE,
|
||
"Received a valid discovery message from, %ws.\n",
|
||
ClientComputerName ));
|
||
|
||
//
|
||
// send response message to client.
|
||
//
|
||
|
||
LOCK_SVC_GLOBAL_DATA();
|
||
|
||
TcpsvcsDbgAssert( GlobalSrvRespMsgLength != 0 );
|
||
|
||
if( GlobalSrvRespMsgLength != 0 ) {
|
||
Error = sendto(
|
||
ReceivedSocket,
|
||
(LPCSTR)GlobalSrvRespMsg,
|
||
GlobalSrvRespMsgLength,
|
||
0,
|
||
SourcesAddress,
|
||
SourcesAddressLength );
|
||
|
||
|
||
if( Error == SOCKET_ERROR ) {
|
||
|
||
Error = WSAGetLastError();
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS, "sendto failed, %ld.\n", Error ));
|
||
}
|
||
else {
|
||
Error = ERROR_SUCCESS;
|
||
}
|
||
}
|
||
else {
|
||
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"GlobalSrvRespMsgLength is zero.\n" ));
|
||
Error = ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
UNLOCK_SVC_GLOBAL_DATA();
|
||
return( Error );
|
||
}
|
||
|
||
VOID
|
||
SocketListenThread(
|
||
LPVOID Parameter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the main thread for the service location protocol. It
|
||
receives messages that arrive from all sockets (that have
|
||
been established by the ServerRegisterAndListen call) and response to
|
||
each of the messages. This thread will stop when all sockets are
|
||
closed by the ServerDeregisterAndStopListen call.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
|
||
fd_set ReadSockets;
|
||
int NumReadySockets;
|
||
DWORD Error;
|
||
BOOL BoolError;
|
||
|
||
//
|
||
// increase the priority of this thread, so that it could handle as
|
||
// many discovery queries as possible.
|
||
//
|
||
|
||
BoolError = SetThreadPriority(
|
||
GetCurrentThread(),
|
||
THREAD_PRIORITY_ABOVE_NORMAL );
|
||
|
||
if(BoolError) {
|
||
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"SetThreadPriority, %ld.\n", GetLastError() ));
|
||
}
|
||
|
||
for( ;; ) {
|
||
|
||
//
|
||
// COMMENT
|
||
// select on all above sockets.
|
||
//
|
||
|
||
//
|
||
// copy all sockets.
|
||
//
|
||
|
||
LOCK_SVC_GLOBAL_DATA();
|
||
memcpy(&ReadSockets, &GlobalSrvSockets, sizeof(GlobalSrvSockets));
|
||
UNLOCK_SVC_GLOBAL_DATA();
|
||
|
||
//
|
||
// do select now.
|
||
//
|
||
|
||
NumReadySockets =
|
||
select(
|
||
0, // compatibility argument, ignored.
|
||
&ReadSockets, // sockets to test for readability.
|
||
NULL, // no write wait
|
||
NULL, // no error check.
|
||
NULL ); // NO timeout.
|
||
|
||
if( NumReadySockets == SOCKET_ERROR ) {
|
||
|
||
//
|
||
// ALL sockets are closed and we are asked to return or
|
||
// something else has happpened which we can't handle.
|
||
//
|
||
|
||
Error = WSAGetLastError();
|
||
goto Cleanup;
|
||
}
|
||
|
||
TcpsvcsDbgAssert( (DWORD)NumReadySockets == ReadSockets.fd_count );
|
||
|
||
DWORD i;
|
||
for( i = 0; i < (DWORD)NumReadySockets; i++ ) {
|
||
|
||
DWORD ReadMessageLength;
|
||
struct sockaddr_nb SourcesAddress;
|
||
int SourcesAddressLength;
|
||
|
||
//
|
||
// read next message.
|
||
//
|
||
|
||
SourcesAddressLength = sizeof(SourcesAddress);
|
||
ReadMessageLength =
|
||
recvfrom(
|
||
ReadSockets.fd_array[i],
|
||
(LPSTR)GlobalSrvRecvBuf,
|
||
GlobalSrvRecvBufLength,
|
||
0,
|
||
(struct sockaddr *)&SourcesAddress,
|
||
&SourcesAddressLength );
|
||
|
||
if( ReadMessageLength == SOCKET_ERROR ) {
|
||
|
||
//
|
||
// ALL sockets are closed and we are asked to return or
|
||
// something else has happpened which we can't handle.
|
||
//
|
||
|
||
Error = WSAGetLastError();
|
||
continue;
|
||
}
|
||
|
||
TcpsvcsDbgAssert( ReadMessageLength <= GlobalSrvRecvBufLength );
|
||
|
||
//
|
||
// received a message.
|
||
//
|
||
|
||
TcpsvcsDbgPrint((
|
||
DEBUG_SVCLOC_MESSAGE,
|
||
"Received a discovery message, %ld.\n",
|
||
ReadMessageLength ));
|
||
|
||
Error = ProcessSvclocQuery(
|
||
ReadSockets.fd_array[i],
|
||
GlobalSrvRecvBuf,
|
||
(DWORD)ReadMessageLength,
|
||
(struct sockaddr *)&SourcesAddress,
|
||
(DWORD)SourcesAddressLength );
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"SendSvclocResponse failed, %ld.\n", Error ));
|
||
}
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS, "SocketListenThread returning, %ld.\n", Error ));
|
||
return;
|
||
}
|
||
|
||
DWORD
|
||
ServerDeregisterAndStopListen(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function call stops the discovery thread and deregisters the
|
||
server name. Also it cleans up the winsock data structures.
|
||
|
||
ASSUME : global data crit sect is locked.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
Windows Error Code.
|
||
|
||
--*/
|
||
{
|
||
DWORD Error;
|
||
DWORD i;
|
||
|
||
//
|
||
// close all sockets, if any opened.
|
||
//
|
||
|
||
for( i = 0; i < GlobalSrvSockets.fd_count; i++ ) {
|
||
|
||
Error = closesocket( GlobalSrvSockets.fd_array[i] );
|
||
|
||
if( Error == SOCKET_ERROR ) {
|
||
Error = WSAGetLastError();
|
||
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"closesocket call failed, %ld\n", Error ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// invalidate GlobalSrvSockets count
|
||
//
|
||
|
||
GlobalSrvSockets.fd_count = 0;
|
||
|
||
//
|
||
// closing all above sockets should stop the service location thread,
|
||
// check to see this is the case and close the thread handle.
|
||
//
|
||
|
||
if( GlobalSrvListenThreadHandle != NULL ) {
|
||
|
||
//
|
||
// The thread may take this critical section, release it around
|
||
// the wait to prevent a deadlock
|
||
//
|
||
|
||
UNLOCK_SVC_GLOBAL_DATA();
|
||
|
||
//
|
||
// Wait for the service location thread to stop, but don't wait
|
||
// for longer than THREAD_TERMINATION_TIMEOUT msecs (60 secs)
|
||
//
|
||
|
||
DWORD WaitStatus =
|
||
WaitForSingleObject(
|
||
GlobalSrvListenThreadHandle,
|
||
30000
|
||
);
|
||
|
||
TcpsvcsDbgAssert( WaitStatus != WAIT_FAILED );
|
||
|
||
if( WaitStatus == WAIT_FAILED ) {
|
||
TcpsvcsDbgPrint((DEBUG_ERRORS,
|
||
"WaitForSingleObject call failed, %ld\n", GetLastError() ));
|
||
}
|
||
|
||
CloseHandle( GlobalSrvListenThreadHandle );
|
||
GlobalSrvListenThreadHandle = NULL;
|
||
|
||
LOCK_SVC_GLOBAL_DATA();
|
||
|
||
|
||
}
|
||
|
||
//
|
||
// deregister rnr.
|
||
//
|
||
|
||
if( GlobalRNRRegistered ) {
|
||
|
||
SOCKADDR_IPX IpxSocketAddress;
|
||
SERVICE_INFO ServiceInfo;
|
||
SERVICE_ADDRESSES ServiceAddresses;
|
||
PSERVICE_ADDRESS ServiceAddr;
|
||
DWORD StatusSetService;
|
||
CHAR SapSvcName[SAP_SERVICE_NAME_LEN + 1];
|
||
CHAR *SapSvcNamePtr;
|
||
|
||
Error = MakeSapServiceName( SapSvcName, sizeof(SapSvcName) );
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
SapSvcNamePtr = NULL;
|
||
}
|
||
else {
|
||
SapSvcNamePtr = SapSvcName;
|
||
}
|
||
|
||
//
|
||
// prepare service address.
|
||
//
|
||
|
||
ServiceAddresses.dwAddressCount = 1;
|
||
ServiceAddr = &ServiceAddresses.Addresses[0];
|
||
|
||
memset( &IpxSocketAddress, 0x0, sizeof(IpxSocketAddress) );
|
||
|
||
ServiceAddr->dwAddressType = PF_IPX;
|
||
ServiceAddr->dwAddressFlags = 0;
|
||
ServiceAddr->dwAddressLength = sizeof( IpxSocketAddress );
|
||
ServiceAddr->dwPrincipalLength = 0;
|
||
ServiceAddr->lpAddress = (LPBYTE)&IpxSocketAddress;
|
||
ServiceAddr->lpPrincipal = NULL;
|
||
|
||
//
|
||
// prepare service info.
|
||
//
|
||
|
||
ServiceInfo.lpServiceType = &GlobalSapGuid;
|
||
ServiceInfo.lpServiceName = SapSvcNamePtr;
|
||
ServiceInfo.lpComment = NULL ;
|
||
ServiceInfo.lpLocale = 0;
|
||
ServiceInfo.dwDisplayHint = 0;
|
||
ServiceInfo.dwVersion =
|
||
MAKEWORD( INET_MAJOR_VERSION, INET_MINOR_VERSION ) ;
|
||
ServiceInfo.dwTime = 0; // ??
|
||
ServiceInfo.lpMachineName = GlobalComputerName;
|
||
ServiceInfo.lpServiceAddress = &ServiceAddresses;
|
||
ServiceInfo.ServiceSpecificInfo.pBlobData = 0;
|
||
ServiceInfo.ServiceSpecificInfo.cbSize = 0;
|
||
|
||
//
|
||
// register service info.
|
||
//
|
||
|
||
if( SetServiceA(
|
||
NS_SAP,
|
||
SERVICE_DEREGISTER,
|
||
0,
|
||
&ServiceInfo,
|
||
0,
|
||
&StatusSetService ) == SOCKET_ERROR ) {
|
||
|
||
Error = WSAGetLastError();
|
||
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
||
"SetServiceW call failed, %ld\n", Error ));
|
||
}
|
||
|
||
GlobalRNRRegistered = FALSE;
|
||
}
|
||
|
||
//
|
||
// DONE.
|
||
//
|
||
|
||
return( ERROR_SUCCESS );
|
||
}
|
||
|