KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > snmp > SNMPv1AgentInterface


1 /*
2  * SNMP Package
3  *
4  * Copyright (C) 2004, Jonathan Sevy <jsevy@mcs.drexel.edu>
5  *
6  * This is free software. Redistribution and use in source and binary forms, with
7  * or without modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  * derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */

29
30
31 package snmp;
32
33 import java.io.*;
34 import java.net.*;
35 import java.util.*;
36
37
38 /**
39 * The class SNMPv1AgentInterface implements an interface for responding to requests sent from a remote SNMP
40 * manager. The agent simply listens for requests for information, and passes requested OIDs on to concrete
41 * subclasses of SNMPRequestListener. These are expected to retrieve requested information from the system,
42 * and return this to the agent interface for inclusion in a response to the manager.
43 * The approach is that from version 1 of SNMP, using no encryption of data. Communication occurs
44 * via UDP, using port 162, the standard SNMP trap port, as the destination port.
45 */

46
47 public class SNMPv1AgentInterface
48                     implements Runnable JavaDoc
49 {
50     public static final int SNMP_PORT = 161;
51     
52     // largest size for datagram packet payload; based on
53
// RFC 1157, need to handle messages of at least 484 bytes
54
public int receiveBufferSize = 512;
55     
56     int version = 0;
57     
58     private DatagramSocket dSocket;
59     private Thread JavaDoc receiveThread;
60     private Vector listenerVector;
61     
62     private PrintWriter errorLog;
63     
64     
65     
66     
67     /**
68     * Construct a new agent object to listen for requests from remote SNMP managers. The agent listens
69     * on the standard SNMP UDP port 161.
70     */

71     
72     public SNMPv1AgentInterface(int version)
73         throws SocketException
74     {
75         this(version, SNMP_PORT, new PrintWriter(System.out));
76     }
77     
78
79     
80     /**
81     * Construct a new agent object to listen for requests from remote SNMP managers. The agent listens
82     * on the supplied port.
83     */

84     
85     public SNMPv1AgentInterface(int version, int localPort)
86         throws SocketException
87     {
88         this(version, localPort, new PrintWriter(System.out));
89     }
90     
91     
92     
93     /**
94     * Construct a new agent object to listen for requests from remote SNMP managers. The agent listens
95     * on the supplied port, and sends error messages to the specified PrintWriter.
96     */

97     
98     public SNMPv1AgentInterface(int version, PrintWriter errorReceiver)
99         throws SocketException
100     {
101         this(version, SNMP_PORT, errorReceiver);
102     }
103     
104     
105     
106     /**
107     * Construct a new agent object to listen for requests from remote SNMP managers. The agent listens
108     * on the supplied port, and sends error messages to the specified PrintWriter.
109     */

110     
111     public SNMPv1AgentInterface(int version, int localPort, PrintWriter errorReceiver)
112         throws SocketException
113     {
114         
115         this.version = version;
116         
117         dSocket = new DatagramSocket(localPort);
118         
119         listenerVector = new Vector();
120             
121         receiveThread = new Thread JavaDoc(this);
122         
123         errorLog = errorReceiver;
124         
125     }
126     
127     
128     
129     /**
130     * Set the specified PrintWriter to receive error messages.
131     */

132     
133     public void setErrorReceiver(PrintWriter errorReceiver)
134     {
135         errorLog = errorReceiver;
136     }
137     
138     
139     
140     public void addRequestListener(SNMPRequestListener listener)
141     {
142         // see if listener already added; if so, ignore
143
for (int i = 0; i < listenerVector.size(); i++)
144         {
145             if (listener == listenerVector.elementAt(i))
146             {
147                 return;
148             }
149         }
150         
151         // if got here, it's not in the list; add it
152
listenerVector.add(listener);
153     }
154     
155     
156     
157     public void removeRequestListener(SNMPRequestListener listener)
158     {
159         // see if listener in list; if so, remove, if not, ignore
160
for (int i = 0; i < listenerVector.size(); i++)
161         {
162             if (listener == listenerVector.elementAt(i))
163             {
164                 listenerVector.removeElementAt(i);
165                 break;
166             }
167         }
168         
169     }
170
171     
172     
173     /**
174     * Start listening for requests from remote managers.
175     */

176     
177     public void startReceiving()
178     {
179         // if receiveThread not already running, start it
180
if (!receiveThread.isAlive())
181         {
182             receiveThread = new Thread JavaDoc(this);
183             receiveThread.start();
184         }
185     }
186     
187
188     
189     
190     /**
191     * Stop listening for requests from remote managers.
192     */

193     
194     public void stopReceiving()
195         throws SocketException
196     {
197         // interrupt receive thread so it will die a natural death
198
receiveThread.interrupt();
199     }
200
201     
202     
203     
204     
205     /**
206     * The run() method for the agent interface's listener. Just waits for SNMP request messages to
207     * come in on port 161 (or the port supplied in the constructor), then dispatches the retrieved
208     * SNMPPDU and community name to each of the registered SNMPRequestListeners by calling their
209     * processRequest() methods.
210     */

211     
212     public void run()
213     {
214         
215         
216         while (!receiveThread.isInterrupted())
217         {
218                 
219             try
220             {
221             
222                 DatagramPacket inPacket = new DatagramPacket(new byte[receiveBufferSize], receiveBufferSize);
223         
224                 dSocket.receive(inPacket);
225                 
226                 InetAddress requesterAddress = inPacket.getAddress();
227                 int requesterPort = inPacket.getPort();
228                 
229                 byte[] encodedMessage = inPacket.getData();
230                 
231                 /*
232                 System.out.println("Message bytes length (in): " + inPacket.getLength());
233                 
234                 System.out.println("Message bytes (in):");
235                 for (int i = 0; i < encodedMessage.length; ++i)
236                 {
237                     System.out.print(hexByte(encodedMessage[i]) + " ");
238                 }
239                 System.out.println("\n");
240                 */

241                 
242                 SNMPMessage receivedMessage = new SNMPMessage(SNMPBERCodec.extractNextTLV(encodedMessage,0).value);
243                 
244                 String JavaDoc communityName = receivedMessage.getCommunityName();
245                 SNMPPDU receivedPDU = receivedMessage.getPDU();
246                 byte requestPDUType = receivedPDU.getPDUType();
247                 
248                 //System.out.println("Received message; community = " + communityName + ", pdu type = " + Byte.toString(requestPDUType));
249
//System.out.println(" read community = " + readCommunityName + ", write community = " + writeCommunityName);
250

251                 SNMPSequence requestedVarList = receivedPDU.getVarBindList();
252                 
253                 Hashtable variablePairHashtable = new Hashtable();
254                 SNMPSequence responseVarList = new SNMPSequence();
255                 int errorIndex = 0;
256                 int errorStatus = SNMPRequestException.NO_ERROR;
257                 int requestID = receivedPDU.getRequestID();
258                 
259                 try
260                 {
261                 
262                     // pass the received PDU and community name to the processRequest method of any listeners;
263
// handle differently depending on whether the request is a get-next, or a get or set
264

265                     if ((requestPDUType == SNMPBERCodec.SNMPGETREQUEST) || (requestPDUType == SNMPBERCodec.SNMPSETREQUEST))
266                     {
267                 
268                         // pass the received PDU and community name to any registered listeners
269
for (int i = 0; i < listenerVector.size(); i++)
270                         {
271                             SNMPRequestListener listener = (SNMPRequestListener)listenerVector.elementAt(i);
272                             
273                             // return value is sequence of variable pairs for those OIDs handled by the listener
274
SNMPSequence handledVarList = listener.processRequest(receivedPDU, communityName);
275                                
276                             // add to Hashtable of handled OIDs, if not already there
277
for (int j = 0; j < handledVarList.size(); j++)
278                             {
279
280                                 SNMPSequence handledPair = (SNMPSequence)handledVarList.getSNMPObjectAt(j);
281                                 SNMPObjectIdentifier snmpOID = (SNMPObjectIdentifier)handledPair.getSNMPObjectAt(0);
282                                 SNMPObject snmpObject = (SNMPObject)handledPair.getSNMPObjectAt(1);
283
284                                 if (!variablePairHashtable.containsKey(snmpOID))
285                                 {
286                                     variablePairHashtable.put(snmpOID, snmpObject);
287                                 }
288
289                             }
290                             
291                         }
292                         
293                         
294                         
295                         // construct response containing the handled OIDs; if any OID not handled, throw exception
296
for (int j = 0; j < requestedVarList.size(); j++)
297                         {
298                             SNMPSequence requestPair = (SNMPSequence)requestedVarList.getSNMPObjectAt(j);
299                             SNMPObjectIdentifier snmpOID = (SNMPObjectIdentifier)requestPair.getSNMPObjectAt(0);
300
301                             // find corresponding SNMP object in hashtable
302
if (!variablePairHashtable.containsKey(snmpOID))
303                             {
304                                 errorIndex = j + 1;
305                                 errorStatus = SNMPRequestException.VALUE_NOT_AVAILABLE;
306                                 
307                                 if (requestPDUType == SNMPBERCodec.SNMPGETREQUEST)
308                                     throw new SNMPGetException("OID " + snmpOID + " not handled", errorIndex, errorStatus);
309                                 else
310                                     throw new SNMPSetException("OID " + snmpOID + " not handled", errorIndex, errorStatus);
311                             }
312
313                             SNMPObject snmpObject = (SNMPObject)variablePairHashtable.get(snmpOID);
314                             SNMPVariablePair responsePair = new SNMPVariablePair(snmpOID, snmpObject);
315
316                             responseVarList.addSNMPObject(responsePair);
317                             
318                         }
319                     
320                     }
321                     else if (requestPDUType == SNMPBERCodec.SNMPGETNEXTREQUEST)
322                     {
323                         // pass the received PDU and community name to any registered listeners
324
for (int i = 0; i < listenerVector.size(); i++)
325                         {
326                             SNMPRequestListener listener = (SNMPRequestListener)listenerVector.elementAt(i);
327                             
328                             // return value is sequence of nested variable pairs for those OIDs handled by the listener:
329
// consists of (supplied OID, (following OID, value)) nested variable pairs
330
SNMPSequence handledVarList = listener.processGetNextRequest(receivedPDU, communityName);
331                                
332                             // add variable pair to Hashtable of handled OIDs, if not already there
333
for (int j = 0; j < handledVarList.size(); j++)
334                             {
335                                 
336                                 SNMPSequence handledPair = (SNMPSequence)handledVarList.getSNMPObjectAt(j);
337                                 SNMPObjectIdentifier snmpOID = (SNMPObjectIdentifier)handledPair.getSNMPObjectAt(0);
338                                 SNMPObject snmpObject = (SNMPObject)handledPair.getSNMPObjectAt(1);
339                                 
340                                 if (!variablePairHashtable.containsKey(snmpOID))
341                                 {
342                                     variablePairHashtable.put(snmpOID, snmpObject);
343                                 }
344                                 
345                             }
346                             
347                         }
348                         
349                         
350                         
351                         // construct response containing the handled OIDs; if any OID not handled, throw exception
352
for (int j = 0; j < requestedVarList.size(); j++)
353                         {
354                             SNMPSequence requestPair = (SNMPSequence)requestedVarList.getSNMPObjectAt(j);
355                             SNMPObjectIdentifier snmpOID = (SNMPObjectIdentifier)requestPair.getSNMPObjectAt(0);
356
357                             // find corresponding SNMP object in hashtable
358
if (!variablePairHashtable.containsKey(snmpOID))
359                             {
360                                errorIndex = j + 1;
361                                errorStatus = SNMPRequestException.VALUE_NOT_AVAILABLE;
362                                
363                                throw new SNMPGetException("OID " + snmpOID + " not handled", errorIndex, errorStatus);
364                             }
365
366                             // value in hashtable is complete variable pair
367
SNMPVariablePair responsePair = (SNMPVariablePair)variablePairHashtable.get(snmpOID);
368
369                             responseVarList.addSNMPObject(responsePair);
370                             
371                         }
372                         
373                     }
374                     else
375                     {
376                         // some other PDU type; silently ignore
377
continue;
378                     }
379                     
380                     
381                 }
382                 catch (SNMPRequestException e)
383                 {
384                     // exception should contain the index and cause of error; return this in message
385
errorIndex = e.errorIndex;
386                     errorStatus = e.errorStatus;
387                     
388                     // just return request variable list as response variable list
389
responseVarList = requestedVarList;
390                 }
391                 catch (Exception JavaDoc e)
392                 {
393                     // don't have a specific index and cause of error; return message as general error, index 0
394
errorIndex = 0;
395                     errorStatus = SNMPRequestException.FAILED;
396                     
397                     // just return request variable list as response variable list
398
responseVarList = requestedVarList;
399                     
400                     // also report the exception locally
401
errorLog.println("Exception while processing request: " + e.toString());
402                     errorLog.flush();
403                 }
404                 
405                 
406                 SNMPPDU pdu = new SNMPPDU(SNMPBERCodec.SNMPGETRESPONSE, requestID, errorStatus, errorIndex, responseVarList);
407                 SNMPMessage message = new SNMPMessage(version, communityName, pdu);
408                 byte[] messageEncoding = message.getBEREncoding();
409                 DatagramPacket outPacket = new DatagramPacket(messageEncoding, messageEncoding.length, requesterAddress, requesterPort);
410         
411         
412                 dSocket.send(outPacket);
413                 
414                 
415         
416             }
417             catch (IOException e)
418             {
419                 // just report the problem
420
errorLog.println("IOException during request processing: " + e.getMessage());
421                 errorLog.flush();
422             }
423             catch (SNMPBadValueException e)
424             {
425                 // just report the problem
426
errorLog.println("SNMPBadValueException during request processing: " + e.getMessage());
427                 errorLog.flush();
428             }
429             catch (Exception JavaDoc e)
430             {
431                 // just report the problem
432
errorLog.println("Exception during request processing: " + e.toString());
433                 errorLog.flush();
434             }
435         
436         }
437                 
438     }
439     
440     
441     
442     
443     private String JavaDoc hexByte(byte b)
444     {
445         int pos = b;
446         if (pos < 0)
447             pos += 256;
448         String JavaDoc returnString = new String JavaDoc();
449         returnString += Integer.toHexString(pos/16);
450         returnString += Integer.toHexString(pos%16);
451         return returnString;
452     }
453     
454     
455     
456     /**
457     * Set the size of the buffer used to receive response packets. RFC 1157 stipulates that an SNMP
458     * implementation must be able to receive packets of at least 484 bytes, so if you try to set the
459     * size to a value less than this, the receive buffer size will be set to 484 bytes. In addition,
460     * the maximum size of a UDP packet payload is 65535 bytes, so setting the buffer to a larger size
461     * will just waste memory. The default value is 512 bytes. The value may need to be increased if
462     * get-requests are issued for multiple OIDs.
463     */

464     
465     public void setReceiveBufferSize(int receiveBufferSize)
466     {
467         if (receiveBufferSize >= 484)
468         {
469             this.receiveBufferSize = receiveBufferSize;
470         }
471         else
472         {
473             this.receiveBufferSize = 484;
474         }
475     }
476     
477     
478     
479     /**
480     * Returns the current size of the buffer used to receive response packets.
481     */

482     
483     public int getReceiveBufferSize()
484     {
485         return this.receiveBufferSize;
486     }
487     
488     
489     
490 }
491
492
493
494
Popular Tags