// 9
int __cdecl main(
int argc,
char **argv)
{
WSADATA wsd;
WSAOVERLAPPED recvol;
// 重叠 IO
SOCKET s=INVALID_SOCKET;
char *icmpbuf=NULL;
struct addrinfo *dest=NULL,
*local=NULL;
IPV4_OPTION_HDR ipopt;
SOCKADDR_STORAGE from;
// socket地址存储结构(9.1)
DWORD bytes,
flags;
int packetlen=
0,
fromlen,
time=
0,
rc,
i,
status =
0;
recvol.hEvent = WSA_INVALID_EVENT;
// 分析输入参数
if (ValidateArgs(argc, argv) == FALSE)
{
status = -
1;
goto EXIT;
}
// socket模块启动初始化
if ((rc = WSAStartup(MAKEWORD(
2,
2), &wsd)) !=
0)
{
printf(
"WSAStartup() failed: %d\n", rc);
status = -
1;
goto EXIT;
}
// 解析目的地址
dest = ResolveAddress(
gDestination,
"0",
gAddressFamily,
0,
0
);
if (dest == NULL)
{
printf(
"bad name %s\n", gDestination);
status = -
1;
goto CLEANUP;
}
gAddressFamily = dest->ai_family;
if (gAddressFamily == AF_INET)
gProtocol = IPPROTO_ICMP;
else if (gAddressFamily == AF_INET6)
gProtocol = IPPROTO_ICMP6;
// 获得本地地址,绑定使用
local = ResolveAddress(
NULL,
"0",
gAddressFamily,
0,
0
);
if (local == NULL)
{
printf(
"Unable to obtain the bind address!\n");
status = -
1;
goto CLEANUP;
}
//创建Raw套接字,protocol = IPPROTO_ICMP
s = socket(gAddressFamily, SOCK_RAW, gProtocol);
if (s == INVALID_SOCKET)
{
printf(
"socket failed: %d\n", WSAGetLastError());
status = -
1;
goto CLEANUP;
}
SetTtl(s, gTtl);
//设置最大跳站数为128
if (gAddressFamily == AF_INET)
packetlen +=
sizeof(ICMP_HDR);
else if (gAddressFamily == AF_INET6)
packetlen +=
sizeof(ICMPV6_HDR) +
sizeof(ICMPV6_ECHO_REQUEST);
// packetlen 为 数据长度+ICMP头部长度
packetlen += gDataSize;
// 分配空间存储ICMP请求(9.2)
icmpbuf = (
char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen);
if (icmpbuf == NULL)
{
fprintf(stderr,
"HeapAlloc failed: %d\n", GetLastError());
status = -
1;
goto CLEANUP;
}
// 初始化 ICMP 头部
if (gAddressFamily == AF_INET)
{
if (bRecordRoute)
// 如有路由记录功能,初始化选项数据段
{
ZeroMemory(&ipopt,
sizeof(ipopt));
ipopt.opt_code = IP_RECORD_ROUTE;
// 路由记录选项
ipopt.opt_ptr =
4;
// 指向可用的地址,每个地址占用4字节,此指针指向第一个可用的存储偏移地址
ipopt.opt_len =
39;
// 选项数据段长度
rc = setsockopt(s, IPPROTO_IP, IP_OPTIONS,
(
char *)&ipopt,
sizeof(ipopt));
if (rc == SOCKET_ERROR)
{
fprintf(stderr,
"setsockopt(IP_OPTIONS) failed: %d\n", WSAGetLastError());
status = -
1;
goto CLEANUP;
}
}
InitIcmpHeader(icmpbuf, gDataSize);
}
else if (gAddressFamily == AF_INET6)
{
InitIcmp6Header(icmpbuf, gDataSize);
}
// 绑定地址,
此套接字可获得
外部单元向这个地址发送的数据
rc = bind(s, local->ai_addr, (
int)local->ai_addrlen);
if (rc == SOCKET_ERROR)
{
fprintf(stderr,
"bind failed: %d\n", WSAGetLastError());
status = -
1;
goto CLEANUP;
}
// 建立接收操作
memset(&recvol,
0,
sizeof(recvol));
recvol.hEvent = WSACreateEvent();
// 事件初始化
if (recvol.hEvent == WSA_INVALID_EVENT)
{
fprintf(stderr,
"WSACreateEvent failed: %d\n", WSAGetLastError());
status = -
1;
goto CLEANUP;
}
// 异步接收
fromlen =
sizeof(from);
PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);
printf(
"\nPinging ");
PrintAddress(dest->ai_addr, (
int)dest->ai_addrlen);
printf(
" with %d bytes of data\n\n", gDataSize);
// ping 4 次
for(i=
0; i < DEFAULT_SEND_COUNT ;i++)
{
// 设置序列号并计算校验和
SetIcmpSequence(icmpbuf);
ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);
time = GetTickCount();
rc = sendto(
// 发送icmp请求
s,
icmpbuf,
packetlen,
0,
dest->ai_addr,
(
int)dest->ai_addrlen
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr,
"sendto failed: %d\n", WSAGetLastError());
status = -
1;
goto CLEANUP;
}
// 等待ICMP回复(9.3)
rc = WaitForSingleObject((HANDLE)recvol.hEvent, DEFAULT_RECV_TIMEOUT);
if (rc == WAIT_FAILED)
{
fprintf(stderr,
"WaitForSingleObject failed: %d\n", GetLastError());
status = -
1;
goto CLEANUP;
}
else if (rc == WAIT_TIMEOUT)
{
printf(
"Request timed out.\n");
}
else
{
// 收到ICMP回复
rc = WSAGetOverlappedResult(
s,
&recvol,
&bytes,
FALSE,
&flags
);
if (rc == FALSE)
{
fprintf(stderr,
"WSAGetOverlappedResult failed: %d\n", WSAGetLastError());
}
time = GetTickCount() - time;
WSAResetEvent(recvol.hEvent);
printf(
"Reply from ");
PrintAddress((SOCKADDR *)&from, fromlen);
if (time ==
0)
printf(
": bytes=%d time<1ms TTL=%d\n", gDataSize, gTtl);
else
printf(
": bytes=%d time=%dms TTL=%d\n", gDataSize, time, gTtl);
PrintPayload(recvbuf, bytes);
if (i < DEFAULT_SEND_COUNT -
1)
{
fromlen =
sizeof(from);
PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);
}
}
Sleep(
1000);
}
CLEANUP:
if (dest)
freeaddrinfo(dest);
if (local)
freeaddrinfo(local);
if (s != INVALID_SOCKET)
closesocket(s);
if (recvol.hEvent != WSA_INVALID_EVENT)
WSACloseEvent(recvol.hEvent);
if (icmpbuf)
HeapFree(GetProcessHeap(),
0, icmpbuf);
WSACleanup();
EXIT:
system(
"pause");
return status;
}