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.
 
 
 
 
 
 

1000 lines
23 KiB

/* --------------------------------------------------------------------
File : tcltclnt.c
Title : client loadable transport for DOS TCP/IP - client side
Description :
History :
6-26-91 Jim Teague Initial version.
-------------------------------------------------------------------- */
#define MAX_HOSTPORTSIZE 32
#define TCP_MAXIMUM_SEND ((3 * 1450) & 0xFFF8)
#define ENDIAN_MASK 16
#include <stdlib.h>
#include <string.h>
#include "sysinc.h"
#include "rpc.h"
#include "rpcdcep.h"
#include "rpctran.h"
#include "rpcerrp.h"
#include "winsock.h"
#include <stdlib.h>
#include <stdarg.h>
#include "callback.h"
//
// To satisfy the compiler...
//
#ifndef WIN
#define errno _FakeErrno
int _FakeErrno;
#endif
typedef struct
{
unsigned char rpc_vers;
unsigned char rpc_vers_minor;
unsigned char PTYPE;
unsigned char pfc_flags;
unsigned char drep[4];
unsigned short frag_length;
unsigned short auth_length;
unsigned long call_id;
} message_header;
typedef struct
{
int Socket;
HWND hWnd;
HANDLE hYield;
unsigned long TickCount;
char PAPI * Buffer;
message_header PeekedMessage;
unsigned short State;
unsigned short PeekInfo;
unsigned short fCallComplete ;
unsigned short fLocalYield ;
int AsyncStatus ;
} CONNECTION, *PCONNECTION;
near_printf(const char *format, ...);
#define ByteSwapLong(Value) \
Value = ( (((Value) & 0xFF000000) >> 24) \
| (((Value) & 0x00FF0000) >> 8) \
| (((Value) & 0x0000FF00) << 8) \
| (((Value) & 0x000000FF) << 24))
#define ByteSwapShort(Value) \
Value = ( (((Value) & 0x00FF) << 8) \
| (((Value) & 0xFF00) >> 8))
#define WNDCLASSNAME "TCLTCLNT"
#define WNDTEXT "RPC TCP/IP"
#define WM_ASYNC_EVENT WM_USER + 9
/*
Following Macros and structs are needed for Tower Stuff
*/
#pragma pack(1)
#define TCP_TRANSPORTID 0x07
#define TCP_TRANSPORTHOSTID 0x09
#define TCP_TOWERFLOORS 5
#define TCP_IP_EP "135"
#define TCP_PROTSEQ "ncacn_ip_tcp"
typedef struct _FLOOR_234 {
unsigned short ProtocolIdByteCount;
unsigned char FloorId;
unsigned short AddressByteCount;
unsigned char Data[2];
} FLOOR_234, PAPI * PFLOOR_234;
#define NEXTFLOOR(t,x) (t)((unsigned char PAPI *)x +((t)x)->ProtocolIdByteCount\
+ ((t)x)->AddressByteCount\
+ sizeof(((t)x)->ProtocolIdByteCount)\
+ sizeof(((t)x)->AddressByteCount))
/*
End of Tower Stuff!
*/
#pragma pack()
#define MAXTICKSBEFOREPEEK 12
#define NOPENDINGRPC 0
#define RPCINITIATED 1
#define NOPEEKINFO 0
#define PEEKEDHEADER 1
#define rpc_shutdown 17
#define rpc_fault 3
extern void (_far pascal _far *DllTermination)(void);
extern HINSTANCE hInstanceDLL;
void LocalBlockingFunc(PCONNECTION pConn) ;
int DoAsyncConnect(
IN PCONNECTION pConn,
IN struct sockaddr _far *server,
IN int size)
{
int status ;
status = connect(pConn->Socket, server, size) ;
if (status == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
do
{
if (LocalBlock(pConn, FD_CONNECT|FD_WRITE) != 0)
return SOCKET_ERROR ;
}
while ( pConn->fCallComplete == FALSE);
if (pConn->AsyncStatus != 0)
{
return SOCKET_ERROR ;
}
}
else
{
return SOCKET_ERROR ;
}
}
return 0 ;
}
int DoAsyncGetHostByName(
PCONNECTION pConn,
IN unsigned char __far *NetworkAddress,
OUT struct hostent __far *hostentry,
IN int size
)
{
HANDLE taskHandle ;
int i = 10;
while (i--)
{
pConn->fCallComplete = FALSE ;
pConn->fLocalYield = TRUE ;
if ((taskHandle = WSAAsyncGetHostByName(pConn->hWnd,
WM_ASYNC_EVENT, NetworkAddress,
(char __far *) hostentry, size)) == 0)
{
return SOCKET_ERROR ;
}
LocalBlockingFunc(pConn) ;
if (pConn->fCallComplete)
{
return pConn->AsyncStatus ? SOCKET_ERROR:0 ;
}
WSACancelAsyncRequest(taskHandle) ;
}
return SOCKET_ERROR ;
}
RPC_TRANS_STATUS RPC_ENTRY
ClientOpen (
IN PCONNECTION pConn,
IN unsigned char _far * NetworkAddress,
IN unsigned char _far * Endpoint,
IN unsigned char _far * NetworkOptions,
IN unsigned char _far * TransportAddress,
IN unsigned char _far * RpcProtocolSequence,
IN unsigned int Timeout
)
// Open a client connection
{
struct sockaddr_in server;
struct hostent __far *hostentry;
WSADATA WSAData;
int NumericEndpoint;
int i;
int bool_on = 1;
unsigned long nobio = 1;
int status ;
RPC_TRANS_STATUS Status ;
// It is safe to call WSAStartup multiple times in the context of the
// same task. For case 2 on it simply increments a counter.
if (WSAStartup(0x0101, &WSAData)) {
return (RPC_S_OUT_OF_RESOURCES);
}
if (NetworkAddress == NULL || NetworkAddress[0] == '\0') {
NetworkAddress = "127.0.0.1";
}
hostentry = (struct hostent __far *) I_RpcAllocate(MAXGETHOSTSTRUCT) ;
if (hostentry == NULL)
{
return (RPC_S_OUT_OF_MEMORY) ;
}
// Create hidden window to receive Async messages
pConn->hWnd = CreateWindow(WNDCLASSNAME,
WNDTEXT,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
(HWND)NULL,
(HMENU)NULL,
hInstanceDLL,
(LPVOID)0);
if (!pConn->hWnd)
{
I_RpcFree(hostentry) ;
WSACleanup();
return (RPC_S_OUT_OF_RESOURCES);
}
UpdateWindow(pConn->hWnd);
ShowWindow(pConn->hWnd, SW_HIDE);
SetWindowLong(pConn->hWnd, 0, (LONG)pConn);
pConn->hYield = (HANDLE)NULL;
//
// See if host address is in numeric format...
//
if ((i = strcspn(NetworkAddress,".0123456789")) == 0) {
server.sin_addr.s_addr = inet_addr(NetworkAddress);
} else {
status = DoAsyncGetHostByName(pConn,
NetworkAddress,
(struct hostent __far *) hostentry,
MAXGETHOSTSTRUCT);
if (status == SOCKET_ERROR ) {
Status = RPC_S_SERVER_UNAVAILABLE ;
goto cleanup ;
}
memcpy((char _far *) &server.sin_addr.s_addr,
(char _far *) hostentry->h_addr,
hostentry->h_length);
}
NumericEndpoint = atoi(Endpoint);
if (_fstrcspn(Endpoint, "0123456789") || NumericEndpoint == 0) {
Status = RPC_S_INVALID_ENDPOINT_FORMAT ;
goto cleanup ;
}
server.sin_family = AF_INET;
server.sin_port = htons(NumericEndpoint);
//
// Get a socket
//
if ((pConn->Socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
Status = RPC_S_OUT_OF_RESOURCES ;
goto cleanup ;
}
ioctlsocket(pConn->Socket, FIONBIO, &nobio);
setsockopt(pConn->Socket, IPPROTO_TCP, TCP_NODELAY,
(char FAR *) &bool_on, sizeof(int));
pConn->State = NOPENDINGRPC;
pConn->PeekInfo = NOPEEKINFO;
pConn->TickCount = time(0);
//
// Try to connect...
//
if (DoAsyncConnect(pConn, (struct sockaddr _far *) &server,
sizeof (server)) < 0) {
closesocket(pConn->Socket);
Status = RPC_S_SERVER_UNAVAILABLE ;
goto cleanup ;
}
return (RPC_S_OK);
cleanup:
WSACleanup();
I_RpcFree(hostentry) ;
DestroyWindow(pConn->hWnd);
return Status ;
}
RPC_TRANS_STATUS RPC_ENTRY
ClientClose (
IN PCONNECTION pConn
)
// Close a client connection
{
// Don't close a connection that is already closed...
closesocket(pConn->Socket);
// WSACleanup required for each task. Calling once per connection is safe.
// If connection is the last connection for the task, then actual cleanup
// will occur.
WSACleanup();
//
// Under some circumstances DestroyWindow causes a NFY_TASKOUT notification
// so don't do it if we are already handling NFY_TASKEXIT.
//
if (FALSE == RpcRuntimeInfo->TaskExiting)
{
DestroyWindow(pConn->hWnd);
}
return (RPC_S_OK);
}
RPC_TRANS_STATUS RPC_ENTRY
ClientWrite (
IN PCONNECTION pConn,
IN void _far * Buffer,
IN unsigned int BufferLength
)
{
int bytes;
unsigned long PrevTicks;
struct timeval Timeout;
int Status;
int total_bytes = 0 ;
if (pConn->State == NOPENDINGRPC)
{
//First Send
PrevTicks = pConn->TickCount;
pConn->TickCount = time(0);
if ( (pConn->TickCount - PrevTicks) > MAXTICKSBEFOREPEEK )
{
fd_set TmpSet;
FD_ZERO(&TmpSet);
FD_SET(pConn->Socket, &TmpSet);
Timeout.tv_sec = 0;
Timeout.tv_usec = 0;
// this call is non blocking because we are calling
// it with a 0 timeout.
Status = select(
1,
&TmpSet,
0,
0,
&Timeout
);
if (Status == SOCKET_ERROR)
{
ClientClose(pConn);
return (RPC_P_SEND_FAILED);
}
if (Status != 0)
{
bytes = RecvWithYield(
pConn,
&pConn->PeekedMessage,
sizeof(message_header)
);
if (bytes == 0) {
ClientClose(pConn);
return(RPC_P_CONNECTION_SHUTDOWN);
}
if (bytes == SOCKET_ERROR) {
ClientClose(pConn);
return (RPC_P_SEND_FAILED);
}
if ( (pConn->PeekedMessage.PTYPE == rpc_fault)
||(pConn->PeekedMessage.PTYPE == rpc_shutdown) )
{
ClientClose(pConn);
return(RPC_P_CONNECTION_SHUTDOWN);
}
else
{
pConn->PeekInfo = PEEKEDHEADER;
}
}
}
pConn->State = RPCINITIATED;
}
while (total_bytes < BufferLength)
{
bytes = send(pConn->Socket, (char _far *) Buffer+total_bytes,
(int) BufferLength-total_bytes, 0);
if (bytes == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
if (LocalBlock(pConn, FD_WRITE|FD_CLOSE) == SOCKET_ERROR)
{
return (RPC_P_SEND_FAILED) ;
}
continue;
}
ClientClose(pConn);
return(RPC_P_SEND_FAILED);
}
total_bytes += bytes ;
}
return(RPC_S_OK);
}
LONG FAR PASCAL _loadds
AsyncEventProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
PCONNECTION pConn;
switch (msg) {
case WM_ASYNC_EVENT:
pConn = (PCONNECTION)GetWindowLong(hWnd, 0);
pConn->fCallComplete = TRUE ;
pConn->AsyncStatus = WSAGETASYNCERROR(lParam) ;
if (pConn->fLocalYield == FALSE)
{
I_RpcWinAsyncCallComplete(pConn);
}
return (TRUE);
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
#define TIMEOUT 2000
int BlockForRecv(PCONNECTION pConn)
{
//if ( pConn->hYield == 0 )
//{
//I_RpcWinAsyncCallEnd(pConn->hYield);
//return(SOCKET_ERROR);
//}
pConn->fLocalYield = FALSE ;
if (WSAAsyncSelect(pConn->Socket, pConn->hWnd,
WM_ASYNC_EVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
return (SOCKET_ERROR) ;
}
if (I_RpcWinAsyncCallWait(pConn->hYield, pConn->hWnd, TIMEOUT) ==
RPC_WIN_WAIT_ABORTED)
{
WSAAsyncSelect(pConn->Socket, pConn->hWnd, 0, 0) ;
return(SOCKET_ERROR);
}
if (WSAAsyncSelect(pConn->Socket, pConn->hWnd, 0, 0) == SOCKET_ERROR)
{
return (SOCKET_ERROR) ;
}
return 0 ;
}
void LocalBlockingFunc(PCONNECTION pConn)
{
MSG wMsg;
DWORD dwYieldTime ;
int Mask;
dwYieldTime = GetCurrentTime() + 20000 ;
Mask = PM_REMOVE;
if (I_RpcWinIsTaskYielding(pConn->hYield) == FALSE)
{
Mask |= PM_NOYIELD;
}
while (!pConn->fCallComplete && GetCurrentTime() < dwYieldTime)
{
if (PeekMessage(&wMsg, pConn->hWnd, 0, 0, Mask))
{
TranslateMessage(&wMsg);
DispatchMessage(&wMsg);
}
}
}
int LocalBlock(PCONNECTION pConn,
int Flags)
{
pConn->fLocalYield = TRUE ;
pConn->fCallComplete = FALSE ;
if (WSAAsyncSelect(pConn->Socket, pConn->hWnd, WM_ASYNC_EVENT, Flags)
== SOCKET_ERROR)
{
return (SOCKET_ERROR) ;
}
LocalBlockingFunc(pConn) ;
if (WSAAsyncSelect(pConn->Socket, pConn->hWnd, 0, 0) == SOCKET_ERROR)
{
ASSERT(0) ;
return (SOCKET_ERROR) ;
}
return 0;
}
int
RecvWithYield(PCONNECTION pConn,
char _far * buf,
int bufsiz)
{
int bytes, remaining;
int status;
pConn->hYield = I_RpcWinAsyncCallBegin(pConn);
remaining = bufsiz;
while (remaining > 0) {
bytes = recv( pConn->Socket, buf, remaining, 0);
if (bytes == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
status = BlockForRecv(pConn) ;
if (status != 0)
{
I_RpcWinAsyncCallEnd(pConn->hYield);
return status ;
}
continue;
}
I_RpcWinAsyncCallEnd(pConn->hYield);
return (SOCKET_ERROR);
}
if (bytes == 0) {
I_RpcWinAsyncCallEnd(pConn->hYield);
return (0);
}
buf += bytes;
remaining -= bytes;
}
I_RpcWinAsyncCallEnd(pConn->hYield);
return (bufsiz);
}
RPC_TRANS_STATUS RPC_ENTRY
ClientRead (
IN PCONNECTION pConn,
IN OUT void _far * _far * Buffer,
IN OUT unsigned int _far * BufferLength
)
// Read a message from a connection.
{
int bytes;
unsigned short total_bytes;
message_header header;
unsigned short native_length;
RPC_STATUS status;
pConn->State = NOPENDINGRPC;
//
// Read protocol header to see how big
// the record is...
//
if (pConn->PeekInfo == PEEKEDHEADER)
{
memcpy((char _far *)&header,&pConn->PeekedMessage,
sizeof(message_header));
bytes = sizeof(message_header);
pConn->PeekInfo = NOPEEKINFO;
}
else
{
bytes = RecvWithYield(
pConn,
(char _far *)&header,
sizeof (message_header)
);
}
if (bytes != sizeof(message_header))
{
ClientClose(pConn);
return (RPC_P_RECEIVE_FAILED);
}
//
// If this fragment header comes from a reverse-endian machine,
// we will need to swap the bytes of the frag_length field...
//
if ( (header.drep[0] & ENDIAN_MASK) == 0)
{
// Big endian...swap
//
((unsigned char _far *) &native_length)[0] =
((unsigned char _far *) &header.frag_length)[1];
((unsigned char _far *) &native_length)[1] =
((unsigned char _far *) &header.frag_length)[0];
}
else
// Little endian, just like us...
//
native_length = header.frag_length;
//
// Make sure buffer is big enough. If it isn't, then go back
// to the runtime to reallocate it.
//
if (native_length > *BufferLength)
{
status = I_RpcTransClientReallocBuffer (pConn,
Buffer,
0,
native_length);
if (status)
{
ClientClose(pConn);
return (RPC_S_OUT_OF_MEMORY);
}
}
*BufferLength = native_length;
//
// Read message segments until we get what we expect...
//
memcpy (*Buffer, &header, sizeof(message_header));
total_bytes = sizeof(message_header);
while (total_bytes < native_length)
{
if((bytes = recv( pConn->Socket,
(unsigned char _far *) *Buffer + total_bytes,
(int) (*BufferLength - total_bytes), 0)) == -1)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
if (LocalBlock(pConn, FD_READ|FD_CLOSE) == SOCKET_ERROR)
{
return (RPC_P_RECEIVE_FAILED) ;
}
continue;
}
ClientClose(pConn);
return (RPC_P_RECEIVE_FAILED);
}
else
total_bytes += bytes;
}
return(RPC_S_OK);
}
#pragma pack(1)
RPC_STATUS RPC_ENTRY
ClientTowerConstruct(
IN char PAPI * Endpoint,
IN char PAPI * NetworkAddress,
OUT unsigned short PAPI * Floors,
OUT unsigned long PAPI * ByteCount,
OUT unsigned char PAPI * PAPI * Tower,
IN char PAPI * Protseq
)
/*++
Routine Description:
This function constructs upper floors of DCE tower from
the supplied endpoint and network address. It returns #of floors
[lower+upper] for this protocol/transport, bytes in upper floors
and the tower [floors 4,5]
Arguments:
Endpoint- A pointer to string representation of Endpoint
NetworkAddress - A pointer to string representation of NW Address
Floors - A pointer to #of floors in the tower
ByteCount - Size of upper floors of tower.
Tower - The constructed tower returmed - The memory is allocated
by the routine and caller will have to free it.
Return Value:
RPC_S_OK
RPC_S_OUT_OF_MEMORY - There is no memory to return the constructed
Tower.
--*/
{
unsigned long TowerSize, * HostId, hostval;
unsigned short * Port, portnum;
PFLOOR_234 Floor;
if (Protseq);
*Floors = TCP_TOWERFLOORS;
TowerSize = 6; /*Endpoint = 2 bytes, HostId = 4 bytes*/
TowerSize += 2*sizeof(FLOOR_234) - 4;
if ((*Tower = (unsigned char PAPI*)I_RpcAllocate((unsigned int)
(*ByteCount = TowerSize)))
== NULL)
{
return (RPC_S_OUT_OF_MEMORY);
}
Floor = (PFLOOR_234) *Tower;
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(TCP_TRANSPORTID & 0xFF);
Floor->AddressByteCount = 2;
Port = (unsigned short *) &Floor->Data[0];
if (Endpoint == NULL || *Endpoint == '\0')
{
Endpoint = TCP_IP_EP;
}
*Port = htons ( atoi (Endpoint));
//Onto the next floor
Floor = NEXTFLOOR(PFLOOR_234, Floor);
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(TCP_TRANSPORTHOSTID & 0xFF);
Floor->AddressByteCount = 4;
HostId = (unsigned long *)&Floor->Data[0];
if ((NetworkAddress) && (*NetworkAddress))
{
*HostId = inet_addr((char *) NetworkAddress);
}
else
{
*HostId = 0;
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientTowerExplode(
IN unsigned char PAPI * Tower,
OUT char PAPI * PAPI * Protseq,
OUT char PAPI * PAPI * Endpoint,
OUT char PAPI * PAPI * NetworkAddress
)
{
/*++
Routine Description:
This function takes the protocol/transport specific floors
and returns Protseq, Endpoint and NwAddress
Note: Since ther is no need to return NW Address, currently
nothing is done for NW Address.
Arguments:
Tower - The DCE tower, upper floors
Protseq - Protocol Sequence returned- memory is allocated by the
routine and caller will have to free using I_RpcFree
Endpoitn- Endpoint returned- memory is allocated by the
routine and caller will have to free using I_RpcFree
NWAddress- Nothing is done here - just incase we need it later
Return Value:
RPC_S_OK
RPC_S_OUT_OF_MEMORY - There is no memory to return the constructed
Tower.
--*/
PFLOOR_234 Floor = (PFLOOR_234) Tower;
RPC_STATUS Status = RPC_S_OK;
unsigned short portnum, *Port;
if (Protseq != NULL)
{
*Protseq = (char PAPI *) I_RpcAllocate(strlen(TCP_PROTSEQ) + 1);
if (*Protseq == NULL)
Status = RPC_S_OUT_OF_MEMORY;
else
memcpy(*Protseq, TCP_PROTSEQ, strlen(TCP_PROTSEQ) + 1);
}
if ((Endpoint == NULL) || (Status != RPC_S_OK))
{
return (Status);
}
*Endpoint = (char PAPI *) I_RpcAllocate(6); //Ports are all <64K [5 decimal dig +1]
if (*Endpoint == NULL)
{
Status = RPC_S_OUT_OF_MEMORY;
}
else
{
Port = (unsigned short *)&Floor->Data[0];
portnum = *Port;
_itoa(ByteSwapShort(portnum), *Endpoint, 10);
}
return(Status);
}
#pragma pack()
RPC_CLIENT_TRANSPORT_INFO TransInfo =
{
RPC_TRANSPORT_INTERFACE_VERSION,
TCP_TRANSPORTID,
ClientTowerConstruct,
ClientTowerExplode,
TCP_MAXIMUM_SEND,
sizeof (CONNECTION),
ClientOpen,
ClientClose,
ClientWrite,
ClientRead,
NULL,
0,
0,
0
};
void __far __pascal MyWep(void);
RPC_CLIENT_TRANSPORT_INFO _far * RPC_ENTRY TransPortLoad (
IN RPC_CHAR _far * RpcProtocolSequence,
IN RPC_CLIENT_RUNTIME_INFO PAPI * RpcClientRuntimeInfo
)
// Loadable transport initialization function
{
WNDCLASS wc;
WSADATA WSAData;
wc.style = WS_OVERLAPPED;
wc.lpfnWndProc = (WNDPROC) AsyncEventProc;
wc.cbWndExtra = sizeof(PCONNECTION);
wc.cbClsExtra = 0;
wc.hInstance = hInstanceDLL;
wc.hIcon = (HICON) NULL;
wc.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WNDCLASSNAME;
RegisterClass(&wc);
RpcRuntimeInfo = RpcClientRuntimeInfo;
AsyncCallComplete = RpcRuntimeInfo->AsyncCallComplete;
DllTermination = MyWep;
return(&TransInfo);
}
void __far __pascal
MyWep(void)
{
// UnregisterClass(WNDCLASSNAME, hInstanceDLL) ;
if (0 != GetModuleHandle("WINSOCK"))
{
WSACleanup();
}
}
#ifdef DEBUGRPC
void __far I_RpcWinAssert(char __far *con,
char __far *file,
unsigned long line)
{
static char T[10];
_ultoa(line, T, 10);
OutputDebugString("Assertiong failed: ");
OutputDebugString(file);
OutputDebugString("(");
OutputDebugString(T);
OutputDebugString(") : ");
OutputDebugString(con);
__asm { int 3 }
return;
}
#endif