• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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