Example #1
0
        /// <summary>
        /// Pulls updates from the FlooderThreads and builds combined FlooderResult objects for LatestUpdate and HistoryResult.
        /// </summary>
        void ProcessUpdates()
        {
            // Sum latest results from all threads.
            FlooderResult resultSum = new FlooderResult();

            for (int i = 0; i < Action.Concurrency; i++)
            {
                resultSum        += ft[i].LatestResult;
                UpdateReceived[i] = false;
            }
            LatestResult = resultSum;

            // Add to History[] array, and recompute single HistoryResult.
            History[HistoryCounter] = resultSum;
            HistoryCounter          = (HistoryCounter + 1) % History.Length;
            FlooderResult historyResult = new FlooderResult();

            for (int i = 0; i < History.Length; i++)
            {
                if (History[i] != null)
                {
                    historyResult += History[i];
                }
            }
            HistoryResult = historyResult;
        }
Example #2
0
 /// <summary>
 /// Stops all threads, and clears all Results objects.
 /// </summary>
 public void Stop()
 {
     foreach (FlooderThread t in ft)
     {
         t.Stop();
     }
     UIUpdateTimer.Stop();
     IsRunning     = false;
     LatestResult  = new FlooderResult();
     HistoryResult = new FlooderResult();
     for (int i = 0; i < History.Length; i++)
     {
         History[i] = null;
     }
 }
Example #3
0
 public Flooder()
 {
     Action                 = new FlooderAction();
     IsRunning              = false;
     ft                     = new FlooderThread[Action.Concurrency];
     UpdateReceived         = new bool[Action.Concurrency];
     LatestResult           = new FlooderResult();
     History                = new FlooderResult[5000 / Action.TimeQuantum];
     HistoryCounter         = 0;
     UIUpdateTimer          = new System.Timers.Timer(Action.TimeQuantum);
     UIUpdateTimer.Elapsed += UIUpdateTimer_Elapsed;
     for (int i = 0; i < Action.Concurrency; i++)
     {
         ft[i] = new FlooderThread(Action);
         ft[i].PropertyChanged += FlooderThread_PropertyChanged;
     }
 }
        /// <summary>
        /// Adds two FlooderResult objects together.
        /// </summary>
        /// <param name="fr1">FlooderResult object #1</param>
        /// <param name="fr2">FlooderResult object #2</param>
        /// <returns>Combined FlooderResult object</returns>
        public static FlooderResult operator +(FlooderResult fr1, FlooderResult fr2)
        {
            var fr = new FlooderResult();

            fr.StartTime       = fr1.StartTime < fr2.StartTime ? fr1.StartTime : fr2.StartTime;
            fr.EndTime         = fr1.EndTime > fr2.EndTime ? fr1.EndTime : fr2.EndTime;
            fr.OctetsSent      = fr1.OctetsSent + fr2.OctetsSent;
            fr.PacketsSent     = fr1.PacketsSent + fr2.PacketsSent;
            fr.OctetsReceived  = fr1.OctetsReceived + fr2.OctetsReceived;
            fr.PacketsReceived = fr1.PacketsReceived + fr2.PacketsReceived;
            fr.SumOfLatency    = fr1.SumOfLatency + fr2.SumOfLatency;
            if (fr1.PacketsReceived > 0)
            {
                fr.PacketsLost = fr1.PacketsLost;
            }
            if (fr2.PacketsReceived > 0)
            {
                fr.PacketsLost = (fr.PacketsLost.HasValue) ? fr.PacketsLost + fr2.PacketsLost : fr2.PacketsLost;
            }
            fr.SeqLastSeen = (fr1.SeqLastSeen > fr2.SeqLastSeen) ? fr1.SeqLastSeen : fr2.SeqLastSeen;
            return(fr);
        }
        /// <summary>
        /// Receives UDP traffic, parses the payload, and records the arrival details.
        /// </summary>
        /// <param name="StopTime">Run until Stopwatch SW registers this number of ticks elapsed.</param>
        /// <param name="MinSeqNumber">The minimum sequence number to expect. Computed by sender thread.</param>
        /// <param name="MaxSeqNumber">The maximum sequence number to expect.  Computed by sender thread.</param>
        /// <returns>Results from receive operations</returns>
        private FlooderResult Receive(long StopTime, ulong MinSeqNumber, ulong MaxSeqNumber)
        {
            int  recvBytes    = 0;
            long timeReceived = 0;

            byte[]        seqReceivedBytes  = new byte[8];
            byte[]        timeReceivedBytes = new byte[8];
            FlooderResult result            = new FlooderResult();

            if (MaxSeqNumber - MinSeqNumber > Math.Pow(2, 24))
            {
                MinSeqNumber = MaxSeqNumber - (ulong)Math.Pow(2, 24);
            }

            int SequenceBuffer = (int)(MaxSeqNumber - MinSeqNumber);

            bool[] SequenceReceived = new bool[SequenceBuffer];

            while (SW.ElapsedTicks < StopTime)
            {
                while (UDPSocket.Available > 0)
                {
                    try
                    {
                        recvBytes = UDPSocket.Receive(recvBuffer, recvBuffer.Length, SocketFlags.None);
                    }
                    catch (SocketException)
                    { }
                    finally
                    {
                        timeReceived = SW.ElapsedTicks;
                        result.PacketsReceived++;
                        result.OctetsReceived += recvBytes + HeaderLen;

                        Array.ConstrainedCopy(recvBuffer, 0, seqReceivedBytes, 0, 8);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(seqReceivedBytes);
                        }
                        ulong Sequence = BitConverter.ToUInt64(seqReceivedBytes, 0);
                        if (MinSeqNumber <= Sequence && Sequence <= MaxSeqNumber)
                        {
                            result.SeqLastSeen = Sequence;
                            SequenceReceived[Sequence - MinSeqNumber] = true;
                        }
                        Array.ConstrainedCopy(recvBuffer, 8, timeReceivedBytes, 0, 8);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(timeReceivedBytes);
                        }
                        long originTime = BitConverter.ToInt64(timeReceivedBytes, 0);
                        result.SumOfLatency += timeReceived - originTime;
                    }
                }
                Thread.Yield();
            }
            if (result.SeqLastSeen != null)
            {
                result.PacketsLost = 0;
                for (int i = 0; i < (int)((ulong)result.SeqLastSeen - MinSeqNumber); i++)
                {
                    if (SequenceReceived[i] == false)
                    {
                        result.PacketsLost++;
                    }
                }
            }
            return(result);
        }
        /// <summary>
        /// Sends and receives UDP traffic in accordance with the parameters in FlooderAction.
        /// </summary>
        /// <param name="worker">BackgroundWorker object that describes the current thread.
        /// Used to get cancellation state and send back FlooderResult objects.</param>
        private void Sender(BackgroundWorker worker)
        {
            byte[]           sendBuffer  = null;
            ulong            SeqNum      = 0;
            Nullable <ulong> SeqLastSeen = null;
            int           PacketsToSend  = 0;
            long          waitInterval   = 0;
            Random        r            = new Random();
            long          LargestSlice = 0;
            FlooderResult result;
            TaskFactory <FlooderResult> receiverFactory = new TaskFactory <FlooderResult>();

            IsRunning = true;
            if (UDPSocket == null)
            {
                Debug.WriteLine("Begin Init Socket");
                UDPSocket = new Socket(SocketType.Dgram, ProtocolType.Udp);
                UDPSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, 12500000);
                UDPSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 12500000);

                // Code to ignore ICMP unreachable messages and prevent the socket from closing on Receive().
                // I don't care if the remote system doesn't reflect messages back.
                //http://stackoverflow.com/questions/7201862/an-existing-connection-was-forcibly-closed-by-the-remote-host
                uint IOC_IN            = 0x80000000;
                uint IOC_VENDOR        = 0x18000000;
                uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                UDPSocket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);

                UDPSocket.Connect(Action.TargetIP, Action.DestPort);
                if (Action.TargetIP.AddressFamily == AddressFamily.InterNetwork)
                {
                    HeaderLen = 28;
                }
                else if (Action.TargetIP.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    HeaderLen = 48;
                }
                else
                {
                    HeaderLen = 0;
                }
                Debug.WriteLine("End Init Socket");
            }
            SW.Start();

            //********** BEGIN Main Loop
            while (!worker.CancellationPending)
            {
                //***** Initialize state for this TimeQuantum.
                int    packetSize = Action.PacketSize;
                int    bandwidth  = Action.BandwidthOctets;
                long   SendStart;
                byte[] SeqBytes;
                byte[] TimeBytes;
                byte[] dateTimeBytes = new byte[8];
                long   Start;
                long   End;

                // Initialize send buffer.  This will vary as the send loop runs.
                sendBuffer = new byte[packetSize - HeaderLen];
                for (int i = 0; i < sendBuffer.Length; i++)
                {
                    sendBuffer[i] = 0x69;
                }

                // Figure out packet sizes, number of packets, buffer sizes, and inter-packet delay.
                long   LifetimeInTicks  = FlooderAction.TicksPerSecond * Action.TimeQuantum / 1000;
                double PacketsToSendDbl = ((double)bandwidth / (double)packetSize) * ((double)Action.TimeQuantum / (double)1000);
                PacketsToSendDbl /= Action.Concurrency;
                PacketsToSend     = (int)PacketsToSendDbl;

                // It is unlikely that PacketsToSendDbl will be an integer, but I cannot send half a packet to the host without
                // compromising the packet size for at least one packet.  This code adds an extra packet based on random chance.
                if (r.NextDouble() < PacketsToSendDbl - PacketsToSend)
                {
                    PacketsToSend++;
                }

                if (PacketsToSend > 0)
                {
                    waitInterval = LifetimeInTicks / PacketsToSend;
                }

                result = new FlooderResult();

                //Debug.WriteLine("Sending " + PacketsToSend);
                //Debug.WriteLine("Delay " + waitInterval);

                ulong MaxSeqNumber = SeqNum + (ulong)PacketsToSend;
                ulong MinSeqNumber = SeqLastSeen == null ? 0 : (ulong)SeqLastSeen + 1;

                // Kick off receive thread.  Lifetime is expressed in timer ticks.
                // new Task((resultObj) => { return Receive(long LifetimeInTicks); });
                Task <FlooderResult> Receiver = receiverFactory.StartNew(() => { return(Receive(SW.ElapsedTicks + LifetimeInTicks, MinSeqNumber, MaxSeqNumber)); });

                if (PacketsToSend == 0)
                {
                    Thread.Sleep(Action.TimeQuantum);
                }
                else
                {
                    for (int i = 0; i < PacketsToSend; i++)
                    {
                        // Start measuring this send packet event.
                        SendStart = SW.ElapsedTicks;

                        // Take the sequence number and current number of elapsed ticks, and add them to the top of the send buffer.
                        SeqBytes  = BitConverter.GetBytes(SeqNum);
                        TimeBytes = BitConverter.GetBytes(SW.ElapsedTicks);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(SeqBytes);
                            Array.Reverse(TimeBytes);
                        }
                        Array.ConstrainedCopy(SeqBytes, 0, sendBuffer, 0, 8);
                        Array.ConstrainedCopy(TimeBytes, 0, sendBuffer, 8, 8);

                        // Fire.
                        try
                        {
                            UDPSocket.Send(sendBuffer);
                        }
                        catch (SocketException)
                        { }
                        finally
                        {
                            SeqNum++;
                            result.PacketsSent++;
                        }

                        // The wai-ai-ting is the harr-dest paaaart.  Sender() tries to be nice to other threads.  However it is
                        // unpredictable how much time Thread.Yield() will actually yield to other running threads.  The largest
                        // value I observed on my hardware was 2700 ticks.  Your mileage may vary.  Wildly.  This code measures
                        // the time between Yield() calls and tries to make a best guess when to start looping without yielding
                        // time to other threads (ensuring the next packet gets off on time).
                        while (SW.ElapsedTicks < waitInterval + SendStart - LargestSlice)
                        {
                            Start = SW.ElapsedTicks;
                            Thread.Yield();
                            End = SW.ElapsedTicks;
                            if (LargestSlice < End - Start)
                            {
                                LargestSlice = End - Start;
                            }
                        }
                        while (SW.ElapsedTicks < waitInterval + SendStart)
                        {
                        }
                        // Done.  Repeat until all packets to send are sent.
                    }
                }
                // Arriving at the end of TimeQuantum.
                // Wrap up the sender statistics.
                result.OctetsSent = result.PacketsSent * packetSize;
                result.EndTime    = DateTime.Now;
                // Get results from receiver thread. Merge results with send thread.  Send results back to UI thread.
                // This concludes the receiver thread.  A new one will be started in the next TimeQuantum.
                FlooderResult receiverResult = Receiver.Result;
                result += receiverResult;
                if (result.SeqLastSeen.HasValue)
                {
                    SeqLastSeen = result.SeqLastSeen;
                }
                // Send result to the main UI thread.
                worker.ReportProgress(0, result);
                result = null;
                //Debug.WriteLine("largest slice: " + LargestSlice);
            }
            //********** END Main Loop

            // Cancel was received.  Shutting down.
            IsRunning = false;
            //SW.Stop();
            if (UDPSocket != null)
            {
                UDPSocket.Shutdown(SocketShutdown.Both);
                UDPSocket.Close(0);
                UDPSocket = null;
            }
        }