/// <summary> /// Called when a new peer has connected. /// </summary> /// <param name="Connection">Peer connection</param> protected virtual void PeerConnected(PeerConnection Connection) { PeerConnectedEventHandler h = this.OnPeerConnected; if (h != null) { try { h(this, Connection); } catch (Exception ex) { Log.Critical(ex); } } }
/// <summary> /// Is called when game data has been received. /// </summary> /// <param name="FromPlayer">Data came from this player.</param> /// <param name="Connection">Data came over this connection.</param> /// <param name="Packet">Data received.</param> protected virtual void GameDataReceived(Player FromPlayer, PeerConnection Connection, byte[] Packet) { GameDataEventHandler h = this.OnGameDataReceived; if (h != null) { try { h(this, new GameDataEventArgs(FromPlayer, Connection, Packet)); } catch (Exception ex) { Events.Log.Critical(ex); } } }
/// <summary> /// Sends a packet to a specific player using UDP. Can only be done if <see cref="State"/>=<see cref="MultiPlayerState.Ready"/>. /// </summary> /// <param name="PlayerId">ID of player to send the packet to.</param> /// <param name="Packet">Packet to send.</param> /// <param name="IncludeNrPreviousPackets">Number of previous packets to include in the datagram. Note that the network limits /// total size of datagram packets.</param> /// <exception cref="Exception">If <see cref="State"/>!=<see cref="MultiPlayerState.Ready"/>.</exception> public void SendUdpTo(Guid PlayerId, byte[] Packet, int IncludeNrPreviousPackets) { Player Player; lock (this.remotePlayersByEndpoint) { if (!this.playersById.TryGetValue(PlayerId, out Player)) { throw new ArgumentException("No player with that ID.", nameof(PlayerId)); } } PeerConnection Connection = Player.Connection; if (Connection != null) { Connection.SendUdp(Packet, IncludeNrPreviousPackets); } }
/// <summary> /// Sends a packet to a specific player using TCP. Can only be done if <see cref="State"/>=<see cref="MultiPlayerState.Ready"/>. /// </summary> /// <param name="PlayerId">ID of player to send the packet to.</param> /// <param name="Packet">Packet to send.</param> /// <exception cref="Exception">If <see cref="State"/>!=<see cref="MultiPlayerState.Ready"/>.</exception> public void SendTcpTo(Guid PlayerId, byte[] Packet) { Player Player; lock (this.remotePlayersByEndpoint) { if (!this.playersById.TryGetValue(PlayerId, out Player)) { throw new ArgumentException("No player with that ID.", nameof(PlayerId)); } } PeerConnection Connection = Player.Connection; if (!(Connection is null)) { Connection.SendTcp(Packet); } }
/// <summary> /// Connects to a peer in the peer-to-peer network. If the remote end point resides behind the same firewall as the current application, /// a direct connection to the local peer is made, for improved performance. /// </summary> /// <param name="RemoteEndPoint">Remote End-point.</param> /// <returns>Peer connection</returns> public async Task <PeerConnection> ConnectToPeer(IPEndPoint RemoteEndPoint) { if (this.state != PeerToPeerNetworkState.Ready) { throw new IOException("Peer-to-peer network not ready."); } TcpClient Client = new TcpClient(); IPEndPoint RemoteEndPoint2; try { if (IPAddress.Equals(RemoteEndPoint.Address, this.externalAddress)) { this.serviceWANIPConnectionV1.GetSpecificPortMappingEntry(string.Empty, (ushort)RemoteEndPoint.Port, "TCP", out ushort InternalPort, out string InternalClient, out bool Enabled, out string PortMappingDescription, out uint LeaseDuration); RemoteEndPoint2 = new IPEndPoint(IPAddress.Parse(InternalClient), InternalPort); await Client.ConnectAsync(RemoteEndPoint2.Address, RemoteEndPoint2.Port); } else { RemoteEndPoint2 = RemoteEndPoint; await Client.ConnectAsync(RemoteEndPoint.Address, RemoteEndPoint.Port); } } catch (Exception) { Client.Dispose(); throw; } PeerConnection Result = new PeerConnection(Client, this, RemoteEndPoint2, this.encapsulatePackets); Result.StartIdleTimer(); return(Result); }
private void Peer_OnClosed(object sender, EventArgs e) { PeerConnection Connection = (PeerConnection)sender; Player Player = (Player)Connection.StateObject; if (Player is null) { return; } if (Player.Connection != Connection) { return; } lock (this.remotePlayersByEndpoint) { Player.Connection = null; this.connectionCount--; Connection.StateObject = null; } MultiPlayerEnvironmentPlayerInformationEventHandler h = this.OnPlayerDisconnected; if (h != null) { try { h(this, Player); } catch (Exception ex) { Events.Log.Critical(ex); } } }
private async void AcceptTcpClients() { try { while (!this.disposed) { TcpClient Client = await this.tcpListener.AcceptTcpClientAsync(); if (Client != null) { try { PeerConnection Connection = new PeerConnection(Client, this, (IPEndPoint)Client.Client.RemoteEndPoint, this.encapsulatePackets); this.State = PeerToPeerNetworkState.Ready; this.PeerConnected(Connection); Connection.Start(); } catch (Exception) { if (this.state != PeerToPeerNetworkState.Closed) { this.State = PeerToPeerNetworkState.Error; } } } } } catch (Exception ex) { Log.Critical(ex); } }
private void Connection_OnReceived(object Sender, byte[] Packet) { PeerConnection Connection = (PeerConnection)Sender; Guid PlayerId; IPAddress PlayerRemoteAddress; IPEndPoint PlayerRemoteEndpoint; try { BinaryInput Input = new BinaryInput(Packet); PlayerId = Input.ReadGuid(); PlayerRemoteAddress = IPAddress.Parse(Input.ReadString()); PlayerRemoteEndpoint = new IPEndPoint(PlayerRemoteAddress, Input.ReadUInt16()); } catch (Exception) { Connection.Dispose(); return; } Player Player = (Player)Connection.StateObject; lock (this.remotePlayersByEndpoint) { if (!this.playersById.TryGetValue(PlayerId, out Player Player2) || Player2.PlayerId != Player.PlayerId) { Connection.Dispose(); return; } Player.Connection = Connection; } Connection.RemoteEndpoint = Player.GetExpectedEndpoint(this.p2pNetwork); Connection.OnReceived -= new BinaryEventHandler(Connection_OnReceived); Connection.OnReceived += new BinaryEventHandler(Peer_OnReceived); Connection.OnSent += new BinaryEventHandler(Connection_OnSent); BinaryOutput Output = new BinaryOutput(); Output.WriteGuid(this.localPlayer.PlayerId); Output.WriteString(this.ExternalAddress.ToString()); Output.WriteUInt16((ushort)this.ExternalEndpoint.Port); Connection.SendTcp(Output.GetPacket()); MultiPlayerEnvironmentPlayerInformationEventHandler h = this.OnPlayerConnected; if (h != null) { try { h(this, Player); } catch (Exception ex) { Events.Log.Critical(ex); } } }
private void Peer_OnReceived(object Sender, byte[] Packet) { PeerConnection Connection = (PeerConnection)Sender; Player Player; if (Connection.StateObject is null) { BinaryInput Input = new BinaryInput(Packet); Guid PlayerId; IPAddress PlayerRemoteAddress; IPEndPoint PlayerRemoteEndpoint; try { PlayerId = Input.ReadGuid(); PlayerRemoteAddress = IPAddress.Parse(Input.ReadString()); PlayerRemoteEndpoint = new IPEndPoint(PlayerRemoteAddress, Input.ReadUInt16()); } catch (Exception) { Connection.Dispose(); return; } if (Input.BytesLeft == 0) { Packet = null; } else { Packet = Input.GetRemainingData(); } bool AllConnected; lock (this.remotePlayersByEndpoint) { if (!this.playersById.TryGetValue(PlayerId, out Player)) { Connection.Dispose(); return; } if (Player.Connection is null) { this.connectionCount++; } else { Player.Connection.Dispose(); } Player.Connection = Connection; Connection.StateObject = Player; Connection.RemoteEndpoint = Player.GetExpectedEndpoint(this.p2pNetwork); AllConnected = this.connectionCount + 1 == this.playerCount; } MultiPlayerEnvironmentPlayerInformationEventHandler h = this.OnPlayerConnected; if (h != null) { try { h(this, Player); } catch (Exception ex) { Events.Log.Critical(ex); } } if (AllConnected) { this.State = MultiPlayerState.Ready; } if (Packet is null) { return; } } else { Player = (Player)Connection.StateObject; } this.GameDataReceived(Player, Connection, Packet); }
private async void AcceptTcpClients() { try { while (!this.disposed) { try { TcpClient Client = await this.tcpListener.AcceptTcpClientAsync(); if (this.disposed) { return; } if (!(Client is null)) { PeerConnection Connection = null; try { Connection = new PeerConnection(Client, this, (IPEndPoint)Client.Client.RemoteEndPoint, this.encapsulatePackets); this.State = PeerToPeerNetworkState.Ready; this.PeerConnected(Connection); Connection.Start(); } catch (Exception) { Connection?.Dispose(); } } } catch (SocketException) { // Ignore } catch (ObjectDisposedException) { // Ignore } catch (NullReferenceException) { // Ignore } catch (Exception ex) { Log.Critical(ex); } } } catch (Exception ex) { if (this.disposed) { return; } Log.Critical(ex); } }
private async void AcceptTcpClients() { try { while (!this.disposed && !(this.tcpListener is null)) { try { TcpClient TcpClient; try { TcpClient = await this.tcpListener.AcceptTcpClientAsync(); if (this.disposed) { return; } } catch (InvalidOperationException) { this.State = PeerToPeerNetworkState.Error; this.tcpListener?.Stop(); this.tcpListener = null; this.udpClient?.Dispose(); this.udpClient = null; return; } if (!(TcpClient is null)) { PeerConnection Connection = null; try { BinaryTcpClient Client = new BinaryTcpClient(TcpClient); Client.Bind(true); Connection = new PeerConnection(Client, this, (IPEndPoint)TcpClient.Client.RemoteEndPoint, this.encapsulatePackets); this.State = PeerToPeerNetworkState.Ready; this.PeerConnected(Connection); Connection.Start(); } catch (Exception) { Connection?.Dispose(); } } } catch (SocketException) { // Ignore } catch (ObjectDisposedException) { // Ignore } catch (NullReferenceException) { // Ignore } catch (Exception ex) { Log.Critical(ex); } } } catch (Exception ex) { if (this.disposed) { return; } Log.Critical(ex); } }
private async Task <bool> Connection_OnReceived(object Sender, byte[] Buffer, int Offset, int Count) { PeerConnection Connection = (PeerConnection)Sender; Guid PlayerId; IPAddress PlayerRemoteAddress; IPEndPoint PlayerRemoteEndpoint; try { BinaryInput Input = new BinaryInput(BinaryTcpClient.ToArray(Buffer, Offset, Count)); PlayerId = Input.ReadGuid(); PlayerRemoteAddress = IPAddress.Parse(Input.ReadString()); PlayerRemoteEndpoint = new IPEndPoint(PlayerRemoteAddress, Input.ReadUInt16()); } catch (Exception) { Connection.Dispose(); return(true); } Player Player = (Player)Connection.StateObject; lock (this.remotePlayersByEndpoint) { if (!this.playersById.TryGetValue(PlayerId, out Player Player2) || Player2.PlayerId != Player.PlayerId) { Connection.Dispose(); return(true); } Player.Connection = Connection; } Connection.RemoteEndpoint = Player.GetExpectedEndpoint(this.p2pNetwork); Connection.OnReceived -= this.Connection_OnReceived; Connection.OnReceived += this.Peer_OnReceived; Connection.OnSent += this.Connection_OnSent; BinaryOutput Output = new BinaryOutput(); Output.WriteGuid(this.localPlayer.PlayerId); Output.WriteString(this.ExternalAddress.ToString()); Output.WriteUInt16((ushort)this.ExternalEndpoint.Port); await Connection.SendTcp(Output.GetPacket()); MultiPlayerEnvironmentPlayerInformationEventHandler h = this.OnPlayerConnected; if (!(h is null)) { try { await h(this, Player); } catch (Exception ex) { Log.Critical(ex); } } return(true); }