public void TrySend(DhtNetwork network) { // check if stuff in queue if (Packets.Count == 0 || Addresses.Count == 0 || network.Core.TimeNow < NextTry) { return; } Attempts++; if (Attempts >= Addresses.Count * 2) // every address known tried twice { Attempts = 0; Packets.RemoveFirst(); return; } RudpAddress target = Addresses.First.Value; Addresses.RemoveFirst(); Addresses.AddLast(target); NextTry = network.Core.TimeNow.AddSeconds(3); Tuple <uint, RudpPacket> tuple = Packets.First.Value; RudpPacket packet = tuple.Param2; packet.Ident = target.Ident; int sentBytes = SendtoAddress(network, target, packet); network.Core.ServiceBandwidth[tuple.Param1].OutPerSec += sentBytes; }
public static int SendtoAddress(DhtNetwork network, RudpAddress target, RudpPacket packet) { Debug.Assert(packet.Payload != null || packet.PacketType == RudpPacketType.LightAck); int sentBytes = 0; // same code used in rudpSocket if (network.Core.Firewall != FirewallType.Blocked && target.LocalProxy == null) { sentBytes = network.SendPacket(target.Address, packet); } else if (target.Address.TunnelClient != null) { sentBytes = network.SendTunnelPacket(target.Address, packet); } else { packet.ToAddress = target.Address; TcpConnect proxy = network.TcpControl.GetProxy(target.LocalProxy); if (proxy != null) { sentBytes = proxy.SendPacket(packet); } else { sentBytes = network.TcpControl.SendRandomProxy(packet); } } return(sentBytes); }
void ReceiveAck(G2ReceivedPacket raw, LightClient client, RudpPacket packet) { // remove acked packet foreach (Tuple <uint, RudpPacket> tuple in client.Packets) { if (tuple.Param2.PeerID == packet.PeerID) { client.Packets.Remove(tuple); client.Attempts = 0; break; } } // read ack ident and move to top foreach (RudpAddress address in client.Addresses) { if (address.Ident == packet.Ident) { client.Addresses.Remove(address); client.Addresses.AddFirst(address); address.LastAck = Core.TimeNow; break; } } client.NextTry = Core.TimeNow; // receieved ack, try to send next packet immediately client.TrySend(Network); }
void SendAck(RudpPacket packet) { RudpPacket ack = new RudpPacket(); ack.TargetID = Session.UserID; ack.TargetClient = Session.ClientID; ack.PeerID = RemotePeerID; ack.PacketType = RudpPacketType.Ack; ack.Sequence = packet.Sequence; ack.Payload = RudpAck.Encode(HighestSeqRecvd, (byte)(MAX_WINDOW_SIZE - RecvPacketMap.Count)); ack.Ident = packet.Ident; //Session.Log("Ack Sent, Seq " + ack.Sequence.ToString() + ", ID " + ack.PeerID.ToString() + ", highest " + HighestSeqRecvd.ToString()); if (!AckMap.Contains(ack.Sequence)) { AckMap[ack.Sequence] = true; AckOrder.Enqueue(ack.Sequence); } while (AckMap.Count > MAX_WINDOW_SIZE * 2) { AckMap.Remove(AckOrder.Dequeue()); } SendTracked(new TrackPacket(ack)); }
public void SendReliable(DhtClient client, uint service, int type, G2Packet packet, bool expedite) { if (!Clients.ContainsKey(client.RoutingID)) { return; } RudpPacket comm = CreateRudpPacket(client, service, type, packet, true); LightClient target = Clients[client.RoutingID]; if (expedite) { target.NextTry = Core.TimeNow; target.Packets.AddFirst(new Tuple <uint, RudpPacket>(service, comm)); target.TrySend(Network); return; } Active[client.RoutingID] = target; target.Packets.AddLast(new Tuple <uint, RudpPacket>(service, comm)); while (target.Packets.Count > 30) { //crit - log to console? Debug.Assert(false); target.Packets.RemoveFirst(); } target.TrySend(Network); }
void ReceivePong(RudpPacket pong) { if (pong.Payload != null) { uint ident = BitConverter.ToUInt32(pong.Payload, 0); SetPrimaryAddress(ident); } }
void ReceivePing(RudpPacket ping) { RudpPacket pong = new RudpPacket(); pong.TargetID = Session.UserID; pong.TargetClient = Session.ClientID; pong.PeerID = RemotePeerID; pong.PacketType = RudpPacketType.Pong; pong.Sequence = 0; pong.Payload = ping.Payload; SendTracked(new TrackPacket(pong)); }
void ReceiveFin(RudpPacket packet) { //Session.Log("Fin Recv, Seq " + packet.Sequence.ToString() + ", ID " + packet.PeerID.ToString() + ", Reason " + packet.Payload[0].ToString()); FinReceived = true; SendAck(packet); if (!FinSent) { RudpClose(CloseReason.YOU_CLOSED); } }
/*public void SendUnreliable(RudpAddress address, uint service, int type, G2Packet packet) * { * // insecure, rudp provides this same method which is more secure, if a rudp connection is already established * * RudpPacket wrap = CreateRudpPacket(address.Address, service, type, packet, false); * * int sentBytes = LightClient.SendtoAddress(Core.Network, address, wrap); * * Core.ServiceBandwidth[service].OutPerSec += sentBytes; * }*/ public void ReceivePacket(G2ReceivedPacket raw, RudpPacket packet) { DhtClient client = new DhtClient(packet.SenderID, packet.SenderClient); if (!Clients.ContainsKey(client.RoutingID)) { Clients[client.RoutingID] = new LightClient(client); } LightClient light = Clients[client.RoutingID]; light.LastSeen = Core.TimeNow; // either direct, or node's proxy light.AddAddress(Core, new RudpAddress(raw.Source), true); if (raw.ReceivedTcp) // add this second so sending ack through tcp proxy is perferred { light.AddAddress(Core, new RudpAddress(raw.Source, raw.Tcp), true); } if (packet.PacketType == RudpPacketType.LightAck) { ReceiveAck(raw, light, packet); } else if (packet.PacketType == RudpPacketType.Light) { RudpLight info = new RudpLight(packet.Payload); if (Core.ServiceBandwidth.ContainsKey(info.Service)) { Core.ServiceBandwidth[info.Service].InPerSec += raw.Root.Data.Length; } if (Data.Contains(info.Service, info.Type)) { Data[info.Service, info.Type].Invoke(client, info.Data); } if (packet.Sequence == 1) // reliable packet { SendAck(light, packet, info.Service); } } }
public void SendPacket(RudpPacket packet, RudpAddress target) { Debug.Assert(packet.Payload != null); // sending syn to (tracked target) through (address target) udp / tcp /*string log = "Sending " + tracked.Packet.PacketType.ToString(); * if (tracked.Packet.Ident != 0) log += ", ID " + tracked.Packet.Ident.ToString(); * log += " to " + Utilities.IDtoBin(tracked.Packet.TargetID).Substring(0, 10); * log += " target address " + target.Address.ToString();*/ int sentBytes = 0; // same code used in lightComm if (Core.Firewall != FirewallType.Blocked && target.LocalProxy == null) { sentBytes = Network.SendPacket(target.Address, packet); } else if (target.Address.TunnelClient != null) { sentBytes = Network.SendTunnelPacket(target.Address, packet); } else { packet.ToAddress = target.Address; TcpConnect proxy = Network.TcpControl.GetProxy(target.LocalProxy); if (proxy != null) { sentBytes = proxy.SendPacket(packet); } else { sentBytes = Network.TcpControl.SendRandomProxy(packet); } //log += " proxied by local tcp"; } Bandwidth.OutPerSec += sentBytes; //Session.Log(log); }
void SendSyn() { RudpPacket syn = new RudpPacket(); lock (SendSection) // ensure queued in right order with right current seq { syn.TargetID = Session.UserID; syn.TargetClient = Session.ClientID; syn.PeerID = 0; syn.PacketType = RudpPacketType.Syn; syn.Sequence = CurrentSeq++; syn.Payload = RudpSyn.Encode(1, Network.Local.UserID, Network.Local.ClientID, PeerID); SendPacketMap.Enqueue(new TrackPacket(syn)); } ManageSendWindow(); }
RudpPacket CreateRudpPacket(DhtClient client, uint service, int type, G2Packet packet, bool reliable) { RudpPacket comm = new RudpPacket(); comm.SenderID = Network.Local.UserID; comm.SenderClient = Network.Local.ClientID; comm.TargetID = client.UserID; comm.TargetClient = client.ClientID; comm.PacketType = RudpPacketType.Light; comm.Payload = RudpLight.Encode(service, type, packet.Encode(Network.Protocol)); if (reliable) { comm.PeerID = (ushort)Core.RndGen.Next(ushort.MaxValue); // used to ack comm.Sequence = 1; } return(comm); }
void SendPing(RudpAddress address) { RudpPacket ping = new RudpPacket(); ping.TargetID = Session.UserID; ping.TargetClient = Session.ClientID; ping.PeerID = RemotePeerID; ping.PacketType = RudpPacketType.Ping; ping.Sequence = 0; ping.Payload = BitConverter.GetBytes(address.Ident); //Session.Log("Keep Alive Sent, Seq " + alive.Sequence.ToString() + ", ID " + alive.PeerID.ToString()); TrackPacket tracked = new TrackPacket(ping); tracked.Target = address; tracked.SpecialTarget = true; SendTracked(tracked); }
void SendAck(LightClient light, RudpPacket packet, uint service) { RudpPacket comm = new RudpPacket(); comm.SenderID = Network.Local.UserID; comm.SenderClient = Network.Local.ClientID; comm.TargetID = light.Client.UserID; comm.TargetClient = light.Client.ClientID; comm.PacketType = RudpPacketType.LightAck; comm.PeerID = packet.PeerID; // so remote knows which packet we're acking comm.Ident = packet.Ident; // so remote knows which address is good comm.Sequence = 0; // send ack to first address, addresses moved to front on receive packet int sentBytes = LightClient.SendtoAddress(Network, light.Addresses.First.Value, comm); Core.ServiceBandwidth[service].OutPerSec += sentBytes; // on resend packet from remote we receive it through different proxy, so that address // is moved to the front of the list automatically and our ack takes that direction }
void ReceiveSyn(RudpPacket packet) { RudpSyn syn = new RudpSyn(packet.Payload); if (RemotePeerID == 0) { RemotePeerID = syn.ConnID; } //Session.Log("Syn Recv, Seq " + packet.Sequence.ToString() + ", ID " + syn.ConnID.ToString()); SendAck(packet); // send ack here also because peerID now set SynAckSent = true; if (SynAckSent && SynAckReceieved) { Session.Log("Connected (recv syn)"); ChangeState(RudpState.Connected); SetConnected(); } }
void StartFin(CloseReason reason) { FinPacket = new RudpPacket(); lock (SendSection) // ensure queued in right order with right current seq { FinPacket.TargetID = Session.UserID; FinPacket.TargetClient = Session.ClientID; FinPacket.PeerID = RemotePeerID; FinPacket.PacketType = RudpPacketType.Fin; FinPacket.Payload = new byte[1] { (byte)reason }; } ChangeState(RudpState.Finishing); FinTimeout = 15; TrySendFin(); //Session.Log("Fin Sent, Seq " + fin.Sequence.ToString() + ", ID " + fin.PeerID.ToString() + ", Reason " + reason.ToString()); ManageSendWindow(); // immediately try to send the fin }
public void SendUnreliable(uint service, uint type, G2Packet packet) { // fast, secure, out-of-band method of sending data // useful for things like VOIP during a file transfer with host // data has got to go out asap, no matter what // check rudp socket is connected if (Status != SessionStatus.Active) { return; } // add to special rudp packet RudpPacket rudp = new RudpPacket(); rudp.SenderID = Network.Local.UserID; rudp.SenderClient = Network.Local.ClientID; rudp.TargetID = UserID; rudp.TargetClient = ClientID; rudp.PeerID = Comm.RemotePeerID; rudp.PacketType = RudpPacketType.Unreliable; CommData data = new CommData(service, type, packet.Encode(Network.Protocol)); rudp.Payload = Utilities.EncryptBytes(data.Encode(Network.Protocol), OutboundEnc.Key); // send Comm.SendPacket(rudp, Comm.PrimaryAddress); // stats Core.ServiceBandwidth[service].OutPerSec += data.Data.Length; PacketLogEntry logEntry = new PacketLogEntry(Core.TimeNow, TransportProtocol.Rudp, DirectionType.Out, Comm.PrimaryAddress.Address, rudp.Payload); Core.Network.LogPacket(logEntry); }
public ListViewItem PackettoItem(PacketLogEntry logEntry) { // hash, protocol, direction, address, type, size string hash = Utilities.BytestoHex(sha.ComputeHash(logEntry.Data), 0, 2, false); string protocol = logEntry.Protocol.ToString(); // Network - Search / Search Req / Store ... - Component // Comm - Data / Ack / Syn // Rudp - Type - Component string name = "?"; G2Header root = new G2Header(logEntry.Data); if (G2Protocol.ReadPacket(root)) { if (logEntry.Protocol == TransportProtocol.Rudp) { name = TransportProtocol.Rudp.ToString() + " - "; name += GetVariableName(typeof(CommPacket), root.Name); if (root.Name == CommPacket.Data) { CommData data = CommData.Decode(root); name += " - " + Network.Core.GetServiceName(data.Service); } } else { name = GetVariableName(typeof(RootPacket), root.Name) + " - "; if (root.Name == RootPacket.Comm) { RudpPacket commPacket = RudpPacket.Decode(root); name += GetVariableName(typeof(RudpPacketType), commPacket.PacketType); } if (root.Name == RootPacket.Network) { NetworkPacket netPacket = NetworkPacket.Decode(root); G2Header internalRoot = new G2Header(netPacket.InternalData); if (G2Protocol.ReadPacket(internalRoot)) { name += GetVariableName(typeof(NetworkPacket), internalRoot.Name); uint id = 0; G2ReceivedPacket wrap = new G2ReceivedPacket(); wrap.Root = internalRoot; // search request / search acks / stores have component types if (internalRoot.Name == NetworkPacket.SearchRequest) { SearchReq req = SearchReq.Decode(wrap); id = req.Service; } if (internalRoot.Name == NetworkPacket.SearchAck) { SearchAck ack = SearchAck.Decode(wrap); id = ack.Service; } if (internalRoot.Name == NetworkPacket.StoreRequest) { StoreReq store = StoreReq.Decode(wrap); id = store.Service; } if (id != 0) { name += " - " + Network.Core.GetServiceName(id); // GetVariableName(typeof(ServiceID), id); } } } } } string time = logEntry.Time.ToString("HH:mm:ss:ff"); string address = (logEntry.Address == null) ? "Broadcast" : logEntry.Address.ToString(); return(new PacketListViewItem(logEntry, new string[] { time, protocol, address, name, logEntry.Data.Length.ToString(), hash }, logEntry.Direction == DirectionType.In)); }
public void ReceivePacket(G2ReceivedPacket packet) { // Network packet if (packet.Root.Name == RootPacket.Network) { NetworkPacket netPacket = NetworkPacket.Decode(packet.Root); G2ReceivedPacket embedded = new G2ReceivedPacket(); embedded.Tcp = packet.Tcp; embedded.Source = packet.Source; embedded.Source.UserID = netPacket.SourceID; embedded.Source.ClientID = netPacket.ClientID; embedded.Root = new G2Header(netPacket.InternalData); // from - received from proxy server if (netPacket.FromAddress != null) { if (packet.ReceivedUdp) { throw new Exception("From tag set on packet received udp"); } if (packet.Tcp.Proxy != ProxyType.Server) { throw new Exception("From tag (" + netPacket.FromAddress.ToString() + ") set on packet not received from server (" + packet.Tcp.ToString() + ")"); } embedded.Source = new DhtContact(netPacket.FromAddress); } // to - received from proxied node, and not for us if (netPacket.ToAddress != null && !(netPacket.ToAddress.UserID == Local.UserID && netPacket.ToAddress.ClientID == Local.ClientID)) { if (packet.ReceivedUdp) { throw new Exception("To tag set on packet received udp"); } if (packet.Tcp.Proxy == ProxyType.Server || packet.Tcp.Proxy == ProxyType.Unset) { throw new Exception("To tag set on packet received from server"); } DhtAddress address = netPacket.ToAddress; netPacket.ToAddress = null; TcpConnect direct = TcpControl.GetProxy(address); if (direct != null) { direct.SendPacket(netPacket); } else { UdpControl.SendTo(address, netPacket); } return; } // process if (G2Protocol.ReadPacket(embedded.Root)) { ReceiveNetworkPacket(embedded); } } // Tunnel Packet else if (packet.Root.Name == RootPacket.Tunnel) { // can only tunnel over lookup network if (!IsLookup) { return; } PacketLogEntry logEntry = new PacketLogEntry(Core.TimeNow, TransportProtocol.Tunnel, DirectionType.In, packet.Source, packet.Root.Data); LogPacket(logEntry); TunnelPacket tunnel = TunnelPacket.Decode(packet.Root); // handle locally if (tunnel.Target.Equals(Local)) { Core.Context.Cores.LockReading(delegate() { foreach (OpCore core in Core.Context.Cores) { if (core.TunnelID == tunnel.Target.TunnelID) { core.Network.ReceiveTunnelPacket(packet, tunnel); } } }); } else if (tunnel.TargetServer != null) { TcpConnect direct = TcpControl.GetProxy(tunnel.Target); // if directly connected add from and forwared if (direct != null) { direct.SendPacket(tunnel); } // only forward udp if received over tcp from a proxied host else if (tunnel.TargetServer != null && packet.ReceivedTcp && packet.Tcp.Proxy != ProxyType.Server) { UdpControl.SendTo(tunnel.TargetServer, tunnel); } } } // Communication Packet else if (packet.Root.Name == RootPacket.Comm) { RudpPacket commPacket = RudpPacket.Decode(packet); // received direct packet.Source.UserID = commPacket.SenderID; packet.Source.ClientID = commPacket.SenderClient; // remote node is proxied if (commPacket.RemoteProxy != null) { packet.Source = new DhtContact(commPacket.RemoteProxy); } // For local host if (commPacket.TargetID == Local.UserID && commPacket.TargetClient == Local.ClientID) { ReceiveCommPacket(packet, commPacket); return; } // Also Forward to appropriate node TcpConnect socket = TcpControl.GetProxy(commPacket.TargetID, commPacket.TargetClient); if (socket != null) { // forward to proxied node - strip TO flag, add from address commPacket.ToAddress = null; commPacket.RemoteProxy = packet.Source; // if remote proxy is null, then we are setting this to the packet's original source socket.SendPacket(commPacket); return; } // received from a proxied node, forward udp if (packet.ReceivedTcp && commPacket.ToAddress != null) { DhtAddress target = commPacket.ToAddress; commPacket.ToAddress = null; // strip TO flag commPacket.RemoteProxy = new DhtAddress(Core.LocalIP, GetLocalSource()); UdpControl.SendTo(target, commPacket); } } }
void ManageRecvWindow() { bool dataReceived = false; lock (RecvPacketMap) { ArrayList removeList = new ArrayList(); foreach (byte seq in RecvPacketMap.Keys) { RudpPacket packet = RecvPacketMap[seq]; // deal with reading in order at 0xFF to zero boundry if (NextSeq > 0xFF - 25 && packet.Sequence < 25) { continue; } if (packet.Sequence != NextSeq) { break; } if (packet.PacketType == RudpPacketType.Syn) { ReceiveSyn(packet); } else if (packet.PacketType == RudpPacketType.Data) { // if local is closing connection, dump pending data so we can get to the fin packet and process it if (State != RudpState.Finishing) { dataReceived = true; break; } } else if (packet.PacketType == RudpPacketType.Fin) { ReceiveFin(packet); } HighestSeqRecvd = packet.Sequence; removeList.Add(packet.Sequence); NextSeq++; } foreach (byte seq in removeList) { RecvPacketMap.Remove(seq); } } // if data waiting to be read // dont let data receive if still connecting (getting ahead of ourselves) need successful ack return path before we recv data if (State == RudpState.Connected && (RecvBuffLength > 0 || dataReceived)) { Session.OnReceive(); } }
void ManageSendWindow() { ArrayList retransmit = new ArrayList(); int rtt = AvgLatency.GetAverage(); int outstanding = 0; lock (SendSection) { // iter through send window foreach (TrackPacket packet in SendPacketMap) { if (packet.Acked) { continue; } else if (packet.TimeSent == 0) { retransmit.Add(packet); } // connecting so must be a syn packet else if (State == RudpState.Connecting) { if (packet.TimeEllapsed(Core) > 1000 * 2) // dont combine with above cause then next else if would always run { retransmit.Add(packet); } } // send packets that havent been sent yet, and ones that need to be retransmitted else if (packet.TimeEllapsed(Core) > rtt * 2) { retransmit.Add(packet); } // mark as outstanding else { outstanding++; } } } // re-transmit packets foreach (TrackPacket track in retransmit) { if (outstanding < SendWindowSize) { //Session.Log("Re-Send ID " + track.Packet.PeerID.ToString() + // ", Type " + track.Packet.Type.ToString() + // ", Seq " + track.Packet.Sequence.ToString() + ", Retries " + track.Retries.ToString() + // ", Passed " + track.TimeEllapsed().ToString() + " ms"); track.Retries++; ReTransmits++; SendTracked(track); outstanding++; } else { break; } } lock (SendSection) { // send number of packets so that outstanding equals window size while (outstanding < SendWindowSize && SendBuffLength > 0 && SendPacketMap.Count < MAX_WINDOW_SIZE) { int buffLen = (SendBuffLength > CHUNK_SIZE) ? CHUNK_SIZE : SendBuffLength; RudpPacket data = new RudpPacket(); data.TargetID = Session.UserID; data.TargetClient = Session.ClientID; data.PeerID = RemotePeerID; data.PacketType = RudpPacketType.Data; data.Sequence = CurrentSeq++; data.Payload = Utilities.ExtractBytes(SendBuff, 0, buffLen); // move next data on deck for next send if (SendBuffLength > buffLen) { Buffer.BlockCopy(SendBuff, buffLen, SendBuff, 0, SendBuffLength - buffLen); } SendBuffLength -= buffLen; TrackPacket track = new TrackPacket(data); SendPacketMap.Enqueue(track); //Session.Log("Data Sent, Seq " + data.Sequence.ToString() + ", ID " + data.PeerID.ToString() + ", Size " + buffLen.ToString()); SendTracked(track); outstanding++; } } // if we can take more data call onsend if (SendBuffLength == 0 && RudpSendBlock) { //Session.Log("OnSend Called"); RudpSendBlock = false; Session.OnSend(); } }
public void ReceiveCommPacket(G2ReceivedPacket raw, RudpPacket packet) { try { if (packet.PacketType == RudpPacketType.Light || packet.PacketType == RudpPacketType.LightAck) { LightComm.ReceivePacket(raw, packet); return; } // if a socket already set up lock (RudpControl.SocketMap) if (RudpControl.SocketMap.ContainsKey(packet.PeerID)) { RudpControl.SocketMap[packet.PeerID].RudpReceive(raw, packet, IsLookup); return; } // if starting new session if (packet.PacketType != RudpPacketType.Syn) { return; } RudpSyn syn = new RudpSyn(packet.Payload); // prevent connection from self if (syn.SenderID == Local.UserID && syn.ClientID == Local.ClientID) { return; } // find connecting session with same or unknown client id ulong id = syn.SenderID ^ syn.ClientID; if (RudpControl.SessionMap.ContainsKey(id)) { RudpSession session = RudpControl.SessionMap[id]; // if session id zero or matches forward if ((session.Comm.State == RudpState.Connecting && session.Comm.RemotePeerID == 0) || (session.Comm.State != RudpState.Closed && session.Comm.RemotePeerID == syn.ConnID)) // duplicate syn { session.Comm.RudpReceive(raw, packet, IsLookup); return; } else if (session.Comm.State == RudpState.Finishing) { RudpControl.RemoveSession(session); // remove session, allow new one to be created } else { return; } } // if clientid not in session, create new session RudpSession newSession = new RudpSession(RudpControl, syn.SenderID, syn.ClientID, true); RudpControl.SessionMap[id] = newSession; // send ack before sending our own syn (connect) // ack tells remote which address is good so that our syn's ack comes back quickly newSession.Comm.RudpReceive(raw, packet, IsLookup); newSession.Connect(); UpdateLog("RUDP", "Inbound session accepted to ClientID " + syn.ClientID.ToString()); } catch (Exception ex) { UpdateLog("Exception", "DhtNetwork::ReceiveCommPacket: " + ex.Message); } }
public TrackPacket(RudpPacket packet) { Packet = packet; }
public int Receive(byte[] buff, int buffOffset, int buffLen) { if (RecvBuffLength > buffLen) { return(FinishReceive(buff, buffOffset, buffLen)); } lock (RecvPacketMap) { ArrayList removeList = new ArrayList(); // copy data from packets // while next element of map equals next in sequence foreach (byte seq in RecvPacketMap.Keys) // read keys because they are sorted { RudpPacket packet = RecvPacketMap[seq]; // deal with reading in order at 0xFF to zero boundry if (NextSeq > 0xFF - 25 && packet.Sequence < 25) { continue; } if (packet.Sequence != NextSeq) { break; } if (packet.PacketType == RudpPacketType.Data) { int dataSize = packet.Payload.Length; if (dataSize > MAX_CHUNK_SIZE) { Session.Log("Too Large Packet Received Size " + packet.Payload.Length + ", Type Data"); RudpClose(CloseReason.LARGE_PACKET); return(-1); } // copy data packet.Payload.CopyTo(RecvBuff, RecvBuffLength); RecvBuffLength += packet.Payload.Length; //Session.Log("Data Recv, Seq " + packet.Sequence.ToString() + ", ID " + packet.PeerID.ToString()); } else { break; } HighestSeqRecvd = packet.Sequence; removeList.Add(packet.Sequence); NextSeq++; if (RecvBuffLength > buffLen) { break; } } foreach (byte seq in removeList) { RecvPacketMap.Remove(seq); } } //Log("Reliable Receive " + NumtoStr(copysize) + ", " + NumtoStr(m_RecvBuffLength) + " left"); return(FinishReceive(buff, buffOffset, buffLen)); }
public void RudpReceive(G2ReceivedPacket raw, RudpPacket packet, bool global) { // check if packet meant for another socket if (packet.PeerID != 0 && packet.PeerID != PeerID) { return; } // check for errors string error = null; if (packet.Sequence > HighestSeqRecvd && State == RudpState.Closed) // accept only packets that came before the fin { error = "Packet Received while in Close State ID " + packet.PeerID.ToString() + ", Type " + packet.PacketType.ToString(); } else if (packet.Payload.Length > 4096) { error = "Too Large Packet Received Size " + packet.Payload.Length.ToString() + ", Type " + packet.PacketType.ToString(); RudpClose(CloseReason.LARGE_PACKET); } if (error != null) { Session.Log(error); return; } Bandwidth.InPerSec += raw.Root.Data.Length; // add proxied and direct addresses // proxied first because that packet has highest chance of being received, no need for retry // also allows quick udp hole punching if (raw.ReceivedTcp) { AddAddress(new RudpAddress(raw.Source, raw.Tcp)); } AddAddress(new RudpAddress(raw.Source)); // either direct node, or node's proxy // received syn, ident 5, from 1001 over tcp /*string log = "Received " + packet.PacketType.ToString(); * if (packet.Ident != 0) log += " ID:" + packet.Ident.ToString(); * log += " from " + raw.Source.ToString(); * * if (raw.Tcp != null) * log += " tcp"; * else * log += " udp"; * Session.Log(log);*/ if (packet.PacketType == RudpPacketType.Unreliable) { Session.UnreliableReceive(packet.Payload); return; } // try to clear up bufffer, helps if full, better than calling this on each return statement ManageRecvWindow(); // if ACK, PING, or PONG if (packet.PacketType == RudpPacketType.Ack || packet.PacketType == RudpPacketType.Ping || packet.PacketType == RudpPacketType.Pong) { if (packet.PacketType == RudpPacketType.Ack) { ReceiveAck(packet); } if (packet.PacketType == RudpPacketType.Ping) { ReceivePing(packet); } if (packet.PacketType == RudpPacketType.Pong) { ReceivePong(packet); } return; } // if SYN, DATA or FIN packet // stop acking so remote host catches up if (packet.Sequence > HighestSeqRecvd + MAX_WINDOW_SIZE || RecvPacketMap.Count > MAX_WINDOW_SIZE) { //Session.Log("Error Packet Overflow"); return; } // Send Ack - cant combine if statements doesnt work if (AckMap.Contains(packet.Sequence)) { //Session.Log("Error Packet Seq " + packet.Sequence.ToString() + " Already Received"); SendAck(packet); return; } // insert into recv map lock (RecvPacketMap) { RecvPacketMap[packet.Sequence] = packet; } ManageRecvWindow(); // ack down here so highest received is iterated, syns send own acks if (packet.PacketType != RudpPacketType.Syn) { SendAck(packet); } }
void ReceiveAck(RudpPacket packet) { int latency = 0; int retries = -1; // find original packet that was sent TrackPacket sent = null; lock (SendSection) { foreach (TrackPacket tracked in SendPacketMap) { if (tracked.Packet.Sequence == packet.Sequence) { sent = tracked; break; } } } // mark packet as acked if (sent != null) { sent.Target.LastAck = Core.TimeNow; // connect handshake if (State == RudpState.Connecting && sent.Packet.PacketType == RudpPacketType.Syn) { SynAckReceieved = true; SetPrimaryAddress(packet.Ident); if (SynAckSent && SynAckReceieved) { Session.Log("Connected (recv ack)"); ChangeState(RudpState.Connected); SetConnected(); // if data packets received before final connection ack, process them now ManageRecvWindow(); } } if (!sent.Acked) { InOrderAcks++; if (sent.Retries == 0) { latency = (int)sent.TimeEllapsed(Core); latency = latency < 5 ? 5 : latency; AvgLatency.Input(latency); AvgLatency.Next(); } } retries = sent.Retries; sent.Acked = true; } RudpAck ack = new RudpAck(packet.Payload); //Session.Log("Ack Recv, Seq " + packet.Sequence.ToString() + ", ID " + packet.PeerID.ToString() + ", highest " + ack.Start.ToString() + ", retries " + retries.ToString() + ", latency " + latency.ToString()); lock (SendSection) { // ack possibly un-acked packets foreach (TrackPacket tracked in SendPacketMap) { // ack if start past the zero boundry with sequences behind if (tracked.Packet.Sequence > 0xFF - 25 && ack.Start < 25) { tracked.Acked = true; } // break start before boundry and sequences ahead are not recvd/acked yet if (ack.Start > 0xFF - 25 && tracked.Packet.Sequence < 25) { break; } // normal acking procedure else if (ack.Start >= tracked.Packet.Sequence) { tracked.Acked = true; } else { break; } } // remove acked, only remove packets from front while (SendPacketMap.Count > 0 && SendPacketMap.Peek().Acked) { // calculate receive speed of remote host by rate they ack AvgBytesSent.Input(SendPacketMap.Peek().Packet.Payload.Length); SendPacketMap.Dequeue(); PacketsCompleted++; } } // increase window if packets removed from beginning of buffer //if(packetsRemoved && SendWindowSize < 25) // SendWindowSize++; ManageSendWindow(); }