Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2020 Robert Bosch GmbH |
| 3 | * Author: Constantin Ziesche (constantin.ziesche@bosch.com) |
| 4 | * |
| 5 | * This program and the accompanying materials are made available under the |
| 6 | * terms of the Eclipse Public License 2.0 which is available at |
| 7 | * http://www.eclipse.org/legal/epl-2.0 |
| 8 | * |
| 9 | * SPDX-License-Identifier: EPL-2.0 |
| 10 | *******************************************************************************/ |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 11 | using NLog; |
| 12 | using System; |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 13 | using System.Collections.Generic; |
| 14 | using System.Linq; |
| 15 | using System.Net; |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 16 | using System.Net.NetworkInformation; |
| 17 | using System.Net.Sockets; |
| 18 | using System.Threading.Tasks; |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 19 | |
| 20 | namespace BaSyx.Utils.Network |
| 21 | { |
| 22 | public static class NetworkUtils |
| 23 | { |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 24 | private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); |
| 25 | |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 26 | /// <summary> |
| 27 | /// This method returns the closest source IP address relative to the the target IP address. |
| 28 | /// The probality of being able to call the target IP hence increases. |
| 29 | /// </summary> |
| 30 | /// <param name="target">Target IP address to call</param> |
| 31 | /// <param name="sources">Source IP address from where to cal the target</param> |
| 32 | /// <returns>The closest source IP address to the the target IP address or the Loopback Address</returns> |
| 33 | public static IPAddress GetClosestIPAddress(IPAddress target, List<IPAddress> sources) |
| 34 | { |
| 35 | Dictionary<int, IPAddress> scoredSourceIPAddresses = new Dictionary<int, IPAddress>(); |
| 36 | byte[] targetBytes = target.GetAddressBytes(); |
| 37 | foreach (var source in sources) |
| 38 | { |
| 39 | byte[] sourceBytes = source.GetAddressBytes(); |
| 40 | int score = CompareIPByteArray(targetBytes, sourceBytes); |
| 41 | |
| 42 | if(!scoredSourceIPAddresses.ContainsKey(score) && score != 0) |
| 43 | scoredSourceIPAddresses.Add(score, source); |
| 44 | } |
| 45 | |
| 46 | if(scoredSourceIPAddresses.Count > 0) |
| 47 | return scoredSourceIPAddresses[scoredSourceIPAddresses.Keys.Max()]; |
| 48 | |
| 49 | return IPAddress.Loopback; |
| 50 | } |
| 51 | |
| 52 | private static int CompareIPByteArray(byte[] target, byte[] source) |
| 53 | { |
| 54 | if (target.Length != source.Length) |
| 55 | return 0; |
| 56 | |
| 57 | int score = 0; |
| 58 | for (int i = 0; i < source.Length; i++) |
| 59 | { |
| 60 | if (target[i] == source[i]) |
| 61 | score++; |
| 62 | else |
| 63 | return score; |
| 64 | } |
| 65 | return score; |
| 66 | } |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 67 | /// <summary> |
| 68 | /// Returns a sequence of network interfaces which are up and running. |
| 69 | /// If there is no other than the loopback interface available, the loopback interface is returned |
| 70 | /// </summary> |
| 71 | /// <returns>Sequence of network interfaces</returns> |
| 72 | public static IEnumerable<NetworkInterface> GetOperationalNetworkInterfaces() |
| 73 | { |
| 74 | NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); |
| 75 | IEnumerable<NetworkInterface> selectedInterfaces = networkInterfaces?.Where(n => n.OperationalStatus == OperationalStatus.Up && n.NetworkInterfaceType != NetworkInterfaceType.Loopback); |
| 76 | if(selectedInterfaces?.Count() > 0) |
| 77 | return selectedInterfaces; |
| 78 | else |
| 79 | return networkInterfaces?.Where(n => n.OperationalStatus == OperationalStatus.Up); |
| 80 | } |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 81 | |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 82 | /// <summary> |
| 83 | /// Returns all IP addresses of all network interfaces without loopback |
| 84 | /// </summary> |
| 85 | /// <returns>Sequence of IP addresses</returns> |
| 86 | public static IEnumerable<IPAddress> GetIPAddresses() |
| 87 | { |
| 88 | IEnumerable<NetworkInterface> networkInterfaces = GetOperationalNetworkInterfaces(); |
| 89 | return networkInterfaces?.SelectMany(n => n.GetIPProperties().UnicastAddresses)?.Select(s => s.Address); |
| 90 | } |
| 91 | |
| 92 | /// <summary> |
| 93 | /// Returns all link local IP addresses |
| 94 | /// </summary> |
| 95 | /// <returns>Sequence of link local IP addresses</returns> |
| 96 | public static List<IPAddress> GetLinkLocalIPAddresses() |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 97 | { |
| 98 | IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); |
| 99 | List<IPAddress> ipAddresses = new List<IPAddress>(); |
| 100 | foreach (var ip in host.AddressList) |
| 101 | { |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 102 | if (ip.AddressFamily == AddressFamily.InterNetwork || ip.AddressFamily == AddressFamily.InterNetworkV6 && ip.IsIPv6LinkLocal) |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 103 | ipAddresses.Add(ip); |
| 104 | } |
| 105 | return ipAddresses; |
| 106 | } |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 107 | |
| 108 | /// <summary> |
| 109 | /// Pings a host and returns true if ping was successfull otherwise false |
| 110 | /// </summary> |
| 111 | /// <param name="hostNameOrAddress">IP-address or host name</param> |
| 112 | /// <returns>true if pingable, false otherwise</returns> |
| 113 | public static async Task<bool> PingHostAsync(string hostNameOrAddress) |
| 114 | { |
| 115 | if (string.IsNullOrEmpty(hostNameOrAddress)) |
| 116 | throw new ArgumentNullException(nameof(hostNameOrAddress)); |
| 117 | |
| 118 | try |
| 119 | { |
| 120 | using (Ping pinger = new Ping()) |
| 121 | { |
| 122 | PingReply reply = await pinger.SendPingAsync(hostNameOrAddress); |
| 123 | if (reply.Status == IPStatus.Success) |
| 124 | { |
| 125 | return true; |
| 126 | } |
| 127 | else |
| 128 | { |
Constantin Ziesche | 310d2aa | 2020-03-25 11:48:26 +0100 | [diff] [blame^] | 129 | logger.Warn($"Pinging {hostNameOrAddress} PingReply-Status: " + Enum.GetName(typeof(IPStatus), reply.Status)); |
Constantin Ziesche | eb92768 | 2020-03-03 11:11:31 +0100 | [diff] [blame] | 130 | return false; |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | catch (PingException e) |
| 135 | { |
| 136 | logger.Error(e, "Ping-Exception"); |
| 137 | return false; |
| 138 | } |
| 139 | } |
Constantin Ziesche | 857c7ab | 2020-02-25 11:24:51 +0100 | [diff] [blame] | 140 | } |
| 141 | } |