/// <summary> /// Scan the client machine for services such as HTTP or samba shares /// </summary> /// <param name="n"></param> private void ScanClient(Node n) { //Check for HTTP string webTitle = string.Empty; try { var wc = new WebClient(); string html = wc.DownloadString("http://" + n.Host); if (!string.IsNullOrEmpty(html)) { webTitle = RegexEx.FindMatches("<title>.*</title>", html).FirstOrDefault(); if (null != webTitle && !string.IsNullOrEmpty(html) && webTitle.Length > 14) { webTitle = webTitle.Substring(7); webTitle = webTitle.Substring(0, webTitle.Length - 8); } } if (string.IsNullOrEmpty(webTitle)) webTitle = "Web"; } catch { } //Check for FTP string ftp = string.Empty; try { var client = new TcpClient(); client.Connect(n.Host, 21); ftp = "FTP"; var sb = new StringBuilder(); long start = Environment.TickCount + 3000; var data = new byte[20000]; client.ReceiveBufferSize = data.Length; while (start > Environment.TickCount && client.Connected) { if (client.GetStream().DataAvailable) { int length = client.GetStream().Read(data, 0, data.Length); sb.Append(Encoding.ASCII.GetString(data, 0, length)); } else { Thread.Sleep(50); } } client.Close(); string title = sb.ToString(); if (!string.IsNullOrEmpty(title)) ftp = title; data = null; } catch { } //Check for samba shares string samba = string.Empty; try { ShareCollection shares = ShareCollection.GetShares(n.Host); var sb = new StringBuilder(); foreach (SambaShare share in shares) { if (share.IsFileSystem && share.ShareType == ShareType.Disk) { try { //Make sure its readable DirectoryInfo[] Flds = share.Root.GetDirectories(); if (sb.Length > 0) sb.Append("|"); sb.Append(share.NetName); } catch { } } } samba = sb.ToString(); } catch { } lock (sync) { //update clients and overlords var r = new Node(); r.SetData("HTTP", webTitle.Replace("\n", "").Replace("\r", "")); r.SetData("FTP", ftp.Replace("\n", "").Replace("\r", "")); r.SetData("Shares", samba.Replace("\n", "").Replace("\r", "")); r.ID = n.ID; r.OverlordID = serverNode.ID; lock (sync) { //Check the client is still connected.. if (connectedClientNodes.Where(nx => nx.Node.ID == r.ID).Count() > 0) { var verb = new UpdateVerb(); verb.Nodes.Add(r); NetworkRequest req = verb.CreateRequest(); req.OverlordID = serverNode.ID; SendToStandardClients(req); //Dont updates about overlords to other overlords if (n.NodeType != ClientType.Overlord) SendToOverlordClients(req); } } //Store info n.SetData("HTTP", webTitle.Replace("\n", "").Replace("\r", "")); n.SetData("FTP", ftp.Replace("\n", "").Replace("\r", "")); n.SetData("Shares", samba.Replace("\n", "").Replace("\r", "")); } }
private void c_OnDisconnect(ClientStream s) { try { lock (sync) { if (connectedClientNodes.Contains(s)) { //Check it is actually the same node // var search = connectedClientNodes.Where(n => n.Node.ID == s.Node.ID && s.Node.Secret == s.Node.Secret).FirstOrDefault(); // if (null == search) { logger.Debug("Server dropped client {0}", s.Node.ID); connectedClientNodes.Remove(s); s.OnDisconnect -= c_OnDisconnect; var info = new UpdateVerb(); info.Nodes.Add(new Node {ID = s.Node.ID, Online = false}); NetworkRequest req = info.CreateRequest(); req.OverlordID = serverNode.ID; req.SourceID = serverNode.ID; SendToOverlordClients(req); SendToStandardClients(req); } } } } catch { } }
/// <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; }
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; }
private void uplink_OnDisconnect(Uplink s) { //A remote overlord has disconnected, notify local clients of all associated peering going offline. lock (sync) { logger.Debug("Server had uplink disconnect to {0}", s.Destination.ID); extOverlordServers.Remove(s); var verb = new UpdateVerb(); foreach (Node node in externalNodes.ToList()) { if (node.OverlordID == s.Destination.ID || node.ID == s.Destination.ID) { //Check the node isnt now logged on locally if (connectedClientNodes.Where(n => n.Node.ID == node.ID).Count() > 0) continue; verb.Nodes.Add(new Node {ID = node.ID, Online = false}); } externalNodes.Remove(node); } verb.Nodes.Add(new Node {ID = s.Destination.ID, Online = false}); NetworkRequest req = verb.CreateRequest(); req.OverlordID = serverNode.ID; SendToStandardClients(req); //Remove the overlord itself if (extOverlordServers.Contains(s)) { extOverlordServers.Remove(s); } } }