Browse Source

Merge branch 'edge' of http://10.6.6.2/zerotier/ZeroTierOne into edge

Adam Ierymenko 9 years ago
parent
commit
5ec5911e1b

+ 102 - 45
windows/WinUI/APIHandler.cs

@@ -5,6 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Net;
 using System.Net;
 using System.IO;
 using System.IO;
+using System.Windows;
 using Newtonsoft.Json;
 using Newtonsoft.Json;
 
 
 namespace WinUI
 namespace WinUI
@@ -13,7 +14,7 @@ namespace WinUI
 
 
     public class APIHandler
     public class APIHandler
     {
     {
-        static string authtoken = "p3ptrzds5jkr2hbx5ipbyf04";  // delete me!
+        private string authtoken;
 
 
         private string url = null;
         private string url = null;
 
 
@@ -22,9 +23,10 @@ namespace WinUI
             url = "http://127.0.0.1:9993";
             url = "http://127.0.0.1:9993";
         }
         }
 
 
-        public APIHandler(string host, int port)
+        public APIHandler(int port, string authtoken)
         {
         {
-            url = "http://" + host + ":" + port;
+            url = "http://localhost:" + port;
+            this.authtoken = authtoken;
         }
         }
 
 
         public ZeroTierStatus GetStatus()
         public ZeroTierStatus GetStatus()
@@ -36,21 +38,32 @@ namespace WinUI
                 request.ContentType = "application/json";
                 request.ContentType = "application/json";
             }
             }
 
 
-            var httpResponse = (HttpWebResponse)request.GetResponse();
-            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
+            try
             {
             {
-                var responseText = streamReader.ReadToEnd();
-
-                ZeroTierStatus status = null;
-                try
-                {
-                    status = JsonConvert.DeserializeObject<ZeroTierStatus>(responseText);
-                }
-                catch (JsonReaderException e)
+                var httpResponse = (HttpWebResponse)request.GetResponse();
+                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                 {
                 {
-                    Console.WriteLine(e.ToString());
+                    var responseText = streamReader.ReadToEnd();
+
+                    ZeroTierStatus status = null;
+                    try
+                    {
+                        status = JsonConvert.DeserializeObject<ZeroTierStatus>(responseText);
+                    }
+                    catch (JsonReaderException e)
+                    {
+                        Console.WriteLine(e.ToString());
+                    }
+                    return status;
                 }
                 }
-                return status;
+            }
+            catch (System.Net.Sockets.SocketException)
+            {
+                return null;
+            }
+            catch (System.Net.WebException)
+            {
+                return null;
             }
             }
         }
         }
 
 
@@ -65,21 +78,32 @@ namespace WinUI
             request.Method = "GET";
             request.Method = "GET";
             request.ContentType = "application/json";
             request.ContentType = "application/json";
 
 
-            var httpResponse = (HttpWebResponse)request.GetResponse();
-            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
+            try
             {
             {
-                var responseText = streamReader.ReadToEnd();
-
-                List<ZeroTierNetwork> networkList = null;
-                try
+                var httpResponse = (HttpWebResponse)request.GetResponse();
+                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                 {
                 {
-                    networkList = JsonConvert.DeserializeObject<List<ZeroTierNetwork>>(responseText);
+                    var responseText = streamReader.ReadToEnd();
+
+                    List<ZeroTierNetwork> networkList = null;
+                    try
+                    {
+                        networkList = JsonConvert.DeserializeObject<List<ZeroTierNetwork>>(responseText);
+                    }
+                    catch (JsonReaderException e)
+                    {
+                        Console.WriteLine(e.ToString());
+                    }
+                    return networkList;
                 }
                 }
-                catch (JsonReaderException e)
-                {
-                    Console.WriteLine(e.ToString());
-                }
-                return networkList;
+            }
+            catch (System.Net.Sockets.SocketException)
+            {
+                return null;
+            }
+            catch (System.Net.WebException)
+            {
+                return null;
             }
             }
         }
         }
 
 
@@ -93,11 +117,22 @@ namespace WinUI
 
 
             request.Method = "POST";
             request.Method = "POST";
 
 
-            var httpResponse = (HttpWebResponse)request.GetResponse();
+            try
+            {
+                var httpResponse = (HttpWebResponse)request.GetResponse();
 
 
-            if (httpResponse.StatusCode != HttpStatusCode.OK)
+                if (httpResponse.StatusCode != HttpStatusCode.OK)
+                {
+                    Console.WriteLine("Error sending join network message");
+                }
+            }
+            catch (System.Net.Sockets.SocketException)
             {
             {
-                Console.WriteLine("Error sending join network message");
+                MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service.");
+            }
+            catch (System.Net.WebException)
+            {
+                MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service.");
             }
             }
         }
         }
 
 
@@ -111,11 +146,22 @@ namespace WinUI
 
 
             request.Method = "DELETE";
             request.Method = "DELETE";
 
 
-            var httpResponse = (HttpWebResponse)request.GetResponse();
+            try
+            {
+                var httpResponse = (HttpWebResponse)request.GetResponse();
 
 
-            if (httpResponse.StatusCode != HttpStatusCode.OK)
+                if (httpResponse.StatusCode != HttpStatusCode.OK)
+                {
+                    Console.WriteLine("Error sending leave network message");
+                }
+            }
+            catch (System.Net.Sockets.SocketException)
+            {
+                MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service.");
+            }
+            catch (System.Net.WebException)
             {
             {
-                Console.WriteLine("Error sending leave network message");
+                MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service.");
             }
             }
         }
         }
 
 
@@ -130,21 +176,32 @@ namespace WinUI
             request.Method = "GET";
             request.Method = "GET";
             request.ContentType = "application/json";
             request.ContentType = "application/json";
 
 
-            var httpResponse = (HttpWebResponse)request.GetResponse();
-            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
+            try
             {
             {
-                var responseText = streamReader.ReadToEnd();
-
-                List<ZeroTierPeer> peerList = null;
-                try
-                {
-                    peerList = JsonConvert.DeserializeObject<List<ZeroTierPeer>>(responseText);
-                }
-                catch (JsonReaderException e)
+                var httpResponse = (HttpWebResponse)request.GetResponse();
+                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                 {
                 {
-                    Console.WriteLine(e.ToString());
+                    var responseText = streamReader.ReadToEnd();
+                    //Console.WriteLine(responseText);
+                    List<ZeroTierPeer> peerList = null;
+                    try
+                    {
+                        peerList = JsonConvert.DeserializeObject<List<ZeroTierPeer>>(responseText);
+                    }
+                    catch (JsonReaderException e)
+                    {
+                        Console.WriteLine(e.ToString());
+                    }
+                    return peerList;
                 }
                 }
-                return peerList;
+            }
+            catch (System.Net.Sockets.SocketException)
+            {
+                return null;
+            }
+            catch (System.Net.WebException)
+            {
+                return null;
             }
             }
         }
         }
     }
     }

+ 74 - 56
windows/WinUI/MainWindow.xaml

@@ -5,58 +5,76 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:local="clr-namespace:WinUI"
         xmlns:local="clr-namespace:WinUI"
         mc:Ignorable="d" x:Class="WinUI.MainWindow"
         mc:Ignorable="d" x:Class="WinUI.MainWindow"
-        Title="ZeroTier One" Height="500" Width="700" Icon="ZeroTierIcon.ico">
+        Title="ZeroTier One" Height="500" Width="600" Icon="ZeroTierIcon.ico">
 	
 	
-	<Window.Resources>
-		<ResourceDictionary>
-			<Style TargetType="{x:Type TabItem}">
-				<Setter Property="BorderThickness"
-						Value="3" />
-				<Setter Property="BorderBrush"
-						Value="Blue" />
-				<Setter Property="VerticalContentAlignment"
-						Value="Center" />
-				<Setter Property="HorizontalContentAlignment"
-						Value="Center" />
-				<Setter Property="Template">
-					<Setter.Value>
-						<ControlTemplate TargetType="{x:Type TabItem}">
-							<Border>
-								<Grid>
-									<Grid>
-										<Border x:Name="border" 
-												CornerRadius="3,3,0,0"
-												Background="{TemplateBinding Background}"
-												BorderBrush="{TemplateBinding BorderBrush}"
-												BorderThickness="1,1,1,0" />
-									</Grid>
-									<Border BorderThickness="{TemplateBinding BorderThickness}"
-											Padding="{TemplateBinding Padding}">
-										<ContentPresenter ContentSource="Header"
-														  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
-														  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
-									</Border>
-								</Grid>
-							</Border>
-							<ControlTemplate.Triggers>
-								<Trigger Property="IsSelected"
-										 Value="True">
-									<Setter TargetName="border"
-											Property="BorderBrush"
-												Value="#ff91a2a3" />
-									<Setter TargetName="border"
-											Property="BorderThickness"
-											Value="0,3,0,0" />
-								</Trigger>
-							</ControlTemplate.Triggers>
-						</ControlTemplate>
-					</Setter.Value>
-				</Setter>
-			</Style>
-		</ResourceDictionary>
-	</Window.Resources>
+    <Window.Resources>
+        <SolidColorBrush x:Key="GreenBrush" Color="#ff91a2a3"/>
 
 
-	<DockPanel>
+        <SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
+
+        <SolidColorBrush x:Key="GreenDisabledBrush" Color="#FF234447" />
+
+        <SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
+
+        <SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
+
+        <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
+        
+        <Style TargetType="{x:Type DataGrid}">
+            <Setter Property="Background" Value="#FFF" />
+            <Setter Property="AlternationCount" Value="2" />
+        </Style>
+
+        <Style TargetType="{x:Type DataGridRow}">
+            <Style.Triggers>
+                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
+                    <Setter Property="Background" Value="#EEE"></Setter>
+                </Trigger>
+                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
+                    <Setter Property="Background" Value="#FFF"></Setter>
+                </Trigger>
+            </Style.Triggers>
+        </Style>
+        
+        <Style TargetType="{x:Type TabItem}">
+            <Setter Property="Template">
+                <Setter.Value>
+                    <ControlTemplate TargetType="{x:Type TabItem}">
+                        <Grid>
+                            <Border 
+                                Name="Border"
+                                Margin="0,0,-4,0" 
+                                Background="{StaticResource GreenBrush}"
+                                BorderBrush="{StaticResource  SolidBorderBrush}" 
+                                BorderThickness="1,1,1,1" 
+                                CornerRadius="2,12,0,0" >
+                                <ContentPresenter x:Name="ContentSite"
+                                    VerticalAlignment="Center"
+                                    HorizontalAlignment="Center"
+                                    ContentSource="Header"
+                                    Margin="12,2,12,2"
+                                    RecognizesAccessKey="True"/>
+                            </Border>
+                        </Grid>
+                        <ControlTemplate.Triggers>
+                            <Trigger Property="IsSelected" Value="True">
+                                <Setter Property="Panel.ZIndex" Value="100" />
+                                <Setter TargetName="Border" Property="Background" Value="{StaticResource GreenDisabledBrush}" />
+                                <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
+                            </Trigger>
+                            <Trigger Property="IsEnabled" Value="False">
+                                <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
+                                <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
+                                <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
+                            </Trigger>
+                        </ControlTemplate.Triggers>
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>
+        </Style>
+    </Window.Resources>
+    
+    <DockPanel>
 		<StatusBar DockPanel.Dock="Bottom" Height="34" Background="#FF234447" Margin="0">
 		<StatusBar DockPanel.Dock="Bottom" Height="34" Background="#FF234447" Margin="0">
 			<StatusBar.ItemsPanel>
 			<StatusBar.ItemsPanel>
                 <ItemsPanelTemplate>
                 <ItemsPanelTemplate>
@@ -77,17 +95,17 @@
             </StatusBar.ItemsPanel>
             </StatusBar.ItemsPanel>
 			<StatusBarItem Grid.Column="0" x:Name="networkId" Content="Network ID" Foreground="White"/>
 			<StatusBarItem Grid.Column="0" x:Name="networkId" Content="Network ID" Foreground="White"/>
 			<StatusBarItem Grid.Column="1" x:Name="onlineStatus" Content="ONLINE" Foreground="White"/>
 			<StatusBarItem Grid.Column="1" x:Name="onlineStatus" Content="ONLINE" Foreground="White"/>
-			<StatusBarItem Grid.Column="2" x:Name="versionString" Content="1.0.5" Foreground="White" Margin="0"/>
-			<StatusBarItem Grid.Column="3" x:Name="blank" Content="" Height="43" Foreground="White" Margin="6,0,-6,-9"/>
+			<StatusBarItem Grid.Column="2" x:Name="versionString" Content="1.0.5" Foreground="White"/>
+			<StatusBarItem Grid.Column="3" x:Name="blank" Content="" Height="43" Foreground="White"/>
 			<StatusBarItem Grid.Column="4">
 			<StatusBarItem Grid.Column="4">
-				<TextBox x:Name="joinNetworkID" Height="23" TextWrapping="Wrap" Width="120" HorizontalAlignment="Right" RenderTransformOrigin="1.168,0.478" ToolTip="Enter Network ID" PreviewTextInput="OnNetworkEntered" MaxLength="16"/>
+				<TextBox x:Name="joinNetworkID" Height="23" TextWrapping="Wrap" Width="120" HorizontalAlignment="Right" ToolTip="Enter Network ID" PreviewTextInput="OnNetworkEntered" MaxLength="16"/>
 			</StatusBarItem>
 			</StatusBarItem>
 			<StatusBarItem Grid.Column="5" x:Name="statusBarButton" Foreground="White" RenderTransformOrigin="0.789,0.442">
 			<StatusBarItem Grid.Column="5" x:Name="statusBarButton" Foreground="White" RenderTransformOrigin="0.789,0.442">
 				<Button x:Name="joinButton" Content="Join" Background="#FFFFB354" Width="77.423" Click="joinButton_Click"/>
 				<Button x:Name="joinButton" Content="Join" Background="#FFFFB354" Width="77.423" Click="joinButton_Click"/>
 			</StatusBarItem>
 			</StatusBarItem>
 		</StatusBar>
 		</StatusBar>
-		<TabControl>
-            <TabItem x:Name="Networks" Header="Networks" Background="#FF234447" Foreground="White" IsSelected="True" IsManipulationEnabled="True">
+		<TabControl Margin="0,0,0,0">
+            <TabItem x:Name="Networks" Header="Networks" Foreground="White" IsSelected="True" IsManipulationEnabled="True">
                 <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                 <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                     <Grid.ColumnDefinitions>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="*"/>
                         <ColumnDefinition Width="*"/>
@@ -98,7 +116,7 @@
                     <local:NetworksPage x:Name="networksPage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Margin="0,0,0,0"/>
                     <local:NetworksPage x:Name="networksPage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Margin="0,0,0,0"/>
                 </Grid>
                 </Grid>
             </TabItem>
             </TabItem>
-            <TabItem x:Name="Peers" Header="Peers" Background="#FF234447" Foreground="White">
+            <TabItem x:Name="Peers" Header="Peers" Foreground="White">
                 <Grid Background="#FFE5E5E5" HorizontalAlignment="Left" VerticalAlignment="Top">
                 <Grid Background="#FFE5E5E5" HorizontalAlignment="Left" VerticalAlignment="Top">
                     <Grid.ColumnDefinitions>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="*"/>
                         <ColumnDefinition Width="*"/>

+ 90 - 19
windows/WinUI/MainWindow.xaml.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
@@ -23,45 +24,115 @@ namespace WinUI
     /// </summary>
     /// </summary>
     public partial class MainWindow : Window
     public partial class MainWindow : Window
     {
     {
-        APIHandler handler = new APIHandler();
+        APIHandler handler;
         Regex charRegex = new Regex("[0-9a-fxA-FX]");
         Regex charRegex = new Regex("[0-9a-fxA-FX]");
         Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$");
         Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$");
 
 
         Timer timer = new Timer();
         Timer timer = new Timer();
 
 
+        bool connected = false;
+
         public MainWindow()
         public MainWindow()
         {
         {
             InitializeComponent();
             InitializeComponent();
 
 
-            networksPage.SetAPIHandler(handler);
+            if (InitAPIHandler())
+            {
+                networksPage.SetAPIHandler(handler);
 
 
-            updateStatus();
-            updateNetworks();
-            updatePeers();
+                updateStatus();
+                if (!connected)
+                {
+                    MessageBox.Show("Unable to connect to ZeroTier Service.");
+                }
+
+                updateNetworks();
+                updatePeers();
+
+                DataObject.AddPastingHandler(joinNetworkID, OnPaste);
+
+                timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer);
+                timer.Interval = 2000;
+                timer.Enabled = true;
+            }
+        }
+
+        private bool InitAPIHandler()
+        {
+            String ztDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One";
+            String authToken = "";
+            Int32 port = 9993;
+            try
+            {
+                byte[] tmp = File.ReadAllBytes(ztDir + "\\authtoken.secret");
+                authToken = System.Text.Encoding.ASCII.GetString(tmp).Trim();
+            }
+            catch
+            {
+                MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One");
+                this.Close();
+                return false;
+            }
 
 
-            DataObject.AddPastingHandler(joinNetworkID, OnPaste);
+            if ((authToken == null) || (authToken.Length <= 0))
+            {
+                MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One");
+                this.Close();
+                return false;
+            }
+            try
+            {
+                byte[] tmp = File.ReadAllBytes(ztDir + "\\zerotier-one.port");
+                port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim());
+                if ((port <= 0) || (port > 65535))
+                    port = 9993;
+            }
+            catch
+            {
+            }
 
 
-            timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer);
-            timer.Interval = 2000;
-            timer.Enabled = true;
+            handler = new APIHandler(port, authToken);
+            return true;
         }
         }
 
 
         private void updateStatus()
         private void updateStatus()
         {
         {
             var status = handler.GetStatus();
             var status = handler.GetStatus();
 
 
-            networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => 
-            { 
-                this.networkId.Content = status.Address; 
-            }));
-            versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+            if (status != null)
             {
             {
-                this.versionString.Content = status.Version;
-            }));
-            onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                connected = true;
+
+                networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    this.networkId.Content = status.Address;
+                }));
+                versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    this.versionString.Content = status.Version;
+                }));
+                onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    this.onlineStatus.Content = (status.Online ? "ONLINE" : "OFFLINE");
+                }));
+            }
+            else
             {
             {
-                this.onlineStatus.Content = (status.Online ? "ONLINE" : "OFFLINE");
-            }));
+                connected = false;
+
+                networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    this.networkId.Content = "";
+                }));
+                versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    this.versionString.Content = "0";
+                }));
+                onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    this.onlineStatus.Content = "OFFLINE";
+                }));
+            }
         }
         }
 
 
         private void updateNetworks()
         private void updateNetworks()

+ 57 - 47
windows/WinUI/NetworkInfoView.xaml

@@ -5,59 +5,69 @@
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
       mc:Ignorable="d"
       mc:Ignorable="d"
 	>
 	>
-	<Grid Background="#FFFFFFFF" Margin="5,0,5,1">
-        <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="auto"/>
-            <ColumnDefinition Width="10"/>
-            <ColumnDefinition Width="*"/>
-        </Grid.ColumnDefinitions>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-            <RowDefinition Height="auto"/>
-        </Grid.RowDefinitions>
-
-        <Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3">
+    
+    <Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1" CornerRadius="8,8,3,3">
+        <Grid Background="#FFFFFFFF" Margin="10,10,10,10">
             <Grid.ColumnDefinitions>
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="auto"/>
                 <ColumnDefinition Width="auto"/>
+                <ColumnDefinition Width="10"/>
                 <ColumnDefinition Width="*"/>
                 <ColumnDefinition Width="*"/>
             </Grid.ColumnDefinitions>
             </Grid.ColumnDefinitions>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+                <RowDefinition Height="auto"/>
+            </Grid.RowDefinitions>
 
 
-            <TextBlock x:Name="networkId" Text="8056c2e21c000001" HorizontalAlignment="Left" Grid.Column="0" Foreground="#FF91A2A3"/>
-            <TextBlock x:Name="networkName" Text="earth.zerotier.net" HorizontalAlignment="Right" Grid.Column="1" Foreground="#FF000000"/>
-        </Grid>
-
-        <TextBlock TextWrapping="Wrap" Text="Status" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="1" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="Type" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="2" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="MAC" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="3" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="MTU" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="4" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="Broadcast" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="5" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="Bridging" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="6" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="Device" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="7" Foreground="#FF000000"/>
-        <TextBlock TextWrapping="Wrap" Text="Managed IPs" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="8" Foreground="#FF000000"/>
+            <Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
 
 
-        <TextBlock x:Name="networkStatus" TextWrapping="Wrap" HorizontalAlignment="Right" Text="OK" TextAlignment="Right"  Grid.Column="2" Grid.Row="1" Foreground="#FF000000"/>
-        <TextBlock x:Name="networkType" TextWrapping="Wrap" Text="PUBLIC" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="2" Foreground="#FF000000"/>
-        <TextBlock x:Name="macAddress" TextWrapping="Wrap" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="3" Foreground="#FF000000"><Span><Run Text="02:83:4a:1e:4b:3a"/></Span></TextBlock>
-        <TextBlock x:Name="mtu" TextWrapping="Wrap" Text="2800" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="4" Foreground="#FF000000"/>
-        <TextBlock x:Name="broadcastEnabled" TextWrapping="Wrap" Text="ENABLED" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="5" Foreground="#FF000000"/>
-        <TextBlock x:Name="bridgingEnabled" TextWrapping="Wrap" Text="DISABLED" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="6" Foreground="#FF000000"/>
-        <TextBlock x:Name="deviceName" TextWrapping="Wrap" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="7" Foreground="#FF000000"><Span><Run Text="ethernet_32771"/></Span></TextBlock>
-        <TextBlock x:Name="managedIps" TextWrapping="Wrap" HorizontalAlignment="Right" TextAlignment="Right"  Grid.Column="2" Grid.Row="8" Foreground="#FF000000"><Span><Run Text="28.2.169.248/7 "/></Span><LineBreak/><Span><Run Text="fd80:56c2:e21c:0000:0199:9383:4a02:a9f8/88"/></Span></TextBlock>
+                <TextBlock x:Name="networkId" Text="8056c2e21c000001" HorizontalAlignment="Left" Grid.Column="0" Foreground="#FF91A2A3"/>
+                <TextBlock x:Name="networkName" Text="earth.zerotier.net" HorizontalAlignment="Right" Grid.Column="1" Foreground="#FF000000"/>
+            </Grid>
+            
+            <Separator Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3"/>
+            
+            <TextBlock TextWrapping="Wrap" Text="Status" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="2" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="Type" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="3" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="MAC" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="4" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="MTU" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="5" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="Broadcast" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="6" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="Bridging" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="7" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="Device" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="8" Foreground="#FF000000"/>
+            <TextBlock TextWrapping="Wrap" Text="Managed IPs" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="9" Foreground="#FF000000"/>
+            
+            <Rectangle Grid.Column="2" Grid.Row="2" Grid.RowSpan="8" Fill="#FFEEEEEE"/>
+            
+            <TextBlock x:Name="networkStatus" TextWrapping="Wrap" HorizontalAlignment="Right" Text="OK" TextAlignment="Right"  Grid.Column="2" Grid.Row="2" Foreground="#FF000000"/>
+            <TextBlock x:Name="networkType" TextWrapping="Wrap" Text="PUBLIC" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="3" Foreground="#FF000000"/>
+            <TextBlock x:Name="macAddress" TextWrapping="Wrap" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="4" Foreground="#FF000000"><Span><Run Text="02:83:4a:1e:4b:3a"/></Span></TextBlock>
+            <TextBlock x:Name="mtu" TextWrapping="Wrap" Text="2800" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="5" Foreground="#FF000000"/>
+            <TextBlock x:Name="broadcastEnabled" TextWrapping="Wrap" Text="ENABLED" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="6" Foreground="#FF000000"/>
+            <TextBlock x:Name="bridgingEnabled" TextWrapping="Wrap" Text="DISABLED" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="7" Background="#FFEEEEEE" Foreground="#FF000000"/>
+            <TextBlock x:Name="deviceName" TextWrapping="Wrap" HorizontalAlignment="Right"  Grid.Column="2" Grid.Row="8" Foreground="#FF000000"><Span><Run Text="ethernet_32771"/></Span></TextBlock>
+            <TextBlock x:Name="managedIps" TextWrapping="Wrap" HorizontalAlignment="Right" TextAlignment="Right"  Grid.Column="2" Grid.Row="9" Foreground="#FF000000"><Span><Run Text="28.2.169.248/7 "/></Span><LineBreak/><Span><Run Text="fd80:56c2:e21c:0000:0199:9383:4a02:a9f8/88"/></Span></TextBlock>
 
 
-        <Grid Grid.Column="0" Grid.Row="9" Grid.ColumnSpan="3" Background="#FFFFFFFF">
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="*"/>
-            </Grid.ColumnDefinitions>
-            <Button />
-            <Button x:Name="leaveButton" Content="Leave" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Background="#FFFFB354" Click="leaveButton_Click"/>
+            <Separator Grid.Column="0" Grid.Row="10" Grid.ColumnSpan="3"/>
+            
+            <Grid Grid.Column="0" Grid.Row="11" Grid.ColumnSpan="3" Background="#FFFFFFFF">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <Button x:Name="leaveButton" Content="Leave" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Background="#FFFFB354" Click="leaveButton_Click"/>
+            </Grid>
         </Grid>
         </Grid>
-    </Grid>
+    </Border>
 </UserControl>
 </UserControl>

+ 2 - 2
windows/WinUI/NetworksPage.xaml

@@ -5,8 +5,8 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              mc:Ignorable="d" 
              mc:Ignorable="d" 
              d:DesignHeight="300" d:DesignWidth="300">
              d:DesignHeight="300" d:DesignWidth="300">
-    <ScrollViewer x:Name="MyScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualHeight}">
-        <WrapPanel x:Name="wrapPanel" Background="#FF555555"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+    <ScrollViewer x:Name="MyScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+        <WrapPanel x:Name="wrapPanel" Background="#FFDDDDDD"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
 
 
         </WrapPanel>
         </WrapPanel>
     </ScrollViewer>
     </ScrollViewer>

+ 4 - 0
windows/WinUI/NetworksPage.xaml.cs

@@ -35,6 +35,10 @@ namespace WinUI
         public void setNetworks(List<ZeroTierNetwork> networks)
         public void setNetworks(List<ZeroTierNetwork> networks)
         {
         {
             this.wrapPanel.Children.Clear();
             this.wrapPanel.Children.Clear();
+            if (networks == null)
+            {
+                return;
+            }
 
 
             for (int i = 0; i < networks.Count; ++i)
             for (int i = 0; i < networks.Count; ++i)
             {
             {

+ 9 - 2
windows/WinUI/PeersPage.xaml

@@ -5,7 +5,14 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              mc:Ignorable="d" 
              mc:Ignorable="d" 
              d:DesignHeight="300" d:DesignWidth="300" Background="White" Foreground="Black">
              d:DesignHeight="300" d:DesignWidth="300" Background="White" Foreground="Black">
-    <DataGrid x:Name="dataGrid" AutoGenerateColumns="False" CanUserResizeColumns="True" Margin="0,0,0,0" CanUserReorderColumns="False" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualHeight}" CanUserSortColumns="False">
+
+    <DataGrid x:Name="dataGrid" GridLinesVisibility="None" AutoGenerateColumns="False" CanUserResizeColumns="True" Margin="0,0,0,0" CanUserReorderColumns="False" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" CanUserSortColumns="False">
+        <DataGrid.CellStyle>
+            <Style TargetType="DataGridCell">
+                <Setter Property="BorderThickness" Value="0"/>
+                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
+            </Style>
+        </DataGrid.CellStyle>
         <DataGrid.Columns>
         <DataGrid.Columns>
             <DataGridTextColumn Header="Address" Binding="{Binding Address}"/>
             <DataGridTextColumn Header="Address" Binding="{Binding Address}"/>
             <DataGridTextColumn Header="Version" Binding="{Binding VersionString}"/>
             <DataGridTextColumn Header="Version" Binding="{Binding VersionString}"/>
@@ -13,7 +20,7 @@
             <DataGridTextColumn Header="Data Paths" Binding="{Binding DataPaths}"/>
             <DataGridTextColumn Header="Data Paths" Binding="{Binding DataPaths}"/>
             <DataGridTextColumn Header="Last Unicast" Binding="{Binding LastUnicastFrame}"/>
             <DataGridTextColumn Header="Last Unicast" Binding="{Binding LastUnicastFrame}"/>
             <DataGridTextColumn Header="Last Multicast" Binding="{Binding LastMulticastFrame}"/>
             <DataGridTextColumn Header="Last Multicast" Binding="{Binding LastMulticastFrame}"/>
-            <DataGridTextColumn Header="Role" Binding="{Binding Role}"/>
+            <DataGridTextColumn Width="*" Header="Role" Binding="{Binding Role}"/>
         </DataGrid.Columns>
         </DataGrid.Columns>
     </DataGrid>
     </DataGrid>
 </UserControl>
 </UserControl>

+ 18 - 3
windows/WinUI/PeersPage.xaml.cs

@@ -29,10 +29,25 @@ namespace WinUI
             dataGrid.ItemsSource = peersList;
             dataGrid.ItemsSource = peersList;
         }
         }
 
 
-        public void SetPeers(List<ZeroTierPeer> peerList)
+        public void SetPeers(List<ZeroTierPeer> list)
         {
         {
-            this.peersList = peerList;
-            dataGrid.ItemsSource = this.peersList;
+            if (list == null)
+                return;
+
+            
+            foreach(ZeroTierPeer p in list)
+            {
+                ZeroTierPeer curPeer = peersList.Find(peer => peer.Equals(p));
+                if (curPeer == null)
+                {
+                    peersList.Add(p);                    
+                }
+                else
+                {
+                    curPeer.Update(p);
+                }
+            }
+
             dataGrid.Items.Refresh();
             dataGrid.Items.Refresh();
         }
         }
     }
     }

+ 4 - 0
windows/WinUI/WinUI.csproj

@@ -63,6 +63,9 @@
   <PropertyGroup>
   <PropertyGroup>
     <SignManifests>false</SignManifests>
     <SignManifests>false</SignManifests>
   </PropertyGroup>
   </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationManifest>app.manifest</ApplicationManifest>
+  </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Reference Include="Accessibility" />
     <Reference Include="Accessibility" />
     <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
     <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@@ -161,6 +164,7 @@
       <Generator>ResXFileCodeGenerator</Generator>
       <Generator>ResXFileCodeGenerator</Generator>
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
     </EmbeddedResource>
     </EmbeddedResource>
+    <None Include="app.manifest" />
     <None Include="packages.config" />
     <None Include="packages.config" />
     <None Include="Properties\Settings.settings">
     <None Include="Properties\Settings.settings">
       <Generator>SettingsSingleFileGenerator</Generator>
       <Generator>SettingsSingleFileGenerator</Generator>

+ 54 - 4
windows/WinUI/ZeroTierPeer.cs

@@ -7,16 +7,48 @@ using Newtonsoft.Json;
 
 
 namespace WinUI
 namespace WinUI
 {
 {
-    public class ZeroTierPeer
+    public class ZeroTierPeer : IEquatable<ZeroTierPeer>
     {
     {
         [JsonProperty("address")]
         [JsonProperty("address")]
         public string Address { get; set; }
         public string Address { get; set; }
 
 
+        private Int64 _lastUnicast;
         [JsonProperty("lastUnicastFrame")]
         [JsonProperty("lastUnicastFrame")]
-        public UInt64 LastUnicastFrame { get; set; }
+        public Int64 LastUnicastFrame
+        {
+            get
+            {
+                if (_lastUnicast == 0)
+                    return 0;
 
 
+                TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
+                Int64 millisecondsSinceEpoch = (Int64)t.TotalMilliseconds;
+                return (millisecondsSinceEpoch - _lastUnicast) / 1000;
+            }
+            set
+            {
+                _lastUnicast = value;
+            }
+        }
+
+        private Int64 _lastMulticast;
         [JsonProperty("lastMulticastFrame")]
         [JsonProperty("lastMulticastFrame")]
-        public UInt64 LastMulticastFrame { get; set; }
+        public Int64 LastMulticastFrame 
+        {
+            get
+            {
+                if (_lastMulticast == 0)
+                    return 0;
+
+                TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
+                Int64 millisecondsSinceEpoch = (Int64)t.TotalMilliseconds;
+                return (millisecondsSinceEpoch - _lastMulticast) / 1000;
+            }
+            set
+            {
+                _lastMulticast = value;
+            }
+        }
 
 
         [JsonProperty("versionMajor")]
         [JsonProperty("versionMajor")]
         public int VersionMajor { get; set; }
         public int VersionMajor { get; set; }
@@ -25,7 +57,7 @@ namespace WinUI
         public int VersionMinor { get; set; }
         public int VersionMinor { get; set; }
 
 
         [JsonProperty("versionRev")]
         [JsonProperty("versionRev")]
-        public int Versionrev { get; set; }
+        public int VersionRev { get; set; }
 
 
         [JsonProperty("version")]
         [JsonProperty("version")]
         public string Version { get; set; }
         public string Version { get; set; }
@@ -62,5 +94,23 @@ namespace WinUI
                 return pathStr;
                 return pathStr;
             }
             }
         }
         }
+
+        public bool Equals(ZeroTierPeer other)
+        {
+            return this.Address.Equals(other.Address, StringComparison.InvariantCultureIgnoreCase);
+        }
+
+        public void Update(ZeroTierPeer other)
+        {
+            _lastUnicast = other._lastUnicast;
+            _lastMulticast = other._lastMulticast;
+            VersionMajor = other.VersionMajor;
+            VersionMinor = other.VersionMinor;
+            VersionRev = other.VersionRev;
+            Version = other.Version;
+            Latency = other.Latency;
+            Role = other.Role;
+            Paths = other.Paths;
+        }
     }
     }
 }
 }

+ 55 - 0
windows/WinUI/app.manifest

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
+        <!-- UAC Manifest Options
+            If you want to change the Windows User Account Control level replace the 
+            requestedExecutionLevel node with one of the following.
+
+        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
+        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
+        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />
+
+            Specifying requestedExecutionLevel node will disable file and registry virtualization.
+            If you want to utilize File and Registry Virtualization for backward 
+            compatibility then delete the requestedExecutionLevel node.
+        -->
+        <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- A list of all Windows versions that this application is designed to work with. 
+      Windows will automatically select the most compatible environment.-->
+
+      <!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node-->
+      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>-->
+
+      <!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
+      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
+
+      <!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node-->
+      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>-->
+
+    </application>
+  </compatibility>
+
+  <!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
+  <!-- <dependency>
+    <dependentAssembly>
+      <assemblyIdentity
+          type="win32"
+          name="Microsoft.Windows.Common-Controls"
+          version="6.0.0.0"
+          processorArchitecture="*"
+          publicKeyToken="6595b64144ccf1df"
+          language="*"
+        />
+    </dependentAssembly>
+  </dependency>-->
+
+</asmv1:assembly>