internal RemotePeer(NetConnection connection, PeerInfo peerInfo) { PeerInfo = peerInfo; if (connection != null) { AddConnection(connection); } }
private void HandleConnection(NetConnection connection) { // Read hail message: IPEndPoint internalEndPoint; ulong sideChannelId; int sideChannelToken; string requestedName; byte[] remotePlayerData = null; try { UInt16 theirAppVersion = connection.RemoteHailMessage.ReadUInt16(); if (theirAppVersion != owner.appConfig.ApplicationVersion) { owner.Log("Disconnected client with wrong application version"); connection.Disconnect(DisconnectStrings.BadGameVersion); return; } int theirAppSignatureLength = (int)connection.RemoteHailMessage.ReadVariableUInt32(); byte[] theirAppSignature; if (theirAppSignatureLength < 0 || theirAppSignatureLength > NetworkAppConfig.ApplicationSignatureMaximumLength) { theirAppSignature = null; } else { theirAppSignature = connection.RemoteHailMessage.ReadBytes(theirAppSignatureLength); } if (theirAppSignature == null || !owner.appConfig.ApplicationSignature.SequenceEqual(theirAppSignature)) { owner.Log("Disconnected client with wrong application signature"); connection.Disconnect(DisconnectStrings.BadGameVersion); return; } internalEndPoint = connection.RemoteHailMessage.ReadIPEndPoint(); sideChannelId = connection.RemoteHailMessage.ReadUInt64(); sideChannelToken = connection.RemoteHailMessage.ReadInt32(); requestedName = connection.RemoteHailMessage.ReadString(); remotePlayerData = connection.RemoteHailMessage.ReadByteArray(); } catch { owner.UnconnectedProtocolError("Bad hail message"); connection.Disconnect(DisconnectStrings.BadHailMessage); return; } if (owner.GameInfo.SideChannelAuth) { int expectedToken; if (sideChannelToken == 0 || authTokens == null || !authTokens.TryGetValue(sideChannelId, out expectedToken) || expectedToken != sideChannelToken) { owner.UnconnectedProtocolError("Bad side-channel authentication"); connection.Disconnect(DisconnectStrings.BadSideChannelAuth); } } requestedName = requestedName.FilterNameNoDuplicates(locallyConnected, owner.LocalPeerInfo.PlayerName); // Check whether the server is full: // (Could possibly handle this as Approve/Deny, but would then have to track slots for pending connections.) if (IsFull) { owner.Log("Rejecting incoming connection (player name: " + requestedName + "): game is full"); connection.Disconnect(DisconnectStrings.GameFull); return; } // Setup remote peer: PeerInfo peerInfo = new PeerInfo() { ConnectionId = nextConnectionId++, PlayerName = requestedName, PlayerData = remotePlayerData, InputAssignment = AssignInput(), InternalEndPoint = internalEndPoint, ExternalEndPoint = connection.RemoteEndPoint, SideChannelId = sideChannelId, IsApplicationConnected = false, IsServer = false, }; RemotePeer remotePeer = new RemotePeer(connection, peerInfo); owner.Log("New connection: " + peerInfo.ToString()); // Setup connection tokens: int[] connectionTokens = new int[locallyConnected.Count]; for (int i = 0; i < connectionTokens.Length; i++) { connectionTokens[i] = random.Next(); } // Send info to joining peer: { var message = NetPeer.CreateMessage(); message.Write(P2PServerMessage.NetworkStartInfo); owner.GameInfo.WriteTo(message); peerInfo.WriteTo(message, true); // Send their peer info (except: they already have their own playerData) owner.LocalPeerInfo.WriteTo(message); // Send our peer info // Write out a list of who to connect to: Debug.Assert(locallyConnected.Count < byte.MaxValue); message.Write((byte)(locallyConnected.Count)); for (int i = 0; i < locallyConnected.Count; i++) { (locallyConnected[i].Tag as RemotePeer).PeerInfo.WriteTo(message); message.Write(connectionTokens[i]); } remotePeer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, 0); } // Send connect instructions to other peers: for (int i = 0; i < locallyConnected.Count; i++) { var message = NetPeer.CreateMessage(); message.Write(P2PServerMessage.PeerJoinedNetwork); peerInfo.WriteTo(message); message.Write(connectionTokens[i]); locallyConnected[i].SendMessage(message, NetDeliveryMethod.ReliableOrdered, 0); } // Add new connection to the local connection list: locallyConnected.Add(connection); // Start waiting for this new client to connect to the full network: StartPendingConnection(remotePeer); // Although the first connection won't need to wait: if (locallyConnected.Count == 1) { ReadyCheckAll(); } }
// Special use (for setting the server's peer info, and for host migration) internal void SetPeerInfo(PeerInfo peerInfo) { PeerInfo = peerInfo; }
// Special use (for setting the server's peer info, and for host migration) internal void SetPeerInfo(PeerInfo peerInfo) { this.PeerInfo = peerInfo; }