Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

602 lines
14 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
gethost.c
Abstract:
This file contains the a version of GetHostByName for IPX/SPX for
dos and windows.
Author:
31 May 94 AlexMit
15 Oct 94 JRoberts - changed to avoid using Novell headers and libs
--*/
#include "sysinc.h"
#include "rpc.h"
#include "rpctran.h"
#include "novell.h"
#include "gethost.h"
#include "netcons.h"
#include "ncb.h"
#ifdef WIN
# include "windows.h"
# define I_RpcAllocate (*(RpcRuntimeInfo->Allocate))
# define I_RpcFree (*(RpcRuntimeInfo->Free))
#else
# include "regalloc.h"
#endif
#define NAME_LEN 48
#define SAP_ECB_COUNT 5
/********************************************************************/
#ifdef WIN
#define CACHE_LENGTH 16
#else
#define CACHE_LENGTH 4
#endif
#define CACHE_EXPIRATION_TIME (10 * 60 * 18)
struct
{
char Name[16];
IPX_ADDRESS Address;
unsigned long Time;
}
ServerCache[CACHE_LENGTH];
/********************************************************************/
extern int atoi(const char *);
/********************************************************************/
unsigned char chtob( unsigned char c1, unsigned char c2 )
/* Convert two hex digits (stored as ascii) into one byte. */
{
unsigned char out;
if (c1 >= '0' && c1 <= '9')
out = (c1 - '0') << 4;
else
{
if (c1 >= 'a' && c1 <= 'f')
out = (c1 - 'a' + 10) << 4;
else if (c1 >= 'A' && c1 <= 'F')
out = (c1 - 'A' + 10) << 4;
else
out = 0;
}
if (c2 >= '0' && c2 <= '9')
out |= c2 -'0';
else
{
if (c2 >= 'a' && c2 <= 'f')
out |= c2 - 'a' + 10;
else if (c2 >= 'A' && c2 <= 'F')
out |= c2 - 'A' + 10;
else
out = 0;
}
return out;
}
unsigned char chtob( unsigned char c1, unsigned char c2 );
RPC_STATUS FromBindery( IPX_ADDRESS __RPC_FAR *host,
RPC_CHAR __RPC_FAR *name );
unsigned long
DosGetTickCount(
)
/*++
Routine Description:
Returns the number of ticks since the last time it was midnight.
There are 65536 ticks per hour.
--*/
{
_asm
{
push bp
push si
push di
xor ax, ax
int 0x1a
mov ax, dx
mov dx, cx
pop di
pop si
pop bp
}
}
void
AddServerToCache(
char PAPI * Name,
IPX_ADDRESS PAPI * Address
)
{
unsigned i;
//
// If the server is already in the table, overwrite the existing entry.
//
for (i=0; i < CACHE_LENGTH; ++i)
{
if (0 == _fstrnicmp(ServerCache[i].Name, Name, 16))
{
break;
}
}
//
// If it is not in the table, try to find an empty entry to fill.
//
if (i == CACHE_LENGTH)
{
for (i=0; i < CACHE_LENGTH; ++i)
{
if (ServerCache[i].Name[0] == '\0')
{
break;
}
}
}
//
// If all entries are full, overwrite the oldest one.
//
if (i == CACHE_LENGTH)
{
unsigned long BestTime = ~0;
unsigned BestIndex;
for (i=0; i < CACHE_LENGTH; ++i)
{
if (ServerCache[i].Time <= BestTime)
{
BestTime = ServerCache[i].Time;
BestIndex = i;
}
}
i = BestIndex;
}
//
// Update the entry's information.
//
_fstrcpy(ServerCache[i].Name, Name);
_fmemcpy(&ServerCache[i].Address, Address, sizeof(IPX_ADDRESS));
ServerCache[i].Time = DosGetTickCount();
}
IPX_ADDRESS *
FindServerInCache(
char PAPI * Name
)
{
unsigned i;
for (i=0; i < CACHE_LENGTH; ++i)
{
if (0 == _fstrcmp(ServerCache[i].Name, Name))
{
return &ServerCache[i].Address;
}
}
return 0;
}
void
CachedServerContacted(
char PAPI * Name
)
{
unsigned i;
for (i=0; i < CACHE_LENGTH; ++i)
{
if (0 == _fstrcmp(ServerCache[i].Name, Name))
{
ServerCache[i].Time = DosGetTickCount();
break;
}
}
}
BOOL
CachedServerNotContacted(
char PAPI * Name
)
{
BOOL Flushed = FALSE;
unsigned i;
for (i=0; i < CACHE_LENGTH; ++i)
{
if (0 == _fstrcmp(ServerCache[i].Name, Name))
{
if (DosGetTickCount() - ServerCache[i].Time > CACHE_EXPIRATION_TIME)
{
ServerCache[i].Name[0] = '\0';
Flushed = TRUE;
break;
}
}
}
return Flushed;
}
BOOL PreferredServerFound = FALSE;
NETWARE_CONNECTION PreferredServer;
RPC_STATUS
SearchBindery(
RPC_CHAR __RPC_FAR *name,
IPX_ADDRESS __RPC_FAR *Address,
unsigned BindingTimeout
)
{
char buffer[128];
unsigned SapTickCount;
unsigned RetryCount = 0;
//
//
//
if (FALSE == PreferredServerFound)
{
reconnect:
PreferredServer.TickLimit = 19;
SapTickCount = 19;
if (BindingTimeout > RPC_C_BINDING_DEFAULT_TIMEOUT)
{
PreferredServer.TickLimit <<= BindingTimeout - RPC_C_BINDING_DEFAULT_TIMEOUT;
SapTickCount <<= BindingTimeout - RPC_C_BINDING_DEFAULT_TIMEOUT;
}
ConnectToAnyFileServer(&PreferredServer, SapTickCount);
if (PreferredServer.ReturnCode || PreferredServer.ConnectionStatus)
{
DisconnectFromServer(&PreferredServer);
PreferredServerFound = FALSE;
return RPC_S_SERVER_UNAVAILABLE;
}
PreferredServerFound = TRUE;
}
//
// Read from the bindery.
//
ReadPropertyValue(&PreferredServer,
name,
RPC_SAP_TYPE,
"NET_ADDRESS",
1,
buffer,
0,
0
);
if (PreferredServer.ReturnCode)
{
DisconnectFromServer(&PreferredServer);
PreferredServerFound = FALSE;
if (RetryCount++)
{
return RPC_S_SERVER_UNAVAILABLE;
}
else
{
goto reconnect;
}
}
//
// Save the host address.
//
_fmemcpy( Address, buffer, 10 );
DisconnectFromServer(&PreferredServer);
return RPC_S_OK;
}
/********************************************************************/
RPC_STATUS
SearchWithSap(
RPC_CHAR __RPC_FAR *name,
IPX_ADDRESS __RPC_FAR *host,
unsigned Timeout
#ifdef WIN
, RPC_CLIENT_RUNTIME_INFO PAPI * RpcRuntimeInfo
#endif
)
{
WORD start;
unsigned SapSocket;
int result;
int i;
int retry;
struct
{
ECB ecb;
IPX_HEADER ipx;
SAP_REQUEST req;
} send;
struct SAP_RESPONSE_ECB
{
ECB ecb;
IPX_HEADER ipx;
SAP_RESPONSE resp;
}
__RPC_FAR * mem;
RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
//
// The base timeout is two seconds; max is a minute.
//
if (Timeout <= RPC_C_BINDING_DEFAULT_TIMEOUT)
{
Timeout = 18 * 2;
}
else
{
Timeout = (18 * 2) << (Timeout - RPC_C_BINDING_DEFAULT_TIMEOUT);
}
result = IPXOpenSocket(TASKID_C &SapSocket, 0);
if (result != 0)
return RPC_S_OUT_OF_RESOURCES;
// Allocate memory for ECBs.
#ifdef WIN
mem = I_RpcAllocate( SAP_ECB_COUNT * sizeof(*mem) );
#else
mem = I_RpcRegisteredBufferAllocate( SAP_ECB_COUNT * sizeof(*mem) );
#endif
if (mem == NULL)
{
status = RPC_S_OUT_OF_MEMORY;
goto cleanup;
}
_fmemset( mem, 0, SAP_ECB_COUNT * sizeof(mem) );
//
// Post some ECBs.
//
for (i = 0; i < SAP_ECB_COUNT; i++)
{
SetupEcb(&mem[i].ecb, SapSocket, sizeof(SAP_RESPONSE));
IPXListenForPacket(TASKID_C &mem[i].ecb );
}
//
// We want to send a SAP request and scan responses for the server
// that we want. We transmit the request up to two times because
// servers sometimes miss a single broadcast.
//
for (retry = 0; retry < 2 ; ++retry)
{
send.ipx.PacketType = IPX_PACKET_TYPE;
send.ipx.Destination.Network = 0;
send.ipx.Destination.Socket = SAP_SOCKET;
_fmemset( send.ipx.Destination.Node, 0xff, sizeof(send.ipx.Destination.Node) );
SetupEcb(&send.ecb, SapSocket, sizeof(send));
_fmemset( send.ecb.immediateAddress, 0xff, sizeof(send.ecb.immediateAddress) );
// Send the data.
send.req.QueryType = SAP_GENERAL_QUERY;
send.req.ServerType = RPC_SAP_TYPE_SWAPPED;
IPXSendPacket(TASKID_C &send.ecb );
while (send.ecb.inUseFlag)
IPXRelinquishControl();
// Verify that the send was successful.
if (send.ecb.completionCode)
{
goto cleanup;
}
//
// Get packets till timeout is returned or a good reply is returned.
//
start = IPXGetIntervalMarker(TASKID);
do
{
struct SAP_RESPONSE_ECB __RPC_FAR * curr;
for (curr = mem; curr < mem + SAP_ECB_COUNT; curr++)
{
if (curr->ecb.inUseFlag == 0)
{
if (curr->ecb.completionCode == 0x00)
{
// Verify the packet.
//
curr->ipx.Length = ByteSwapShort( curr->ipx.Length );
curr->ipx.Length -= sizeof(IPX_HEADER);
if (curr->ipx.Source.Socket == SAP_SOCKET &&
curr->ipx.Length >= sizeof (SAP_RESPONSE) &&
curr->resp.PacketType == SAP_GENERAL_RESPONSE )
{
unsigned num_entry = curr->ipx.Length / sizeof(SAP_ENTRY);
for (i = 0; i < num_entry; i++)
{
if (0 == _fstrnicmp( name, curr->resp.Entries[i].Name, NAME_LEN))
{
// Only copy the network and node numbers, not the socket.
//
_fmemcpy( host, &curr->resp.Entries[i].Address, 10 );
status = RPC_S_OK;
goto cleanup;
}
}
}
}
//
// Repost the receive.
//
IPXListenForPacket( TASKID_C &curr->ecb );
}
}
IPXRelinquishControl();
}
while (IPXGetIntervalMarker(TASKID) - start < Timeout);
}
cleanup:
//
// Cancel the ECBs.
//
if (mem)
{
for (i = 0; i < SAP_ECB_COUNT; i++)
{
if (mem[i].ecb.inUseFlag)
{
IPXCancelEvent( TASKID_C &mem[i].ecb );
while (mem[i].ecb.inUseFlag)
{
IPXRelinquishControl();
}
}
}
//
// Free the memory.
//
#ifdef WIN
I_RpcFree( mem );
#else
I_RpcRegisteredBufferFree( mem );
#endif
}
IPXCloseSocket(TASKID_C SapSocket);
return status;
}
/********************************************************************/
RPC_STATUS
IpxGetHostByName(
RPC_CHAR __RPC_FAR * name,
IPX_ADDRESS __RPC_FAR * Address,
RPC_CHAR __RPC_FAR * endpoint,
unsigned Timeout
#ifdef WIN
, RPC_CLIENT_RUNTIME_INFO * RpcClientRuntimeInfo
#endif
)
{
RPC_STATUS status;
int i;
int length;
IPX_ADDRESS * CachedAddress;
// Set the endpoint.
Address->Socket = ByteSwapShort(atoi(endpoint));
// Fail if no address was specified.
if (name == NULL || name[0] == '\0')
return RPC_S_SERVER_UNAVAILABLE;
// If the name starts with ~, convert it directly to a network address.
length = _fstrlen(name);
if (name[0] == '~')
{
unsigned char __RPC_FAR * Temp;
if (length != 21)
return RPC_S_INVALID_NET_ADDR;
Temp = (unsigned char __RPC_FAR *) &Address->Network;
for (i = 0; i < 4; i++)
{
Temp[i] = chtob( name[2*i + 1], name[2*i + 2] );
}
Temp = (unsigned char __RPC_FAR *) Address->Node;
for (i = 0; i < 6; i++)
{
Temp[i] = chtob( name[2*i + 9], name[2*i + 10] );
}
return RPC_S_OK;
}
if (length > 15)
{
return RPC_S_INVALID_NET_ADDR;
}
CachedAddress = FindServerInCache(name);
if (CachedAddress)
{
_fmemcpy(Address, CachedAddress, 10);
return RPC_S_OK;
}
// Try the bindery.
status = SearchBindery(name, Address, Timeout);
if (status && !PreferredServerFound)
{
status = SearchWithSap(name,
Address,
Timeout
#ifdef WIN
, RpcClientRuntimeInfo
#endif
);
}
if (!status)
{
AddServerToCache(name, Address);
}
return status;
}