- °³¿ä
- ICMP library on Win32
- Usage Sample
- ICMPRepository.h
- ICMPRepository.cpp
- Ping Implementation
- Microsoft ICMP Library Version
- PingI.c
- RAW Socket Version
- Ping.h
- Ping.c
1 °³¿ä
Internet Control Message Protocol, ÁÙ¿©¼ ICMP¿¡ °üÇÑ ³»¿ëµéÀÌ´Ù.
2 ICMP library on Win32
Win32 »ó¿¡¼ ±¸ÇöÇÑ Internet Control Message Protocol (ICMP) ¶óÀ̺귯¸®´Ù. ¿ø·¡ ¼Ò½º ÆÄÀÏÀº C·Î ±¸ÇöµÇ¾î ÀÖ¾ú°í, ½Ì±Û ¾²·¹µå¿´´Ù. icmp.dll ³»ºÎ¿¡ ÀÖ´Â ÇÔ¼ö¸¦ ÀÌ¿ëÇϴµ¥ ÀÌ ÇÔ¼ö°¡ ºí·ÏÅ·ÀÌ µÇ´Â ÇÔ¼ö±â ¶§¹®¿¡ ½ÇÁ¦·Î °ÔÀÓ ¼¹ö µî¿¡¼ ¾²·Á¸é ¸ÖƼ ¾²·¹µùÀÌ Çʼö´Ù. ±×·¡¼ ¸ÖƼ ¾²·¹µù°ú °ü·ÃµÈ Äڵ带 Áý¾î³Ö¾ú´Ù.
´ÙÀ½Àº ¿ø·¡ ¼Ò½º¿¡ ÀÖ´ø ¸Ó¸´¸»ÀÌ´Ù.
/*------------------------------------------------------------------
* Filename: MS_ICMP.H
*
* Description:
* Prototypes and typedefs Microsoft's ICMP.DLL functions & structs
* for access to Internet Control Message Protocol. This is capable
* of doing "ping or "traceroute", although beware that Microsoft
* discourages the use of these APIs.
*
* Some Background:
*
* The standard Berkeley Sockets SOCK_RAW socket type, is normally used
* to create ping (echo request/reply), and sometimes traceroute applications
* (the original traceroute application from Van Jacobson used UDP, rather
* than ICMP). Microsoft's WinSock version 2 implementations for NT4 and
* Windows 95 support raw sockets, but none of their WinSock version 1.1
* implementations (WFWG, NT3.x or standard Windows 95) did.
*
* Microsoft has their own API for an ICMP.DLL that their ping and tracert
* applications use (by the way, they are both non-GUI text-based console
* applications. This is a proprietary API, and all function calls that
* involve network functions operate in blocking mode. They still include
* it with WinSock 2 implementations.
*
* There is little documentation available (I first found it in the Win32
* SDK in \MSTOOLS\ICMP, and it exists on the MS Developers' Network
* CD-ROM now, also). Microsoft disclaims this API about as strongly as
* possible. The README.TXT that accompanies it says:
*
* [DISCLAIMER]
*
* We have had requests in the past to expose the functions exported from
* icmp.dll. The files in this directory are provided for your convenience
* in building applications which make use of ICMPSendEcho(). Notice that
* the functions in icmp.dll are not considered part of the Win32 API and
* will not be supported in future releases. Once we have a more complete
* solution in the operating system, this DLL, and the functions it exports,
* will be dropped.
*
* [DOCUMENTATION]
*
* The ICMPSendEcho() function sends an ICMP echo request to the specified
* destination IP address and returns any replies received within the timeout
* specified. The API is synchronous, requiring the process to spawn a thread
* before calling the API to avoid blocking. An open IcmpHandle is required
* for the request to complete. IcmpCreateFile() and IcmpCloseHandle()
* functions are used to create and destroy the context handle.</P>
*/
¾Æ·¡ÀÇ ÄÚµåµéÀº »ùÇà ÄÚµå¿Í ¶óÀ̺귯¸® Çì´õ, ±¸Çö ÆÄÀÏ·Î ³ª´µ¾îÁ® Àִµ¥, ¼Ò½º¸¦ ±×³É ±Ü¾î¼ ÄÄÆÄÀÏÇϸé ÄÄÆÄÀϵÇÁö ¾Ê´Â´Ù. Å©¸®Æ¼Äà ¼½¼ÇÀ̶óµçÁö ½Ì±Û·¹Åæ ÆÐÅÏ µî¿¡ °üÇÑ Çì´õ ÆÄÀϵµ °°ÀÌ ÀÖ¾î¾ß ÄÄÆÄÀÏÀÌ µÈ´Ù. Àû´çÈ÷ Àß~ °íÃļ ÄÄÆÄÀÏÇØº¸±â ¹Ù¶õ´Ù.
2.1 Usage Sample
#include "ICMPRepository.h"
#include <conio.h>
void main()
{
Socket::initializeWinsock();
//g_pICMPRepository->enqueueRequest("155.230.29.10", ICMP_REQUEST_CLASS_PING);
g_pICMPRepository->enqueueRequest("155.230.29.10", ICMP_REQUEST_CLASS_TRACEROUTE);
while (true)
{
ICMP_RESULT* pResult = g_pICMPRepository->getResult("155.230.29.10");
if (pResult != NULL)
{
cout << "*** PING RESULT ***" << endl;
cout << "Average Time : " << pResult->AverageTime << endl;
cout << "Bytes Transffered : " << pResult->BytesTransferred << endl;
cout << "*** TRACEROUTE RESULT ***" << endl;
ICMP_HOP_LIST::const_iterator itr = pResult->HopList.begin();
for (; itr != pResult->HopList.end(); itr++)
{
cout << "HOP:" << *itr << endl;
}
break;
}
else
{
Sleep(1000);
}
}
_getch();
Socket::finalizeWinsock();
}
2.2 ICMPRepository.h
#ifndef __ICMPREPOSITORY_H__
#define __ICMPREPOSITORY_H__
#ifndef __MTYPES_H__
#include "MTypes.h"
#endif
#ifndef __SINGLETON_H__
#include "Singleton.h"
#endif
#ifndef __STRINGHASHMAP_H__
#include "StringHashMap.h"
#endif
#ifndef __THREAD_H__
#include "Thread.h"
#endif
#ifndef _LIST_
#include <list>
#endif
//----------------------------------------------------------------------------
enum ICMPStatus
{
IP_STATUS_BASE = 11000,
IP_SUCCESS = 0,
IP_BUF_TOO_SMALL = IP_STATUS_BASE + 1,
IP_DEST_NET_UNREACHABLE = IP_STATUS_BASE + 2,
IP_DEST_HOST_UNREACHABLE = IP_STATUS_BASE + 3,
IP_DEST_PROT_UNREACHABLE = IP_STATUS_BASE + 4,
IP_DEST_PORT_UNREACHABLE = IP_STATUS_BASE + 5,
IP_NO_RESOURCES = IP_STATUS_BASE + 6,
IP_BAD_OPTION = IP_STATUS_BASE + 7,
IP_HW_ERROR = IP_STATUS_BASE + 8,
IP_PACKET_TOO_BIG = IP_STATUS_BASE + 9,
IP_REQ_TIMED_OUT = IP_STATUS_BASE + 10,
IP_BAD_REQ = IP_STATUS_BASE + 11,
IP_BAD_ROUTE = IP_STATUS_BASE + 12,
IP_TTL_EXPIRED_TRANSIT = IP_STATUS_BASE + 13,
IP_TTL_EXPIRED_REASSEM = IP_STATUS_BASE + 14,
IP_PARAM_PROBLEM = IP_STATUS_BASE + 15,
IP_SOURCE_QUENCH = IP_STATUS_BASE + 16,
IP_OPTION_TOO_BIG = IP_STATUS_BASE + 17,
IP_BAD_DESTINATION = IP_STATUS_BASE + 18,
IP_ADDR_DELETED = IP_STATUS_BASE + 19,
IP_SPEC_MTU_CHANGE = IP_STATUS_BASE + 20,
IP_MTU_CHANGE = IP_STATUS_BASE + 21,
IP_UNLOAD = IP_STATUS_BASE + 22,
IP_GENERAL_FAILURE = IP_STATUS_BASE + 50,
MAX_IP_STATUS = IP_GENERAL_FAILURE,
IP_PENDING = IP_STATUS_BASE + 255
};
//----------------------------------------------------------------------------
// ICMPSendEcho Error String
// The values in the status word returned in the ICMP Echo
// Reply buffer after calling IcmpSendEcho() all have a
// base value of 11000 (IP_STATUS_BASE). At times,
// when IcmpSendEcho() fails outright, GetLastError() will
// subsequently return these error values also.
// Two Errors value defined in ms_icmp.h are missing from
// this string table (just to simplify use of the table):
// "IP_GENERAL_FAILURE (11050)"
// "IP_PENDING (11255)"
//----------------------------------------------------------------------------
const IDSTRING ICMPStatus2String[] =
{
{IP_STATUS_BASE, "IP_STATUS_BASE (11000)"},
{IP_BUF_TOO_SMALL, "IP_BUF_TOO_SMALL (11001)"},
{IP_DEST_NET_UNREACHABLE, "IP_DEST_NET_UNREACHABLE (11002)"},
{IP_DEST_HOST_UNREACHABLE, "IP_DEST_HOST_UNREACHABLE (11003)"},
{IP_DEST_PROT_UNREACHABLE, "IP_DEST_PROT_UNREACHABLE (11004)"},
{IP_DEST_PORT_UNREACHABLE, "IP_DEST_PORT_UNREACHABLE (11005)"},
{IP_NO_RESOURCES, "IP_NO_RESOURCES (11006)"},
{IP_BAD_OPTION, "IP_BAD_OPTION (11007)"},
{IP_HW_ERROR, "IP_HW_ERROR (11008)"},
{IP_PACKET_TOO_BIG, "IP_PACKET_TOO_BIG (11009)"},
{IP_REQ_TIMED_OUT, "IP_REQ_TIMED_OUT (11010)"},
{IP_BAD_REQ, "IP_BAD_REQ (11011)"},
{IP_BAD_ROUTE, "IP_BAD_ROUTE (11012)"},
{IP_TTL_EXPIRED_TRANSIT, "IP_TTL_EXPIRED_TRANSIT (11013)"},
{IP_TTL_EXPIRED_REASSEM, "IP_TTL_EXPIRED_REASSEM (11014)"},
{IP_PARAM_PROBLEM, "IP_PARAM_PROBLEM (11015)"},
{IP_SOURCE_QUENCH, "IP_SOURCE_QUENCH (11016)"},
{IP_OPTION_TOO_BIG, "IP_OPTION_TOO_BIG (11017)"},
{IP_BAD_DESTINATION, "IP_BAD_DESTINATION (11018)"},
{IP_ADDR_DELETED, "IP_ADDR_DELETED (11019)"},
{IP_SPEC_MTU_CHANGE, "IP_SPEC_MTU_CHANGE (11020)"},
{IP_MTU_CHANGE, "IP_MTU_CHANGE (11021)"},
{IP_UNLOAD, "IP_UNLOAD (11022)"},
{IP_GENERAL_FAILURE, "IP_GENERAL_FAILURE"},
{-1, NULL}
};
//----------------------------------------------------------------------------
// IP Flags - 3 bits
// bit 0: reserved
// bit 1: 0=May Fragment, 1=Don't Fragment
// bit 2: 0=Last Fragment, 1=More Fragments
//----------------------------------------------------------------------------
#define IPFLAG_DONT_FRAGMENT 0x02
//----------------------------------------------------------------------------
// Router Alert is defined by Dave Katz of Cisco in
// ftp://ds.internic.net/rfc/rfc2113.txt
// and is used by RSVP and IGMPv2
//
// The Router Alert option has the following format:
//
// +--------+--------+--------+--------+
// |10010100|00000100| 2 octet value |
// +--------+--------+--------+--------+
//
// Type:
// Copied flag: 1 (all fragments must carry the option)
// Option class: 0 (control)
// Option number: 20 (decimal)
//
// Length: 4
//
// Value: A two octet code with the following values:
// 0 - Router shall examine packet
// 1 - 65535 - Reserved
//----------------------------------------------------------------------------
#define IPOPT_ROUTER_ALERT 0x94040000L
//----------------------------------------------------------------------------
// *** Note 2 ***
// For the most part, you can refer to RFC 791 for detials
// on how to fill in values for the IP option information structure.
//----------------------------------------------------------------------------
typedef struct ip_option_information
{
unsigned char TTL; // Time To Live (used for traceroute)
unsigned char TOS; // Type Of Service (usually 0)
unsigned char Flags; // IP header flags (usually 0)
unsigned char OptionsSize; // Size of options data (usually 0, max 40)
unsigned char FAR* OptionsData; // Options data buffer
} IPINFO, *PIPINFO, FAR *LPIPINFO;
//----------------------------------------------------------------------------
// *** Note 1 ***
// The Reply Buffer will have an array of ICMP_ECHO_REPLY
// structures, followed by options and the data in ICMP echo reply
// datagram received. You must have room for at least one ICMP
// echo reply structure, plus 8 bytes for an ICMP header.
//----------------------------------------------------------------------------
typedef struct icmp_echo_reply
{
unsigned long Address; // source address
unsigned long Status; // IP status value (see below)
unsigned long RTTime; // Round Trip Time in milliseconds
unsigned short DataSize; // reply data size
unsigned short Reserved;
void FAR* Data; // reply data buffer
struct ip_option_information Options; // reply options
} ICMPECHO, *PICMPECHO, FAR *LPICMPECHO;
//----------------------------------------------------------------------------
enum ICMP_REQUEST_CLASS
{
ICMP_REQUEST_CLASS_PING = 0,
ICMP_REQUEST_CLASS_TRACEROUTE,
ICMP_REQUEST_CLASS_MAX
};
//----------------------------------------------------------------------------
typedef struct icmp_request
{
int RequestClass;
string Host;
int nDataLength;
int nLoopLimit;
int nTimeout;
bool bDontFrag;
bool bDebug;
int nTTL;
int nTOS;
bool bRouterAlert;
} ICMP_REQUEST;
//----------------------------------------------------------------------------
typedef list<string> ICMP_HOP_LIST;
//----------------------------------------------------------------------------
typedef struct icmp_result
{
int RequestClass;
string Host;
DWORD AverageTime;
DWORD BytesTransferred;
ICMP_HOP_LIST HopList;
} ICMP_RESULT;
class ICMPThread;
//////////////////////////////////////////////////////////////////////////////
// Classname : ICMPRepository
// Description :
//////////////////////////////////////////////////////////////////////////////
class ICMPRepository : public Singleton<ICMPRepository>
{
private:
typedef list<ICMP_REQUEST*> REQUEST_LIST;
typedef hash_map<string, ICMP_RESULT*> RESULT_MAP;
private:
REQUEST_LIST m_RequestList;
RESULT_MAP m_ResultMap;
mutable CriticalSection m_RequestCS;
mutable CriticalSection m_ResultCS;
ICMPThread** m_ppICMPThreads;
int m_ICMPThreadCount;
public:
ICMPRepository();
~ICMPRepository();
public:
// ICMP operation ¿äûÀ» Å¥¿¡´Ù Áý¾î³Ö´Â´Ù.
// ±âº» ¿É¼ÇÀ» »ç¿ëÇØ¼ ¿äûÀ» ÇÒ ¶§ ¾²ÀÌ´Â ÇÔ¼ö´Ù.
void enqueueRequest(const string& host, int request);
// ICMP operation ¿äûÀ» Å¥¿¡´Ù Áý¾î³Ö´Â´Ù.
// ±âº» ¿É¼ÇÀ» ¿À¹ö¶óÀ̵åÇØ¼ ¿äûÀ» ÇϰíÀÚÇÒ ¶§ ¾²ÀÌ´Â ÇÔ¼ö´Ù.
void enqueueRequest(ICMP_REQUEST* pRequest);
// ICMP operation ¿äûÀ» Å¥¿¡¼ ²¨³½´Ù.
// Å¥¿¡ ¾Æ¹« °Íµµ ¾øÀ» °æ¿ì NULLÀ» ¸®ÅÏÇÑ´Ù.
ICMP_REQUEST* dequeueRequest();
// operation °á°ú Á¤º¸¸¦ ¸Ê¿¡¼ ã¾Æ¼ ¸®ÅÏÇÑ´Ù. ¾øÀ¸¸é NULLÀ» ¸®ÅÏ
ICMP_RESULT* getResult(const string& host) const;
// operation °á°ú Á¤º¸¸¦ ¸Ê¿¡´Ù Ãß°¡ÇÑ´Ù. ÀÌ¹Ì ÀÖÀ» °æ¿ì ¾î¼Æ®!
void addResult(ICMP_RESULT* pResult);
// ÇØ´çÇÏ´Â operation °á°ú Á¤º¸¸¦ ¸Ê¿¡¼ »èÁ¦ÇÑ´Ù. ¾øÀ» °æ¿ì ¾î¼Æ®
void deleteResult(const string& host);
};
// global varible
#define g_pICMPRepository ICMPRepository::instance()
//////////////////////////////////////////////////////////////////////////////
// Classname : ICMPThread
// Description :
//////////////////////////////////////////////////////////////////////////////
class ICMPThread : public Thread
{
friend class ICMPRepository;
private:
typedef HANDLE (CALLBACK *PROC_ICMP_CREATE_FILE)(VOID);
typedef BOOL (CALLBACK *PROC_ICMP_CLOSE_HANDLE)(HANDLE ICMPHandle);
typedef DWORD (CALLBACK *PROC_ICMP_SEND_ECHO)(HANDLE IcmpHandle, unsigned long DestAddress, LPVOID RequestData, WORD RequestSize, LPIPINFO RequestOptns, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout);
private:
bool m_bContinue;
HMODULE m_hICMPDLL;
HANDLE m_hICMP;
PROC_ICMP_CREATE_FILE m_pfnIcmpCreateFile;
PROC_ICMP_CLOSE_HANDLE m_pfnIcmpCloseHandle;
PROC_ICMP_SEND_ECHO m_pfnIcmpSendEcho;
char* m_pRequestData;
char* m_pReplyData;
int m_DataBufferSize;
public:
ICMPThread();
~ICMPThread();
public:
// ¾²·¹µå¿¡¼ µ¶¸³ÀûÀ¸·Î ½ÇÇàµÇ´Â Äڵ尡 µé¾î°¡´Â ºÎºÐÀÌ´Ù. Thread Ŭ·¡½º¸¦
// »ó¼Ó¹ÞÀº ÇÏÀ§ Ŭ·¡½º´Â Ç×»ó ÀÌ ÇÔ¼ö¸¦ ÀçÁ¤ÀÇÇØÁà¾ß ÇÑ´Ù.
DWORD run();
// ¾²·¹µå ÇÔ¼ö¸¦ ¿ÏÀüÈ÷ Á¾·á½ÃŲ´Ù.
// ÀÌ method¸¦ ºÎ¸¥ µÚ¿¡´Â ¾²·¹µå¸¦ Àç½ÇÇà½Ãų ¼ö ¾ø´Ù.
void stop();
private:
// pingÀ» ½ÃµµÇÑ´Ù.
void ping(ICMP_REQUEST* pRequest, ICMP_RESULT* pResult);
// traceroute¸¦ ½ÃµµÇÑ´Ù.
void traceroute(ICMP_REQUEST* pRequest, ICMP_RESULT* pResult);
// ±âÁ¸ÀÇ µ¥ÀÌÅÍ ¹öÆÛ¸¦ »èÁ¦Çϰí, »õ·Î¿î µ¥ÀÌÅÍ ¹öÆÛ¸¦ »ý¼ºÇÑ´Ù.
void resizeDataBuffer(int NewDataLength);
// ¿¡·¯ Äڵ带 ¹®ÀÚ¿·Î ¹Ù²ã¼ ȸ鿡 Ãâ·ÂÇÑ´Ù.
void outputError(int nICMPError) const;
};
#endif //__ICMPREPOSITORY_H__
2.3 ICMPRepository.cpp
#include "ICMPRepository.h"
#include "FunctionObject.h"
#include "StringStream.h"
#include <iostream>
ICMPRepository::ICMPRepository()
{
m_ICMPThreadCount = 1;
m_ppICMPThreads = new ICMPThread*[m_ICMPThreadCount];
for (int i=0; i<m_ICMPThreadCount; i++)
{
m_ppICMPThreads[i] = new ICMPThread();
m_ppICMPThreads[i]->start(true);
}
}
ICMPRepository::~ICMPRepository()
{
for (int i=0; i<m_ICMPThreadCount; i++)
{
m_ppICMPThreads[i]->stop();
Sleep(1000);
delete m_ppICMPThreads[i];
}
delete [] m_ppICMPThreads;
DESTROY_ALL_OBJECT_1(m_RequestList);
DESTROY_ALL_OBJECT_2(m_ResultMap);
}
// ICMP operation ¿äûÀ» Å¥¿¡´Ù Áý¾î³Ö´Â´Ù.
// ±âº» ¿É¼ÇÀ» »ç¿ëÇØ¼ ¿äûÀ» ÇÒ ¶§ ¾²ÀÌ´Â ÇÔ¼ö´Ù.
void ICMPRepository::enqueueRequest(const string& host, int request)
{
Assert(!host.empty());
Assert(request >= 0);
Assert(request < ICMP_REQUEST_CLASS_MAX);
__GUARDED_AREA(m_RequestCS);
// ÀÌ¹Ì °°Àº È£½ºÆ®°¡ Á¸ÀçÇÏÁö ¾Ê´ÂÁö °Ë»çÇÑ´Ù.
// È¿À²¼ºÀÌ ÀǽɵǴ ºÎºÐÀÌ´Ï ³ªÁß¿¡´Â »©¾ßÇÑ´Ù.
REQUEST_LIST::const_iterator itr = m_RequestList.begin();
for (; itr != m_RequestList.end(); itr++)
{
ICMP_REQUEST* pRequest = *itr;
if (host == pRequest->Host)
{
Assert(false);
}
}
ICMP_REQUEST* pNewRequest = new ICMP_REQUEST;
// ±âº» ¿É¼ÇÀ» ¼¼ÆÃÇÑ´Ù.
// ±âº» ¿É¼Ç ÀÚü¸¦ ¼öÁ¤ÇÏ´Â ÇÔ¼ö¸¦ Á¦°øÇÏ°í ½Í±â´Â ÇÏÁö¸¸, ±ÍÂú´Ù.
pNewRequest->RequestClass = request;
pNewRequest->Host = host;
pNewRequest->nDataLength = 8192;
pNewRequest->nLoopLimit = 4;
pNewRequest->nTimeout = 5000;
pNewRequest->bDontFrag = false;
pNewRequest->bDebug = false;
pNewRequest->nTTL = 64;
pNewRequest->nTOS = 0;
pNewRequest->bRouterAlert = false;
m_RequestList.push_back(pNewRequest);
}
// ICMP operation ¿äûÀ» Å¥¿¡´Ù Áý¾î³Ö´Â´Ù.
// ±âº» ¿É¼ÇÀ» ¿À¹ö¶óÀ̵åÇØ¼ ¿äûÀ» ÇϰíÀÚÇÒ ¶§ ¾²ÀÌ´Â ÇÔ¼ö´Ù.
void ICMPRepository::enqueueRequest(ICMP_REQUEST* pRequest)
{
Assert(!(pRequest->Host.empty()));
Assert(pRequest->RequestClass >= 0);
Assert(pRequest->RequestClass < ICMP_REQUEST_CLASS_MAX);
__GUARDED_AREA(m_RequestCS);
// ÀÌ¹Ì °°Àº È£½ºÆ®°¡ Á¸ÀçÇÏÁö ¾Ê´ÂÁö °Ë»çÇÑ´Ù.
// È¿À²¼ºÀÌ ÀǽɵǴ ºÎºÐÀÌ´Ï ³ªÁß¿¡´Â »©¾ßÇÑ´Ù.
REQUEST_LIST::const_iterator itr = m_RequestList.begin();
for (; itr != m_RequestList.end(); itr++)
{
ICMP_REQUEST* pPrevRequest = *itr;
if (pRequest->Host == pPrevRequest->Host)
{
Assert(false);
}
}
// ÀÌ ºÎºÐ¿¡ ÇÔ¼ö ÀÎÀÚ¸¦ Á¶»çÇÒ Çʿ䰡 ÀÖÀ» µíÇѵ¥...
m_RequestList.push_back(pRequest);
}
// ICMP operation ¿äûÀ» Å¥¿¡¼ ²¨³½´Ù.
// Å¥¿¡ ¾Æ¹« °Íµµ ¾øÀ» °æ¿ì NULLÀ» ¸®ÅÏÇÑ´Ù.
ICMP_REQUEST* ICMPRepository::dequeueRequest()
{
__GUARDED_AREA(m_RequestCS);
if (m_RequestList.empty()) return NULL;
ICMP_REQUEST* pRequest = m_RequestList.front();
m_RequestList.pop_front();
return pRequest;
}
// operation °á°ú Á¤º¸¸¦ ¸Ê¿¡¼ ã¾Æ¼ ¸®ÅÏÇÑ´Ù. ¾øÀ¸¸é NULLÀ» ¸®ÅÏ
ICMP_RESULT* ICMPRepository::getResult(const string& host) const
{
__GUARDED_AREA(m_ResultCS);
RESULT_MAP::const_iterator itr = m_ResultMap.find(host);
if (itr != m_ResultMap.end())
{
return itr->second;
}
return NULL;
}
// operation °á°ú Á¤º¸¸¦ ¸Ê¿¡´Ù Ãß°¡ÇÑ´Ù. ÀÌ¹Ì ÀÖÀ» °æ¿ì ¾î¼Æ®!
void ICMPRepository::addResult(ICMP_RESULT* pResult)
{
__GUARDED_AREA(m_ResultCS);
RESULT_MAP::const_iterator itr = m_ResultMap.find(pResult->Host);
if (itr == m_ResultMap.end())
{
m_ResultMap.insert(RESULT_MAP::value_type(pResult->Host, pResult));
}
else
{
NEVER_GET_HERE;
}
}
// ÇØ´çÇÏ´Â operation °á°ú Á¤º¸¸¦ ¸Ê¿¡¼ »èÁ¦ÇÑ´Ù. ¾øÀ» °æ¿ì ¾î¼Æ®
void ICMPRepository::deleteResult(const string& host)
{
__GUARDED_AREA(m_ResultCS);
RESULT_MAP::iterator itr = m_ResultMap.find(host);
if (itr != m_ResultMap.end())
{
SAFE_DELETE(itr->second);
m_ResultMap.erase(itr);
}
else
{
NEVER_GET_HERE;
}
}
ICMPThread::ICMPThread()
: Thread()
{
m_bContinue = true;
m_DataBufferSize = 0;
m_pRequestData = NULL;
m_pReplyData = NULL;
// Load the ICMP.DLL
m_hICMPDLL = ::LoadLibrary("ICMP.DLL");
if (m_hICMPDLL == 0)
{
printError("Unable to locate ICMP.DLL!");
NEVER_GET_HERE;
}
// Get pointers to ICMP.DLL functions
m_pfnIcmpCreateFile = (PROC_ICMP_CREATE_FILE)GetProcAddress(m_hICMPDLL,"IcmpCreateFile");
m_pfnIcmpCloseHandle = (PROC_ICMP_CLOSE_HANDLE)GetProcAddress(m_hICMPDLL,"IcmpCloseHandle");
m_pfnIcmpSendEcho = (PROC_ICMP_SEND_ECHO)GetProcAddress(m_hICMPDLL,"IcmpSendEcho");
if (!m_pfnIcmpCreateFile || !m_pfnIcmpCloseHandle || !m_pfnIcmpSendEcho)
{
printError("failed to get at least one function.");
NEVER_GET_HERE;
}
m_hICMP = (HANDLE)m_pfnIcmpCreateFile();
Assert(m_hICMP != INVALID_HANDLE_VALUE);
resizeDataBuffer(8192);
}
ICMPThread::~ICMPThread()
{
SAFE_DELETE_ARRAY(m_pRequestData);
SAFE_DELETE_ARRAY(m_pReplyData);
if (!m_pfnIcmpCloseHandle(m_hICMP))
{
NEVER_GET_HERE;
}
// Shut down...
::FreeLibrary(m_hICMPDLL);
}
// ¾²·¹µå¿¡¼ µ¶¸³ÀûÀ¸·Î ½ÇÇàµÇ´Â Äڵ尡 µé¾î°¡´Â ºÎºÐÀÌ´Ù. Thread Ŭ·¡½º¸¦
// »ó¼Ó¹ÞÀº ÇÏÀ§ Ŭ·¡½º´Â Ç×»ó ÀÌ ÇÔ¼ö¸¦ ÀçÁ¤ÀÇÇØÁà¾ß ÇÑ´Ù.
DWORD ICMPThread::run()
{
while (m_bContinue)
{
ICMP_REQUEST* pRequest = g_pICMPRepository->dequeueRequest();
if (pRequest == NULL)
{
Sleep(1000);
continue;
}
ICMP_RESULT* pResult = new ICMP_RESULT;
pResult->RequestClass = pRequest->RequestClass;
pResult->Host = pRequest->Host;
pResult->AverageTime = 0;
pResult->BytesTransferred = 0;
if (pRequest->RequestClass == ICMP_REQUEST_CLASS_PING)
{
ping(pRequest, pResult);
}
else if (pRequest->RequestClass == ICMP_REQUEST_CLASS_TRACEROUTE)
{
traceroute(pRequest, pResult);
}
else
{
NEVER_GET_HERE;
}
// °á°ú°ªÀ» Ãß°¡Çϰí...
g_pICMPRepository->addResult(pResult);
// ¿äû Á¤º¸¸¦ »èÁ¦ÇÑ´Ù.
SAFE_DELETE(pRequest);
}
return 0;
}
// ¾²·¹µå ÇÔ¼ö¸¦ ¿ÏÀüÈ÷ Á¾·á½ÃŲ´Ù.
// ÀÌ method¸¦ ºÎ¸¥ µÚ¿¡´Â ¾²·¹µå¸¦ Àç½ÇÇà½Ãų ¼ö ¾ø´Ù.
void ICMPThread::stop()
{
m_bContinue = false;
}
void ICMPThread::ping(ICMP_REQUEST* pRequest, ICMP_RESULT* pResult)
{
IPINFO stIPInfo;
IN_ADDR stDestAddr;
// Is the string an address?
stDestAddr.s_addr = inet_addr(pResult->Host.c_str());
Assert(stDestAddr.s_addr != INADDR_NONE);
if (pRequest->nDataLength > m_DataBufferSize)
{
resizeDataBuffer(pRequest->nDataLength);
}
// Init data buffer printable ASCII, 32 (space) through 126 (tilde)
for (int j=0, i=32; j<pRequest->nDataLength; j++, i++)
{
if (i>=126) i= 32;
m_pRequestData[j] = i;
}
// Init IPInfo structure
stIPInfo.TTL = pRequest->nTTL;
stIPInfo.TOS = pRequest->nTOS;
stIPInfo.Flags = pRequest->bDontFrag ? IPFLAG_DONT_FRAGMENT : 0;
if (pRequest->bRouterAlert)
{
// Works if IP Flags NOT set
DWORD dwIPOption = htonl(IPOPT_ROUTER_ALERT);
stIPInfo.OptionsSize = sizeof(dwIPOption);
stIPInfo.OptionsData = (unsigned char*)&dwIPOption;
}
else
{
stIPInfo.OptionsSize = 0;
stIPInfo.OptionsData = NULL;
}
// Ping Loop
for (int k=0; k<pRequest->nLoopLimit; k++)
{
// Send the ICMP Echo Request and read the Reply
DWORD dwReplyCount = m_pfnIcmpSendEcho(
m_hICMP,
stDestAddr.s_addr,
m_pRequestData,
pRequest->nDataLength,
&stIPInfo,
m_pReplyData,
sizeof(ICMPECHO) + m_DataBufferSize,
pRequest->nTimeout);
if (dwReplyCount != 0)
{
IN_ADDR stDestAddr;
DWORD dwStatus;
stDestAddr.s_addr = *(DWORD*)m_pReplyData;
// Reply from %s : inet_ntoa(stDestAddr)
// Bytes Transferred %d : *(DWORD*)&(m_pReplyData[12])
// Time (millisecond) %d : *(DWORD*)&(m_pReplyData[8])
// TTL %d : (*(char*)&(m_pReplyData[20])) & 0x00FF
pResult->BytesTransferred += *(DWORD*)&(m_pReplyData[12]);
pResult->AverageTime += *(DWORD*)&(m_pReplyData[8]);
dwStatus = *(DWORD*)&(m_pReplyData[4]);
if (dwStatus != IP_SUCCESS)
{
outputError(dwStatus);
}
}
else
{
outputError(GetLastError());
break;
}
}
pResult->AverageTime = pResult->AverageTime / pRequest->nLoopLimit;
}
void ICMPThread::traceroute(ICMP_REQUEST* pRequest, ICMP_RESULT* pResult)
{
IPINFO stIPInfo;
IN_ADDR stDestAddr;
// Is the string an address?
stDestAddr.s_addr = inet_addr(pResult->Host.c_str());
Assert(stDestAddr.s_addr != INADDR_NONE);
if (pRequest->nDataLength > m_DataBufferSize)
{
resizeDataBuffer(pRequest->nDataLength);
}
// Init data buffer printable ASCII, 32 (space) through 126 (tilde)
for (int j=0, i=32; j<pRequest->nDataLength; j++, i++)
{
if (i>=126) i= 32;
m_pRequestData[j] = i;
}
// Init IPInfo structure
// traceroute¸¦ ÇÒ ¶§´Â TTLÀº ¹Ýµå½Ã 0À̾î¾ßÇÑ´Ù.
stIPInfo.TTL = 0;
stIPInfo.TOS = pRequest->nTOS;
stIPInfo.Flags = pRequest->bDontFrag ? IPFLAG_DONT_FRAGMENT : 0;
if (pRequest->bRouterAlert)
{
// Works if IP Flags NOT set
DWORD dwIPOption = htonl(IPOPT_ROUTER_ALERT);
stIPInfo.OptionsSize = sizeof(dwIPOption);
stIPInfo.OptionsData = (unsigned char*)&dwIPOption;
}
else
{
stIPInfo.OptionsSize = 0;
stIPInfo.OptionsData = NULL;
}
// traceroute loop
while (true)
{
// increase IP Time To Live
++stIPInfo.TTL;
// Send the ICMP Echo Request and read the Reply
DWORD dwReplyCount = m_pfnIcmpSendEcho(m_hICMP,
stDestAddr.s_addr,
m_pRequestData,
pRequest->nDataLength,
&stIPInfo,
m_pReplyData,
sizeof(ICMPECHO) + m_DataBufferSize,
pRequest->nTimeout);
if (dwReplyCount != 0)
{
IN_ADDR stDestAddr;
DWORD dwStatus;
stDestAddr.s_addr = *(DWORD *)m_pReplyData;
// Reply from %s : inet_ntoa(stDestAddr)
// Bytes Transferred %d : *(DWORD*)&(m_pReplyData[12])
// Time (millisecond) %d : *(DWORD*)&(m_pReplyData[8])
// TTL %d : (*(char*)&(m_pReplyData[20])) & 0x00FF
pResult->HopList.push_back(string(inet_ntoa(stDestAddr)));
dwStatus = *(DWORD*)&(m_pReplyData[4]);
if (dwStatus == IP_SUCCESS)
{
// We're done, since we reached the destination!
break;
}
}
else
{
outputError(::GetLastError());
}
}
}
// ±âÁ¸ÀÇ µ¥ÀÌÅÍ ¹öÆÛ¸¦ »èÁ¦Çϰí, »õ·Î¿î µ¥ÀÌÅÍ ¹öÆÛ¸¦ »ý¼ºÇÑ´Ù.
void ICMPThread::resizeDataBuffer(int NewDataLength)
{
Assert(m_DataBufferSize < NewDataLength);
SAFE_DELETE_ARRAY(m_pRequestData);
SAFE_DELETE_ARRAY(m_pReplyData);
m_DataBufferSize = NewDataLength;
m_pRequestData = new char[m_DataBufferSize];
m_pReplyData = new char[sizeof(ICMPECHO) + m_DataBufferSize];
}
// ¿¡·¯ Äڵ带 ¹®ÀÚ¿·Î ¹Ù²ã¼ ȸ鿡 Ãâ·ÂÇÑ´Ù.
void ICMPThread::outputError(int nICMPErr) const
{
int nErrIndex = nICMPErr - IP_STATUS_BASE;
if (ID2String(ICMPStatus2String, nErrIndex) == NULL)
{
cerr << "(" << nICMPErr << ") " << convertErrorToString(nICMPErr) << endl;
}
else
{
cerr << ID2String(ICMPStatus2String, nErrIndex) << endl;
}
}
3 Ping Implementation
3.1 Microsoft ICMP Library Version
Microsoft ICMP ¶óÀ̺귯¸®¸¦ »ç¿ëÇÑ Ping ¿¹Á¦ÀÌ´Ù.
3.1.1 PingI.c
//
// PingI.c -- Simple ping program using the proprietary
// Microsoft ICMP API
//
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <string.h>
typedef struct tagIPINFO
{
u_char Ttl; // Time To Live
u_char Tos; // Type Of Service
u_char IPFlags; // IP flags
u_char OptSize; // Size of options data
u_char FAR *Options; // Options data buffer
}IPINFO, *PIPINFO;
typedef struct tagICMPECHO
{
u_long Source; // Source address
u_long Status; // IP status
u_long RTTime; // Round trip time in milliseconds
u_short DataSize; // Reply data size
u_short Reserved; // Unknown
void FAR *pData; // Reply data buffer
IPINFO ipInfo; // Reply options
}ICMPECHO, *PICMPECHO;
// ICMP.DLL Export Function Pointers
HANDLE (WINAPI *pIcmpCreateFile)(VOID);
BOOL (WINAPI *pIcmpCloseHandle)(HANDLE);
DWORD (WINAPI *pIcmpSendEcho)
(HANDLE,DWORD,LPVOID,WORD,PIPINFO,LPVOID,DWORD,DWORD);
//
//
void main(int argc, char **argv)
{
WSADATA wsaData; // WSADATA
ICMPECHO icmpEcho; // ICMP Echo reply buffer
HANDLE hndlIcmp; // LoadLibrary() handle to ICMP.DLL
HANDLE hndlFile; // Handle for IcmpCreateFile()
LPHOSTENT pHost; // Pointer to host entry structure
struct in_addr iaDest; // Internet address structure
DWORD *dwAddress; // IP Address
IPINFO ipInfo; // IP Options structure
int nRet; // General use return code
DWORD dwRet; // DWORD return code
int x;
// Check arguments
if (argc != 2)
{
fprintf(stderr,"\nSyntax: pingi HostNameOrIPAddress\n");
return;
}
// Dynamically load the ICMP.DLL
hndlIcmp = LoadLibrary("ICMP.DLL");
if (hndlIcmp == NULL)
{
fprintf(stderr,"\nCould not load ICMP.DLL\n");
return;
}
// Retrieve ICMP function pointers<