예제 #1
0
파일: Ping.cs 프로젝트: zanderphh/PowerPing
        private void SendPacket()
        {
            byte[] receiveBuffer = new byte[m_PingAttributes.ReceiveBufferSize]; // Ipv4Header.length + IcmpHeader.length + attrs.recievebuffersize
            int    bytesRead     = 0;

            // Sending loop
            for (int index = 1; m_PingAttributes.Continous || index <= m_PingAttributes.Count; index++)
            {
                if (index != 1)
                {
                    // Wait for set interval before sending again or cancel if requested
                    if (m_CancellationToken.WaitHandle.WaitOne(m_PingAttributes.Interval))
                    {
                        break;
                    }

                    // Generate random interval when RandomTiming flag is set
                    if (m_PingAttributes.RandomTiming)
                    {
                        m_PingAttributes.Interval = Helper.RandomInt(5000, 100000);
                    }
                }

                // Update packet before sending
                UpdatePacketSequenceNumber(index);
                if (m_PingAttributes.RandomMessage)
                {
                    UpdatePacketMessage(Encoding.ASCII.GetBytes(Helper.RandomString()));
                }
                UpdatePacketChecksum();

                try {
                    // Show request packet
                    if (Display.ShowRequests)
                    {
                        Display.RequestPacket(m_Packet, Display.UseInputtedAddress | Display.UseResolvedAddress ? m_PingAttributes.InputtedAddress : m_PingAttributes.ResolvedAddress, index);
                    }

                    // If there were extra responses from a prior request, ignore them
                    while (m_Socket.Available != 0)
                    {
                        bytesRead = m_Socket.Receive(receiveBuffer);
                    }

                    // Send ping request
                    m_Socket.SendTo(m_Packet.GetBytes(), m_PacketSize, SocketFlags.None, m_RemoteEndpoint); // Packet size = message field + 4 header bytes
                    long requestTimestamp = Stopwatch.GetTimestamp();
                    m_PingResults.IncrementSentPackets();

                    // Just for artifically testing higher ping response times
                    if (m_Debug)
                    {
                        Random rnd = new Random();
                        Thread.Sleep(rnd.Next(10, 400));
                        if (rnd.Next(3) == 1)
                        {
                            throw new SocketException();
                        }
                    }

                    // Try and recieve a packet
                    ICMP     response   = null;
                    EndPoint responseEP = m_RemoteEndpoint;
                    TimeSpan replyTime  = TimeSpan.Zero;
                    ReceivePacket(ref response, ref responseEP, ref replyTime, ref bytesRead, requestTimestamp);

                    if (Display.ShowReplies)
                    {
                        // Determine what form the response address is going to be displayed in
                        string responseAddress = responseEP.ToString();
                        if (Display.UseResolvedAddress)
                        {
                            // Returned address normally have port at the end (eg 8.8.8.8:0) so we need to remove that before trying to query the DNS
                            string responseIP = responseEP.ToString().Split(':')[0];

                            // Resolve the ip and store as the response address
                            responseAddress = Helper.RunWithCancellationToken(() => Lookup.QueryHost(responseIP), m_CancellationToken);
                        }
                        else if (Display.UseInputtedAddress)
                        {
                            responseAddress = m_PingAttributes.InputtedAddress;
                        }

                        Display.ReplyPacket(response, responseAddress, index, replyTime, bytesRead);
                    }

                    // Store response info
                    m_PingResults.IncrementReceivedPackets();
                    m_PingResults.CountPacketType(response.Type);
                    m_PingResults.SaveResponseTime(replyTime.TotalMilliseconds);

                    if (m_PingAttributes.BeepMode == 2)
                    {
                        try { Console.Beep(); }
                        catch (Exception) { } // Silently continue if Console.Beep errors
                    }
                }
                catch (IOException) {
                    if (Display.ShowOutput)
                    {
                        Display.Error("General transmit error");
                    }
                    m_PingResults.SaveResponseTime(-1);
                    m_PingResults.IncrementLostPackets();
                }
                catch (SocketException) {
                    Display.Timeout(index);
                    if (m_PingAttributes.BeepMode == 1)
                    {
                        try { Console.Beep(); }
                        catch (Exception) { }
                    }
                    m_PingResults.SaveResponseTime(-1);
                    m_PingResults.IncrementLostPackets();
                }
                catch (OperationCanceledException) {
                    m_PingResults.ScanWasCanceled = true;
                    break;
                }
                catch (Exception) {
                    if (Display.ShowOutput)
                    {
                        Display.Error("General error occured");
                    }
                    m_PingResults.SaveResponseTime(-1);
                    m_PingResults.IncrementLostPackets();
                }

                // Run callback (if provided) to notify of updated results
                OnPingResultsUpdateCallback?.Invoke(m_PingResults);
            }
        }
예제 #2
0
        private PingResults SendICMP(PingAttributes attrs, Action <PingResults> resultsUpdateCallback = null)
        {
            PingResults results = new PingResults();
            ICMP        packet  = new ICMP();

            byte[] receiveBuffer = new byte[attrs.RecieveBufferSize]; // Ipv4Header.length + IcmpHeader.length + attrs.recievebuffersize
            int    bytesRead, packetSize;

            // Convert to IPAddress
            IPAddress ipAddr = IPAddress.Parse(attrs.Address);

            // Setup endpoint
            IPEndPoint iep = new IPEndPoint(ipAddr, 0);

            // Setup raw socket
            Socket sock = CreateRawSocket(ipAddr.AddressFamily);

            // Helper function to set receive timeout (only if it's changing)
            int appliedReceiveTimeout = 0;

            void SetReceiveTimeout(int receiveTimeout)
            {
                if (receiveTimeout != appliedReceiveTimeout)
                {
                    sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeout);
                    appliedReceiveTimeout = receiveTimeout;
                }
            }

            // Set socket options
            sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, attrs.Ttl);
            sock.DontFragment      = attrs.DontFragment;
            sock.ReceiveBufferSize = attrs.RecieveBufferSize;

            // Create packet message payload
            byte[] payload;
            if (attrs.Size != -1)
            {
                payload = Helper.GenerateByteArray(attrs.Size);
            }
            else
            {
                payload = Encoding.ASCII.GetBytes(attrs.Message);
            }

            // Construct our ICMP packet
            packet.Type = attrs.Type;
            packet.Code = attrs.Code;
            Buffer.BlockCopy(BitConverter.GetBytes(m_SessionId), 0, packet.Message, 0, 2); // Add identifier to ICMP message
            Buffer.BlockCopy(payload, 0, packet.Message, 4, payload.Length);               // Add text into ICMP message
            packet.MessageSize = payload.Length + 4;
            packetSize         = packet.MessageSize + 4;

            // Sending loop
            for (int index = 1; attrs.Continous || index <= attrs.Count; index++)
            {
                if (index != 1)
                {
                    // Wait for set interval before sending again or cancel if requested
                    if (m_CancellationToken.WaitHandle.WaitOne(attrs.Interval))
                    {
                        break;
                    }

                    // Generate random interval when RandomTimings flag is set
                    if (attrs.RandomTiming)
                    {
                        attrs.Interval = Helper.RandomInt(5000, 100000);
                    }
                }

                // Include sequence number in ping message
                ushort sequenceNum = (ushort)index;
                Buffer.BlockCopy(BitConverter.GetBytes(sequenceNum), 0, packet.Message, 2, 2);

                // Fill ICMP message field
                if (attrs.RandomMsg)
                {
                    payload = Encoding.ASCII.GetBytes(Helper.RandomString());
                    Buffer.BlockCopy(payload, 0, packet.Message, 4, payload.Length);
                }

                // Update packet checksum
                packet.Checksum = 0;
                UInt16 chksm = packet.GetChecksum();
                packet.Checksum = chksm;

                try {
                    // Show request packet
                    if (Display.ShowRequests)
                    {
                        Display.RequestPacket(packet, Display.UseInputtedAddress | Display.UseResolvedAddress ? attrs.InputtedAddress : attrs.Address, index);
                    }

                    // If there were extra responses from a prior request, ignore them
                    while (sock.Available != 0)
                    {
                        bytesRead = sock.Receive(receiveBuffer);
                    }

                    // Send ping request
                    sock.SendTo(packet.GetBytes(), packetSize, SocketFlags.None, iep); // Packet size = message field + 4 header bytes
                    long requestTimestamp = Stopwatch.GetTimestamp();
                    try { results.Sent++; }
                    catch (OverflowException) { results.HasOverflowed = true; }

                    if (m_Debug)
                    {
                        // Induce random wait for debugging
                        Random rnd = new Random();
                        Thread.Sleep(scale);//rnd.Next(scale));//1500));
                        //Thread.Sleep(rnd.Next(100));
                        if (inverting)
                        {
                            scale -= 5;
                        }
                        else
                        {
                            scale += 5;
                        }
                        if (scale > 1100)
                        {
                            inverting = true;
                        }
                        else if (scale == 10)
                        {
                            inverting = false;
                        }
                        //if (rnd.Next(20) == 1) { throw new SocketException(); }
                    }

                    ICMP     response;
                    EndPoint responseEP = iep;
                    TimeSpan replyTime  = TimeSpan.Zero;
                    do
                    {
                        // Cancel if requested
                        m_CancellationToken.ThrowIfCancellationRequested();

                        // Set receive timeout, limited to 250ms so we don't block very long without checking for
                        // cancellation. If the requested ping timeout is longer, we will wait some more in subsequent
                        // loop iterations until the requested ping timeout is reached.
                        int remainingTimeout = (int)Math.Ceiling(attrs.Timeout - replyTime.TotalMilliseconds);
                        if (remainingTimeout <= 0)
                        {
                            throw new SocketException();
                        }
                        SetReceiveTimeout(Math.Min(remainingTimeout, 250));

                        // Wait for response
                        try {
                            bytesRead = sock.ReceiveFrom(receiveBuffer, ref responseEP);
                        } catch (SocketException) {
                            bytesRead = 0;
                        }
                        replyTime = new TimeSpan(Helper.StopwatchToTimeSpanTicks(Stopwatch.GetTimestamp() - requestTimestamp));

                        if (bytesRead == 0)
                        {
                            response = null;
                        }
                        else
                        {
                            // Store reply packet
                            response = new ICMP(receiveBuffer, bytesRead);

                            // If we sent an echo and receive a response with a different identifier or sequence
                            // number, ignore it (it could correspond to an older request that timed out)
                            if (packet.Type == 8 && response.Type == 0)
                            {
                                ushort responseSessionId   = BitConverter.ToUInt16(response.Message, 0);
                                ushort responseSequenceNum = BitConverter.ToUInt16(response.Message, 2);
                                if (responseSessionId != m_SessionId || responseSequenceNum != sequenceNum)
                                {
                                    response = null;
                                }
                            }
                        }
                    } while (response == null);

                    // Display reply packet
                    if (Display.ShowReplies)
                    {
                        Display.ReplyPacket(response, Display.UseInputtedAddress | Display.UseResolvedAddress ? attrs.InputtedAddress : responseEP.ToString(), index, replyTime, bytesRead);
                    }

                    // Store response info
                    try { results.Received++; }
                    catch (OverflowException) { results.HasOverflowed = true; }
                    results.CountPacketType(response.Type);
                    results.SaveResponseTime(replyTime.TotalMilliseconds);

                    if (attrs.BeepLevel == 2)
                    {
                        try { Console.Beep(); }
                        catch (Exception) { } // Silently continue if Console.Beep errors
                    }
                } catch (IOException) {
                    if (Display.ShowOutput)
                    {
                        Display.Error("General transmit error");
                    }
                    results.SaveResponseTime(-1);
                    try { results.Lost++; }
                    catch (OverflowException) { results.HasOverflowed = true; }
                } catch (SocketException) {
                    Display.Timeout(index);
                    if (attrs.BeepLevel == 1)
                    {
                        try { Console.Beep(); }
                        catch (Exception) { results.HasOverflowed = true; }
                    }
                    results.SaveResponseTime(-1);
                    try { results.Lost++; }
                    catch (OverflowException) { results.HasOverflowed = true; }
                } catch (OperationCanceledException) {
                    results.ScanWasCanceled = true;
                    break;
                } catch (Exception) {
                    if (Display.ShowOutput)
                    {
                        Display.Error("General error occured");
                    }
                    results.SaveResponseTime(-1);
                    try { results.Lost++; }
                    catch (OverflowException) { results.HasOverflowed = true; }
                }

                // Run callback (if provided) to notify of updated results
                resultsUpdateCallback?.Invoke(results);
            }

            // Clean up
            sock.Close();

            return(results);
        }