KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > snmp > daemon > SnmpRequestHandler


1 /*
2  * @(#)file SnmpRequestHandler.java
3  * @(#)author Sun Microsystems, Inc.
4  * @(#)version 4.31
5  * @(#)date 08/02/09
6  *
7  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
8  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
9  *
10  */

11
12
13 package com.sun.jmx.snmp.daemon;
14
15
16
17 // java import
18
//
19
import java.util.Vector JavaDoc;
20 import java.util.Enumeration JavaDoc;
21 import java.util.Hashtable JavaDoc;
22 import java.io.InterruptedIOException JavaDoc;
23 import java.net.DatagramSocket JavaDoc;
24 import java.net.DatagramPacket JavaDoc;
25 import java.net.SocketException JavaDoc;
26
27 // jmx imports
28
//
29
import javax.management.MBeanServer JavaDoc;
30 import javax.management.ObjectName JavaDoc;
31 import com.sun.jmx.snmp.SnmpMessage;
32 import com.sun.jmx.snmp.SnmpPduFactory;
33 import com.sun.jmx.snmp.SnmpPduBulk;
34 import com.sun.jmx.snmp.SnmpPduPacket;
35 import com.sun.jmx.snmp.SnmpPduRequest;
36 import com.sun.jmx.snmp.SnmpPduTrap;
37 import com.sun.jmx.snmp.SnmpValue;
38 import com.sun.jmx.snmp.SnmpVarBind;
39 import com.sun.jmx.snmp.SnmpVarBindList;
40 import com.sun.jmx.snmp.SnmpDefinitions;
41 import com.sun.jmx.snmp.SnmpStatusException;
42 import com.sun.jmx.snmp.SnmpTooBigException;
43 import com.sun.jmx.snmp.SnmpDataTypeEnums;
44
45 // RI imports
46
//
47
import com.sun.jmx.trace.Trace;
48
49 // SNMP runtime import
50
//
51
import com.sun.jmx.snmp.agent.SnmpMibAgent;
52 import com.sun.jmx.snmp.agent.SnmpUserDataFactory;
53 //import com.sun.jmx.snmp.IPAcl.IPAcl;
54
import com.sun.jmx.snmp.InetAddressAcl;
55
56
57 class SnmpRequestHandler extends ClientHandler implements SnmpDefinitions {
58
59     private transient DatagramSocket JavaDoc socket = null ;
60     private transient DatagramPacket JavaDoc packet = null ;
61     private transient Vector JavaDoc mibs = null ;
62   
63     /**
64      * Contains the list of sub-requests associated to the current request.
65      */

66     private transient Hashtable JavaDoc subs = null ;
67     
68     /**
69      * Reference on the MIBS
70      */

71     private transient SnmpMibTree root;
72  
73     private transient Object JavaDoc ipacl = null ;
74     private transient SnmpPduFactory pduFactory = null ;
75     private transient SnmpUserDataFactory userDataFactory = null ;
76     private transient SnmpAdaptorServer adaptor = null;
77     /**
78      * Full constructor
79      */

80     public SnmpRequestHandler(SnmpAdaptorServer server, int id,
81                               DatagramSocket JavaDoc s, DatagramPacket JavaDoc p,
82                               SnmpMibTree tree, Vector JavaDoc m, Object JavaDoc a,
83                               SnmpPduFactory factory,
84                               SnmpUserDataFactory dataFactory,
85                               MBeanServer JavaDoc f, ObjectName JavaDoc n)
86     {
87         super(server, id, f, n);
88     
89     // Need a reference on SnmpAdaptorServer for getNext & getBulk,
90
// in case of oid equality (mib overlapping).
91
//
92
adaptor = server;
93         socket = s;
94         packet = p;
95         root= tree;
96         mibs = (Vector JavaDoc) m.clone();
97         subs= new Hashtable JavaDoc(mibs.size());
98         ipacl = a;
99         pduFactory = factory ;
100         userDataFactory = dataFactory ;
101         //thread.start();
102
}
103     
104     /**
105      * Treat the request available in 'packet' and send the result
106      * back to the client.
107      * Note: we overwrite 'packet' with the response bytes.
108      */

109     public void doRun() {
110   
111         // Trace the input packet
112
//
113
if (isTraceOn()) {
114             trace("doRun", "Packet received:\n" + SnmpMessage.dumpHexBuffer(packet.getData(), 0, packet.getLength()));
115         }
116
117         // Let's build the response packet
118
//
119
DatagramPacket JavaDoc respPacket = makeResponsePacket(packet) ;
120     
121         // Trace the output packet
122
//
123
if (isTraceOn() && (respPacket != null)) {
124             trace("doRun", "Packet to be sent:\n" + SnmpMessage.dumpHexBuffer(respPacket.getData(), 0, respPacket.getLength()));
125         }
126     
127         // Send the response packet if any
128
//
129
if (respPacket != null) {
130             try {
131                 socket.send(respPacket) ;
132             }
133             catch (SocketException JavaDoc e) {
134                 if (isDebugOn()) {
135                     if (e.getMessage().equals(InterruptSysCallMsg))
136                         debug("doRun", "interrupted");
137                     else {
138                         debug("doRun", "i/o exception");
139                         debug("doRun", e);
140                     }
141                 }
142             }
143             catch(InterruptedIOException JavaDoc e) {
144                 if (isDebugOn()) {
145                     debug("doRun", "interrupted");
146                 }
147             }
148             catch(Exception JavaDoc e) {
149                 if (isDebugOn()) {
150                     debug("doRun", "failure when sending response");
151                     debug("doRun", e);
152                 }
153             }
154         }
155     }
156
157     /**
158      * Here we make a response packet from a request packet.
159      * We return null if there no response packet to sent.
160      */

161     private DatagramPacket JavaDoc makeResponsePacket(DatagramPacket JavaDoc reqPacket) {
162         DatagramPacket JavaDoc respPacket = null ;
163     
164         // Transform the request packet into a request SnmpMessage
165
//
166
SnmpMessage reqMsg = new SnmpMessage() ;
167         try {
168             reqMsg.decodeMessage(reqPacket.getData(), reqPacket.getLength()) ;
169             reqMsg.address = reqPacket.getAddress() ;
170             reqMsg.port = reqPacket.getPort() ;
171         }
172         catch(SnmpStatusException x) {
173             if (isDebugOn()) {
174                 debug("makeResponsePacket", "packet decoding failed");
175         debug("makeResponsePacket", x);
176             }
177             reqMsg = null ;
178             ((SnmpAdaptorServer)adaptorServer).incSnmpInASNParseErrs(1) ;
179         }
180     
181         // Make the response SnmpMessage if any
182
//
183
SnmpMessage respMsg = null ;
184         if (reqMsg != null) {
185             respMsg = makeResponseMessage(reqMsg) ;
186         }
187     
188         // Try to transform the response SnmpMessage into response packet.
189
// NOTE: we overwrite the request packet.
190
//
191
if (respMsg != null) {
192             try {
193                 reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ;
194                 respPacket = reqPacket ;
195             }
196             catch(SnmpTooBigException x) {
197                 if (isDebugOn()) {
198                     debug("makeResponsePacket", "response message is too big");
199                 }
200                 try {
201                     respMsg = newTooBigMessage(reqMsg) ;
202                     reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ;
203                     respPacket = reqPacket ;
204                 }
205                 catch(SnmpTooBigException xx) {
206                     if (isDebugOn()) {
207                         debug("makeResponsePacket", "'too big' is 'too big' !!!");
208                     }
209             adaptor.incSnmpSilentDrops(1);
210                 }
211             }
212         }
213     
214         return respPacket ;
215     }
216   
217     /**
218      * Here we make a response message from a request message.
219      * We return null if there is no message to reply.
220      */

221     private SnmpMessage makeResponseMessage(SnmpMessage reqMsg) {
222         SnmpMessage respMsg = null ;
223     
224         // Transform the request message into a request pdu
225
//
226
SnmpPduPacket reqPdu = null ;
227         Object JavaDoc userData = null;
228         try {
229             reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ;
230             if (reqPdu != null && userDataFactory != null)
231                 userData = userDataFactory.allocateUserData(reqPdu);
232         }
233         catch(SnmpStatusException x) {
234             reqPdu = null ;
235             SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
236             snmpServer.incSnmpInASNParseErrs(1) ;
237             if (x.getStatus()== SnmpDefinitions.snmpWrongSnmpVersion)
238                 snmpServer.incSnmpInBadVersions(1) ;
239             if (isDebugOn()) {
240                 debug("makeResponseMessage", "message decoding failed");
241         debug("makeResponseMessage",x);
242             }
243         }
244
245         // Make the response pdu if any
246
//
247
SnmpPduPacket respPdu = null ;
248         if (reqPdu != null) {
249             respPdu = makeResponsePdu(reqPdu,userData) ;
250             try {
251                 if (userDataFactory != null)
252                     userDataFactory.releaseUserData(userData,respPdu);
253             } catch (SnmpStatusException x) {
254                 respPdu = null;
255             }
256         }
257     
258         // Try to transform the response pdu into a response message if any
259
//
260
if (respPdu != null) {
261             try {
262                 respMsg = (SnmpMessage)pduFactory.
263             encodeSnmpPdu(respPdu, packet.getData().length) ;
264             }
265             catch(SnmpStatusException x) {
266                 respMsg = null ;
267                 if (isDebugOn()) {
268                     debug("makeResponseMessage",
269               "failure when encoding the response message");
270                     debug("makeResponseMessage", x);
271                 }
272             }
273             catch(SnmpTooBigException x) {
274                 if (isDebugOn()) {
275                     debug("makeResponseMessage",
276               "response message is too big");
277                 }
278
279                 try {
280                     // if the PDU is too small, why should we try to do
281
// recovery ?
282
//
283
if (packet.getData().length <=32)
284                         throw x;
285                     int pos= x.getVarBindCount();
286                     if (isDebugOn()) {
287                         debug("makeResponseMessage", "fail on element" + pos);
288                     }
289                     int old= 0;
290                     while (true) {
291                         try {
292                             respPdu = reduceResponsePdu(reqPdu, respPdu, pos) ;
293                             respMsg = (SnmpMessage)pduFactory.
294                 encodeSnmpPdu(respPdu,
295                           packet.getData().length -32) ;
296                             break;
297                         } catch (SnmpTooBigException xx) {
298                             if (isDebugOn()) {
299                                 debug("makeResponseMessage",
300                       "response message is still too big");
301                             }
302                             old= pos;
303                             pos= xx.getVarBindCount();
304                             if (isDebugOn()) {
305                                 debug("makeResponseMessage",
306                       "fail on element" + pos);
307                             }
308                             if (pos == old) {
309                                 // we can not go any further in trying to
310
// reduce the message !
311
//
312
throw xx;
313                             }
314                         }
315                     }// end of loop
316
} catch(SnmpStatusException xx) {
317                     respMsg = null ;
318                     if (isDebugOn()) {
319                         debug("makeResponseMessage",
320                   "failure when encoding the response message");
321                         debug("makeResponseMessage", xx);
322                     }
323                 }
324                 catch(SnmpTooBigException xx) {
325                     try {
326                         respPdu = newTooBigPdu(reqPdu) ;
327                         respMsg = (SnmpMessage)pduFactory.
328                 encodeSnmpPdu(respPdu, packet.getData().length) ;
329                     }
330                     catch(SnmpTooBigException xxx) {
331                         respMsg = null ;
332                         if (isDebugOn()) {
333                             debug("makeResponseMessage",
334                   "'too big' is 'too big' !!!");
335                         }
336             adaptor.incSnmpSilentDrops(1);
337                     }
338                     catch(Exception JavaDoc xxx) {
339             debug("makeResponseMessage", xxx);
340                         respMsg = null ;
341                     }
342                 }
343                 catch(Exception JavaDoc xx) {
344             debug("makeResponseMessage", xx);
345                     respMsg = null ;
346                 }
347             }
348         }
349         return respMsg ;
350     }
351   
352     /**
353      * Here we make a response pdu from a request pdu.
354      * We return null if there is no pdu to reply.
355      */

356     private SnmpPduPacket makeResponsePdu(SnmpPduPacket reqPdu,
357                                           Object JavaDoc userData) {
358         
359         SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
360         SnmpPduPacket respPdu = null ;
361     
362         snmpServer.updateRequestCounters(reqPdu.type) ;
363         if (reqPdu.varBindList != null)
364             snmpServer.updateVarCounters(reqPdu.type,
365                                          reqPdu.varBindList.length) ;
366     
367         if (checkPduType(reqPdu)) {
368             respPdu = checkAcl(reqPdu) ;
369             if (respPdu == null) { // reqPdu is accepted by ACLs
370
if (mibs.size() < 1) {
371                     if (isTraceOn()) {
372                         trace("makeResponsePdu", "Request " +
373                               reqPdu.requestId +
374                               " received but no MIB registered.");
375                     }
376             return makeNoMibErrorPdu((SnmpPduRequest)reqPdu, userData);
377                 }
378                 switch(reqPdu.type) {
379                 case SnmpPduPacket.pduGetRequestPdu:
380                 case SnmpPduPacket.pduGetNextRequestPdu:
381                 case SnmpPduPacket.pduSetRequestPdu:
382                     respPdu = makeGetSetResponsePdu((SnmpPduRequest)reqPdu,
383                                                     userData) ;
384                     break ;
385             
386                 case SnmpPduPacket.pduGetBulkRequestPdu:
387                     respPdu = makeGetBulkResponsePdu((SnmpPduBulk)reqPdu,
388                                                      userData) ;
389                     break ;
390                 }
391             }
392             else { // reqPdu is rejected by ACLs
393
// respPdu contains the error response to be sent.
394
// We send this response only if authResEnabled is true.
395
if (!snmpServer.getAuthRespEnabled()) { // No response should be sent
396
respPdu = null ;
397                 }
398                 if (snmpServer.getAuthTrapEnabled()) { // A trap must be sent
399
try {
400                         snmpServer.snmpV1Trap(SnmpPduTrap.
401                           trapAuthenticationFailure, 0,
402                           new SnmpVarBindList()) ;
403                     }
404                     catch(Exception JavaDoc x) {
405                         if (isDebugOn()) {
406                             debug("makeResponsePdu",
407                   "failure when sending authentication trap");
408                             debug("makeResponsePdu", x);
409                         }
410                     }
411                 }
412             }
413         }
414         return respPdu ;
415     }
416   
417     //
418
// Generates a response packet, filling the values in the
419
// varbindlist with one of endOfMibView, noSuchObject, noSuchInstance
420
// according to the value of <code>status</code>
421
//
422
// @param statusTag should be one of:
423
// <li>SnmpDataTypeEnums.errEndOfMibViewTag</li>
424
// <li>SnmpDataTypeEnums.errNoSuchObjectTag</li>
425
// <li>SnmpDataTypeEnums.errNoSuchInstanceTag</li>
426
//
427
SnmpPduPacket makeErrorVarbindPdu(SnmpPduPacket req, int statusTag) {
428
429         final SnmpVarBind[] vblist = req.varBindList;
430         final int length = vblist.length;
431
432         switch (statusTag) {
433         case SnmpDataTypeEnums.errEndOfMibViewTag:
434             for (int i=0 ; i<length ; i++)
435                 vblist[i].value = SnmpVarBind.endOfMibView;
436             break;
437         case SnmpDataTypeEnums.errNoSuchObjectTag:
438             for (int i=0 ; i<length ; i++)
439                 vblist[i].value = SnmpVarBind.noSuchObject;
440             break;
441         case SnmpDataTypeEnums.errNoSuchInstanceTag:
442             for (int i=0 ; i<length ; i++)
443                 vblist[i].value = SnmpVarBind.noSuchInstance;
444             break;
445         default:
446             return newErrorResponsePdu(req,snmpRspGenErr,1);
447         }
448         return newValidResponsePdu(req,vblist);
449     }
450
451     // Generates an appropriate response when no mib is registered in
452
// the adaptor.
453
//
454
// <li>If the version is V1:</li>
455
// <ul><li>Generates a NoSuchName error V1 response PDU</li></ul>
456
// <li>If the version is V2:</li>
457
// <ul><li>If the request is a GET, fills the varbind list with
458
// NoSuchObject's</li>
459
// <li>If the request is a GET-NEXT/GET-BULK, fills the varbind
460
// list with EndOfMibView's</li>
461
// <li>If the request is a SET, generates a NoAccess error V2
462
// response PDU</li>
463
// </ul>
464
//
465
//
466
SnmpPduPacket makeNoMibErrorPdu(SnmpPduRequest req, Object JavaDoc userData) {
467         // There is no agent registered
468
//
469
if (req.version == SnmpDefinitions.snmpVersionOne) {
470             // Version 1: => NoSuchName
471
return
472                 newErrorResponsePdu(req,snmpRspNoSuchName,1);
473         } else if (req.version == SnmpDefinitions.snmpVersionTwo) {
474             // Version 2: => depends on PDU type
475
switch (req.type) {
476             case pduSetRequestPdu :
477             case pduWalkRequest :
478                 // SET request => NoAccess
479
return
480                     newErrorResponsePdu(req,snmpRspNoAccess,1);
481             case pduGetRequestPdu :
482                 // GET request => NoSuchObject
483
return
484                     makeErrorVarbindPdu(req,SnmpDataTypeEnums.
485                     errNoSuchObjectTag);
486             case pduGetNextRequestPdu :
487             case pduGetBulkRequestPdu :
488                 // GET-NEXT or GET-BULK => EndOfMibView
489
return
490                     makeErrorVarbindPdu(req,SnmpDataTypeEnums.
491                     errEndOfMibViewTag);
492             default:
493             }
494         }
495         // Something wrong here: => snmpRspGenErr
496
return newErrorResponsePdu(req,snmpRspGenErr,1);
497     }
498
499     /**
500      * Here we make the response pdu from a get/set request pdu.
501      * At this level, the result is never null.
502      */

503     private SnmpPduPacket makeGetSetResponsePdu(SnmpPduRequest req,
504                                                 Object JavaDoc userData) {
505    
506         // Create the trhead group specific for handling sub-requests
507
// associated to the current request. Use the invoke id
508
//
509
// Nice idea to use a thread group on a request basis.
510
// However the impact on performance is terrible !
511
// theGroup= new ThreadGroup(thread.getThreadGroup(),
512
// "request " + String.valueOf(req.requestId));
513

514         // Let's build the varBindList for the response pdu
515
//
516

517         if (req.varBindList == null) {
518             // Good ! Let's make a full response pdu.
519
//
520
return newValidResponsePdu(req, null) ;
521         }
522
523         // First we need to split the request into subrequests
524
//
525
splitRequest(req);
526         int nbSubRequest= subs.size();
527         if (nbSubRequest == 1)
528             return turboProcessingGetSet(req,userData);
529   
530     
531         // Execute all the subrequests resulting from the split of the
532
// varbind list.
533
//
534
SnmpPduPacket result= executeSubRequest(req,userData);
535         if (result != null)
536             // It means that an error occured. The error is already
537
// formatted by the executeSubRequest
538
// method.
539
return result;
540         
541         // So far so good. So we need to concatenate all the answers.
542
//
543
if (isTraceOn()) {
544             trace("makeGetSetResponsePdu",
545           "Build the unified response for request " + req.requestId);
546         }
547         return mergeResponses(req);
548     }
549   
550     /**
551      * The method runs all the sub-requests associated to the current
552      * instance of SnmpRequestHandler.
553      */

554     private SnmpPduPacket executeSubRequest(SnmpPduPacket req,
555                                             Object JavaDoc userData) {
556     
557         int errorStatus = SnmpDefinitions.snmpRspNoError ;
558         int nbSubRequest= subs.size();
559             
560     int i=0;
561         // If it's a set request, we must first check any varBind
562
//
563
if (req.type == pduSetRequestPdu) {
564      
565         i=0;
566             for(Enumeration JavaDoc e= subs.elements(); e.hasMoreElements() ; i++) {
567                 // Indicate to the sub request that a check must be invoked ...
568
// OK we should have defined out own tag for that !
569
//
570
SnmpSubRequestHandler sub= (SnmpSubRequestHandler)
571             e.nextElement();
572                 sub.setUserData(userData);
573                 sub.type= pduWalkRequest;
574
575         sub.run();
576
577         sub.type= pduSetRequestPdu;
578
579         if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) {
580             // No point to go any further.
581
//
582
if (isDebugOn()) {
583             debug("executeSubRequest", "an error occurs");
584             }
585
586             return newErrorResponsePdu(req, errorStatus,
587                            sub.getErrorIndex() + 1) ;
588         }
589             }
590         }// end processing check operation for a set PDU.
591

592         // Let's start the sub-requests.
593
//
594
i=0;
595         for(Enumeration JavaDoc e= subs.elements(); e.hasMoreElements() ;i++) {
596             SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
597         /* NPCTE fix for bugId 4492741, esc 0, 16-August 2001 */
598         sub.setUserData(userData);
599     /* end of NPCTE fix for bugId 4492741 */
600
601         sub.run();
602
603             if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) {
604                 // No point to go any further.
605
//
606
if (isDebugOn()) {
607                     debug("executeSubRequest", "an error occurs");
608                 }
609
610                 return newErrorResponsePdu(req, errorStatus,
611                        sub.getErrorIndex() + 1) ;
612             }
613     }
614     
615         // everything is ok
616
//
617
return null;
618     }
619   
620     /**
621      * Optimize when there is only one sub request
622      */

623     private SnmpPduPacket turboProcessingGetSet(SnmpPduRequest req,
624                                                 Object JavaDoc userData) {
625   
626         int errorStatus = SnmpDefinitions.snmpRspNoError ;
627         SnmpSubRequestHandler sub= (SnmpSubRequestHandler)
628         subs.elements().nextElement();
629         sub.setUserData(userData);
630
631         // Indicate to the sub request that a check must be invoked ...
632
// OK we should have defined out own tag for that !
633
//
634
if (req.type == SnmpDefinitions.pduSetRequestPdu) {
635             sub.type= pduWalkRequest;
636             sub.run();
637             sub.type= pduSetRequestPdu;
638        
639             // Check the error status.
640
//
641
errorStatus= sub.getErrorStatus();
642             if (errorStatus != SnmpDefinitions.snmpRspNoError) {
643                 // No point to go any further.
644
//
645
return newErrorResponsePdu(req, errorStatus,
646                        sub.getErrorIndex() + 1) ;
647             }
648         }
649   
650         // process the operation
651
//
652

653         sub.run();
654         errorStatus= sub.getErrorStatus();
655         if (errorStatus != SnmpDefinitions.snmpRspNoError) {
656             // No point to go any further.
657
//
658
if (isDebugOn()) {
659                 debug("turboProcessingGetSet", "an error occurs");
660             }
661             int realIndex= sub.getErrorIndex() + 1;
662             return newErrorResponsePdu(req, errorStatus, realIndex) ;
663         }
664     
665         // So far so good. So we need to concatenate all the answers.
666
//
667

668         if (isTraceOn()) {
669             trace("turboProcessingGetSet",
670           "build the unified response for request " + req.requestId);
671         }
672         return mergeResponses(req);
673     }
674   
675     /**
676      * Here we make the response pdu for a bulk request.
677      * At this level, the result is never null.
678      */

679     private SnmpPduPacket makeGetBulkResponsePdu(SnmpPduBulk req,
680                                                  Object JavaDoc userData) {
681    
682         SnmpVarBind[] respVarBindList = null ;
683     
684         // RFC 1905, Section 4.2.3, p14
685
int L = req.varBindList.length ;
686         int N = Math.max(Math.min(req.nonRepeaters, L), 0) ;
687         int M = Math.max(req.maxRepetitions, 0) ;
688         int R = L - N ;
689     
690         if (req.varBindList == null) {
691             // Good ! Let's make a full response pdu.
692
//
693
return newValidResponsePdu(req, null) ;
694         }
695     
696         // Split the request into subrequests.
697
//
698
splitBulkRequest(req, N, M, R);
699         SnmpPduPacket result= executeSubRequest(req,userData);
700         if (result != null)
701             return result;
702     
703         respVarBindList= mergeBulkResponses(N + (M * R));
704
705         // Now we remove useless trailing endOfMibView.
706
//
707
int m2 ; // respVarBindList[m2] item and next are going to be removed
708
int t = respVarBindList.length ;
709         while ((t > N) && (respVarBindList[t-1].
710                value.equals(SnmpVarBind.endOfMibView))) {
711             t-- ;
712         }
713         if (t == N)
714             m2 = N + R ;
715         else
716             m2 = N + ((t -1 -N) / R + 2) * R ; // Trivial, of course...
717
if (m2 < respVarBindList.length) {
718             SnmpVarBind[] truncatedList = new SnmpVarBind[m2] ;
719             for (int i = 0 ; i < m2 ; i++) {
720                 truncatedList[i] = respVarBindList[i] ;
721             }
722             respVarBindList = truncatedList ;
723         }
724
725         // Good ! Let's make a full response pdu.
726
//
727
return newValidResponsePdu(req, respVarBindList) ;
728     }
729   
730     /**
731      * Check the type of the pdu: only the get/set/bulk request
732      * are accepted.
733      */

734     private boolean checkPduType(SnmpPduPacket pdu) {
735
736         boolean result = true ;
737
738         switch(pdu.type) {
739     
740         case SnmpDefinitions.pduGetRequestPdu:
741         case SnmpDefinitions.pduGetNextRequestPdu:
742         case SnmpDefinitions.pduSetRequestPdu:
743         case SnmpDefinitions.pduGetBulkRequestPdu:
744             result = true ;
745             break;
746
747         default:
748             if (isDebugOn()) {
749                 debug("checkPduType", "cannot respond to this kind of PDU");
750             }
751             result = false ;
752             break;
753         }
754     
755         return result ;
756     }
757   
758     /**
759      * Check if the specified pdu is conform to the ACL.
760      * This method returns null if the pdu is ok. If not, it returns
761      * the response pdu to be replied.
762      */

763     private SnmpPduPacket checkAcl(SnmpPduPacket pdu) {
764         SnmpPduPacket response = null ;
765         String JavaDoc community = new String JavaDoc(pdu.community) ;
766     
767         // We check the pdu type and create an error response if
768
// the check failed.
769
//
770
if (ipacl != null) {
771             if (pdu.type == SnmpDefinitions.pduSetRequestPdu) {
772                 if (!((InetAddressAcl)ipacl).
773             checkWritePermission(pdu.address, community)) {
774                     if (isTraceOn()) {
775                         trace("checkAcl", "sender is " + pdu.address +
776                   " with " + community);
777                         trace("checkAcl", "sender has no write permission");
778                     }
779             int err = SnmpSubRequestHandler.
780             mapErrorStatus(SnmpDefinitions.
781                        snmpRspAuthorizationError,
782                        pdu.version, pdu.type);
783                     response = newErrorResponsePdu(pdu, err, 0) ;
784                 }
785                 else {
786                     if (isTraceOn()) {
787                         trace("checkAcl", "sender is " + pdu.address +
788                   " with " + community);
789                         trace("checkAcl", "sender has write permission");
790                     }
791                 }
792             }
793             else {
794                 if (!((InetAddressAcl)ipacl).checkReadPermission(pdu.address, community)) {
795                     if (isTraceOn()) {
796                         trace("checkAcl", "sender is " + pdu.address +
797                   " with " + community);
798                         trace("checkAcl", "sender has no read permission");
799                     }
800             int err = SnmpSubRequestHandler.
801             mapErrorStatus(SnmpDefinitions.
802                        snmpRspAuthorizationError,
803                        pdu.version, pdu.type);
804                     response = newErrorResponsePdu(pdu,
805                            err,
806                            0);
807             SnmpAdaptorServer snmpServer =
808             (SnmpAdaptorServer)adaptorServer;
809             snmpServer.updateErrorCounters(SnmpDefinitions.
810                            snmpRspNoSuchName);
811                 }
812         else {
813                     if (isTraceOn()) {
814                         trace("checkAcl", "sender is " + pdu.address +
815                   " with " + community);
816                         trace("checkAcl", "sender has read permission");
817                     }
818                 }
819             }
820         }
821     
822         // If the response is not null, this means the pdu is rejected.
823
// So let's update the statistics.
824
//
825
if (response != null) {
826             SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
827             snmpServer.incSnmpInBadCommunityUses(1) ;
828             if (((InetAddressAcl)ipacl).checkCommunity(community) == false)
829                 snmpServer.incSnmpInBadCommunityNames(1) ;
830         }
831     
832         return response ;
833     }
834     
835     /**
836      * Make a response pdu with the specified error status and index.
837      * NOTE: the response pdu share its varBindList with the request pdu.
838      */

839     private SnmpPduRequest newValidResponsePdu(SnmpPduPacket reqPdu,
840                            SnmpVarBind[] varBindList) {
841         SnmpPduRequest result = new SnmpPduRequest() ;
842     
843         result.address = reqPdu.address ;
844         result.port = reqPdu.port ;
845         result.version = reqPdu.version ;
846         result.community = reqPdu.community ;
847         result.type = result.pduGetResponsePdu ;
848         result.requestId = reqPdu.requestId ;
849         result.errorStatus = SnmpDefinitions.snmpRspNoError ;
850         result.errorIndex = 0 ;
851         result.varBindList = varBindList ;
852     
853         ((SnmpAdaptorServer)adaptorServer).
854         updateErrorCounters(result.errorStatus) ;
855     
856         return result ;
857     }
858   
859     /**
860      * Make a response pdu with the specified error status and index.
861      * NOTE: the response pdu share its varBindList with the request pdu.
862      */

863     private SnmpPduRequest newErrorResponsePdu(SnmpPduPacket req,int s,int i) {
864         SnmpPduRequest result = newValidResponsePdu(req, null) ;
865         result.errorStatus = s ;
866         result.errorIndex = i ;
867         result.varBindList = req.varBindList ;
868
869         ((SnmpAdaptorServer)adaptorServer).
870         updateErrorCounters(result.errorStatus) ;
871     
872         return result ;
873     }
874
875     private SnmpMessage newTooBigMessage(SnmpMessage reqMsg)
876     throws SnmpTooBigException {
877         SnmpMessage result = null ;
878         SnmpPduPacket reqPdu = null ;
879     
880         try {
881             reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ;
882             if (reqPdu != null) {
883                 SnmpPduPacket respPdu = newTooBigPdu(reqPdu) ;
884                 result = (SnmpMessage)pduFactory.
885             encodeSnmpPdu(respPdu, packet.getData().length) ;
886             }
887         }
888         catch(SnmpStatusException x) {
889             // This should not occur because decodeIncomingRequest has normally
890
// been successfully called before.
891
debug("InternalError: ", x);
892             throw new InternalError JavaDoc() ;
893         }
894     
895         return result ;
896     }
897   
898     private SnmpPduPacket newTooBigPdu(SnmpPduPacket req) {
899         SnmpPduRequest result =
900         newErrorResponsePdu(req, SnmpDefinitions.snmpRspTooBig, 0) ;
901         result.varBindList = null ;
902         return result ;
903     }
904
905     private SnmpPduPacket reduceResponsePdu(SnmpPduPacket req,
906                         SnmpPduPacket resp,
907                         int acceptedVbCount)
908         throws SnmpTooBigException {
909   
910         // Reduction can be attempted only on bulk response
911
//
912
if (req.type != req.pduGetBulkRequestPdu) {
913             if (isDebugOn()) {
914                 debug("reduceResponsePdu", "cannot remove anything");
915             }
916             throw new SnmpTooBigException(acceptedVbCount) ;
917         }
918     
919         // We're going to reduce the varbind list.
920
// First determine which items should be removed.
921
// Next duplicate and replace the existing list by the reduced one.
922
//
923
// acceptedVbCount is the number of varbind which have been
924
// successfully encoded before reaching bufferSize:
925
// * when it is >= 2, we split the varbindlist at this
926
// position (-1 to be safe),
927
// * when it is 1, we only put one (big?) item in the varbindlist
928
// * when it is 0 (in fact, acceptedVbCount is not available),
929
// we split the varbindlist by 2.
930
//
931
int vbCount = resp.varBindList.length ;
932         if (acceptedVbCount >= 3)
933             vbCount = Math.min(acceptedVbCount - 1, resp.varBindList.length) ;
934         else if (acceptedVbCount == 1)
935             vbCount = 1 ;
936         else // acceptedCount == 0 ie it is unknown
937
vbCount = resp.varBindList.length / 2 ;
938     
939         if (vbCount < 1) {
940             if (isDebugOn()) {
941                 debug("reduceResponsePdu", "cannot remove anything");
942             }
943             throw new SnmpTooBigException(acceptedVbCount) ;
944         }
945         else {
946             SnmpVarBind[] newVbList = new SnmpVarBind[vbCount] ;
947             for (int i = 0 ; i < vbCount ; i++) {
948                 newVbList[i] = resp.varBindList[i] ;
949             }
950             if (isDebugOn()) {
951                 debug("reduceResponsePdu",
952               (resp.varBindList.length - newVbList.length) +
953               " items have been removed");
954             }
955             resp.varBindList = newVbList ;
956         }
957     
958         return resp ;
959     }
960
961     /**
962      * The method takes the incoming requests and split it into subrequests.
963      */

964     private void splitRequest(SnmpPduRequest req) {
965     
966         int nbAgents= mibs.size();
967         SnmpMibAgent agent= (SnmpMibAgent) mibs.firstElement();
968         if (nbAgents == 1) {
969             // Take all the oids contained in the request and
970
//
971
subs.put(agent, new SnmpSubRequestHandler(agent, req, true));
972             return;
973         }
974     
975         // For the get next operation we are going to send the varbind list
976
// to all agents
977
//
978
if (req.type == pduGetNextRequestPdu) {
979             for(Enumeration JavaDoc e= mibs.elements(); e.hasMoreElements(); ) {
980                 SnmpMibAgent ag= (SnmpMibAgent) e.nextElement();
981                 subs.put(ag, new SnmpSubNextRequestHandler(adaptor, ag, req));
982             }
983             return;
984         }
985
986         int nbReqs= req.varBindList.length;
987         SnmpVarBind[] vars= req.varBindList;
988         SnmpSubRequestHandler sub;
989         for(int i=0; i < nbReqs; i++) {
990             agent= root.getAgentMib(vars[i].oid);
991             sub= (SnmpSubRequestHandler) subs.get(agent);
992             if (sub == null) {
993                 // We need to create the sub request handler and update
994
// the hashtable
995
//
996
sub= new SnmpSubRequestHandler(agent, req);
997                 subs.put(agent, sub);
998             }
999       
1000            // Update the translation table within the subrequest
1001
//
1002
sub.updateRequest(vars[i], i);
1003        }
1004    }
1005  
1006    /**
1007     * The method takes the incoming get bulk requests and split it into
1008     * subrequests.
1009     */

1010    private void splitBulkRequest(SnmpPduBulk req,
1011                  int nonRepeaters,
1012                  int maxRepetitions,
1013                  int R) {
1014    // Send the getBulk to all agents
1015
//
1016
for(Enumeration JavaDoc e= mibs.elements(); e.hasMoreElements(); ) {
1017        SnmpMibAgent agent = (SnmpMibAgent) e.nextElement();
1018
1019        if(isDebugOn())
1020        trace("splitBulkRequest", "Create a sub with : " +
1021              agent + " " + nonRepeaters + " " +
1022              maxRepetitions + " " + R);
1023
1024        subs.put(agent,
1025             new SnmpSubBulkRequestHandler(adaptor,
1026                           agent,
1027                           req,
1028                           nonRepeaters,
1029                           maxRepetitions,
1030                           R));
1031    }
1032    return;
1033    }
1034  
1035    private SnmpPduPacket mergeResponses(SnmpPduRequest req) {
1036    
1037        if (req.type == pduGetNextRequestPdu) {
1038            return mergeNextResponses(req);
1039        }
1040      
1041        SnmpVarBind[] result= req.varBindList;
1042  
1043        // Go through the list of subrequests and concatenate.
1044
// Hopefully, by now all the sub-requests should be finished
1045
//
1046
for(Enumeration JavaDoc e= subs.elements(); e.hasMoreElements();) {
1047            SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
1048            sub.updateResult(result);
1049        }
1050        return newValidResponsePdu(req,result);
1051    }
1052  
1053    private SnmpPduPacket mergeNextResponses(SnmpPduRequest req) {
1054        int max= req.varBindList.length;
1055        SnmpVarBind[] result= new SnmpVarBind[max];
1056    
1057        // Go through the list of subrequests and concatenate.
1058
// Hopefully, by now all the sub-requests should be finished
1059
//
1060
for(Enumeration JavaDoc e= subs.elements(); e.hasMoreElements();) {
1061            SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
1062            sub.updateResult(result);
1063        }
1064    
1065        if (req.version == snmpVersionTwo) {
1066            return newValidResponsePdu(req,result);
1067        }
1068    
1069        // In v1 make sure there is no endOfMibView ...
1070
//
1071
for(int i=0; i < max; i++) {
1072            SnmpValue val= result[i].value;
1073            if (val == SnmpVarBind.endOfMibView)
1074                return newErrorResponsePdu(req,
1075                   SnmpDefinitions.snmpRspNoSuchName, i+1);
1076        }
1077    
1078        // So far so good ...
1079
//
1080
return newValidResponsePdu(req,result);
1081    }
1082  
1083    private SnmpVarBind[] mergeBulkResponses(int size) {
1084        // Let's allocate the array for storing the result
1085
//
1086
SnmpVarBind[] result= new SnmpVarBind[size];
1087        for(int i= size-1; i >=0; --i) {
1088            result[i]= new SnmpVarBind();
1089            result[i].value= SnmpVarBind.endOfMibView;
1090        }
1091    
1092        // Go through the list of subrequests and concatenate.
1093
// Hopefully, by now all the sub-requests should be finished
1094
//
1095
for(Enumeration JavaDoc e= subs.elements(); e.hasMoreElements();) {
1096            SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
1097            sub.updateResult(result);
1098        }
1099   
1100        return result;
1101    }
1102    
1103    protected boolean isTraceOn() {
1104        return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP);
1105    }
1106
1107    protected void trace(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
1108        Trace.send(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP, clz,func,info);
1109    }
1110
1111    protected void trace(String JavaDoc func, String JavaDoc info) {
1112        trace(dbgTag, func, info);
1113    }
1114    
1115    protected boolean isDebugOn() {
1116        return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
1117    }
1118
1119    protected void debug(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
1120        Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz,func,info);
1121    }
1122
1123    protected void debug(String JavaDoc clz, String JavaDoc func, Throwable JavaDoc exception) {
1124        Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func,
1125           exception);
1126    }
1127
1128    protected void debug(String JavaDoc func, String JavaDoc info) {
1129        debug(dbgTag, func, info);
1130    }
1131    
1132    protected void debug(String JavaDoc func, Throwable JavaDoc exception) {
1133        debug(dbgTag, func, exception);
1134    }
1135    
1136    protected String JavaDoc makeDebugTag() {
1137        return "SnmpRequestHandler[" + adaptorServer.getProtocol() + ":" +
1138        adaptorServer.getPort() + "]";
1139    }
1140
1141    Thread JavaDoc createThread(Runnable JavaDoc r) {
1142    return null;
1143    }
1144
1145    static final private String JavaDoc InterruptSysCallMsg =
1146    "Interrupted system call";
1147
1148    static final private SnmpStatusException noSuchNameException =
1149        new SnmpStatusException(SnmpDefinitions.snmpRspNoSuchName) ;
1150}
1151
1152
Popular Tags