mf/tests: Add some tests for EVR sink services.
[wine.git] / dlls / iphlpapi / icmp.c
blob8ef03219e5248b1f71c6fed205bb87d258f5408b
1 /*
2 * ICMP
4 * Francois Gouget, 1999, based on the work of
5 * RW Hall, 1999, based on public domain code PING.C by Mike Muus (1983)
6 * and later works (c) 1989 Regents of Univ. of California - see copyright
7 * notice at end of source-code.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 /* Future work:
25 * - Systems like FreeBSD don't seem to support the IP_TTL option and maybe others.
26 * But using IP_HDRINCL and building the IP header by hand might work.
27 * - Not all IP options are supported.
28 * - Are ICMP handles real handles, i.e. inheritable and all? There might be some
29 * more work to do here, including server side stuff with synchronization.
30 * - This API should probably be thread safe. Is it really?
31 * - Using the winsock functions has not been tested.
34 #include "config.h"
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
39 #endif
40 #ifdef HAVE_NETDB_H
41 # include <netdb.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_SYSTM_H
44 # include <netinet/in_systm.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
50 #ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
52 #endif
53 #include <stdarg.h>
54 #include <string.h>
55 #include <errno.h>
56 #ifdef HAVE_UNISTD_H
57 # include <unistd.h>
58 #endif
59 #ifdef HAVE_ARPA_INET_H
60 # include <arpa/inet.h>
61 #endif
62 #ifdef HAVE_SYS_POLL_H
63 # include <sys/poll.h>
64 #endif
66 #define USE_WS_PREFIX
68 #include "windef.h"
69 #include "winbase.h"
70 #include "winerror.h"
71 #include "winternl.h"
72 #include "ipexport.h"
73 #include "icmpapi.h"
74 #include "wine/debug.h"
76 /* Set up endianness macros for the ip and ip_icmp BSD headers */
77 #ifndef BIG_ENDIAN
78 #define BIG_ENDIAN 4321
79 #endif
80 #ifndef LITTLE_ENDIAN
81 #define LITTLE_ENDIAN 1234
82 #endif
83 #ifndef BYTE_ORDER
84 #ifdef WORDS_BIGENDIAN
85 #define BYTE_ORDER BIG_ENDIAN
86 #else
87 #define BYTE_ORDER LITTLE_ENDIAN
88 #endif
89 #endif /* BYTE_ORDER */
91 #define u_int16_t WORD
92 #define u_int32_t DWORD
94 /* These are BSD headers. We use these here because they are needed on
95 * libc5 Linux systems. On other platforms they are usually simply more
96 * complete than the native stuff, and cause less portability problems
97 * so we use them anyway.
99 #include "ip.h"
100 #include "ip_icmp.h"
103 WINE_DEFAULT_DEBUG_CHANNEL(icmp);
104 WINE_DECLARE_DEBUG_CHANNEL(winediag);
107 typedef struct {
108 int sid;
109 IP_OPTION_INFORMATION default_opts;
110 } icmp_t;
112 #define IP_OPTS_UNKNOWN 0
113 #define IP_OPTS_DEFAULT 1
114 #define IP_OPTS_CUSTOM 2
116 #define MAXIPLEN 60
117 #define MAXICMPLEN 76
119 /* The sequence number is unique process wide, so that all threads
120 * have a distinct sequence number.
122 static LONG icmp_sequence=0;
124 static int in_cksum(u_short *addr, int len)
126 int nleft=len;
127 u_short *w = addr;
128 int sum = 0;
129 u_short answer = 0;
131 while (nleft > 1) {
132 sum += *w++;
133 nleft -= 2;
136 if (nleft == 1) {
137 *(u_char *)(&answer) = *(u_char *)w;
138 sum += answer;
141 sum = (sum >> 16) + (sum & 0xffff);
142 sum += (sum >> 16);
143 answer = ~sum;
144 return(answer);
147 /* Receive a reply (IPv4); this function uses, takes ownership of and will always free `buffer` */
148 static DWORD icmp_get_reply(int sid, unsigned char *buffer, DWORD send_time, void *reply_buf, DWORD reply_size, DWORD timeout)
150 int repsize = MAXIPLEN + MAXICMPLEN + min(65535, reply_size);
151 struct icmp *icmp_header = (struct icmp*)buffer;
152 char *endbuf = (char*)reply_buf + reply_size;
153 struct ip *ip_header = (struct ip*)buffer;
154 struct icmp_echo_reply *ier = reply_buf;
155 unsigned short id, seq, cksum;
156 struct sockaddr_in addr;
157 int ip_header_len = 0;
158 socklen_t addrlen;
159 struct pollfd fdr;
160 DWORD recv_time;
161 int res;
163 id = icmp_header->icmp_id;
164 seq = icmp_header->icmp_seq;
165 cksum = icmp_header->icmp_cksum;
166 fdr.fd = sid;
167 fdr.events = POLLIN;
168 addrlen = sizeof(addr);
170 while (poll(&fdr,1,timeout)>0) {
171 recv_time = GetTickCount();
172 res=recvfrom(sid, buffer, repsize, 0, (struct sockaddr*)&addr, &addrlen);
173 TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr));
174 ier->Status=IP_REQ_TIMED_OUT;
176 /* Check whether we should ignore this packet */
177 if ((ip_header->ip_p==IPPROTO_ICMP) && (res>=sizeof(struct ip)+ICMP_MINLEN)) {
178 ip_header_len=ip_header->ip_hl << 2;
179 icmp_header=(struct icmp*)(((char*)ip_header)+ip_header_len);
180 TRACE("received an ICMP packet of type,code=%d,%d\n",icmp_header->icmp_type,icmp_header->icmp_code);
181 if (icmp_header->icmp_type==ICMP_ECHOREPLY) {
182 if ((icmp_header->icmp_id==id) && (icmp_header->icmp_seq==seq))
184 ier->Status=IP_SUCCESS;
185 SetLastError(NO_ERROR);
187 } else {
188 switch (icmp_header->icmp_type) {
189 case ICMP_UNREACH:
190 switch (icmp_header->icmp_code) {
191 case ICMP_UNREACH_HOST:
192 #ifdef ICMP_UNREACH_HOST_UNKNOWN
193 case ICMP_UNREACH_HOST_UNKNOWN:
194 #endif
195 #ifdef ICMP_UNREACH_ISOLATED
196 case ICMP_UNREACH_ISOLATED:
197 #endif
198 #ifdef ICMP_UNREACH_HOST_PROHIB
199 case ICMP_UNREACH_HOST_PROHIB:
200 #endif
201 #ifdef ICMP_UNREACH_TOSHOST
202 case ICMP_UNREACH_TOSHOST:
203 #endif
204 ier->Status=IP_DEST_HOST_UNREACHABLE;
205 break;
206 case ICMP_UNREACH_PORT:
207 ier->Status=IP_DEST_PORT_UNREACHABLE;
208 break;
209 case ICMP_UNREACH_PROTOCOL:
210 ier->Status=IP_DEST_PROT_UNREACHABLE;
211 break;
212 case ICMP_UNREACH_SRCFAIL:
213 ier->Status=IP_BAD_ROUTE;
214 break;
215 default:
216 ier->Status=IP_DEST_NET_UNREACHABLE;
218 break;
219 case ICMP_TIMXCEED:
220 if (icmp_header->icmp_code==ICMP_TIMXCEED_REASS)
221 ier->Status=IP_TTL_EXPIRED_REASSEM;
222 else
223 ier->Status=IP_TTL_EXPIRED_TRANSIT;
224 break;
225 case ICMP_PARAMPROB:
226 ier->Status=IP_PARAM_PROBLEM;
227 break;
228 case ICMP_SOURCEQUENCH:
229 ier->Status=IP_SOURCE_QUENCH;
230 break;
232 if (ier->Status!=IP_REQ_TIMED_OUT) {
233 struct ip* rep_ip_header;
234 struct icmp* rep_icmp_header;
235 /* The ICMP header size of all the packets we accept is the same */
236 rep_ip_header=(struct ip*)(((char*)icmp_header)+ICMP_MINLEN);
237 rep_icmp_header=(struct icmp*)(((char*)rep_ip_header)+(rep_ip_header->ip_hl << 2));
239 /* Make sure that this is really a reply to our packet */
240 if (ip_header_len+ICMP_MINLEN+(rep_ip_header->ip_hl << 2)+ICMP_MINLEN>ip_header->ip_len) {
241 ier->Status=IP_REQ_TIMED_OUT;
242 } else if ((rep_icmp_header->icmp_type!=ICMP_ECHO) ||
243 (rep_icmp_header->icmp_code!=0) ||
244 (rep_icmp_header->icmp_id!=id) ||
245 /* windows doesn't check this checksum, else tracert */
246 /* behind a Linux 2.2 masquerading firewall would fail*/
247 /* (rep_icmp_header->icmp_cksum!=cksum) || */
248 (rep_icmp_header->icmp_seq!=seq)) {
249 /* This was not a reply to one of our packets after all */
250 TRACE("skipping type,code=%d,%d id,seq=%d,%d cksum=%d\n",
251 rep_icmp_header->icmp_type,rep_icmp_header->icmp_code,
252 rep_icmp_header->icmp_id,rep_icmp_header->icmp_seq,
253 rep_icmp_header->icmp_cksum);
254 TRACE("expected type,code=8,0 id,seq=%d,%d cksum=%d\n",
255 id,seq,
256 cksum);
257 ier->Status=IP_REQ_TIMED_OUT;
263 if (ier->Status==IP_REQ_TIMED_OUT) {
264 /* This packet was not for us.
265 * Decrease the timeout so that we don't enter an endless loop even
266 * if we get flooded with ICMP packets that are not for us.
268 DWORD t = (recv_time - send_time);
269 if (timeout > t) timeout -= t;
270 else timeout = 0;
271 continue;
272 } else {
273 /* Check free space, should be large enough for an ICMP_ECHO_REPLY and remainning icmp data */
274 if (endbuf-(char *)ier < sizeof(struct icmp_echo_reply)+(res-ip_header_len-ICMP_MINLEN)) {
275 res=ier-(ICMP_ECHO_REPLY *)reply_buf;
276 SetLastError(IP_GENERAL_FAILURE);
277 goto done;
279 /* This is a reply to our packet */
280 memcpy(&ier->Address,&ip_header->ip_src,sizeof(IPAddr));
281 /* Status is already set */
282 ier->RoundTripTime= recv_time - send_time;
283 ier->DataSize=res-ip_header_len-ICMP_MINLEN;
284 ier->Reserved=0;
285 ier->Data=endbuf-ier->DataSize;
286 memcpy(ier->Data, ((char *)ip_header)+ip_header_len+ICMP_MINLEN, ier->DataSize);
287 ier->Options.Ttl=ip_header->ip_ttl;
288 ier->Options.Tos=ip_header->ip_tos;
289 ier->Options.Flags=ip_header->ip_off >> 13;
290 ier->Options.OptionsSize=ip_header_len-sizeof(struct ip);
291 if (ier->Options.OptionsSize!=0) {
292 ier->Options.OptionsData=(unsigned char *) ier->Data-ier->Options.OptionsSize;
293 /* FIXME: We are supposed to rearrange the option's 'source route' data */
294 memcpy(ier->Options.OptionsData, ((char *)ip_header)+ip_header_len, ier->Options.OptionsSize);
295 endbuf=(char*)ier->Options.OptionsData;
296 } else {
297 ier->Options.OptionsData=NULL;
298 endbuf=ier->Data;
301 /* Prepare for the next packet */
302 ier++;
304 /* Check out whether there is more but don't wait this time */
305 timeout=0;
308 res=ier-(ICMP_ECHO_REPLY*)reply_buf;
309 if (res==0)
310 SetLastError(IP_REQ_TIMED_OUT);
311 done:
312 if (res)
314 /* Move the data so there's no gap between it and the ICMP_ECHO_REPLY array */
315 DWORD gap_size = endbuf - (char*)ier;
317 if (gap_size)
319 memmove(ier, endbuf, ((char*)reply_buf + reply_size) - endbuf);
321 /* Fix the pointers */
322 while (ier-- != reply_buf)
324 ier->Data = (char*)ier->Data - gap_size;
325 if (ier->Options.OptionsData)
326 ier->Options.OptionsData -= gap_size;
329 /* According to MSDN, the reply buffer needs to hold space for a IO_STATUS_BLOCK,
330 found at the very end of the reply. This is confirmed on Windows XP, but Vista
331 and later do not store it anywhere and in fact don't even require it at all.
333 However, in case old apps analyze this IO_STATUS_BLOCK and expect it, we mimic
334 it and write it out if there's enough space available in the buffer. */
335 if (gap_size >= sizeof(IO_STATUS_BLOCK))
337 IO_STATUS_BLOCK *io = (IO_STATUS_BLOCK*)((char*)reply_buf + reply_size - sizeof(IO_STATUS_BLOCK));
339 io->Pointer = NULL; /* Always NULL or STATUS_SUCCESS */
340 io->Information = reply_size - gap_size;
345 HeapFree(GetProcessHeap(), 0, buffer);
346 TRACE("received %d replies\n",res);
347 return res;
353 * Exported Routines.
356 /***********************************************************************
357 * Icmp6CreateFile (IPHLPAPI.@)
359 HANDLE WINAPI Icmp6CreateFile(VOID)
361 icmp_t* icp;
363 int sid=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6);
364 if (sid < 0)
366 /* Some systems (e.g. Linux 3.0+ and Mac OS X) support
367 non-privileged ICMP via SOCK_DGRAM type. */
368 sid=socket(AF_INET6,SOCK_DGRAM,IPPROTO_ICMPV6);
370 if (sid < 0) {
371 ERR_(winediag)("Failed to use ICMPV6 (network ping), this requires special permissions.\n");
372 SetLastError(ERROR_ACCESS_DENIED);
373 return INVALID_HANDLE_VALUE;
376 icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
377 if (icp==NULL) {
378 close(sid);
379 SetLastError(IP_NO_RESOURCES);
380 return INVALID_HANDLE_VALUE;
382 icp->sid=sid;
383 icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
384 return (HANDLE)icp;
388 /***********************************************************************
389 * Icmp6SendEcho2 (IPHLPAPI.@)
391 DWORD WINAPI Icmp6SendEcho2(
392 HANDLE IcmpHandle,
393 HANDLE Event,
394 PIO_APC_ROUTINE ApcRoutine,
395 PVOID ApcContext,
396 struct sockaddr_in6* SourceAddress,
397 struct sockaddr_in6* DestinationAddress,
398 LPVOID RequestData,
399 WORD RequestSize,
400 PIP_OPTION_INFORMATION RequestOptions,
401 LPVOID ReplyBuffer,
402 DWORD ReplySize,
403 DWORD Timeout
406 FIXME("(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle, Event,
407 ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData,
408 RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
409 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
410 return 0;
414 /***********************************************************************
415 * IcmpCreateFile (IPHLPAPI.@)
417 HANDLE WINAPI IcmpCreateFile(VOID)
419 icmp_t* icp;
421 int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
422 if (sid < 0)
424 /* Some systems (e.g. Linux 3.0+ and Mac OS X) support
425 non-privileged ICMP via SOCK_DGRAM type. */
426 sid=socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP);
428 if (sid < 0) {
429 ERR_(winediag)("Failed to use ICMP (network ping), this requires special permissions.\n");
430 SetLastError(ERROR_ACCESS_DENIED);
431 return INVALID_HANDLE_VALUE;
434 icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
435 if (icp==NULL) {
436 close(sid);
437 SetLastError(IP_NO_RESOURCES);
438 return INVALID_HANDLE_VALUE;
440 icp->sid=sid;
441 icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
442 return (HANDLE)icp;
446 /***********************************************************************
447 * IcmpCloseHandle (IPHLPAPI.@)
449 BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle)
451 icmp_t* icp=(icmp_t*)IcmpHandle;
452 if (IcmpHandle==INVALID_HANDLE_VALUE) {
453 /* FIXME: in fact win98 seems to ignore the handle value !!! */
454 SetLastError(ERROR_INVALID_HANDLE);
455 return FALSE;
458 close( icp->sid );
459 HeapFree(GetProcessHeap (), 0, icp);
460 return TRUE;
464 /***********************************************************************
465 * IcmpSendEcho (IPHLPAPI.@)
467 DWORD WINAPI IcmpSendEcho(
468 HANDLE IcmpHandle,
469 IPAddr DestinationAddress,
470 LPVOID RequestData,
471 WORD RequestSize,
472 PIP_OPTION_INFORMATION RequestOptions,
473 LPVOID ReplyBuffer,
474 DWORD ReplySize,
475 DWORD Timeout
478 return IcmpSendEcho2Ex(IcmpHandle, NULL, NULL, NULL, 0, DestinationAddress,
479 RequestData, RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
482 /***********************************************************************
483 * IcmpSendEcho2 (IPHLPAPI.@)
485 DWORD WINAPI IcmpSendEcho2(
486 HANDLE IcmpHandle,
487 HANDLE Event,
488 PIO_APC_ROUTINE ApcRoutine,
489 PVOID ApcContext,
490 IPAddr DestinationAddress,
491 LPVOID RequestData,
492 WORD RequestSize,
493 PIP_OPTION_INFORMATION RequestOptions,
494 LPVOID ReplyBuffer,
495 DWORD ReplySize,
496 DWORD Timeout
499 return IcmpSendEcho2Ex(IcmpHandle, Event, ApcRoutine, ApcContext, 0,
500 DestinationAddress, RequestData, RequestSize, RequestOptions,
501 ReplyBuffer, ReplySize, Timeout);
504 /***********************************************************************
505 * IcmpSendEcho2Ex (IPHLPAPI.@)
507 DWORD WINAPI IcmpSendEcho2Ex(
508 HANDLE IcmpHandle,
509 HANDLE Event,
510 PIO_APC_ROUTINE ApcRoutine,
511 PVOID ApcContext,
512 IPAddr SourceAddress,
513 IPAddr DestinationAddress,
514 LPVOID RequestData,
515 WORD RequestSize,
516 PIP_OPTION_INFORMATION RequestOptions,
517 LPVOID ReplyBuffer,
518 DWORD ReplySize,
519 DWORD Timeout
522 icmp_t* icp=(icmp_t*)IcmpHandle;
523 struct icmp* icmp_header;
524 struct sockaddr_in addr;
525 unsigned short id, seq;
526 unsigned char *buffer;
527 int reqsize, repsize;
528 DWORD send_time;
530 TRACE("(%p, %p, %p, %p, %08x, %08x, %p, %d, %p, %p, %d, %d)\n", IcmpHandle,
531 Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData,
532 RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
534 if (IcmpHandle==INVALID_HANDLE_VALUE) {
535 /* FIXME: in fact win98 seems to ignore the handle value !!! */
536 SetLastError(ERROR_INVALID_PARAMETER);
537 return 0;
540 if (!ReplyBuffer||!ReplySize) {
541 SetLastError(ERROR_INVALID_PARAMETER);
542 return 0;
545 if (ReplySize<sizeof(ICMP_ECHO_REPLY)) {
546 SetLastError(IP_BUF_TOO_SMALL);
547 return 0;
549 /* check the request size against SO_MAX_MSG_SIZE using getsockopt */
551 if (!DestinationAddress) {
552 SetLastError(ERROR_INVALID_NETNAME);
553 return 0;
556 if (Event)
558 FIXME("unsupported for events\n");
559 return 0;
561 if (ApcRoutine)
563 FIXME("unsupported for APCs\n");
564 return 0;
566 if (SourceAddress)
568 FIXME("unsupported for source addresses\n");
569 return 0;
572 /* Prepare the request */
573 id=getpid() & 0xFFFF;
574 seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
576 reqsize=ICMP_MINLEN+RequestSize;
577 /* max ip header + max icmp header and error data + reply size(max 65535 on Windows) */
578 /* FIXME: request size of 65535 is not supported yet because max buffer size of raw socket on linux is 32767 */
579 repsize = MAXIPLEN + MAXICMPLEN + min( 65535, ReplySize );
580 buffer = HeapAlloc(GetProcessHeap(), 0, max( repsize, reqsize ));
581 if (buffer == NULL) {
582 SetLastError(ERROR_OUTOFMEMORY);
583 return 0;
586 icmp_header=(struct icmp*)buffer;
587 icmp_header->icmp_type=ICMP_ECHO;
588 icmp_header->icmp_code=0;
589 icmp_header->icmp_cksum=0;
590 icmp_header->icmp_id=id;
591 icmp_header->icmp_seq=seq;
592 memcpy(buffer+ICMP_MINLEN, RequestData, RequestSize);
593 icmp_header->icmp_cksum=in_cksum((u_short*)buffer,reqsize);
595 addr.sin_family=AF_INET;
596 addr.sin_addr.s_addr=DestinationAddress;
597 addr.sin_port=0;
599 if (RequestOptions!=NULL) {
600 int val;
601 if (icp->default_opts.OptionsSize==IP_OPTS_UNKNOWN) {
602 socklen_t len;
603 /* Before we mess with the options, get the default values */
604 len=sizeof(val);
605 getsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,&len);
606 icp->default_opts.Ttl=val;
608 len=sizeof(val);
609 getsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,&len);
610 icp->default_opts.Tos=val;
611 /* FIXME: missing: handling of IP 'flags', and all the other options */
614 val=RequestOptions->Ttl;
615 setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val));
616 val=RequestOptions->Tos;
617 setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val));
618 /* FIXME: missing: handling of IP 'flags', and all the other options */
620 icp->default_opts.OptionsSize=IP_OPTS_CUSTOM;
621 } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) {
622 int val;
624 /* Restore the default options */
625 val=icp->default_opts.Ttl;
626 setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val));
627 val=icp->default_opts.Tos;
628 setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val));
629 /* FIXME: missing: handling of IP 'flags', and all the other options */
631 icp->default_opts.OptionsSize=IP_OPTS_DEFAULT;
634 /* Send the packet */
635 TRACE("Sending %d bytes (RequestSize=%d) to %s\n", reqsize, RequestSize, inet_ntoa(addr.sin_addr));
636 #if 0
637 if (TRACE_ON(icmp)){
638 int i;
639 printf("Output buffer:\n");
640 for (i=0;i<reqsize;i++)
641 printf("%2x,", buffer[i]);
642 printf("\n");
644 #endif
646 send_time = GetTickCount();
647 if (sendto(icp->sid, buffer, reqsize, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
648 if (errno==EMSGSIZE)
649 SetLastError(IP_PACKET_TOO_BIG);
650 else {
651 switch (errno) {
652 case ENETUNREACH:
653 SetLastError(IP_DEST_NET_UNREACHABLE);
654 break;
655 case EHOSTUNREACH:
656 SetLastError(IP_DEST_HOST_UNREACHABLE);
657 break;
658 default:
659 TRACE("unknown error: errno=%d\n",errno);
660 SetLastError(IP_GENERAL_FAILURE);
663 HeapFree(GetProcessHeap(), 0, buffer);
664 return 0;
667 return icmp_get_reply(icp->sid, buffer, send_time, ReplyBuffer, ReplySize, Timeout);
671 * Copyright (c) 1989 The Regents of the University of California.
672 * All rights reserved.
674 * This code is derived from software contributed to Berkeley by
675 * Mike Muuss.
677 * Redistribution and use in source and binary forms, with or without
678 * modification, are permitted provided that the following conditions
679 * are met:
680 * 1. Redistributions of source code must retain the above copyright
681 * notice, this list of conditions and the following disclaimer.
682 * 2. Redistributions in binary form must reproduce the above copyright
683 * notice, this list of conditions and the following disclaimer in the
684 * documentation and/or other materials provided with the distribution.
685 * 3. Neither the name of the University nor the names of its contributors
686 * may be used to endorse or promote products derived from this software
687 * without specific prior written permission.
689 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
690 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
691 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
692 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
693 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
694 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
695 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
696 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
697 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
698 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
699 * SUCH DAMAGE.