private void Receive_Patch(DhtAddress source, byte[] data) { // invoke patch G2Header root = new G2Header(data); if (G2Protocol.ReadPacket(root)) { if (root.Name == StorePacket.Patch) { PatchPacket packet = PatchPacket.Decode(root); if (packet == null) { return; } foreach (PatchTag patch in packet.PatchData) { if (PatchEvent.Contains(patch.Service, patch.DataType)) { PatchEvent[patch.Service, patch.DataType].Invoke(source, patch.Tag); } } } } }
void InvokeTags(ulong user, ServiceData data) { foreach (PatchTag tag in data.Tags) { if (TagReceived.Contains(tag.Service, tag.DataType)) { TagReceived[tag.Service, tag.DataType].Invoke(user, tag.Tag); } } }
public void Receive_StoreReq(G2ReceivedPacket packet) { StoreReq store = StoreReq.Decode(packet); if (Core.ServiceBandwidth.ContainsKey(store.Service)) { Core.ServiceBandwidth[store.Service].InPerSec += packet.Root.Data.Length; } if (store.Source.Firewall == FirewallType.Open) { // dont need to add to routing if nat/blocked because eventual routing ping by server will auto add Network.Routing.Add(new DhtContact(store.Source, packet.Source.IP)); } // forward to proxied nodes - only replicate data to blocked nodes on operation network if (!Network.IsLookup) { // when we go offline it will be these nodes that update their next proxy with stored info foreach (TcpConnect socket in Network.TcpControl.ProxyClients) { if (packet.Tcp != socket) { if (packet.ReceivedUdp) { store.FromAddress = packet.Source; } socket.SendPacket(store); } } } // pass to components DataReq data = new DataReq(packet.Source, store.Key, store.Service, store.DataType, store.Data); if (packet.ReceivedTcp && packet.Tcp.Proxy == ProxyType.Server) { data.LocalProxy = new DhtClient(packet.Tcp); } if (data.Service == 0) { Receive_Patch(packet.Source, store.Data); } else if (StoreEvent.Contains(store.Service, store.DataType)) { StoreEvent[store.Service, store.DataType].Invoke(data); } }
/*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 ReceiveRequest(G2ReceivedPacket packet) { SearchReq request = SearchReq.Decode(packet); // loopback if (Network.Local.Equals(request.Source)) { return; } if (Core.ServiceBandwidth.ContainsKey(request.Service)) { Core.ServiceBandwidth[request.Service].InPerSec += packet.Root.Data.Length; } if (packet.ReceivedTcp && request.SearchID != 0) { // request from blocked node if (packet.Tcp.Proxy == ProxyType.ClientBlocked) { int proxySearches = 0; lock (Active) foreach (DhtSearch search in Active) { if (search.ProxyTcp == packet.Tcp) { proxySearches++; if (request.EndProxySearch && search.SearchID == request.SearchID) { search.FinishSearch("Proxied node finished search"); return; } } } if (proxySearches < MAX_SEARCHES) { DhtSearch search = new DhtSearch(this, request.TargetID, "Proxy", request.Service, request.DataType); search.Parameters = request.Parameters; search.ProxyTcp = packet.Tcp; search.SearchID = request.SearchID; search.Activate(); Active.Add(search); search.Log("Active - Proxy Search"); } // continue processing request and send local results } // request from proxy server if (packet.Tcp.Proxy == ProxyType.Server && request.EndProxySearch) { lock (Active) foreach (DhtSearch search in Active) { if (search.SearchID == request.SearchID) { if (!search.Finished) { search.FinishSearch("Server finished search"); } } } } } if (request.Source.Firewall == FirewallType.Open) { Routing.Add(new DhtContact(request.Source, packet.Source.IP)); } // forward to proxied nodes foreach (TcpConnect socket in Network.TcpControl.ProxyClients) { // prevents incoming udp from proxy and being forwarded to same host tcp if (socket != packet.Tcp && !(packet.Source.UserID == socket.UserID && packet.Source.ClientID == socket.ClientID)) { request.FromAddress = packet.Source; socket.SendPacket(request); } } // send ack bool sendNoResults = (request.SearchID != 0 || request.Service == Core.DhtServiceID) && (packet.ReceivedUdp || packet.Tunneled); SearchAck ack = new SearchAck(); ack.Source = Network.GetLocalSource(); ack.SearchID = request.SearchID; ack.Service = request.Service; // search for connected proxy if (Network.TcpControl.ProxyMap.Values.Any(p => p.UserID == request.TargetID)) { ack.Proxied = true; } // only send nodes from proxy server routing table if (request.Nodes && (packet.ReceivedUdp || packet.Tunneled)) { ack.ContactList = Routing.Find(request.TargetID, 8); } // dont send an ack if behind a proxy server and no results if (!SearchEvent.Contains(request.Service, request.DataType)) { if (sendNoResults) { SendAck(packet, request, ack); } } else { List <byte[]> results = new List <byte[]>(); SearchEvent[request.Service, request.DataType].Invoke(request.TargetID, request.Parameters, results); // if nothing found, still send ack with closer contacts if (results == null || results.Count == 0) { if (sendNoResults) { SendAck(packet, request, ack); } return; } // if a direct search if (request.SearchID == 0) { foreach (byte[] value in results) { Network.Store.Send_StoreReq(packet.Source, packet.Tcp, new DataReq(null, request.TargetID, request.Service, request.DataType, value)); } return; } // else send normal search results int totalSize = 0; foreach (byte[] data in results) { if (data.Length + totalSize > 1200) { SendAck(packet, request, ack); ack.ValueList.Clear(); ack.ContactList.Clear(); // dont send twice totalSize = 0; } ack.ValueList.Add(data); totalSize += data.Length; } if (totalSize > 0) { SendAck(packet, request, ack); } } }
private void Process_LocationData(DataReq data, SignedData signed, LocationData location) { Core.IndexKey(location.UserID, ref location.Key); Debug.Assert(location.UserID == location.Source.UserID); if (location.UserID != location.Source.UserID) { return; } ClientInfo client = GetLocationInfo(location.UserID, location.Source.ClientID); // check location version if (client != null) { if (location.Version == client.Data.Version) { return; } else if (location.Version < client.Data.Version) { if (data != null && data.Source != null) { Network.Store.Send_StoreReq(data.Source, data.LocalProxy, new DataReq(null, client.Data.UserID, ServiceID, 0, client.SignedData)); } return; } } Core.IndexName(location.UserID, location.Name); // notify components of new versions (usually just localsync service signed up for this) DhtAddress address = new DhtAddress(location.IP, location.Source); foreach (PatchTag tag in location.Tags) { if (TagReceived.Contains(tag.Service, tag.DataType)) { TagReceived[tag.Service, tag.DataType].Invoke(address, location.UserID, tag.Tag); } } // add location if (client == null) { // if too many clients, and not us, return if (location.UserID != Core.UserID && ActiveClientCount(location.UserID) > MaxClientsperUser) { return; } client = new ClientInfo(location); Clients.SafeAdd(client.RoutingID, client); // dont need to worry about remote caching old locs indefinitely because if a loc is cached remotely // that means the remote is being continuall pinged, or else the loc would expire // if we're still interested in loc after a min, it will be pinged locally } client.Data = location; client.SignedData = signed.Encode(Network.Protocol); if (client.Data.UserID == Core.UserID && client.Data.Source.ClientID == Network.Local.ClientID) { LocalClient = client; } AddRoutingData(location); // only get down here if loc was new version in first place (recently published) // with live comm trickle down this prevents highers from being direct ping flooded to find their // online status client.LastSeen = Core.TimeNow; SignalUpdate(client, true); }