1268 lines
35 KiB
C++
1268 lines
35 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2001 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// tdisample.cpp
|
|
//
|
|
// Abstract:
|
|
// test executable--demonstrates the tdi client by calling it via the library
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "libbase.h"
|
|
|
|
const ULONG MAX_ADDRESS_SIZE = sizeof(TRANSPORT_ADDRESS) + TDI_ADDRESS_LENGTH_OSI_TSAP;
|
|
const USHORT DGRAM_SERVER_PORT = 0x5555;
|
|
const USHORT DGRAM_CLIENT_PORT = 0x4444;
|
|
const USHORT CONN_SERVER_PORT = 0x5656;
|
|
const USHORT CONN_CLIENT_PORT = 0x4545;
|
|
|
|
VOID
|
|
ServerTest(ULONG ulType,
|
|
ULONG ulNumDevices);
|
|
|
|
|
|
VOID
|
|
ClientTest(ULONG ulType,
|
|
ULONG ulNumDevices);
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: main
|
|
//
|
|
// Descript: parse the arguments to the program, initialize library and driver,
|
|
// then call client or server side of test
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
|
|
int __cdecl main(ULONG argc, TCHAR *argv[])
|
|
{
|
|
//
|
|
// first step: get the arguments for this run
|
|
//
|
|
BOOLEAN fIsServer = FALSE;
|
|
ULONG ulType = TDI_ADDRESS_TYPE_UNSPEC;
|
|
BOOLEAN fArgsOk = FALSE;
|
|
TCHAR *pArgStr;
|
|
|
|
if(argc > 1)
|
|
{
|
|
for(ULONG ulArg = 1; ulArg < argc; ulArg++)
|
|
{
|
|
pArgStr = argv[ulArg];
|
|
if ((*pArgStr == TEXT('/')) || (*pArgStr == TEXT('-')))
|
|
{
|
|
pArgStr++;
|
|
}
|
|
if (_tcsicmp(pArgStr, TEXT("server")) == 0)
|
|
{
|
|
if (fIsServer)
|
|
{
|
|
fArgsOk = FALSE;
|
|
break;
|
|
}
|
|
fIsServer = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fArgsOk = FALSE;
|
|
if (ulType)
|
|
{
|
|
break;
|
|
}
|
|
if (_tcsicmp(pArgStr, TEXT("ipx")) == 0)
|
|
{
|
|
fArgsOk = TRUE;
|
|
ulType = TDI_ADDRESS_TYPE_IPX;
|
|
}
|
|
else if (_tcsicmp(pArgStr, TEXT("ipv4")) == 0)
|
|
{
|
|
fArgsOk = TRUE;
|
|
ulType = TDI_ADDRESS_TYPE_IP;
|
|
}
|
|
else if (_tcsicmp(pArgStr, TEXT("netbt")) == 0)
|
|
{
|
|
fArgsOk = TRUE;
|
|
ulType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!fArgsOk)
|
|
{
|
|
_putts(TEXT("Usage: tdisample [/server] [/ipx | /ipv4 | /netbt] \n"));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// ready to go. Initialize the library, connect to the driver, etc
|
|
//
|
|
if (TdiLibInit())
|
|
{
|
|
//
|
|
// change this to limit debug output for kernel mode driver
|
|
// 0 = none, 1 = commands, 2 = handlers, 3 = both
|
|
//
|
|
DoDebugLevel(0x03);
|
|
ULONG ulNumDevices = DoGetNumDevices(ulType);
|
|
if (ulNumDevices)
|
|
{
|
|
if (fIsServer)
|
|
{
|
|
ServerTest(ulType, ulNumDevices);
|
|
}
|
|
else
|
|
{
|
|
ClientTest(ulType, ulNumDevices);
|
|
}
|
|
}
|
|
TdiLibClose();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// server-side test functions
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG_PTR
|
|
__cdecl
|
|
ServerThread(LPVOID pvDummy);
|
|
|
|
|
|
BOOLEAN WaitForClient(
|
|
ULONG TdiHandle,
|
|
PTRANSPORT_ADDRESS pRemoteAddr
|
|
);
|
|
|
|
CRITICAL_SECTION CriticalSection;
|
|
HANDLE hEvent;
|
|
ULONG ulServerCount;
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: IncServerCount
|
|
//
|
|
// Descript: multi-thread safe incrementing of server count
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
VOID IncServerCount()
|
|
{
|
|
EnterCriticalSection(&CriticalSection);
|
|
++ulServerCount;
|
|
LeaveCriticalSection(&CriticalSection);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: DecServerCount
|
|
//
|
|
// Descript: multi-thread safe decrementing of server count
|
|
// when last one done, sets event
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
VOID DecServerCount()
|
|
{
|
|
BOOLEAN fDone = FALSE;
|
|
|
|
EnterCriticalSection(&CriticalSection);
|
|
--ulServerCount;
|
|
if (!ulServerCount)
|
|
{
|
|
fDone = TRUE;
|
|
}
|
|
LeaveCriticalSection(&CriticalSection);
|
|
if (fDone)
|
|
{
|
|
SetEvent(hEvent);
|
|
}
|
|
}
|
|
|
|
struct THREAD_DATA
|
|
{
|
|
ULONG ulType;
|
|
ULONG ulSlot;
|
|
};
|
|
typedef THREAD_DATA *PTHREAD_DATA;
|
|
|
|
// ----------------------------------------------
|
|
//
|
|
// Function: ServerTest
|
|
//
|
|
// Arguments: ulType -- protocol type to use
|
|
// NumDevices -- number of devices of this protocol type
|
|
//
|
|
// Descript: this function controls the server side of the test
|
|
//
|
|
// ----------------------------------------------
|
|
|
|
|
|
VOID
|
|
ServerTest(ULONG ulType, ULONG ulNumDevices)
|
|
{
|
|
//
|
|
// initialize globals
|
|
//
|
|
try
|
|
{
|
|
InitializeCriticalSection(&CriticalSection);
|
|
}
|
|
catch(...)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
hEvent = CreateEvent(NULL,
|
|
TRUE, // manual reset
|
|
FALSE, // starts reset
|
|
NULL);
|
|
ulServerCount = 1; // a single bogus reference, so event doesn't fire prematurely
|
|
|
|
|
|
|
|
//
|
|
// go thru our list of nodes, starting a thread for each one
|
|
//
|
|
for(ULONG ulCount = 0; ulCount < ulNumDevices; ulCount++)
|
|
{
|
|
ULONG ulThreadId;
|
|
PTHREAD_DATA pThreadData = (PTHREAD_DATA)LocalAllocateMemory(sizeof(THREAD_DATA));
|
|
if (!pThreadData)
|
|
{
|
|
_putts(TEXT("ServerTest: unable to allocate memory for pThreadData\n"));
|
|
break;
|
|
}
|
|
|
|
pThreadData->ulType = ulType;
|
|
pThreadData->ulSlot = ulCount;
|
|
|
|
//
|
|
// reference for one starting now
|
|
//
|
|
IncServerCount();
|
|
|
|
HANDLE hThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)ServerThread,
|
|
(LPVOID)pThreadData,
|
|
0,
|
|
&ulThreadId);
|
|
|
|
if (!hThread)
|
|
{
|
|
_putts(TEXT("ServerTest: failed starting server thread\n"));
|
|
DecServerCount();
|
|
}
|
|
Sleep(100);
|
|
}
|
|
|
|
//
|
|
// get rid of bogus reference
|
|
//
|
|
DecServerCount();
|
|
|
|
//
|
|
// wait until all the threads have completed
|
|
//
|
|
WaitForSingleObject(hEvent, INFINITE);
|
|
|
|
//
|
|
// cleanup
|
|
//
|
|
CloseHandle(hEvent);
|
|
DeleteCriticalSection(&CriticalSection);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: ServerThread
|
|
//
|
|
// Arguments: pvData -- actually pThreadData for this server
|
|
//
|
|
// Descript: This is the thread that runs for each server instance
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
ULONG_PTR
|
|
__cdecl
|
|
ServerThread(LPVOID pvData)
|
|
{
|
|
PTHREAD_DATA pThreadData = (PTHREAD_DATA)pvData;
|
|
PTRANSPORT_ADDRESS pTransAddr = NULL;
|
|
PTRANSPORT_ADDRESS pRemoteAddr = NULL;
|
|
TCHAR *pDeviceName = NULL;
|
|
BOOLEAN fSuccessful = FALSE;
|
|
|
|
while (TRUE)
|
|
{
|
|
//
|
|
// stores local interface address (server)
|
|
//
|
|
pTransAddr = (PTRANSPORT_ADDRESS)LocalAllocateMemory(MAX_ADDRESS_SIZE);
|
|
if (!pTransAddr)
|
|
{
|
|
_putts(TEXT("ServerThread: unable to allocate memory for pTransAddr\n"));
|
|
break;
|
|
}
|
|
pTransAddr->TAAddressCount = 1;
|
|
|
|
//
|
|
// stores remote interface address (client)
|
|
//
|
|
pRemoteAddr = (PTRANSPORT_ADDRESS)LocalAllocateMemory(MAX_ADDRESS_SIZE);
|
|
if (!pRemoteAddr)
|
|
{
|
|
_putts(TEXT("ServerThread: unable to allocate memory for pRemoteAddr\n"));
|
|
break;
|
|
}
|
|
pRemoteAddr->TAAddressCount = 1;
|
|
|
|
//
|
|
// stores local interface name (server)
|
|
//
|
|
pDeviceName = (TCHAR *)LocalAllocateMemory(256 * sizeof(TCHAR));
|
|
if (!pDeviceName)
|
|
{
|
|
_putts(TEXT("ServerThread: unable to allocate memory for pDeviceName\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// get name of local device
|
|
//
|
|
if (DoGetDeviceName(pThreadData->ulType, pThreadData->ulSlot, pDeviceName) != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
TCHAR *pDataDeviceName = NULL;
|
|
TCHAR *pConnDeviceName = NULL;
|
|
|
|
//
|
|
// for netbios, each "address" has its own name. You open a device based mostly on the name
|
|
//
|
|
if (pThreadData->ulType == TDI_ADDRESS_TYPE_NETBIOS)
|
|
{
|
|
pDataDeviceName = pDeviceName;
|
|
pConnDeviceName = pDeviceName;
|
|
|
|
PTA_NETBIOS_ADDRESS pTaAddr = (PTA_NETBIOS_ADDRESS)pTransAddr;
|
|
|
|
pTaAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
pTaAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
|
|
pTaAddr->Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
memcpy(pTaAddr->Address[0].Address[0].NetbiosName, "SERVER", 7); // NOTE: ascii string
|
|
}
|
|
|
|
//
|
|
// for others, there is one name for the datagram device and another for the "connected"
|
|
// device. You open an interface based largely on the address
|
|
//
|
|
else
|
|
{
|
|
if (DoGetAddress(pThreadData->ulType, pThreadData->ulSlot, pTransAddr) != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch (pThreadData->ulType)
|
|
{
|
|
case TDI_ADDRESS_TYPE_IPX:
|
|
{
|
|
PTA_IPX_ADDRESS pAddr = (PTA_IPX_ADDRESS)pTransAddr;
|
|
pAddr->Address[0].Address[0].Socket = DGRAM_SERVER_PORT;
|
|
|
|
pDataDeviceName = TEXT("\\device\\nwlnkipx");
|
|
pConnDeviceName = TEXT("\\device\\nwlnkspx");
|
|
break;
|
|
}
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
{
|
|
PTA_IP_ADDRESS pAddr = (PTA_IP_ADDRESS)pTransAddr;
|
|
pAddr->Address[0].Address[0].sin_port = DGRAM_SERVER_PORT;
|
|
|
|
pDataDeviceName = TEXT("\\device\\udp");
|
|
pConnDeviceName = TEXT("\\device\\tcp");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
_tprintf(TEXT("ServerThread: DeviceName: %s\n"), pDeviceName);
|
|
_putts(TEXT("Device Address:\n"));
|
|
DoPrintAddress(pTransAddr);
|
|
|
|
//
|
|
// wait for a client to contact us
|
|
//
|
|
ULONG TdiHandle = DoOpenAddress(pDataDeviceName, pTransAddr);
|
|
if (!TdiHandle)
|
|
{
|
|
_putts(TEXT("ServerThread: failed to open address object\n"));
|
|
break;
|
|
}
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_ERROR);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_RECEIVE_DATAGRAM);
|
|
|
|
if (!WaitForClient(TdiHandle, pRemoteAddr))
|
|
{
|
|
_putts(TEXT("ServerThread: Timed out waiting for client\n"));
|
|
DoCloseAddress(TdiHandle);
|
|
break;
|
|
}
|
|
_putts(TEXT("ServerThread: Found by client. Client address:\n"));
|
|
DoPrintAddress(pTransAddr);
|
|
|
|
//
|
|
// echo datagram packets until we get one that is TEXT("Last Packet"), or until we time out
|
|
//
|
|
for (ULONG ulCount = 1; ulCount < 60000; ulCount++)
|
|
{
|
|
ULONG ulNumBytes;
|
|
PUCHAR pucData;
|
|
|
|
Sleep(10);
|
|
ulNumBytes = DoReceiveDatagram(TdiHandle, NULL, pRemoteAddr, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, pucData, ulNumBytes);
|
|
|
|
TCHAR *pString = (TCHAR *)pucData;
|
|
_tprintf(TEXT("ServerThread: Packet Received: %s\n"), pString);
|
|
if (_tcscmp(pString, TEXT("Last Packet")))
|
|
{
|
|
ulCount = 0;
|
|
}
|
|
LocalFreeMemory(pucData);
|
|
if (ulCount)
|
|
{
|
|
_putts(TEXT("ServerThread: Exitting datagram receive loop\n"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Sleep(50);
|
|
DoCloseAddress(TdiHandle);
|
|
|
|
//
|
|
// now, open an endpoint, and wait for a connection request
|
|
//
|
|
switch (pThreadData->ulType)
|
|
{
|
|
case TDI_ADDRESS_TYPE_IPX:
|
|
{
|
|
PTA_IPX_ADDRESS pAddr = (PTA_IPX_ADDRESS)pTransAddr;
|
|
pAddr->Address[0].Address[0].Socket = CONN_SERVER_PORT;
|
|
break;
|
|
}
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
{
|
|
PTA_IP_ADDRESS pAddr = (PTA_IP_ADDRESS)pTransAddr;
|
|
pAddr->Address[0].Address[0].sin_port = CONN_SERVER_PORT;
|
|
break;
|
|
}
|
|
}
|
|
TdiHandle = DoOpenEndpoint(pConnDeviceName, pTransAddr);
|
|
if (!TdiHandle)
|
|
{
|
|
_putts(TEXT("ServerThread: unable to open endpoint\n"));
|
|
break;
|
|
}
|
|
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_CONNECT);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_DISCONNECT);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_ERROR);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_RECEIVE);
|
|
|
|
fSuccessful = FALSE;
|
|
for (ULONG ulCount = 0; ulCount < 100; ulCount++)
|
|
{
|
|
if (DoIsConnected(TdiHandle))
|
|
{
|
|
_putts(TEXT("ServerThread: connect successful\n"));
|
|
fSuccessful = TRUE;
|
|
break;
|
|
}
|
|
Sleep(20);
|
|
}
|
|
if (!fSuccessful)
|
|
{
|
|
_putts(TEXT("ServerThread: timed out waiting for connect\n"));
|
|
DoCloseEndpoint(TdiHandle);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// echo packets until we get one that is TEXT("Last Packet")
|
|
//
|
|
|
|
for (ULONG ulCount = 0; ulCount < 60000; ulCount++)
|
|
{
|
|
ULONG ulNumBytes;
|
|
PUCHAR pucData;
|
|
|
|
Sleep(10);
|
|
ulNumBytes = DoReceive(TdiHandle, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
DoSend(TdiHandle, pucData, ulNumBytes, 0);
|
|
|
|
TCHAR *pString = (TCHAR *)pucData;
|
|
_tprintf(TEXT("ServerThread: Packet received: %s\n"), pString);
|
|
if (_tcscmp(pString, TEXT("Last Packet")))
|
|
{
|
|
ulCount = 0;
|
|
}
|
|
LocalFreeMemory(pucData);
|
|
if (ulCount)
|
|
{
|
|
_putts(TEXT("ServerThread: Exitting connected receive loop\n"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (ulCount = 0; ulCount < 1000; ulCount++)
|
|
{
|
|
if (!DoIsConnected(TdiHandle))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
DoCloseEndpoint(TdiHandle);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// cleanup
|
|
//
|
|
if (pTransAddr)
|
|
{
|
|
LocalFreeMemory(pTransAddr);
|
|
}
|
|
if (pRemoteAddr)
|
|
{
|
|
LocalFreeMemory(pTransAddr);
|
|
}
|
|
if (pDeviceName)
|
|
{
|
|
LocalFreeMemory(pDeviceName);
|
|
}
|
|
LocalFreeMemory(pvData);
|
|
DecServerCount();
|
|
_putts(TEXT("ServerThread: exitting\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: WaitForClient
|
|
//
|
|
// Arguments: TdiHandle -- address object handle for calling driver
|
|
// pRemoteAddr -- returns address received from
|
|
//
|
|
// Returns: TRUE if hear from client before timeout
|
|
//
|
|
// Descript: This function is used by the server side of the test to
|
|
// wait for contact with the client side.
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
BOOLEAN WaitForClient(ULONG TdiHandle,
|
|
PTRANSPORT_ADDRESS pRemoteAddr)
|
|
{
|
|
while(TRUE)
|
|
{
|
|
//
|
|
// wait for up to a 2 minutes for first packet (broadcast)
|
|
//
|
|
BOOLEAN fSuccessful = FALSE;
|
|
for (ULONG ulCount = 0; ulCount < 6000; ulCount++)
|
|
{
|
|
ULONG ulNumBytes;
|
|
PUCHAR pucData;
|
|
|
|
Sleep(20);
|
|
ulNumBytes = DoReceiveDatagram(TdiHandle, NULL, pRemoteAddr, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
if (ulNumBytes == 4)
|
|
{
|
|
PULONG pulValue = (PULONG)pucData;
|
|
if (*pulValue == 0x12345678)
|
|
{
|
|
_putts(TEXT("WaitForClient: first packet received\n"));
|
|
fSuccessful = TRUE;
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("WaitForClient: unexpected packet received\n"));
|
|
}
|
|
}
|
|
LocalFreeMemory(pucData);
|
|
//
|
|
// break out of wait loop if successful
|
|
//
|
|
if (fSuccessful)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for timed out
|
|
//
|
|
if (!fSuccessful)
|
|
{
|
|
_putts(TEXT("WaitForClient: timed out waiting for first packet\n"));
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// send 1st response
|
|
//
|
|
ULONG ulBuffer = 0x98765432;
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, (PUCHAR)&ulBuffer, sizeof(ULONG));
|
|
|
|
//
|
|
// wait for second response (directed)
|
|
//
|
|
fSuccessful = FALSE;
|
|
for (ULONG ulCount = 0; ulCount < 1000; ulCount++)
|
|
{
|
|
ULONG ulNumBytes;
|
|
PUCHAR pucData;
|
|
|
|
Sleep(10);
|
|
ulNumBytes = DoReceiveDatagram(TdiHandle, NULL, NULL, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
if (ulNumBytes == 4)
|
|
{
|
|
PULONG pulValue = (PULONG)pucData;
|
|
if (*pulValue == 0x22222222)
|
|
{
|
|
_putts(TEXT("WaitForClient: Second packet received\n"));
|
|
fSuccessful = TRUE;
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("WaitForClient: unexpected packet received\n"));
|
|
}
|
|
}
|
|
LocalFreeMemory(pucData);
|
|
//
|
|
// break out if recieved
|
|
//
|
|
if (fSuccessful)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if received second packet, send second response
|
|
//
|
|
if (fSuccessful)
|
|
{
|
|
ulBuffer = 0x33333333;
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, (PUCHAR)&ulBuffer, sizeof(ULONG));
|
|
return TRUE;
|
|
}
|
|
//
|
|
// else reloop and wait again for broadcast
|
|
//
|
|
_putts(TEXT("WaitForClient: timed out waiting for second packet\n"));
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// client-side test functions
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
BOOLEAN
|
|
FindServer(TCHAR *pDataDeviceName,
|
|
PTRANSPORT_ADDRESS pTransAddr,
|
|
PTRANSPORT_ADDRESS pRemoteAddr);
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: ClientTest
|
|
//
|
|
// Arguments: ulType -- protocol type to use
|
|
// NumDevices -- number of devices of this protocol type
|
|
//
|
|
// Descript: this function controls the client side of the test
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
VOID
|
|
ClientTest(ULONG ulType, ULONG ulNumDevices)
|
|
{
|
|
//
|
|
// address of local interface
|
|
//
|
|
PTRANSPORT_ADDRESS pTransAddr = (PTRANSPORT_ADDRESS)LocalAllocateMemory(MAX_ADDRESS_SIZE);
|
|
if (!pTransAddr)
|
|
{
|
|
_putts(TEXT("ClientTest: unable to allocate memory for pTransAddr\n"));
|
|
return;
|
|
}
|
|
pTransAddr->TAAddressCount = 1;
|
|
|
|
//
|
|
// address of remote interface
|
|
//
|
|
PTRANSPORT_ADDRESS pRemoteAddr = (PTRANSPORT_ADDRESS)LocalAllocateMemory(MAX_ADDRESS_SIZE);
|
|
if (!pRemoteAddr)
|
|
{
|
|
_putts(TEXT("ClientTest: unable to allocate memory for pRemoteAddr\n"));
|
|
LocalFreeMemory(pTransAddr);
|
|
return;
|
|
}
|
|
pRemoteAddr->TAAddressCount = 1;
|
|
|
|
//
|
|
// name of device (from driver)
|
|
//
|
|
TCHAR *pDeviceName = (TCHAR *)LocalAllocateMemory(256 * sizeof(TCHAR));
|
|
if (!pDeviceName)
|
|
{
|
|
_putts(TEXT("ClientTest: unable to allocate memory for pDeviceNameAddr\n"));
|
|
LocalFreeMemory(pTransAddr);
|
|
LocalFreeMemory(pRemoteAddr);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// name of tdi datagram interface to open
|
|
//
|
|
TCHAR *pDataDeviceName = NULL;
|
|
//
|
|
// name of tdi connection endpoint interface to open
|
|
//
|
|
TCHAR *pConnDeviceName = NULL;
|
|
//
|
|
// Stores handle used by driver to access interface
|
|
//
|
|
ULONG TdiHandle;
|
|
|
|
//
|
|
// for netbios, each "address" has its own name. You open a device based on the name
|
|
//
|
|
if (ulType == TDI_ADDRESS_TYPE_NETBIOS)
|
|
{
|
|
PTA_NETBIOS_ADDRESS pTaAddr = (PTA_NETBIOS_ADDRESS)pTransAddr;
|
|
|
|
pTaAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
pTaAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
|
|
pTaAddr->Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
memcpy(pTaAddr->Address[0].Address[0].NetbiosName, "CLIENT", 7); // NOTE: ascii string
|
|
}
|
|
|
|
//
|
|
// for others, there is one name for the datagram device and another for the "connected"
|
|
// device. You open an interface based on the address
|
|
//
|
|
else
|
|
{
|
|
switch (ulType)
|
|
{
|
|
case TDI_ADDRESS_TYPE_IPX:
|
|
pDataDeviceName = TEXT("\\device\\nwlnkipx");
|
|
pConnDeviceName = TEXT("\\device\\nwlnkspx");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
pDataDeviceName = TEXT("\\device\\udp");
|
|
pConnDeviceName = TEXT("\\device\\tcp");
|
|
break;
|
|
}
|
|
_putts(TEXT("ClientTest: get provider information\n"));
|
|
TdiHandle = DoOpenControl(pDataDeviceName);
|
|
|
|
if (TdiHandle)
|
|
{
|
|
PTDI_PROVIDER_INFO pInfo = (PTDI_PROVIDER_INFO)DoTdiQuery(TdiHandle, TDI_QUERY_PROVIDER_INFO);
|
|
if (pInfo)
|
|
{
|
|
DoPrintProviderInfo(pInfo);
|
|
LocalFreeMemory(pInfo);
|
|
}
|
|
DoCloseControl(TdiHandle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// loop thru the available devices, trying each one in turn..
|
|
//
|
|
for (ULONG ulCount = 0; ulCount < ulNumDevices; ulCount++)
|
|
{
|
|
//
|
|
// collect necessary information
|
|
//
|
|
if (DoGetDeviceName(ulType, ulCount, pDeviceName) != STATUS_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
_tprintf(TEXT("ClientTest: LocalDeviceName = %s\n"), pDeviceName);
|
|
|
|
if (ulType == TDI_ADDRESS_TYPE_NETBIOS)
|
|
{
|
|
pDataDeviceName = pDeviceName;
|
|
pConnDeviceName = pDeviceName;
|
|
|
|
_putts(TEXT("ClientTest: get provider information\n"));
|
|
TdiHandle = DoOpenControl(pDataDeviceName);
|
|
if (TdiHandle)
|
|
{
|
|
PTDI_PROVIDER_INFO pInfo = (PTDI_PROVIDER_INFO)DoTdiQuery(TdiHandle, TDI_QUERY_PROVIDER_INFO);
|
|
if (pInfo)
|
|
{
|
|
DoPrintProviderInfo(pInfo);
|
|
LocalFreeMemory(pInfo);
|
|
}
|
|
DoCloseControl(TdiHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (DoGetAddress(ulType, ulCount, pTransAddr) != STATUS_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
_putts(TEXT("ClientTest: Local device address:\n"));
|
|
DoPrintAddress(pTransAddr);
|
|
|
|
//
|
|
// try to contact server
|
|
//
|
|
if (FindServer(pDataDeviceName, pTransAddr, pRemoteAddr))
|
|
{
|
|
_putts(TEXT("Remote interface found:\n"));
|
|
DoPrintAddress(pRemoteAddr);
|
|
//
|
|
// do a datagram send/receive test
|
|
//
|
|
TdiHandle = DoOpenAddress(pDataDeviceName, pTransAddr);
|
|
if (TdiHandle)
|
|
{
|
|
_putts(TEXT("ClientTest: Sending first test packet\n"));
|
|
|
|
TCHAR *strBuffer = TEXT("This is only a test");
|
|
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_ERROR);
|
|
DoPostReceiveBuffer(TdiHandle, 128);
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, (PUCHAR)strBuffer, sizeof(TCHAR) * (1 + _tcslen(strBuffer)));
|
|
Sleep(300);
|
|
|
|
PUCHAR pucData;
|
|
ULONG ulNumBytes = DoFetchReceiveBuffer(TdiHandle, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
strBuffer = (TCHAR *)pucData;
|
|
_tprintf(TEXT("ClientTest: Response received: %s\n"), strBuffer);
|
|
LocalFreeMemory(pucData);
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("ClientTest: Response packet not received\n"));
|
|
}
|
|
|
|
_putts(TEXT("ClientTest: Sending second test packet\n"));
|
|
|
|
DoPostReceiveBuffer(TdiHandle, 128);
|
|
strBuffer = TEXT("Last Packet");
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, (PUCHAR)strBuffer, sizeof(TCHAR) * (1 + _tcslen(strBuffer)));
|
|
Sleep(300);
|
|
ulNumBytes = DoFetchReceiveBuffer(TdiHandle, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
strBuffer = (TCHAR *)pucData;
|
|
_tprintf(TEXT("ClientTest: Response received: %s\n"), strBuffer);
|
|
LocalFreeMemory(pucData);
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("ClientTest: Response packet not received\n"));
|
|
}
|
|
Sleep(50);
|
|
DoCloseAddress(TdiHandle);
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("ClientTest: unable to open address object\n"));
|
|
}
|
|
|
|
//
|
|
// adjust addresses...
|
|
//
|
|
switch (ulType)
|
|
{
|
|
case TDI_ADDRESS_TYPE_IPX:
|
|
{
|
|
PTA_IPX_ADDRESS pAddr = (PTA_IPX_ADDRESS)pRemoteAddr;
|
|
pAddr->Address[0].Address[0].Socket = CONN_SERVER_PORT;
|
|
|
|
pAddr = (PTA_IPX_ADDRESS)pTransAddr;
|
|
pAddr->Address[0].Address[0].Socket = CONN_CLIENT_PORT;
|
|
break;
|
|
}
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
{
|
|
PTA_IP_ADDRESS pAddr = (PTA_IP_ADDRESS)pRemoteAddr;
|
|
pAddr->Address[0].Address[0].sin_port = CONN_SERVER_PORT;
|
|
|
|
pAddr = (PTA_IP_ADDRESS)pTransAddr;
|
|
pAddr->Address[0].Address[0].sin_port = CONN_CLIENT_PORT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// establish a connection
|
|
//
|
|
_putts(TEXT("ClientTest: Attempt to establish a connection\n"));
|
|
TdiHandle = DoOpenEndpoint(pConnDeviceName, pTransAddr);
|
|
if (TdiHandle)
|
|
{
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_CONNECT);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_DISCONNECT);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_ERROR);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_RECEIVE);
|
|
|
|
if (DoConnect(TdiHandle, pRemoteAddr, 20) == STATUS_SUCCESS)
|
|
{
|
|
_putts(TEXT("ClientTest: Sending first packet over connection\n"));
|
|
|
|
//
|
|
// do a connected send/receive test
|
|
//
|
|
TCHAR *strBuffer = TEXT("This is only a test");
|
|
|
|
DoSend(TdiHandle, (PUCHAR)strBuffer, sizeof(TCHAR) * (1 + _tcslen(strBuffer)), 0);
|
|
|
|
//
|
|
// wait for response
|
|
//
|
|
for (ULONG ulWait = 0; ulWait < 100; ulWait++)
|
|
{
|
|
Sleep(10);
|
|
PUCHAR pucData;
|
|
ULONG ulNumBytes = DoReceive(TdiHandle, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
_tprintf(TEXT("ClientTest: Response received: %s\n"), (TCHAR *)pucData);
|
|
LocalFreeMemory(pucData);
|
|
break;
|
|
}
|
|
}
|
|
_putts(TEXT("ClientTest: Sending second packet over connection\n"));
|
|
|
|
strBuffer = TEXT("Last Packet");
|
|
|
|
DoSend(TdiHandle, (PUCHAR)strBuffer, sizeof(TCHAR) * (1 + _tcslen(strBuffer)), 0);
|
|
|
|
//
|
|
// wait for response
|
|
//
|
|
for (ULONG ulWait = 0; ulWait < 100; ulWait++)
|
|
{
|
|
Sleep(10);
|
|
PUCHAR pucData;
|
|
ULONG ulNumBytes = DoReceive(TdiHandle, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
_tprintf(TEXT("ClientTest: Response received: %s\n"), (TCHAR *)pucData);
|
|
LocalFreeMemory(pucData);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// shut down the connection
|
|
//
|
|
_putts(TEXT("ClientTest: closing connection\n"));
|
|
|
|
DoDisconnect(TdiHandle, TDI_DISCONNECT_RELEASE);
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("ClientTest: failed to establish connection\n"));
|
|
}
|
|
DoCloseEndpoint(TdiHandle);
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("ClientTest: failed to open endpoint\n"));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
_putts(TEXT("Unable to find remote server"));
|
|
}
|
|
|
|
if (ulType == TDI_ADDRESS_TYPE_NETBIOS)
|
|
{
|
|
_putts(TEXT("ClientTest: get provider status\n"));
|
|
TdiHandle = DoOpenControl(pDataDeviceName);
|
|
if (TdiHandle)
|
|
{
|
|
PADAPTER_STATUS pStatus = (PADAPTER_STATUS)DoTdiQuery(TdiHandle, TDI_QUERY_ADAPTER_STATUS);
|
|
if (pStatus)
|
|
{
|
|
DoPrintAdapterStatus(pStatus);
|
|
LocalFreeMemory(pStatus);
|
|
}
|
|
|
|
DoCloseControl(TdiHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ulType != TDI_ADDRESS_TYPE_NETBIOS)
|
|
{
|
|
_putts(TEXT("ClientTest: get provider statistics\n"));
|
|
|
|
TdiHandle = DoOpenControl(pDataDeviceName);
|
|
if (TdiHandle)
|
|
{
|
|
|
|
PTDI_PROVIDER_STATISTICS pStats
|
|
= (PTDI_PROVIDER_STATISTICS)DoTdiQuery(TdiHandle,
|
|
TDI_QUERY_PROVIDER_STATISTICS);
|
|
if (pStats)
|
|
{
|
|
DoPrintProviderStats(pStats);
|
|
LocalFreeMemory(pStats);
|
|
}
|
|
DoCloseControl(TdiHandle);
|
|
}
|
|
}
|
|
LocalFreeMemory(pDeviceName);
|
|
LocalFreeMemory(pTransAddr);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Function: FindServer
|
|
//
|
|
// Arguments: pDataDeviceName -- name of data device to open
|
|
// pTransAddr -- address of data device to open
|
|
// pRemoteAddr -- on return, address of remote device
|
|
//
|
|
// Returns: TRUE if able to establish communication with server,
|
|
// FALSE if it times out
|
|
//
|
|
// Descript: This function is called by the client to find a server
|
|
// to participate with it in the tests.
|
|
//
|
|
/////////////////////////////////////////////////
|
|
|
|
BOOLEAN
|
|
FindServer(TCHAR *pDataDeviceName,
|
|
PTRANSPORT_ADDRESS pTransAddr,
|
|
PTRANSPORT_ADDRESS pRemoteAddr)
|
|
{
|
|
//
|
|
// set up remote and local address for broadcast/multicast search for server
|
|
//
|
|
pRemoteAddr->Address[0].AddressLength = pTransAddr->Address[0].AddressLength;
|
|
pRemoteAddr->Address[0].AddressType = pTransAddr->Address[0].AddressType;
|
|
|
|
switch (pTransAddr->Address[0].AddressType)
|
|
{
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
{
|
|
PTDI_ADDRESS_IP pTdiAddressIp
|
|
= (PTDI_ADDRESS_IP)pTransAddr->Address[0].Address;
|
|
ULONG ulAddr = pTdiAddressIp->in_addr;
|
|
|
|
pTdiAddressIp->sin_port = DGRAM_CLIENT_PORT;
|
|
|
|
|
|
pTdiAddressIp = (PTDI_ADDRESS_IP)pRemoteAddr->Address[0].Address;
|
|
pTdiAddressIp->in_addr = 0xFFFF0000 | ulAddr;
|
|
pTdiAddressIp->sin_port = DGRAM_SERVER_PORT;
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IPX:
|
|
{
|
|
PTDI_ADDRESS_IPX pTdiAddressIpx
|
|
= (PTDI_ADDRESS_IPX)pTransAddr->Address[0].Address;
|
|
ULONG TempNetwork = pTdiAddressIpx->NetworkAddress;
|
|
pTdiAddressIpx->Socket = DGRAM_CLIENT_PORT;
|
|
|
|
pTdiAddressIpx = (PTDI_ADDRESS_IPX)pRemoteAddr->Address[0].Address;
|
|
pTdiAddressIpx->NetworkAddress = TempNetwork;
|
|
pTdiAddressIpx->Socket = DGRAM_SERVER_PORT;
|
|
memset(pTdiAddressIpx->NodeAddress, 0xFF, 6);
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_NETBIOS:
|
|
{
|
|
PTDI_ADDRESS_NETBIOS pTdiAddressNetbios
|
|
= (PTDI_ADDRESS_NETBIOS)pRemoteAddr->Address[0].Address;
|
|
|
|
pTdiAddressNetbios->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
memcpy(pTdiAddressNetbios->NetbiosName, "SERVER", 7 ); // NOTE: ascii string
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
_putts(TEXT("FindServer: invalid address type\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// try to find server program to test against
|
|
//
|
|
BOOLEAN fSuccessful = FALSE;
|
|
ULONG TdiHandle;
|
|
|
|
_putts(TEXT("FindServer: try to find remote test server\n"));
|
|
|
|
while (TRUE)
|
|
{
|
|
TdiHandle = DoOpenAddress(pDataDeviceName, pTransAddr);
|
|
if (!TdiHandle)
|
|
{
|
|
_putts(TEXT("FindServer: unable to open address object\n"));
|
|
break;
|
|
}
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_ERROR);
|
|
DoEnableEventHandler(TdiHandle, TDI_EVENT_RECEIVE_DATAGRAM);
|
|
|
|
//
|
|
// send broadcast query
|
|
//
|
|
_putts(TEXT("FindServer: send first packet (broadcast)\n"));
|
|
|
|
ULONG ulBuffer = 0x12345678;
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, (PUCHAR)&ulBuffer, sizeof(ULONG));
|
|
|
|
//
|
|
// wait for first response
|
|
//
|
|
for (ULONG ulCount = 0; ulCount < 100; ulCount++)
|
|
{
|
|
Sleep(10);
|
|
PUCHAR pucData;
|
|
ULONG ulNumBytes = DoReceiveDatagram(TdiHandle, NULL, pRemoteAddr, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
if (ulNumBytes == 4)
|
|
{
|
|
PULONG pulValue = (PULONG)pucData;
|
|
if (*pulValue == 0x98765432)
|
|
{
|
|
_putts(TEXT("FindServer: first response received\n"));
|
|
fSuccessful = TRUE;
|
|
}
|
|
}
|
|
LocalFreeMemory(pucData);
|
|
//
|
|
// break out of loop if received response
|
|
//
|
|
if (fSuccessful)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// timed out -- no response
|
|
//
|
|
if (!fSuccessful)
|
|
{
|
|
_putts(TEXT("FindServer: did not receive first response\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// send second message
|
|
//
|
|
fSuccessful = FALSE;
|
|
ulBuffer = 0x22222222;
|
|
_putts(TEXT("FindServer: send second packet (directed)\n"));
|
|
|
|
DoSendDatagram(TdiHandle, pRemoteAddr, (PUCHAR)&ulBuffer, sizeof(ULONG));
|
|
|
|
//
|
|
// wait for second response
|
|
//
|
|
for (ULONG ulCount = 0; ulCount < 50; ulCount++)
|
|
{
|
|
Sleep(10);
|
|
PUCHAR pucData;
|
|
ULONG ulNumBytes = DoReceiveDatagram(TdiHandle, NULL, NULL, &pucData);
|
|
if (ulNumBytes)
|
|
{
|
|
if (ulNumBytes == 4)
|
|
{
|
|
PULONG pulValue = (PULONG)pucData;
|
|
if (*pulValue == 0x33333333)
|
|
{
|
|
_putts(TEXT("FindServer: second response received\n"));
|
|
fSuccessful = TRUE;
|
|
}
|
|
}
|
|
LocalFreeMemory(pucData);
|
|
//
|
|
// break out if got response
|
|
//
|
|
if (fSuccessful)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!fSuccessful)
|
|
{
|
|
_putts(TEXT("FindServer: second response not received\n"));
|
|
|
|
}
|
|
if (TdiHandle)
|
|
{
|
|
DoCloseAddress(TdiHandle);
|
|
}
|
|
return fSuccessful;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// end of file tdisample.cpp
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|