示例#1
0
        /// <summary> Sends signal to all components of Server to stop, then waits for everything to shut down. </summary>
        public static void Stop()
        {
            Log.Output(Log.Severity.DEBUG, Log.Source.NETWORK, "Stopping Server.");
            Stopping = true;
            WatchdogManager.Stop();

            // This is a meh solution to the WaitForClientsTCP thread not ending until the next client connects.
            TcpClient Dummy = new TcpClient();

            Dummy.Connect(new IPEndPoint(IPAddress.Loopback, ((IPEndPoint)TCPListener.LocalEndpoint).Port));
            Dummy.Close();

            while (Initialized)
            {
                Thread.Sleep(50);
            }                                         // Wait for all threads to stop.
        }
示例#2
0
        /// <summary> Prepares the server for use, and starts listening for clients. </summary>
        /// <param name="PortTCP"> The port to listen on for clients communicating via TCP. </param>
        /// <param name="PortUDP"> The port to listen on for clients communicating via UDP. </param>
        /// <param name="ReceiveBufferSize"> The size, in bytes, of the receive data buffers. Increase this if your packets are longer than the default. </param>
        /// <param name="OperationPeriod"> The time, in ms, between network operations. If you are sending/receiving a lot of packets, and notice delays, lower this. </param>
        /// <param name="UsePriorityQueue"> If it is ture, packet priority control will be enabled. </param>
        public static void Start(int PortTCP, int PortUDP, int ReceiveBufferSize = 64, int OperationPeriod = 20, bool UsePriorityQueue = false)
        {
            Server.ReceiveBufferSize = ReceiveBufferSize;
            Server.OperationPeriod   = OperationPeriod;
            Stopping = false;

            if (!Initialized)
            {
                Log.Output(Log.Severity.DEBUG, Log.Source.NETWORK, "Initializing Server.");
                Log.Output(Log.Severity.DEBUG, Log.Source.NETWORK, "Listening on ports " + PortTCP + " (TCP), and " + PortUDP + " (UDP).");

                Clients              = new Dictionary <string, ScarletClient>();
                SendQueues           = new Dictionary <string, PacketBuffer>();
                ReceiveQueue         = new QueueBuffer();
                PacketsSent          = new List <Packet>();
                PacketsReceived      = new List <Packet>();
                Initialized          = true;
                PriorityQueueEnabled = UsePriorityQueue;

                // Initialize default priority
                if (PriorityQueueEnabled)
                {
                    DefaultPriority = PacketPriority.MEDIUM;
                }
                else
                {
                    DefaultPriority = 0;
                }

                // Start Handler and listener
                PacketHandler.Start();
                new Thread(new ParameterizedThreadStart(StartThreads)).Start(new Tuple <int, int>(PortTCP, PortUDP));

                // Start watchdog
                WatchdogManager.Start(false);
                WatchdogManager.ConnectionChanged += WatchdogStatusUpdate;
            }
            else
            {
                Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Attempted to start Server when already started.");
            }
        }
示例#3
0
 /// <summary> Immediately sends a packet. Blocks until sending is complete, regardless of protocol. </summary>
 public static void SendNow(Packet ToSend)
 {
     if (!Initialized)
     {
         throw new InvalidOperationException("Cannot use Server before initialization. Call Server.Start().");
     }
     if (ToSend.Data.ID != Constants.WATCHDOG_PING || OutputWatchdogDebug)
     {
         Log.Output(Log.Severity.DEBUG, Log.Source.NETWORK, "Sending packet: " + ToSend);
     }
     if (!Clients.ContainsKey(ToSend.Endpoint))
     {
         WatchdogManager.RemoveWatchdog(ToSend.Endpoint);
         Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Tried to send packet to unknown client. Dropping.");
         return;
     }
     if (!Clients[ToSend.Endpoint].Connected)
     {
         Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Cannot send packet to client that is not connected.");
         return;
     }
     try
     {
         if (ToSend.IsUDP)
         {
             if (!Clients.ContainsKey(ToSend.Endpoint))
             {
                 throw new InvalidOperationException("Cannot send packet to client that is not connected.");
             }
             lock (Clients[ToSend.Endpoint])
             {
                 byte[] Data = ToSend.GetForSend();
                 UDPListener.Send(Data, Data.Length, Clients[ToSend.Endpoint].EndpointUDP);
                 if (StorePackets)
                 {
                     PacketsSent.Add(ToSend);
                 }
             }
         }
         else
         {
             if (!Clients.ContainsKey(ToSend.Endpoint))
             {
                 throw new InvalidOperationException("Cannot send packet to client that is not connected.");
             }
             lock (Clients[ToSend.Endpoint])
             {
                 byte[] Data = ToSend.GetForSend();
                 Clients[ToSend.Endpoint].TCP.GetStream().Write(Data, 0, Data.Length);
                 if (StorePackets)
                 {
                     PacketsSent.Add(ToSend);
                 }
             }
         }
     }
     catch (Exception Exc)
     {
         Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Failed to send packet.");
         Log.Exception(Log.Source.NETWORK, Exc);
     }
 }
示例#4
0
        /// <summary>
        /// Waits for, and receives data from a connected TCP client.
        /// This must be started on a thread, as it will block until CommHandler.Stopping is true, or the client disconnects.
        /// </summary>
        /// <param name="ClientObj"> The client to receive data from. Must be TcpClient. </param>
        private static void HandleTCPClient(object ClientObj)
        {
            TcpClient     Client  = (TcpClient)ClientObj;
            NetworkStream Receive = Client.GetStream();

            if (!Receive.CanRead)
            {
                Log.Output(Log.Severity.ERROR, Log.Source.NETWORK, "Client connection does not permit reading.");
                throw new Exception("NetworkStream does not support reading");
            }
            // Receive client name.
            String ClientName;

            byte[] DataBuffer = new byte[Math.Max(ReceiveBufferSize, 64)];
            try
            {
                int DataSize = Receive.Read(DataBuffer, 0, DataBuffer.Length);
                if (DataSize == 0)
                {
                    Receive?.Close();
                    if (!Stopping)
                    {
                        Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Client disconnected before sending name.");
                    }
                    return;
                }
                else
                {
                    ClientName = null;
                    try { ClientName = UtilData.ToString(DataBuffer.Take(DataSize).ToArray()); } catch { }
                    if (ClientName != null && ClientName.Length > 0)
                    {
                        Log.Output(Log.Severity.INFO, Log.Source.NETWORK, "TCP Client connected with name \"" + ClientName + "\".");
                        lock (Clients)
                        {
                            if (Clients.ContainsKey(ClientName))
                            {
                                Clients[ClientName].TCP       = Client;
                                Clients[ClientName].Connected = true;
                            }
                            else
                            {
                                ScarletClient NewClient = new ScarletClient()
                                {
                                    TCP       = Client,
                                    Name      = ClientName,
                                    Connected = true
                                };
                                Clients.Add(ClientName, NewClient);
                            }
                        }

                        // Create buffer for the client
                        CreateBufferIfClientIsNew(ClientName);
                    }
                    else
                    {
                        Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Invalid TCP client name received. Dropping connection.");
                    }
                }
            }
            catch (Exception Exc)
            {
                Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Failed to read name from incoming client. Dropping connection.");
                Log.Exception(Log.Source.NETWORK, Exc);
                Receive?.Close();
                return;
            }
            ClientConnChange(new EventArgs());
            WatchdogManager.AddWatchdog(ClientName);

            // Receive data from client.
            DataBuffer = new byte[ReceiveBufferSize];
            while (!Stopping && Clients[ClientName].Connected)
            {
                try
                {
                    int DataSize = Receive.Read(DataBuffer, 0, DataBuffer.Length);
                    Log.Output(Log.Severity.DEBUG, Log.Source.NETWORK, "Received data from client (TCP).");
                    if (DataSize == 0)
                    {
                        Log.Output(Log.Severity.INFO, Log.Source.NETWORK, "Client has disconnected.");
                        lock (Clients[ClientName]) { Clients[ClientName].Connected = false; }
                        break;
                    }
                    if (DataSize >= 5)
                    {
                        byte[]     Data           = DataBuffer.Take(DataSize).ToArray();
                        IPEndPoint ClientEndpoint = (IPEndPoint)Client.Client.RemoteEndPoint;
                        Packet     ReceivedPack   = new Packet(new Message(Data), false, ClientName);
                        ReceiveQueue.Enqueue(ReceivedPack);

                        if (StorePackets)
                        {
                            PacketsReceived.Add(ReceivedPack);
                        }
                    }
                    else
                    {
                        Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Data received from client was too short. Discarding.");
                    }
                }
                catch (IOException IOExc)
                {
                    if (IOExc.InnerException is SocketException)
                    {
                        int Error = ((SocketException)IOExc.InnerException).ErrorCode;
                        Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Failed to read data from connected client with SocketExcpetion code " + Error);
                        Log.Exception(Log.Source.NETWORK, IOExc);
                        if (Error == 10054)
                        {
                            Clients[ClientName].Connected = false;
                        }
                    }
                    else
                    {
                        Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Failed to read data from connected client because of IO exception.");
                        Log.Exception(Log.Source.NETWORK, IOExc);
                    }
                }
                catch (Exception OtherExc)
                {
                    Log.Output(Log.Severity.WARNING, Log.Source.NETWORK, "Failed to read data from connected client.");
                    Log.Exception(Log.Source.NETWORK, OtherExc);
                }
                Thread.Sleep(OperationPeriod);
            }
            lock (Clients) { Clients.Remove(ClientName); }
            Client.Client.Disconnect(true);
            Receive.Close();
            Client.Close();
            ClientConnChange(new EventArgs());
        }
示例#5
0
 /// <summary> Watchdog parse handler </summary>
 /// <param name="WatchdogPacket"> Packet to parse </param>
 public static void ParseWatchdogPacket(Packet WatchdogPacket)
 {
     WatchdogManager.FoundWatchdog(UtilData.ToString(WatchdogPacket.Data.Payload));
 }