<commit_before>using System;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using GT.Net;
using GT.Utils;

namespace GT.Net
{
    public delegate void NetPacketReceivedHandler(EndPoint ep, byte[] message);

    public class UdpMultiplexer : IStartable
    {
        protected readonly IPAddress address;
        protected readonly int port;
        protected UdpClient udpClient;
        protected Dictionary<EndPoint,NetPacketReceivedHandler> handlers = 
            new Dictionary<EndPoint,NetPacketReceivedHandler>();
        protected NetPacketReceivedHandler defaultHandler;

        // theoretical maximum is 65535 bytes; practical limit is 65507
        // <http://en.wikipedia.org/wiki/User_Datagram_Protocol>
        protected byte[] buffer = new byte[65535];

        public UdpMultiplexer(IPAddress address, int port)
        {
            this.address = address;
            this.port = port;
        }

        public int MaximumPacketSize {
            get { return udpClient.Client.SendBufferSize; }
        }

        public IPEndPoint LocalEndPoint
        {
            get { return new IPEndPoint(address, port); }
        }
        
        public bool Active
        {
            get { return udpClient != null; }
        }

        public void Start()
        {
            udpClient = new UdpClient(new IPEndPoint(address, port));
            udpClient.Client.Blocking = false;
            // udp sockets don't support LingerState/SO_LINGER
        }

        public void Stop()
        {
            if (udpClient == null) { return; }
            udpClient.Close();
            udpClient = null;
        }

        public void Dispose()
        {
            Stop();
            defaultHandler = null;
            handlers = null;
            udpClient = null;
        }

        public void SetDefaultMessageHandler(NetPacketReceivedHandler handler)
        {
            defaultHandler = handler;
        }

        public NetPacketReceivedHandler RemoveDefaultMessageHandler() {
            NetPacketReceivedHandler old = defaultHandler;
            defaultHandler = null;
            return old;
        }

        public void SetMessageHandler(EndPoint ep, NetPacketReceivedHandler handler)
        {
            handlers[ep] = handler;
        }

        public NetPacketReceivedHandler RemoveMessageHandler(EndPoint ep) {
            NetPacketReceivedHandler hdl;
            if (handlers == null || !handlers.TryGetValue(ep, out hdl)) { return null; }
            handlers.Remove(ep);
            return hdl;
        }

        /// <summary>
        /// Process any incoming messages from the UDP socket.
        /// </summary>
        /// <exception cref="SocketException">thrown if there is a socket error</exception>
        public void Update()
        {
            while (udpClient.Available > 0)
            {
                EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
                int rc;
                try { rc = udpClient.Client.ReceiveFrom(buffer, ref remote); }
                catch (SocketException e)
                {
                    if (e.SocketErrorCode == SocketError.ConnectionReset)
                    {
                        // "Windows seems to use this error code to indicate that the socket
                        // passed to recvfrom previously sent some traffic to a local address which 
                        // was not listening. A superficial reading of POSIX suggests that ECONNRESET 
                        // is indeed a valid return for recvfrom()." 
                        // <http://twistedmatrix.com/trac/ticket/2627>
                        // FIXME: Unfortunately once this happens, the socket returns ConnectionReset 
                        // forever more.  So on ConnectionReset we restart this demultiplexer.  Unfortunately
                        // we don't get the remote's address so we can't actually figure out which
                        // UdpHandle is responsible.  
                        // Thought to implement an explicit  session-close message except that doesn't 
                        // deal with improper shutdowns.
                        Console.WriteLine("ECONNRESET: {0}", remote);
                        Stop(); Start();
                        continue;
                    }
                    throw e;
                }
                NetPacketReceivedHandler h;
                DebugUtils.WriteLine(this + ": received " + rc + " bytes from " + remote);
                DebugUtils.DumpMessage("UDP-Mux received", buffer, 0, rc);
                if (!handlers.TryGetValue(remote, out h) || h == null)
                {
                    h = defaultHandler;
                    if (h == null)
                    {
                        /* FIXME: do something! */
                        Console.WriteLine(this + ": WARNING: no handler available for " + remote);
                        continue;
                    }
                    else
                    {
                        DebugUtils.WriteLine(this + ": no handler found; using default");
                    }
                }
                else
                {
                    DebugUtils.WriteLine(this + ": found handler: " + h);
                }
                h.Invoke(remote, new MemoryStream(buffer, 0, rc).ToArray());
            }<commit_msg>Set SIO_UDP_CONNRESET to false to prevent ConnectionResets. As described in <http://support.microsoft.com/kb/q263823/>. Fixes immediate problem of <https://papyrus.usask.ca/trac/gt/ticket/41>.<commit_after>using System;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using GT.Net;
using GT.Utils;

namespace GT.Net
{
    public delegate void NetPacketReceivedHandler(EndPoint ep, byte[] message);

    public class UdpMultiplexer : IStartable
    {
        protected readonly IPAddress address;
        protected readonly int port;
        protected UdpClient udpClient;
        protected Dictionary<EndPoint,NetPacketReceivedHandler> handlers = 
            new Dictionary<EndPoint,NetPacketReceivedHandler>();
        protected NetPacketReceivedHandler defaultHandler;

        // theoretical maximum is 65535 bytes; practical limit is 65507
        // <http://en.wikipedia.org/wiki/User_Datagram_Protocol>
        protected byte[] buffer = new byte[65535];

        public UdpMultiplexer(IPAddress address, int port)
        {
            this.address = address;
            this.port = port;
        }

        public int MaximumPacketSize {
            get { return udpClient.Client.SendBufferSize; }
        }

        public IPEndPoint LocalEndPoint
        {
            get { return new IPEndPoint(address, port); }
        }
        
        public bool Active
        {
            get { return udpClient != null; }
        }

        public void Start()
        {
            udpClient = new UdpClient(new IPEndPoint(address, port));
            udpClient.Client.Blocking = false;
            DisableUdpConnectionResetBehaviour();
        }

        /// <summary>Hack to avoid the ConnectionReset/ECONNRESET problem described
        /// in <a href="https://papyrus.usask.ca/trac/gt/ticket/41">bug 41</a>.</summary>
        private void DisableUdpConnectionResetBehaviour()
        {
            /// Code from http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic47566.aspx
            try
            {
                const int SIO_UDP_CONNRESET = -1744830452;
                byte[] inValue = new byte[4];   // zeroes = false
                udpClient.Client.IOControl(SIO_UDP_CONNRESET, inValue, null);
                DebugUtils.WriteLine("INFO: installed SIO_UDP_CONNRESET hack for UdpMultiplexer");
            }
            catch (Exception e) {
                DebugUtils.WriteLine("INFO: unable to install SIO_UDP_CONNRESET hack for UdpMultiplexer: {0}", e.Message);
            }
        }

        public void Stop()
        {
            if (udpClient == null) { return; }
            udpClient.Close();
            udpClient = null;
        }

        public void Dispose()
        {
            Stop();
            defaultHandler = null;
            handlers = null;
            udpClient = null;
        }

        public void SetDefaultMessageHandler(NetPacketReceivedHandler handler)
        {
            defaultHandler = handler;
        }

        public NetPacketReceivedHandler RemoveDefaultMessageHandler() {
            NetPacketReceivedHandler old = defaultHandler;
            defaultHandler = null;
            return old;
        }

        public void SetMessageHandler(EndPoint ep, NetPacketReceivedHandler handler)
        {
            handlers[ep] = handler;
        }

        public NetPacketReceivedHandler RemoveMessageHandler(EndPoint ep) {
            NetPacketReceivedHandler hdl;
            if (handlers == null || !handlers.TryGetValue(ep, out hdl)) { return null; }
            handlers.Remove(ep);
            return hdl;
        }

        /// <summary>
        /// Process any incoming messages from the UDP socket.
        /// </summary>
        /// <exception cref="SocketException">thrown if there is a socket error</exception>
        public void Update()
        {
            while (udpClient.Available > 0)
            {
                EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
                // any SocketExceptions will be caught by callers
                int rc = udpClient.Client.ReceiveFrom(buffer, ref remote); 
                DebugUtils.WriteLine("{0}: received {1} bytes from {2}", this, rc, remote);
                DebugUtils.DumpMessage("UDP-Mux received", buffer, 0, rc);
                NetPacketReceivedHandler h;
                if (!handlers.TryGetValue(remote, out h) || h == null)
                {
                    h = defaultHandler;
                    if (h == null)
                    {
                        Console.WriteLine("{0}: WARNING: no default handler for {1}: ignoring incoming packet", this, remote);
                        continue;
                    }
                    DebugUtils.WriteLine("{0}: no handler found for {1}; using default handler", this, remote);
                }
                else
                {
                    DebugUtils.WriteLine("{0}: found handler: {1}", this, h);
                }
                h.Invoke(remote, new MemoryStream(buffer, 0, rc).ToArray());
            }
{'fraction_non_alphanumeric': 0.08381420868413585, 'fraction_numerical': 0.007662472802951471, 'mean_word_length': 1.593719332679097, 'pattern_counts': {'":': 4, '<': 24, '<?xml version=': 0, '>': 26, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6869084', 'n_tokens_mistral': 2704, 'n_tokens_neox': 2521, 'n_words': 697}