<commit_before>﻿using MumbleSharp.Audio;
using MumbleSharp.Audio.Codecs;
using MumbleSharp.Packets;
using ProtoBuf;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;

namespace MumbleSharp
{
    /// <summary>
    /// Handles the low level details of connecting to a mumble server. Once connection is established decoded packets are passed off to the MumbleProtocol for processing
    /// </summary>
    public class MumbleConnection
    {
        public ConnectionStates State { get; private set; }

        TcpSocket _tcp;
        UdpSocket _udp;

        DateTime _lastSentPing = DateTime.MinValue;

        public IMumbleProtocol Protocol { get; private set; }

        public IPEndPoint Host
        {
            get;
            private set;
        }

        readonly CryptState _cryptState = new CryptState();

        /// <summary>
        /// Creates a connection to the server using the given address and port.
        /// </summary>
        /// <param name="server">The server adress or IP.</param>
        /// <param name="port">The port the server listens to.</param>
        /// <param name="protocol">An object which will handle messages from the server</param>
        public MumbleConnection(string server, int port, IMumbleProtocol protocol)
            : this(new IPEndPoint(Dns.GetHostAddresses(server).First(a => a.AddressFamily == AddressFamily.InterNetwork), port), protocol)
        {
        }

        /// <summary>
        /// Creates a connection to the server
        /// </summary>
        /// <param name="host"></param>
        /// <param name="protocol"></param>
        public MumbleConnection(IPEndPoint host, IMumbleProtocol protocol)
        {
            Host = host;
            State = ConnectionStates.Disconnected;
            Protocol = protocol;
        }

        public void Connect(string username, string password, string[] tokens, string serverName)
        {
            if (State != ConnectionStates.Disconnected)
                throw new InvalidOperationException(string.Format("Cannot start connecting MumbleConnection when connection state is {0}", State));

            State = ConnectionStates.Connecting;
            Protocol.Initialise(this);

            _tcp = new TcpSocket(Host, Protocol, this);
            _tcp.Connect(username, password, tokens, serverName);

            // UDP Connection is disabled while decryption is broken
            // See: https://github.com/martindevans/MumbleSharp/issues/4
            // UDP being disabled does not reduce functionality, it forces packets to be sent over TCP instead
            _udp = new UdpSocket(Host, Protocol, this);
            //_udp.Connect();

            State = ConnectionStates.Connected;
        }

        public void Close()
        {
            State = ConnectionStates.Disconnecting;

            _udp.Close();
            _tcp.Close();

            State = ConnectionStates.Disconnected;
        }

        public void Process()
        {
            if ((DateTime.Now - _lastSentPing).TotalSeconds > 15)
            {
                _tcp.SendPing();

                if (_udp.IsConnected)
                    _udp.SendPing();

                _lastSentPing = DateTime.Now;
            }
            _tcp.Process();
            _udp.Process();
        }

        public void SendControl<T>(PacketType type, T packet)
        {
            _tcp.Send<T>(type, packet);
        }

        public void SendVoice(ArraySegment<byte> packet)
        {
            _tcp.Send(PacketType.UDPTunnel, packet);
        }

        private void ReceivedEncryptedUdp(byte[] packet)
        {
            byte[] plaintext = _cryptState.Decrypt(packet, packet.Length);

            if (plaintext == null)
            {
                Console.WriteLine("Decryption failed");
                return;
            }

            ReceiveDecryptedUdp(plaintext);
        }

        private void ReceiveDecryptedUdp(byte[] packet)
        {
            int type = packet[0] >> 5 & 0x7;

            if (type == 1)
                Protocol.UdpPing(packet);
            else
            {
                var vType = (SpeechCodecs)(packet[0] >> 5 & 0x7);
                var target = (SpeechTarget)(packet[0] & 0x1F);

                using (var reader = new UdpPacketReader(new MemoryStream(packet, 1, packet.Length - 1)))
                {
                    UInt32 session = (uint)reader.ReadVarInt64();
                    Int64 sequence = reader.ReadVarInt64();<commit_msg>Added a comment relating to #17<commit_after>﻿using MumbleSharp.Audio;
using MumbleSharp.Audio.Codecs;
using MumbleSharp.Packets;
using ProtoBuf;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;

namespace MumbleSharp
{
    /// <summary>
    /// Handles the low level details of connecting to a mumble server. Once connection is established decoded packets are passed off to the MumbleProtocol for processing
    /// </summary>
    public class MumbleConnection
    {
        public ConnectionStates State { get; private set; }

        TcpSocket _tcp;
        UdpSocket _udp;

        DateTime _lastSentPing = DateTime.MinValue;

        public IMumbleProtocol Protocol { get; private set; }

        public IPEndPoint Host
        {
            get;
            private set;
        }

        readonly CryptState _cryptState = new CryptState();

        /// <summary>
        /// Creates a connection to the server using the given address and port.
        /// </summary>
        /// <param name="server">The server adress or IP.</param>
        /// <param name="port">The port the server listens to.</param>
        /// <param name="protocol">An object which will handle messages from the server</param>
        public MumbleConnection(string server, int port, IMumbleProtocol protocol)
            : this(new IPEndPoint(Dns.GetHostAddresses(server).First(a => a.AddressFamily == AddressFamily.InterNetwork), port), protocol)
        {
        }

        /// <summary>
        /// Creates a connection to the server
        /// </summary>
        /// <param name="host"></param>
        /// <param name="protocol"></param>
        public MumbleConnection(IPEndPoint host, IMumbleProtocol protocol)
        {
            Host = host;
            State = ConnectionStates.Disconnected;
            Protocol = protocol;
        }

        public void Connect(string username, string password, string[] tokens, string serverName)
        {
            if (State != ConnectionStates.Disconnected)
                throw new InvalidOperationException(string.Format("Cannot start connecting MumbleConnection when connection state is {0}", State));

            State = ConnectionStates.Connecting;
            Protocol.Initialise(this);

            _tcp = new TcpSocket(Host, Protocol, this);
            _tcp.Connect(username, password, tokens, serverName);

            // UDP Connection is disabled while decryption is broken
            // See: https://github.com/martindevans/MumbleSharp/issues/4
            // UDP being disabled does not reduce functionality, it forces packets to be sent over TCP instead
            _udp = new UdpSocket(Host, Protocol, this);
            //_udp.Connect();

            State = ConnectionStates.Connected;
        }

        public void Close()
        {
            State = ConnectionStates.Disconnecting;

            _udp.Close();
            _tcp.Close();

            State = ConnectionStates.Disconnected;
        }

        public void Process()
        {
            if ((DateTime.Now - _lastSentPing).TotalSeconds > 15)
            {
                _tcp.SendPing();

                if (_udp.IsConnected)
                    _udp.SendPing();

                _lastSentPing = DateTime.Now;
            }
            _tcp.Process();
            _udp.Process();
        }

        public void SendControl<T>(PacketType type, T packet)
        {
            _tcp.Send<T>(type, packet);
        }

        public void SendVoice(ArraySegment<byte> packet)
        {
            //This is *totally wrong*
            //the packet contains raw encoded voice data, but we need to put it into the proper packet format

            _tcp.Send(PacketType.UDPTunnel, packet);
        }

        private void ReceivedEncryptedUdp(byte[] packet)
        {
            byte[] plaintext = _cryptState.Decrypt(packet, packet.Length);

            if (plaintext == null)
            {
                Console.WriteLine("Decryption failed");
                return;
            }

            ReceiveDecryptedUdp(plaintext);
        }

        private void ReceiveDecryptedUdp(byte[] packet)
        {
            int type = packet[0] >> 5 & 0x7;

            if (type == 1)
                Protocol.UdpPing(packet);
            else
            {
                var vType = (SpeechCodecs)(packet[0] >> 5 & 0x7);
                var target = (SpeechTarget)(packet[0] & 0x1F);

                using (var reader = new UdpPacketReader(new MemoryStream(packet, 1, packet.Length - 1)))
                {
                    UInt32 session = (uint)reader.ReadVarInt64();
                    Int64 sequence = reader.ReadVarInt64();
{'fraction_non_alphanumeric': 0.0949845596848046, 'fraction_numerical': 0.0063890959429240765, 'mean_word_length': 1.8590563165905631, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 53, 'https://': 2, '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': '3493565', 'n_tokens_mistral': 2491, 'n_tokens_neox': 2344, 'n_words': 664}