private void InitializeNetwork()
        {
            lock (m_initializeLock)
            {
                // make sure this is properly set up again, if required.

                // start network thread if not running
                NetPeerManager.StartNetworkThread();

                m_configuration.Lock();

                if (m_status == NetPeerStatus.Running)
                {
                    return;
                }

                if (m_configuration.m_enableUPnP)
                {
                    m_upnp = new NetUPnP(this);
                }

                InitializePools();

                m_releasedIncomingMessages.Clear();
                m_unsentUnconnectedMessages.Clear();

                _handshakeManager.Handshakes.Clear();

                // bind to socket
                BindSocket(false);

                m_receiveBuffer            = new byte[m_configuration.ReceiveBufferSize];
                m_sendBuffer               = new byte[m_configuration.SendBufferSize];
                m_readHelperMessage        = new NetIncomingMessage(NetIncomingMessageType.Error);
                m_readHelperMessage.m_data = m_receiveBuffer;

                byte[] macBytes = NetUtility.GetMacAddressBytes();

                var    boundEp  = m_socket.LocalEndPoint as NetEndPoint;
                byte[] epBytes  = BitConverter.GetBytes(boundEp.GetHashCode());
                byte[] combined = new byte[epBytes.Length + macBytes.Length];
                Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
                Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
                m_uniqueIdentifier = BitConverter.ToInt64(NetUtility.ComputeSHAHash(combined), 0);

                m_status = NetPeerStatus.Running;
            }
        }
        public void ExecutePeerShutdown()
        {
            Console.WriteLine("Network shutdown enter");
            // disconnect and make one final heartbeat
            var list = new List <NetConnection>(_handshakeManager.Handshakes.Count + m_connections.Count);

            lock (m_connections)
            {
                foreach (var conn in m_connections)
                {
                    if (conn != null)
                    {
                        list.Add(conn);
                    }
                }
            }

            foreach (var hs in _handshakeManager.Handshakes.Values)
            {
                if (hs != null && list.Contains(hs) == false)
                {
                    list.Add(hs);
                }
            }


            // shut down connections
            foreach (NetConnection conn in list)
            {
                conn.Shutdown(m_shutdownReason);
            }

            FlushDelayedPackets();

            // one final heartbeat, will send stuff and do disconnect
            PeerUpdate();

            NetUtility.Sleep(10);

            lock (m_initializeLock)
            {
                try
                {
                    if (m_socket != null)
                    {
                        try
                        {
                            // shutdown socket send and recieve handlers.
                            m_socket.Shutdown(SocketShutdown.Both);
                        }
                        catch (Exception e)
                        {
                            LogDebug(e.ToString());
                        }
                        finally
                        {
                            // close connection, if present
                            m_socket.Close(2);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogDebug("socket shutdown method exception: " + ex.ToString());
                    throw;
                }
                finally
                {
                    NetPeerManager.RemovePeer(this);
                    // wake up any threads waiting for server shutdown
                    m_messageReceivedEvent?.Set();

                    m_lastSocketBind = float.MinValue;
                    m_receiveBuffer  = null;
                    m_sendBuffer     = null;
                    m_unsentUnconnectedMessages?.Clear();
                    m_connections?.Clear();
                    m_connectionLookup?.Clear();
                    _handshakeManager.Handshakes?.Clear();
                    _handshakeManager = null;

                    m_status = NetPeerStatus.NotRunning;
                    LogDebug("Shutdown complete");
                    Console.WriteLine("Shutdown network peer properly");
                }
            }

            return;
        }
        /// <summary>
        /// Bind socket - with rebind parameter for when you need to rebind a socket
        /// </summary>
        /// <param name="rebind"></param>
        private void BindSocket(bool rebind)
        {
            double now = NetTime.Now;

            if (now - m_lastSocketBind < 1.0)
            {
                LogDebug("Suppressed socket rebind; last bound " + (now - m_lastSocketBind) + " seconds ago");
                return; // only allow rebind once every second
            }

            m_lastSocketBind = now;

            if (m_socket == null)
            {
                m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            }

            // todo: write unit test which executes rebinding of the sockets on android and ios
            if (rebind)
            {
                m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);
            }

            // Register this peer to our manager
            NetPeerManager.AddPeer(this);

            m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);

            m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
            m_socket.SendBufferSize    = m_configuration.SendBufferSize;
            m_socket.Blocking          = false;

            var ep = (EndPoint) new NetEndPoint(m_configuration.LocalAddress, rebind ? m_listenPort : m_configuration.Port);

            m_socket.Bind(ep);

            // try catch only works on linux not osx
            try
            {
                // this is not supported in mono / mac or linux yet.
                if (Environment.OSVersion.Platform != PlatformID.Unix)
                {
                    const uint IOC_IN            = 0x80000000;
                    const uint IOC_VENDOR        = 0x18000000;
                    uint       SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                    m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
                }
                else
                {
                    LogDebug("Platform doesn't support SIO_UDP_CONNRESET");
                }
            }
            catch (System.Exception e)
            {
                LogDebug("Platform doesn't support SIO_UDP_CONNRESET");
                // this will be thrown on linux but not mac if it doesn't exist.
                // ignore; SIO_UDP_CONNRESET not supported on this platform
            }

            var boundEp = m_socket.LocalEndPoint as NetEndPoint;

            LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound);
            m_listenPort = boundEp.Port;
        }