private static PingReply CreatePingReplyFromIcmpEchoReply(Interop.IpHlpApi.IcmpEchoReply reply) { const int DontFragmentFlag = 2; IPAddress address = new IPAddress(reply.address); IPStatus ipStatus = (IPStatus)reply.status; // The icmpsendecho IP status codes. long rtt; PingOptions options; byte[] buffer; if (ipStatus == IPStatus.Success) { // Only copy the data if we succeed w/ the ping operation. rtt = reply.roundTripTime; options = new PingOptions(reply.options.ttl, (reply.options.flags & DontFragmentFlag) > 0); buffer = new byte[reply.dataSize]; Marshal.Copy(reply.data, buffer, 0, reply.dataSize); } else { rtt = default(long); options = default(PingOptions); buffer = Array.Empty <byte>(); } return(new PingReply(address, options, ipStatus, rtt, buffer)); }
// Private callback invoked when icmpsendecho APIs succeed. private void PingCallback() { TaskCompletionSource <PingReply> tcs = _taskCompletionSource; _taskCompletionSource = null; PingReply reply = null; Exception error = null; bool canceled = false; try { lock (_lockObject) { canceled = _canceled; // Parse reply buffer. SafeLocalAllocHandle buffer = _replyBuffer; // Marshals and constructs new reply. if (_ipv6) { Interop.IpHlpApi.Icmp6EchoReply icmp6Reply = Marshal.PtrToStructure <Interop.IpHlpApi.Icmp6EchoReply>(buffer.DangerousGetHandle()); reply = CreatePingReplyFromIcmp6EchoReply(icmp6Reply, buffer.DangerousGetHandle(), _sendSize); } else { Interop.IpHlpApi.IcmpEchoReply icmpReply = Marshal.PtrToStructure <Interop.IpHlpApi.IcmpEchoReply>(buffer.DangerousGetHandle()); reply = CreatePingReplyFromIcmpEchoReply(icmpReply); } } } catch (Exception e) { // In case of failure, create a failed event arg. error = new PingException(SR.net_ping, e); } finally { FreeUnmanagedStructures(); UnregisterWaitHandle(); Finish(); } // Once we've called Finish, complete the task if (canceled) { tcs.SetCanceled(); } else if (reply != null) { tcs.SetResult(reply); } else { Debug.Assert(error != null); tcs.SetException(error); } }
// Private callback invoked when icmpsendecho APIs succeed. private static void PingCallback(object state, bool signaled) { Ping ping = (Ping)state; PingCompletedEventArgs eventArgs = null; bool cancelled = false; AsyncOperation asyncOp = null; SendOrPostCallback onPingCompletedDelegate = null; try { lock (ping._lockObject) { cancelled = ping._cancelled; asyncOp = ping._asyncOp; onPingCompletedDelegate = ping._onPingCompletedDelegate; if (!cancelled) { // Parse reply buffer. SafeLocalAllocHandle buffer = ping._replyBuffer; // Marshals and constructs new reply. PingReply reply; if (ping._ipv6) { Interop.IpHlpApi.Icmp6EchoReply icmp6Reply = Marshal.PtrToStructure <Interop.IpHlpApi.Icmp6EchoReply>(buffer.DangerousGetHandle()); reply = new PingReply(icmp6Reply, buffer.DangerousGetHandle(), ping._sendSize); } else { Interop.IpHlpApi.IcmpEchoReply icmpReply = Marshal.PtrToStructure <Interop.IpHlpApi.IcmpEchoReply>(buffer.DangerousGetHandle()); reply = new PingReply(icmpReply); } eventArgs = new PingCompletedEventArgs(reply, null, false, asyncOp.UserSuppliedState); } else { // Canceled. eventArgs = new PingCompletedEventArgs(null, null, true, asyncOp.UserSuppliedState); } } } catch (Exception e) { // In case of failure, create a failed event arg. PingException pe = new PingException(SR.net_ping, e); eventArgs = new PingCompletedEventArgs(null, pe, false, asyncOp.UserSuppliedState); } finally { ping.FreeUnmanagedStructures(); ping.UnregisterWaitHandle(); ping.Finish(true); } asyncOp.PostOperationCompleted(onPingCompletedDelegate, eventArgs); }
private PingReply CreatePingReply() { SafeLocalAllocHandle buffer = _replyBuffer; // Marshals and constructs new reply. if (_ipv6) { Interop.IpHlpApi.Icmp6EchoReply icmp6Reply = Marshal.PtrToStructure <Interop.IpHlpApi.Icmp6EchoReply>(buffer.DangerousGetHandle()); return(CreatePingReplyFromIcmp6EchoReply(icmp6Reply, buffer.DangerousGetHandle(), _sendSize)); } Interop.IpHlpApi.IcmpEchoReply icmpReply = Marshal.PtrToStructure <Interop.IpHlpApi.IcmpEchoReply>(buffer.DangerousGetHandle()); return(CreatePingReplyFromIcmpEchoReply(icmpReply)); }
internal PingReply(Interop.IpHlpApi.IcmpEchoReply reply) { _address = new IPAddress(reply.address); // The icmpsendecho IP status codes. _ipStatus = (IPStatus)reply.status; // Only copy the data if we succeed w/ the ping operation. if (_ipStatus == IPStatus.Success) { _rtt = (long)reply.roundTripTime; _buffer = new byte[reply.dataSize]; Marshal.Copy(reply.data, _buffer, 0, reply.dataSize); _options = new PingOptions(reply.options); } else { _buffer = Array.Empty <byte>(); } }
private PingReply InternalSend(IPAddress address, byte[] buffer, int timeout, PingOptions options, bool async) { _ipv6 = (address.AddressFamily == AddressFamily.InterNetworkV6) ? true : false; _sendSize = buffer.Length; // Get and cache correct handle. if (!_ipv6 && _handlePingV4 == null) { _handlePingV4 = Interop.IpHlpApi.IcmpCreateFile(); if (_handlePingV4.IsInvalid) { _handlePingV4 = null; throw new Win32Exception(); // Gets last error. } } else if (_ipv6 && _handlePingV6 == null) { _handlePingV6 = Interop.IpHlpApi.Icmp6CreateFile(); if (_handlePingV6.IsInvalid) { _handlePingV6 = null; throw new Win32Exception(); // Gets last error. } } var ipOptions = new Interop.IpHlpApi.IPOptions(options); if (_replyBuffer == null) { _replyBuffer = SafeLocalAllocHandle.LocalAlloc(MaxUdpPacket); } // Queue the event. int error; try { if (async) { if (pingEvent == null) { pingEvent = new ManualResetEvent(false); } else { pingEvent.Reset(); } _registeredWait = ThreadPool.RegisterWaitForSingleObject(pingEvent, new WaitOrTimerCallback(PingCallback), this, -1, true); } SetUnmanagedStructures(buffer); if (!_ipv6) { if (async) { SafeWaitHandle pingEventSafeWaitHandle = pingEvent.GetSafeWaitHandle(); error = (int)Interop.IpHlpApi.IcmpSendEcho2( _handlePingV4, pingEventSafeWaitHandle, IntPtr.Zero, IntPtr.Zero, (uint)address.GetAddress(), _requestBuffer, (ushort)buffer.Length, ref ipOptions, _replyBuffer, MaxUdpPacket, (uint)timeout); } else { error = (int)Interop.IpHlpApi.IcmpSendEcho2( _handlePingV4, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, (uint)address.GetAddress(), _requestBuffer, (ushort)buffer.Length, ref ipOptions, _replyBuffer, MaxUdpPacket, (uint)timeout); } } else { IPEndPoint ep = new IPEndPoint(address, 0); Internals.SocketAddress remoteAddr = IPEndPointExtensions.Serialize(ep); byte[] sourceAddr = new byte[28]; if (async) { SafeWaitHandle pingEventSafeWaitHandle = pingEvent.GetSafeWaitHandle(); error = (int)Interop.IpHlpApi.Icmp6SendEcho2( _handlePingV6, pingEventSafeWaitHandle, IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.Buffer, _requestBuffer, (ushort)buffer.Length, ref ipOptions, _replyBuffer, MaxUdpPacket, (uint)timeout); } else { error = (int)Interop.IpHlpApi.Icmp6SendEcho2( _handlePingV6, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.Buffer, _requestBuffer, (ushort)buffer.Length, ref ipOptions, _replyBuffer, MaxUdpPacket, (uint)timeout); } } } catch { UnregisterWaitHandle(); throw; } if (error == 0) { error = Marshal.GetLastWin32Error(); // Only skip Async IO Pending error value. if (async && error == Interop.IpHlpApi.ERROR_IO_PENDING) { // Expected async return value. return(null); } // Cleanup. FreeUnmanagedStructures(); UnregisterWaitHandle(); if (async || // No IPStatus async errors. error < (int)IPStatus.DestinationNetworkUnreachable || // Min error > (int)IPStatus.DestinationScopeMismatch) // Max or Out of IPStatus range. { throw new Win32Exception(error); } return(new PingReply((IPStatus)error)); // Synchronous IPStatus errors. } if (async) { return(null); } FreeUnmanagedStructures(); PingReply reply; if (_ipv6) { Interop.IpHlpApi.Icmp6EchoReply icmp6Reply = Marshal.PtrToStructure <Interop.IpHlpApi.Icmp6EchoReply>(_replyBuffer.DangerousGetHandle()); reply = new PingReply(icmp6Reply, _replyBuffer.DangerousGetHandle(), _sendSize); } else { Interop.IpHlpApi.IcmpEchoReply icmpReply = Marshal.PtrToStructure <Interop.IpHlpApi.IcmpEchoReply>(_replyBuffer.DangerousGetHandle()); reply = new PingReply(icmpReply); } // IcmpEchoReply still has an unsafe IntPtr reference into replybuffer // and replybuffer was being freed prematurely by the GC, causing AccessViolationExceptions. GC.KeepAlive(_replyBuffer); return(reply); }