-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
Copy pathPing.cpp
815 lines (713 loc) · 21.6 KB
/
Ping.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
// From Network Programming for Microsoft Windows, Second Edition by
// Anthony Jones and James Ohlund.
// Copyright 2002. Reproduced by permission of Microsoft Press.
// All rights reserved.
//
//
// Sample: IPv4 and IPv6 Ping Sample
//
// Files:
// iphdr.h - IPv4 and IPv6 packet header definitions
// ping.cpp - this file
// resolve.cpp - Common name resolution routine
// resolve.h - Header file for common name resolution routines
//
// Description:
// This sample illustrates how to use raw sockets to send ICMP
// echo requests and receive their response. This sample performs
// both IPv4 and IPv6 ICMP echo requests. When using raw sockets,
// the protocol value supplied to the socket API is used as the
// protocol field (or next header field) of the IP packet. Then
// as a part of the data submitted to sendto, we include both
// the ICMP request and data.
//
// For IPv4 the IP record route option is supported via the
// IP_OPTIONS socket option.
//
// Compile:
// cl -o ping.exe ping.cpp resolve.cpp ws2_32.lib
//
// Command Line Options/Parameters:
// ping.exe [-a 4|6] [-i ttl] [-l datasize] [-r] [host]
//
// -a Address family (IPv4 or IPv6)
// -i ttl TTL value to set on socket
// -l size Amount of data to send as part of the ICMP request
// -r Use IPv4 record route
// host Hostname or literal address
//
#ifdef _IA64_
#pragma warning (disable: 4267)
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include "resolve.h"
#include "iphdr.h"
#define DEFAULT_DATA_SIZE 32 // default data size
#define DEFAULT_SEND_COUNT 4 // number of ICMP requests to send
#define DEFAULT_RECV_TIMEOUT 6000 // six second
#define DEFAULT_TTL 128
#define MAX_RECV_BUF_LEN 0xFFFF // Max incoming packet size.
int gAddressFamily=AF_UNSPEC, // Address family to use
gProtocol=IPPROTO_ICMP, // Protocol value
gTtl=DEFAULT_TTL; // Default TTL value
int gDataSize=DEFAULT_DATA_SIZE; // Amount of data to send
BOOL bRecordRoute=FALSE; // Use IPv4 record route?
char *gDestination=NULL, // Destination
recvbuf[MAX_RECV_BUF_LEN]; // For received packets
int recvbuflen = MAX_RECV_BUF_LEN; // Length of received packets.
//
// Function: usage
//
// Description:
// Print usage information.
//
void usage(char *progname)
{
printf("usage: %s [options] <host> \n", progname);
printf(" host Remote machine to ping\n");
printf(" options: \n");
printf(" -a 4|6 Address family (default: AF_UNSPEC)\n");
printf(" -i ttl Time to live (default: 128) \n");
printf(" -l bytes Amount of data to send (default: 32) \n");
printf(" -r Record route (IPv4 only)\n");
return;
}
//
// Function: InitIcmpHeader
//
// Description:
// Helper function to fill in various stuff in our ICMP request.
//
void InitIcmpHeader(char *buf, int datasize)
{
ICMP_HDR *icmp_hdr=NULL;
char *datapart=NULL;
icmp_hdr = (ICMP_HDR *)buf;
icmp_hdr->icmp_type = ICMPV4_ECHO_REQUEST_TYPE; // request an ICMP echo
icmp_hdr->icmp_code = ICMPV4_ECHO_REQUEST_CODE;
icmp_hdr->icmp_id = (USHORT)GetCurrentProcessId();
icmp_hdr->icmp_checksum = 0;
icmp_hdr->icmp_sequence = 0;
datapart = buf + sizeof(ICMP_HDR);
//
// Place some data in the buffer.
//
memset(datapart, 'E', datasize);
}
//
// Function: InitIcmp6Header
//
// Description:
// Initialize the ICMP6 header as well as the echo request header.
//
int InitIcmp6Header(char *buf, int datasize)
{
ICMPV6_HDR *icmp6_hdr=NULL;
ICMPV6_ECHO_REQUEST *icmp6_req=NULL;
char *datapart=NULL;
// Initialize the ICMP6 headerf ields
icmp6_hdr = (ICMPV6_HDR *)buf;
icmp6_hdr->icmp6_type = ICMPV6_ECHO_REQUEST_TYPE;
icmp6_hdr->icmp6_code = ICMPV6_ECHO_REQUEST_CODE;
icmp6_hdr->icmp6_checksum = 0;
// Initialize the echo request fields
icmp6_req = (ICMPV6_ECHO_REQUEST *)(buf + sizeof(ICMPV6_HDR));
icmp6_req->icmp6_echo_id = (USHORT)GetCurrentProcessId();
icmp6_req->icmp6_echo_sequence = 0;
datapart = (char *)buf + sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST);
memset(datapart, '#', datasize);
return (sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST));
}
//
// Function: checksum
//
// Description:
// This function calculates the 16-bit one's complement sum
// of the supplied buffer (ICMP) header.
//
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
//
// Function: ValidateArgs
//
// Description:
// Parse the command line arguments.
//
BOOL ValidateArgs(int argc, char **argv)
{
int i;
BOOL isValid = FALSE;
for(i=1; i < argc ;i++)
{
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{
switch (tolower(argv[i][1]))
{
case 'a': // address family
if (i+1 >= argc)
{
usage(argv[0]);
goto CLEANUP;
}
if (argv[i+1][0] == '4')
gAddressFamily = AF_INET;
else if (argv[i+1][0] == '6')
gAddressFamily = AF_INET6;
else
{
usage(argv[0]);
goto CLEANUP;
}
i++;
break;
case 'i': // Set TTL value
if (i+1 >= argc)
{
usage(argv[0]);
goto CLEANUP;
}
gTtl = atoi(argv[++i]);
break;
case 'l': // buffer size tos end
if (i+1 >= argc)
{
usage(argv[0]);
goto CLEANUP;
}
gDataSize = atoi(argv[++i]);
break;
case 'r': // record route option
bRecordRoute = TRUE;
break;
default:
usage(argv[0]);
goto CLEANUP;
}
}
else
{
gDestination = argv[i];
}
}
isValid = TRUE;
CLEANUP:
return isValid;
}
//
// Function: SetIcmpSequence
//
// Description:
// This routine sets the sequence number of the ICMP request packet.
//
void SetIcmpSequence(char *buf)
{
ULONG sequence=0;
sequence = GetTickCount();
if (gAddressFamily == AF_INET)
{
ICMP_HDR *icmpv4=NULL;
icmpv4 = (ICMP_HDR *)buf;
icmpv4->icmp_sequence = (USHORT)sequence;
}
else if (gAddressFamily == AF_INET6)
{
ICMPV6_HDR *icmpv6=NULL;
ICMPV6_ECHO_REQUEST *req6=NULL;
icmpv6 = (ICMPV6_HDR *)buf;
req6 = (ICMPV6_ECHO_REQUEST *)(buf + sizeof(ICMPV6_HDR));
req6->icmp6_echo_sequence = (USHORT)sequence;
}
}
//
// Function: ComputeIcmp6PseudoHeaderChecksum
//
// Description:
// This routine computes the ICMP6 checksum which includes the pseudo
// header of the IPv6 header (see RFC2460 and RFC2463). The one difficulty
// here is we have to know the source and destination IPv6 addresses which
// will be contained in the IPv6 header in order to compute the checksum.
// To do this we call the SIO_ROUTING_INTERFACE_QUERY ioctl to find which
// local interface for the outgoing packet.
//
USHORT ComputeIcmp6PseudoHeaderChecksum(SOCKET s, char *icmppacket, int icmplen, struct addrinfo *dest)
{
SOCKADDR_STORAGE localif;
DWORD bytes;
char tmp[MAX_RECV_BUF_LEN] = {'\0'},
*ptr=NULL,
proto=0;
int rc, total, length, i;
// Find out which local interface for the destination
rc = WSAIoctl(
s,
SIO_ROUTING_INTERFACE_QUERY,
dest->ai_addr,
(DWORD) dest->ai_addrlen,
(SOCKADDR *) &localif,
(DWORD) sizeof(localif),
&bytes,
NULL,
NULL
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "WSAIoctl failed: %d\n", WSAGetLastError());
return 0xFFFF;
}
// We use a temporary buffer to calculate the pseudo header.
ptr = tmp;
total = 0;
// Copy source address
memcpy(ptr, &((SOCKADDR_IN6 *)&localif)->sin6_addr, sizeof(struct in6_addr));
ptr += sizeof(struct in6_addr);
total += sizeof(struct in6_addr);
printf("%x%x%x%x\n",
((SOCKADDR_IN6 *) &localif)->sin6_addr.u.Byte[0],
((SOCKADDR_IN6 *) &localif)->sin6_addr.u.Byte[1],
((SOCKADDR_IN6 *) &localif)->sin6_addr.u.Byte[2],
((SOCKADDR_IN6 *) &localif)->sin6_addr.u.Byte[3]
);
// Copy destination address
memcpy(ptr, &((SOCKADDR_IN6 *)dest->ai_addr)->sin6_addr, sizeof(struct in6_addr));
ptr += sizeof(struct in6_addr);
total += sizeof(struct in6_addr);
// Copy ICMP packet length
length = htonl(icmplen);
memcpy(ptr, &length, sizeof(length));
ptr += sizeof(length);
total += sizeof(length);
printf("%x%x%x%x\n",
(char ) *(ptr - 4),
(char ) *(ptr - 3),
(char ) *(ptr - 2),
(char ) *(ptr - 1)
);
// Zero the 3 bytes
memset(ptr, 0, 3);
ptr += 3;
total += 3;
// Copy next hop header
proto = IPPROTO_ICMP6;
memcpy(ptr, &proto, sizeof(proto));
ptr += sizeof(proto);
total += sizeof(proto);
// Copy the ICMP header and payload
memcpy(ptr, icmppacket, icmplen);
ptr += icmplen;
total += icmplen;
for(i=0; i < icmplen%2 ;i++)
{
*ptr = 0;
ptr++;
total++;
}
return checksum((USHORT *)tmp, total);
}
//
// Function: ComputeIcmpChecksum
//
// Description:
// This routine computes the checksum for the ICMP request. For IPv4 its
// easy, just compute the checksum for the ICMP packet and data. For IPv6,
// its more complicated. The pseudo checksum has to be computed for IPv6
// which includes the ICMP6 packet and data plus portions of the IPv6
// header which is difficult since we aren't building our own IPv6
// header.
//
void ComputeIcmpChecksum(SOCKET s, char *buf, int packetlen, struct addrinfo *dest)
{
if (gAddressFamily == AF_INET)
{
ICMP_HDR *icmpv4=NULL;
icmpv4 = (ICMP_HDR *)buf;
icmpv4->icmp_checksum = 0;
icmpv4->icmp_checksum = checksum((USHORT *)buf, packetlen);
}
else if (gAddressFamily == AF_INET6)
{
ICMPV6_HDR *icmpv6=NULL;
icmpv6 = (ICMPV6_HDR *)buf;
icmpv6->icmp6_checksum = 0;
icmpv6->icmp6_checksum = ComputeIcmp6PseudoHeaderChecksum(
s,
buf,
packetlen,
dest
);
}
}
//
// Function: PostRecvfrom
//
// Description:
// This routine posts an overlapped WSARecvFrom on the raw socket.
//
int PostRecvfrom(SOCKET s, char *buf, int buflen, SOCKADDR *from, int *fromlen, WSAOVERLAPPED *ol)
{
WSABUF wbuf;
DWORD flags,
bytes;
int rc;
wbuf.buf = buf;
wbuf.len = buflen;
flags = 0;
rc = WSARecvFrom(
s,
&wbuf,
1,
&bytes,
&flags,
from,
fromlen,
ol,
NULL
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "WSARecvFrom failed: %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
}
return NO_ERROR;
}
//
// Function: PrintPayload
//
// Description:
// This routine is for IPv4 only. It determines if there are any IP options
// present (by seeing if the IP header length is greater than 20 bytes) and
// if so it prints the IP record route options.
//
void PrintPayload(char *buf, int bytes)
{
int hdrlen=0,
routes=0,
i;
UNREFERENCED_PARAMETER(bytes);
if (gAddressFamily == AF_INET)
{
SOCKADDR_IN hop;
IPV4_OPTION_HDR *v4opt=NULL;
IPV4_HDR *v4hdr=NULL;
hop.sin_family = (USHORT)gAddressFamily;
hop.sin_port = 0;
v4hdr = (IPV4_HDR *)buf;
hdrlen = (v4hdr->ip_verlen & 0x0F) * 4;
// If the header length is greater than the size of the basic IPv4
// header then there are options present. Find them and print them.
if (hdrlen > sizeof(IPV4_HDR))
{
v4opt = (IPV4_OPTION_HDR *)(buf + sizeof(IPV4_HDR));
routes = (v4opt->opt_ptr / sizeof(ULONG)) - 1;
for(i=0; i < routes ;i++)
{
hop.sin_addr.s_addr = v4opt->opt_addr[i];
// Print the route
if (i == 0)
printf(" Route: ");
else
printf(" ");
PrintAddress((SOCKADDR *)&hop, sizeof(hop));
if (i < routes-1)
printf(" ->\n");
else
printf("\n");
}
}
}
return;
}
//
// Function: SetTtl
//
// Description:
// Sets the TTL on the socket.
//
int SetTtl(SOCKET s, int ttl)
{
int optlevel = 0,
option = 0,
rc;
rc = NO_ERROR;
if (gAddressFamily == AF_INET)
{
optlevel = IPPROTO_IP;
option = IP_TTL;
}
else if (gAddressFamily == AF_INET6)
{
optlevel = IPPROTO_IPV6;
option = IPV6_UNICAST_HOPS;
}
else
{
rc = SOCKET_ERROR;
}
if (rc == NO_ERROR)
{
rc = setsockopt(
s,
optlevel,
option,
(char *)&ttl,
sizeof(ttl)
);
}
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "SetTtl: setsockopt failed: %d\n", WSAGetLastError());
}
return rc;
}
//
// Function: main
//
// Description:
// Setup the ICMP raw socket and create the ICMP header. Add
// the appropriate IP option header and start sending ICMP
// echo requests to the endpoint. For each send and receive we
// set a timeout value so that we don't wait forever for a
// response in case the endpoint is not responding. When we
// receive a packet decode it.
//
int __cdecl main(int argc, char **argv)
{
WSADATA wsd;
WSAOVERLAPPED recvol;
SOCKET s=INVALID_SOCKET;
char *icmpbuf=NULL;
struct addrinfo *dest=NULL,
*local=NULL;
IPV4_OPTION_HDR ipopt;
SOCKADDR_STORAGE from;
DWORD bytes,
flags;
int packetlen=0,
fromlen,
time=0,
rc,
i,
status = 0;
recvol.hEvent = WSA_INVALID_EVENT;
// Parse the command line
if (ValidateArgs(argc, argv) == FALSE)
{
// invalid arguments supplied.
status = -1;
goto EXIT;
}
// Load Winsock
if ((rc = WSAStartup(MAKEWORD(2,2), &wsd)) != 0)
{
printf("WSAStartup() failed: %d\n", rc);
status = -1;
goto EXIT;
}
// Resolve the destination address
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;
// Get the bind address
local = ResolveAddress(
NULL,
"0",
gAddressFamily,
0,
0
);
if (local == NULL)
{
printf("Unable to obtain the bind address!\n");
status = -1;
goto CLEANUP;
}
// Create the raw socket
s = socket(gAddressFamily, SOCK_RAW, gProtocol);
if (s == INVALID_SOCKET)
{
printf("socket failed: %d\n", WSAGetLastError());
status = -1;
goto CLEANUP;
}
SetTtl(s, gTtl);
// Figure out the size of the ICMP header and payload
if (gAddressFamily == AF_INET)
packetlen += sizeof(ICMP_HDR);
else if (gAddressFamily == AF_INET6)
packetlen += sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST);
// Add in the data size
packetlen += gDataSize;
// Allocate the buffer that will contain the ICMP request
icmpbuf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen);
if (icmpbuf == NULL)
{
fprintf(stderr, "HeapAlloc failed: %d\n", GetLastError());
status = -1;
goto CLEANUP;
}
// Initialize the ICMP headers
if (gAddressFamily == AF_INET)
{
if (bRecordRoute)
{
// Setup the IP option header to go out on every ICMP packet
ZeroMemory(&ipopt, sizeof(ipopt));
ipopt.opt_code = IP_RECORD_ROUTE; // record route option
ipopt.opt_ptr = 4; // point to the first addr offset
ipopt.opt_len = 39; // length of option header
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);
}
// Bind the socket -- need to do this since we post a receive first
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;
}
// Setup the receive operation
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;
}
// Post the first overlapped receive
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);
// Start sending the ICMP requests
for(i=0; i < DEFAULT_SEND_COUNT ;i++)
{
// Set the sequence number and compute the checksum
SetIcmpSequence(icmpbuf);
ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);
time = GetTickCount();
rc = sendto(
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;
}
// Waite for a response
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
{
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:
//
// 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:
return status;
}