public override void ConnectClients() { base.ConnectClients(); Assert.AreEqual(XmppState.Connected, this.client1.State); Assert.AreEqual(XmppState.Connected, this.client2.State); this.synchronizationClient1 = new SynchronizationClient(this.client1); this.synchronizationClient2 = new SynchronizationClient(this.client2); }
/// <summary> /// Adds the extension to the client. /// </summary> /// <param name="Instance">Actor instance.</param> /// <param name="Client">XMPP Client</param> public override Task Add(IActor Instance, Waher.Networking.XMPP.XmppClient Client) { SynchronizationClient Extension = new SynchronizationClient(Client); Client.SetTag("SynchronizationClient", Extension); Extension.OnUpdated += (Sender, e) => { this.Model.ExternalEvent(Instance, "OnUpdated", new KeyValuePair <string, object>("e", e), new KeyValuePair <string, object>("Client", Client)); }; return(Task.CompletedTask); }
public override void DisposeClients() { if (this.synchronizationClient2 != null) { this.synchronizationClient2.Dispose(); this.synchronizationClient2 = null; } if (this.synchronizationClient1 != null) { this.synchronizationClient1.Dispose(); this.synchronizationClient1 = null; } base.DisposeClients(); }
/// <summary> /// Analyzes the difference between the clock on the local machine with the clock on /// another machine, connected to the XMPP network, and compatible with the IEEE /// XMPP IoT extensions. /// /// Command line switches: /// /// -h HOST XMPP Server host name. /// -p PORT XMPP Port number, if different from 5222 /// -a ACCOUNT XMPP Account name to use when connecting to the server. /// -pwd PASSWORD PASSWORD to use when authenticating with the server. /// -i INTERVAL Interval (in milliseconds) used to check clocks. /// -j JID JID of clock source to monitor. /// Default=5000. /// -r RECORDS Number of measurements to collect. /// -n HISTORY Number of records in history. Averages are calculated /// on records in this history. Default=100 /// -w WINDOW Filter window size. The window is used to detect /// and eliminate bad measurements. Default=16 /// -s SPIKE_POS Spike position. Where spikes are detected, in /// window. Default=6 /// -sw SPIKE_WIDTH Spike width. Number of measurements in a row that can /// constitute a spike. Default=3 /// -o OUTPUT_FILE File name of report file. /// -enc ENCODING Text encoding. Default=UTF-8 /// -t TRANSFORM_FILE XSLT transform to use. /// -? Help. /// </summary> static int Main(string[] args) { try { Encoding Encoding = Encoding.UTF8; string OutputFileName = null; string XsltPath = null; string Host = null; string Account = null; string Password = null; string Jid = null; string s; int Port = 5222; int Records = 0; int Interval = 5000; int History = 100; int Window = 16; int SpikePos = 6; int SpikeWidth = 3; int i = 0; int c = args.Length; bool Help = false; while (i < c) { s = args[i++].ToLower(); switch (s) { case "-o": if (i >= c) { throw new Exception("Missing output file name."); } if (string.IsNullOrEmpty(OutputFileName)) { OutputFileName = args[i++]; } else { throw new Exception("Only one output file name allowed."); } break; case "-h": if (i >= c) { throw new Exception("Missing host name."); } if (string.IsNullOrEmpty(Host)) { Host = args[i++]; } else { throw new Exception("Only one host name allowed."); } break; case "-p": if (i >= c) { throw new Exception("Missing port number."); } if (!int.TryParse(args[i++], out Port) || Port <= 0 || Port > 65535) { throw new Exception("Invalid port number."); } break; case "-j": if (i >= c) { throw new Exception("Missing JID."); } if (string.IsNullOrEmpty(Jid)) { Jid = args[i++]; } else { throw new Exception("Only one JID allowed."); } break; case "-i": if (i >= c) { throw new Exception("Missing interval."); } if (!int.TryParse(args[i++], out Interval) || Interval < 1000) { throw new Exception("Invalid interval."); } break; case "-r": if (i >= c) { throw new Exception("Missing number of records to collect."); } if (!int.TryParse(args[i++], out Records) || Records <= 0) { throw new Exception("Invalid number of records to collect."); } break; case "-n": if (i >= c) { throw new Exception("Missing number of history records."); } if (!int.TryParse(args[i++], out History) || History <= 0) { throw new Exception("Invalid number of history records."); } break; case "-w": if (i >= c) { throw new Exception("Missing window size."); } if (!int.TryParse(args[i++], out Window) || Window <= 0) { throw new Exception("Invalid window size."); } break; case "-s": if (i >= c) { throw new Exception("Missing spike position."); } if (!int.TryParse(args[i++], out SpikePos) || SpikePos <= 0) { throw new Exception("Invalid spike position."); } break; case "-sw": if (i >= c) { throw new Exception("Missing spike width."); } if (!int.TryParse(args[i++], out SpikeWidth) || SpikeWidth <= 0) { throw new Exception("Invalid spike width."); } break; case "-a": if (i >= c) { throw new Exception("Missing account name."); } if (string.IsNullOrEmpty(Account)) { Account = args[i++]; } else { throw new Exception("Only one account name allowed."); } break; case "-pwd": if (i >= c) { throw new Exception("Missing password."); } if (string.IsNullOrEmpty(Password)) { Password = args[i++]; } else { throw new Exception("Only one password allowed."); } break; case "-enc": if (i >= c) { throw new Exception("Text encoding missing."); } Encoding = Encoding.GetEncoding(args[i++]); break; case "-t": if (i >= c) { throw new Exception("XSLT transform missing."); } XsltPath = args[i++]; break; case "-?": Help = true; break; default: throw new Exception("Unrecognized switch: " + s); } } if (Help || c == 0) { Console.Out.WriteLine("Analyzes the difference between the clock on the local machine with the clock on"); Console.Out.WriteLine("another machine, connected to the XMPP network, and compatible with the IEEE"); Console.Out.WriteLine("XMPP IoT extensions."); Console.Out.WriteLine(); Console.Out.WriteLine("Command line switches:"); Console.Out.WriteLine(); Console.Out.WriteLine("-h HOST XMPP Server host name."); Console.Out.WriteLine("-p PORT XMPP Port number, if different from 5222"); Console.Out.WriteLine("-a ACCOUNT XMPP Account name to use when connecting to the server."); Console.Out.WriteLine("-pwd PASSWORD PASSWORD to use when authenticating with the server."); Console.Out.WriteLine("-j JID JID of clock source to monitor."); Console.Out.WriteLine("-i INTERVAL Interval (in milliseconds) used to check clocks."); Console.Out.WriteLine(" Default=5000."); Console.Out.WriteLine("-r RECORDS Number of measurements to collect."); Console.Out.WriteLine("-n HISTORY Number of records in history. Averages are calculated"); Console.Out.WriteLine(" on records in this history. Default=100"); Console.Out.WriteLine("-w WINDOW Filter window size. The window is used to detect"); Console.Out.WriteLine(" and eliminate bad measurements. Default=16"); Console.Out.WriteLine("-s SPIKE_POS Spike position. Where spikes are detected, in"); Console.Out.WriteLine(" window. Default=6"); Console.Out.WriteLine("-sw SPIKE_WIDTH Spike width. Number of measurements in a row that can"); Console.Out.WriteLine(" constitute a spike. Default=3"); Console.Out.WriteLine("-o OUTPUT_FILE File name of report file."); Console.Out.WriteLine("-enc ENCODING Text encoding. Default=UTF-8"); Console.Out.WriteLine("-t TRANSFORM_FILE XSLT transform to use."); Console.Out.WriteLine("-? Help."); return(0); } if (string.IsNullOrEmpty(Host)) { throw new Exception("No host name specified."); } if (string.IsNullOrEmpty(Account)) { throw new Exception("No account name specified."); } if (string.IsNullOrEmpty(Password)) { throw new Exception("No password specified."); } if (string.IsNullOrEmpty(Jid)) { throw new Exception("No clock source JID specified."); } if (Records <= 0) { throw new Exception("Number of records to collect not specified."); } if (string.IsNullOrEmpty(OutputFileName)) { throw new Exception("No output filename specified."); } XmppCredentials Credentials = new XmppCredentials() { Host = Host, Port = Port, Account = Account, Password = Password, AllowCramMD5 = true, AllowEncryption = true, AllowDigestMD5 = true, AllowPlain = true, AllowScramSHA1 = true, AllowScramSHA256 = true, AllowRegistration = false }; using (XmppClient Client = new XmppClient(Credentials, "en", typeof(Program).Assembly)) { ManualResetEvent Done = new ManualResetEvent(false); ManualResetEvent Error = new ManualResetEvent(false); Client.OnStateChanged += (sender, NewState) => { switch (NewState) { case XmppState.Connected: Done.Set(); break; case XmppState.Error: case XmppState.Offline: Error.Set(); break; } }; Client.Connect(); i = WaitHandle.WaitAny(new WaitHandle[] { Done, Error }); if (i == 1) { throw new Exception("Unable to connect to broker."); } if (Jid.Contains("@") && !Jid.Contains("/")) { RosterItem Contact = Client.GetRosterItem(Jid); if (Contact is null || (Contact.State != SubscriptionState.Both && Contact.State != SubscriptionState.To)) { Done.Reset(); Client.OnPresenceSubscribed += (sender, e) => { if (string.Compare(e.FromBareJID, Jid, true) == 0) { Done.Set(); } }; Client.OnPresenceUnsubscribed += (sender, e) => { if (string.Compare(e.FromBareJID, Jid, true) == 0) { Error.Set(); } }; Console.WriteLine("Requesting presence subscription to " + Jid); Client.RequestPresenceSubscription(Jid); i = WaitHandle.WaitAny(new WaitHandle[] { Done, Error }); if (i == 1) { throw new Exception("Unable to obtain presence subscription."); } Console.WriteLine("Presence subscription obtained."); } } ManualResetEvent Done2 = new ManualResetEvent(false); using (StreamWriter f = File.CreateText(OutputFileName)) { XmlWriterSettings Settings = new XmlWriterSettings() { Encoding = Encoding, Indent = true, IndentChars = "\t", NewLineChars = Console.Out.NewLine, OmitXmlDeclaration = false, WriteEndDocumentOnClose = true }; using (XmlWriter w = XmlWriter.Create(f, Settings)) { w.WriteStartDocument(); if (!string.IsNullOrEmpty(XsltPath)) { w.WriteProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"" + XML.Encode(XsltPath) + "\""); } w.WriteStartElement("ClockStatistics", "http://waher.se/Schema/Networking/ClockStatistics.xsd"); w.WriteStartElement("Parameters"); w.WriteAttributeString("clientJid", Client.BareJID); w.WriteAttributeString("sourceJid", Jid); w.WriteAttributeString("records", Records.ToString()); w.WriteAttributeString("interval", Interval.ToString()); w.WriteAttributeString("history", History.ToString()); w.WriteAttributeString("window", Window.ToString()); w.WriteAttributeString("spikePos", SpikePos.ToString()); w.WriteAttributeString("spikeWidth", SpikeWidth.ToString()); w.WriteAttributeString("hfFreq", System.Diagnostics.Stopwatch.Frequency.ToString()); w.WriteEndElement(); w.WriteStartElement("Samples"); using (SynchronizationClient SynchClient = new SynchronizationClient(Client)) { SynchClient.OnUpdated += (sender, e) => { DateTime TP = DateTime.Now; double? StdDev; w.WriteStartElement("Sample"); w.WriteAttributeString("timestamp", XML.Encode(TP)); if (SynchClient.RawLatency100Ns.HasValue) { w.WriteAttributeString("rawLatencyMs", CommonTypes.Encode(SynchClient.RawLatency100Ns.Value * 1e-4)); } if (SynchClient.LatencySpikeRemoved.HasValue) { w.WriteAttributeString("spikeLatencyRemoved", CommonTypes.Encode(SynchClient.LatencySpikeRemoved.Value)); } if (SynchClient.RawClockDifference100Ns.HasValue) { w.WriteAttributeString("rawDifferenceMs", CommonTypes.Encode(SynchClient.RawClockDifference100Ns.Value * 1e-4)); } if (SynchClient.ClockDifferenceSpikeRemoved.HasValue) { w.WriteAttributeString("spikeDifferenceRemoved", CommonTypes.Encode(SynchClient.ClockDifferenceSpikeRemoved.Value)); } if (SynchClient.FilteredLatency100Ns.HasValue) { w.WriteAttributeString("filteredLatencyMs", CommonTypes.Encode(SynchClient.FilteredLatency100Ns.Value * 1e-4)); } if (SynchClient.FilteredClockDifference100Ns.HasValue) { w.WriteAttributeString("filteredDifferenceMs", CommonTypes.Encode(SynchClient.FilteredClockDifference100Ns.Value * 1e-4)); } if (SynchClient.AvgLatency100Ns.HasValue) { w.WriteAttributeString("avgLatencyMs", CommonTypes.Encode(SynchClient.AvgLatency100Ns.Value * 1e-4)); } if (SynchClient.AvgClockDifference100Ns.HasValue) { w.WriteAttributeString("avgDifferenceMs", CommonTypes.Encode(SynchClient.AvgClockDifference100Ns.Value * 1e-4)); } StdDev = SynchClient.CalcStdDevLatency100Ns(); if (StdDev.HasValue) { w.WriteAttributeString("stdDevLatencyMs", CommonTypes.Encode(StdDev.Value * 1e-4)); } StdDev = SynchClient.CalcStdDevClockDifference100Ns(); if (StdDev.HasValue) { w.WriteAttributeString("stdDevDifferenceMs", CommonTypes.Encode(StdDev.Value * 1e-4)); } if (SynchClient.RawLatencyHf.HasValue) { w.WriteAttributeString("rawLatencyHf", SynchClient.RawLatencyHf.Value.ToString()); } if (SynchClient.LatencyHfSpikeRemoved.HasValue) { w.WriteAttributeString("spikeLatencyHfRemoved", CommonTypes.Encode(SynchClient.LatencyHfSpikeRemoved.Value)); } if (SynchClient.RawClockDifferenceHf.HasValue) { w.WriteAttributeString("rawDifferenceHf", SynchClient.RawClockDifferenceHf.Value.ToString()); } if (SynchClient.ClockDifferenceHfSpikeRemoved.HasValue) { w.WriteAttributeString("spikeDifferenceHfRemoved", CommonTypes.Encode(SynchClient.ClockDifferenceHfSpikeRemoved.Value)); } if (SynchClient.FilteredLatencyHf.HasValue) { w.WriteAttributeString("filteredLatencyHf", SynchClient.FilteredLatencyHf.ToString()); } if (SynchClient.FilteredClockDifferenceHf.HasValue) { w.WriteAttributeString("filteredDifferenceHf", SynchClient.FilteredClockDifferenceHf.ToString()); } if (SynchClient.AvgLatencyHf.HasValue) { w.WriteAttributeString("avgLatencyHf", SynchClient.AvgLatencyHf.ToString()); } if (SynchClient.AvgClockDifferenceHf.HasValue) { w.WriteAttributeString("avgDifferenceHf", SynchClient.AvgClockDifferenceHf.ToString()); } StdDev = SynchClient.CalcStdDevLatencyHf(); if (StdDev.HasValue) { w.WriteAttributeString("stdDevLatencyHf", CommonTypes.Encode(StdDev.Value)); } StdDev = SynchClient.CalcStdDevClockDifferenceHf(); if (StdDev.HasValue) { w.WriteAttributeString("stdDevDifferenceHf", CommonTypes.Encode(StdDev.Value)); } w.WriteEndElement(); Console.Out.Write("."); if (--Records <= 0) { Done2.Set(); } }; SynchClient.MonitorClockDifference(Jid, Interval, History, Window, SpikePos, SpikeWidth, true); Done2.WaitOne(); } w.WriteEndElement(); w.WriteEndElement(); w.WriteEndDocument(); w.Flush(); Console.Out.WriteLine(); } } } return(0); } catch (Exception ex) { Console.Out.WriteLine(ex.Message); return(-1); } }