1 using System; 2 using System.Collections.Generic; 3 using System.Text.RegularExpressions; 4 using Lextm.SharpSnmpLib.Mib.Elements; 5 using Lextm.SharpSnmpLib.Mib.Elements.Entities; 6 using Lextm.SharpSnmpLib.Mib.Elements.Types; 7 8 namespace Lextm.SharpSnmpLib.Mib 9 { 10 public static class MibTypesResolver 11 { 12 private static readonly Regex _namedOidPathRegex = new Regex(@"^(?<Name>[^\(]+)\((?<Value>\d+)\)$"); 13 private static readonly List<IMibResolver> _resolver = new List<IMibResolver>(); 14 private static readonly List<IModule> _cachedModules = new List<IModule>(); 15 RegisterResolver(IMibResolver resolver)16 public static void RegisterResolver(IMibResolver resolver) 17 { 18 if (resolver != null) 19 { 20 _resolver.Add(resolver); 21 } 22 } 23 ResolveModule(string moduleName)24 public static IModule ResolveModule(string moduleName) 25 { 26 // check if module is already cached 27 foreach (MibModule cachedModule in _cachedModules) 28 { 29 if (cachedModule.Name == moduleName) 30 { 31 return cachedModule; 32 } 33 } 34 35 foreach (IMibResolver resolver in _resolver) 36 { 37 IModule resolvedModule = resolver.Resolve(moduleName); 38 if (resolvedModule != null) 39 { 40 ResolveTypes(resolvedModule); 41 _cachedModules.Add(resolvedModule); 42 return resolvedModule; 43 } 44 } 45 46 return null; 47 } 48 ResolveTypes(IModule module)49 public static void ResolveTypes(IModule module) 50 { 51 foreach (IEntity entity in module.Entities) 52 { 53 ITypeReferrer typeReferringEntity = entity as ITypeReferrer; 54 55 if (typeReferringEntity != null) 56 { 57 CheckTypeReferrer(module, typeReferringEntity); 58 } 59 } 60 61 if (!_cachedModules.Contains(module)) 62 { 63 _cachedModules.Add(module); 64 } 65 } 66 CheckTypeReferrer(IModule module, ITypeReferrer typeReferringEntity)67 private static void CheckTypeReferrer(IModule module, ITypeReferrer typeReferringEntity) 68 { 69 TypeAssignment unknownType = typeReferringEntity.ReferredType as TypeAssignment; 70 if (unknownType != null) 71 { 72 typeReferringEntity.ReferredType = ResolveType(module, unknownType); 73 74 if (typeReferringEntity.ReferredType is TypeAssignment) 75 { 76 Console.WriteLine(String.Format("Could not resolve type '{0}' declared in module '{1}'", (typeReferringEntity.ReferredType as TypeAssignment).Type, typeReferringEntity.ReferredType.Module.Name)); 77 } 78 } 79 80 ITypeReferrer nextTypeReferringEntity = typeReferringEntity.ReferredType as ITypeReferrer; 81 if (nextTypeReferringEntity != null) 82 { 83 CheckTypeReferrer(module, nextTypeReferringEntity); 84 } 85 } 86 ResolveType(IModule module, TypeAssignment type)87 public static ITypeAssignment ResolveType(IModule module, TypeAssignment type) 88 { 89 ITypeAssignment result = ResolveDeclaration(module, type.Type) as ITypeAssignment; 90 91 return (result != null) ? result : type; 92 } 93 ResolveDeclaration(IModule module, string name)94 public static IDeclaration ResolveDeclaration(IModule module, string name) 95 { 96 if ((module == null) || String.IsNullOrEmpty(name)) 97 { 98 return null; 99 } 100 101 // check module internal types 102 foreach (IDeclaration decl in module.Declarations) 103 { 104 if (decl.Name == name) 105 { 106 return decl; 107 } 108 } 109 110 // check if type is imported 111 if (module.Imports != null) 112 { 113 ImportsFrom imports = module.Imports.GetImportFromType(name); 114 if (imports != null) 115 { 116 IModule importedModule = ResolveModule(imports.Module); 117 if (importedModule != null) 118 { 119 return ResolveDeclaration(importedModule, name); 120 } 121 } 122 } 123 124 return null; 125 } 126 ResolveOid(IEntity entity)127 public static ObjectIdentifier ResolveOid(IEntity entity) 128 { 129 ObjectIdentifier result = new ObjectIdentifier(); 130 131 if (entity != null) 132 { 133 ResolveOid(entity, result); 134 } 135 136 return result; 137 } 138 ResolveOid(IEntity entity, ObjectIdentifier result)139 private static void ResolveOid(IEntity entity, ObjectIdentifier result) 140 { 141 result.Prepend(entity.Name, entity.Value); 142 143 // check parent 144 if (!String.IsNullOrEmpty(entity.Parent)) 145 { 146 string[] pathParts = entity.Parent.Split('.'); 147 uint value; 148 149 // all parts except the first should have their value directly or indirectly with them 150 if (pathParts.Length > 1) 151 { 152 for (int i=pathParts.Length-1; i>=1; i--) 153 { 154 if (uint.TryParse(pathParts[i], out value)) 155 { 156 result.Prepend("", value); 157 } 158 else 159 { 160 Match m = _namedOidPathRegex.Match(pathParts[i]); 161 if (m.Success) 162 { 163 result.Prepend(m.Groups["Name"].Value, uint.Parse(m.Groups["Value"].Value)); 164 } 165 else 166 { 167 throw new MibException("Invalid OID path detected for entity '" + entity.Name + "' in module '" + entity.Module + "'!"); 168 } 169 } 170 } 171 } 172 173 // parse root part: either another entity or a standard root object 174 if (IsOidRoot(pathParts[0], out value)) 175 { 176 result.Prepend(pathParts[0], value); 177 } 178 else 179 { 180 // try to find entity inside this module 181 if (entity.Module != null) 182 { 183 entity = ResolveDeclaration(entity.Module, pathParts[0]) as IEntity; 184 185 if (entity != null) 186 { 187 ResolveOid(entity, result); 188 } 189 else 190 { 191 result.Prepend("", uint.MaxValue); 192 } 193 } 194 else 195 { 196 result.Prepend("", uint.MaxValue); 197 } 198 } 199 } 200 } 201 IsOidRoot(string name, out uint value)202 public static bool IsOidRoot(string name, out uint value) 203 { 204 value = uint.MaxValue; 205 206 switch (name) 207 { 208 case "ccitt": value = 0; return true; 209 case "iso": value = 1; return true; 210 case "joint-iso-ccitt": value = 2; return true; 211 } 212 213 return false; 214 } 215 } 216 } 217