<commit_before>﻿// Copyright (c) CodesInChaos
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using PacketDotNet;
using PacketDotNet.Utils;

namespace NetworkSniffer
{
    public class IpSnifferRawSocketSingleInterface : IpSniffer
    {
        private readonly IPAddress _localIp;

        private bool _isInit;
        private Socket _socket;

        public IpSnifferRawSocketSingleInterface(IPAddress localIp)
        {
            _localIp = localIp;
        }

        private void Init()
        {
            Debug.Assert(_socket == null);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);

            if (_localIp != null)
            {
                _socket.Bind(new IPEndPoint(_localIp, 0));
            }
            _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
            var receiveAllIp = BitConverter.GetBytes(3);
            _socket.IOControl(IOControlCode.ReceiveAll, receiveAllIp, null);
            _socket.ReceiveBufferSize = 1 << 24;
            Task.Run(()=>ReadAsync(_socket));
        }

        async Task ReadAsync(Socket s)
        {
            // Reusable SocketAsyncEventArgs and awaitable wrapper 
            var args = new SocketAsyncEventArgs();
            args.SetBuffer(new byte[0x100000], 0, 0x100000);
            var awaitable = new SocketAwaitable(args);
            while (_isInit)
            {
                await s.ReceiveAsync(awaitable);
                int bytesRead = args.BytesTransferred;
                if (bytesRead <= 0) throw new Exception("Raw socket is disconnected");
                var ipPacket = new IPv4Packet(new ByteArraySegment(args.Buffer, 0, bytesRead));
                if (ipPacket.Version != IpVersion.IPv4 || ipPacket.Protocol!=IPProtocolType.TCP)
                    continue;
                OnPacketReceived(ipPacket);
            }
            _socket.Close();
            _socket = null;
        }

        private void Finish()
        {
            if (!_isInit)
            {
                return;
            }
            Debug.Assert(_socket != null);
            _isInit = false;
        }
        
        protected override void SetEnabled(bool value)
        {
            if (value)
            {
                try
                {
                    Init();
                    _isInit = true;
                }
                catch
                {
                    // ignored
                }
            }
            else
            {
                Finish();
            }
        }


        public override string ToString()
        {
            return $"{base.ToString()} {_localIp}";
        }
    }

    public sealed class SocketAwaitable : INotifyCompletion
    {
        private readonly static Action SENTINEL = () => { };

        internal bool m_wasCompleted;
        internal Action m_continuation;
        internal SocketAsyncEventArgs m_eventArgs;

        public SocketAwaitable(SocketAsyncEventArgs eventArgs)<commit_msg>Fix stop working on bad packet recieved in raw sockets mode<commit_after>﻿// Copyright (c) CodesInChaos
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Data;
using PacketDotNet;
using PacketDotNet.Utils;

namespace NetworkSniffer
{
    public class IpSnifferRawSocketSingleInterface : IpSniffer
    {
        private readonly IPAddress _localIp;

        private bool _isInit;
        private Socket _socket;

        public IpSnifferRawSocketSingleInterface(IPAddress localIp)
        {
            _localIp = localIp;
        }

        private void Init()
        {
            Debug.Assert(_socket == null);
            if (_isInit) return;
            try
            {
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);

                if (_localIp != null)
                {
                    _socket.Bind(new IPEndPoint(_localIp, 0));
                }
                _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
                var receiveAllIp = BitConverter.GetBytes(3);
                _socket.IOControl(IOControlCode.ReceiveAll, receiveAllIp, null);
                _socket.ReceiveBufferSize = 1 << 24;
            }
            catch { return; }
            Task.Run(()=>ReadAsync(_socket));
            _isInit = true;
        }

        async Task ReadAsync(Socket s)
        {
            // Reusable SocketAsyncEventArgs and awaitable wrapper 
            var args = new SocketAsyncEventArgs();
            args.SetBuffer(new byte[0x100000], 0, 0x100000);
            var awaitable = new SocketAwaitable(args);
            while (_isInit)
            {
                await s.ReceiveAsync(awaitable);
                int bytesRead = args.BytesTransferred;
                if (bytesRead <= 0) throw new Exception("Raw socket is disconnected");
                IPv4Packet ipPacket;
                try
                {
                    ipPacket = new IPv4Packet(new ByteArraySegment(args.Buffer, 0, bytesRead));
                }
                catch (InvalidOperationException e)
                {
                    BasicTeraData.LogError(e.Message, false, true);
                    continue;
                }
                
                if (ipPacket.Version != IpVersion.IPv4 || ipPacket.Protocol!=IPProtocolType.TCP)
                    continue;
                OnPacketReceived(ipPacket);
            }
            _socket.Close();
            _socket = null;
        }

        private void Finish()
        {
            Debug.Assert(_socket != null);
            _isInit = false;
        }
        
        protected override void SetEnabled(bool value)
        {
            if (value) Init();
            else Finish();
        }


        public override string ToString()
        {
            return $"{base.ToString()} {_localIp}";
        }
    }

    public sealed class SocketAwaitable : INotifyCompletion
    {
        private readonly static Action SENTINEL = () => { };

        internal bool m_wasCompleted;
        internal Action m_continuation;
        internal SocketAsyncEventArgs m_eventArgs;

        public SocketAwaitable(SocketAsyncEventArgs eventArgs)
{'fraction_non_alphanumeric': 0.07742703990470517, 'fraction_numerical': 0.007296009529481834, 'mean_word_length': 1.6549407114624506, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2489476', 'n_tokens_mistral': 1771, 'n_tokens_neox': 1659, 'n_words': 410}