private int HandleIncomingCommands(Event evnt, Address receivedAddress, Buffer buffer) { uint receivedDataLength = buffer.DataLength; var header = ProtocolHeader.Create(buffer, Version); if (header == null) { return(0); } ushort peerID = header.PeerID; Peer peer = null; if (peerID != Version.MaxPeerID) { if (peerID > PeerCount) { return(0); } peer = Peers[peerID]; if (peer.State == PeerState.DISCONNECTED || peer.State == PeerState.ZOMBIE) { return(0); } if ((receivedAddress.Host != peer.Address.Host || receivedAddress.Port != peer.Address.Port) && peer.Address.Host != Address.Broadcast) { return(0); } if (header.SessionID != peer.SessionID) { return(0); } peer.Address = receivedAddress; peer.IncomingDataTotal += receivedDataLength; } while (buffer.BytesLeft > 0) { var command = Protocol.Create(buffer, Version); if (command == null || command is Protocol.None) { break; } if (peer == null && !(command is Protocol.Connect)) { break; } int result; switch (command) { case Protocol.Acknowledge c: result = HandleAcknowledge(evnt, peer, c); break; case Protocol.Connect c: result = HandleConnect(receivedAddress, ref peer, c); break; case Protocol.VerifyConnect c: result = HandleVerifyConnect(evnt, peer, c); break; case Protocol.Disconnect c: result = HandleDisconnect(peer, c); break; case Protocol.Ping _: result = 0; break; case Protocol.Send.Reliable c: result = HandleSendReliable(peer, c, buffer); break; case Protocol.Send.Unreliable c: result = HandleSendUnreliable(peer, c, buffer); break; case Protocol.Send.Unsequenced c: result = HandleSendUnsequenced(peer, c, buffer); break; case Protocol.Send.Fragment c: result = HandleSendFragment(peer, c, buffer); break; case Protocol.BandwidthLimit c: result = HandleBandwidthLimit(peer, c); break; case Protocol.ThrottleConfigure c: result = HandleThrottleConfigure(peer, c); break; default: result = -1; break; } ; if (result != 0) { break; } if (peer != null && command.Flags.HasFlag(ProtocolFlag.ACKNOWLEDGE)) { if (header.TimeSent is ushort sentTime) { switch (peer.State) { case PeerState.DISCONNECTING: case PeerState.ACKNOWLEDGING_CONNECT: break; case PeerState.ACKNOWLEDGING_DISCONNECT: if (command is Protocol.Disconnect) { peer.QueueAcknowledgement(command, sentTime); } break; default: peer.QueueAcknowledgement(command, sentTime); break; } } else { break; } } } if (evnt != null && evnt.Type != EventType.NONE) { return(1); } return(0); }
private int SendOutgoingCommands(Event evnt, bool checkForTimeout) { var buffer = new Buffer(MAXIMUM_MTU); bool continueSending = true; while (continueSending) { continueSending = false; foreach (var currentPeer in Peers) { if (currentPeer.State == PeerState.DISCONNECTED || currentPeer.State == PeerState.ZOMBIE) { continue; } bool hasSentTime = false; buffer.Position = Version.MaxHeaderSizeSend; buffer.DataLength = currentPeer.MTU; if (!currentPeer.Acknowledgements.Empty) { SendAcknowledgements(currentPeer, buffer, ref continueSending); } if (checkForTimeout && !currentPeer.SentReliableCommands.Empty && !Utils.TimeLess(ServiceTime, currentPeer.NextTimeout)) { if (CheckTimeouts(currentPeer, evnt) == 1) { return(1); } } if (!currentPeer.OutgoingReliableCommands.Empty) { SendReliableOutgoingCommands(currentPeer, buffer, ref continueSending, ref hasSentTime); } else if (currentPeer.SentReliableCommands.Empty && Utils.TimeDiff(ServiceTime, currentPeer.LastReceiveTime) >= Peer.PING_INTERVAL) { if (Protocol.Ping.SIZE <= buffer.BytesLeft) { currentPeer.Ping(); SendReliableOutgoingCommands(currentPeer, buffer, ref continueSending, ref hasSentTime); } } if (!currentPeer.OutgoingUnreliableCommands.Empty) { SendUnreliableOutgoingCommands(currentPeer, buffer, ref continueSending); } if (buffer.Position <= Version.MaxHeaderSizeSend) { continue; } if (currentPeer.PacketLossEpoch == 0u) { currentPeer.PacketLossEpoch = ServiceTime; } else if (Utils.TimeDiff(ServiceTime, currentPeer.PacketLossEpoch) >= Version.PacketLossInterval && currentPeer.PacketsSent > 0u) { uint packetLoss = currentPeer.PacketsLost * Peer.PACKET_LOSS_SCALE / currentPeer.PacketsSent; currentPeer.PacketLossVariance -= currentPeer.PacketLossVariance / 4u; if (packetLoss >= currentPeer.PacketLoss) { currentPeer.PacketLoss += (packetLoss - currentPeer.PacketLoss) / 8u; currentPeer.PacketLossVariance += (packetLoss - currentPeer.PacketLoss) / 4u; } else { currentPeer.PacketLoss -= (currentPeer.PacketLoss - packetLoss) / 8u; currentPeer.PacketLossVariance += (currentPeer.PacketLoss - packetLoss) / 4u; } currentPeer.PacketLossEpoch = ServiceTime; currentPeer.PacketsSent = 0; currentPeer.PacketsLost = 0; } uint bufferLength = buffer.Position; uint bufferOffset = 0; var header = new ProtocolHeader { SessionID = currentPeer.SessionID, PeerID = currentPeer.OutgoingPeerID, }; if (hasSentTime) { header.TimeSent = (ushort)ServiceTime; } else { header.TimeSent = null; bufferOffset += 2; bufferLength -= 2; } buffer.Position = bufferOffset; header.Write(buffer, Version); currentPeer.LastSendTime = ServiceTime; int sentLength = Socket.SendTo(currentPeer.Address, buffer.Data, bufferOffset, bufferLength); RemoveSentUnreliableCommands(currentPeer); if (sentLength < 0) { return(-1); } TotalSentData += (uint)sentLength; TotalSentPackets++; } } return(0); }