From 53b9dbdafdd3219ce4a1b859357b69cb5f3c78f3 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Thu, 20 Oct 2016 18:46:28 +0100
Subject: [PATCH] Add support for multiple interfaces.

---
 PixelHub-Client/PixelHub-Client.ino         |  2 +-
 PixelHub-Server/PixelHub/DiscoveryBeacon.cs | 21 +++++++++++++--
 PixelHub-Server/PixelHub/NetTools.cs        | 29 +++++++++++++++++++++
 PixelHub-Server/PixelHub/PixelHub.csproj    |  1 +
 PixelHub-Server/PixelHub/Program.cs         | 20 +++++++++++---
 5 files changed, 66 insertions(+), 7 deletions(-)
 create mode 100644 PixelHub-Server/PixelHub/NetTools.cs

diff --git a/PixelHub-Client/PixelHub-Client.ino b/PixelHub-Client/PixelHub-Client.ino
index d1454c5..e2a2ef6 100644
--- a/PixelHub-Client/PixelHub-Client.ino
+++ b/PixelHub-Client/PixelHub-Client.ino
@@ -10,7 +10,7 @@
 
 #include "Utilities.h"
 
-char ssid[] = "evenstar-2.4";
+char ssid[] = "ZimWeaver";
 char password[] = "***REMOVED***";
 
 // The address that the PixelHub beacon is broadcasting on.
diff --git a/PixelHub-Server/PixelHub/DiscoveryBeacon.cs b/PixelHub-Server/PixelHub/DiscoveryBeacon.cs
index 7c1f5e4..2bcd85c 100644
--- a/PixelHub-Server/PixelHub/DiscoveryBeacon.cs
+++ b/PixelHub-Server/PixelHub/DiscoveryBeacon.cs
@@ -40,6 +40,13 @@ namespace PixelHub.Net
 		/// Setting this value affects the IP address that is broadcast by the beacon.
 		/// </remarks>
 		public IPAddress LocalIP { get; set; }
+
+		/// <summary>
+		/// The name of the entwork interface to bind to.
+		/// If you don't want to bind to a specific interface, leave this property alone.
+		/// </summary>
+		public string NetworkInterfaceName { get; set; } = string.Empty;
+
 		/// <summary>
 		/// The (multicast) IP address that the beacon should broadcast to.
 		/// </summary>
@@ -57,7 +64,7 @@ namespace PixelHub.Net
 		/// The role that the program hosted at this beacon plays. Default: server.
 		/// </summary>
 		public string Role {
-			get{
+			get {
 				return role;
 			}
 			private set {
@@ -95,7 +102,6 @@ namespace PixelHub.Net
 			MulticastChannel = new IPEndPoint(DestinationAddress, Port);
 
 			LocalIP = findLocalIP();
-			logger.WriteLine("Using {0} as the local IP Address.", LocalIP);
 		}
 		/// <summary>
 		/// Initializes a new instance of the <see cref="PixelHub.Net.DiscoveryBeacon"/> class.
@@ -118,6 +124,7 @@ namespace PixelHub.Net
 		/// </summary>
 		public async Task Emit()
 		{
+			logger.WriteLine("Using {0} as the local IP Address.", LocalIP);
 			connect();
 			logger.WriteLine("Beacon activated with broadcast interval of {0}ms.", EmitFrequency);
 			while(true)
@@ -143,6 +150,16 @@ namespace PixelHub.Net
 		private void connect()
 		{
 			beacon = new UdpClient(Port);
+
+			if(NetworkInterfaceName != string.Empty)
+			{
+				beacon.Client.SetSocketOption(
+					SocketOptionLevel.IP,
+					SocketOptionName.MulticastInterface,
+					(int)IPAddress.HostToNetworkOrder(NetTools.GetNetworkIndexByName4(NetworkInterfaceName))
+				);
+			}
+
 			Active = true;
 			beacon.JoinMulticastGroup(DestinationAddress);
 			logger.WriteLine("One way beacon set up pointing at {0}.", MulticastChannel);
diff --git a/PixelHub-Server/PixelHub/NetTools.cs b/PixelHub-Server/PixelHub/NetTools.cs
new file mode 100644
index 0000000..7c6ee9e
--- /dev/null
+++ b/PixelHub-Server/PixelHub/NetTools.cs
@@ -0,0 +1,29 @@
+﻿using System;
+using System.Net.NetworkInformation;
+using System.Runtime.InteropServices;
+
+namespace SBRL.Utilities
+{
+	public static class NetTools
+	{
+		/// <summary>
+		/// case-insensitively gets the IPv4 index of the network interface with the given name.
+		/// </summary>
+		/// <param name="interfaceName">The interface name to search for.</param>
+		/// <returns>The IPv4 index of the network interface with the given name.</returns>
+		public static int GetNetworkIndexByName4(string targetInterfaceName)
+		{
+			NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
+			foreach (NetworkInterface nic in nics)
+			{
+				Console.WriteLine("Id: {0}, Description: {1}", nic.Id, nic.Description);
+				IPInterfaceProperties ipProps = nic.GetIPProperties();
+				IPv4InterfaceProperties ip4Props = ipProps.GetIPv4Properties();
+				if (nic.Id == targetInterfaceName)
+					return ip4Props.Index;
+			}
+			throw new Exception($"Error: Can't find network interface with the name {targetInterfaceName}.");
+		}
+	}
+}
+
diff --git a/PixelHub-Server/PixelHub/PixelHub.csproj b/PixelHub-Server/PixelHub/PixelHub.csproj
index a152533..940e7dc 100644
--- a/PixelHub-Server/PixelHub/PixelHub.csproj
+++ b/PixelHub-Server/PixelHub/PixelHub.csproj
@@ -42,6 +42,7 @@
     <Compile Include="SBRL.Utilities\PrefixedWriter.cs" />
     <Compile Include="PixelCommand.cs" />
     <Compile Include="PixelBot.cs" />
+    <Compile Include="NetTools.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/PixelHub-Server/PixelHub/Program.cs b/PixelHub-Server/PixelHub/Program.cs
index e43006f..a5000bd 100644
--- a/PixelHub-Server/PixelHub/Program.cs
+++ b/PixelHub-Server/PixelHub/Program.cs
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
 
 using SBRL.Utilities;
 using PixelHub.Net;
+using System.Net.NetworkInformation;
 
 namespace PixelHub.Server
 {
@@ -22,13 +23,24 @@ namespace PixelHub.Server
 				IPAddress.Parse("239.62.148.30"), port,
 				beaconWriter
 			);
+			beacon.LocalIP = IPAddress.Parse("10.42.0.1");
+			beacon.NetworkInterfaceName = "wlan0";
+
 			PixelHub server = new PixelHub(port, serverWriter);
+			//server.BindAddress = IPAddress.Parse("10.42.0.1");
+
 			systemWriter.WriteLine("Server booting complete. Beginning async loop.");
 			//AsyncTools.ForgetTask(beacon.Emit());
-			Task.WaitAll(new Task[] {
-				beacon.Emit(),
-				server.Listen()
-			});
+			try {
+				Task.WaitAll(new Task[] {
+					beacon.Emit(),
+					server.Listen()
+				});
+			}
+			catch(AggregateException error) {
+				foreach (Exception innerErr in error.InnerExceptions)
+					Console.WriteLine(innerErr);
+			}
 		}
 	}
 }
