예제 #1
0
        public NetEvent[] PollEvents()
        {
            List <NetEvent> events = new List <NetEvent>();

            #region Client Udp Handshake
            if (_ConnectionState == ConnectionState.Initialising && Side == Side.Client && UdpHandshakeGuid != null && !IsConnectedToLocalServer)
            {
                SendRaw(SendMode.Udp, UdpHandshakeGuid, Channels[UDP_HANDSHAKE_CHANNEL_INDEX], Server);
            }
            #endregion
            #region Client Heartbeat Sending
            if (_HeartbeatSendRate >= 0 && Side == Side.Client && DateTime.Now.Subtract(TimeSpan.FromMilliseconds(_HeartbeatSendRate)) > HeartbeatLastSend)
            {
                HeartbeatLastSend = DateTime.Now;
                SendRaw(SendMode.Udp, new byte[0], Channels[HEARTBEAT_CHANNEL_INDEX], Server);
            }
            #endregion

            #region Server Heartbeat Checking
            if (Side == Side.Server && _ClientTimeoutTime >= 0)
            {
                DateTime lastValidTime = DateTime.Now.Subtract(TimeSpan.FromMilliseconds(_ClientTimeoutTime));
                foreach (NetClient client in _Clients)
                {
                    if (lastValidTime > client.LastHeartbeat)
                    {
                        DisconnectClient(client, "Client timed out");
                    }
                }
            }
            #endregion

            while (EventQueue.TryDequeue(out ManagerEvent managerEvent))
            {
                switch (managerEvent.Type)
                {
                    #region Client-only Events
                case ManagerEventType.TcpConnectionComplete:
                {
                    var connectionEvent = (TcpConnectionCompleteEvent)managerEvent.Data;

                    if (connectionEvent.Type == ConnectionResult.Success)
                    {
                        ConnectionState = ConnectionState.Initialising;

                        //create channel index sync packet
                        var channels = new SyncableStringArray.OptionalString[Channels.Count];
                        for (int i = 0; i < Channels.Count; i++)
                        {
                            channels[i] = new SyncableStringArray.OptionalString(Channels[i].StringID, Channels[i].Necessary);
                        }

                        ChannelSyncGuid = Guid.NewGuid();

                        PollingNet = true;
                        Task.Run(ClientTcpListen);
                        Task.Run(ClientUdpListen);

                        //send
                        SyncableStringArray syncArray = new SyncableStringArray(ChannelSyncGuid, channels);
                        Channels[CHANNEL_INDEX_SYNC_CHANNEL_INDEX].SendSerialized(SendMode.Tcp, syncArray, Server);
                    }
                    else
                    {
                        ConnectionCompleteEvent failureEvent = new ConnectionCompleteEvent
                        {
                            Success         = false,
                            SocketErrorCode = 10060                                             //WSAETIMEDOUT
                        };

                        ConnectionState = ConnectionState.Unconnected;

                        if (connectionEvent.Exception != null)
                        {
                            failureEvent.SocketErrorCode = connectionEvent.Exception.ErrorCode;
                        }

                        events.Add(failureEvent);

                        CleanupAfterDisconnect();
                    }

                    break;
                }

                case ManagerEventType.UdpHandshakeUpdate:
                {
                    if (ConnectionState != ConnectionState.Initialising)
                    {
                        continue;
                    }

                    var handshakeEvent = (UdpHandshakeUpdateEvent)managerEvent.Data;
                    if (handshakeEvent.Complete)
                    {
                        //udp handshake successful, increment connection state
                        IncrementInitialisationState();
                        break;
                    }

                    //got the guid
                    if (UdpHandshakeGuid == null)
                    {
                        UdpHandshakeGuid = handshakeEvent.GuidData;
                    }

                    break;
                }

                case ManagerEventType.ConnectionComplete:
                {
                    ConnectionState = ConnectionState.Connected;

                    ConnectionCompleteEvent successEvent = new ConnectionCompleteEvent
                    {
                        Success = true
                    };
                    events.Add(successEvent);
                    break;
                }

                case ManagerEventType.DisconnectedSelf:
                {
                    events.Add(new DisconnectedSelfEvent());
                    break;
                }
                    #endregion

                    #region Server-only Events
                case ManagerEventType.RecievedTcpConnection:
                {
                    TcpClient newTcp = (TcpClient)managerEvent.Data;

                    //create udp handshake guid
                    Guid handshakeGuid = Guid.NewGuid();

                    NetClient newClient = new NetClient
                    {
                        Tcp = newTcp,
                        UdpHandshakeGuid = handshakeGuid,
                        Manager          = this
                    };
                    _Clients.Add(newClient);

                    byte[] handshakeGuidPacket = new byte[17];                                     // 1 + sizeof(Guid)
                    handshakeGuidPacket[0] = 0;
                    Array.Copy(handshakeGuid.ToByteArray(), 0, handshakeGuidPacket, 1, 16);

                    SendRaw(SendMode.Tcp, handshakeGuidPacket, Channels[UDP_HANDSHAKE_CHANNEL_INDEX], newClient);

                    Task.Run(() => ServerTcpListenToClient(newClient));                                     //start listening to client

                    break;
                }

                case ManagerEventType.RecievedLocalConnection:
                {
                    NetManager manager = (NetManager)managerEvent.Data;

                    NetClient newClient = new NetClient
                    {
                        IsLocal = true,
                        HasCompletedUdpHandshake = true,
                        LocalManager             = manager,
                        InitialisationCount      = 1,
                        Manager = this
                    };
                    _Clients.Add(newClient);

                    manager.LocalServersideClient = newClient;

                    break;
                }

                case ManagerEventType.RecievedUdpHandshakeAttempt:
                {
                    var handshakeAttempt = (UdpHandshakeAttemptEvent)managerEvent.Data;

                    foreach (NetClient client in Clients)
                    {
                        if (!client.HasCompletedUdpHandshake && handshakeAttempt.Guid == client.UdpHandshakeGuid)
                        {
                            client.HasCompletedUdpHandshake = true;
                            client.EP = handshakeAttempt.SenderEP;

                            IncrementClientInitialisationCount(client);

                            //create success packet
                            byte[] successPacket = new byte[17];                                             //gotta pad to 17 or the client doesn't accept it
                            successPacket[0] = 1;
                            Array.Copy(new Guid().ToByteArray(), 0, successPacket, 1, 16);

                            //notify client of success
                            SendRaw(SendMode.Tcp, successPacket, Channels[UDP_HANDSHAKE_CHANNEL_INDEX], client);

                            break;
                        }
                    }

                    break;
                }

                case ManagerEventType.ClientConnectionComplete:
                {
                    var connectedClient = (NetClient)managerEvent.Data;
                    ClientConnectedEvent connectedEvent = new ClientConnectedEvent
                    {
                        ConnectedClient = connectedClient
                    };
                    events.Add(connectedEvent);
                    break;
                }

                case ManagerEventType.ClientDisconnected:
                {
                    var disconnectEvent = (TcpClientDisconnectEvent)managerEvent.Data;

                    ClientDisconnectedEvent clientDisconnectedEvent = new ClientDisconnectedEvent
                    {
                        DisconnectedClient = disconnectEvent.Client,
                        DisconnectReason   = disconnectEvent.Reason
                    };
                    events.Add(clientDisconnectedEvent);
                    break;
                }
                    #endregion

                    #region Shared Events
                case ManagerEventType.RecievedData:
                {
                    Packet packet    = (Packet)managerEvent.Data;
                    byte[] data      = packet.Data;
                    ushort channelID = BitConverter.ToUInt16(data, 0);

                    //todo: depending on how the order of channels lines up i might be able to do a direct lookup here
                    NetChannel channel = null;
                    for (int i = (packet.SendMode == SendMode.Tcp ? TCP_CHANNEL_SKIP_AMOUNT : UDP_CHANNEL_SKIP_AMOUNT); i < Channels.Count; i++)                                     //skip any reserved channel indexes
                    {
                        if (Channels[i].ID == channelID)
                        {
                            channel = Channels[i];
                            break;
                        }
                    }

                    if (channel == null)
                    {
                        break;
                    }

                    byte[] headerless = new byte[data.Length - sizeof(ushort)];
                    Array.Copy(data, 2, headerless, 0, headerless.Length);

                    NetClient client = null;
                    if (Side == Side.Client)
                    {
                        //only possible sender is the server if we're a client
                        client = Server;
                    }
                    else
                    {
                        if (packet.SendMode == SendMode.Tcp)
                        {
                            client = packet.Client;
                        }
                        else
                        {
                            foreach (NetClient possibleClient in Clients)
                            {
                                if (possibleClient.EP?.Equals(packet.EP) ?? false)                                                 //null check to prevent nullrefs
                                {
                                    client = possibleClient;
                                    break;
                                }
                            }
                        }
                    }

                    if (client != null)
                    {
                        channel.RecieveData(headerless, client);
                    }

                    break;
                }
                    #endregion
                }
            }

            return(events.ToArray());
        }
예제 #2
0
        public static NetManager CreateServer(int port)
        {
            NetManager createdManager = new NetManager();

            createdManager.Side       = Side.Server;
            createdManager.ListenPort = port;
            createdManager.Udp        = new UdpClient(port);

            IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);

            createdManager.TcpListener = new TcpListener(localEP);

            //this could be done with a custom channel for serialization and shit but what's even the point lol
            createdManager.Channels[DISCONNECT_CHANNEL_INDEX].OnRecieveRaw +=
                (byte[] data, NetClient sender) => createdManager.DisconnectClient(sender, Encoding.Unicode.GetString(data));

            createdManager.Channels[HEARTBEAT_CHANNEL_INDEX].OnRecieveRaw += (byte[] data, NetClient sender) =>
            {
                sender.LastHeartbeat = DateTime.Now;
            };

            createdManager.Channels[CHANNEL_INDEX_SYNC_CHANNEL_INDEX].OnRecieveSerialized += (object objData, NetClient sender) =>
            {
                SyncableStringArray data = (SyncableStringArray)objData;

                if (data.SendingIndexes)
                {
                    return;
                }

                int[] indexes = new int[data.Items.Length];
                for (int i = 0; i < data.Items.Length; i++)
                {
                    NetChannel foundChannel = null;
                    foreach (NetChannel channel in createdManager.Channels)
                    {
                        if (channel.StringID == data.Items[i].String)
                        {
                            foundChannel = channel;
                            break;
                        }
                    }

                    if (foundChannel == null)
                    {
                        if (data.Items[i].Necessary)
                        {
                            createdManager.DisconnectClient(sender, $"Server is missing client's required channel: {data.Items[i].String}");
                            return;
                        }
                        else
                        {
                            indexes[i] = UNKNOWN_CHANNEL_CHANNEL_INDEX;
                            continue;
                        }
                    }

                    //put index of channel into index array
                    indexes[i] = foundChannel.ID;
                }

                List <NetChannel> serverChannelsNotOnClient = new List <NetChannel>();
                foreach (NetChannel channel in createdManager.Channels)
                {
                    if (Array.IndexOf(indexes, channel.ID) == -1)
                    {
                        if (channel.Necessary)
                        {
                            createdManager.DisconnectClient(sender, $"Client is missing server's required channel: {channel.StringID}");
                            return;
                        }
                        else
                        {
                            serverChannelsNotOnClient.Add(channel);
                        }
                    }
                }

                if (serverChannelsNotOnClient.Count != 0)
                {
                    //create packet containing new channels
                    var channelsNotOnClientNames = new SyncableStringArray.OptionalString[serverChannelsNotOnClient.Count];
                    for (int i = 0; i < serverChannelsNotOnClient.Count; i++)
                    {
                        channelsNotOnClientNames[i] = new SyncableStringArray.OptionalString(serverChannelsNotOnClient[i].StringID, true);
                    }

                    SyncableStringArray missingChannels = new SyncableStringArray(data.ID, channelsNotOnClientNames);
                    createdManager.Channels[CHANNEL_INDEX_SYNC_CHANNEL_INDEX].SendSerialized(SendMode.Tcp, missingChannels, sender);

                    int oldLength = indexes.Length;
                    Array.Resize(ref indexes, indexes.Length + serverChannelsNotOnClient.Count);
                    for (int i = oldLength; i < indexes.Length; i++)
                    {
                        indexes[i] = serverChannelsNotOnClient[i - oldLength].ID;
                    }
                }

                var indexPacket = new SyncableStringArray(data.ID, indexes);
                createdManager.Channels[CHANNEL_INDEX_SYNC_CHANNEL_INDEX].SendSerialized(SendMode.Tcp, indexPacket, sender);

                createdManager.IncrementClientInitialisationCount(sender);
            };


            return(createdManager);
        }