www.pudn.com > SNMPDLL_src.zip > SNMPUtils.cs


//////////////////////////////////////////////////////////////////////////////// 
// 
// SNMP++.NET v. 1.14 (2005-02-07 09:30:00) 
// 
// Copyright (c) 2003-2004 Military Communication Institute, Zegrze, Poland 
// Author: Marek Malowidzki 
// 
// This software is based on SNMP++ from Jochen Katz, Frank Fock, 
// which is in turn based on SNMP++2.6 from Hewlett Packard: 
// 
// Copyright (c) 2001-2003 Jochen Katz, Frank Fock 
// 
// Copyright (c) 1996 
// Hewlett-Packard Company 
// 
// ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS. 
// Permission to use, copy, modify, distribute and/or sell this software  
// and/or its documentation is hereby granted without fee. User agrees  
// to display the above copyright notice and this license notice in all  
// copies of the software and any documentation of the software. User  
// agrees to assume all liability for the use of the software;  
// Hewlett-Packard, Jochen Katz and Military Communication Institute make 
// no representations about the suitability of this software for any purpose. 
// It is provided  "AS-IS" without warranty of any kind, either express 
// or implied. User hereby grants a royalty-free license to any and all 
// derivatives based upon this software code base.  
//  
// 
// This class has been transform by Olivier Griffet to match with the SNMPDll  
//////////////////////////////////////////////////////////////////////////////// 
 
using System; 
using System.Diagnostics; 
using System.IO; 
using System.Reflection; 
using System.Threading; 
using Org.Snmp.Snmp_pp; 
using System.Collections; 
 
namespace Org.Snmp.Snmp_pp 
{ 
	 
	//////////////////////////////////////////////////////////////////////////// 
	// Barrier - a simple barrier for threads synchronization. 
	//////////////////////////////////////////////////////////////////////////// 
	 
	internal sealed class Barrier 
	{ 
		private readonly object	lock_ = new object(); 
		private readonly uint	n_; 
		private uint			c_; 
 
		public Barrier(uint n) { n_ = n; } 
 
		public uint Size  { get { return n_; } } 
 
		public uint Count { get { return c_; } } 
 
		public void Enter() 
		{ 
			lock (lock_) 
			{ 
				if (++c_ == n_) 
				{ 
					c_ = 0; 
					Monitor.PulseAll(lock_); 
				} 
				else 
				{ 
					Monitor.Wait(lock_); 
				} 
			} 
		} 
	} 
 
	//////////////////////////////////////////////////////////////////////////// 
	// MemoryStats - this simple class drops memory usage statistics to files. 
	//////////////////////////////////////////////////////////////////////////// 
 
	internal sealed class MemoryStats 
	{ 
		private readonly string	filePfx_; 
		private volatile int	nStats_; 
 
		public MemoryStats(string filePfx) { filePfx_ = filePfx; } 
 
		public int StatsCount { get { return nStats_; } } 
 
		public void Collect() 
		{ 
			DateTime start = DateTime.Now; 
			try 
			{ 
				using (StreamWriter mn = new StreamWriter(filePfx_ + ".managed"), 
						   hm = new StreamWriter(filePfx_ + ".heaps")) 
				{ 
					mn.AutoFlush = true; 
					hm.AutoFlush = true; 
 
					while (true) 
					{ 
						long managedMemory = GC.GetTotalMemory(false), 
							heapsMemory   = MemoryManager.GetHeapsMemory(); 
 
						TimeSpan tspan = DateTime.Now.Subtract(start); 
						double tmsec = tspan.TotalMilliseconds, 
							sec  = tmsec / 1000.0; 
						int msec = (int) ((long) tmsec % 1000); 
 
						mn.WriteLine("{0}\t{1}", sec, managedMemory); 
						if (heapsMemory < 0) 
							hm.Write("# ");		// write error code as a comment 
						hm.WriteLine("{0}\t{1}", sec, heapsMemory); 
						nStats_++; 
 
						Thread.Sleep(1000 - msec); 
					} 
				} 
			} 
			catch (ThreadInterruptedException) {} 
		} 
 
		public void WaitForNextStat() 
		{ 
			int nstat = nStats_; 
			do 
			{ 
				Thread.Sleep(100); 
			} 
			while (nstat == nStats_); 
		} 
	} 
	 
	//////////////////////////////////////////////////////////////////////////// 
	// Manager -  this is the class that demonstrates the use of the SNMP++.NET 
	// API. It may look excessively complex as it tries to present most options 
	// and scenarios but the real SNMP code is really straightforward. 
	//////////////////////////////////////////////////////////////////////////// 
 
	public sealed class Manager 
	{ 
		#region method 
		private readonly int		id_; 
		private readonly Snmp		snmp_; 
		private readonly SnmpTarget target_; 
		private readonly Pdu		pdu_; 
		private readonly OperType	operType_; 
		private readonly TableReader.GetTableOptions tableOptions_; 
		private readonly uint		nRepeats_; 
		private readonly bool		asyncSync_, 
			debug_; 
		private readonly Barrier	barrier_; 
		private volatile int		nCalls_, 
			nRepd_; 
		private volatile Hashtable htResult_; 
		private Exception			exc_; 
 
		private enum OperType {Simple, Walk, Table}; 
 
		private Manager(int id, 
			Snmp snmp, SnmpTarget target, Pdu pdu, OperType operType, 
			ref TableReader.GetTableOptions tableOptions, Barrier barrier, 
			uint nRepeats, bool asyncSync, bool debug) 
		{ 
			id_        = id; 
			snmp_      = snmp; 
			target_    = target; 
			pdu_       = pdu; 
			operType_  = operType; 
			tableOptions_ = tableOptions; 
			barrier_   = barrier; 
			nRepeats_  = nRepeats; 
			asyncSync_ = asyncSync; 
			debug_     = debug; 
		} 
 
		private Manager Clone(int id) 
		{ 
			TableReader.GetTableOptions to = tableOptions_; 
			return new Manager(id, snmp_, target_, pdu_, 
				operType_, ref to, 
				barrier_, nRepeats_, asyncSync_, debug_); 
		} 
 
		private void DoSnmp() 
		{ 
			barrier_.Enter(); 
			try 
			{ 
				TableReader.GetTableOptions to = tableOptions_; 
				Hashtable htResp = DoSnmp(snmp_, target_, pdu_, 
					operType_, ref to, 
					nRepeats_, asyncSync_, debug_); 
				int count = (int)htResp["count"]; 
				htResult_ = htResp; 
				lock (barrier_) 
				{ 
					nCalls_ += count; 
				} 
			} 
			catch (Exception e) 
			{ 
				lock (barrier_) 
				{ 
					exc_ = e; 
				} 
				Console.Error.WriteLine(e); 
			} 
			finally 
			{ 
				barrier_.Enter(); 
			} 
		} 
 
		private void AsyncDoSnmp() 
		{ 
			if (operType_ != OperType.Table) 
			{ 
				AsyncDoSnmp(snmp_, target_, pdu_, 
					new AsyncCallback(ResponseCallback), this); 
			} 
			else 
			{ 
				Oid[] columnOids = GetColumnOids(pdu_); 
				Pdu pdu = pdu_.Clone(new Vb[0]);	// not really needed; for test purposes 
				TableReader.BeginGetTable(snmp_, pdu, target_, 
					columnOids, tableOptions_, 
					new AsyncCallback(TableResponseCallback), columnOids); 
			} 
		} 
 
		private void ResponseCallback(IAsyncResult ar) 
		{ 
			if (ar.AsyncState != this) 
			{ 
				throw new ArgumentException( 
					"Fatal: invalid data passed to callback"); 
			} 
 
			using (MemoryManager.GetMemoryManager()) 
			{ 
				Pdu pdu; 
				try 
				{ 
					pdu = snmp_.EndInvoke(ar); 
				} 
				catch (Exception e) 
				{ 
					Console.Error.WriteLine(e); 
					barrier_.Enter(); 
					return; 
				} 
 
				bool show = (nRepd_ % 1000) == 0; 
				if (show || debug_) 
				{ 
					//ManagerUtilities.PrintPdu(Console.Out,"Callback PDU:", pdu, true, id_.ToString()); 
				} 
 
				Pdu nextPdu = pdu_; 
				if (operType_ == OperType.Walk) 
				{ 
					Vb nextVb = pdu[0]; 
					Oid nextOid = nextVb.Oid; 
					Oid rootOid = pdu_[0].Oid; 
					if (nextOid.StartsWith(rootOid)) 
					{ 
						if (show) 
						{ 
							SnmpSyntax val = nextVb.Value; 
							SmiSyntax type = val != null ? val.SmiSyntax : SmiSyntax.Null; 
							Console.WriteLine("[{0}]: {1},{2},{3}", id_, nextOid, val, type); 
						} 
 
						nRepd_--; 
						nextPdu = pdu_.Clone(new Vb(nextOid)); 
					} 
				} 
 
				nCalls_++; 
				nRepd_++; 
				if (nRepd_ < nRepeats_) 
				{ 
					AsyncDoSnmp(snmp_, target_, nextPdu, 
						new AsyncCallback(ResponseCallback), this); 
				} 
				else 
				{ 
					barrier_.Enter(); 
				} 
			} 
		} 
 
		private void TableResponseCallback(IAsyncResult ar) 
		{ 
			Vb[][] vbTable; 
			Oid[] columnOids = (Oid[]) ar.AsyncState; 
			try 
			{ 
				int nRequests = 0; 
				vbTable = TableReader.EndGetTable(ar, ref nRequests); 
				nCalls_ += nRequests; 
				TableReader.PrintTable(Console.Out, columnOids, vbTable); 
			} 
			catch (Exception e) 
			{ 
				Console.Error.WriteLine(e); 
			} 
			finally 
			{ 
				barrier_.Enter(); 
			} 
		} 
 
		private Barrier Barrier 
		{ 
			get { return barrier_; } 
		} 
 
		private int Calls 
		{ 
			get 
			{ 
				if (exc_ != null) 
				{ 
					throw exc_; 
				} 
				return nCalls_; 
			} 
		} 
 
		private Hashtable Results 
		{ 
			get 
			{ 
				if (exc_ != null) 
				{ 
					throw exc_; 
				} 
				return htResult_; 
			} 
		} 
 
		private static void PrintPdu(TextWriter os, string text, Pdu pdu, bool debug) 
		{ 
			ManagerUtilities.PrintPdu(os, text, pdu, debug, Thread.CurrentThread.Name); 
		} 
 
		private static Pdu Invoke(Snmp snmp, Pdu pdu, SnmpTarget target, bool asyncSync) 
		{ 
			if (asyncSync) 
			{ 
				IAsyncResult ar = snmp.BeginInvoke(pdu, target, null, null); 
				return snmp.EndInvoke(ar); 
			} 
			else 
			{ 
				return snmp.Invoke(pdu, target); 
			} 
		} 
				 
		private static void Walk(Snmp snmp, Pdu pdu, SnmpTarget target, 
			bool asyncSync, bool show, bool debug, ref int ncalls) 
		{ 
			Console.WriteLine("Rentre dans le Walk"); 
			string thName = Thread.CurrentThread.Name; 
			Oid rootOid = pdu[0].Oid; 
			while (true) 
			{ 
				if (debug) 
				{ 
					PrintPdu(Console.Out, "Sending PDU to target " + target, pdu, debug); 
				} 
 
				Pdu resp = Invoke(snmp, pdu, target, asyncSync); 
				ncalls++; 
 
				Vb nextVb = resp[0]; 
				Oid nextOid = nextVb.Oid; 
				if (!nextOid.StartsWith(rootOid)) 
				{ 
					break; 
				} 
 
				if (debug) 
				{ 
					PrintPdu(Console.Out, "Received PDU:", resp, debug); 
				} 
				else 
					if (show) 
				{ 
					SnmpSyntax val = nextVb.Value; 
					SmiSyntax type = val != null ? val.SmiSyntax : SmiSyntax.Null; 
					Console.WriteLine("[{0}]: {1},{2},{3}", thName, nextOid, val, type); 
				} 
				 
				pdu = pdu.Clone(new Vb(nextOid)); 
			} 
		} 
 
		private static Oid[] GetColumnOids(Pdu pdu) 
		{ 
			Vb[] vbs = pdu.Vbs; 
			Oid[] columnOids = new Oid[vbs.Length]; 
			for (int i = 0; i < columnOids.Length; i++) 
			{ 
				columnOids[i] = vbs[i].Oid; 
			} 
			return columnOids; 
		} 
 
		private static void Table(Snmp snmp, Pdu pdu, SnmpTarget target, 
			ref TableReader.GetTableOptions tableOptions, bool show, bool debug, 
			ref int ncalls) 
		{ 
			Oid[] columnOids = GetColumnOids(pdu); 
			pdu = pdu.Clone(new Vb[0]);	// not really needed; for test purposes 
			Vb[][] vbTable = TableReader.GetTable(snmp, pdu, target, 
				columnOids, tableOptions, ref ncalls); 
			if (show || debug) 
			{ 
				TableReader.PrintTable(Console.Out, columnOids, vbTable); 
			} 
		} 
 
		private static Pdu DoSnmp(Snmp snmp, SnmpTarget target, Pdu pdu, 
			OperType operType, ref TableReader.GetTableOptions tableOptions, 
			bool asyncSync, bool show, bool debug, ref int ncalls) 
		{ 
			switch (operType) 
			{ 
				case OperType.Walk: 
					Walk(snmp, pdu, target, asyncSync, show, debug, ref ncalls); 
					pdu = null; 
					break; 
				case OperType.Table: 
					Table(snmp, pdu, target, ref tableOptions, show, debug, ref ncalls); 
					pdu = null; 
					break; 
				default: 
					pdu = Invoke(snmp, pdu, target, asyncSync); 
					ncalls++; 
					break; 
			} 
			return pdu; 
		} 
		 
		private static Hashtable DoSnmp(Snmp snmp, SnmpTarget target, Pdu pdu, 
			OperType operType, ref TableReader.GetTableOptions tableOptions, 
			uint repeat, bool asyncSync, bool debug) 
		{ 
			int ncalls = 0; 
			Hashtable htResult = new Hashtable(); 
			for (uint i = 0; i < repeat; i++) 
			{ 
				using (IMemoryManager mgr = MemoryManager.GetMemoryManager()) 
				{ 
					bool show = (i % 1000) == 0; 
					if (show || debug) 
					{ 
						//PrintPdu(Console.Out, "Sending PDU to target " + target, pdu, debug); 
					} 
 
					Pdu resPdu = DoSnmp(snmp, target, pdu, 
						operType, ref tableOptions, 
						asyncSync, show, debug, ref ncalls); 
 
					if ((show || debug) && resPdu != null) 
					{ 
						//**********OLI***********// 
						//PrintPdu(Console.Out, "Received PDU:", resPdu, debug); 
						//************************// 
						htResult = ManagerUtilities.getValues(resPdu); 
						 
						 
					} 
					if (debug) 
					{ 
						Console.WriteLine("Removing " + mgr.Count + " objects"); 
					} 
				} 
			} 
			htResult.Add("count",ncalls); 
			return htResult; 
			//return ncalls; 
		} 
 
		private static void DoSnmp(Object o) 
		{ 
			((Manager) o).DoSnmp(); 
		} 
		 
		private static void AsyncDoSnmp(Snmp snmp, SnmpTarget target, Pdu pdu, 
			AsyncCallback callback, Object data) 
		{ 
			snmp.BeginInvoke(pdu, target, callback, data); 
		} 
 
		private static void SetupThreads(Manager mgr, uint nThreads) 
		{ 
			// The thread pool is much more convenient as it allows the state 
			// to be passed as an arg. We use the pool for 5 threads or less. 
			if (nThreads <= 5) 
			{ 
				WaitCallback wc = new WaitCallback(DoSnmp); 
				for (int i = 0; i < nThreads; i++) 
				{ 
					ThreadPool.QueueUserWorkItem(wc, mgr); 
				} 
			} 
			else 
			{ 
				ThreadStart ts = new ThreadStart(mgr.DoSnmp); 
				for (int i = 0; i < nThreads; i++) 
				{ 
					Thread t = new Thread(ts); 
					t.Name = (i + 1).ToString(); 
					t.Start(); 
				} 
			} 
		} 
 
		private static Hashtable Process(Manager mgr, ref string option) 
		{ 
			// We use a single Manager object in all threads; the current 
			// thread is also processing the job 
			option = ""; 
			uint nThreads = mgr.Barrier.Size; 
			SetupThreads(mgr, nThreads - 1); 
 
			option = ""; 
			mgr.DoSnmp(); 
 
			// All threads have finished processing (and entered the barrier) 
			return mgr.Results; 
		} 
 
		private static int AsyncProcess(Manager mgr, ref string option) 
		{ 
			Hashtable htResult = new Hashtable(); 
			// Note that each "thread" needs to maintain its own number 
			// of repetitions - we need a single object per each "thread" 
			option = ""; 
			Barrier barrier = mgr.Barrier; 
			uint nThreads = barrier.Size - 1; 
			Manager[] mgrs = new Manager[nThreads]; 
			for (int i = 0; i < nThreads; i++) 
			{ 
				mgrs[i] = mgr.Clone(i); 
				mgrs[i].AsyncDoSnmp(); 
			} 
 
			// Wait for all threads to finish processing (and enter the barrier) 
			barrier.Enter(); 
 
			int ncalls = 0; 
			for (int i = 0; i < nThreads; i++) 
			{ 
				ncalls += mgrs[i].Calls; 
			} 
			return ncalls; 
		} 
		 
		private static void GetOperType(string op, 
			out PduType pduType, out OperType operType) 
		{ 
			operType = OperType.Simple; 
			switch (op) 
			{ 
				case "walk": 
					pduType = PduType.GetNext; 
					operType = OperType.Walk; 
					break; 
				case "table": 
					pduType = PduType.GetBulk; 
					operType = OperType.Table; 
					break; 
				default: 
					pduType = (PduType) Enum.Parse(typeof(PduType), op, true); 
					break; 
			} 
		} 
 
		private static bool ParseBoolWithDefault(string val) 
		{ 
			return val.Length == 0 ? true : bool.Parse(val); 
		} 
 
		private delegate Hashtable Delegate(Manager mgr, ref string option); 
 
		#endregion 
 
 
 
		public static Hashtable makeOrder(string[] args)  
		{ 
			Hashtable htResult = new Hashtable() ; 
			#region init variable + presentation 
			 
#if REQUIRES_CRT_INIT 
			CRT.Auto.Initialize(); 
#endif 
 
			/*	EXAMPLE***************** 
			 * 	args = new string[5]; 
			 *  args[0] = "get"; 
			 *  args[1] = "127.0.0.1"; 
			 *  args[2] = "-o"; 
			 *  args[3] = "1.3.6.1.2.1.1.5.0"; 
			 *  args[4] = "-Dl0"; 
			 */ 
 
 
			if (args.Length < 2) 
			{ 
				Console.WriteLine("SNMP++.NET command line utility\n" 
					+ "Author: Marek Malowidzki 2003,2004 (maom_onet@poczta.onet.pl)\n" 
					+ "Based on SNMP++ package from Peter E. Mellquist (HP) and Jochen Katz\n" 
					+ "SNMP++.NET " + Assembly.GetAssembly(typeof(Snmp)) 
					+ " built on " + Snmp.BuildTime 
					+ "; SNMP++ v. " + Snmp.Snmp_ppVersion + "\n\n" 
					+ "Usage: " + Environment.GetCommandLineArgs()[0] + "   []\n" 
					+ "where:\n" 
					+ "op           - SNMP operation to perform (get,getnext,getbulk,set,walk,table)\n" 
					+ "agent        - IP address or DNS name of an agent\n" 
					+ "options are the following:\n" 
					+ "-v  - SNMP version to use (v1(default),v2c,v3)\n" 
					+ "-p     - port number to use\n" 
					+ "-r  - number of retries (default: 2)\n" 
					+ "-t  - timeout in milliseconds (default: 1000)\n" 
					+ "-d     - print debug messages\n" 
					+ "-o      - subsequent OID\n" 
					+ "-T     - subsequent SNMP type name:\n" 
					+ string.Join(",", SnmpSyntax.SupportedSyntaxNames) 
					+ " (o stands for oid and s for string)\n" 
					+ "-V    - subsequent value\n" 
					+ "Debug options:\n" 
					+ "-Df    - log file name\n" 
					+ "-Dl   - log level\n" 
					+ "SNMPv1/v2c options:\n" 
					+ "-c     - read community name (default: public)\n" 
					+ "-C     - write community name (default: public)\n" 
					+ "SNMPv3 options:\n" 
					+ "-b     - boot counter value (default: 100)\n" 
					+ "-sn - security name\n" 
					+ "-sl- security level (" 
					+ ManagerUtilities.EnumInfo(typeof(SecurityLevel), SecurityLevel.AuthPriv) + ")\n" 
					+ "-sm- security model (" 
					+ ManagerUtilities.EnumInfo(typeof(SecurityModel), SecurityModel.USM) + ")\n" 
					+ "-xn - context name\n" 
					+ "-xe- context engine ID (default: discover)\n" 
					+ "-A- authentication protocol (" 
					+ ManagerUtilities.EnumInfo(typeof(AuthProtocol), AuthProtocol.None) + ")\n" 
					+ "-P- privacy protocol (" 
					+ ManagerUtilities.EnumInfo(typeof(PrivProtocol), PrivProtocol.None) + ")\n" 
					+ "-Ua- authentication password\n" 
					+ "-Up- privacy password\n" 
					+ "Table operation options:\n" 
					+ "-Os  - row index to start from\n" 
					+ "-Oe  - row index to finish at\n" 
					+ "-On   - max number of rows to retrieve\n" 
					+ "-Or   - rows per query or 0 for heuristics\n" 
					+ "Testing options:\n" 
					+ "-Xa    - use asynchronous interface\n" 
					+ "-Xm - collect memory usage in . files, where ext denotes memory type\n" 
					+ "-Xn  - repeat number of times (default: 1)\n" 
					+ "-Xp- set process priority (" 
					+ ManagerUtilities.EnumInfo(typeof(ProcessPriorityClass), ProcessPriorityClass.Normal) + ")\n" 
					+ "-Xs    - use asychronous interface for synchronous calls\n" 
					+ "-Xt - run multiple threads (default: 1)"); 
				Console.ReadLine(); 
				Environment.Exit(1); 
			} 
			//Console.ReadLine(); 
 
			string option = ""; 
			Thread statsCollector = null; 
			MemoryStats stats = null; 
			int retCode = 1; 
			bool hasCleanUp = false; 
			try 
			{ 
				UdpAddress udp = new UdpAddress(args[1]); 
				SnmpVersion ver = SnmpVersion.SNMPv1; 
				SnmpTarget.DefaultRetries = 2; 
				SnmpTarget.DefaultTimeout = 1000; 
				uint nRepeats = 1, nThreads = 1; 
				int debugLevel = int.MinValue; 
				string statsFile = null, debugFile = null; 
				TableReader.GetTableOptions tableOptions = new TableReader.GetTableOptions(); 
				bool async = false, asyncSync = false, debug = false; 
 
				string  readCommunity  = "public", 
					writeCommunity = "public"; 
				AuthProtocol authProto = AuthProtocol.None; 
				PrivProtocol privProto = PrivProtocol.None; 
				string  authPass = "", 
					privPass = "", 
					secName  = "", 
					ctxName  = "", 
					ctxEngId = ""; 
				SecurityLevel secLevel = SecurityLevel.AuthPriv; 
				SecurityModel secModel = SecurityModel.USM; 
				uint boot = 100; 
 
				string[] oids  = new string[128], 
					types = new string[128], 
					vals  = new string[128]; 
				int noids = 0, ntypes = 0, nvals = 0; 
 
				string val; 
				int index = 2; 
				while (ManagerUtilities.GetOption(args, out option, out val, ref index)) 
				{ 
					char sub; 
					switch (option) 
					{ 
						case "v": 
							ver = (SnmpVersion)	Enum.Parse( 
								typeof(SnmpVersion), "SNMPv" + val, true); 
							break; 
						case "p": 
							udp = new UdpAddress(udp.Ip, int.Parse(val)); 
							break; 
						case "r": 
							SnmpTarget.DefaultRetries = int.Parse(val); 
							break; 
						case "t": 
							SnmpTarget.DefaultTimeout = int.Parse(val); 
							break; 
						case "d": 
							debug = bool.Parse(val); 
							break; 
						case "o": 
							oids[noids++] = val; 
							break; 
						case "T": 
							types[ntypes++] = val; 
							break; 
						case "V": 
							vals[nvals++] = val; 
							break; 
						case "c": 
							readCommunity = val; 
							break; 
						case "C": 
							writeCommunity = val; 
							break; 
						case "b": 
							boot = uint.Parse(val); 
							break; 
						case "s": 
						switch (sub = ManagerUtilities.GetSubOption(ref val)) 
						{ 
							case 'n': 
								secName = val; 
								break; 
							case 'l': 
								secLevel = (SecurityLevel) Enum.Parse( 
									typeof(SecurityLevel), val, true); 
								break; 
							case 'm': 
								secModel = (SecurityModel) Enum.Parse( 
									typeof(SecurityModel), val, true); 
								break; 
							default: 
								throw new ArgumentException( 
									sub + ": invalid sub-option"); 
						} 
							break; 
						case "x": 
						switch (sub = ManagerUtilities.GetSubOption(ref val)) 
						{ 
							case 'n': 
								ctxName = val; 
								break; 
							case 'e': 
								ctxEngId = val; 
								break; 
							default: 
								throw new ArgumentException( 
									sub + ": invalid sub-option"); 
						} 
							break; 
						case "A": 
							authProto = (AuthProtocol) Enum.Parse( 
								typeof(AuthProtocol), val, true); 
							break; 
						case "P": 
							privProto = (PrivProtocol) Enum.Parse( 
								typeof(PrivProtocol), val, true); 
							break; 
						case "D": 
						switch (sub = ManagerUtilities.GetSubOption(ref val)) 
						{ 
							case 'f': 
								debugFile = val; 
								break; 
							case 'l': 
								debugLevel = int.Parse(val); 
								break; 
							default: 
								throw new ArgumentException( 
									sub + ": invalid sub-option"); 
						} 
							break; 
						case "U": 
						switch (sub = ManagerUtilities.GetSubOption(ref val)) 
						{ 
							case 'a': 
								authPass = val; 
								break; 
							case 'p': 
								privPass = val; 
								break; 
							default: 
								throw new ArgumentException( 
									sub + ": invalid sub-option"); 
						} 
							break; 
						case "O": 
						{ 
							switch (sub = ManagerUtilities.GetSubOption(ref val)) 
							{ 
								case 's': 
									tableOptions.startRowIndex = new Oid(val); 
									break; 
								case 'e': 
									tableOptions.endRowIndex = new Oid(val); 
									break; 
								case 'n': 
									tableOptions.maxRows = int.Parse(val); 
									break; 
								case 'r': 
									tableOptions.rowsPerQuery = int.Parse(val); 
									break; 
								default: 
									throw new ArgumentException( 
										sub + ": invalid sub-option"); 
							} 
							break; 
						} 
						case "X": 
						switch (sub = ManagerUtilities.GetSubOption(ref val)) 
						{ 
							case 'a': 
								async = ParseBoolWithDefault(val); 
								break; 
							case 'm': 
								statsFile = val; 
								break; 
							case 'n': 
								nRepeats = uint.Parse(val); 
								break; 
							case 'p': 
								System.Diagnostics.Process.GetCurrentProcess().PriorityClass 
									= (ProcessPriorityClass) Enum.Parse( 
									typeof(ProcessPriorityClass), val, true); 
								break; 
							case 's': 
								asyncSync = ParseBoolWithDefault(val); 
								break; 
							case 't': 
								if ((nThreads = uint.Parse(val)) <= 0) 
								{ 
									throw new ArgumentException( 
										val + ": invalid threads number"); 
								} 
								break; 
							default: 
								throw new ArgumentException( 
									sub + ": invalid sub-option"); 
						} 
							break; 
						default: 
							throw new ArgumentException( 
								"-" + option + ": invalid option"); 
					} 
				} 
 
				if (noids == 0) 
				{ 
					option = ""; 
					throw new ArgumentException( 
						"No OIDs specified, use -o option"); 
				} 
 
				bool asyncMode = async || asyncSync; 
 
				// Debug options 
				if (debugFile != null) 
				{ 
					Snmp.DebugLogFile = debugFile; 
				} 
				if (debugLevel != int.MinValue) 
				{ 
					Snmp.DebugLogLevel = debugLevel; 
				} 
 
				// Operation type processing 
				option = ""; 
				PduType pduType; 
				OperType operType; 
				GetOperType(args[0].ToLower(), out pduType, out operType); 
 
				// Adjusting settings for a table operation 
				if (operType == OperType.Table) 
				{ 
					TableReader.UseAsyncInvoke = asyncMode; 
				} 
 
				#endregion 
				// Pdu creation 
				Pdu pdu; 
				using (IMemoryManager mgr = MemoryManager.GetMemoryManager()) 
				{ 
					Vb[] vbs = ManagerUtilities.CreateVbs(pduType, oids, noids, types, ntypes, vals, nvals); 
					pdu = new Pdu(pduType, vbs); 
					mgr.Remove(pdu);	// remove Pdu from the memory manager 
				} 
 
				// SnmpTarget creation 
				SnmpTarget target; 
				if (ver == SnmpVersion.SNMPv3) 
				{ 
					option = ""; 
					V3MP.Init(new OctetStr("SNMP++.NET"), boot); 
					USM usm = V3MP.Instance.Usm; 
					usm.AddUsmUser(secName, authProto, privProto, authPass, privPass); 
 
					target = new UTarget(udp, secName, secModel); 
 
					pdu.SecurityLevel = secLevel; 
					pdu.ContextName = new OctetStr(ctxName); 
					pdu.ContextEngineId = new OctetStr(ctxEngId); 
				} 
				else 
				{ 
					option = ""; 
					target = new CTarget(udp, ver, readCommunity, writeCommunity); 
				} 
				udp = null; 
 
				// Memory usage statistics initialization 
				option = ""; 
				if (statsFile != null) 
				{ 
					stats = new MemoryStats(statsFile); 
					statsCollector = new Thread(new ThreadStart(stats.Collect)); 
					statsCollector.Priority = ThreadPriority.BelowNormal; 
					statsCollector.Start(); 
				} 
 
				// Snmp session initialization & further processing 
				option = ""; 
				using (Snmp snmp = new Snmp(asyncMode)) 
				{ 
					//Thread.CurrentThread.Name = "0"; 
 
					Barrier barrier; 
					Delegate fun; 
					if (async) 
					{ 
						throw new Exception("the asyn method does not work write now..."); 
						//fun = new Delegate(AsyncProcess); 
						barrier = new Barrier(nThreads + 1); 
					} 
					else 
					{ 
						fun = new Delegate(Process); 
						barrier = new Barrier(nThreads); 
					} 
 
					Manager mgr = new Manager(0, snmp, target, pdu, operType, 
						ref tableOptions, barrier, 
						nRepeats, asyncSync, debug); 
 
					DateTime start = DateTime.Now; 
					htResult = fun(mgr, ref option); 
					int  ncalls = (int)htResult["count"]; 
					double msec = DateTime.Now.Subtract(start).TotalMilliseconds; 
 
					// clear references on stack 
					pdu = null; target = null; mgr = null; 
					if (debug) 
					{ 
						Console.WriteLine("{0} {1} SNMP request(s) in {2} msec. ({3} req./sec.)", 
							ncalls, asyncMode ? "asynchronous" : "synchronous", 
							(int) msec, msec > 0 ? (1000 * (long) ncalls / msec) : 0); 
					} 
				} 
				retCode = 0; 
 
				//Clean up de memory 
				if (debug) 
				{ 
					Console.WriteLine("Remaining native SNMP++ objects before GC: " 
						+ MemoryManager.Count); 
				} 
				if (statsCollector != null) 
				{ 
					stats.WaitForNextStat(); 
				} 
 
				GC.Collect(); 
				GC.Collect(); 
				GC.WaitForPendingFinalizers(); 
 
				if (statsCollector != null) 
				{ 
					stats.WaitForNextStat(); 
 
					statsCollector.Interrupt(); 
					statsCollector.Join(); 
				} 
 
				// Despite our honest intentions, there may still be uncollected 
				// SNMP++.NET objects, especially in the Release mode 
				if (debug) 
				{ 
					Console.WriteLine("Remaining native SNMP++ objects after GC: " 
						+ MemoryManager.Count); 
				} 
				hasCleanUp = true; 
 
			} 
			catch (SnmpClassException e) 
			{ 
				Console.Error.WriteLine("*** SNMP class error while processing {0}:\n" 
					+ "SnmpClass status code: {1}\n{2}", option, e.Status, e); 
			} 
			catch (SnmpException e) 
			{ 
				Console.Error.WriteLine("*** SNMP protocol error while processing {0}:\n" 
					+ "SNMP error status: {1}\nSNMP error index: {2}\n{3}", 
					option, e.ErrorStatus, e.ErrorIndex, e); 
			} 
			catch (Exception e) 
			{ 
				Console.Error.WriteLine("*** Error while processing {0}:\n{1}", option, e); 
			} 
 
			if (!hasCleanUp) 
			{ 
				if (statsCollector != null) 
				{ 
					stats.WaitForNextStat(); 
				} 
 
				GC.Collect(); 
				GC.Collect(); 
				GC.WaitForPendingFinalizers(); 
 
				if (statsCollector != null) 
				{ 
					stats.WaitForNextStat(); 
 
					statsCollector.Interrupt(); 
					statsCollector.Join(); 
				} 
			} 
 
			 
 
 
			return htResult; 
		} 
		 
	} 
 
 
 
 
 
 
 
	public sealed class ManagerUtilities 
	{ 
		private ManagerUtilities() {} 
 
		public static string EnumInfo(Type t, object defaultValue) 
		{ 
			string[] names = Enum.GetNames(t); 
			string defname = Enum.GetName(t, defaultValue); 
			for (int i = 0; i < names.Length; i++) 
			{ 
				if (names[i] == defname)  
				{ 
					names[i] += "(default)"; 
					break; 
				} 
			} 
			return string.Join(",", names); 
		} 
 
		public static bool GetOption(string[] args, 
			out string option, out string val, ref int index) 
		{ 
			option = val = null; 
			if (index >= args.Length) 
			{ 
				return false; 
			} 
 
			option = args[index++]; 
			if (!(option.Length > 1 && option[0] == '-')) 
			{ 
				throw new ArgumentException("expected option, got " + option, "option"); 
			} 
 
			val = option.Substring(2); 
			option = option.Substring(1, 1); 
 
			if (val.Length == 0) 
			{ 
				if (index >= args.Length) 
				{ 
					throw new ArgumentException("no value for option -" + option, "option"); 
				} 
				val = args[index++]; 
			} 
			return true; 
		} 
 
		public static char GetSubOption(ref string s) 
		{ 
			if (s.Length == 0) 
			{ 
				throw new ArgumentException("sub-option expected", "s"); 
			} 
 
			char c = s[0]; 
			s = s.Substring(1); 
			return c; 
		} 
 
		public static Vb[] CreateVbs(PduType pduType, string[] oids, int oidsCount, 
			string[] types, int typesCount, string[] values, int valuesCount) 
		{ 
			if (typesCount != valuesCount) 
			{ 
				throw new ArgumentException( 
					"types and values must be specified the same number of times"); 
			} 
 
			Vb[] vbs = new Vb[oidsCount]; 
			if (pduType != PduType.Set && typesCount == 0) 
			{ 
				for (int i = 0; i < oidsCount; i++) 
				{ 
					vbs[i] = new Vb(oids[i]); 
				} 
			} 
			else 
			{ 
				if (oidsCount != typesCount) 
				{ 
					throw new ArgumentException( 
						"OBJECT IDENTIFIERs and types must be specified" 
						+ " the same number of times"); 
				} 
 
				for (int i = 0; i < oidsCount; i++) 
				{ 
					vbs[i] = Vb.Create(oids[i], types[i], values[i]); 
				} 
			} 
			return vbs; 
		} 
 
		public static Hashtable getValues(Pdu pdu) 
		{ 
			Hashtable htResult = new Hashtable(); 
			int i = 0; 
			foreach (Vb vb in pdu) 
			{ 
				i++; 
				SnmpSyntax val = vb.Value; 
				SmiSyntax type = val != null ? val.SmiSyntax : SmiSyntax.Null; 
				 
 
				Hashtable htElement = new Hashtable(); 
 
				//Transform val to a string 
				StringWriter sw = new StringWriter(); 
				sw.Write("{0}",val); 
				string myValue = sw.ToString(); 
 
				htElement.Add("value",myValue); 
				htElement.Add("type",type.ToString()); 
				htElement.Add("oid",vb.Oid.ToString()); 
				htResult.Add(i,htElement); 
			} 
			return htResult; 
		} 
 
 
 
		public static void PrintPdu(TextWriter os, string text, 
			Pdu pdu, bool debug, object id) 
		{ 
			lock (os) 
			{ 
				os.WriteLine("+++[{0}]: {1}{2}", id, text, debug ? "\n" + pdu : ""); 
 
				// another way would be through Pdu.Vbs: 
				// foreach (Vb vb in pdu.Vbs) {...} 
				int i = 0; 
				foreach (Vb vb in pdu) 
				{ 
					SnmpSyntax val = vb.Value; 
					SmiSyntax type = val != null ? val.SmiSyntax : SmiSyntax.Null; 
 
					os.WriteLine("###oid [{0}]: {1}\n###val [{0}]: {2} ({3})", i, vb.Oid, val, type); 
					i++; 
				} 
			} 
		} 
	} 
}