void ManageFragment(Datagram datagram) { if (!datagram.IsFragmented) { datagram.Dispose(); throw new InvalidOperationException("Datagram isn't fragemented"); } if (datagram.FragmentationInfo.Frame > datagram.FragmentationInfo.Frames) { logger.Error($"Invalid fragmented datagram frame {datagram.FragmentationInfo.Frame} > frames {datagram.FragmentationInfo.Frames}. Dropping..."); datagram.Dispose(); return; } FragmentHolder fragmentHolder = this.fragments.GetOrAdd(datagram.FragmentationInfo.FragmentationGroupId, (groupId) => { return(new FragmentHolder(datagram.FragmentationInfo.FragmentationGroupId, datagram.FragmentationInfo.Frames)); }); fragmentHolder.SetFrame(datagram); if (fragmentHolder.IsCompleted) { if (this.fragments.TryRemove(datagram.FragmentationInfo.FragmentationGroupId, out FragmentHolder removed)) { var message = fragmentHolder.Merge(peer.Configuration.MemoryStreamPool); ReleaseMessage(message, datagram.DeliveryType, datagram.Channel); fragmentHolder.Dispose(); } } }
void OnMtuExpand(Datagram datagram) { if (!CheckStatus(datagram, UdpConnectionStatus.Connected)) { return; } int size = datagram.GetTotalSize(); byte fix = 0; if (size > peer.Configuration.LimitMtu) { size = peer.Configuration.LimitMtu; fix = 1; } logger.Debug($"MTU Successfully expanded to {size} by request from other side"); var mtuDatagram = CreateSpecialDatagram(MessageType.ExpandMTUSuccess, 5); using (WardenStreamWriter writer = new WardenStreamWriter(mtuDatagram.BaseStream, true)) { writer.WriteVarInt(size); writer.Write(fix); } if (size > this.Mtu) { this.Mtu = size; } _ = SendDatagramAsync(mtuDatagram); datagram.Dispose(); }
void OnPing(Datagram datagram) { if (!CheckStatus(datagram, UdpConnectionStatus.Connected)) { return; } SendPong(datagram); datagram.Dispose(); }
bool CheckStatus(Datagram datagram, params UdpConnectionStatus[] status) { if (!CheckStatus(status)) { string expected = string.Join(",", status.Select(s => s.ToString())); logger.Debug($"Got {datagram.Type} in wrong connection status: {Status}, expected: {expected}. Dropping..."); datagram.Dispose(); return(false); } return(true); }
void OnDisconnectReq(Datagram datagram) { if (!CheckStatus(datagram, UdpConnectionStatus.Connected)) { return; } SendDatagramAsync(CreateSpecialDatagram(MessageType.DisconnectResp)); CloseInternal(DisconnectReason.ClosedByOtherPeer, datagram.ConvertToMessage()); datagram.Dispose(); }
void IChannelConnection.ReleaseDatagram(Datagram datagram) { if (datagram.IsFragmented) { ManageFragment(datagram); } else { ReleaseMessage(datagram.ConvertToMessage(), datagram.DeliveryType, datagram.Channel); datagram.Dispose(); } }
void OnConnectResp(Datagram datagram) { if (!CheckStatus(datagram, UdpConnectionStatus.Connecting)) { return; } ChangeStatus(UdpConnectionStatus.Connected); connectReq.Dispose(); connectReq = null; datagram.Dispose(); }
void OnPong(Datagram datagram) { if (!CheckStatus(datagram, UdpConnectionStatus.Connected)) { return; } int relate = ChannelBase.RelativeSequenceNumber(datagram.Sequence, lastPingSequence); if (relate != 0) { logger.Debug($"Got wrong pong, relate: {relate}"); datagram.Dispose(); return; } float latency = (float)(DateTime.UtcNow - lastPingSent).TotalMilliseconds; UpdateLatency(latency); datagram.Dispose(); }
public override void OnDatagram(Datagram datagram) { CheckDatagramValid(datagram); connection.ReleaseDatagram(datagram); lock (channelMutex) { int relate = RelativeSequenceNumber(datagram.Sequence, lastSequenceIn + 1); if (relate < 0) { logger.Debug($"Dropping old {datagram}"); datagram.Dispose(); return; //drop old } lastSequenceIn = datagram.Sequence; } }
internal void OnDatagram(Datagram datagram) { if (datagram.ConnectionKey != this.EndPoint.ConnectionKey) { logger.Warn($"Got wrong {datagram}: connection id mismatch"); datagram.Dispose(); return; } Statistics.PacketIn(); Statistics.BytesIn(datagram.GetTotalSize()); switch (datagram.Type) { case MessageType.ConnectReq: OnConnectReq(datagram); break; case MessageType.ConnectResp: OnConnectResp(datagram); break; case MessageType.DisconnectReq: OnDisconnectReq(datagram); break; case MessageType.DisconnectResp: OnDisconnectResp(datagram); break; case MessageType.Ping: OnPing(datagram); break; case MessageType.Pong: OnPong(datagram); break; case MessageType.ExpandMTURequest: OnMtuExpand(datagram); break; case MessageType.ExpandMTUSuccess: OnMtuSuccess(datagram); break; case MessageType.DeliveryAck: OnAckReceived(datagram); break; default: OnDataReceived(datagram); break; } }
void OnConnectReq(Datagram datagram) { switch (Status) { case UdpConnectionStatus.Connected: logger.Debug($"Got late {datagram.Type} resend connect resp"); SendDatagramAsync(CreateSpecialDatagram(MessageType.ConnectResp)); break; case UdpConnectionStatus.Waiting: var connectionAccepted = peer.OnAcceptConnection(new OnAcceptConnectionEventArgs(this.EndPoint.EndPoint, datagram.ConvertToMessage())); if (connectionAccepted) { logger.Debug($"Accepting connection {this}"); SendDatagramAsync(CreateSpecialDatagram(MessageType.ConnectResp)); ChangeStatus(UdpConnectionStatus.Connected); } else { logger.Debug($"Rejecting connection {this}"); SendDatagramAsync(CreateSpecialDatagram(MessageType.DisconnectResp)); ChangeStatus(UdpConnectionStatus.Disconnected); } break; case UdpConnectionStatus.Disconnected: logger.Debug($"Got late {datagram.Type}, but connection is closed. Resend disconnect resp"); SendDatagramAsync(CreateSpecialDatagram(MessageType.DisconnectResp)); break; default: logger.Debug($"Got {datagram.Type} in wrong connection status: {Status}. Dropping..."); break; } datagram.Dispose(); }
public override void OnAckReceived(Datagram datagram) { lock (channelMutex) { int relate = RelativeSequenceNumber(datagram.Sequence, ackWindowStart); if (relate < 0) { logger.Trace("Got duplicate/late ack"); datagram.Dispose(); return; //late/duplicate ack } if (relate == 0) { logger.Trace($"Got ack just in time, clearing pending {datagram}"); //connection.UpdateLatency(sendPendingPackets[ackWindowStart % WINDOW_SIZE].GetDelay()); sendPendingPackets[ackWindowStart % WINDOW_SIZE].Clear(); ackWindowStart = (ackWindowStart + 1) % MAX_SEQUENCE; while (sendPendingPackets[ackWindowStart % WINDOW_SIZE].AckReceived) { logger.Trace($"Clearing early pending {datagram}"); sendPendingPackets[ackWindowStart % WINDOW_SIZE].Clear(); ackWindowStart = (ackWindowStart + 1) % MAX_SEQUENCE; } datagram.Dispose(); TrySendDelayedPackets(); return; } int sendRelate = RelativeSequenceNumber(datagram.Sequence, lastSequenceOut); if (sendRelate < 0) { if (sendRelate < -WINDOW_SIZE) { logger.Trace("Very old ack received"); datagram.Dispose(); return; } //we have sent this message, it's just early if (sendPendingPackets[datagram.Sequence % WINDOW_SIZE].GotAck()) { //connection.UpdateLatency(sendPendingPackets[ackWindowStart % WINDOW_SIZE].GetDelay()); logger.Trace($"Got early ack {datagram} {sendRelate} {relate}"); } else { logger.Debug($"Got ack {datagram} for packet we're not waiting for {sendRelate} {relate}"); } } else if (sendRelate > 0) { logger.Debug("Got Ack for message we have not sent"); } datagram.Dispose(); //Probably gap in ack sequence need faster message resend //int curSequence = datagram.Sequence; //do //{ // curSequence--; // if (curSequence < 0) // curSequence = MAX_SEQUENCE - 1; // int slot = curSequence % WINDOW_SIZE; // if (!ackReceived[slot]) // { // if (sendPendingPackets[slot].ReSendNum == 1) // { // sendPendingPackets[slot].TryReSend(SendImmidiately, connection.GetInitialResendDelay(), false); // } // } //} while (curSequence != ackWindowStart); } }
public override void OnDatagram(Datagram datagram) { CheckDatagramValid(datagram); connection.SendDatagramAsync(datagram.CreateAck()); lock (channelMutex) { int relate = RelativeSequenceNumber(datagram.Sequence, recvWindowStart); if (relate == 0) { //right in time connection.ReleaseDatagram(datagram); AdvanceWindow(); int nextSeqNr = (datagram.Sequence + 1) % MAX_SEQUENCE; if (ordered) { while (recvWithheld[nextSeqNr % WINDOW_SIZE] != null) { connection.ReleaseDatagram(recvWithheld[nextSeqNr % WINDOW_SIZE]); AdvanceWindow(); nextSeqNr++; } } else { while (recvEarlyReceived[nextSeqNr % WINDOW_SIZE]) { AdvanceWindow(); nextSeqNr++; } } return; } if (relate < 0) { //duplicate logger.Trace($"Dropped duplicate {datagram}"); datagram.Dispose(); return; } if (relate > WINDOW_SIZE) { //too early message logger.Trace($"Dropped too early {datagram}"); datagram.Dispose(); return; } if (ordered) { if (recvWithheld[datagram.Sequence % WINDOW_SIZE] != null) { //duplicate logger.Trace($"Dropped duplicate {datagram}"); datagram.Dispose(); return; } recvWithheld[datagram.Sequence % WINDOW_SIZE] = datagram; } else { if (recvEarlyReceived[datagram.Sequence % WINDOW_SIZE]) { //duplicate logger.Trace($"Dropped duplicate {datagram}"); datagram.Dispose(); return; } recvEarlyReceived[datagram.Sequence % WINDOW_SIZE] = true; connection.ReleaseDatagram(datagram); } } }
void OnDisconnectResp(Datagram datagram) { CloseInternal(DisconnectReason.ClosedByThisPeer, null); datagram.Dispose(); }