public static RudpPacket Decode(G2Header root) { RudpPacket gc = new RudpPacket(); if (G2Protocol.ReadPayload(root)) { gc.Payload = Utilities.ExtractBytes(root.Data, root.PayloadPos, root.PayloadSize); } G2Protocol.ResetPacket(root); G2Header child = new G2Header(root.Data); while (G2Protocol.ReadNextChild(root, child) == G2ReadResult.PACKET_GOOD) { if (!G2Protocol.ReadPayload(child)) { continue; } switch (child.Name) { case Packet_SenderDht: gc.SenderID = BitConverter.ToUInt64(child.Data, child.PayloadPos); break; case Packet_SenderClient: gc.SenderClient = BitConverter.ToUInt16(child.Data, child.PayloadPos); break; case Packet_TargetDht: gc.TargetID = BitConverter.ToUInt64(child.Data, child.PayloadPos); break; case Packet_TargetClient: gc.TargetClient = BitConverter.ToUInt16(child.Data, child.PayloadPos); break; case Packet_Type: gc.PacketType = child.Data[child.PayloadPos]; break; case Packet_ID: gc.PeerID = BitConverter.ToUInt16(child.Data, child.PayloadPos); break; case Packet_Seq: gc.Sequence = (byte)child.Data[child.PayloadPos]; break; case Packet_Ident: gc.Ident = BitConverter.ToUInt32(child.Data, child.PayloadPos); break; case Packet_To: gc.ToAddress = DhtAddress.ReadPacket(child); break; case Packet_Proxy: gc.RemoteProxy = DhtAddress.ReadPacket(child); break; } } return(gc); }
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 static RudpPacket Decode(G2Header root) { RudpPacket gc = new RudpPacket(); if( G2Protocol.ReadPayload(root) ) gc.Payload = Utilities.ExtractBytes(root.Data, root.PayloadPos, root.PayloadSize); G2Protocol.ResetPacket(root); G2Header child = new G2Header(root.Data); while( G2Protocol.ReadNextChild(root, child) == G2ReadResult.PACKET_GOOD ) { if (!G2Protocol.ReadPayload(child)) continue; switch (child.Name) { case Packet_SenderDht: gc.SenderID = BitConverter.ToUInt64(child.Data, child.PayloadPos); break; case Packet_SenderClient: gc.SenderClient = BitConverter.ToUInt16(child.Data, child.PayloadPos); break; case Packet_TargetDht: gc.TargetID = BitConverter.ToUInt64(child.Data, child.PayloadPos); break; case Packet_TargetClient: gc.TargetClient = BitConverter.ToUInt16(child.Data, child.PayloadPos); break; case Packet_Type: gc.PacketType = child.Data[child.PayloadPos]; break; case Packet_ID: gc.PeerID = BitConverter.ToUInt16(child.Data, child.PayloadPos); break; case Packet_Seq: gc.Sequence = (byte)child.Data[child.PayloadPos]; break; case Packet_Ident: gc.Ident = BitConverter.ToUInt32(child.Data, child.PayloadPos); break; case Packet_To: gc.ToAddress = DhtAddress.ReadPacket(child); break; case Packet_Proxy: gc.RemoteProxy = DhtAddress.ReadPacket(child); break; } } return gc; }
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 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(); }
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 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) ); }
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 ReceivePong(RudpPacket pong) { if (pong.Payload != null) { uint ident = BitConverter.ToUInt32(pong.Payload, 0); SetPrimaryAddress(ident); } }
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(); }
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); }
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 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); }
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); }
public TrackPacket(RudpPacket packet) { Packet = packet; }
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 }