diff --git a/DesktopEdge/MainMenu.xaml b/DesktopEdge/MainMenu.xaml index 7e3a10ce..7e10e8fe 100644 --- a/DesktopEdge/MainMenu.xaml +++ b/DesktopEdge/MainMenu.xaml @@ -102,6 +102,9 @@ + + + diff --git a/DesktopEdge/MainMenu.xaml.cs b/DesktopEdge/MainMenu.xaml.cs index b4e8879c..77f664de 100644 --- a/DesktopEdge/MainMenu.xaml.cs +++ b/DesktopEdge/MainMenu.xaml.cs @@ -452,5 +452,22 @@ namespace ZitiDesktopEdge { IdListView.Children.Add(item); } } + + public void SetAppUpgradeAvailableText(string msg) { + this.Dispatcher.Invoke(() => { + VersionOlder.Content = msg; + VersionNewer.Content = ""; + VersionOlder.Visibility = Visibility.Visible; + VersionNewer.Visibility = Visibility.Collapsed; + }); + } + public void SetAppIsNewer(string msg) { + this.Dispatcher.Invoke(() => { + VersionNewer.Content = msg; + VersionOlder.Content = ""; + VersionNewer.Visibility = Visibility.Visible; + VersionOlder.Visibility = Visibility.Collapsed; + }); + } } } \ No newline at end of file diff --git a/DesktopEdge/MainWindow.xaml.cs b/DesktopEdge/MainWindow.xaml.cs index c5b06ccc..bfa01ae1 100644 --- a/DesktopEdge/MainWindow.xaml.cs +++ b/DesktopEdge/MainWindow.xaml.cs @@ -14,6 +14,7 @@ using System.Threading.Tasks; using ZitiDesktopEdge.Models; using ZitiDesktopEdge.DataStructures; using ZitiDesktopEdge.ServiceClient; +using ZitiDesktopEdge.Utility; using NLog; using NLog.Config; @@ -282,6 +283,7 @@ namespace ZitiDesktopEdge { monitorClient.OnClientConnected += MonitorClient_OnClientConnected; monitorClient.OnServiceStatusEvent += MonitorClient_OnServiceStatusEvent; monitorClient.OnShutdownEvent += MonitorClient_OnShutdownEvent; + monitorClient.OnReconnectFailure += MonitorClient_OnReconnectFailure; Application.Current.Properties.Add("MonitorClient", monitorClient); Application.Current.Properties.Add("Identities", new List()); @@ -308,6 +310,31 @@ namespace ZitiDesktopEdge { Placement(); } + string nextVersionStr = null; + private void MonitorClient_OnReconnectFailure(object sender, object e) { + if(nextVersionStr == null) { + // check for the current version + nextVersionStr = "checking for update"; + Version nextVersion = VersionUtil.NormalizeVersion(GithubAPI.GetVersion(GithubAPI.GetJson(GithubAPI.ProdUrl))); + nextVersionStr = nextVersion.ToString(); + Version currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; //fetch from ziti? + + int compare = currentVersion.CompareTo(nextVersion); + if (compare < 0) { + MainMenu.SetAppUpgradeAvailableText("Upgrade available: " + nextVersionStr); + logger.Info("upgrade is available. Published version: {} is newer than the current version: {}", nextVersion, currentVersion); + //UpgradeAvailable(); + } else if (compare > 0) { + logger.Info("the version installed: {0} is newer than the released version: {1}", currentVersion, nextVersion); + MainMenu.SetAppIsNewer("This version is newer than the latest: " + nextVersionStr); + } else { + logger.Info("Current version installed: {0} is the same as the latest released version {1}", currentVersion, nextVersion); + MainMenu.SetAppUpgradeAvailableText(""); + } + + } + } + private void MonitorClient_OnShutdownEvent(object sender, StatusEvent e) { Application.Current.Shutdown(); } @@ -433,6 +460,7 @@ namespace ZitiDesktopEdge { private void MonitorClient_OnClientConnected(object sender, object e) { logger.Debug("MonitorClient_OnClientConnected"); + MainMenu.SetAppUpgradeAvailableText(""); } async private void LogLevelChanged(string level) { diff --git a/DesktopEdge/Properties/AssemblyInfo.cs b/DesktopEdge/Properties/AssemblyInfo.cs index 7841b0c5..206acfd2 100644 --- a/DesktopEdge/Properties/AssemblyInfo.cs +++ b/DesktopEdge/Properties/AssemblyInfo.cs @@ -50,6 +50,6 @@ using System.Windows; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -// [assembly: AssemblyVersion("1.7.6.0")] -[assembly: AssemblyVersion("1.7.6.0")] -[assembly: AssemblyFileVersion("1.7.6.0")] +// [assembly: AssemblyVersion("1.7.8.0")] +[assembly: AssemblyVersion("1.7.8.0")] +[assembly: AssemblyFileVersion("1.7.8.0")] diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip index 73373d6d..862c6a01 100644 --- a/Installer/ZitiDesktopEdge.aip +++ b/Installer/ZitiDesktopEdge.aip @@ -22,10 +22,10 @@ - + - + diff --git a/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs b/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs index 00b8031d..81053e52 100644 --- a/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs +++ b/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs @@ -15,6 +15,10 @@ using ZitiDesktopEdge.DataStructures; namespace ZitiDesktopEdge.ServiceClient { public abstract class AbstractClient { + public event EventHandler OnClientConnected = null; + public event EventHandler OnClientDisconnected; + public event EventHandler OnShutdownEvent; + public event EventHandler OnReconnectFailure; protected NamedPipeClientStream pipeClient = null; protected NamedPipeClientStream eventClient = null; @@ -81,6 +85,10 @@ namespace ZitiDesktopEdge.ServiceClient { OnShutdownEvent?.Invoke(this, e); } + protected virtual void ReconnectFailureEvent(object e) { + OnReconnectFailure?.Invoke(this, e); + } + async protected Task sendAsync(object objToSend) { bool retried = false; while (true) { @@ -118,10 +126,6 @@ namespace ZitiDesktopEdge.ServiceClient { } } - public event EventHandler OnClientConnected = null; - public event EventHandler OnClientDisconnected; - public event EventHandler OnShutdownEvent; - public bool Reconnecting { get; set; } public bool Connected { get; set; } public bool CleanShutdown { get; set; } @@ -162,6 +166,11 @@ namespace ZitiDesktopEdge.ServiceClient { //ClientDisconnected(null); } } catch { + try { + ReconnectFailureEvent("reconnect failure"); + } catch { + + } var now = DateTime.Now; if (now > logAgainAfter) { Logger.Debug("Reconnect failed. Trying again..."); diff --git a/ZitiDesktopEdge.Client/Utility/GithubAPI.cs b/ZitiDesktopEdge.Client/Utility/GithubAPI.cs new file mode 100644 index 00000000..b5390874 --- /dev/null +++ b/ZitiDesktopEdge.Client/Utility/GithubAPI.cs @@ -0,0 +1,33 @@ +using System; +using System.Net; +using System.IO; + +using NLog; +using Newtonsoft.Json.Linq; + +namespace ZitiDesktopEdge.Utility { + public static class GithubAPI { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public const string ProdUrl = "https://api.github.com/repos/openziti/desktop-edge-win/releases/latest"; + public const string BetaUrl = "https://api.github.com/repos/openziti/desktop-edge-win-beta/releases/latest"; + + public static JObject GetJson(string url) { + HttpWebRequest httpWebRequest = WebRequest.CreateHttp(url); + httpWebRequest.Method = "GET"; + httpWebRequest.ContentType = "application/json"; + httpWebRequest.UserAgent = "OpenZiti UpdateService"; + HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()); + string currentResponse = streamReader.ReadToEnd(); + Logger.Trace("response received: {0}", currentResponse); + return JObject.Parse(currentResponse); + } + + public static Version GetVersion(JObject json) { + string releaseVersion = json.Property("tag_name").Value.ToString(); + string releaseName = json.Property("name").Value.ToString(); + return VersionUtil.NormalizeVersion(new Version(releaseVersion)); + } + } +} diff --git a/ZitiDesktopEdge.Client/Utility/VersionUtil.cs b/ZitiDesktopEdge.Client/Utility/VersionUtil.cs new file mode 100644 index 00000000..14323ff7 --- /dev/null +++ b/ZitiDesktopEdge.Client/Utility/VersionUtil.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZitiDesktopEdge.Utility { + public static class VersionUtil { + public static Version NormalizeVersion(Version v) { + if (v.Minor < 1) return new Version(v.Major, 0, 0, 0); + if (v.Build < 1) return new Version(v.Major, v.Minor, 0, 0); + if (v.Revision < 1) return new Version(v.Major, v.Minor, v.Build, 0); + return v; + } + } +} diff --git a/ZitiDesktopEdge.Client/ZitiDesktopEdge.Client.csproj b/ZitiDesktopEdge.Client/ZitiDesktopEdge.Client.csproj index b093c37d..f864053b 100644 --- a/ZitiDesktopEdge.Client/ZitiDesktopEdge.Client.csproj +++ b/ZitiDesktopEdge.Client/ZitiDesktopEdge.Client.csproj @@ -62,6 +62,8 @@ + + diff --git a/ZitiUpdateService/Properties/AssemblyInfo.cs b/ZitiUpdateService/Properties/AssemblyInfo.cs index 49d06c1f..6c862ebf 100644 --- a/ZitiUpdateService/Properties/AssemblyInfo.cs +++ b/ZitiUpdateService/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -// [assembly: AssemblyVersion("1.7.6.0")] -[assembly: AssemblyVersion("1.7.6.0")] -[assembly: AssemblyFileVersion("1.7.6.0")] +// [assembly: AssemblyVersion("1.7.8.0")] +[assembly: AssemblyVersion("1.7.8.0")] +[assembly: AssemblyFileVersion("1.7.8.0")] diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs index aec33308..b1d2c910 100644 --- a/ZitiUpdateService/UpdateService.cs +++ b/ZitiUpdateService/UpdateService.cs @@ -8,13 +8,17 @@ using System.Configuration; using System.Threading.Tasks; using System.Reflection; using System.Security.Cryptography.X509Certificates; +using System.IO.Compression; -using NLog; using ZitiDesktopEdge.DataStructures; using ZitiDesktopEdge.ServiceClient; using ZitiDesktopEdge.Server; -using System.IO.Compression; +using ZitiDesktopEdge.Utility; + +using NLog; using Newtonsoft.Json; +using DnsClient; +using System.Net; namespace ZitiUpdateService { public partial class UpdateService : ServiceBase { @@ -53,6 +57,9 @@ namespace ZitiUpdateService { Task eventServer = null; checkers.UpdateCheck check = null; + private Timer dnsProbeTimer = new Timer(); + private IPAddress dnsIpAddress = null; + public UpdateService() { InitializeComponent(); @@ -366,10 +373,61 @@ namespace ZitiUpdateService { }); } Logger.Info("ziti-monitor service is initialized and running"); + dnsProbeTimer.Elapsed += DnsProbe_Elapsed; + dnsProbeTimer.Interval = dnsProbeIntervalInSeconds * 1000; base.OnStart(args); } - async private Task onEventsClientAsync(StreamWriter writer) { + IPAddress lh = IPAddress.Parse("127.0.0.1"); //expected result + int dnsProbeFailCount = 0; + int dnsProbeIntervalInSeconds = 15; + bool dnsProbeStarted = false; + + private void DnsProbe_Elapsed(object sender, ElapsedEventArgs e) { + if (dnsProbeStarted) return; //skip out if it's already going... + dnsProbeStarted = true; + try { + if (dnsIpAddress != null) { + DnsQuestion q = new DnsQuestion("dew-dns-probe.openziti.org", QueryType.A); + var dnsEp = new IPEndPoint(dnsIpAddress, 53); + var dnsProbe = new LookupClient(dnsEp); + + foreach (DnsClient.Protocol.ARecord arec in dnsProbe.Query(q).AllRecords) { + if (arec.Address.Equals(lh)) { + dnsProbeFailCount = 0; + } else { + dnsProbeFailCount++; + logDnsProbeFailure(null); + } + } + } + } catch(Exception dnse) { + //don't really care but it probably means a timeout happened. but might as well log a trace error anyway... + //it's expected that this is due to the service shutting down... + dnsProbeFailCount++; + logDnsProbeFailure(dnse); + } + dnsProbeStarted = false; + } + + private void logDnsProbeFailure(Exception e) { + bool logit = false; + if (dnsProbeFailCount <= 4) { + logit = true; + } else { + //else log it every 5 minutes... + logit = dnsProbeFailCount % (5 * 60 / dnsProbeIntervalInSeconds) == 0; + } + if (logit) { + if (e != null) { + Logger.Warn(e, "dns probe failed due to error. This has happened {0} times", dnsProbeFailCount); + } else { + Logger.Warn("dns probe failed. This has happened {0} times", dnsProbeFailCount); + } + } + } + + async private Task onEventsClientAsync(StreamWriter writer) { Logger.Info("a new events client was connected"); //reset to release stream //initial status when connecting the event stream @@ -613,7 +671,7 @@ namespace ZitiUpdateService { if (fi.Name.StartsWith(filePrefix)) { Logger.Debug("scanning for staleness: " + f); string ver = Path.GetFileNameWithoutExtension(f).Substring(filePrefix.Length); - Version fileVersion = checkers.UpdateCheck.NormalizeVersion(new Version(ver)); + Version fileVersion = VersionUtil.NormalizeVersion(new Version(ver)); if (isOlder(fileVersion)) { Logger.Info("Removing old download: " + fi.Name); fi.Delete(); @@ -709,18 +767,26 @@ namespace ZitiUpdateService { EventRegistry.SendEventToConsumers(status); } - private static void Svc_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) { + private void Svc_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) { string dns = e?.Status?.IpInfo?.DNS; string version = e?.Status?.ServiceVersion.Version; string op = e?.Op; Logger.Info($"Operation {op}. running dns: {dns} at version {version}"); + + try { + dnsIpAddress = IPAddress.Parse(dns); + } catch { + //ignore it + } } - private static void Svc_OnClientConnected(object sender, object e) { + private void Svc_OnClientConnected(object sender, object e) { Logger.Info("successfully connected to service"); + dnsProbeTimer.Start(); } private void Svc_OnClientDisconnected(object sender, object e) { + //dnsProbeTimer.Stop(); DataClient svc = (DataClient)sender; if (svc.CleanShutdown) { //then this is fine and expected - the service is shutting down diff --git a/ZitiUpdateService/ZitiUpdateService.csproj b/ZitiUpdateService/ZitiUpdateService.csproj index d2e99b4e..a2e7c843 100644 --- a/ZitiUpdateService/ZitiUpdateService.csproj +++ b/ZitiUpdateService/ZitiUpdateService.csproj @@ -76,6 +76,9 @@ bin\Releases\ + + ..\packages\DnsClient.1.3.2\lib\net471\DnsClient.dll + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll @@ -83,6 +86,9 @@ ..\packages\NLog.4.7.6\lib\net45\NLog.dll + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + diff --git a/ZitiUpdateService/checkers/GithubCheck.cs b/ZitiUpdateService/checkers/GithubCheck.cs index 628944e8..eeca9452 100644 --- a/ZitiUpdateService/checkers/GithubCheck.cs +++ b/ZitiUpdateService/checkers/GithubCheck.cs @@ -1,12 +1,13 @@ using System; using System.IO; using System.Net; - using System.Security.Cryptography; using NLog; using Newtonsoft.Json.Linq; +using ZitiDesktopEdge.Utility; + namespace ZitiUpdateService.checkers { internal class GithubCheck : UpdateCheck { @@ -14,7 +15,6 @@ namespace ZitiUpdateService.checkers { string url; string downloadUrl = null; string downloadFileName = null; - string currentResponse = null; Version nextVersion = null; public GithubCheck(string url) { @@ -40,15 +40,7 @@ namespace ZitiUpdateService.checkers { override public int IsUpdateAvailable(Version currentVersion) { Logger.Debug("checking for update begins. current version detected as {0}", currentVersion); Logger.Debug("issuing http get to url: {0}", url); - HttpWebRequest httpWebRequest = WebRequest.CreateHttp(url); - httpWebRequest.Method = "GET"; - httpWebRequest.ContentType = "application/json"; - httpWebRequest.UserAgent = "OpenZiti UpdateService"; - HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); - StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()); - currentResponse = streamReader.ReadToEnd(); - Logger.Trace("response received: {0}", currentResponse); - JObject json = JObject.Parse(currentResponse); + JObject json = GithubAPI.GetJson(url); JArray assets = JArray.Parse(json.Property("assets").Value.ToString()); foreach (JObject asset in assets.Children()) { @@ -72,7 +64,8 @@ namespace ZitiUpdateService.checkers { string releaseVersion = json.Property("tag_name").Value.ToString(); string releaseName = json.Property("name").Value.ToString(); - nextVersion = NormalizeVersion(new Version(releaseVersion)); + nextVersion = VersionUtil.NormalizeVersion(new Version(releaseVersion)); + int compare = currentVersion.CompareTo(nextVersion); if (compare < 0) { Logger.Info("upgrade {} is available. Published version: {} is newer than the current version: {}", releaseName, nextVersion, currentVersion); diff --git a/ZitiUpdateService/checkers/UpdateCheckers.cs b/ZitiUpdateService/checkers/UpdateCheckers.cs index 29f8e76e..582a15d8 100644 --- a/ZitiUpdateService/checkers/UpdateCheckers.cs +++ b/ZitiUpdateService/checkers/UpdateCheckers.cs @@ -12,12 +12,5 @@ namespace ZitiUpdateService.checkers { public abstract bool AlreadyDownloaded(string destinationFolder, string destinationName); public abstract bool HashIsValid(string destinationFolder, string destinationName); public abstract Version GetNextVersion(); - - public static Version NormalizeVersion(Version v) { - if (v.Minor < 1) return new Version(v.Major, 0, 0, 0); - if (v.Build < 1) return new Version(v.Major, v.Minor, 0, 0); - if (v.Revision < 1) return new Version(v.Major, v.Minor, v.Build, 0); - return v; - } } } diff --git a/ZitiUpdateService/packages.config b/ZitiUpdateService/packages.config index 04f986fe..18c2b3df 100644 --- a/ZitiUpdateService/packages.config +++ b/ZitiUpdateService/packages.config @@ -1,6 +1,8 @@  + + \ No newline at end of file diff --git a/service/build.bat b/service/build.bat index 8a77e20d..dac04bcb 100644 --- a/service/build.bat +++ b/service/build.bat @@ -14,7 +14,7 @@ REM See the License for the specific language governing permissions and REM limitations under the License. REM SET REPO_URL=https://github.com/openziti/ziti-tunnel-sdk-c.git -SET ZITI_TUNNEL_REPO_BRANCH=v0.8.15 +SET ZITI_TUNNEL_REPO_BRANCH=v0.8.16 REM override the c sdk used in the build - leave blank for the same as specified in the tunneler sdk SET ZITI_SDK_C_BRANCH= REM the number of TCP connections the tunneler sdk can have at any one time diff --git a/service/cziti/dns.go b/service/cziti/dns.go index b7ce7a0a..627867c6 100644 --- a/service/cziti/dns.go +++ b/service/cziti/dns.go @@ -274,6 +274,15 @@ func DnsInit(tun api.DesktopEdgeIface, ip string, maskBits int) { dnsMgrPrivate.serviceMap = make(map[string]*ctxService) //DNS.ipMap = make(map[uint32]string) dnsMgrPrivate.hostnameMap = make(map[string]*ctxIp) + //register the test dns entry: + dnsMgrPrivate.hostnameMap[normalizeDnsName("dew-dns-probe.openziti.org")] = &ctxIp{ + //ctx: nil, + ip: net.ParseIP("127.0.0.1"), + //network: "", + dnsEnabled: true, + refCount: 0, + } + dnsip = net.ParseIP(ip).To4() mask := net.CIDRMask(maskBits, 32) dnsMgrPrivate.cidr = binary.BigEndian.Uint32(dnsip) & binary.BigEndian.Uint32(mask) diff --git a/service/cziti/sdk.go b/service/cziti/sdk.go index 4b372039..6b4cb0cc 100644 --- a/service/cziti/sdk.go +++ b/service/cziti/sdk.go @@ -26,6 +26,7 @@ package cziti #include "ziti/ziti_log.h" #include "sdk.h" +extern void doZitiShutdown(uv_async_t *handle); extern void zitiContextEvent(ziti_context nf, int status, void *ctx); extern void eventCB(ziti_context ztx, ziti_event_t *event); @@ -212,6 +213,22 @@ func (c *ZIdentity) Controller() string { return C.GoString(c.Options.controller) } +func (zid *ZIdentity) Shutdown() { + + async := (*C.uv_async_t)(C.malloc(C.sizeof_uv_async_t)) + async.data = unsafe.Pointer(zid.czctx) + log.Debugf("setting up call to ziti_shutdown for context %p using uv_async_t", async.data) + C.uv_async_init(_impl.libuvCtx.l, async, C.uv_async_cb(C.doZitiShutdown)) + C.uv_async_send((*C.uv_async_t)(unsafe.Pointer(async))) +} + +//export doZitiShutdown +func doZitiShutdown(async *C.uv_async_t) { + ctx := C.ziti_context(async.data) + log.Infof("invoking ziti_shutdown for context %p", &ctx) + C.ziti_shutdown(ctx) +} + var cTunClientCfgName = C.CString("ziti-tunneler-client.v1") var cTunServerCfgName = C.CString("ziti-tunneler-server.v1") diff --git a/service/ziti-tunnel/service/ipc.go b/service/ziti-tunnel/service/ipc.go index 97f09eaa..d10730b7 100644 --- a/service/ziti-tunnel/service/ipc.go +++ b/service/ziti-tunnel/service/ipc.go @@ -846,6 +846,7 @@ func removeIdentity(out *json.Encoder, fingerprint string) { resp := dto.Response{Message: "success", Code: SUCCESS, Error: anyErrs, Payload: nil} respond(out, resp) + // call shutdown some day id.CId.Shutdown() log.Infof("request to remove identity by fingerprint: %s responded to", fingerprint) } diff --git a/version b/version index 91c74a58..84298f96 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.7.7 +1.7.8