Skip to content

Example Async Receive SNMP Trap

qingxiao_ren edited this page Sep 5, 2018 · 1 revision

Async Receive SNMP version 1 traps and 2c traps and informs

Example tested with SnmpSharpNet version 0.7.3.

This example shows how to use Socket class with async receive functionality in a WinForms GUI application without network
causing negative impact on GUI operation. This example will correctly parse and display information in SNMPv1-TRAP, SNMPV2-TRAP
and SNMPV2-INFORM format.

Critical methods in this example are Socket.BeginReceiveFrom(), Socket.EndReceiveFrom()

Example is a very simple application containing a check box (displayed as on/off button) that allows users to enable or disable
SNMP trap/inform reception and a list box that dumps trap, inform and error information.

using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using SnmpSharpNet;
 
namespace AsyncTrapReceiver
{
	public class Form1 : Form
	{
		protected Socket _socket;
		protected byte[] _inbuffer;
		protected IPEndPoint _peerIP;
		private System.Windows.Forms.ListBox listBox1;
		private System.Windows.Forms.CheckBox startCheckBox;
 
		public Form1 ()
		{
			// it is not neccessary to initialize variables to null, but better safe then sorry
			_socket = null;
 
			this.listBox1 = new System.Windows.Forms.ListBox ();
			this.startCheckBox = new System.Windows.Forms.CheckBox ();
			this.SuspendLayout ();
			//
			// listBox1
			//
			this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)
				((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
				| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)));
			this.listBox1.FormattingEnabled = true;
			this.listBox1.Location = new System.Drawing.Point (13, 13);
			this.listBox1.Name = "listBox1";
			this.listBox1.Size = new System.Drawing.Size (328, 368);
			this.listBox1.TabIndex = 0;
			//
			// startCheckBox
			//
			this.startCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)
				((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.startCheckBox.Appearance = System.Windows.Forms.Appearance.Button;
			this.startCheckBox.Location = new System.Drawing.Point (347, 12);
			this.startCheckBox.Name = "startCheckBox";
			this.startCheckBox.Size = new System.Drawing.Size (75, 24);
			this.startCheckBox.TabIndex = 3;
			this.startCheckBox.Text = "&Start";
			this.startCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			this.startCheckBox.UseVisualStyleBackColor = true;
			this.startCheckBox.CheckedChanged += new System.EventHandler (this.onStartChanged);
			// 
			// Form1
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF (6f, 13f);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size (434, 391);
			this.Controls.Add (this.startCheckBox);
			this.Controls.Add (this.listBox1);
			this.Name = "Form1";
			this.Text = "Form1";
			this.ResumeLayout (false);
		}
		public bool InitializeReceiver ()
		{
			if (_socket != null) {
				StopReceiver ();
			}
			try {
				// create an IP/UDP socket
				_socket = new Socket (AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 
			} catch (Exception ex) {
				listBox1.Items.Add ("SNMP trap receiver socket initialization failed with error: " + ex.Message);
				// there is no need to close the socket because it was never correctly created
				_socket = null;
			}
			if (_socket == null)
				return false;
			try {
				// prepare to "bind" the socket to the local port number
				// binding notifies the operating system that application 
				// wishes to receive data sent to the specified port number
 
				// prepare EndPoint that will bind the application to all available 
				//IP addresses and port 162 (snmp-trap)
				EndPoint localEP = new IPEndPoint (IPAddress.Any, 162);
				// bind socket
				_socket.Bind (localEP);
			} catch (Exception ex) {
				listBox1.Items.Add ("SNMP trap receiver initialization failed with error: " + ex.Message);
				_socket.Close ();
				_socket = null;
			}
			if (_socket == null)
				return false;
 
			if (!RegisterReceiveOperation ())
				return false;
 
			return true;
		}
		public void StopReceiver ()
		{
			if (_socket != null) {
				_socket.Close ();
				_socket = null;
			}
		}
		public bool RegisterReceiveOperation ()
		{
			if (_socket == null)
				return false;
			// socket has been closed
			try {
				_peerIP = new IPEndPoint (IPAddress.Any, 0);
				// receive from anybody
				EndPoint ep = (EndPoint)_peerIP;
				_inbuffer = new byte[64 * 1024];
				// nice and big receive buffer
				_socket.BeginReceiveFrom (_inbuffer, 0, 64 * 1024, 
					SocketFlags.None, ref ep, new AsyncCallback (ReceiveCallback), _socket);
			} catch (Exception ex) {
				listBox1.Items.Add ("Registering receive operation failed with message: " + ex.Message);
				_socket.Close ();
				_socket = null;
			}
			if (_socket == null)
				return false;
			return true;
		}
		private void ReceiveCallback (IAsyncResult result)
		{
			// get a reference to the socket. This is handy if socket has been closed elsewhere in the class
			Socket sock = (Socket)result.AsyncState;
 
			_peerIP = new IPEndPoint (IPAddress.Any, 0);
 
			// variable to store received data length
			int inlen;
 
			try {
				EndPoint ep = (EndPoint)_peerIP;
				inlen = sock.EndReceiveFrom (result, ref ep);
				_peerIP = (IPEndPoint)ep;
			} catch (Exception ex) {
				// only post messages if class socket reference is not null
				// in all other cases, user has terminated the socket
				if (_socket != null) {
					PostAsyncMessage ("Receive operation failed with message: " + ex.Message);
				}
				inlen = -1;
			}
			// if socket has been closed, ignore received data and return
			if (_socket == null)
				return;
			// check that received data is long enough
			if (inlen <= 0) {
				// request next packet
				RegisterReceiveOperation ();
				return;
			}
			int packetVersion = SnmpPacket.GetProtocolVersion (_inbuffer, inlen);
			if (packetVersion == (int)SnmpVersion.Ver1) {
				SnmpV1TrapPacket pkt = new SnmpV1TrapPacket ();
				try {
					pkt.decode (_inbuffer, inlen);
				} catch (Exception ex) {
					PostAsyncMessage ("Error parsing SNMPv1 Trap: " + ex.Message);
					pkt = null;
				}
				if (pkt != null) {
					PostAsyncMessage (String.Format ("** SNMPv1 TRAP from {0}", _peerIP.ToString ()));
					PostAsyncMessage (
						String.Format ("*** community {0} generic id: {1} specific id: {2}", 
							pkt.Community, pkt.Pdu.Generic, pkt.Pdu.Specific)
					);
					PostAsyncMessage (String.Format ("*** PDU count: {0}", pkt.Pdu.VbCount));
					foreach (Vb vb in pkt.Pdu.VbList) {
						PostAsyncMessage (
							String.Format ("**** Vb oid: {0} type: {1} value: {2}", 
								vb.Oid.ToString (), SnmpConstants.GetTypeName (vb.Value.Type), vb.Value.ToString ())
						);
					}
					PostAsyncMessage ("** End of SNMPv1 TRAP");
				}
			} else if (packetVersion == (int)SnmpVersion.Ver2) {
				SnmpV2Packet pkt = new SnmpV2Packet ();
				try {
					pkt.decode (_inbuffer, inlen);
				} catch (Exception ex) {
					PostAsyncMessage ("Error parsing SNMPv1 Trap: " + ex.Message);
					pkt = null;
				}
				if (pkt != null) {
					if (pkt.Pdu.Type == PduType.V2Trap) {
						PostAsyncMessage (String.Format ("** SNMPv2 TRAP from {0}", _peerIP.ToString ()));
					} else if (pkt.Pdu.Type == PduType.Inform) {
						PostAsyncMessage (String.Format ("** SNMPv2 INFORM from {0}", _peerIP.ToString ()));
					} else {
						PostAsyncMessage (String.Format ("Invalid SNMPv2 packet from {0}", _peerIP.ToString ()));
						pkt = null;
					}
					if (pkt != null) {
						PostAsyncMessage (
							String.Format ("*** community {0} sysUpTime: {1} trapObjectID: {2}", 
								pkt.Community, pkt.Pdu.TrapSysUpTime.ToString (), pkt.Pdu.TrapObjectID.ToString ())
						);
						PostAsyncMessage (String.Format ("*** PDU count: {0}", pkt.Pdu.VbCount));
						foreach (Vb vb in pkt.Pdu.VbList)
						{
							PostAsyncMessage (
								String.Format ("**** Vb oid: {0} type: {1} value: {2}", 
									vb.Oid.ToString (), SnmpConstants.GetTypeName (vb.Value.Type), vb.Value.ToString ())
							);
						}
						if (pkt.Pdu.Type == PduType.V2Trap)
							PostAsyncMessage ("** End of SNMPv2 TRAP");
						else {
							PostAsyncMessage ("** End of SNMPv2 INFORM");
 
							// send ACK back to the INFORM sender
							SnmpV2Packet response = pkt.BuildInformResponse ();
							byte[] buf = response.encode ();
							_socket.SendTo (buf, (EndPoint)_peerIP);
						}
					}
				}
			}
			RegisterReceiveOperation ();
		}
		protected delegate void PostAsyncMessageDelegate (string msg);
		protected void PostAsyncMessage (string msg)
		{
			if (InvokeRequired)
				Invoke (new PostAsyncMessageDelegate (PostAsyncMessage), new object[] { msg });
			else
				listBox1.Items.Add (msg);
		}
 
		private void onStartChanged (object sender, EventArgs e)
		{
			if (startCheckBox.Checked) {
				if (!InitializeReceiver ()) {
					// unable to start TRAP receiver
					startCheckBox.Checked = false;
					return;
				} else {
					startCheckBox.Text = "S&top";
				}
			} else {
				StopReceiver ();
				startCheckBox.Text = "&Start";
			}
		}
	}
}

Same thing in VB.Net

Imports System
Imports System.Windows.Forms
Imports System.Net
Imports System.Net.Sockets
Imports SnmpSharpNet
 
Public Class Form1
    Inherits Form
    Dim _socket As Socket
    Dim _inbuffer() As Byte
    Dim _peerIP As IPEndPoint
    Dim listBox1 As System.Windows.Forms.ListBox
    Dim WithEvents startCheckBox As System.Windows.Forms.CheckBox
 
    Public Sub New()
 
        System.Diagnostics.Debug.WriteLine("OnLoad event")
 
        _socket = Nothing
 
        listBox1 = New System.Windows.Forms.ListBox()
        startCheckBox = New System.Windows.Forms.CheckBox()
        SuspendLayout()
        '
        ' listBox1
        '
        listBox1.Parent = Me
        listBox1.Anchor = ((((System.Windows.Forms.AnchorStyles.Top Or _
                              System.Windows.Forms.AnchorStyles.Bottom) Or _
                              System.Windows.Forms.AnchorStyles.Left) Or _
                              System.Windows.Forms.AnchorStyles.Right))
        listBox1.FormattingEnabled = True
        listBox1.Location = New System.Drawing.Point(13, 13)
        listBox1.Name = "listBox1"
        listBox1.Size = New System.Drawing.Size(328, 368)
        listBox1.TabIndex = 0
        '
        ' startCheckBox
        '
        startCheckBox.Parent = Me
        startCheckBox.Anchor = (System.Windows.Forms.AnchorStyles.Top Or _
                                System.Windows.Forms.AnchorStyles.Right)
        startCheckBox.Appearance = System.Windows.Forms.Appearance.Button
        startCheckBox.Location = New System.Drawing.Point(347, 12)
        startCheckBox.Name = "startCheckBox"
        startCheckBox.Size = New System.Drawing.Size(75, 24)
        startCheckBox.TabIndex = 3
        startCheckBox.Text = "&Start"
        startCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
        startCheckBox.UseVisualStyleBackColor = True
        ' 
        ' Form1
        ' 
        AutoScaleDimensions = New System.Drawing.SizeF(6.0F, 13.0F)
        AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        ClientSize = New System.Drawing.Size(434, 391)
        Me.Controls.Add(startCheckBox)
        Me.Controls.Add(listBox1)
        Name = "Form1"
        Text = "Form1"
        ResumeLayout(False)
    End Sub
 
    Public Function InitializeReceiver() As Boolean
        If _socket IsNot Nothing Then
            StopReceiver()
        End If
        Try
            _socket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
        Catch ex As Exception
            listBox1.Items.Add("SNMP trap receiver socket initialization failed with error: " & ex.Message)
            ' there is no need to close the socket because it was never correctly created
            _socket = Nothing
            Return False
        End Try
        Try
            Dim ep As EndPoint = New IPEndPoint(System.Net.IPAddress.Any, 162)
            _socket.Bind(ep)
        Catch ex As Exception
            listBox1.Items.Add("SNMP trap receiver initialization failed with error: " & ex.Message)
            _socket.Close()
            _socket = Nothing
            Return False
        End Try
        If RegisterReceiveOperation() = False Then
            Return False
        End If
        Return True
    End Function
 
    Public Sub StopReceiver()
        If _socket IsNot Nothing Then
            _socket.Close()
            _socket = Nothing
        End If
    End Sub
 
    Public Function RegisterReceiveOperation() As Boolean
        If _socket Is Nothing Then
            Return False
        End If
        Try
            _peerIP = New IPEndPoint(System.Net.IPAddress.Any, 0) ' receive from anybody
            _inbuffer = New [Byte](64 * 1024) {} ' nice and big receive buffer
            _socket.BeginReceiveFrom(_inbuffer, 0, _inbuffer.Length, _
                                     System.Net.Sockets.SocketFlags.None, _
                                     _peerIP, New AsyncCallback(AddressOf ReceiveCallback), _socket)
        Catch ex As Exception
            listBox1.Items.Add("Registering receive operation failed with message: " & ex.Message)
            _socket.Close()
            _socket = Nothing
            Return False
        End Try
        Return True
    End Function
 
    Public Sub ReceiveCallback(ByVal result As IAsyncResult)
        Dim sock As Socket = result.AsyncState
        Dim inlen As Integer
        _peerIP = New IPEndPoint(System.Net.IPAddress.Any, 0)
        Try
            inlen = sock.EndReceiveFrom(result, _peerIP)
        Catch ex As Exception
            ' only post messages if class socket reference is not null
            ' in all other cases, user has terminated the socket
            If _socket IsNot Nothing Then
                PostAsyncMessage("Receive operation failed with message: " & ex.Message)
            End If
            inlen = -1
        End Try
        ' if socket has been closed, don't process received data
        If _socket IsNot Nothing Then
            ' check that received data is long enough
            If inlen > 0 Then
                Dim packetVersion As Integer = SnmpPacket.GetProtocolVersion(_inbuffer, inlen)
                If packetVersion = SnmpVersion.Ver1 Then
                    Dim pkt As SnmpV1TrapPacket = New SnmpV1TrapPacket
                    Try
                        pkt.decode(_inbuffer, inlen)
                    Catch ex As Exception
                        PostAsyncMessage("Error parsing SNMPv1 Trap: " + ex.Message)
                        pkt = Nothing
                    End Try
                    If pkt IsNot Nothing Then
 
                        PostAsyncMessage(String.Format("** SNMPv1 TRAP from {0}", _peerIP.ToString()))
                        PostAsyncMessage(String.Format("*** community {0} generic id: {1} specific id: {2}", _
                                                       pkt.Community, pkt.Pdu.Generic, pkt.Pdu.Specific))
                        PostAsyncMessage(String.Format("*** PDU count: {0}", pkt.Pdu.VbCount))
                        Dim vb As Vb
                        For Each vb In pkt.Pdu.VbList
                            PostAsyncMessage(String.Format("**** Vb oid: {0} type: {1} value: {2}", _
                                vb.Oid.ToString(), SnmpConstants.GetTypeName(vb.Value.Type), _
                                vb.Value.ToString()))
                        Next
                        PostAsyncMessage("** End of SNMPv1 TRAP")
                    End If
                ElseIf packetVersion = SnmpVersion.Ver2 Then
                    Dim pkt As SnmpV2Packet = New SnmpV2Packet
                    Try
                        pkt.decode(_inbuffer, inlen)
                    Catch ex As Exception
                        pkt = Nothing
                    End Try
                    If pkt.Pdu.Type = PduType.V2Trap Then
                        PostAsyncMessage(String.Format("** SNMPv2 TRAP from {0}", _peerIP.ToString()))
                    ElseIf pkt.Pdu.Type = PduType.Inform Then
                        PostAsyncMessage(String.Format("** SNMPv2 INFORM from {0}", _peerIP.ToString()))
                    Else
                        PostAsyncMessage(String.Format("Invalid SNMPv2 packet from {0}", _peerIP.ToString()))
                        pkt = Nothing
                    End If
                    If pkt IsNot Nothing Then
                        PostAsyncMessage(String.Format("*** community {0} sysUpTime: {1} trapObjectID: {2}", _
                         pkt.Community, pkt.Pdu.TrapSysUpTime.ToString(), pkt.Pdu.TrapObjectID.ToString()))
                        PostAsyncMessage(String.Format("*** PDU count: {0}", pkt.Pdu.VbCount))
                        Dim vb As Vb
                        For Each vb In pkt.Pdu.VbList
                            PostAsyncMessage(String.Format("**** Vb oid: {0} type: {1} value: {2}", _
                             vb.Oid.ToString(), SnmpConstants.GetTypeName(vb.Value.Type), vb.Value.ToString()))
                        Next
                        If pkt.Pdu.Type = PduType.V2Trap Then
                            PostAsyncMessage("** End of SNMPv2 TRAP")
                        Else
                            PostAsyncMessage("** End of SNMPv2 INFORM")
                            ' send ACK back to the INFORM sender
                            Dim response As SnmpV2Packet = pkt.BuildInformResponse()
                            Dim buf() As Byte = response.encode()
                            _socket.SendTo(buf, _peerIP)
                        End If
                    End If
                End If
                RegisterReceiveOperation()
            End If
        End If
    End Sub
 
    Protected Delegate Sub PostAsyncMessageDelegate(ByVal msg As String)
 
    Protected Sub PostAsyncMessage(ByVal msg As String)
        If InvokeRequired Then
            Dim param() As Object
            param = New Object() {msg}
            Invoke(New PostAsyncMessageDelegate(AddressOf PostAsyncMessage), param)
        Else
            listBox1.Items.Add(msg)
        End If
    End Sub
 
    Private Sub OnStartChanged(ByVal sender As Object, ByVal e As EventArgs) _
        Handles startCheckBox.CheckedChanged
        If startCheckBox.Checked Then
            If Not InitializeReceiver() Then
                startCheckBox.Checked = False
            Else
                startCheckBox.Text = "S&top"
            End If
        Else
            StopReceiver()
            startCheckBox.Text = "&Start"
        End If
    End Sub
End Class