internal extern static uint Icmp6SendEcho2(SafeCloseIcmpHandle icmpHandle, IntPtr Event, IntPtr apcRoutine, IntPtr apcContext, byte[] sourceSocketAddress, byte[] destSocketAddress, [In] SafeLocalAllocHandle data, ushort dataSize, ref IPOptions options, SafeLocalAllocHandle replyBuffer, uint replySize, uint timeout);
// internal method responsible for sending echo request on win2k and higher 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 = UnsafeNetInfoNativeMethods.IcmpCreateFile (); if (handlePingV4.IsInvalid) { handlePingV4 = null; throw new Win32Exception(); // Gets last error } } else if (ipv6 && handlePingV6 == null) { handlePingV6 = UnsafeNetInfoNativeMethods.Icmp6CreateFile(); if (handlePingV6.IsInvalid) { handlePingV6 = null; throw new Win32Exception(); // Gets last error } } //setup the options IPOptions ipOptions = new IPOptions (options); //setup the reply buffer if (replyBuffer == null) { replyBuffer = SafeLocalFree.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); } //Copy user dfata into the native world SetUnmanagedStructures (buffer); if (!ipv6) { if (async) { error = (int)UnsafeNetInfoNativeMethods.IcmpSendEcho2 (handlePingV4, pingEvent.SafeWaitHandle, IntPtr.Zero, IntPtr.Zero, (uint)address.m_Address, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout); } else{ error = (int)UnsafeNetInfoNativeMethods.IcmpSendEcho2 (handlePingV4, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, (uint)address.m_Address, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout); } } else { IPEndPoint ep = new IPEndPoint (address, 0); SocketAddress remoteAddr = ep.Serialize (); byte[] sourceAddr = new byte[28]; if(async){ error = (int)UnsafeNetInfoNativeMethods.Icmp6SendEcho2 (handlePingV6, pingEvent.SafeWaitHandle, IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.m_Buffer, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout); } else{ error = (int)UnsafeNetInfoNativeMethods.Icmp6SendEcho2 (handlePingV6, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.m_Buffer, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout); } } } catch { UnregisterWaitHandle(); throw; } //need this if something is bogus. if (error == 0) { error = (int)Marshal.GetLastWin32Error(); // Only skip Async IO Pending error value if (async && error == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) return null; // Expected async return value // Cleanup FreeUnmanagedStructures(); UnregisterWaitHandle(); if (async // No IPStatus async errors || error < (int)IPStatus.DestinationNetworkUnreachable // Min || error > (int)IPStatus.DestinationScopeMismatch) // Max // Out of IPStatus range throw new Win32Exception(error); return new PingReply((IPStatus)error); // Synchronous IPStatus errors } if (async) { return null; } FreeUnmanagedStructures (); //return the reply PingReply reply; if (ipv6) { Icmp6EchoReply icmp6Reply = (Icmp6EchoReply)Marshal.PtrToStructure(replyBuffer.DangerousGetHandle(), typeof(Icmp6EchoReply)); reply = new PingReply(icmp6Reply, replyBuffer.DangerousGetHandle(), sendSize); } else { IcmpEchoReply icmpReply = (IcmpEchoReply)Marshal.PtrToStructure(replyBuffer.DangerousGetHandle(), typeof(IcmpEchoReply)); 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; }
internal extern static uint IcmpSendEcho2(SafeCloseIcmpHandle icmpHandle, SafeWaitHandle Event, IntPtr apcRoutine, IntPtr apcContext, uint ipAddress, [In] SafeLocalAllocHandle data, ushort dataSize, ref IPOptions options, SafeLocalAllocHandle replyBuffer, uint replySize, uint timeout);
//cancel pending async requests, close the handles private void InternalDispose () { disposeRequested = true; if (Interlocked.CompareExchange(ref status, Disposed, Free) != Free) { // Already disposed, or Finish will call Dispose again once Free return; } if (handlePingV4 != null) { handlePingV4.Close (); handlePingV4 = null; } if (handlePingV6 != null) { handlePingV6.Close (); handlePingV6 = null; } UnregisterWaitHandle(); if (pingEvent != null) { pingEvent.Close(); pingEvent = null; } if (replyBuffer != null) { replyBuffer.Close(); replyBuffer = null; } if (asyncFinished != null) { asyncFinished.Close(); asyncFinished = null; } }