1 include { "internet.g" }
2
3 import "ws2_32.dll" {
4
5 int setsockopt( uint, int, int, uint, int )
6 int getsockopt( uint, int, int, uint, uint )
7 int sendto( uint, uint, int, int, uint, int )
8 int recvfrom( uint, uint, int, int, uint, uint )
9 uint WSASocketA( uint, uint, uint, uint, uint, uint )->WSASocket
10 uint getprotobyname( uint )
11 }
12
13 import "kernel32.dll" {
14 uint GetTickCount()
15 Sleep( uint )
16 uint GetCurrentProcessId()
17 }
18
19 define {
20 SOL_SOCKET = 0xFFFF
21 SO_SNDTIMEO = 0x1005 /* send timeout */
22 SO_RCVTIMEO = 0x1006 /* receive timeout */
23
24 ICMP_ECHO = 8
25 ICMP_ECHOREPLY = 0
26
27 MAX_PACKET = 1024
28
29 INADDR_ANY = 0x00000000
30 WSAETIMEDOUT = 10060
31 }
32
33 type icmphdr {
34 byte icmp_type /* type of message */
35 byte icmp_code /* type sub code */
36 ushort icmp_cksum /* ones complement cksum */
37 ushort icmp_id /* identifier */
38 ushort icmp_seq /* sequence number */
39 uint timestamp
40 }
41
42 type protoent {
43 uint p_name
44 uint p_aliases
45 short p_proto;
46 };
47
48
49 func ushort checksum( uint b, uint len )
50 {
51 uint lsum = 0
52 uint m = b + len
53
54 while b < m
55 {
56 lsum += b->ushort /* add word value to sum */
57 b += 2
58 }
59
60 /*if( len % 1 )
61 {
62 lsum += ( b - 1 )->ushort;
63 }*/
64
65 lsum = (lsum & 0xffff) + (lsum>>16)
66 lsum += (lsum >> 16)
67
68 return ( ~lsum )
69 }
70
71 func uint ping( str hostname, uint timeout, uint datasize, uint repeat,
72 uint perrcode )
73 {
74 uint sock
75 uint hp, addr
76 uint seq_no
77 int bwrote, bread
78 uint i
79 sockaddr_in dest from
80 uint tmp
81 buf icmp recv
82 uint icmp_d recv_d
83 timeout = max( timeout, 100 )
84 datasize = max( datasize, 1 )
85 uint pr
86 uint he
87 uint tmperror
88
89 if !perrcode : perrcode = &tmperror
90
91 pr as getprotobyname("icmp".ptr())->protoent
92 if !&pr
93 {
94 perrcode->uint = 1
95 return 0
96 }
97
98 sock = createsocket( $AF_INET, $SOCK_RAW, pr.p_proto)//$IPPROTO_ICMP
99
100 if sock == $INVALID_SOCKET
101 {
102 perrcode->uint = 2
103 return 0
104 }
105
106 if setsockopt( sock, $SOL_SOCKET, $SO_RCVTIMEO, &timeout, 4 ) == $SOCKET_ERROR ||
107 setsockopt( sock, $SOL_SOCKET, $SO_SNDTIMEO, &timeout, 4 ) == $SOCKET_ERROR
108 {
109 perrcode->uint = 3
110 return 0
111 }
112
113 dest.sin_addr = inet_addr( hostname.ptr() )
114 if dest.sin_addr == 0xFFFFFFFF
115 {
116 he = gethostbyname( hostname.ptr() )
117 if !he
118 {
119 perrcode->uint = 4
120 return 0
121 }
122 dest.sin_addr = ( he->hostent.h_addr_list->uint)->uint
123 }
124 dest.sin_family = $AF_INET;
125
126 datasize += sizeof( icmphdr );
127 datasize = min( $MAX_PACKET, datasize )
128
129 icmp.expand($MAX_PACKET);
130 recv.expand($MAX_PACKET);
131
132 icmp_d as icmp.ptr()->icmphdr
133
134 icmp_d.icmp_type = $ICMP_ECHO;
135
136 icmp_d.icmp_id = ushort( GetCurrentProcessId() );
137
138 fornum i = sizeof( icmphdr ), datasize
139 {
140 icmp[i] = i % 256
141 }
142
143 from.sin_addr = $INADDR_ANY
144 from.sin_family = $AF_INET
145
146 repeat = max( 1, repeat )
147 while( repeat-- )
148 {
149 icmp_d.icmp_cksum = 0;
150 icmp_d.timestamp = GetTickCount();
151 icmp_d.icmp_seq = seq_no++;
152 icmp_d.icmp_cksum = checksum( &icmp_d, datasize );
153
154 bwrote = sendto( sock, &icmp_d, datasize, 0, &dest, sizeof(sockaddr_in) )
155 if ( bwrote == $SOCKET_ERROR )
156 {
157 perrcode->uint = 5
158 break
159 }
160 bwrote = sizeof( sockaddr_in )
161 bread = recvfrom( sock, recv.ptr(), $MAX_PACKET, 0, &from, &bwrote )
162
163 if bread == $SOCKET_ERROR
164 {
165 if WSAGetLastError() == $WSAETIMEDOUT && repeat : continue
166 perrcode->uint = 6
167 break
168 }
169 recv_d = recv.ptr()
170 recv.use = bread
171 recv_d += ( recv_d->byte & 0x0F ) * 4
172
173 recv_d as icmphdr
174 i = GetTickCount() - recv_d.timestamp
175
176 if recv_d.icmp_type != $ICMP_ECHOREPLY
177 {
178 perrcode->uint = 7
179 break
180 }
181 if recv_d.icmp_id == icmp_d.icmp_id &&
182 recv_d.icmp_seq == icmp_d.icmp_seq
183 {
184 return max( 1, i )
185 }
186 Sleep( 1000 )
187 }
188 return 0;
189 }
190
191