blob: c8b211ad893f7f58ba9e7c323c04f3bc6c74cb0c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27package com.sun.jmx.snmp.daemon;
28
29
30
31// java import
32//
33import java.util.Vector;
34import java.util.Enumeration;
35import java.util.Hashtable;
36import java.util.logging.Level;
37import java.io.InterruptedIOException;
38import java.net.DatagramSocket;
39import java.net.DatagramPacket;
40import java.net.SocketException;
41
42// jmx imports
43//
44import javax.management.MBeanServer;
45import javax.management.ObjectName;
46import com.sun.jmx.snmp.SnmpMessage;
47import com.sun.jmx.snmp.SnmpPduFactory;
48import com.sun.jmx.snmp.SnmpPduBulk;
49import com.sun.jmx.snmp.SnmpPduPacket;
50import com.sun.jmx.snmp.SnmpPduRequest;
51import com.sun.jmx.snmp.SnmpPduTrap;
52import com.sun.jmx.snmp.SnmpValue;
53import com.sun.jmx.snmp.SnmpVarBind;
54import com.sun.jmx.snmp.SnmpVarBindList;
55import com.sun.jmx.snmp.SnmpDefinitions;
56import com.sun.jmx.snmp.SnmpStatusException;
57import com.sun.jmx.snmp.SnmpTooBigException;
58import com.sun.jmx.snmp.SnmpDataTypeEnums;
59
60// RI imports
61//
62import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
63
64// SNMP runtime import
65//
66import com.sun.jmx.snmp.agent.SnmpMibAgent;
67import com.sun.jmx.snmp.agent.SnmpUserDataFactory;
68//import com.sun.jmx.snmp.IPAcl.IPAcl;
69import com.sun.jmx.snmp.InetAddressAcl;
70
71
72class SnmpRequestHandler extends ClientHandler implements SnmpDefinitions {
73
74 private transient DatagramSocket socket = null ;
75 private transient DatagramPacket packet = null ;
76 private transient Vector mibs = null ;
77
78 /**
79 * Contains the list of sub-requests associated to the current request.
80 */
81 private transient Hashtable<SnmpMibAgent, SnmpSubRequestHandler> subs = null;
82
83 /**
84 * Reference on the MIBS
85 */
86 private transient SnmpMibTree root;
87
88 private transient Object ipacl = null ;
89 private transient SnmpPduFactory pduFactory = null ;
90 private transient SnmpUserDataFactory userDataFactory = null ;
91 private transient SnmpAdaptorServer adaptor = null;
92 /**
93 * Full constructor
94 */
95 public SnmpRequestHandler(SnmpAdaptorServer server, int id,
96 DatagramSocket s, DatagramPacket p,
97 SnmpMibTree tree, Vector m, Object a,
98 SnmpPduFactory factory,
99 SnmpUserDataFactory dataFactory,
100 MBeanServer f, ObjectName n)
101 {
102 super(server, id, f, n);
103
104 // Need a reference on SnmpAdaptorServer for getNext & getBulk,
105 // in case of oid equality (mib overlapping).
106 //
107 adaptor = server;
108 socket = s;
109 packet = p;
110 root= tree;
111 mibs = (Vector) m.clone();
112 subs= new Hashtable<SnmpMibAgent, SnmpSubRequestHandler>(mibs.size());
113 ipacl = a;
114 pduFactory = factory ;
115 userDataFactory = dataFactory ;
116 //thread.start();
117 }
118
119 /**
120 * Treat the request available in 'packet' and send the result
121 * back to the client.
122 * Note: we overwrite 'packet' with the response bytes.
123 */
124 public void doRun() {
125
126 // Trace the input packet
127 //
128 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
129 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
130 "doRun","Packet received:\n" +
131 SnmpMessage.dumpHexBuffer(packet.getData(), 0, packet.getLength()));
132 }
133
134 // Let's build the response packet
135 //
136 DatagramPacket respPacket = makeResponsePacket(packet) ;
137
138 // Trace the output packet
139 //
140 if ((SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) && (respPacket != null)) {
141 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
142 "doRun","Packet to be sent:\n" +
143 SnmpMessage.dumpHexBuffer(respPacket.getData(), 0, respPacket.getLength()));
144 }
145
146 // Send the response packet if any
147 //
148 if (respPacket != null) {
149 try {
150 socket.send(respPacket) ;
151 } catch (SocketException e) {
152 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
153 if (e.getMessage().equals(InterruptSysCallMsg)) {
154 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
155 "doRun", "interrupted");
156 } else {
157 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
158 "doRun", "I/O exception", e);
159 }
160 }
161 } catch(InterruptedIOException e) {
162 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
163 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
164 "doRun", "interrupted");
165 }
166 } catch(Exception e) {
167 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
168 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
169 "doRun", "failure when sending response", e);
170 }
171 }
172 }
173 }
174
175 /**
176 * Here we make a response packet from a request packet.
177 * We return null if there no response packet to sent.
178 */
179 private DatagramPacket makeResponsePacket(DatagramPacket reqPacket) {
180 DatagramPacket respPacket = null ;
181
182 // Transform the request packet into a request SnmpMessage
183 //
184 SnmpMessage reqMsg = new SnmpMessage() ;
185 try {
186 reqMsg.decodeMessage(reqPacket.getData(), reqPacket.getLength()) ;
187 reqMsg.address = reqPacket.getAddress() ;
188 reqMsg.port = reqPacket.getPort() ;
189 }
190 catch(SnmpStatusException x) {
191 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
192 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
193 "makeResponsePacket", "packet decoding failed", x);
194 }
195 reqMsg = null ;
196 ((SnmpAdaptorServer)adaptorServer).incSnmpInASNParseErrs(1) ;
197 }
198
199 // Make the response SnmpMessage if any
200 //
201 SnmpMessage respMsg = null ;
202 if (reqMsg != null) {
203 respMsg = makeResponseMessage(reqMsg) ;
204 }
205
206 // Try to transform the response SnmpMessage into response packet.
207 // NOTE: we overwrite the request packet.
208 //
209 if (respMsg != null) {
210 try {
211 reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ;
212 respPacket = reqPacket ;
213 }
214 catch(SnmpTooBigException x) {
215 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
216 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
217 "makeResponsePacket", "response message is too big");
218 }
219 try {
220 respMsg = newTooBigMessage(reqMsg) ;
221 reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ;
222 respPacket = reqPacket ;
223 }
224 catch(SnmpTooBigException xx) {
225 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
226 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
227 "makeResponsePacket", "'too big' is 'too big' !!!");
228 }
229 adaptor.incSnmpSilentDrops(1);
230 }
231 }
232 }
233
234 return respPacket ;
235 }
236
237 /**
238 * Here we make a response message from a request message.
239 * We return null if there is no message to reply.
240 */
241 private SnmpMessage makeResponseMessage(SnmpMessage reqMsg) {
242 SnmpMessage respMsg = null ;
243
244 // Transform the request message into a request pdu
245 //
246 SnmpPduPacket reqPdu = null ;
247 Object userData = null;
248 try {
249 reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ;
250 if (reqPdu != null && userDataFactory != null)
251 userData = userDataFactory.allocateUserData(reqPdu);
252 }
253 catch(SnmpStatusException x) {
254 reqPdu = null ;
255 SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
256 snmpServer.incSnmpInASNParseErrs(1) ;
257 if (x.getStatus()== SnmpDefinitions.snmpWrongSnmpVersion)
258 snmpServer.incSnmpInBadVersions(1) ;
259 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
260 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
261 "makeResponseMessage", "message decoding failed", x);
262 }
263 }
264
265 // Make the response pdu if any
266 //
267 SnmpPduPacket respPdu = null ;
268 if (reqPdu != null) {
269 respPdu = makeResponsePdu(reqPdu,userData) ;
270 try {
271 if (userDataFactory != null)
272 userDataFactory.releaseUserData(userData,respPdu);
273 } catch (SnmpStatusException x) {
274 respPdu = null;
275 }
276 }
277
278 // Try to transform the response pdu into a response message if any
279 //
280 if (respPdu != null) {
281 try {
282 respMsg = (SnmpMessage)pduFactory.
283 encodeSnmpPdu(respPdu, packet.getData().length) ;
284 }
285 catch(SnmpStatusException x) {
286 respMsg = null ;
287 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
288 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
289 "makeResponseMessage", "failure when encoding the response message", x);
290 }
291 }
292 catch(SnmpTooBigException x) {
293 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
294 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
295 "makeResponseMessage", "response message is too big");
296 }
297
298 try {
299 // if the PDU is too small, why should we try to do
300 // recovery ?
301 //
302 if (packet.getData().length <=32)
303 throw x;
304 int pos= x.getVarBindCount();
305 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
306 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
307 "makeResponseMessage", "fail on element" + pos);
308 }
309 int old= 0;
310 while (true) {
311 try {
312 respPdu = reduceResponsePdu(reqPdu, respPdu, pos) ;
313 respMsg = (SnmpMessage)pduFactory.
314 encodeSnmpPdu(respPdu,
315 packet.getData().length -32) ;
316 break;
317 } catch (SnmpTooBigException xx) {
318 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
319 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
320 "makeResponseMessage", "response message is still too big");
321 }
322 old= pos;
323 pos= xx.getVarBindCount();
324 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
325 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
326 "makeResponseMessage","fail on element" + pos);
327 }
328 if (pos == old) {
329 // we can not go any further in trying to
330 // reduce the message !
331 //
332 throw xx;
333 }
334 }
335 }// end of loop
336 } catch(SnmpStatusException xx) {
337 respMsg = null ;
338 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
339 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
340 "makeResponseMessage", "failure when encoding the response message", xx);
341 }
342 }
343 catch(SnmpTooBigException xx) {
344 try {
345 respPdu = newTooBigPdu(reqPdu) ;
346 respMsg = (SnmpMessage)pduFactory.
347 encodeSnmpPdu(respPdu, packet.getData().length) ;
348 }
349 catch(SnmpTooBigException xxx) {
350 respMsg = null ;
351 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
352 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
353 "makeResponseMessage", "'too big' is 'too big' !!!");
354 }
355 adaptor.incSnmpSilentDrops(1);
356 }
357 catch(Exception xxx) {
358 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
359 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
360 "makeResponseMessage", "Got unexpected exception", xxx);
361 }
362 respMsg = null ;
363 }
364 }
365 catch(Exception xx) {
366 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
367 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
368 "makeResponseMessage", "Got unexpected exception", xx);
369 }
370 respMsg = null ;
371 }
372 }
373 }
374 return respMsg ;
375 }
376
377 /**
378 * Here we make a response pdu from a request pdu.
379 * We return null if there is no pdu to reply.
380 */
381 private SnmpPduPacket makeResponsePdu(SnmpPduPacket reqPdu,
382 Object userData) {
383
384 SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
385 SnmpPduPacket respPdu = null ;
386
387 snmpServer.updateRequestCounters(reqPdu.type) ;
388 if (reqPdu.varBindList != null)
389 snmpServer.updateVarCounters(reqPdu.type,
390 reqPdu.varBindList.length) ;
391
392 if (checkPduType(reqPdu)) {
393 respPdu = checkAcl(reqPdu) ;
394 if (respPdu == null) { // reqPdu is accepted by ACLs
395 if (mibs.size() < 1) {
396 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
397 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
398 "makeResponsePdu", "Request " + reqPdu.requestId +
399 " received but no MIB registered.");
400 }
401 return makeNoMibErrorPdu((SnmpPduRequest)reqPdu, userData);
402 }
403 switch(reqPdu.type) {
404 case SnmpPduPacket.pduGetRequestPdu:
405 case SnmpPduPacket.pduGetNextRequestPdu:
406 case SnmpPduPacket.pduSetRequestPdu:
407 respPdu = makeGetSetResponsePdu((SnmpPduRequest)reqPdu,
408 userData) ;
409 break ;
410
411 case SnmpPduPacket.pduGetBulkRequestPdu:
412 respPdu = makeGetBulkResponsePdu((SnmpPduBulk)reqPdu,
413 userData) ;
414 break ;
415 }
416 }
417 else { // reqPdu is rejected by ACLs
418 // respPdu contains the error response to be sent.
419 // We send this response only if authResEnabled is true.
420 if (!snmpServer.getAuthRespEnabled()) { // No response should be sent
421 respPdu = null ;
422 }
423 if (snmpServer.getAuthTrapEnabled()) { // A trap must be sent
424 try {
425 snmpServer.snmpV1Trap(SnmpPduTrap.
426 trapAuthenticationFailure, 0,
427 new SnmpVarBindList()) ;
428 }
429 catch(Exception x) {
430 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
431 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
432 "makeResponsePdu", "Failure when sending authentication trap", x);
433 }
434 }
435 }
436 }
437 }
438 return respPdu ;
439 }
440
441 //
442 // Generates a response packet, filling the values in the
443 // varbindlist with one of endOfMibView, noSuchObject, noSuchInstance
444 // according to the value of <code>status</code>
445 //
446 // @param statusTag should be one of:
447 // <li>SnmpDataTypeEnums.errEndOfMibViewTag</li>
448 // <li>SnmpDataTypeEnums.errNoSuchObjectTag</li>
449 // <li>SnmpDataTypeEnums.errNoSuchInstanceTag</li>
450 //
451 SnmpPduPacket makeErrorVarbindPdu(SnmpPduPacket req, int statusTag) {
452
453 final SnmpVarBind[] vblist = req.varBindList;
454 final int length = vblist.length;
455
456 switch (statusTag) {
457 case SnmpDataTypeEnums.errEndOfMibViewTag:
458 for (int i=0 ; i<length ; i++)
459 vblist[i].value = SnmpVarBind.endOfMibView;
460 break;
461 case SnmpDataTypeEnums.errNoSuchObjectTag:
462 for (int i=0 ; i<length ; i++)
463 vblist[i].value = SnmpVarBind.noSuchObject;
464 break;
465 case SnmpDataTypeEnums.errNoSuchInstanceTag:
466 for (int i=0 ; i<length ; i++)
467 vblist[i].value = SnmpVarBind.noSuchInstance;
468 break;
469 default:
470 return newErrorResponsePdu(req,snmpRspGenErr,1);
471 }
472 return newValidResponsePdu(req,vblist);
473 }
474
475 // Generates an appropriate response when no mib is registered in
476 // the adaptor.
477 //
478 // <li>If the version is V1:</li>
479 // <ul><li>Generates a NoSuchName error V1 response PDU</li></ul>
480 // <li>If the version is V2:</li>
481 // <ul><li>If the request is a GET, fills the varbind list with
482 // NoSuchObject's</li>
483 // <li>If the request is a GET-NEXT/GET-BULK, fills the varbind
484 // list with EndOfMibView's</li>
485 // <li>If the request is a SET, generates a NoAccess error V2
486 // response PDU</li>
487 // </ul>
488 //
489 //
490 SnmpPduPacket makeNoMibErrorPdu(SnmpPduRequest req, Object userData) {
491 // There is no agent registered
492 //
493 if (req.version == SnmpDefinitions.snmpVersionOne) {
494 // Version 1: => NoSuchName
495 return
496 newErrorResponsePdu(req,snmpRspNoSuchName,1);
497 } else if (req.version == SnmpDefinitions.snmpVersionTwo) {
498 // Version 2: => depends on PDU type
499 switch (req.type) {
500 case pduSetRequestPdu :
501 case pduWalkRequest :
502 // SET request => NoAccess
503 return
504 newErrorResponsePdu(req,snmpRspNoAccess,1);
505 case pduGetRequestPdu :
506 // GET request => NoSuchObject
507 return
508 makeErrorVarbindPdu(req,SnmpDataTypeEnums.
509 errNoSuchObjectTag);
510 case pduGetNextRequestPdu :
511 case pduGetBulkRequestPdu :
512 // GET-NEXT or GET-BULK => EndOfMibView
513 return
514 makeErrorVarbindPdu(req,SnmpDataTypeEnums.
515 errEndOfMibViewTag);
516 default:
517 }
518 }
519 // Something wrong here: => snmpRspGenErr
520 return newErrorResponsePdu(req,snmpRspGenErr,1);
521 }
522
523 /**
524 * Here we make the response pdu from a get/set request pdu.
525 * At this level, the result is never null.
526 */
527 private SnmpPduPacket makeGetSetResponsePdu(SnmpPduRequest req,
528 Object userData) {
529
530 // Create the trhead group specific for handling sub-requests
531 // associated to the current request. Use the invoke id
532 //
533 // Nice idea to use a thread group on a request basis.
534 // However the impact on performance is terrible !
535 // theGroup= new ThreadGroup(thread.getThreadGroup(),
536 // "request " + String.valueOf(req.requestId));
537
538 // Let's build the varBindList for the response pdu
539 //
540
541 if (req.varBindList == null) {
542 // Good ! Let's make a full response pdu.
543 //
544 return newValidResponsePdu(req, null) ;
545 }
546
547 // First we need to split the request into subrequests
548 //
549 splitRequest(req);
550 int nbSubRequest= subs.size();
551 if (nbSubRequest == 1)
552 return turboProcessingGetSet(req,userData);
553
554
555 // Execute all the subrequests resulting from the split of the
556 // varbind list.
557 //
558 SnmpPduPacket result= executeSubRequest(req,userData);
559 if (result != null)
560 // It means that an error occured. The error is already
561 // formatted by the executeSubRequest
562 // method.
563 return result;
564
565 // So far so good. So we need to concatenate all the answers.
566 //
567 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
568 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
569 "makeGetSetResponsePdu",
570 "Build the unified response for request " + req.requestId);
571 }
572 return mergeResponses(req);
573 }
574
575 /**
576 * The method runs all the sub-requests associated to the current
577 * instance of SnmpRequestHandler.
578 */
579 private SnmpPduPacket executeSubRequest(SnmpPduPacket req,
580 Object userData) {
581
582 int errorStatus = SnmpDefinitions.snmpRspNoError ;
583 int nbSubRequest= subs.size();
584
585 int i=0;
586 // If it's a set request, we must first check any varBind
587 //
588 if (req.type == pduSetRequestPdu) {
589
590 i=0;
591 for(Enumeration e= subs.elements(); e.hasMoreElements() ; i++) {
592 // Indicate to the sub request that a check must be invoked ...
593 // OK we should have defined out own tag for that !
594 //
595 SnmpSubRequestHandler sub= (SnmpSubRequestHandler)
596 e.nextElement();
597 sub.setUserData(userData);
598 sub.type= pduWalkRequest;
599
600 sub.run();
601
602 sub.type= pduSetRequestPdu;
603
604 if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) {
605 // No point to go any further.
606 //
607 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
608 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
609 "executeSubRequest", "an error occurs");
610 }
611
612 return newErrorResponsePdu(req, errorStatus,
613 sub.getErrorIndex() + 1) ;
614 }
615 }
616 }// end processing check operation for a set PDU.
617
618 // Let's start the sub-requests.
619 //
620 i=0;
621 for(Enumeration e= subs.elements(); e.hasMoreElements() ;i++) {
622 SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
623 /* NPCTE fix for bugId 4492741, esc 0, 16-August 2001 */
624 sub.setUserData(userData);
625 /* end of NPCTE fix for bugId 4492741 */
626
627 sub.run();
628
629 if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) {
630 // No point to go any further.
631 //
632 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
633 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
634 "executeSubRequest", "an error occurs");
635 }
636
637 return newErrorResponsePdu(req, errorStatus,
638 sub.getErrorIndex() + 1) ;
639 }
640 }
641
642 // everything is ok
643 //
644 return null;
645 }
646
647 /**
648 * Optimize when there is only one sub request
649 */
650 private SnmpPduPacket turboProcessingGetSet(SnmpPduRequest req,
651 Object userData) {
652
653 int errorStatus = SnmpDefinitions.snmpRspNoError ;
654 SnmpSubRequestHandler sub = subs.elements().nextElement();
655 sub.setUserData(userData);
656
657 // Indicate to the sub request that a check must be invoked ...
658 // OK we should have defined out own tag for that !
659 //
660 if (req.type == SnmpDefinitions.pduSetRequestPdu) {
661 sub.type= pduWalkRequest;
662 sub.run();
663 sub.type= pduSetRequestPdu;
664
665 // Check the error status.
666 //
667 errorStatus= sub.getErrorStatus();
668 if (errorStatus != SnmpDefinitions.snmpRspNoError) {
669 // No point to go any further.
670 //
671 return newErrorResponsePdu(req, errorStatus,
672 sub.getErrorIndex() + 1) ;
673 }
674 }
675
676 // process the operation
677 //
678
679 sub.run();
680 errorStatus= sub.getErrorStatus();
681 if (errorStatus != SnmpDefinitions.snmpRspNoError) {
682 // No point to go any further.
683 //
684 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
685 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
686 "turboProcessingGetSet", "an error occurs");
687 }
688 int realIndex= sub.getErrorIndex() + 1;
689 return newErrorResponsePdu(req, errorStatus, realIndex) ;
690 }
691
692 // So far so good. So we need to concatenate all the answers.
693 //
694
695 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
696 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
697 "turboProcessingGetSet", "build the unified response for request "
698 + req.requestId);
699 }
700 return mergeResponses(req);
701 }
702
703 /**
704 * Here we make the response pdu for a bulk request.
705 * At this level, the result is never null.
706 */
707 private SnmpPduPacket makeGetBulkResponsePdu(SnmpPduBulk req,
708 Object userData) {
709
710 SnmpVarBind[] respVarBindList = null ;
711
712 // RFC 1905, Section 4.2.3, p14
713 int L = req.varBindList.length ;
714 int N = Math.max(Math.min(req.nonRepeaters, L), 0) ;
715 int M = Math.max(req.maxRepetitions, 0) ;
716 int R = L - N ;
717
718 if (req.varBindList == null) {
719 // Good ! Let's make a full response pdu.
720 //
721 return newValidResponsePdu(req, null) ;
722 }
723
724 // Split the request into subrequests.
725 //
726 splitBulkRequest(req, N, M, R);
727 SnmpPduPacket result= executeSubRequest(req,userData);
728 if (result != null)
729 return result;
730
731 respVarBindList= mergeBulkResponses(N + (M * R));
732
733 // Now we remove useless trailing endOfMibView.
734 //
735 int m2 ; // respVarBindList[m2] item and next are going to be removed
736 int t = respVarBindList.length ;
737 while ((t > N) && (respVarBindList[t-1].
738 value.equals(SnmpVarBind.endOfMibView))) {
739 t-- ;
740 }
741 if (t == N)
742 m2 = N + R ;
743 else
744 m2 = N + ((t -1 -N) / R + 2) * R ; // Trivial, of course...
745 if (m2 < respVarBindList.length) {
746 SnmpVarBind[] truncatedList = new SnmpVarBind[m2] ;
747 for (int i = 0 ; i < m2 ; i++) {
748 truncatedList[i] = respVarBindList[i] ;
749 }
750 respVarBindList = truncatedList ;
751 }
752
753 // Good ! Let's make a full response pdu.
754 //
755 return newValidResponsePdu(req, respVarBindList) ;
756 }
757
758 /**
759 * Check the type of the pdu: only the get/set/bulk request
760 * are accepted.
761 */
762 private boolean checkPduType(SnmpPduPacket pdu) {
763
764 boolean result = true ;
765
766 switch(pdu.type) {
767
768 case SnmpDefinitions.pduGetRequestPdu:
769 case SnmpDefinitions.pduGetNextRequestPdu:
770 case SnmpDefinitions.pduSetRequestPdu:
771 case SnmpDefinitions.pduGetBulkRequestPdu:
772 result = true ;
773 break;
774
775 default:
776 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
777 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
778 "checkPduType", "cannot respond to this kind of PDU");
779 }
780 result = false ;
781 break;
782 }
783
784 return result ;
785 }
786
787 /**
788 * Check if the specified pdu is conform to the ACL.
789 * This method returns null if the pdu is ok. If not, it returns
790 * the response pdu to be replied.
791 */
792 private SnmpPduPacket checkAcl(SnmpPduPacket pdu) {
793 SnmpPduPacket response = null ;
794 String community = new String(pdu.community) ;
795
796 // We check the pdu type and create an error response if
797 // the check failed.
798 //
799 if (ipacl != null) {
800 if (pdu.type == SnmpDefinitions.pduSetRequestPdu) {
801 if (!((InetAddressAcl)ipacl).
802 checkWritePermission(pdu.address, community)) {
803 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
804 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
805 "checkAcl", "sender is " + pdu.address +
806 " with " + community +". Sender has no write permission");
807 }
808 int err = SnmpSubRequestHandler.
809 mapErrorStatus(SnmpDefinitions.
810 snmpRspAuthorizationError,
811 pdu.version, pdu.type);
812 response = newErrorResponsePdu(pdu, err, 0) ;
813 }
814 else {
815 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
816 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
817 "checkAcl", "sender is " + pdu.address +
818 " with " + community +". Sender has write permission");
819 }
820 }
821 }
822 else {
823 if (!((InetAddressAcl)ipacl).checkReadPermission(pdu.address, community)) {
824 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
825 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
826 "checkAcl", "sender is " + pdu.address +
827 " with " + community +". Sender has no read permission");
828 }
829 int err = SnmpSubRequestHandler.
830 mapErrorStatus(SnmpDefinitions.
831 snmpRspAuthorizationError,
832 pdu.version, pdu.type);
833 response = newErrorResponsePdu(pdu,
834 err,
835 0);
836 SnmpAdaptorServer snmpServer =
837 (SnmpAdaptorServer)adaptorServer;
838 snmpServer.updateErrorCounters(SnmpDefinitions.
839 snmpRspNoSuchName);
840 }
841 else {
842 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
843 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
844 "checkAcl", "sender is " + pdu.address +
845 " with " + community +". Sender has read permission");
846 }
847 }
848 }
849 }
850
851 // If the response is not null, this means the pdu is rejected.
852 // So let's update the statistics.
853 //
854 if (response != null) {
855 SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
856 snmpServer.incSnmpInBadCommunityUses(1) ;
857 if (((InetAddressAcl)ipacl).checkCommunity(community) == false)
858 snmpServer.incSnmpInBadCommunityNames(1) ;
859 }
860
861 return response ;
862 }
863
864 /**
865 * Make a response pdu with the specified error status and index.
866 * NOTE: the response pdu share its varBindList with the request pdu.
867 */
868 private SnmpPduRequest newValidResponsePdu(SnmpPduPacket reqPdu,
869 SnmpVarBind[] varBindList) {
870 SnmpPduRequest result = new SnmpPduRequest() ;
871
872 result.address = reqPdu.address ;
873 result.port = reqPdu.port ;
874 result.version = reqPdu.version ;
875 result.community = reqPdu.community ;
876 result.type = result.pduGetResponsePdu ;
877 result.requestId = reqPdu.requestId ;
878 result.errorStatus = SnmpDefinitions.snmpRspNoError ;
879 result.errorIndex = 0 ;
880 result.varBindList = varBindList ;
881
882 ((SnmpAdaptorServer)adaptorServer).
883 updateErrorCounters(result.errorStatus) ;
884
885 return result ;
886 }
887
888 /**
889 * Make a response pdu with the specified error status and index.
890 * NOTE: the response pdu share its varBindList with the request pdu.
891 */
892 private SnmpPduRequest newErrorResponsePdu(SnmpPduPacket req,int s,int i) {
893 SnmpPduRequest result = newValidResponsePdu(req, null) ;
894 result.errorStatus = s ;
895 result.errorIndex = i ;
896 result.varBindList = req.varBindList ;
897
898 ((SnmpAdaptorServer)adaptorServer).
899 updateErrorCounters(result.errorStatus) ;
900
901 return result ;
902 }
903
904 private SnmpMessage newTooBigMessage(SnmpMessage reqMsg)
905 throws SnmpTooBigException {
906 SnmpMessage result = null ;
907 SnmpPduPacket reqPdu = null ;
908
909 try {
910 reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ;
911 if (reqPdu != null) {
912 SnmpPduPacket respPdu = newTooBigPdu(reqPdu) ;
913 result = (SnmpMessage)pduFactory.
914 encodeSnmpPdu(respPdu, packet.getData().length) ;
915 }
916 }
917 catch(SnmpStatusException x) {
918 // This should not occur because decodeIncomingRequest has normally
919 // been successfully called before.
920 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
921 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
922 "newTooBigMessage", "Internal error", x);
923 }
924 throw new InternalError() ;
925 }
926
927 return result ;
928 }
929
930 private SnmpPduPacket newTooBigPdu(SnmpPduPacket req) {
931 SnmpPduRequest result =
932 newErrorResponsePdu(req, SnmpDefinitions.snmpRspTooBig, 0) ;
933 result.varBindList = null ;
934 return result ;
935 }
936
937 private SnmpPduPacket reduceResponsePdu(SnmpPduPacket req,
938 SnmpPduPacket resp,
939 int acceptedVbCount)
940 throws SnmpTooBigException {
941
942 // Reduction can be attempted only on bulk response
943 //
944 if (req.type != req.pduGetBulkRequestPdu) {
945 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
946 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
947 "reduceResponsePdu", "cannot remove anything");
948 }
949 throw new SnmpTooBigException(acceptedVbCount) ;
950 }
951
952 // We're going to reduce the varbind list.
953 // First determine which items should be removed.
954 // Next duplicate and replace the existing list by the reduced one.
955 //
956 // acceptedVbCount is the number of varbind which have been
957 // successfully encoded before reaching bufferSize:
958 // * when it is >= 2, we split the varbindlist at this
959 // position (-1 to be safe),
960 // * when it is 1, we only put one (big?) item in the varbindlist
961 // * when it is 0 (in fact, acceptedVbCount is not available),
962 // we split the varbindlist by 2.
963 //
964 int vbCount = resp.varBindList.length ;
965 if (acceptedVbCount >= 3)
966 vbCount = Math.min(acceptedVbCount - 1, resp.varBindList.length) ;
967 else if (acceptedVbCount == 1)
968 vbCount = 1 ;
969 else // acceptedCount == 0 ie it is unknown
970 vbCount = resp.varBindList.length / 2 ;
971
972 if (vbCount < 1) {
973 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
974 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
975 "reduceResponsePdu", "cannot remove anything");
976 }
977 throw new SnmpTooBigException(acceptedVbCount) ;
978 }
979 else {
980 SnmpVarBind[] newVbList = new SnmpVarBind[vbCount] ;
981 for (int i = 0 ; i < vbCount ; i++) {
982 newVbList[i] = resp.varBindList[i] ;
983 }
984 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
985 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
986 "reduceResponsePdu", (resp.varBindList.length - newVbList.length) +
987 " items have been removed");
988 }
989 resp.varBindList = newVbList ;
990 }
991
992 return resp ;
993 }
994
995 /**
996 * The method takes the incoming requests and split it into subrequests.
997 */
998 private void splitRequest(SnmpPduRequest req) {
999
1000 int nbAgents= mibs.size();
1001 SnmpMibAgent agent= (SnmpMibAgent) mibs.firstElement();
1002 if (nbAgents == 1) {
1003 // Take all the oids contained in the request and
1004 //
1005 subs.put(agent, new SnmpSubRequestHandler(agent, req, true));
1006 return;
1007 }
1008
1009 // For the get next operation we are going to send the varbind list
1010 // to all agents
1011 //
1012 if (req.type == pduGetNextRequestPdu) {
1013 for(Enumeration e= mibs.elements(); e.hasMoreElements(); ) {
1014 SnmpMibAgent ag= (SnmpMibAgent) e.nextElement();
1015 subs.put(ag, new SnmpSubNextRequestHandler(adaptor, ag, req));
1016 }
1017 return;
1018 }
1019
1020 int nbReqs= req.varBindList.length;
1021 SnmpVarBind[] vars= req.varBindList;
1022 SnmpSubRequestHandler sub;
1023 for(int i=0; i < nbReqs; i++) {
1024 agent= root.getAgentMib(vars[i].oid);
1025 sub= subs.get(agent);
1026 if (sub == null) {
1027 // We need to create the sub request handler and update
1028 // the hashtable
1029 //
1030 sub= new SnmpSubRequestHandler(agent, req);
1031 subs.put(agent, sub);
1032 }
1033
1034 // Update the translation table within the subrequest
1035 //
1036 sub.updateRequest(vars[i], i);
1037 }
1038 }
1039
1040 /**
1041 * The method takes the incoming get bulk requests and split it into
1042 * subrequests.
1043 */
1044 private void splitBulkRequest(SnmpPduBulk req,
1045 int nonRepeaters,
1046 int maxRepetitions,
1047 int R) {
1048 // Send the getBulk to all agents
1049 //
1050 for(Enumeration e= mibs.elements(); e.hasMoreElements(); ) {
1051 SnmpMibAgent agent = (SnmpMibAgent) e.nextElement();
1052
1053 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1054 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1055 "splitBulkRequest", "Create a sub with : " + agent + " " + nonRepeaters
1056 + " " + maxRepetitions + " " + R);
1057 }
1058
1059 subs.put(agent,
1060 new SnmpSubBulkRequestHandler(adaptor,
1061 agent,
1062 req,
1063 nonRepeaters,
1064 maxRepetitions,
1065 R));
1066 }
1067 return;
1068 }
1069
1070 private SnmpPduPacket mergeResponses(SnmpPduRequest req) {
1071
1072 if (req.type == pduGetNextRequestPdu) {
1073 return mergeNextResponses(req);
1074 }
1075
1076 SnmpVarBind[] result= req.varBindList;
1077
1078 // Go through the list of subrequests and concatenate.
1079 // Hopefully, by now all the sub-requests should be finished
1080 //
1081 for(Enumeration e= subs.elements(); e.hasMoreElements();) {
1082 SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
1083 sub.updateResult(result);
1084 }
1085 return newValidResponsePdu(req,result);
1086 }
1087
1088 private SnmpPduPacket mergeNextResponses(SnmpPduRequest req) {
1089 int max= req.varBindList.length;
1090 SnmpVarBind[] result= new SnmpVarBind[max];
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 e= subs.elements(); e.hasMoreElements();) {
1096 SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
1097 sub.updateResult(result);
1098 }
1099
1100 if (req.version == snmpVersionTwo) {
1101 return newValidResponsePdu(req,result);
1102 }
1103
1104 // In v1 make sure there is no endOfMibView ...
1105 //
1106 for(int i=0; i < max; i++) {
1107 SnmpValue val= result[i].value;
1108 if (val == SnmpVarBind.endOfMibView)
1109 return newErrorResponsePdu(req,
1110 SnmpDefinitions.snmpRspNoSuchName, i+1);
1111 }
1112
1113 // So far so good ...
1114 //
1115 return newValidResponsePdu(req,result);
1116 }
1117
1118 private SnmpVarBind[] mergeBulkResponses(int size) {
1119 // Let's allocate the array for storing the result
1120 //
1121 SnmpVarBind[] result= new SnmpVarBind[size];
1122 for(int i= size-1; i >=0; --i) {
1123 result[i]= new SnmpVarBind();
1124 result[i].value= SnmpVarBind.endOfMibView;
1125 }
1126
1127 // Go through the list of subrequests and concatenate.
1128 // Hopefully, by now all the sub-requests should be finished
1129 //
1130 for(Enumeration e= subs.elements(); e.hasMoreElements();) {
1131 SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
1132 sub.updateResult(result);
1133 }
1134
1135 return result;
1136 }
1137
1138 protected String makeDebugTag() {
1139 return "SnmpRequestHandler[" + adaptorServer.getProtocol() + ":" +
1140 adaptorServer.getPort() + "]";
1141 }
1142
1143 Thread createThread(Runnable r) {
1144 return null;
1145 }
1146
1147 static final private String InterruptSysCallMsg =
1148 "Interrupted system call";
1149
1150 static final private SnmpStatusException noSuchNameException =
1151 new SnmpStatusException(SnmpDefinitions.snmpRspNoSuchName) ;
1152}