예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
        }