/// <summary> /// Called when a packet has been determined as lost /// </summary> /// <param name="Packet">The packet that was lost</param> private void PacketLost(GMPacket Packet) { if (!Packet.IgnoreLoss) // Only resend if needed { Send(Packet); } }
/// <summary> /// The <see cref="Socket"/> send callback /// </summary> /// <param name="AR"></param> private void OnSendTo(IAsyncResult AR) { try { int Sent = _Socket.EndSendTo(AR); if (_Connected) { GMPacket InQueue = _SendQueue.TakeFirst(); if (InQueue != null) { Send(InQueue, true); } else { _Sending = false; } } else { _Socket.Close(); _Socket.Dispose(); _Socket = null; } } catch (Exception E) { Logger.Log(E, true); Dispose("Networking Error, 0x01"); } }
/// <summary> /// Sends a packet to the set <see cref="EndPoint"/> /// </summary> /// <param name="Packet">The <see cref="GMPacket"/> to send</param> /// <param name="Bypass">Should this send bypass the <see cref="_Sending"/> variable</param> public void Send(GMPacket Packet, bool Bypass = false) { if (!_Connected && Packet.Type != GMPacketType.Disconnect) { return; } if (_Sending && !Bypass) { _SendQueue.Add(Packet); return; } _Sending = true; Packet.SequenceId = _LocalSequence++; Packet.SequenceAck = _RemoteSequence; Packet.AckBitfield = CreateAckBitfield(); _SentPackets.TryAdd(Packet.SequenceId, new Tuple <GMPacket, DateTime>(Packet, DateTime.Now)); Tuple <GMPacket, DateTime> Out; if (_SentPackets.TryRemove((ushort)(Packet.SequenceId - Sent_Packet_Queue_Length), out Out)) { PacketLost(Out.Item1); } byte[] Bytes = Packet.GetData(); _Socket.BeginSendTo(Bytes, 0, Bytes.Length, SocketFlags.None, _RemoteEndPoint, OnSendTo, Packet); }
/// <summary> /// The receive callback /// </summary> /// <param name="AR"></param> private void OnReceiveFrom(IAsyncResult AR) { if (_Connected) { try { //EndPoint ClientEP = new IPEndPoint(IPAddress.Any, 0); int Length = _Socket.EndReceiveFrom(AR, ref _RemoteEndPoint); _ReceiveTimeout = DateTime.Now; _HasReceived = true; if (Length <= 0) { Dispose("Networking Error, 0x03"); } else { byte[] Data = new byte[Length]; Array.Copy(_ReceiveBuffer, Data, Length); ReceivedPacket(GMPacket.Create(Data)); BeginReceive(); } } catch (Exception E) // Disconnected { Logger.Log(E, true); Dispose("Networking Error, 0x04"); } } }
private void OnReceivePacket(GMPacket Packet) { if (Packet.Type == GMPacketType.Connect) { if (!Done) { Done = true; GMConnectPacket Connect = (GMConnectPacket)Packet; _OnConnect?.Invoke(Connect.Port); } } else if (!Done) { Done = true; _OnConnect?.Invoke(0); } }
/// <summary> /// Called when a <see cref="GMPacket"/> is received from the remote client /// </summary> /// <param name="Packet">The <see cref="GMPacket"/> received</param> private void ReceivedPacket(GMPacket Packet) { try { int SeqDif = SequenceDifference(_RemoteSequence, Packet.SequenceId); if (SeqDif > 0) // If the packet is newer { _RemoteSequence = Packet.SequenceId; Array.Copy(_RemoteReceived, 0, _RemoteReceived, SeqDif, _RemoteReceived.Length - SeqDif); // Shift Array _RemoteReceived[0] = true; for (int i = 1; i < SeqDif; i++) // Reset the unshifted elements if the SeqDif is > 1 { _RemoteReceived[i] = false; } } else if (SeqDif < 0 && SeqDif > -(_RemoteReceived.Length - 1)) // An older packet, if the sequence is out of the receive array, drop it { _RemoteReceived[Math.Abs(SeqDif)] = true; } ParseAcknowledegment(Packet.SequenceAck, Packet.AckBitfield); if (Packet.Type == GMPacketType.Ping) { Send(new GMPongPacket { PingId = ((GMPingPacket)Packet).PingId }); } OnReceivedPacket?.Invoke(Packet); } catch (Exception E) { Logger.Log(E, true); Dispose("Networking Error, 0x02"); } }