using PcapDotNet.Core;
using PcapDotNet.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RawSocket
{
    class Program
    {
        static uint PKT_NUM = 3;

        static void Main(string[] args)
        {
            uint timeout = 250;

            byte[] sv_packet = new byte[] {
                0x01, 0x0c, 0xcd, 0x04, 0x00, 0x01, 0x00, 0x20, 0x9d, 0x23, 0xd4, 0x59, /* vlan */ 0x81, 0x00, 0x80, 0x00, /* vlan */ 0x88, 0xba, 0x40, 0x00,
                0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x60, 0x63, 0x80, 0x01, 0x01, 0xa2, 0x5e, 0x30, 0x5c, 0x80,
                0x0b, 0x58, 0x4a, 0x50, 0x41, 0x5f, 0x4d, 0x55, 0x30, 0x36, 0x30, 0x31, 0x82, 0x02, 0x00, 0x00,
                0x83, 0x04, 0x00, 0x00, 0x00, 0x01, 0x85, 0x01, 0x00, 0x87, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            };

            if (args.Length > 0)
            {
                timeout = uint.Parse(args[0]);
            }

            if (args.Length > 1)
            {
                PKT_NUM = uint.Parse(args[1]);
            }

            // Retrieve the device list from the local machine
            IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;

            if (allDevices.Count == 0)
            {
                Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
                return;
            }

            int deviceIndex = -1;

            // Print the list
            for (int i = 0; i != allDevices.Count; ++i)
            {
                IPacketDevice device = allDevices[i];

                // IP addresses
                foreach (DeviceAddress address in device.Addresses)
                {
                    Console.WriteLine(("\tAddress: " + address.Address));
                    if (address.Address.ToString() == "Internet 10.0.1.1")
                    {
                        // Name
                        Console.WriteLine(device.Name);

                        // Description
                        if (device.Description != null)
                            Console.WriteLine("\tDescription: " + device.Description);

                        Console.WriteLine(("\tAddress: " + address.Address));
                        deviceIndex = i;
                        break;
                    }
                }
                if (deviceIndex != -1)
                {
                    break;
                }
            }

            if (deviceIndex == -1)
            {
                return;
            }

            // Take the selected adapter
            PacketDevice selectedDevice = allDevices[deviceIndex];

            // Open the device
            using (PacketCommunicator communicator =
                selectedDevice.Open(65536,                                  // portion of the packet to capture
                                                                            // 65536 guarantees that the whole packet will be captured on all the link layers
                                    PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
                                    1000))                                  // read timeout
            {
                Console.WriteLine("Sending to " + selectedDevice.Description + "...");

                if (System.Diagnostics.Stopwatch.IsHighResolution)
                {
                    Console.WriteLine("Using high resolution timer");
                }

                long v = (timeout * System.Diagnostics.Stopwatch.Frequency) / 1000000;

                for (;;)
                {
                    DateTime curr = DateTime.Now;
                    //Console.WriteLine(curr.ToString("yyyy-MM-dd hh:mm:ss.fff"));

                    // start the capture
                    for (uint i = 0; i < 4000; i++)
                    {
                        var sw = System.Diagnostics.Stopwatch.StartNew();

                        using (PacketSendBuffer sv_buffer = new PacketSendBuffer((uint)((sv_packet.Length + 16) * PKT_NUM)))
                        {
                            sv_packet[0x2e + 4] = (byte)((i >> 8) & 0xff);
                            sv_packet[0x2f + 4] = (byte)(i & 0xff);
                            for (byte j = 1; j < (1 + PKT_NUM); j++)
                            {
                                sv_packet[0x05] = j;

                                sv_buffer.Enqueue(new Packet(sv_packet, curr, DataLinkKind.Ethernet));
                            }
                            communicator.Transmit(sv_buffer, false);
                        }

                        while (sw.ElapsedTicks < v)
                        {
                        }
                    }
                }
            }
        }
    }
}
