/// <summary>
        /// Queries the given OIDs and returns the value as string or null if the OID is not available.
        /// </summary>
        /// <param name="lowerLayer">The lower layer engine to extend.</param>
        /// <param name="oid">The OID to query.</param>
        /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param>
        /// <param name="encoding">If not null, will try to detect whether the string is a hex string and then use the given encoding to decode it.</param>
        /// <returns>The OID's value as string or null if the OID is not available.</returns>
        public static string QueryAsString(this ISnmpLowerLayer lowerLayer, Oid oid, string what, Encoding encoding = null)
        {
            VbCollection result = lowerLayer.Query(oid);
            var          retVal = result[oid]?.Value?.ToString();

            if (retVal == null)
            {
                log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as string returned null");
            }

            if ((encoding != null) && (retVal.Length > 0))
            {
                bool couldBeHexString = true;
                for (int i = 2; i < retVal.Length; i += 3)
                {
                    if (retVal[i] != ' ')
                    {
                        couldBeHexString = false;
                        break;
                    }
                }

                if (couldBeHexString)
                {
                    retVal = encoding.GetString(retVal.HexStringToByteArray(' '));
                }
            }

            return(retVal);
        }
        /// <summary>
        /// Queries the given OIDs and returns the value as OID or null if the OID is not available.
        /// </summary>
        /// <param name="lowerLayer">The lower layer engine to extend.</param>
        /// <param name="oid">The OID to query.</param>
        /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param>
        /// <returns>The OID's value as OID or null if the OID is not available.</returns>
        public static Oid QueryAsOid(this ISnmpLowerLayer lowerLayer, Oid oid, string what)
        {
            VbCollection result = lowerLayer.Query(oid);
            var          retVal = result[oid]?.Value as Oid;

            if (retVal == null)
            {
                log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as OID returned null");
            }

            return(retVal);
        }
        /// <summary>
        /// Queries the given OIDs and returns the value as string or null if the OID is not available.
        /// </summary>
        /// <param name="lowerLayer">The lower layer engine to extend.</param>
        /// <param name="oid">The OID to query.</param>
        /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param>
        /// <returns>The OID's value as int or <see cref="int.MinValue" /> if the OID is not available.</returns>
        public static int QueryAsInt(this ISnmpLowerLayer lowerLayer, Oid oid, string what)
        {
            VbCollection result = lowerLayer.Query(oid);

            int retVal = int.MinValue;

            if (!(result[oid]?.Value?.TryToInt(out retVal) ?? false))
            {
                log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as string returned null");
            }

            return(retVal);
        }
        /// <summary>
        /// Queries the given OIDs and returns the value as <see cref="TimeSpan" /> or null if the OID is not available.
        /// </summary>
        /// <param name="lowerLayer">The lower layer engine to extend.</param>
        /// <param name="oid">The OID to query.</param>
        /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param>
        /// <returns>The OID's value as <see cref="TimeSpan" /> or null if the OID is not available or cannot be parsed as <see cref="TimeSpan" />.</returns>
        public static TimeSpan?QueryAsTimeSpan(this ISnmpLowerLayer lowerLayer, Oid oid, string what)
        {
            VbCollection result = lowerLayer.Query(oid);
            var          retVal = result[oid]?.Value as TimeTicks;

            if (retVal == null)
            {
                log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as TimeTicks returned null");
                return(null);
            }

            return(TimeSpan.FromMilliseconds(retVal.Milliseconds));
        }
        /// <summary>
        /// Queries the given OIDs and returns the value as string or null if the OID is not available.
        /// </summary>
        /// <param name="lowerLayer">The lower layer engine to extend.</param>
        /// <param name="oids">The OIDs list to query.</param>
        /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param>
        /// <returns>The OID's value as int or or <see cref="int.MinValue" /> if the OID is not available.</returns>
        public static Dictionary <Oid, int> QueryAsInt(this ISnmpLowerLayer lowerLayer, IEnumerable <Oid> oids, string what)
        {
            if (oids == null)
            {
                throw new ArgumentNullException(nameof(oids), "The array of oids to query is null");
            }

            VbCollection queryResult = lowerLayer.Query(oids);

            return(queryResult.ToDictionary(qr => qr.Oid, qr =>
            {
                int retVal = int.MinValue;
                if (!(qr.Value?.TryToInt(out retVal) ?? false))
                {
                    log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as Dictionary<Oid, int>: Conversion to int returned null for response '{qr}'");
                }

                return retVal;
            }));
        }
Exemple #6
0
        /// <inheritdoc />
        public override IDeviceHandler CreateHandler(ISnmpLowerLayer lowerLayer, IQuerierOptions options)
        {
            if (!this.detectionId.HasValue)
            {
                var ex = new InvalidOperationException("Cannot perform CreateHandler() without previous and successful call to IsApplicable");
                this.CollectException("UbntSnmp: CreateHandler(ISnmpLowerLayer, IQuerierOptions)", ex);
                throw ex;
            }

            try
            {
                List <Oid> queryList = new List <Oid>();

                Oid osVersionOid = null;
                if (string.IsNullOrWhiteSpace(this.osDetectedVersion))
                {
                    osVersionOid = OsVersionRootOid + new Oid(new uint[] { this.detectionId.Value });
                    queryList.Add(osVersionOid);
                }

                Oid modelOid = null;
                if (string.IsNullOrWhiteSpace(this.detectedModel))
                {
                    modelOid = ModelRootOid + new Oid(new uint[] { this.detectionId.Value });
                    queryList.Add(modelOid);
                }

                VbCollection osVersionCollection = null;
                if (queryList.Count > 0)
                {
                    osVersionCollection = lowerLayer.Query(queryList);
                }

                string osVersionString = (osVersionOid != null)
                    ? osVersionCollection[osVersionOid].Value.ToString()
                    : this.osDetectedVersion;

                Match           match     = OsVersionExtractionRegex.Match(osVersionString);
                SemanticVersion osVersion = match.Success ? match.Groups[1].Value.ToSemanticVersion() : null;

                string model = (modelOid != null)
                    ? osVersionCollection[modelOid].Value.ToString()
                    : this.detectedModel;

                if (string.IsNullOrWhiteSpace(model))
                {
                    var info = $"Model (retrieved using OID '{modelOid}') is null, empty or white-space-only";
                    log.Warn(info);
                    var ex = new HamnetSnmpException(info, lowerLayer?.Address?.ToString());
                    this.CollectException("UbntSnmp: No model", ex);
                    throw ex;
                }

                log.Info($"Detected device '{lowerLayer.Address}' as Ubiquiti '{model}' v '{osVersion}'");

                DeviceVersion            deviceVersion;
                IDeviceSpecificOidLookup oidTable = this.ObtainOidTable(model.Trim(), osVersion, out deviceVersion, lowerLayer?.Address);
                if (string.IsNullOrWhiteSpace(deviceVersion.HandlerClassName))
                {
                    return((model == AirFiberFakeModelString)
                        ? new UbiquitiAirFiberDeviceHandler(lowerLayer, oidTable, osVersion, model, options) as IDeviceHandler
                        : new UbiquitiAirOsAbove56DeviceHandler(lowerLayer, oidTable, osVersion, model, options) as IDeviceHandler);
                }
                else
                {
                    return(this.GetHandlerViaReflection(deviceVersion.HandlerClassName, lowerLayer, oidTable, osVersion, model, options));
                }
            }
            catch (Exception ex)
            {
                this.CollectException("UbntSnmp: Model detection and OID lookup", ex);

                // we want to catch and nest the exception here as the APIs involved are not able to append the infomration for which
                // device (i.e. IP address) the exception is for
                throw new HamnetSnmpException($"Failed to create handler for Ubiquiti device '{lowerLayer.Address}': {ex.Message}", ex, lowerLayer?.Address?.ToString());
            }
        }