666 lines
22 KiB
C
666 lines
22 KiB
C
|
#line 1 "manyicmp.c"
|
||
|
//================================================================================
|
||
|
// Microsoft Confidential
|
||
|
// Copyright (C) Microsoft Corporation 1997
|
||
|
//
|
||
|
// Author: RameshV
|
||
|
//================================================================================
|
||
|
|
||
|
//================================================================================
|
||
|
// Required headers
|
||
|
//================================================================================
|
||
|
#include "inc.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <ipexport.h>
|
||
|
#include <icmpif.h>
|
||
|
#include <icmpapi.h>
|
||
|
#include <winsock.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <align.h>
|
||
|
#include <adt.h>
|
||
|
#include "adt.c"
|
||
|
|
||
|
//================================================================================
|
||
|
// Required function, IMPORTED
|
||
|
//================================================================================
|
||
|
VOID
|
||
|
HandleIcmpResult( // Handle a processed ICMP packet.
|
||
|
IPAddr DestAddr, // Attempted dest address
|
||
|
BOOL Status, // Non-zero=> Dest reachable
|
||
|
LPVOID Context // Whatever was passed to DoIcmpRe..
|
||
|
);
|
||
|
|
||
|
|
||
|
//================================================================================
|
||
|
// Functions EXPORTED
|
||
|
//================================================================================
|
||
|
DWORD // Win32 errors
|
||
|
DoIcmpRequest( // send icmp req. and process asynchro..
|
||
|
IPAddr DestAddr, // Address to send ping to
|
||
|
LPVOID Context // the parameter to above function..
|
||
|
);
|
||
|
|
||
|
DWORD // Win32 errors
|
||
|
PingInit( // Initialize all globals..
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
PingCleanup( // Free memory and close handles..
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
|
||
|
//================================================================================
|
||
|
// Some defines
|
||
|
//================================================================================
|
||
|
#define PING_TEST // Yes, we are testing PING.
|
||
|
#define WAIT_TIME 5000
|
||
|
#define RCV_BUF_SIZE 0x2000
|
||
|
#define SEND_MESSAGE "IcmpDhcpTest"
|
||
|
#define THREAD_KILL_TIME INFINITE
|
||
|
|
||
|
#define MAX_PENDING_REQUESTS 100
|
||
|
#define NUM_RETRIES 3
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
#define DhcpAssert(Condition) do{ \
|
||
|
if(!(Condition)) AssertFailed(#Condition, __FILE__, __LINE__); } \
|
||
|
while(0)
|
||
|
#define ErrorPrint printf
|
||
|
#else
|
||
|
#define DhcpAssert(Condition)
|
||
|
#define ErrorPrint (void)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//================================================================================
|
||
|
// Data structures NOT EXPORTED
|
||
|
//================================================================================
|
||
|
|
||
|
// The follwing is the structure that is passed back to the callback function
|
||
|
typedef struct st_apcContext { // struct passed to APC routine
|
||
|
LIST_ENTRY IcmpRepliesList; // the chain of replies got is stored here
|
||
|
LIST_ENTRY IcmpRequestsList; // The list that holds the icmp response
|
||
|
PICMP_ECHO_REPLY Reply; // Icmp reply packet
|
||
|
DWORD ReplySize; // The size of above buffer.
|
||
|
IPAddr DestinationAddress; // Who are we try to ping?
|
||
|
DWORD Status; // Did we succeed? Also retry count.
|
||
|
LPVOID Context; // Dont know what this is goint to be
|
||
|
} APC_CONTEXT, *PAPC_CONTEXT;
|
||
|
|
||
|
// All globals are here.
|
||
|
LIST_ENTRY IcmpRepliesList; // Here is where the IcmpReplies are spooled
|
||
|
LIST_ENTRY IcmpRequestsList; // Here is where the
|
||
|
CRITICAL_SECTION IcmpRepliesCritSect; // To access the replies list
|
||
|
CRITICAL_SECTION IcmpRequestsCritSect; // To access the requests list
|
||
|
HANDLE IcmpRepliesEvent; // Signaled each time a reply is received
|
||
|
HANDLE IcmpRequestsEvent; // Singaled whenever a request is received
|
||
|
|
||
|
HANDLE TerminateEvent; // Quit everything being done.
|
||
|
CRITICAL_SECTION OutputCritSect; // To co-ordinate access to console output
|
||
|
|
||
|
HANDLE RequestsThreadHandle; // The handle of the thread that takes requests
|
||
|
HANDLE RepliesThreadHandle; // The handle of the thread that takes replies
|
||
|
|
||
|
HANDLE IcmpHandle; // Handle to do IcmpSendEcho2 etc.
|
||
|
|
||
|
PRODCONS IcmpProdConsSynchObj; // Producer/Consumer synchro.. object
|
||
|
|
||
|
BOOL Terminating = FALSE; // Are we terminating?
|
||
|
|
||
|
#define LOCK_REPLIES_LIST() EnterCriticalSection(&IcmpRepliesCritSect)
|
||
|
#define LOCK_REQUESTS_LIST() EnterCriticalSection(&IcmpRequestsCritSect)
|
||
|
#define LOCK_OUTPUT() EnterCriticalSection(&OutputCritSect)
|
||
|
|
||
|
#define UNLOCK_REPLIES_LIST() LeaveCriticalSection(&IcmpRepliesCritSect)
|
||
|
#define UNLOCK_REQUESTS_LIST() LeaveCriticalSection(&IcmpRequestsCritSect)
|
||
|
#define UNLOCK_OUTPUT() LeaveCriticalSection(&OutputCritSect)
|
||
|
|
||
|
//================================================================================
|
||
|
// Assertion failure routine + allocation free routines
|
||
|
//================================================================================
|
||
|
VOID static _inline
|
||
|
AssertFailed(
|
||
|
LPSTR Condition,
|
||
|
LPSTR File,
|
||
|
DWORD Line
|
||
|
) {
|
||
|
BYTE Buf[1000];
|
||
|
DWORD RetVal;
|
||
|
|
||
|
sprintf(Buf, "[%s:%d] %s", File, Line, Condition);
|
||
|
RetVal = MessageBox(
|
||
|
NULL, // hWnd: NULL => default desktop
|
||
|
Buf, // Text to print
|
||
|
"Assertion Failure", // Window caption
|
||
|
MB_OK | MB_ICONSTOP // Message type
|
||
|
);
|
||
|
}
|
||
|
|
||
|
LPVOID _inline
|
||
|
DhcpAllocateMemory(
|
||
|
DWORD Size
|
||
|
) {
|
||
|
return LocalAlloc(LMEM_FIXED, Size);
|
||
|
}
|
||
|
|
||
|
VOID _inline
|
||
|
DhcpFreeMemory(
|
||
|
LPVOID Ptr
|
||
|
) {
|
||
|
LocalFree(Ptr);
|
||
|
}
|
||
|
|
||
|
//================================================================================
|
||
|
// Routines
|
||
|
//================================================================================
|
||
|
|
||
|
//--------------------------------------------------------------------------------
|
||
|
// The following functions are on the replies side. They handle the icmp reply
|
||
|
// packet and take the necessary action depending on the status, etc.
|
||
|
//--------------------------------------------------------------------------------
|
||
|
|
||
|
VOID static
|
||
|
ApcRoutine( // This is called when ping completes
|
||
|
IN PVOID Context, // The above structure
|
||
|
IN PIO_STATUS_BLOCK Ignored1, // Unused param
|
||
|
IN ULONG Ignored2 // Unused param
|
||
|
) {
|
||
|
BOOL Status;
|
||
|
PAPC_CONTEXT ApcContext = (PAPC_CONTEXT)Context;
|
||
|
|
||
|
if( TRUE == Terminating ) {
|
||
|
// Just free memory and quit?
|
||
|
ASSERT( FALSE );
|
||
|
DhcpFreeMemory(ApcContext);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// All we have to do is add it to the Replies List and signal the event
|
||
|
LOCK_REPLIES_LIST();
|
||
|
InsertTailList(&IcmpRepliesList, &ApcContext->IcmpRepliesList);
|
||
|
UNLOCK_REPLIES_LIST();
|
||
|
|
||
|
Status = SetEvent(IcmpRepliesEvent);
|
||
|
ASSERT( FALSE != Status );
|
||
|
}
|
||
|
|
||
|
// The following function decides if the Destination is reachable or not.
|
||
|
BOOL static
|
||
|
DestReachable( // Is destination reachable?
|
||
|
IN PAPC_CONTEXT ApcContext // this has the info of sender etc..
|
||
|
) {
|
||
|
DWORD nReplies, i;
|
||
|
|
||
|
// First parse the packet.
|
||
|
nReplies = IcmpParseReplies(ApcContext->Reply, ApcContext->ReplySize);
|
||
|
|
||
|
// if no replies, then straight assume that destination is unreachable.
|
||
|
if( 0 == nReplies ) {
|
||
|
// If there was no reply, there is no way for us to reach this
|
||
|
// So, we assume that the Dest is NOT reachable.
|
||
|
// Reasons could be IP_REQ_TIMED_OUT or IP_BAD_DESTINATION etc..
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Now we check each reply to see if there is anything from the same dest
|
||
|
// address we are looking for. And if the status is success. If the status
|
||
|
// is not success, we actually do not check anything there. Potentially, it
|
||
|
// could be IP_DEST_PORT_UNREACHABLE, in which case, the dest machine is up,
|
||
|
// but for some reason we tried the wrong port..
|
||
|
|
||
|
for( i = 0; i < nReplies; i ++ ) {
|
||
|
if( ApcContext->DestinationAddress == ApcContext->Reply[i].Address ) {
|
||
|
// hit the destination!
|
||
|
|
||
|
ASSERT( IP_SUCCESS == ApcContext->Reply[i].Status );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
ASSERT( IP_SUCCESS != ApcContext->Reply[i].Status);
|
||
|
}
|
||
|
|
||
|
// None of the replies were successful.
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
VOID static
|
||
|
HandleRepliesEvent( // Process all replies received
|
||
|
VOID
|
||
|
) {
|
||
|
PAPC_CONTEXT ApcContext;
|
||
|
PLIST_ENTRY listEntry;
|
||
|
BOOL Status;
|
||
|
|
||
|
LOCK_REPLIES_LIST();
|
||
|
while( !IsListEmpty( &IcmpRepliesList ) ) {
|
||
|
// retrive the first element in the list
|
||
|
|
||
|
ApcContext = CONTAINING_RECORD(IcmpRepliesList.Flink, APC_CONTEXT, IcmpRepliesList);
|
||
|
RemoveEntryList(&ApcContext->IcmpRepliesList);
|
||
|
|
||
|
UNLOCK_REPLIES_LIST();
|
||
|
|
||
|
Status = DestReachable(ApcContext);
|
||
|
|
||
|
if( Status || NUM_RETRIES <= ApcContext->Status ) {
|
||
|
StartConsumer(&IcmpProdConsSynchObj);
|
||
|
HandleIcmpResult(
|
||
|
ApcContext->DestinationAddress,
|
||
|
Status,
|
||
|
ApcContext->Context
|
||
|
);
|
||
|
|
||
|
DhcpFreeMemory(ApcContext);
|
||
|
EndConsumer(&IcmpProdConsSynchObj);
|
||
|
} else {
|
||
|
// retry
|
||
|
|
||
|
LOCK_REQUESTS_LIST();
|
||
|
InsertTailList(&IcmpRequestsList, &ApcContext->IcmpRequestsList);
|
||
|
UNLOCK_REQUESTS_LIST();
|
||
|
|
||
|
Status = SetEvent(IcmpRequestsEvent);
|
||
|
ASSERT( TRUE == Status );
|
||
|
}
|
||
|
|
||
|
LOCK_REPLIES_LIST();
|
||
|
}
|
||
|
UNLOCK_REPLIES_LIST();
|
||
|
}
|
||
|
|
||
|
|
||
|
// This routine sleeps on a loop, and is woken up by the call back function when an ICMP
|
||
|
// reply comes through. On waking up, this routine processes ALL ICMP replies.
|
||
|
DWORD static // THREAD ENTRY
|
||
|
LoopOnIcmpReplies( // Loop on all the ICMP replies.
|
||
|
LPVOID Unused
|
||
|
) {
|
||
|
DWORD Status;
|
||
|
HANDLE WaitHandles[2];
|
||
|
|
||
|
WaitHandles[0] = TerminateEvent;
|
||
|
WaitHandles[1] = IcmpRepliesEvent;
|
||
|
|
||
|
while( TRUE ) {
|
||
|
Status = WaitForMultipleObjects(
|
||
|
sizeof(WaitHandles)/sizeof(WaitHandles[0]),
|
||
|
WaitHandles,
|
||
|
FALSE,
|
||
|
INFINITE
|
||
|
);
|
||
|
|
||
|
|
||
|
if( WAIT_OBJECT_0 == Status ) break; // Termination
|
||
|
if( 1+WAIT_OBJECT_0 == Status ) {
|
||
|
HandleRepliesEvent();
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ASSERT( FALSE );
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
#define AlignSizeof(X) ROUND_UP_COUNT(sizeof(X),ALIGN_WORST)
|
||
|
|
||
|
DWORD // exported
|
||
|
DoIcmpRequest(
|
||
|
IPAddr DestAddr,
|
||
|
LPVOID Context
|
||
|
) {
|
||
|
PAPC_CONTEXT pCtxt;
|
||
|
LPBYTE startAddress;
|
||
|
DWORD Status;
|
||
|
BOOL BoolStatus;
|
||
|
|
||
|
// Create the context
|
||
|
pCtxt = DhcpAllocateMemory(AlignSizeof(APC_CONTEXT) + RCV_BUF_SIZE);
|
||
|
startAddress = (LPBYTE)pCtxt;
|
||
|
if( NULL == pCtxt ) return GetLastError();
|
||
|
|
||
|
// Now fill the context with all that we know.
|
||
|
pCtxt->Reply = (PICMP_ECHO_REPLY)(startAddress + AlignSizeof(APC_CONTEXT));
|
||
|
pCtxt->ReplySize = RCV_BUF_SIZE;
|
||
|
pCtxt->DestinationAddress = DestAddr;
|
||
|
pCtxt->Status = 0;
|
||
|
pCtxt->Context = Context;
|
||
|
|
||
|
|
||
|
// enqueue this guy.
|
||
|
StartProducer(&IcmpProdConsSynchObj);
|
||
|
|
||
|
LOCK_REQUESTS_LIST();
|
||
|
InsertTailList(&IcmpRequestsList, &pCtxt->IcmpRequestsList);
|
||
|
UNLOCK_REQUESTS_LIST();
|
||
|
|
||
|
EndProducer(&IcmpProdConsSynchObj);
|
||
|
|
||
|
// Signal the Requests loop.
|
||
|
BoolStatus = SetEvent(IcmpRequestsEvent);
|
||
|
ASSERT( TRUE == BoolStatus );
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------
|
||
|
// The following functions handle the the end that sends ICMP echoes.
|
||
|
//--------------------------------------------------------------------------------
|
||
|
VOID static
|
||
|
HandleRequestsEvent( // Process every request for ICMP echo.
|
||
|
VOID
|
||
|
) {
|
||
|
PAPC_CONTEXT ApcContext;
|
||
|
PLIST_ENTRY listEntry;
|
||
|
DWORD Status;
|
||
|
|
||
|
|
||
|
LOCK_REQUESTS_LIST();
|
||
|
|
||
|
while( !IsListEmpty( &IcmpRequestsList ) ) {
|
||
|
// retrive the first element in the list
|
||
|
ApcContext = CONTAINING_RECORD(IcmpRequestsList.Flink, APC_CONTEXT, IcmpRequestsList);
|
||
|
RemoveEntryList(&ApcContext->IcmpRequestsList);
|
||
|
|
||
|
UNLOCK_REQUESTS_LIST();
|
||
|
|
||
|
// Send an Icmp echo and return immediately..
|
||
|
ApcContext->Status ++;
|
||
|
Status = IcmpSendEcho2(
|
||
|
IcmpHandle, // The handle to register APC and send echo
|
||
|
NULL, // No event
|
||
|
ApcRoutine, // The call back routine
|
||
|
(LPVOID)ApcContext, // The first parameter to the callback routine
|
||
|
ApcContext->DestinationAddress, // The address being PING'ed
|
||
|
SEND_MESSAGE,
|
||
|
(WORD)strlen(SEND_MESSAGE),
|
||
|
NULL,
|
||
|
(LPVOID)ApcContext->Reply,
|
||
|
ApcContext->ReplySize,
|
||
|
WAIT_TIME
|
||
|
);
|
||
|
|
||
|
if( FALSE == Status ) Status = GetLastError();
|
||
|
else Status = ERROR_SUCCESS;
|
||
|
|
||
|
// Since we queued an APC, we expect an STATUS_PENDING.
|
||
|
if( ERROR_SUCCESS != Status && ERROR_IO_PENDING != Status ) {
|
||
|
ASSERT(FALSE);
|
||
|
LOCK_OUTPUT();
|
||
|
ErrorPrint("IcmpSendEcho2:GetLastError: %d\n", Status);
|
||
|
UNLOCK_OUTPUT();
|
||
|
}
|
||
|
LOCK_REQUESTS_LIST();
|
||
|
}
|
||
|
UNLOCK_REQUESTS_LIST();
|
||
|
}
|
||
|
|
||
|
|
||
|
// This function handles the Requests.. For each one, it just sends an IcmpEcho
|
||
|
// asynchronously and returns back immediately. When the APC routine is called,
|
||
|
// it would queue it up on the Replies list and then it would get processed...
|
||
|
DWORD static // THREAD ENTRY
|
||
|
LoopOnIcmpRequests( // Process pending requests for echo
|
||
|
LPVOID Unused
|
||
|
) {
|
||
|
DWORD Status;
|
||
|
HANDLE WaitHandles[2];
|
||
|
|
||
|
WaitHandles[0] = TerminateEvent;
|
||
|
WaitHandles[1] = IcmpRequestsEvent;
|
||
|
|
||
|
while( TRUE ) {
|
||
|
Status = WaitForMultipleObjectsEx(
|
||
|
sizeof(WaitHandles)/sizeof(WaitHandles[0]), // # of handles
|
||
|
WaitHandles, // array of handles
|
||
|
FALSE, // any one of them set
|
||
|
INFINITE, // wait forever
|
||
|
TRUE // allow APC's
|
||
|
);
|
||
|
|
||
|
if( WAIT_OBJECT_0 == Status ) break; // Termination
|
||
|
if( WAIT_IO_COMPLETION == Status) continue;
|
||
|
if( 1+WAIT_OBJECT_0 == Status ) {
|
||
|
HandleRequestsEvent();
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------
|
||
|
// Initialization, Cleanup routines.
|
||
|
//--------------------------------------------------------------------------------
|
||
|
DWORD // exported
|
||
|
PingInit(
|
||
|
VOID
|
||
|
) {
|
||
|
DWORD ThreadId, Status;
|
||
|
|
||
|
// Initialize all data vars.
|
||
|
IcmpRepliesEvent = IcmpRequestsEvent = TerminateEvent = NULL;
|
||
|
RepliesThreadHandle = RequestsThreadHandle = NULL;
|
||
|
IcmpHandle = NULL;
|
||
|
|
||
|
// Open IcmpHandle..
|
||
|
IcmpHandle = IcmpCreateFile();
|
||
|
if( NULL == IcmpHandle ) return GetLastError();
|
||
|
|
||
|
// Initialize Lists.
|
||
|
InitializeListHead(&IcmpRepliesList);
|
||
|
InitializeListHead(&IcmpRequestsList);
|
||
|
|
||
|
// Initialize Critical Sections.
|
||
|
InitializeCriticalSection(&IcmpRepliesCritSect);
|
||
|
InitializeCriticalSection(&IcmpRequestsCritSect);
|
||
|
InitializeCriticalSection(&OutputCritSect);
|
||
|
|
||
|
// Create Events,
|
||
|
IcmpRepliesEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
|
if( NULL == IcmpRepliesEvent ) return GetLastError();
|
||
|
IcmpRequestsEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
|
if( NULL == IcmpRequestsEvent ) return GetLastError();
|
||
|
TerminateEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||
|
if( NULL == TerminateEvent ) return GetLastError();
|
||
|
|
||
|
// Create producer-consumer synchronization object
|
||
|
Status = InitializeProducerConsumer(
|
||
|
&IcmpProdConsSynchObj,
|
||
|
MAX_PENDING_REQUESTS,
|
||
|
MAX_PENDING_REQUESTS
|
||
|
);
|
||
|
if( ERROR_SUCCESS != Status ) return Status;
|
||
|
|
||
|
// Create Threads
|
||
|
RepliesThreadHandle = CreateThread(
|
||
|
(LPSECURITY_ATTRIBUTES)
|
||
|
NULL, // No security information
|
||
|
0, // Stack size = same as default primary thread
|
||
|
LoopOnIcmpReplies, // The function to call
|
||
|
NULL, // No paramter needs to be passed to this function
|
||
|
0, // Flags: just start this thread right away
|
||
|
&ThreadId // The return ThreadId value.
|
||
|
);
|
||
|
if( NULL == RepliesThreadHandle ) return GetLastError();
|
||
|
|
||
|
RequestsThreadHandle = CreateThread(
|
||
|
NULL, // No security information
|
||
|
0, // Stack size = same as default primary thread
|
||
|
LoopOnIcmpRequests, // The function to call
|
||
|
NULL, // No paramter needs to be passed to this function
|
||
|
0, // Flags: just start this thread right away
|
||
|
&ThreadId // The return ThreadId value.
|
||
|
);
|
||
|
if( NULL == RequestsThreadHandle ) return GetLastError();
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
VOID // exported
|
||
|
PingCleanup(
|
||
|
VOID
|
||
|
) {
|
||
|
DWORD Status;
|
||
|
BOOL BoolStatus;
|
||
|
PAPC_CONTEXT ApcContext;
|
||
|
PLIST_ENTRY listEntry;
|
||
|
|
||
|
// Kill the replies and reqeusts threads after waiting for a while.
|
||
|
// Kill the Replies and Requests ThreadHandle 's.
|
||
|
if( NULL != RepliesThreadHandle || NULL != RequestsThreadHandle ) {
|
||
|
// ASSERT ( NULL != TerminateEvent )
|
||
|
Terminating = TRUE;
|
||
|
SetEvent(TerminateEvent);
|
||
|
|
||
|
if( NULL != RepliesThreadHandle ) {
|
||
|
Status = WaitForSingleObject(
|
||
|
RepliesThreadHandle,
|
||
|
THREAD_KILL_TIME
|
||
|
);
|
||
|
if( WAIT_OBJECT_0 != Status ) {
|
||
|
// did not succeed in stopping the thread..
|
||
|
BoolStatus = TerminateThread(
|
||
|
RepliesThreadHandle,
|
||
|
0xFF
|
||
|
);
|
||
|
ASSERT(BoolStatus);
|
||
|
}
|
||
|
CloseHandle(RepliesThreadHandle);
|
||
|
}
|
||
|
|
||
|
if( NULL != RequestsThreadHandle ) {
|
||
|
Status = WaitForSingleObject(
|
||
|
RequestsThreadHandle,
|
||
|
THREAD_KILL_TIME
|
||
|
);
|
||
|
if( WAIT_OBJECT_0 != Status ) {
|
||
|
// did not succeed in stopping the thread..
|
||
|
BoolStatus = TerminateThread(
|
||
|
RequestsThreadHandle,
|
||
|
0xFF
|
||
|
);
|
||
|
ASSERT(BoolStatus);
|
||
|
}
|
||
|
CloseHandle(RequestsThreadHandle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Close Event handles.
|
||
|
CloseHandle(IcmpRepliesEvent);
|
||
|
CloseHandle(IcmpRequestsEvent);
|
||
|
CloseHandle(TerminateEvent);
|
||
|
|
||
|
// Destroy producer consumer synchronization object
|
||
|
DestroyProducerConsumer(&IcmpProdConsSynchObj);
|
||
|
|
||
|
// Freeup all elements of lists..
|
||
|
while( !IsListEmpty( &IcmpRepliesList ) ) {
|
||
|
// retrive the first element in the list
|
||
|
ApcContext = CONTAINING_RECORD(IcmpRepliesList.Flink, APC_CONTEXT, IcmpRepliesList);
|
||
|
RemoveEntryList(&ApcContext->IcmpRepliesList);
|
||
|
|
||
|
DhcpFreeMemory(ApcContext);
|
||
|
}
|
||
|
while( !IsListEmpty( &IcmpRequestsList ) ) {
|
||
|
// retrive the first element in the list
|
||
|
ApcContext = CONTAINING_RECORD(IcmpRequestsList.Flink, APC_CONTEXT, IcmpRequestsList);
|
||
|
RemoveEntryList(&ApcContext->IcmpRequestsList);
|
||
|
|
||
|
DhcpFreeMemory(ApcContext);
|
||
|
}
|
||
|
|
||
|
// Close Icmp handle
|
||
|
CloseHandle(IcmpHandle);
|
||
|
|
||
|
// Destroy critical sections
|
||
|
DeleteCriticalSection(&IcmpRepliesCritSect);
|
||
|
DeleteCriticalSection(&IcmpRequestsCritSect);
|
||
|
DeleteCriticalSection(&OutputCritSect);
|
||
|
}
|
||
|
|
||
|
#ifdef PING_TEST
|
||
|
//--------------------------------------------------------------------------------
|
||
|
// Test module. This exercises the above functions.
|
||
|
//--------------------------------------------------------------------------------
|
||
|
DWORD SA, EA;
|
||
|
DWORD
|
||
|
TestPing(
|
||
|
LPSTR StartAddrString,
|
||
|
LPSTR EndAddrString
|
||
|
) {
|
||
|
IPAddr i, StartAddr, EndAddr;
|
||
|
DWORD Status;
|
||
|
BOOL BoolStatus;
|
||
|
HANDLE ThreadHandle;
|
||
|
|
||
|
StartAddr = SA = inet_addr(StartAddrString);
|
||
|
EndAddr = EA = inet_addr(EndAddrString);
|
||
|
|
||
|
Status = PingInit();
|
||
|
if( ERROR_SUCCESS != Status ) return Status;
|
||
|
|
||
|
for( i = htonl(StartAddr); i <= htonl(EndAddr); i ++ ) {
|
||
|
|
||
|
Status = DoIcmpRequest(ntohl(i), NULL);
|
||
|
ASSERT( ERROR_SUCCESS == Status );
|
||
|
}
|
||
|
|
||
|
LOCK_OUTPUT();
|
||
|
printf("Done\n");
|
||
|
UNLOCK_OUTPUT();
|
||
|
|
||
|
// Sleep for a while and then signal termination...
|
||
|
Sleep(30000);
|
||
|
// Give the threads time to die?
|
||
|
PingCleanup();
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------
|
||
|
// Main function. Just does the test routine.
|
||
|
//--------------------------------------------------------------------------------
|
||
|
VOID _cdecl
|
||
|
main(
|
||
|
int argc,
|
||
|
char *argv[]
|
||
|
) {
|
||
|
DWORD Status;
|
||
|
if( argc != 3 ) {
|
||
|
fprintf(stderr, "\nUsage: %s start-ip-addr end-ip-addr\n", argv[0]);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
Status = TestPing(argv[1], argv[2]);
|
||
|
if( ERROR_SUCCESS != Status ) {
|
||
|
fprintf(stderr, "Error: %d\n", Status);
|
||
|
}
|
||
|
}
|
||
|
#endif PING_TEST
|
||
|
|
||
|
//--------------------------------------------------------------------------------
|
||
|
// End of file.
|
||
|
//--------------------------------------------------------------------------------
|
||
|
|
||
|
// This will really be defined elsewhere.. until then.
|
||
|
VOID
|
||
|
HandleIcmpResult( // Handle a processed ICMP packet.
|
||
|
IPAddr DestAddr, // Attempted dest address
|
||
|
BOOL Status, // Non-zero=> Dest reachable
|
||
|
LPVOID Context // Whatever was passed to DoIcmpRe..
|
||
|
) {
|
||
|
|
||
|
LOCK_OUTPUT();
|
||
|
printf("Ping[%s] does %s exist\n",
|
||
|
inet_ntoa(*(struct in_addr *)&DestAddr),
|
||
|
Status? "" : "not" );
|
||
|
UNLOCK_OUTPUT();
|
||
|
}
|