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.
1566 lines
39 KiB
1566 lines
39 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: ipxname.cxx
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
/*++
|
|
|
|
Module Name:
|
|
|
|
gethost.c
|
|
|
|
Abstract:
|
|
|
|
Maps a server name to SPX address by consulting the Netware Bindery.
|
|
Attach/Detach/FindFileServer, and ReadPropertyValue were all borrowed
|
|
from the SQL 6.0 code base.
|
|
|
|
Author:
|
|
|
|
Jeff Roberts (jroberts) 20-Nov-1995
|
|
|
|
Revision History:
|
|
|
|
20-Nov-1995 (jroberts) Took code from AndreasK of SQL Server, and modified
|
|
it for RPC.
|
|
|
|
24-Jan-1997 (MarioGo) C++ and cache cleanup work.
|
|
|
|
--*/
|
|
|
|
#include <precomp.hxx>
|
|
#include <CharConv.hxx>
|
|
|
|
const GUID SERVICE_TYPE = { 0x000b0640, 0, 0, { 0xC0,0,0,0,0,0,0,0x46 } };
|
|
|
|
#define CRITICAL_SECTION_WRAPPER RTL_CRITICAL_SECTION
|
|
|
|
#define MAX_FILESRVS 5 /* try 5 servers (chicago uses this same number) */
|
|
|
|
/***** NETWARE MAGIC NUMBERS *****/
|
|
|
|
#define NSPROTO_NCP (NSPROTO_IPX+0x11)
|
|
|
|
/* NCP Request Types */
|
|
#define CREATE_CONN_REQTYPE 0x1111
|
|
#define DESTROY_CONN_REQYPE 0x5555
|
|
#define GENERAL_REQTYPE 0x2222
|
|
|
|
/* NCP Request Codes */
|
|
#define NCP_SCAN_BINDERY 0x17
|
|
#define NCP_END_OF_TASK 0x18
|
|
#define NCP_LOGOUT 0x19
|
|
#define NCP_NEG_BUFFER_SIZE 0x21
|
|
|
|
/* NCP Function codes */
|
|
#define SCAN_BINDERY_FUNC 0x37
|
|
#define READ_PROP_VALUE_FUNC 0x3D
|
|
|
|
/* SAP protocol request codes */
|
|
#define SAP_GENERAL_QUERY 0x0100 /* general query hi-lo */
|
|
#define SAP_GENERAL_RESPONSE 0x0200 /* general response hi-lo */
|
|
#define SAP_NEAREST_QUERY 0x0300 /* nearest query hi-lo */
|
|
#define SAP_NEAREST_RESPONSE 0x0400 /* nearest response hi-lo */
|
|
|
|
|
|
/* Socket Numbers */
|
|
#define NCP_SOCKET 0x5104 /* SAP socket hi-lo */
|
|
#define SAP_SOCKET 0x5204 /* SAP socket hi-lo */
|
|
#define GUEST_SOCKET 0x1840
|
|
|
|
/* SAP Service Types */
|
|
#define FILE_SERVER 0x0400 /* netware file server hi-lo */
|
|
#define SNA_SERVER 0x4404 /* SNA Server type 0x0444 */
|
|
#define BRIDGE_SERVER 0x2400
|
|
|
|
#define SAP_SERVICE_STOPPED 0x1000 /* invalid hub count, hi-lo */
|
|
#define SAP_TIMEOUT 60000 /* SAP timeout, one minute */
|
|
#define NCP_CONNECTION_ERROR 0x15 /* connection error mask */
|
|
|
|
#define BINDERY_FAILURE 0x00FF /* bindery call failed */
|
|
|
|
#define RPC_SAP_TYPE 0x0640
|
|
|
|
#define SWAP(x) RpcpByteSwapShort(x)
|
|
|
|
typedef struct
|
|
{
|
|
CSADDR_INFO info;
|
|
SOCKADDR_IPX addr1;
|
|
SOCKADDR_IPX addr2;
|
|
} CSADDR_BUFFER;
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct _sip_entry
|
|
{
|
|
char server_name[48];
|
|
unsigned long network;
|
|
char node[6];
|
|
unsigned short socket;
|
|
unsigned short hops;
|
|
} SIP_ENTRY;
|
|
|
|
typedef struct _sip /* Service Information Packet */
|
|
{
|
|
unsigned short response_type;
|
|
unsigned short server_type;
|
|
SIP_ENTRY entries[7];
|
|
} SIP;
|
|
|
|
typedef struct /* Service Query Packet */
|
|
{
|
|
unsigned short query_type;
|
|
unsigned short server_type;
|
|
} SQP;
|
|
|
|
typedef struct /* NCP Request Header */
|
|
{
|
|
unsigned short req_type;
|
|
unsigned char seq_no;
|
|
unsigned char conn_no_low;
|
|
unsigned char task_no;
|
|
unsigned char conn_no_high;
|
|
unsigned char req_code;
|
|
|
|
} NCPHDR;
|
|
|
|
typedef struct /* NCP Response Header */
|
|
{
|
|
unsigned short req_type;
|
|
unsigned char seq_no;
|
|
unsigned char conn_no_low;
|
|
unsigned char task_no;
|
|
unsigned char conn_no_high;
|
|
unsigned char ret_code;
|
|
unsigned char conn_status;
|
|
} NCPRSP;
|
|
|
|
typedef struct /* Scan Bindery Request */
|
|
{
|
|
NCPHDR hdr;
|
|
unsigned short length;
|
|
unsigned char func_code;
|
|
unsigned long last_id;
|
|
unsigned short obj_type;
|
|
unsigned char sstring[49];
|
|
} SCANREQ;
|
|
#define SCANSIZE 56
|
|
|
|
typedef struct /* Scan Bindery Response */
|
|
{
|
|
NCPRSP hdr;
|
|
unsigned long obj_id;
|
|
unsigned short obj_type;
|
|
unsigned char obj_name[48];
|
|
unsigned char obj_status;
|
|
unsigned char sec_status;
|
|
unsigned char status_flags;
|
|
} SCANRSP;
|
|
|
|
typedef struct /* Read Propery Value */
|
|
{
|
|
NCPHDR hdr;
|
|
unsigned short length;
|
|
unsigned char func_code;
|
|
unsigned short obj_type;
|
|
unsigned char obj_name[49];
|
|
unsigned char seg_no;
|
|
unsigned char prop_name[17];
|
|
} RVALREQ;
|
|
#define RVALSIZE 70
|
|
|
|
typedef struct /* Read Propery Value Response */
|
|
{
|
|
NCPRSP hdr;
|
|
unsigned char prop_value[128];
|
|
unsigned char more_flag;
|
|
unsigned char prop_flags;
|
|
} RVALRSP;
|
|
|
|
#pragma pack()
|
|
|
|
#define BUFFER_SIZE 1024 /* Size of send and recv buffer */
|
|
|
|
struct
|
|
{
|
|
SOCKADDR_IPX nsRemote[MAX_FILESRVS]; /* Remote IPX addresses */
|
|
unsigned ServerCount; /* number of valid entries in nsRemote */
|
|
unsigned ActiveServer; /* index of the the address in use */
|
|
SOCKET s; /* Socket handle */
|
|
unsigned short ConnectionId;
|
|
NCPHDR *nhHeader; /* Last NCP header sent */
|
|
char *RcvBuffer;
|
|
}
|
|
nsStatus;
|
|
|
|
typedef struct IPXAddress
|
|
{
|
|
char network[4];
|
|
char node[6];
|
|
unsigned short socket;
|
|
} IPXAddress;
|
|
|
|
|
|
int FindFileServers();
|
|
BOOL AttachToFileServer();
|
|
BOOL ConnectToActiveServer();
|
|
BOOL DetachFromActiveServer();
|
|
int SendPacket( SOCKET, char *, int, SOCKADDR *, DWORD );
|
|
USHORT ReadPropertyValue( char *, USHORT, char *, USHORT, UCHAR *,
|
|
UCHAR *, UCHAR * );
|
|
int
|
|
NcpTransaction(
|
|
int iSize
|
|
);
|
|
|
|
DWORD
|
|
InitializeCriticalSectionWrapper(
|
|
RTL_CRITICAL_SECTION * Mutex
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlInitializeCriticalSection(Mutex);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
DWORD
|
|
DeleteCriticalSectionWrapper(
|
|
RTL_CRITICAL_SECTION * Mutex
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlDeleteCriticalSection(Mutex);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
DWORD
|
|
EnterCriticalSectionWrapper(
|
|
RTL_CRITICAL_SECTION * Mutex
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlEnterCriticalSection(Mutex);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
DWORD
|
|
LeaveCriticalSectionWrapper(
|
|
RTL_CRITICAL_SECTION * Mutex
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlLeaveCriticalSection(Mutex);
|
|
ASSERT (NT_SUCCESS(NtStatus));
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
AttachToFileServer(
|
|
)
|
|
//**************************************************************************
|
|
//
|
|
// This function creates an attachment between an NT workstation and
|
|
// a Novell Netware file server.
|
|
//
|
|
// Params:
|
|
// USHORT *pConectionID - Receives the connection ID for the newly
|
|
// attached file server
|
|
// LOBYTE(ConnectionID) = conn_no_low
|
|
// HIBYTE(ConnectionID) = conn_no_high
|
|
//
|
|
// Return Values:
|
|
//
|
|
// TRUE - successful
|
|
// FALSE - unsuccessful
|
|
//
|
|
//***************************************************************************
|
|
{
|
|
DWORD IDThread;
|
|
unsigned i;
|
|
char scratch[2];
|
|
|
|
SOCKET s;
|
|
SOCKADDR_IPX nsAddr;
|
|
unsigned Timeout;
|
|
|
|
s = socket( AF_NS, SOCK_DGRAM, NSPROTO_NCP );
|
|
if ( s == INVALID_SOCKET )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Set the receive timeout.
|
|
//
|
|
Timeout = 3000;
|
|
if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &Timeout, sizeof(Timeout)))
|
|
{
|
|
closesocket(s);
|
|
return FALSE;
|
|
}
|
|
|
|
memset( &nsAddr, '\0', sizeof(SOCKADDR_IPX) );
|
|
nsAddr.sa_family = AF_NS;
|
|
if (SOCKET_ERROR == bind(s, (SOCKADDR *)&nsAddr, sizeof(SOCKADDR_IPX)) )
|
|
{
|
|
closesocket(s);
|
|
return FALSE;
|
|
}
|
|
|
|
nsStatus.s = s;
|
|
|
|
/* Find the nearest file server. */
|
|
|
|
if( nsStatus.ServerCount )
|
|
{
|
|
for (i=0; i < nsStatus.ServerCount; i++)
|
|
{
|
|
nsStatus.ActiveServer = i;
|
|
if( ConnectToActiveServer() )
|
|
{
|
|
nsStatus.ConnectionId = nsStatus.nhHeader->conn_no_low + (nsStatus.nhHeader->conn_no_high << 8);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
FindFileServers();
|
|
|
|
if( nsStatus.ServerCount )
|
|
{
|
|
for (i=0; i < nsStatus.ServerCount; i++)
|
|
{
|
|
nsStatus.ActiveServer = i;
|
|
if( ConnectToActiveServer() )
|
|
{
|
|
nsStatus.ConnectionId = nsStatus.nhHeader->conn_no_low + (nsStatus.nhHeader->conn_no_high << 8);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
closesocket(s);
|
|
nsStatus.s = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int
|
|
FindFileServers(
|
|
)
|
|
/****************************************************************************/
|
|
/* */
|
|
/* This function uses the SAP (Service Advertise Protocol) Find Nearest */
|
|
/* query to find a netware file server. */
|
|
/* */
|
|
/* Returns: */
|
|
/* Number of servers found (0 - MAX_FILESRVS) */
|
|
/* */
|
|
/****************************************************************************/
|
|
{
|
|
SOCKET s;
|
|
BOOL bBcst;
|
|
SQP sqp;
|
|
SIP sip;
|
|
unsigned Timeout;
|
|
|
|
SOCKADDR_IPX raddr;
|
|
SOCKADDR_IPX nsAddr;
|
|
|
|
|
|
//
|
|
// Create a socket for the SAP broadcast.
|
|
//
|
|
s = socket( AF_NS, SOCK_DGRAM, NSPROTO_IPX );
|
|
if( s == INVALID_SOCKET )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
memset( &nsAddr, '\0', sizeof(SOCKADDR_IPX) );
|
|
nsAddr.sa_family = AF_NS;
|
|
if(SOCKET_ERROR == bind(s, (SOCKADDR *)&nsAddr, sizeof(SOCKADDR_IPX)) )
|
|
{
|
|
closesocket(s);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Enable broadcasts.
|
|
//
|
|
bBcst = TRUE;
|
|
if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&bBcst, sizeof(BOOL)))
|
|
{
|
|
closesocket(s);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Set the receive timeout.
|
|
//
|
|
Timeout = 2000;
|
|
if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &Timeout, sizeof(Timeout)))
|
|
{
|
|
closesocket(s);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Build a SAP query packet.
|
|
//
|
|
sqp.query_type = SAP_NEAREST_QUERY;
|
|
sqp.server_type = FILE_SERVER;
|
|
|
|
raddr.sa_family = AF_NS;
|
|
*((unsigned long UNALIGNED *) &raddr.sa_netnum) = 0;
|
|
memset( &raddr.sa_nodenum, 0xff, 6 );
|
|
raddr.sa_socket = SAP_SOCKET;
|
|
|
|
//
|
|
// Send the SAP request.
|
|
//
|
|
if (SOCKET_ERROR == sendto( s, (char *) &sqp, sizeof(SQP), 0, (SOCKADDR *) &raddr, sizeof(SOCKADDR_IPX) ))
|
|
{
|
|
closesocket(s);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Collate responses.
|
|
//
|
|
nsStatus.ServerCount = 0;
|
|
do
|
|
{
|
|
unsigned length;
|
|
|
|
irrelevant_packet:
|
|
|
|
length = recvfrom(s, (char *) &sip, sizeof(sip), 0, 0, 0);
|
|
if (SOCKET_ERROR == length)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// IPX router spec says find nearest responses can contain only one
|
|
// entry.
|
|
//
|
|
if (length != sizeof(sip) - sizeof(sip.entries) + sizeof(SIP_ENTRY))
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
|
|
if (sip.response_type != SAP_NEAREST_RESPONSE)
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
|
|
if (sip.server_type != FILE_SERVER)
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
|
|
nsStatus.nsRemote[nsStatus.ServerCount].sa_family = AF_NS;
|
|
nsStatus.nsRemote[nsStatus.ServerCount].sa_socket = NCP_SOCKET;
|
|
memcpy( &nsStatus.nsRemote[nsStatus.ServerCount].sa_netnum,
|
|
&sip.entries[0].network,
|
|
sizeof(sip.entries[0].network)+sizeof(sip.entries[0].node)
|
|
);
|
|
}
|
|
while ( ++nsStatus.ServerCount < MAX_FILESRVS );
|
|
|
|
closesocket(s);
|
|
return nsStatus.ServerCount;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ConnectToActiveServer(
|
|
)
|
|
/****************************************************************************/
|
|
/* */
|
|
/* This function creates a NCP connection between the local workstation */
|
|
/* and the specified file server. It sends the following NCP packets to */
|
|
/* the file server: */
|
|
/* 1. Create Connection */
|
|
/* 2. Negotiate Buffer Size */
|
|
/* */
|
|
/* Params: */
|
|
/* SOCKADDR_IPX *ipxDest - server's IPX address */
|
|
/* */
|
|
/* Returns: */
|
|
/* TRUE - SUCCEEDED */
|
|
/* FALSE - FAILED */
|
|
/* */
|
|
/****************************************************************************/
|
|
{
|
|
SOCKADDR_IPX nsAddr;
|
|
NCPHDR *pnhReq;
|
|
NCPRSP *pnrResp;
|
|
USHORT UNALIGNED *pwBufSize;
|
|
BOOL fSuccess;
|
|
|
|
//
|
|
// Build a CREATE_CONNECTION request.
|
|
//
|
|
memset( nsStatus.nhHeader, '\0', sizeof(NCPHDR));
|
|
|
|
pnhReq = nsStatus.nhHeader;
|
|
pnhReq->req_type = CREATE_CONN_REQTYPE;
|
|
pnhReq->seq_no = 0; /* reset sequence number */
|
|
pnhReq->conn_no_low = 0xFF; /* no connection yet */
|
|
pnhReq->conn_no_high = 0xFF; /* no connection yet */
|
|
pnhReq->task_no = 0;
|
|
pnhReq->req_code = 0;
|
|
|
|
//
|
|
// Send the packet and wait for response.
|
|
//
|
|
fSuccess = FALSE;
|
|
if (SOCKET_ERROR != NcpTransaction(sizeof(NCPHDR)) )
|
|
{
|
|
/* Save our connection number, it is used in all the subsequent */
|
|
/* NCP packets. */
|
|
pnrResp = (NCPRSP *)nsStatus.RcvBuffer;
|
|
if ( pnrResp->ret_code == 0 )
|
|
{
|
|
nsStatus.nhHeader->conn_no_low = pnrResp->conn_no_low;
|
|
nsStatus.nhHeader->conn_no_high = pnrResp->conn_no_high;
|
|
|
|
fSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DetachFromActiveServer(
|
|
)
|
|
/****************************************************************************/
|
|
/* */
|
|
/* This function logs out the bindery object and detaches the workstation */
|
|
/* from the specified file server. */
|
|
/* */
|
|
/* Params: */
|
|
/* none
|
|
/* */
|
|
/* Returns: */
|
|
/* TRUE - Always */
|
|
/* */
|
|
/****************************************************************************/
|
|
{
|
|
int iret;
|
|
|
|
if (0 == nsStatus.s)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
nsStatus.nhHeader->req_type = DESTROY_CONN_REQYPE;
|
|
nsStatus.nhHeader->seq_no++;
|
|
nsStatus.nhHeader->req_code = 0;
|
|
|
|
NcpTransaction(sizeof(NCPHDR));
|
|
|
|
closesocket( nsStatus.s );
|
|
nsStatus.s = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
USHORT
|
|
ReadPropertyValue(
|
|
char *ObjectName,
|
|
USHORT ObjectType,
|
|
char *PropertyName,
|
|
USHORT SegmentNumber,
|
|
UCHAR *PropertyValue,
|
|
UCHAR *MoreSegments,
|
|
UCHAR *PropertyFlags
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
RVALREQ *pReq;
|
|
RVALRSP *pRsp;
|
|
int iRet;
|
|
|
|
if ( !nsStatus.s )
|
|
{
|
|
return BINDERY_FAILURE;
|
|
}
|
|
|
|
/* Build a SCAN_BINDERY request */
|
|
pReq = (RVALREQ *) nsStatus.nhHeader;
|
|
pReq->hdr.seq_no++;
|
|
pReq->hdr.req_code = NCP_SCAN_BINDERY;
|
|
pReq->hdr.req_type = GENERAL_REQTYPE;
|
|
pReq->func_code = READ_PROP_VALUE_FUNC;
|
|
pReq->length = SWAP(RVALSIZE);
|
|
|
|
pReq->obj_type = SWAP(ObjectType);
|
|
memset( pReq->obj_name, '\0', sizeof(pReq->obj_name));
|
|
strcpy((PCHAR)pReq->obj_name+1, ObjectName );
|
|
pReq->obj_name[0] = (UCHAR)(sizeof(pReq->obj_name)-1);
|
|
pReq->seg_no = (UCHAR)SegmentNumber;
|
|
memset( pReq->prop_name, '\0', sizeof(pReq->prop_name));
|
|
strcpy((PCHAR)pReq->prop_name+1, PropertyName );
|
|
pReq->prop_name[0] = (UCHAR)strlen(PropertyName);
|
|
|
|
/* Send the request and wait for response */
|
|
iRet = NcpTransaction(sizeof(RVALREQ));
|
|
|
|
/* If OK set output parameter values from the response packet */
|
|
if ( iRet != SOCKET_ERROR )
|
|
{
|
|
pRsp = (RVALRSP *) nsStatus.RcvBuffer;
|
|
if ( pRsp->hdr.ret_code == 0 )
|
|
{
|
|
*MoreSegments = pRsp->more_flag;
|
|
*PropertyFlags = pRsp->prop_flags;
|
|
memcpy( PropertyValue, pRsp->prop_value, sizeof(pRsp->prop_value));
|
|
}
|
|
|
|
return((USHORT)pRsp->hdr.ret_code);
|
|
}
|
|
|
|
return(BINDERY_FAILURE);
|
|
}
|
|
|
|
|
|
int
|
|
NcpTransaction(
|
|
int iSize
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send an NCP request to the active file server and wait for a response.
|
|
Most necessary data has been stored in the nsStatus structure by
|
|
the caller.
|
|
|
|
Arguments:
|
|
|
|
iSize - size of buffer to send.
|
|
|
|
Return Value:
|
|
|
|
SOCKET_ERROR if the fn failed,
|
|
anything else if successful
|
|
|
|
--*/
|
|
|
|
NCPRSP * pRsp;
|
|
SOCKADDR_IPX SockAddr;
|
|
int SockAddrLength;
|
|
int Bytes;
|
|
int Attempts = 0;
|
|
|
|
/* Send the packet and retry three times if the response doesn't */
|
|
/* arrive within the specified timeout */
|
|
|
|
SockAddrLength = sizeof(SOCKADDR_IPX);
|
|
pRsp = (NCPRSP *) nsStatus.RcvBuffer;
|
|
|
|
do
|
|
{
|
|
if (SOCKET_ERROR == sendto( nsStatus.s,
|
|
(char *) nsStatus.nhHeader,
|
|
iSize,
|
|
0,
|
|
(SOCKADDR *) &nsStatus.nsRemote[nsStatus.ActiveServer],
|
|
sizeof(SOCKADDR_IPX)
|
|
))
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
irrelevant_packet:
|
|
|
|
Bytes = recvfrom( nsStatus.s,
|
|
nsStatus.RcvBuffer,
|
|
BUFFER_SIZE,
|
|
0,
|
|
(SOCKADDR *) &SockAddr,
|
|
&SockAddrLength
|
|
);
|
|
|
|
//
|
|
// If we get a packet, compare the source address and sequence #.
|
|
// We also compare the connection number except on the initial
|
|
// connection request.
|
|
//
|
|
if (Bytes != SOCKET_ERROR)
|
|
{
|
|
if (0 != memcmp(SockAddr.sa_nodenum,
|
|
nsStatus.nsRemote[nsStatus.ActiveServer].sa_nodenum,
|
|
6))
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
|
|
if (0 != memcmp(SockAddr.sa_netnum,
|
|
nsStatus.nsRemote[nsStatus.ActiveServer].sa_netnum,
|
|
4))
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
|
|
if (nsStatus.nhHeader->req_type != CREATE_CONN_REQTYPE)
|
|
{
|
|
if (pRsp->conn_no_low != nsStatus.nhHeader->conn_no_low ||
|
|
pRsp->conn_no_high != nsStatus.nhHeader->conn_no_high)
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
}
|
|
|
|
if (pRsp->seq_no != nsStatus.nhHeader->seq_no )
|
|
{
|
|
goto irrelevant_packet;
|
|
}
|
|
}
|
|
}
|
|
while ( Bytes == SOCKET_ERROR && WSAGetLastError() == WSAETIMEDOUT && ++Attempts < 3 );
|
|
|
|
return Bytes;
|
|
}
|
|
|
|
|
|
CRITICAL_SECTION_WRAPPER FileServerMutex;
|
|
|
|
BOOL fCsnwCheckCompleted = FALSE;
|
|
BOOL fCsnwInstalled = FALSE;
|
|
|
|
DWORD
|
|
GetCsnwStatus(
|
|
LPSERVICE_STATUS pServiceStatus
|
|
)
|
|
{
|
|
SC_HANDLE ServiceController;
|
|
SC_HANDLE Csnw;
|
|
DWORD status;
|
|
|
|
ServiceController = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
|
|
if (NULL == ServiceController)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
Csnw = OpenService(ServiceController, L"NWCWorkstation", SERVICE_QUERY_STATUS);
|
|
|
|
status = GetLastError();
|
|
|
|
CloseServiceHandle(ServiceController);
|
|
|
|
if (NULL == Csnw)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
if (FALSE == QueryServiceStatus(Csnw, pServiceStatus))
|
|
{
|
|
status = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
status = 0;
|
|
}
|
|
|
|
CloseServiceHandle(Csnw);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
void
|
|
CheckForCsnw(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asks the service controller whether Client Services for Netware is installed.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
no explicit return value
|
|
|
|
updates fKnowCsnwInstallState and fCsnwInstalled
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
SERVICE_STATUS ServiceStatus;
|
|
|
|
Status = GetCsnwStatus(&ServiceStatus);
|
|
|
|
if (Status && Status != ERROR_SERVICE_DOES_NOT_EXIST)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!Status)
|
|
{
|
|
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING ||
|
|
ServiceStatus.dwCurrentState == SERVICE_START_PENDING ||
|
|
ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING )
|
|
{
|
|
fCsnwInstalled = TRUE;
|
|
}
|
|
}
|
|
|
|
fCsnwCheckCompleted = TRUE;
|
|
}
|
|
|
|
|
|
struct
|
|
{
|
|
PCHAR Name;
|
|
SOCKADDR_IPX Address;
|
|
unsigned Time;
|
|
}
|
|
ServerCache[CACHE_SIZE];
|
|
|
|
CRITICAL_SECTION_WRAPPER CacheMutex;
|
|
|
|
RPC_STATUS
|
|
InitializeIpxNameCache(
|
|
)
|
|
{
|
|
static BOOL fInitialized = FALSE;
|
|
|
|
if (fInitialized)
|
|
{
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS Status;
|
|
PVOID Buffer0, Buffer1;
|
|
|
|
Buffer0 = I_RpcAllocate(1024);
|
|
if (Buffer0 == NULL)
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
|
|
Buffer1 = I_RpcAllocate(1024);
|
|
if (Buffer1 == NULL)
|
|
{
|
|
I_RpcFree(Buffer0);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Status = InitializeCriticalSectionWrapper(&CacheMutex);
|
|
|
|
if (!Status)
|
|
{
|
|
Status = InitializeCriticalSectionWrapper(&FileServerMutex);
|
|
|
|
if (Status)
|
|
{
|
|
DeleteCriticalSectionWrapper(&CacheMutex);
|
|
}
|
|
}
|
|
|
|
if (Status)
|
|
{
|
|
I_RpcFree(Buffer0);
|
|
I_RpcFree(Buffer1);
|
|
return(Status);
|
|
}
|
|
|
|
nsStatus.nhHeader = (NCPHDR *)Buffer0;
|
|
nsStatus.RcvBuffer = (PCHAR) Buffer1;
|
|
|
|
ASSERT(nsStatus.ServerCount == 0);
|
|
ASSERT(nsStatus.s == 0);
|
|
|
|
ASSERT(!fInitialized);
|
|
fInitialized = TRUE;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
AddServerToCache(
|
|
IN char * Name,
|
|
IN SOCKADDR_IPX * Address
|
|
)
|
|
{
|
|
unsigned i;
|
|
RPC_STATUS Status;
|
|
|
|
Status = EnterCriticalSectionWrapper(&CacheMutex);
|
|
if (Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check if the name is already in the cache, we might be re-resolving
|
|
// the name or another thread might have put the name in the cache
|
|
// since we last checked.
|
|
//
|
|
for (i=0; i < CACHE_SIZE; ++i)
|
|
{
|
|
if ( ServerCache[i].Name &&
|
|
0 == RpcpStringCompareA(ServerCache[i].Name, Name))
|
|
{
|
|
// Check if entry already matches our address.
|
|
if ( memcmp(Address->sa_netnum, ServerCache[i].Address.sa_netnum, 4)
|
|
|| memcmp(Address->sa_nodenum, ServerCache[i].Address.sa_nodenum, 6))
|
|
{
|
|
// New information, update cache.
|
|
memcpy(&ServerCache[i].Address, Address, sizeof(SOCKADDR_IPX));
|
|
Status = RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
Status = RPC_P_MATCHED_CACHE;
|
|
}
|
|
LeaveCriticalSectionWrapper(&CacheMutex);
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it is not in the table, try to find an empty entry to fill.
|
|
//
|
|
if (i == CACHE_SIZE)
|
|
{
|
|
for (i=0; i < CACHE_SIZE; ++i)
|
|
{
|
|
if (ServerCache[i].Name == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If all entries are full, overwrite the oldest one.
|
|
//
|
|
if (i == CACHE_SIZE)
|
|
{
|
|
unsigned BestIndex = 0;
|
|
LONG now = GetTickCount();
|
|
LONG BestDiff = now - ServerCache[0].Time;
|
|
|
|
ASSERT(CACHE_SIZE > 1);
|
|
|
|
for (i = 1; i < CACHE_SIZE; ++i)
|
|
{
|
|
LONG diff = now - ServerCache[i].Time;
|
|
if (diff > BestDiff)
|
|
{
|
|
BestIndex = i;
|
|
BestDiff = diff;
|
|
}
|
|
}
|
|
|
|
i = BestIndex;
|
|
}
|
|
|
|
//
|
|
// Update the entry's information.
|
|
//
|
|
|
|
ASSERT(strlen(Name) <= IPX_MAXIMUM_PRETTY_NAME);
|
|
|
|
if (NULL == ServerCache[i].Name)
|
|
{
|
|
ServerCache[i].Name = new CHAR[IPX_MAXIMUM_PRETTY_NAME + 1];
|
|
}
|
|
|
|
if (ServerCache[i].Name)
|
|
{
|
|
strcpy(ServerCache[i].Name, Name);
|
|
memcpy(&ServerCache[i].Address, Address, sizeof(SOCKADDR_IPX));
|
|
|
|
ServerCache[i].Time = GetTickCount();
|
|
|
|
Status = RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
LeaveCriticalSectionWrapper(&CacheMutex);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindServerInCache(
|
|
char * Name,
|
|
SOCKADDR_IPX * Address,
|
|
unsigned * Time
|
|
)
|
|
{
|
|
unsigned i;
|
|
RPC_STATUS Status;
|
|
|
|
Status = EnterCriticalSectionWrapper(&CacheMutex);
|
|
if (Status)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < CACHE_SIZE; ++i)
|
|
{
|
|
if ( ServerCache[i].Name
|
|
&& (0 == RpcpStringCompareA(ServerCache[i].Name, Name)) )
|
|
{
|
|
memcpy(Address, &ServerCache[i].Address, sizeof(SOCKADDR_IPX));
|
|
*Time = ServerCache[i].Time;
|
|
|
|
LeaveCriticalSectionWrapper(&CacheMutex);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSectionWrapper(&CacheMutex);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CachedServerNotContacted(
|
|
char * Name
|
|
)
|
|
{
|
|
unsigned i;
|
|
BOOL Flushed = FALSE;
|
|
RPC_STATUS Status;
|
|
|
|
Status = EnterCriticalSectionWrapper(&CacheMutex);
|
|
if (Status)
|
|
{
|
|
return Flushed;
|
|
}
|
|
|
|
for (i=0; i < CACHE_SIZE; ++i)
|
|
{
|
|
if ( ServerCache[i].Name
|
|
&& 0 == RpcpStringCompareA(ServerCache[i].Name, Name))
|
|
{
|
|
if (GetTickCount() - ServerCache[i].Time > CACHE_EXPIRATION_TIME)
|
|
{
|
|
delete ServerCache[i].Name;
|
|
ServerCache[i].Name = 0;
|
|
Flushed = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSectionWrapper(&CacheMutex);
|
|
|
|
return Flushed;
|
|
}
|
|
|
|
void
|
|
CachedServerContacted(
|
|
char * Name
|
|
)
|
|
{
|
|
unsigned i;
|
|
RPC_STATUS Status;
|
|
|
|
Status = EnterCriticalSectionWrapper(&CacheMutex);
|
|
if (Status)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i=0; i < CACHE_SIZE; ++i)
|
|
{
|
|
if ( ServerCache[i].Name
|
|
&& 0 == RpcpStringCompareA(ServerCache[i].Name, Name))
|
|
{
|
|
ServerCache[i].Time = GetTickCount();
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSectionWrapper(&CacheMutex);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
LookupViaRnr(
|
|
char * Name,
|
|
SOCKADDR_IPX * Address,
|
|
unsigned Timeout
|
|
)
|
|
{
|
|
CSADDR_BUFFER csaddr[2];
|
|
int num;
|
|
INT protocol_list[2];
|
|
DWORD csaddr_size = sizeof(csaddr);
|
|
|
|
protocol_list[0] = NSPROTO_IPX ;
|
|
protocol_list[1] = 0;
|
|
num = GetAddressByNameA(NS_SAP,
|
|
(GUID *)&SERVICE_TYPE,
|
|
Name,
|
|
protocol_list,
|
|
0,
|
|
FALSE,
|
|
&csaddr,
|
|
&csaddr_size,
|
|
NULL,
|
|
0);
|
|
if (num <= 0)
|
|
{
|
|
return RPC_S_SERVER_UNAVAILABLE;
|
|
}
|
|
|
|
memcpy( Address, csaddr[0].info.RemoteAddr.lpSockaddr, sizeof(SOCKADDR_IPX) );
|
|
|
|
return(AddServerToCache(Name, Address));
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
LookupViaBindery(
|
|
char * Name,
|
|
SOCKADDR_IPX * Address,
|
|
unsigned Timeout
|
|
)
|
|
{
|
|
USHORT Connection;
|
|
USHORT NwStatus;
|
|
UCHAR MoreSegments;
|
|
UCHAR PropertyFlags;
|
|
UCHAR buffer[128];
|
|
|
|
RPC_STATUS Status;
|
|
|
|
Status = EnterCriticalSectionWrapper(&FileServerMutex);
|
|
if (Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find a Netware server and connect to it.
|
|
//
|
|
if (FALSE == AttachToFileServer())
|
|
{
|
|
LeaveCriticalSectionWrapper(&FileServerMutex);
|
|
|
|
return RPC_S_SERVER_UNAVAILABLE;
|
|
}
|
|
|
|
//
|
|
// Read from the bindery.
|
|
//
|
|
NwStatus = ReadPropertyValue( Name,
|
|
RPC_SAP_TYPE,
|
|
"NET_ADDRESS",
|
|
1,
|
|
buffer,
|
|
&MoreSegments,
|
|
&PropertyFlags
|
|
);
|
|
|
|
//
|
|
// Disconnect from the file server.
|
|
//
|
|
DetachFromActiveServer();
|
|
|
|
LeaveCriticalSectionWrapper(&FileServerMutex);
|
|
|
|
if (!NwStatus)
|
|
{
|
|
memcpy(&Address->sa_netnum, buffer, 12);
|
|
return(AddServerToCache(Name, Address));
|
|
}
|
|
|
|
return RPC_S_SERVER_UNAVAILABLE;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
IpxNameToAddress(
|
|
char * Name,
|
|
SOCKADDR_IPX * Address,
|
|
unsigned Timeout
|
|
)
|
|
{
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
|
|
Status = EnterCriticalSectionWrapper(&FileServerMutex);
|
|
if (Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (!fCsnwCheckCompleted)
|
|
{
|
|
CheckForCsnw();
|
|
}
|
|
|
|
LeaveCriticalSectionWrapper(&FileServerMutex);
|
|
|
|
if (fCsnwInstalled)
|
|
{
|
|
Status = LookupViaRnr(Name, Address, Timeout);
|
|
}
|
|
else
|
|
{
|
|
Status = LookupViaBindery(Name, Address, Timeout);
|
|
if ( Status != RPC_S_OK
|
|
&& Status != RPC_P_MATCHED_CACHE)
|
|
{
|
|
Status = LookupViaRnr(Name, Address, Timeout);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
void IPX_AddressToName(
|
|
IN SOCKADDR_IPX *pAddr,
|
|
OUT RPC_CHAR *pName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a raw IPX address into the string address format used
|
|
by RPC.
|
|
|
|
~NNNNNNNNAAAAAAAAAAAA
|
|
N - network number in hex
|
|
A - network address (IEEE 802) in hex
|
|
|
|
Arguments:
|
|
|
|
pAddr - The sockaddr containing the address to convert
|
|
pName - Will contain the string address on return, assumed
|
|
to be IPX_MAXIMUM_RAW_NAME characters.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
|
|
*pName++ = '~';
|
|
for (i = 0; i < sizeof(pAddr->sa_netnum); i++)
|
|
{
|
|
*pName++ = HexDigits[ (UCHAR)(pAddr->sa_netnum[i]) >> 4 ];
|
|
*pName++ = HexDigits[ (UCHAR)(pAddr->sa_netnum[i]) & 0x0F ];
|
|
}
|
|
for (i = 0; i < sizeof(pAddr->sa_nodenum); i++)
|
|
{
|
|
*pName++ = HexDigits[ (UCHAR)(pAddr->sa_nodenum[i]) >> 4 ];
|
|
*pName++ = HexDigits[ (UCHAR)(pAddr->sa_nodenum[i]) & 0x0F ];
|
|
}
|
|
*pName = 0;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
IPX_NameToAddress(
|
|
RPC_CHAR *Name,
|
|
BOOL fUseCache,
|
|
OUT SOCKADDR_IPX *pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a name into an IPX address if possible. Handles the
|
|
case of ~ names and pretty names.
|
|
|
|
Arguments:
|
|
|
|
Name - The name to convert
|
|
fUseCache - Usually TRUE, if which case a value cached from
|
|
a previous call with the same name maybe used. If FALSE,
|
|
then full name resolution must be used.
|
|
pAddr - Will overwrite the sa_netnum and sa_nodenum with the
|
|
IPX address if successful.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Full lookup, completed ok.
|
|
RPC_S_FOUND_IN_CACHE - Lookup completed and found in cache.
|
|
RPC_S_MATCHED_CACHE - Full lookup required (fUseCache == FALSE) but
|
|
results didn't change.
|
|
|
|
RPC_S_SERVER_UNAVAILABLE - Lookup failed.
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_OUT_OF_MEMORY
|
|
|
|
--*/
|
|
{
|
|
int length;
|
|
|
|
ASSERT(pAddr->sa_family == AF_IPX);
|
|
ASSERT(pAddr->sa_socket == 0);
|
|
|
|
//
|
|
// First see if the address is local.
|
|
//
|
|
if (Name == 0 || *Name == 0)
|
|
{
|
|
//
|
|
// Use the cached local address, if valid.
|
|
//
|
|
if (fIpxAddrValid == TRUE)
|
|
{
|
|
memcpy(pAddr->sa_netnum, IpxAddr.sa_netnum, 4);
|
|
memcpy(pAddr->sa_nodenum, IpxAddr.sa_nodenum, 6);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
//
|
|
// Figure out the loopback address, not a easy task on IPX.
|
|
//
|
|
|
|
SOCKET sock;
|
|
sock = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
//
|
|
switch(GetLastError())
|
|
{
|
|
case WSAEAFNOSUPPORT:
|
|
case WSAEPROTONOSUPPORT:
|
|
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
|
|
break;
|
|
|
|
case WSAENOBUFS:
|
|
case WSAEMFILE:
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// zero-out the netnum and nodenum members
|
|
memset(pAddr->sa_netnum, 0, sizeof(pAddr->sa_netnum));
|
|
memset(pAddr->sa_nodenum, 0, sizeof(pAddr->sa_nodenum));
|
|
|
|
if ( bind(sock, (PSOCKADDR)pAddr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR)
|
|
{
|
|
closesocket(sock);
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
int len = sizeof(SOCKADDR_IPX);
|
|
if ( getsockname(sock, (PSOCKADDR)pAddr, &len) == SOCKET_ERROR)
|
|
{
|
|
closesocket(sock);
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
// Update cache
|
|
memcpy(IpxAddr.sa_netnum, pAddr->sa_netnum, sizeof(IpxAddr.sa_netnum));
|
|
memcpy(IpxAddr.sa_nodenum, pAddr->sa_nodenum, sizeof(IpxAddr.sa_nodenum));
|
|
fIpxAddrValid = TRUE;
|
|
|
|
closesocket(sock);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
//
|
|
// Must resolve the name, validate and convert to ansi.
|
|
//
|
|
length = RpcpStringLength(Name) + 1;
|
|
|
|
if (length > IPX_MAXIMUM_PRETTY_NAME)
|
|
{
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
if ( *Name == RPC_T('~')
|
|
&& length != IPX_MAXIMUM_RAW_NAME)
|
|
{
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
|
|
CHAR AnsiName[IPX_MAXIMUM_PRETTY_NAME + 1];
|
|
RpcpMemorySet(&(AnsiName[0]), 0x00, IPX_MAXIMUM_PRETTY_NAME + 1);
|
|
PlatformToAnsi(Name, AnsiName);
|
|
|
|
//
|
|
// If the name starts with ~, convert it directly to a network address.
|
|
//
|
|
if (AnsiName[0] == '~')
|
|
{
|
|
|
|
ASSERT(Name[0] == RPC_T('~'));
|
|
|
|
int i;
|
|
PCHAR p = AnsiName;
|
|
|
|
|
|
p++; // Skip ~
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
pAddr->sa_netnum[i] = HexDigitsToBinary(*p, *(p+1));
|
|
p += 2;
|
|
}
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
pAddr->sa_nodenum[i] = HexDigitsToBinary(*p, *(p+1));
|
|
p += 2;
|
|
}
|
|
|
|
if (fUseCache)
|
|
{
|
|
return(RPC_S_OK);
|
|
}
|
|
else
|
|
{
|
|
return(RPC_P_MATCHED_CACHE);
|
|
}
|
|
}
|
|
|
|
if (fUseCache)
|
|
{
|
|
UINT t = 0;
|
|
//
|
|
// Look up the server in the name cache.
|
|
//
|
|
if (FindServerInCache(AnsiName, pAddr, &t))
|
|
{
|
|
return(RPC_P_FOUND_IN_CACHE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Gotta go look for it.
|
|
//
|
|
|
|
RPC_STATUS status = IpxNameToAddress(AnsiName, pAddr, 0);
|
|
|
|
if ( (status == RPC_P_MATCHED_CACHE)
|
|
&& fUseCache)
|
|
{
|
|
// Race - another thread added the name to the cache
|
|
// while we did the lookup.
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
BOOL fIpxAddrValid = FALSE;
|
|
SOCKADDR_IPX IpxAddr;
|
|
|
|
RPC_STATUS
|
|
IPX_BuildAddressVector(
|
|
OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Use by both IPX and SPX RPC servers to build the network
|
|
address structure to be returned to the RPC runtime.
|
|
Before calling this the caller must make sure the global
|
|
fIpxAddrValid is TRUE.
|
|
|
|
Arguments:
|
|
|
|
ppAddressVector - The place to store the constructed address
|
|
vector.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_OUT_OF_MEMORY
|
|
|
|
--*/
|
|
{
|
|
NETWORK_ADDRESS_VECTOR *pVector;
|
|
|
|
pVector = new( sizeof(RPC_CHAR *)
|
|
+ gdwComputerNameLength * sizeof(RPC_CHAR))
|
|
NETWORK_ADDRESS_VECTOR;
|
|
|
|
if (NULL == pVector)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
pVector->Count = 1;
|
|
pVector->NetworkAddresses[0] = (RPC_CHAR*)&pVector->NetworkAddresses[1];
|
|
RpcpStringCopy(pVector->NetworkAddresses[0], gpstrComputerName);
|
|
|
|
*ppAddressVector = pVector;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|