コード例 #1
0
        /// <summary>
        /// Parse
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static IEnumerable <AddressRange> Parse(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentNullException(nameof(value));
            }
            var split = value.Split(new char[] { ';', ',' },
                                    StringSplitOptions.RemoveEmptyEntries);

            return(split
                   .SelectMany(s => {
                var x = s.Split('/');
                if (x.Length != 2)
                {
                    throw new FormatException("Bad suffix format");
                }
                var suffix = int.Parse(x[1]);
                if (suffix == 0 || suffix > 32)
                {
                    throw new FormatException("Bad suffix value");
                }
                if (x[0] == "*")
                {
                    return NetworkInformationEx.GetAllNetInterfaces(
                        NetworkClass.Wired)
                    .Select(t => new AddressRange(t, false, suffix));
                }
                return new AddressRange(IPAddress.Parse(x[0]), suffix)
                .YieldReturn();
            }).Distinct().ToList());
        }
コード例 #2
0
 /// <summary>
 /// Create scanner
 /// </summary>
 /// <param name="logger"></param>
 /// <param name="replies"></param>
 /// <param name="local"></param>
 /// <param name="addresses"></param>
 /// <param name="netclass"></param>
 /// <param name="maxProbeCount"></param>
 /// <param name="timeout"></param>
 /// <param name="ct"></param>
 public NetworkScanner(ILogger logger, Action <NetworkScanner, PingReply> replies,
                       bool local, IEnumerable <AddressRange> addresses, NetworkClass netclass,
                       int?maxProbeCount, TimeSpan?timeout, CancellationToken ct)
 {
     _logger     = logger;
     _replies    = replies;
     _ct         = ct;
     _timeout    = timeout ?? kDefaultProbeTimeout;
     _completion = new TaskCompletionSource <bool>();
     _candidates = new List <uint>();
     if (addresses == null)
     {
         _addresses = NetworkInformationEx.GetAllNetInterfaces(netclass)
                      .Select(t => new AddressRange(t, local)).Distinct().ToList();
     }
     else
     {
         _addresses = addresses.Select(a => a.Copy()).Distinct().ToList();
     }
     _pings = CreatePings(local ? _addresses.Count + 1 :
                          maxProbeCount ?? kDefaultMaxProbeCount);
     // Start initial pings
     _logger.Information("Start scanning {addresses}...",
                         _addresses.Select(a => a.ToString()));
     foreach (var ping in _pings.ToList())
     {
         OnNextPing(ping);
     }
 }
コード例 #3
0
        /// <summary>
        /// Create request wrapper
        /// </summary>
        /// <param name="request"></param>
        /// <param name="networkClass"></param>
        public DiscoveryRequest(DiscoveryRequestModel request,
                                NetworkClass networkClass = NetworkClass.Wired)
        {
            Request      = request?.Clone() ?? throw new ArgumentNullException(nameof(request));
            NetworkClass = networkClass;

            if (!string.IsNullOrEmpty(request.Configuration?.AddressRangesToScan))
            {
                if (AddressRange.TryParse(request.Configuration?.AddressRangesToScan,
                                          out var addresses))
                {
                    AddressRanges = addresses;
                }
            }

            if (AddressRanges == null)
            {
                if (request.Discovery == DiscoveryMode.Fast)
                {
                    var interfaces = NetworkInformationEx.GetAllNetInterfaces(NetworkClass.Wired);
                    AddressRanges = interfaces.Select(t => new AddressRange(t, false, 24));
                    AddressRanges = AddressRanges.Concat(interfaces
                                                         .Where(t => t.Gateway != null &&
                                                                !t.Gateway.Equals(System.Net.IPAddress.Any) &&
                                                                !t.Gateway.Equals(System.Net.IPAddress.None))
                                                         .Select(i => new AddressRange(i.Gateway, 32)));
                }
            }

            if (!string.IsNullOrEmpty(request.Configuration?.PortRangesToScan))
            {
                if (PortRange.TryParse(request.Configuration?.PortRangesToScan,
                                       out var ports))
                {
                    PortRanges = ports;
                }
            }

            if (PortRanges == null)
            {
                switch (request.Discovery)
                {
                case DiscoveryMode.Local:
                    PortRanges = PortRange.All;
                    break;

                case DiscoveryMode.Fast:
                    PortRanges = PortRange.WellKnown;
                    break;

                case DiscoveryMode.Scan:
                    PortRanges = PortRange.Unassigned;
                    break;

                default:
                    PortRanges = PortRange.OpcUa;
                    break;
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Parse
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static IEnumerable <AddressRange> Parse(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentNullException(nameof(value));
            }
            var split = value.Split(new char[] { ';', ',' },
                                    StringSplitOptions.RemoveEmptyEntries);
            var unmerged = split
                           .SelectMany(s => {
                var nic = string.Empty;
                var x   = s.Split('[', StringSplitOptions.RemoveEmptyEntries);
                if (x.Length > 1)
                {
                    var postFix = x[1].Split(']');
                    if (postFix.Length > 1)
                    {
                        nic = postFix[0];
                    }
                    s = x[0].Trim();
                }
                x = s.Split('/', StringSplitOptions.RemoveEmptyEntries);
                if (x.Length != 2)
                {
                    x = s.Split('-', StringSplitOptions.RemoveEmptyEntries);
                    if (x.Length != 2)
                    {
                        throw new FormatException("Bad suffix format");
                    }
                    // Combine into cidr ranges and parse so we get distinct ranges
                    return(Parse(new AddressRange(
                                     new IPv4Address(IPAddress.Parse(x[0])),
                                     new IPv4Address(IPAddress.Parse(x[1])), nic).ToString()));
                }
                var suffix = int.Parse(x[1]);
                if (suffix == 0 || suffix > 32)
                {
                    throw new FormatException("Bad suffix value");
                }
                if (x[0] == "*")
                {
                    return(NetworkInformationEx.GetAllNetInterfaces(
                               NetworkClass.Wired)
                           .Select(t => new AddressRange(t, false, suffix)));
                }
                return(new AddressRange(IPAddress.Parse(x[0]), suffix, nic)
                       .YieldReturn());
            })
                           .Distinct()
                           .ToList();

            return(Merge(unmerged));
        }
コード例 #5
0
        public void TestSubnetNicLocal()
        {
            var nics = NetworkInformationEx.GetAllNetInterfaces(NetworkClass.Wired);

            if (!nics.Any())
            {
                return;
            }
            var nic   = nics.First();
            var range = new AddressRange(nic, true);

            Assert.Equal(nic.UnicastAddress, (IPv4Address)range.Low);
            Assert.Equal(nic.UnicastAddress, (IPv4Address)range.High);
            Assert.Equal(1, range.Count);
        }
コード例 #6
0
        public void TestSubnetNic()
        {
            var nics = NetworkInformationEx.GetAllNetInterfaces(NetworkClass.Wired);

            if (!nics.Any())
            {
                return;
            }
            var nic      = nics.First();
            var expected = new AddressRange(nic.UnicastAddress, nic.SubnetMask);
            var range    = new AddressRange(nic);

            Assert.Equal((IPv4Address)expected.Low, (IPv4Address)range.Low);
            Assert.Equal((IPv4Address)expected.High, (IPv4Address)range.High);
            Assert.Equal(expected.Count, range.Count);
        }
コード例 #7
0
        /// <inheritdoc/>
        public async Task <IPublisherClient> ConnectAsync()
        {
            const string kPublisherName = "opcpublisher";
            const int    kPublisherPort = 62222;

            _logger.Information("Finding publisher to use as publish service...");

            var deviceId = _identity.DeviceId;

            if (string.IsNullOrEmpty(deviceId))
            {
                // No identity at this point - look up from IoT Edge environment
                deviceId = Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
            }
            if (!string.IsNullOrEmpty(deviceId))
            {
                _logger.Debug("Get all modules in current edge context.");
                // Get modules
                var modules = await _modules.GetModulesAsync(deviceId);

                var publisherModule = modules
                                      .Where(m => m.Status.EqualsIgnoreCase("running"))
                                      .FirstOrDefault(m =>
                                                      m.ImageName?.Contains("opc-publisher") ?? (false ||
                                                                                                 m.Id.EqualsIgnoreCase(kPublisherName)));

                if (publisherModule == null)
                {
                    _logger.Warning("No publisher module running in edge context.");
                }

                // Have publisher module
                var moduleId = publisherModule?.Id ?? kPublisherName;
                _logger.Information("Testing publisher module {moduleId} using methods...",
                                    moduleId);
                var publisher = new PublisherMethodClient(_methods, deviceId, moduleId, _logger);
                var error     = await TestConnectivityAsync(publisher);

                if (error == null)
                {
                    _logger.Information(
                        "Success - using publisher module '{moduleId}' ({image}) via methods.",
                        moduleId, publisherModule?.ImageName ?? "<unknown>");
                    return(publisher);
                }
                _logger.Debug("Publisher module {moduleId} method call uncuccessful." +
                              " Fallback to UA server...", moduleId, error);
            }

            using (var cts = new CancellationTokenSource()) {
                // Try shortcut of finding it on default publisher edge module
                var edgeUri       = new Uri($"opc.tcp://{kPublisherName}:{kPublisherPort}");
                var edgeEndpoints = await _discovery.FindEndpointsAsync(edgeUri, null, cts.Token);

                if (edgeEndpoints.Any())
                {
#if !TEST_PNP_SCAN
                    var publisher = new PublisherServerClient(_client, edgeUri, _logger);
                    var error     = await TestConnectivityAsync(publisher);

                    if (error == null)
                    {
                        _logger.Information("Using publisher server on localhost.");
                        return(publisher);
                    }
#endif
                }

                // Try shortcut of finding it on localhost
                var uri            = new Uri($"opc.tcp://{Utils.GetHostName()}:{kPublisherPort}");
                var localEndpoints = await _discovery.FindEndpointsAsync(uri, null, cts.Token);

                if (localEndpoints.Any())
                {
#if !TEST_PNP_SCAN
                    var publisher = new PublisherServerClient(_client, uri, _logger);
                    var error     = await TestConnectivityAsync(publisher);

                    if (error == null)
                    {
                        _logger.Information("Using publisher server on localhost.");
                        return(publisher);
                    }
#endif
                }

                // Discover publishers in network - use fast scanning
                _logger.Information("Try finding publishers in module network...");
                var addresses = new List <IPAddress>();
                using (var netscanner = new NetworkScanner(_logger,
                                                           (_, reply) => addresses.Add(reply.Address), false,
                                                           NetworkInformationEx.GetAllNetInterfaces(NetworkClass.Wired)
                                                           .Select(t => new AddressRange(t, false, 24)),
                                                           NetworkClass.Wired, 1000, // TODO: make configurable - intent is fast.
                                                           null, cts.Token)) {
                    await netscanner.Completion;
                }
                var publishers = new List <IPEndPoint>();
                var probe      = new ServerProbe(_logger);
                using (var portscan = new PortScanner(_logger,
                                                      addresses.Select(a => new IPEndPoint(a, kPublisherPort)),
                                                      (_, found) => {
                    cts.Cancel();     // Cancel on first found publisher.
                    publishers.Add(found);
                }, probe, null, null, null, cts.Token)) {
                    try {
                        await portscan.Completion;
                    }
                    catch (TaskCanceledException) {
                        // We got a port, and scanning is cancelled.
                    }
                }

                // We might have found a couple publishers - lets test them...
                foreach (var ep in publishers)
                {
                    var remoteEp = await ep.TryResolveAsync();

                    _logger.Information("Test publisher at address {remoteEp} in network.",
                                        remoteEp);
                    uri = new Uri("opc.tcp://" + remoteEp);
                    var endpoints = await _discovery.FindEndpointsAsync(uri, null,
                                                                        CancellationToken.None);

                    if (!endpoints.Any())
                    {
                        continue;
                    }
                    var publisher = new PublisherServerClient(_client, uri, _logger);
                    var error     = await TestConnectivityAsync(publisher);

                    if (error == null)
                    {
                        _logger.Information("Using publisher server at address {remoteEp}.",
                                            remoteEp);
                        return(publisher);
                    }
                }

                // TODO: Consider loading publisher as side car service?
                // No publisher found - will try again later.
                return(null);
            }
        }
コード例 #8
0
        /// <summary>
        /// Create request wrapper
        /// </summary>
        /// <param name="request"></param>
        /// <param name="networkClass"></param>
        /// <param name="isScan"></param>
        public DiscoveryRequest(DiscoveryRequestModel request,
                                NetworkClass networkClass = NetworkClass.Wired, bool isScan = false)
        {
            Request      = request?.Clone() ?? throw new ArgumentNullException(nameof(request));
            _cts         = new CancellationTokenSource();
            NetworkClass = networkClass;
            IsScan       = isScan;

            if (Request.Configuration == null)
            {
                Request.Configuration = new DiscoveryConfigModel();
            }

            if (Request.Discovery == null ||
                Request.Discovery == DiscoveryMode.Off)
            {
                // Report empty configuration if off, but keep the
                // discovery urls details from the original request
                Request.Configuration = new DiscoveryConfigModel()
                {
                    ActivationFilter = Request.Configuration.ActivationFilter?.Clone(),
                    DiscoveryUrls    = Request.Configuration.DiscoveryUrls?.ToList(),
                    Locales          = Request.Configuration.Locales?.ToList()
                };
                Request.Discovery = DiscoveryMode.Off;
                return;
            }

            // Parse whatever provided

            if (!string.IsNullOrEmpty(Request.Configuration.PortRangesToScan))
            {
                if (PortRange.TryParse(Request.Configuration.PortRangesToScan,
                                       out var ports))
                {
                    PortRanges = ports;
                    if (Request.Discovery == null)
                    {
                        Request.Discovery = DiscoveryMode.Fast;
                    }
                }
            }

            if (!string.IsNullOrEmpty(Request.Configuration.AddressRangesToScan))
            {
                if (AddressRange.TryParse(Request.Configuration.AddressRangesToScan,
                                          out var addresses))
                {
                    AddressRanges = addresses;
                    if (Request.Discovery == null)
                    {
                        Request.Discovery = DiscoveryMode.Fast;
                    }
                }
            }

            // Set default ranges

            if (AddressRanges == null)
            {
                IEnumerable <NetInterface> interfaces;
                switch (Request.Discovery)
                {
                case DiscoveryMode.Local:
                    interfaces    = NetworkInformationEx.GetAllNetInterfaces(NetworkClass);
                    AddressRanges = AddLocalHost(interfaces
                                                 .Select(t => new AddressRange(t, true)))
                                    .Distinct();
                    break;

                case DiscoveryMode.Fast:
                    interfaces    = NetworkInformationEx.GetAllNetInterfaces(NetworkClass.Wired);
                    AddressRanges = AddLocalHost(interfaces
                                                 .Select(t => new AddressRange(t, false, 24))
                                                 .Concat(interfaces
                                                         .Where(t => t.Gateway != null &&
                                                                !t.Gateway.Equals(IPAddress.Any) &&
                                                                !t.Gateway.Equals(IPAddress.None))
                                                         .Select(i => new AddressRange(i.Gateway, 32)))
                                                 .Distinct());
                    break;

                case DiscoveryMode.Network:
                case DiscoveryMode.Scan:
                    interfaces    = NetworkInformationEx.GetAllNetInterfaces(NetworkClass);
                    AddressRanges = AddLocalHost(interfaces
                                                 .Select(t => new AddressRange(t, false))
                                                 .Concat(interfaces
                                                         .Where(t => t.Gateway != null &&
                                                                !t.Gateway.Equals(IPAddress.Any) &&
                                                                !t.Gateway.Equals(IPAddress.None))
                                                         .Select(i => new AddressRange(i.Gateway, 32)))
                                                 .Distinct());
                    break;

                case DiscoveryMode.Off:
                default:
                    AddressRanges = Enumerable.Empty <AddressRange>();
                    break;
                }
            }

            if (PortRanges == null)
            {
                switch (Request.Discovery)
                {
                case DiscoveryMode.Local:
                    PortRanges = PortRange.All;
                    break;

                case DiscoveryMode.Fast:
                    PortRanges = PortRange.WellKnown;
                    break;

                case DiscoveryMode.Scan:
                    PortRanges = PortRange.Unassigned;
                    break;

                case DiscoveryMode.Network:
                    PortRanges = PortRange.OpcUa;
                    break;

                case DiscoveryMode.Off:
                default:
                    PortRanges = Enumerable.Empty <PortRange>();
                    break;
                }
            }

            // Update reported configuration with used settings

            if (AddressRanges != null && AddressRanges.Any())
            {
                Request.Configuration.AddressRangesToScan = AddressRange.Format(AddressRanges);
                TotalAddresses = AddressRanges?.Sum(r => r.Count) ?? 0;
            }

            if (PortRanges != null && PortRanges.Any())
            {
                Request.Configuration.PortRangesToScan = PortRange.Format(PortRanges);
                TotalPorts = PortRanges?.Sum(r => r.Count) ?? 0;
            }

            Request.Configuration.IdleTimeBetweenScans ??= kDefaultIdleTime;
            Request.Configuration.PortProbeTimeout ??= kDefaultPortProbeTimeout;
            Request.Configuration.NetworkProbeTimeout ??= kDefaultNetworkProbeTimeout;
        }
コード例 #9
0
        /// <summary>
        /// Create request wrapper
        /// </summary>
        /// <param name="request"></param>
        /// <param name="networkClass"></param>
        /// <param name="isScan"></param>
        public DiscoveryRequest(DiscoveryRequestModel request,
                                NetworkClass networkClass = NetworkClass.Wired, bool isScan = false)
        {
            Request      = request?.Clone() ?? throw new ArgumentNullException(nameof(request));
            _cts         = new CancellationTokenSource();
            NetworkClass = networkClass;
            IsScan       = isScan;

            if (request == null)
            {
                request = new DiscoveryRequestModel {
                    Discovery = DiscoveryMode.Off
                };
            }
            if (request.Configuration == null)
            {
                request.Configuration = new DiscoveryConfigModel();
            }

            if (!string.IsNullOrEmpty(request.Configuration.AddressRangesToScan))
            {
                if (AddressRange.TryParse(request.Configuration.AddressRangesToScan,
                                          out var addresses))
                {
                    AddressRanges = addresses;
                }
            }

            if (AddressRanges == null)
            {
                switch (request.Discovery)
                {
                case DiscoveryMode.Local:
                    AddressRanges = NetworkInformationEx.GetAllNetInterfaces(NetworkClass)
                                    .Select(t => new AddressRange(t, true)).Distinct();
                    break;

                case DiscoveryMode.Fast:
                    var interfaces = NetworkInformationEx.GetAllNetInterfaces(NetworkClass.Wired);
                    AddressRanges = interfaces.Select(t => new AddressRange(t, false, 24));
                    AddressRanges = AddressRanges.Concat(interfaces
                                                         .Where(t => t.Gateway != null &&
                                                                !t.Gateway.Equals(System.Net.IPAddress.Any) &&
                                                                !t.Gateway.Equals(System.Net.IPAddress.None))
                                                         .Select(i => new AddressRange(i.Gateway, 32)));
                    break;

                case DiscoveryMode.Off:
                    AddressRanges = Enumerable.Empty <AddressRange>();
                    break;

                case DiscoveryMode.Scan:
                    AddressRanges = NetworkInformationEx.GetAllNetInterfaces(NetworkClass)
                                    .Select(t => new AddressRange(t, false)).Distinct();
                    break;

                default:
                    AddressRanges = Enumerable.Empty <AddressRange>();
                    break;
                }
            }

            request.Configuration.AddressRangesToScan = AddressRange.Format(AddressRanges);

            if (!string.IsNullOrEmpty(request.Configuration.PortRangesToScan))
            {
                if (PortRange.TryParse(request.Configuration.PortRangesToScan,
                                       out var ports))
                {
                    PortRanges = ports;
                }
            }

            if (PortRanges == null)
            {
                switch (request.Discovery)
                {
                case DiscoveryMode.Local:
                    PortRanges = PortRange.All;
                    break;

                case DiscoveryMode.Fast:
                    PortRanges = PortRange.WellKnown;
                    break;

                case DiscoveryMode.Scan:
                    PortRanges = PortRange.Unassigned;
                    break;

                case DiscoveryMode.Off:
                    PortRanges = Enumerable.Empty <PortRange>();
                    break;

                default:
                    PortRanges = PortRange.OpcUa;
                    break;
                }
            }

            request.Configuration.PortRangesToScan = PortRange.Format(PortRanges);
            request.Configuration.IdleTimeBetweenScans ??= kDefaultIdleTime;
            request.Configuration.PortProbeTimeout ??= kDefaultPortProbeTimeout;
            request.Configuration.NetworkProbeTimeout ??= kDefaultNetworkProbeTimeout;

            TotalAddresses = AddressRanges?.Sum(r => r.Count) ?? 0;
            TotalPorts     = PortRanges?.Sum(r => r.Count) ?? 0;
        }