private bool HandleConnect(NetworkRequest r, RequestEventArgs e) { string address = string.Empty; try { var iv = new ConnectVerb(); iv.ProcessRequest(r); address = iv.Address; if (string.IsNullOrEmpty(iv.Secret)) { //Dont allow connections with no secret return(false); } //Dont allow connections to ourselves.. if (iv.Address == serverNode.Location) { return(false); } //Only allow one connect attempt at once lock (sync) { if (connectingIDs.Contains(address)) { return(false); } connectingIDs.Add(address); } //Connect to the remote client var verb = new InfoVerb(); var client = new Client(serverNode); if (!client.Execute(verb, address)) { return(false); } //Connected ok var c = new ClientStream(); c.OnDisconnect += c_OnDisconnect; Node n = verb.GetValidatedNode(); if (null == n) { return(false); } n.Location = iv.Address; n.Online = true; n.NodeType = iv.ClientType; n.OverlordID = serverNode.ID; n.Secret = iv.Secret; lock (sync) { //Notify other clients var update = new UpdateVerb(); //Was this person already connected? ClientStream search = connectedClientNodes.Where(xn => xn.Node.ID == n.ID).FirstOrDefault(); if (null != search) { connectedClientNodes.Remove(search); search.Kill(); } c.Start(n, serverNode); connectedClientNodes.Add(c); update.Nodes.Add(n); NetworkRequest req = update.CreateRequest(); req.SourceID = serverNode.ID; req.OverlordID = serverNode.ID; req.AuthKey = iv.Secret; SendToStandardClients(req); //Dont send overlord logs to other overlords if (n.NodeType != ClientType.Overlord) { SendToOverlordClients(req); } } //Find client servers ThreadPool.QueueUserWorkItem(ScanClientAsync, n); //return ok //Add headers var headers = e.Response.Headers as HeaderCollection; if (null != headers) { headers.Add("FAP-AUTH", iv.Secret); headers.Add("FAP-SOURCE", serverNode.ID); headers.Add("FAP-OVERLORD", serverNode.ID); } SendResponse(e, null); //Send network info if (n.NodeType == ClientType.Overlord) { var update = new UpdateVerb(); //Only send local nodes foreach ( ClientStream peer in connectedClientNodes.ToList().Where(x => x.Node.NodeType == ClientType.Client)) { update.Nodes.Add(peer.Node); } NetworkRequest req = update.CreateRequest(); req.SourceID = serverNode.ID; req.OverlordID = serverNode.ID; req.AuthKey = iv.Secret; c.AddMessage(req); } else { var update = new UpdateVerb(); //None overlord client. Send local nodes and external ones. update.Nodes = GetBestKnownClientList(); NetworkRequest req = update.CreateRequest(); req.SourceID = serverNode.ID; req.OverlordID = serverNode.ID; req.AuthKey = iv.Secret; c.AddMessage(req); } return(true); } catch { } finally { connectingIDs.Remove(address); } SendError(e); return(false); }
/// <summary> /// Handle updates from local clients, external overlords and peers on external overlords from their overlord. /// </summary> /// <param name="e"></param> /// <param name="req"></param> /// <returns></returns> private bool HandleUpdate(RequestEventArgs e, NetworkRequest req) { try { var verb = new UpdateVerb(); verb.ProcessRequest(req); //Ignore updates about ourself if (verb.Nodes != null && verb.Nodes.Count == 1 && verb.Nodes[0].ID == serverNode.ID) { SendResponse(e, null); return(true); } //Is the call from a local client? ClientStream localClient = connectedClientNodes.ToList().Where( n => n.Node.ID == req.SourceID && n.Node.Secret == req.AuthKey && n.Node.NodeType != ClientType.Overlord).FirstOrDefault(); if (null != localClient) { //Only allow updates about itself Node client = verb.Nodes.Where(n => n.ID == localClient.Node.ID).FirstOrDefault(); if (null != client && verb.Nodes.Count == 1) { logger.Trace("Server got update from local client {0}", client.ID); lock (sync) { //Copy to local store foreach (var value in verb.Nodes[0].Data) { localClient.Node.SetData(value.Key, value.Value); } req.OverlordID = serverNode.ID; //Retransmit SendToOverlordClients(req); SendToStandardClients(req); //Has the client disconnected? if (!localClient.Node.Online) { localClient.Kill(); connectedClientNodes.Remove(localClient); } } SendResponse(e, null); return(true); } } else { //Is the update from an external overlord? Uplink overlord = extOverlordServers.ToList().Where( n => n.Destination.ID == req.OverlordID && n.Destination.Secret == req.AuthKey && n.Destination.NodeType == ClientType.Overlord).FirstOrDefault(); if (null != overlord) { logger.Trace("Server got update from external overlord {0}", overlord.Destination.ID); //Check each update var nverb = new UpdateVerb(); foreach (Node update in verb.Nodes) { if (!string.IsNullOrEmpty(update.ID)) { //Ignore updates about ourself if (update.ID == serverNode.ID) { continue; } lock (sync) { //Is the update about the overlord itself? Uplink osearch = extOverlordServers.Where( o => o.Destination.ID == update.ID && o.Destination.Secret == req.AuthKey). FirstOrDefault(); if (null != osearch) { logger.Trace("Server got update from external about itself: {0}", osearch.Destination.ID); //Copy to local store foreach (var value in update.Data) { osearch.Destination.SetData(value.Key, value.Value); } //Retransmit changes nverb.Nodes.Add(update); //Overlord going offline if (!osearch.Destination.Online) { osearch.OnDisconnect -= uplink_OnDisconnect; osearch.Kill(); //Remove associated external nodes foreach (Node enode in externalNodes.ToList()) { if (enode.OverlordID == osearch.Destination.OverlordID) { externalNodes.Remove(enode); //Only signal disconnect is the node isnt a local node //I.e. they connected locally without disconnecting externally. ClientStream search = connectedClientNodes.Where(n => n.Node.ID == enode.ID). FirstOrDefault(); if (null == search) { //The node isn't connected locally, is it connected elsewhere externally? Node bestExternal = externalNodes.ToList().Where(n => n.ID == enode.ID). OrderByDescending(n => n.LastUpdate).FirstOrDefault(); if (null != bestExternal) { //User has logged on elsewhere, update local clients of new details nverb.Nodes.Add(bestExternal); } else { nverb.Nodes.Add(new Node { ID = enode.ID, Online = false }); } } } } } } else { logger.Trace("Server got update from external server about : {0}", update.ID); //Check to see if the external node is connected locally, if so then dont retransmit changes but store changes under the relevant object ClientStream localNode = connectedClientNodes.Where(n => n.Node.ID == update.ID).FirstOrDefault(); //Update about an external node from an external overlord Node search = externalNodes.Where(n => n.ID == update.ID && n.OverlordID == req.OverlordID) .FirstOrDefault(); if (null == search) { if (!string.IsNullOrEmpty(update.ID)) { //New external node search = new Node(); //Copy to local store foreach (var value in update.Data) { search.SetData(value.Key, value.Value); } search.OverlordID = req.OverlordID; externalNodes.Add(search); //Dont retransmit external node as it is local if (null == localNode) { nverb.Nodes.Add(update); } } } else { //Copy to local store foreach (var value in update.Data) { search.SetData(value.Key, value.Value); } //Has the external node changed to a different overlord? if (search.OverlordID != req.OverlordID) { search.OverlordID = req.OverlordID; update.OverlordID = req.OverlordID; } //Dont retransmit external node as it is local if (null == localNode) { //Retransmit changes nverb.Nodes.Add(update); } } } } } } //Only transmit external node info to local clients if (nverb.Nodes.Count > 0) { NetworkRequest nreq = nverb.CreateRequest(); nreq.OverlordID = req.OverlordID; SendToStandardClients(nreq); } SendResponse(e, null); return(true); } } } catch { } logger.Debug("Server received an invalid update"); SendError(e); return(false); }