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(); }
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; }
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); } }
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; } }
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); }
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; } }
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); }
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; } } }
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); } }