public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod)
        {
            if (!started)
            {
                return;
            }

            if (!(conn is SteamP2PConnection steamp2pConn))
            {
                return;
            }
            if (!connectedClients.Contains(steamp2pConn) && conn != OwnerConnection)
            {
                DebugConsole.ThrowError("Tried to send message to unauthenticated connection: " + steamp2pConn.SteamID.ToString());
                return;
            }

            IWriteMessage msgToSend = new WriteOnlyMessage();

            byte[] msgData = new byte[msg.LengthBytes];
            msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
            msgToSend.Write(conn.SteamID);
            msgToSend.Write((byte)deliveryMethod);
            msgToSend.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
            msgToSend.Write((UInt16)length);
            msgToSend.Write(msgData, 0, length);

            byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
            Array.Resize(ref bufToSend, msgToSend.LengthBytes);
            ChildServerRelay.Write(bufToSend);
        }
        public override void Close(string msg = null)
        {
            if (!started)
            {
                return;
            }

            if (OwnerConnection != null)
            {
                OwnerConnection.Status = NetworkConnectionStatus.Disconnected;
            }

            for (int i = pendingClients.Count - 1; i >= 0; i--)
            {
                RemovePendingClient(pendingClients[i], DisconnectReason.ServerShutdown, msg);
            }

            for (int i = connectedClients.Count - 1; i >= 0; i--)
            {
                Disconnect(connectedClients[i], msg ?? DisconnectReason.ServerShutdown.ToString());
            }

            pendingClients.Clear();
            connectedClients.Clear();

            ChildServerRelay.ShutDown();

            OnShutdown?.Invoke();
        }
Example #3
0
        public override void Close(string msg = null, bool disableReconnect = false)
        {
            if (!isActive)
            {
                return;
            }

            isActive = false;

            for (int i = remotePeers.Count - 1; i >= 0; i--)
            {
                DisconnectPeer(remotePeers[i], msg ?? DisconnectReason.ServerShutdown.ToString());
            }

            Thread.Sleep(100);

            for (int i = remotePeers.Count - 1; i >= 0; i--)
            {
                ClosePeerSession(remotePeers[i]);
            }

            ChildServerRelay.ClosePipes();

            OnDisconnect?.Invoke(disableReconnect);

            SteamManager.LeaveLobby();
            Steamworks.SteamNetworking.ResetActions();
            Steamworks.SteamUser.OnValidateAuthTicketResponse -= OnAuthChange;
        }
        protected override void SendMsgInternal(NetworkConnection conn, DeliveryMethod deliveryMethod, IWriteMessage msg)
        {
            IWriteMessage msgToSend = new WriteOnlyMessage();

            msgToSend.Write(conn.SteamID);
            msgToSend.Write((byte)deliveryMethod);
            msgToSend.Write(msg.Buffer, 0, msg.LengthBytes);
            byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
            Array.Resize(ref bufToSend, msgToSend.LengthBytes);
            ChildServerRelay.Write(bufToSend);
        }
        public override void Start()
        {
            IWriteMessage outMsg = new WriteOnlyMessage();

            outMsg.Write(OwnerSteamID);
            outMsg.Write((byte)DeliveryMethod.Reliable);
            outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));

            byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
            Array.Resize(ref msgToSend, outMsg.LengthBytes);
            ChildServerRelay.Write(msgToSend);

            started = true;
        }
Example #6
0
        public override void Update(float deltaTime)
        {
            if (!isActive)
            {
                return;
            }

            if (ChildServerRelay.HasShutDown || (ChildServerRelay.Process?.HasExited ?? true))
            {
                Close();
                var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), TextManager.Get("ServerProcessClosed"));
                msgBox.Buttons[0].OnClicked += (btn, obj) => { GameMain.MainMenuScreen.Select(); return(false); };
                return;
            }

            for (int i = remotePeers.Count - 1; i >= 0; i--)
            {
                if (remotePeers[i].DisconnectTime != null && remotePeers[i].DisconnectTime < Timing.TotalTime)
                {
                    ClosePeerSession(remotePeers[i]);
                }
            }

            for (int i = 0; i < 100; i++)
            {
                if (!Steamworks.SteamNetworking.IsP2PPacketAvailable())
                {
                    break;
                }
                var packet = Steamworks.SteamNetworking.ReadP2PPacket();
                if (packet.HasValue)
                {
                    OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
                    receivedBytes += packet?.Data.Length ?? 0;
                }
            }

            GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, receivedBytes);
            GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, sentBytes);

            while (ChildServerRelay.Read(out byte[] incBuf))
            {
                ChildServerRelay.DisposeLocalHandles();
                IReadMessage inc = new ReadOnlyMessage(incBuf, false, 0, incBuf.Length, ServerConnection);
                HandleDataMessage(inc);
            }
        }
Example #7
0
        private void OnAuthChange(Steamworks.SteamId steamID, Steamworks.SteamId ownerID, Steamworks.AuthResponse status)
        {
            RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);

            DebugConsole.Log(steamID + " validation: " + status + ", " + (remotePeer != null));

            if (remotePeer == null)
            {
                return;
            }

            if (remotePeer.Authenticated)
            {
                if (status != Steamworks.AuthResponse.OK)
                {
                    DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication status changed: " + status.ToString());
                }
                return;
            }

            if (status == Steamworks.AuthResponse.OK)
            {
                remotePeer.OwnerSteamID   = ownerID;
                remotePeer.Authenticated  = true;
                remotePeer.Authenticating = false;
                foreach (var msg in remotePeer.UnauthedMessages)
                {
                    //rewrite the owner id before
                    //forwarding the messages to
                    //the server, since it's only
                    //known now
                    int prevBitPosition = msg.Message.BitPosition;
                    msg.Message.BitPosition = sizeof(ulong) * 8;
                    msg.Message.Write(ownerID);
                    msg.Message.BitPosition = prevBitPosition;
                    byte[] msgToSend = (byte[])msg.Message.Buffer.Clone();
                    Array.Resize(ref msgToSend, msg.Message.LengthBytes);
                    ChildServerRelay.Write(msgToSend);
                }
                remotePeer.UnauthedMessages.Clear();
            }
            else
            {
                DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication failed: " + status.ToString());
                return;
            }
        }
Example #8
0
        public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
        {
            if (!isActive)
            {
                return;
            }

            IWriteMessage msgToSend = new WriteOnlyMessage();

            byte[] msgData = new byte[msg.LengthBytes];
            msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
            msgToSend.Write(selfSteamID);
            msgToSend.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
            msgToSend.Write((UInt16)length);
            msgToSend.Write(msgData, 0, length);

            byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
            Array.Resize(ref bufToSend, msgToSend.LengthBytes);
            ChildServerRelay.Write(bufToSend);
        }
        private void SendDisconnectMessage(UInt64 steamId, string msg)
        {
            if (!started)
            {
                return;
            }
            if (string.IsNullOrWhiteSpace(msg))
            {
                return;
            }

            IWriteMessage msgToSend = new WriteOnlyMessage();

            msgToSend.Write(steamId);
            msgToSend.Write((byte)DeliveryMethod.Reliable);
            msgToSend.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
            msgToSend.Write(msg);

            byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
            Array.Resize(ref bufToSend, msgToSend.LengthBytes);
            ChildServerRelay.Write(bufToSend);
        }
Example #10
0
        private void OnAuthChange(Steamworks.SteamId steamID, Steamworks.SteamId ownerID, Steamworks.AuthResponse status)
        {
            RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);

            DebugConsole.Log(steamID + " validation: " + status + ", " + (remotePeer != null));

            if (remotePeer == null)
            {
                return;
            }

            if (remotePeer.Authenticated)
            {
                if (status != Steamworks.AuthResponse.OK)
                {
                    DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication status changed: " + status.ToString());
                }
                return;
            }

            if (status == Steamworks.AuthResponse.OK)
            {
                remotePeer.Authenticated  = true;
                remotePeer.Authenticating = false;
                foreach (var msg in remotePeer.UnauthedMessages)
                {
                    byte[] msgToSend = (byte[])msg.Message.Buffer.Clone();
                    Array.Resize(ref msgToSend, msg.Message.LengthBytes);
                    ChildServerRelay.Write(msgToSend);
                }
                remotePeer.UnauthedMessages.Clear();
            }
            else
            {
                DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication failed: " + status.ToString());
                return;
            }
        }
Example #11
0
        private void UpdatePendingClient(PendingClient pendingClient)
        {
            if (!started)
            {
                return;
            }

            if (serverSettings.BanList.IsBanned(pendingClient.SteamID, out string banReason))
            {
                RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
                return;
            }

            //DebugConsole.NewMessage("pending client status: " + pendingClient.InitializationStep);

            if (connectedClients.Count >= serverSettings.MaxPlayers - 1)
            {
                RemovePendingClient(pendingClient, DisconnectReason.ServerFull, "");
            }

            if (pendingClient.InitializationStep == ConnectionInitialization.Success)
            {
                SteamP2PConnection newConnection = new SteamP2PConnection(pendingClient.Name, pendingClient.SteamID)
                {
                    Status = NetworkConnectionStatus.Connected
                };
                connectedClients.Add(newConnection);
                pendingClients.Remove(pendingClient);
                OnInitializationComplete?.Invoke(newConnection);
            }

            pendingClient.TimeOut -= Timing.Step;
            if (pendingClient.TimeOut < 0.0)
            {
                RemovePendingClient(pendingClient, DisconnectReason.Unknown, Lidgren.Network.NetConnection.NoResponseMessage);
            }

            if (Timing.TotalTime < pendingClient.UpdateTime)
            {
                return;
            }
            pendingClient.UpdateTime = Timing.TotalTime + 1.0;

            IWriteMessage outMsg = new WriteOnlyMessage();

            outMsg.Write(pendingClient.SteamID);
            outMsg.Write((byte)DeliveryMethod.Reliable);
            outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep |
                                PacketHeader.IsServerMessage));
            outMsg.Write((byte)pendingClient.InitializationStep);
            switch (pendingClient.InitializationStep)
            {
            case ConnectionInitialization.ContentPackageOrder:
                var mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent).ToList();
                outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count);
                for (int i = 0; i < mpContentPackages.Count; i++)
                {
                    outMsg.Write(mpContentPackages[i].MD5hash.Hash);
                }
                break;

            case ConnectionInitialization.Password:
                outMsg.Write(pendingClient.PasswordSalt == null); outMsg.WritePadBits();
                if (pendingClient.PasswordSalt == null)
                {
                    pendingClient.PasswordSalt = Lidgren.Network.CryptoRandom.Instance.Next();
                    outMsg.Write(pendingClient.PasswordSalt.Value);
                }
                else
                {
                    outMsg.Write(pendingClient.Retries);
                }
                break;
            }

            byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
            Array.Resize(ref msgToSend, outMsg.LengthBytes);
            ChildServerRelay.Write(msgToSend);
        }
Example #12
0
        private void HandleDataMessage(IReadMessage inc)
        {
            if (!isActive)
            {
                return;
            }

            UInt64         recipientSteamId = inc.ReadUInt64();
            DeliveryMethod deliveryMethod   = (DeliveryMethod)inc.ReadByte();

            int p2pDataStart = inc.BytePosition;

            byte incByte = inc.ReadByte();

            bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
            bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
            bool isDisconnectMessage            = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
            bool isServerMessage    = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
            bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;

            if (recipientSteamId != selfSteamID)
            {
                if (!isServerMessage)
                {
                    DebugConsole.ThrowError("Received non-server message meant for remote peer");
                    return;
                }

                RemotePeer peer = remotePeers.Find(p => p.SteamID == recipientSteamId);

                if (peer == null)
                {
                    return;
                }

                if (isDisconnectMessage)
                {
                    DisconnectPeer(peer, inc.ReadString());
                    return;
                }

                Steamworks.P2PSend sendType;
                switch (deliveryMethod)
                {
                case DeliveryMethod.Reliable:
                case DeliveryMethod.ReliableOrdered:
                    //the documentation seems to suggest that the Reliable send type
                    //enforces packet order (TODO: verify)
                    sendType = Steamworks.P2PSend.Reliable;
                    break;

                default:
                    sendType = Steamworks.P2PSend.Unreliable;
                    break;
                }

                byte[] p2pData;

                if (isConnectionInitializationStep)
                {
                    p2pData    = new byte[inc.LengthBytes - p2pDataStart + 8];
                    p2pData[0] = inc.Buffer[p2pDataStart];
                    Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 64, p2pData, 8);
                    Array.Copy(inc.Buffer, p2pDataStart + 1, p2pData, 9, inc.LengthBytes - p2pDataStart - 1);
                }
                else
                {
                    p2pData = new byte[inc.LengthBytes - p2pDataStart];
                    Array.Copy(inc.Buffer, p2pDataStart, p2pData, 0, p2pData.Length);
                }

                if (p2pData.Length + 4 >= MsgConstants.MTU)
                {
                    DebugConsole.Log("WARNING: message length comes close to exceeding MTU, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
                    sendType = Steamworks.P2PSend.Reliable;
                }

                bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
                sentBytes += p2pData.Length;

                if (!successSend)
                {
                    if (sendType != Steamworks.P2PSend.Reliable)
                    {
                        DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
                        sendType    = Steamworks.P2PSend.Reliable;
                        successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
                        sentBytes  += p2pData.Length;
                    }
                    if (!successSend)
                    {
                        DebugConsole.ThrowError("Failed to send message to remote peer! (" + p2pData.Length.ToString() + " bytes)");
                    }
                }
            }
            else
            {
                if (isDisconnectMessage)
                {
                    DebugConsole.ThrowError("Received disconnect message from owned server");
                    return;
                }
                if (!isServerMessage)
                {
                    DebugConsole.ThrowError("Received non-server message from owned server");
                    return;
                }
                if (isHeartbeatMessage)
                {
                    return; //timeout is handled by Lidgren, ignore this message
                }
                if (isConnectionInitializationStep)
                {
                    IWriteMessage outMsg = new WriteOnlyMessage();
                    outMsg.Write(selfSteamID);
                    outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
                    outMsg.Write(Name);

                    byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
                    Array.Resize(ref msgToSend, outMsg.LengthBytes);
                    ChildServerRelay.Write(msgToSend);
                    return;
                }
                else
                {
                    if (initializationStep != ConnectionInitialization.Success)
                    {
                        OnInitializationComplete?.Invoke();
                        initializationStep = ConnectionInitialization.Success;
                    }
                    UInt16       length = inc.ReadUInt16();
                    IReadMessage msg    = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, ServerConnection);
                    OnMessageReceived?.Invoke(msg);

                    return;
                }
            }
        }
Example #13
0
        private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
        {
            if (!isActive)
            {
                return;
            }

            RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamId);

            if (remotePeer == null || remotePeer.DisconnectTime != null)
            {
                return;
            }

            IWriteMessage outMsg = new WriteOnlyMessage();

            outMsg.Write(steamId);
            outMsg.Write(data, 1, dataLength - 1);

            DeliveryMethod deliveryMethod = (DeliveryMethod)data[0];

            byte incByte      = data[1];
            bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
            bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
            bool isDisconnectMessage            = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
            bool isServerMessage    = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
            bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;

            if (!remotePeer.Authenticated)
            {
                if (!remotePeer.Authenticating)
                {
                    if (isConnectionInitializationStep)
                    {
                        remotePeer.DisconnectTime = null;

                        IReadMessage             authMsg            = new ReadOnlyMessage(data, isCompressed, 2, dataLength - 2, null);
                        ConnectionInitialization initializationStep = (ConnectionInitialization)authMsg.ReadByte();
                        //Console.WriteLine("received init step from "+steamId.ToString()+" ("+initializationStep.ToString()+")");
                        if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
                        {
                            remotePeer.Authenticating = true;

                            authMsg.ReadString(); //skip name
                            authMsg.ReadInt32();  //skip owner key
                            authMsg.ReadUInt64(); //skip steamid
                            UInt16 ticketLength = authMsg.ReadUInt16();
                            byte[] ticket       = authMsg.ReadBytes(ticketLength);

                            Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
                            if (authSessionStartState != Steamworks.BeginAuthResult.OK)
                            {
                                DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam auth session failed to start: " + authSessionStartState.ToString());
                                return;
                            }
                        }
                    }
                }
            }

            if (remotePeer.Authenticating)
            {
                remotePeer.UnauthedMessages.Add(new RemotePeer.UnauthedMessage()
                {
                    DeliveryMethod = deliveryMethod, Message = outMsg
                });
            }
            else
            {
                byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
                Array.Resize(ref msgToSend, outMsg.LengthBytes);
                ChildServerRelay.Write(msgToSend);
            }
        }