Exemple #1
0
        //structure should be
        //uno: guid
        //dos: 0/1 (to distinguish string or int array)
        //tres: actual data (actual int or string array)

        public override SerializationResult <byte[]> SerializeData(object objData, NetClient client)
        {
            if (!(objData is SyncableStringArray))
            {
                return(new SerializationResult <byte[]>(false));
            }

            SyncableStringArray data = (SyncableStringArray)objData;

            byte[] guidData      = data.ID.ToByteArray();
            byte   isIndexesData = (byte)(data.SendingIndexes ? 1 : 0);

            //todo: possibly rework this to use shorts instead of ints in packets, would be smaller
            byte[] itemData;
            if (data.SendingIndexes)
            {
                //encoding indexes
                itemData = new byte[data.Indexes.Length * sizeof(int)];
                for (int i = 0; i < data.Indexes.Length; i++)
                {
                    Array.Copy(BitConverter.GetBytes(data.Indexes[i]), 0, itemData, i * sizeof(int), sizeof(int));
                }
            }
            else
            {
                //encoding strings + necessary indexes
                int      fullLength = 0;
                byte[][] strData    = new byte[data.Items.Length][];
                for (int i = 0; i < strData.Length; i++)
                {
                    strData[i]  = Encoding.Unicode.GetBytes(data.Items[i].String);
                    fullLength += strData[i].Length;
                }

                int currentPosition = 0;
                itemData = new byte[fullLength + (strData.Length * (sizeof(int) + sizeof(byte)))];
                for (int i = 0; i < strData.Length; i++)
                {
                    itemData[currentPosition] = (byte)(data.Items[i].Necessary ? 1 : 0);
                    Array.Copy(BitConverter.GetBytes(strData[i].Length), 0, itemData, currentPosition + 1, sizeof(int));
                    Array.Copy(strData[i], 0, itemData, currentPosition + sizeof(int) + 1, strData[i].Length);
                    currentPosition += sizeof(int) + strData[i].Length + 1;
                }
            }

            byte[] fullData = new byte[guidData.Length + sizeof(byte) + itemData.Length];
            Array.Copy(guidData, 0, fullData, 0, guidData.Length);
            fullData[guidData.Length] = isIndexesData;
            Array.Copy(itemData, 0, fullData, guidData.Length + sizeof(byte), itemData.Length);

            return(new SerializationResult <byte[]>(true, fullData));
        }
Exemple #2
0
        public override SerializationResult <object> DeserializeData(byte[] data, NetClient client)
        {
            if (data[16] > 1 || data.Length < 17 || (data[16] == 1 && (data.Length - 17) % sizeof(int) != 0))
            {
                return(new SerializationResult <object>(false));
            }

            SyncableStringArray ret = new SyncableStringArray();

            byte[] guidData = new byte[16];
            Array.Copy(data, 0, guidData, 0, guidData.Length);
            ret.ID = new Guid(guidData);

            ret.SendingIndexes = data[guidData.Length] == 1 ? true : false;
            if (ret.SendingIndexes)
            {
                ret.Indexes = new int[(data.Length - 17) / sizeof(int)];
                for (int i = 0; i < ret.Indexes.Length; i++)
                {
                    ret.Indexes[i] = BitConverter.ToInt32(data, (i * sizeof(int)) + 17);
                }
            }
            else
            {
                byte[] strData = new byte[data.Length - 17];
                Array.Copy(data, 17, strData, 0, strData.Length);

                var strings = new List <SyncableStringArray.OptionalString>();
                int i       = 0;
                while (i < strData.Length)
                {
                    bool   necessary = strData[i] == 1 ? true : false;
                    int    strLen    = BitConverter.ToInt32(strData, i + 1);
                    byte[] strBuf    = new byte[strLen];
                    Array.Copy(strData, i + sizeof(int) + 1, strBuf, 0, strBuf.Length);

                    strings.Add(new SyncableStringArray.OptionalString(Encoding.Unicode.GetString(strBuf), necessary));

                    i += strLen + sizeof(int) + 1;
                }

                ret.Items = strings.ToArray();
            }

            return(new SerializationResult <object>(true, ret));
        }
        public static NetManager CreateClient()
        {
            NetManager createdManager = new NetManager();

            createdManager.Udp  = new UdpClient();
            createdManager.Side = Side.Client;

            //this could be done with a custom channel for serialization and validation and shit but what's even the point lol
            createdManager.Channels[UDP_HANDSHAKE_CHANNEL_INDEX].OnRecieveRaw += (byte[] data, NetClient sender) =>
            {
                if (data.Length != sizeof(byte) + 16)
                {
                    return;
                }

                UdpHandshakeUpdateEvent updateEvent;
                if (data[0] == 0)                         //not completed
                {
                    byte[] guidData = new byte[16];
                    Array.Copy(data, 1, guidData, 0, guidData.Length);

                    updateEvent = new UdpHandshakeUpdateEvent
                    {
                        Complete = false,
                        GuidData = guidData
                    };
                }
                else
                {
                    updateEvent = new UdpHandshakeUpdateEvent
                    {
                        Complete = true
                    }
                };

                ManagerEvent handshakeEvent = new ManagerEvent(ManagerEventType.UdpHandshakeUpdate, updateEvent);
                createdManager.EventQueue.Enqueue(handshakeEvent);
            };

            createdManager.Channels[DISCONNECT_CHANNEL_INDEX].OnRecieveRaw +=
                (byte[] data, NetClient sender) => createdManager.Disconnect(Encoding.Unicode.GetString(data));

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

                if (data.ID != createdManager.ChannelSyncGuid)
                {
                    return;
                }

                if (data.SendingIndexes)
                {
                    for (int i = 0; i < createdManager.Channels.Count; i++)
                    {
                        createdManager.Channels[i].ID = (ushort)data.Indexes[i];
                    }

                    createdManager.IncrementInitialisationState();
                }
                else
                {
                    foreach (SyncableStringArray.OptionalString channel in data.Items)
                    {
                        createdManager.CreateChannel(channel.String);
                    }
                }
            };

            return(createdManager);
        }
Exemple #4
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());
        }
Exemple #5
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);
        }