1 /* 2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 25 * OF SUCH DAMAGE. 26 * 27 * This file is part of the lwIP TCP/IP stack. 28 * 29 * Author: Martin Hentschel <info@cl-soft.de> 30 * 31 */ 32 33 using System; 34 using System.Collections.Generic; 35 using CCodeGeneration; 36 37 namespace LwipSnmpCodeGeneration 38 { 39 public class SnmpScalarNode: SnmpNode 40 { 41 protected const string LocalValueName = "v"; // name of (casted) local value variable 42 43 private SnmpDataType dataType; 44 private SnmpAccessMode accessMode; 45 private readonly List<IRestriction> restrictions = new List<IRestriction>(); 46 47 private bool useExternalMethods = false; 48 private string externalGetMethod; 49 private string externalTestMethod; 50 private string externalSetMethod; 51 52 SnmpScalarNode(SnmpTreeNode parentNode)53 public SnmpScalarNode(SnmpTreeNode parentNode) 54 : base(parentNode) 55 { 56 } 57 58 public override string FullNodeName 59 { 60 get { return this.Name.ToLowerInvariant() + "_scalar"; } 61 } 62 63 public SnmpDataType DataType 64 { 65 get { return this.dataType; } 66 set { this.dataType = value; } 67 } 68 69 public List<IRestriction> Restrictions 70 { 71 get { return this.restrictions; } 72 } 73 74 public SnmpAccessMode AccessMode 75 { 76 get { return this.accessMode; } 77 set { this.accessMode = value; } 78 } 79 80 public virtual string FixedValueLength 81 { 82 get { return null; } 83 } 84 85 /// <summary> 86 /// If scalar is used as a table index its value becomes part of the OID. This value returns how many OID parts are required to represent this value. 87 /// </summary> 88 public virtual int OidRepresentationLen 89 { 90 get { return -1; } 91 } 92 93 public bool UseExternalMethods 94 { 95 get { return this.useExternalMethods; } 96 set { this.useExternalMethods = value; } 97 } 98 99 public string ExternalGetMethod 100 { 101 get { return this.externalGetMethod; } 102 set { this.externalGetMethod = value; } 103 } 104 public string ExternalTestMethod 105 { 106 get { return this.externalTestMethod; } 107 set { this.externalTestMethod = value; } 108 } 109 public string ExternalSetMethod 110 { 111 get { return this.externalSetMethod; } 112 set { this.externalSetMethod = value; } 113 } 114 GenerateCode(MibCFile mibFile)115 public override void GenerateCode(MibCFile mibFile) 116 { 117 string getMethodName; 118 string testMethodName; 119 string setMethodName; 120 121 if (this.useExternalMethods) 122 { 123 getMethodName = this.externalGetMethod; 124 testMethodName = this.externalTestMethod; 125 setMethodName = this.externalSetMethod; 126 } 127 else 128 { 129 getMethodName = LwipDefs.Null; 130 testMethodName = LwipDefs.Null; 131 setMethodName = LwipDefs.Null; 132 133 if ((this.accessMode == SnmpAccessMode.ReadWrite) || (this.accessMode == SnmpAccessMode.ReadOnly)) 134 { 135 FunctionDeclaration getMethodDecl = new FunctionDeclaration(this.Name + LwipDefs.FnctSuffix_GetValue, isStatic: true); 136 getMethodDecl.Parameter.Add(new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*")); 137 getMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); 138 getMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_S16); 139 mibFile.Declarations.Add(getMethodDecl); 140 141 Function getMethod = Function.FromDeclaration(getMethodDecl); 142 getMethodName = getMethod.Name; 143 144 VariableDeclaration returnValue = new VariableDeclaration((VariableType)getMethod.ReturnType.Clone()); 145 returnValue.Type.Name = "value_len"; 146 getMethod.Declarations.Add(returnValue); 147 getMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getMethod.Parameter[0].Name); 148 149 bool valueVarUsed = false; 150 GenerateGetMethodCode(getMethod, getMethod.Parameter[1].Name, ref valueVarUsed, returnValue.Type.Name); 151 if (!valueVarUsed) 152 { 153 getMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getMethod.Parameter[1].Name); 154 } 155 156 getMethod.AddCodeFormat("return {0};", returnValue.Type.Name); 157 158 mibFile.Implementation.Add(getMethod); 159 } 160 161 if ((this.accessMode == SnmpAccessMode.ReadWrite) || (this.accessMode == SnmpAccessMode.WriteOnly)) 162 { 163 bool valueVarUsed; 164 bool lenVarUsed; 165 VariableDeclaration returnValue; 166 167 if (this.restrictions.Count > 0) 168 { 169 FunctionDeclaration testMethodDecl = new FunctionDeclaration(this.Name + LwipDefs.FnctSuffix_SetTest, isStatic: true); 170 testMethodDecl.Parameter.Add(new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*")); 171 testMethodDecl.Parameter.Add(new VariableType("len", LwipDefs.Vt_U16)); 172 testMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); 173 testMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); 174 mibFile.Declarations.Add(testMethodDecl); 175 176 Function testMethod = Function.FromDeclaration(testMethodDecl); 177 testMethodName = testMethod.Name; 178 179 returnValue = new VariableDeclaration((VariableType)testMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_WrongValue); 180 returnValue.Type.Name = "err"; 181 testMethod.Declarations.Add(returnValue); 182 testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[0].Name); 183 184 valueVarUsed = false; 185 lenVarUsed = false; 186 187 GenerateTestMethodCode(testMethod, testMethod.Parameter[2].Name, ref valueVarUsed, testMethod.Parameter[1].Name, ref lenVarUsed, returnValue.Type.Name); 188 189 if (!valueVarUsed) 190 { 191 testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[2].Name); 192 } 193 if (!lenVarUsed) 194 { 195 testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[1].Name); 196 } 197 198 testMethod.AddCodeFormat("return {0};", returnValue.Type.Name); 199 200 mibFile.Implementation.Add(testMethod); 201 202 } 203 else 204 { 205 testMethodName = LwipDefs.FnctName_SetTest_Ok; 206 } 207 208 FunctionDeclaration setMethodDecl = null; 209 setMethodDecl = new FunctionDeclaration(this.Name + LwipDefs.FnctSuffix_SetValue, isStatic: true); 210 setMethodDecl.Parameter.Add(new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*")); 211 setMethodDecl.Parameter.Add(new VariableType("len", LwipDefs.Vt_U16)); 212 setMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); 213 setMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); 214 mibFile.Declarations.Add(setMethodDecl); 215 216 Function setMethod = Function.FromDeclaration(setMethodDecl); 217 setMethodName = setMethod.Name; 218 219 returnValue = new VariableDeclaration((VariableType)setMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_Ok); 220 returnValue.Type.Name = "err"; 221 setMethod.Declarations.Add(returnValue); 222 setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[0].Name); 223 224 valueVarUsed = false; 225 lenVarUsed = false; 226 227 GenerateSetMethodCode(setMethod, setMethod.Parameter[2].Name, ref valueVarUsed, setMethod.Parameter[1].Name, ref lenVarUsed, returnValue.Type.Name); 228 229 if (!valueVarUsed) 230 { 231 setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[2].Name); 232 } 233 if (!lenVarUsed) 234 { 235 setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[1].Name); 236 } 237 238 setMethod.AddCodeFormat("return {0};", returnValue.Type.Name); 239 240 mibFile.Implementation.Add(setMethod); 241 } 242 } 243 244 // create and add node declaration 245 string nodeInitialization; 246 if (this.accessMode == SnmpAccessMode.ReadOnly) 247 { 248 nodeInitialization = String.Format("SNMP_SCALAR_CREATE_NODE_READONLY({0}, {1}, {2})", 249 this.Oid, 250 LwipDefs.GetAsn1DefForSnmpDataType(this.dataType), 251 getMethodName); 252 } 253 else 254 { 255 nodeInitialization = String.Format("SNMP_SCALAR_CREATE_NODE({0}, {1}, {2}, {3}, {4}, {5})", 256 this.Oid, 257 LwipDefs.GetLwipDefForSnmpAccessMode(this.accessMode), 258 LwipDefs.GetAsn1DefForSnmpDataType(this.dataType), 259 getMethodName, 260 testMethodName, 261 setMethodName); 262 } 263 264 mibFile.Declarations.Add(new VariableDeclaration( 265 new VariableType(this.FullNodeName, LwipDefs.Vt_StScalarNode, null, ConstType.Value), 266 nodeInitialization, isStatic: true)); 267 } 268 GenerateGetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string retLenVarName)269 public virtual void GenerateGetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string retLenVarName) 270 { 271 bool localValueVarUsed; 272 if (GenerateValueDeclaration(container, LocalValueName, valueVarName)) 273 { 274 valueVarUsed = true; 275 localValueVarUsed = false; 276 } 277 else 278 { 279 localValueVarUsed = true; // do not generate UNUSED_ARG code 280 } 281 282 if (this.FixedValueLength == null) 283 { 284 // check that value with variable length fits into buffer 285 container.AddElement(new Comment(String.Format("TODO: take care that value with variable length fits into buffer: ({0} <= SNMP_MAX_VALUE_SIZE)", retLenVarName), singleLine: true)); 286 } 287 288 GenerateGetMethodCodeCore(container, LocalValueName, ref localValueVarUsed, retLenVarName); 289 if (!localValueVarUsed) 290 { 291 container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", LocalValueName)); 292 } 293 } 294 GenerateGetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string retLenVarName)295 protected virtual void GenerateGetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string retLenVarName) 296 { 297 container.AddElement(new Comment(String.Format("TODO: put requested value to '*{0}' here", localValueVarName), singleLine: true)); 298 container.AddCodeFormat("{0} = {1};", 299 retLenVarName, 300 (!String.IsNullOrWhiteSpace(this.FixedValueLength)) ? this.FixedValueLength : "0"); 301 } 302 GenerateTestMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName)303 public virtual void GenerateTestMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) 304 { 305 if (this.Restrictions.Count > 0) 306 { 307 bool localVarUsed; 308 if (GenerateValueDeclaration(container, LocalValueName, valueVarName)) 309 { 310 valueVarUsed = true; 311 localVarUsed = false; 312 } 313 else 314 { 315 localVarUsed = true; // do not generate UNUSED_ARG code 316 } 317 318 if (!String.IsNullOrWhiteSpace(this.FixedValueLength)) 319 { 320 // check for fixed value 321 container.AddCodeFormat("LWIP_ASSERT(\"Invalid length for datatype\", ({0} == {1}));", lenVarName, this.FixedValueLength); 322 lenVarUsed = true; 323 } 324 325 GenerateTestMethodCodeCore(container, LocalValueName, ref localVarUsed, lenVarName, ref lenVarUsed, retErrVarName); 326 327 if (!localVarUsed) 328 { 329 container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", LocalValueName)); 330 } 331 } 332 else 333 { 334 container.AddCodeFormat("{0} = {1};", retErrVarName, LwipDefs.Def_ErrorCode_Ok); 335 } 336 } 337 GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName)338 protected virtual void GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) 339 { 340 container.AddElement(new Comment(String.Format("TODO: test new value here:\nif (*{0} == ) {1} = {2};", localValueVarName, retErrVarName, LwipDefs.Def_ErrorCode_Ok))); 341 } 342 GenerateSetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName)343 public virtual void GenerateSetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) 344 { 345 bool localVarUsed; 346 if (GenerateValueDeclaration(container, LocalValueName, valueVarName)) 347 { 348 valueVarUsed = true; 349 localVarUsed = false; 350 } 351 else 352 { 353 localVarUsed = true; // do not generate UNUSED_ARG code 354 } 355 356 GenerateSetMethodCodeCore(container, LocalValueName, ref localVarUsed, lenVarName, ref lenVarUsed, retErrVarName); 357 358 if (!localVarUsed) 359 { 360 container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", LocalValueName)); 361 } 362 } 363 GenerateSetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName)364 protected virtual void GenerateSetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) 365 { 366 container.AddElement(new Comment(String.Format("TODO: store new value contained in '*{0}' here", localValueVarName), singleLine: true)); 367 } 368 369 GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName)370 protected virtual bool GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName) 371 { 372 container.AddDeclaration(new VariableDeclaration( 373 new VariableType(variableName, LwipDefs.Vt_U8, "*"), 374 "(" + new VariableType(null, LwipDefs.Vt_U8, "*") + ")" + sourceName)); 375 376 return true; 377 } 378 CreateFromDatatype(SnmpDataType dataType, SnmpTreeNode parentNode)379 public static SnmpScalarNode CreateFromDatatype(SnmpDataType dataType, SnmpTreeNode parentNode) 380 { 381 switch (dataType) 382 { 383 case SnmpDataType.Integer: 384 return new SnmpScalarNodeInt(parentNode); 385 386 case SnmpDataType.Gauge: 387 case SnmpDataType.Counter: 388 case SnmpDataType.TimeTicks: 389 return new SnmpScalarNodeUint(dataType, parentNode); 390 } 391 392 return new SnmpScalarNode(parentNode); 393 } 394 } 395 } 396