View Javadoc
1   // NAME
2   //      $RCSfile: SnmpContextv3Pool.java,v $
3   // DESCRIPTION
4   //      [given below in javadoc format]
5   // DELTA
6   //      $Revision: 3.27 $
7   // CREATED
8   //      $Date: 2009/03/05 13:27:41 $
9   // COPYRIGHT
10  //      Westhawk Ltd
11  // TO DO
12  //
13  
14  /*
15   * Copyright (C) 2000 - 2006 by Westhawk Ltd
16   * <a href="www.westhawk.co.uk">www.westhawk.co.uk</a>
17   *
18   * Permission to use, copy, modify, and distribute this software
19   * for any purpose and without fee is hereby granted, provided
20   * that the above copyright notices appear in all copies and that
21   * both the copyright notice and this permission notice appear in
22   * supporting documentation.
23   * This software is provided "as is" without express or implied
24   * warranty.
25   */
26  
27  package uk.co.westhawk.snmp.stack;
28  
29  /*-
30   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
31   * SNMP Java Client
32   * ჻჻჻჻჻჻
33   * Copyright 2023 Sentry Software, Westhawk
34   * ჻჻჻჻჻჻
35   * This program is free software: you can redistribute it and/or modify
36   * it under the terms of the GNU Lesser General Public License as
37   * published by the Free Software Foundation, either version 3 of the
38   * License, or (at your option) any later version.
39   *
40   * This program is distributed in the hope that it will be useful,
41   * but WITHOUT ANY WARRANTY; without even the implied warranty of
42   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43   * GNU General Lesser Public License for more details.
44   *
45   * You should have received a copy of the GNU General Lesser Public
46   * License along with this program.  If not, see
47   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
48   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
49   */
50  
51  import uk.co.westhawk.snmp.pdu.*;
52  import uk.co.westhawk.snmp.util.*;
53  import uk.co.westhawk.snmp.event.*;
54  import java.util.*;
55  
56  /**
57   * This class contains the pool of SNMP v3 contexts.
58   * This class reuses the existings contexts instead of creating a new
59   * one every time.
60   * <p>
61   * Every time a property changes the pool is checked for a SnmpContextv3
62   * context that matches all the new properties of this class. If no such
63   * context exists, a new one is made.
64   * The PDUs associated with the old context remain associated with the
65   * old context.
66   * </p>
67   *
68   * <p>
69   * A counter indicates the number of times the context is referenced.
70   * The counter is decreased when <code>destroy()</code> is called.
71   * When the counter
72   * reaches zero, the context is released.
73   * </p>
74   *
75   * <p>
76   * Note that because the underlying context can change when a property
77   * is changed and the PDUs remain associated with the old context, all
78   * properties have to be set BEFORE a PDU is sent.
79   * </p>
80   *
81   * @see SnmpContextv3
82   * @see SnmpContextPool
83   * @see SnmpContextv2cPool
84   *
85   * @author <a href="mailto:snmp@westhawk.co.uk">Birgit Arkesteijn</a>
86   * @version $Revision: 3.27 $ $Date: 2009/03/05 13:27:41 $
87   */
88  public class SnmpContextv3Pool implements SnmpContextv3Face
89  {
90      private static final String     version_id =
91          "@(#)$Id: SnmpContextv3Pool.java,v 3.27 2009/03/05 13:27:41 birgita Exp $ Copyright Westhawk Ltd";
92  
93      protected static Hashtable contextPool;
94  
95      protected String hostname, socketType, bindAddr;
96      protected int hostPort;
97  
98      protected SnmpContextv3 context = null;
99      protected String userName = "";
100     protected boolean useAuthentication = false;
101     protected String userAuthenticationPassword = "";
102     protected boolean usePrivacy = false;
103     protected String userPrivacyPassword = "";
104     protected int authenticationProtocol = MD5_PROTOCOL;
105     protected byte [] contextEngineId = new byte[0];
106     protected String contextName = Default_ContextName;
107     protected UsmAgent usmAgent = null;
108 
109     protected boolean hasChanged = false;
110     protected  int privacyProtocol = DES_ENCRYPT;
111 
112 /**
113  * Constructor, using the Standard socket.
114  *
115  * @param host The host to which the PDU will be sent
116  * @param port The port where the SNMP server will be
117  * @see SnmpContextv3#SnmpContextv3(String, int)
118  */
119 public SnmpContextv3Pool(String host, int port) throws java.io.IOException
120 {
121     this(host, port, null, STANDARD_SOCKET);
122 }
123 
124 /**
125  * Constructor.
126  * Parameter typeSocket should be either STANDARD_SOCKET, TCP_SOCKET or a
127  * fully qualified classname.
128  *
129  * @param host The host to which the PDU will be sent
130  * @param port The port where the SNMP server will be
131  * @param typeSocket The type of socket to use.
132  *
133  * @see SnmpContextv3#SnmpContextv3(String, int, String)
134  * @see SnmpContextBasisFace#STANDARD_SOCKET
135  * @see SnmpContextBasisFace#TCP_SOCKET
136  */
137 public SnmpContextv3Pool(String host, int port, String typeSocket)
138 throws java.io.IOException
139 {
140     this(host, port, null, typeSocket);
141 }
142 
143 /**
144  * Constructor.
145  * Parameter typeSocket should be either STANDARD_SOCKET, TCP_SOCKET or a
146  * fully qualified classname.
147  *
148  * @param host The host to which the PDU will be sent
149  * @param port The port where the SNMP server will be
150  * @param bindAddress The local address the server will bind to
151  * @param typeSocket The type of socket to use.
152  *
153  * @see SnmpContextv3#SnmpContextv3(String, int, String)
154  * @see SnmpContextBasisFace#STANDARD_SOCKET
155  * @see SnmpContextBasisFace#TCP_SOCKET
156  *
157  * @since 4_14
158  */
159 public SnmpContextv3Pool(String host, int port, String bindAddress, String typeSocket)
160 throws java.io.IOException
161 {
162     initPools();
163     hostname = host;
164     hostPort = port;
165     bindAddr = bindAddress;
166     socketType = typeSocket;
167 
168     // No point in creating a context, a lot of the parameters 
169     // are probably going to be set.
170     //context = getMatchingContext();
171 }
172 
173 private static synchronized void initPools()
174 {
175     if (contextPool == null)
176     {
177         contextPool = new Hashtable(5);
178     }
179 }
180 /**
181  * Returns the SNMP version of the context.
182  *
183  * @return The version
184  */
185 public int getVersion()
186 {
187     return SnmpConstants.SNMP_VERSION_3;
188 }
189 
190 /**
191  * Returns the host.
192  *
193  * @return The host
194  */
195 public String getHost()
196 {
197     return hostname;
198 }
199 
200 /**
201  * Returns the port number.
202  *
203  * @return The port no
204  */
205 public int getPort()
206 {
207     return hostPort;
208 }
209 
210 public String getBindAddress()
211 {
212     return bindAddr;
213 }
214 
215 /**
216  * Returns the type of socket.
217  *
218  * @return The type of socket 
219  */
220 public String getTypeSocket()
221 {
222     return socketType;
223 }
224 
225 public String getSendToHostAddress()
226 {
227     String res = null;
228     if (context != null)
229     {
230         res = context.getSendToHostAddress();
231     }
232     return res;
233 }
234 
235 public String getReceivedFromHostAddress()
236 {
237     String res = null;
238     if (context != null)
239     {
240         res = context.getReceivedFromHostAddress();
241     }
242     return res;
243 }
244 
245 
246 public String getUserName()
247 {
248     return userName;
249 }
250 
251 public void setUserName(String newUserName)
252 {
253     if (newUserName != null && newUserName.equals(userName) == false)
254     {
255         userName = newUserName;
256         hasChanged = true;
257     }
258 }
259 
260 public boolean isUseAuthentication()
261 {
262     return useAuthentication;
263 }
264 
265 public void setUseAuthentication(boolean newUseAuthentication)
266 {
267     if (newUseAuthentication != useAuthentication)
268     {
269         useAuthentication = newUseAuthentication;
270         hasChanged = true;
271     }
272 }
273 
274 public String getUserAuthenticationPassword()
275 {
276     return userAuthenticationPassword;
277 }
278 
279 public void setUserAuthenticationPassword(String newUserAuthenticationPd)
280 {
281     if (newUserAuthenticationPd != null
282             &&
283         newUserAuthenticationPd.equals(userAuthenticationPassword) == false)
284     {
285         userAuthenticationPassword = newUserAuthenticationPd;
286         hasChanged = true;
287     }
288 }
289 
290 public void setPrivacyProtocol(int protocol) throws IllegalArgumentException 
291 {
292     if (protocol == AES_ENCRYPT || protocol == DES_ENCRYPT)
293     {
294         if (protocol != privacyProtocol)
295         {
296             privacyProtocol = protocol;
297             hasChanged = true;
298         }
299     }
300     else
301     {
302         hasChanged = false;
303         throw new IllegalArgumentException("Privacy Protocol "
304             + "should be DES or AES");
305     }
306 }
307 
308 public void setAuthenticationProtocol(int protocol)
309 throws IllegalArgumentException
310 {
311     if (protocol == MD5_PROTOCOL || protocol == SHA1_PROTOCOL)
312     {
313         if (protocol != authenticationProtocol)
314         {
315             authenticationProtocol = protocol;
316             hasChanged = true;
317         }
318     }
319     else
320     {
321         hasChanged = false;
322         throw new IllegalArgumentException("Authentication Protocol "
323             + "should be MD5 or SHA1");
324     }
325 }
326 
327 
328 public int getPrivacyProtocol() 
329 {
330     return privacyProtocol;
331 }
332 
333 
334 public int getAuthenticationProtocol()
335 {
336     return authenticationProtocol;
337 }
338 
339 public boolean isUsePrivacy()
340 {
341     return usePrivacy;
342 }
343 
344 public void setUsePrivacy(boolean newUsePrivacy)
345 {
346     if (newUsePrivacy != usePrivacy)
347     {
348         usePrivacy = newUsePrivacy;
349         hasChanged = true;
350     }
351 }
352 
353 public String getUserPrivacyPassword()
354 {
355     return userPrivacyPassword;
356 }
357 
358 public void setUserPrivacyPassword(String newUserPrivacyPd)
359 {
360     if (newUserPrivacyPd != null
361             &&
362         newUserPrivacyPd.equals(userPrivacyPassword) == false)
363     {
364         userPrivacyPassword = newUserPrivacyPd;
365         hasChanged = true;
366     }
367 }
368 
369 
370 public void setContextEngineId(byte [] newContextEngineId)
371 throws IllegalArgumentException
372 {
373     if (newContextEngineId != null)
374     {
375         if (newContextEngineId.equals(contextEngineId) == false)
376         {
377             contextEngineId = newContextEngineId;
378             hasChanged = true;
379         }
380     }
381     else
382     {
383         hasChanged = false;
384         throw new IllegalArgumentException("contextEngineId is null");
385     }
386 }
387 
388 public byte [] getContextEngineId()
389 {
390     return contextEngineId;
391 }
392 
393 public void setContextName(String newContextName)
394 {
395     if (newContextName != null
396             &&
397         newContextName.equals(contextName) == false)
398     {
399         contextName = newContextName;
400         hasChanged = true;
401     }
402 }
403 
404 public String getContextName()
405 {
406     return contextName;
407 }
408 
409 
410 public void setUsmAgent(UsmAgent newAgent)
411 {
412     if (newAgent != null
413             &&
414         newAgent != usmAgent)
415     {
416         usmAgent = newAgent;
417         hasChanged = true;
418     }
419 }
420 
421 public UsmAgent getUsmAgent()
422 {
423     return usmAgent;
424 }
425 
426 public boolean addDiscoveryPdu(DiscoveryPdu pdu)
427 throws java.io.IOException, PduException, IllegalArgumentException
428 {
429     if (hasChanged == true || context == null)
430     {
431         context = getMatchingContext();
432     }
433     return context.addDiscoveryPdu(pdu);
434 }
435 
436 public boolean addPdu(Pdu pdu)
437 throws java.io.IOException, PduException, IllegalArgumentException
438 {
439     if (hasChanged == true || context == null)
440     {
441         context = getMatchingContext();
442     }
443     return context.addPdu(pdu);
444 }
445 
446 public boolean removePdu(int requestId)
447 {
448     boolean res = false;
449     if (context != null)
450     {
451         res = context.removePdu(requestId);
452     }
453     return res;
454 }
455 
456 public byte [] encodeDiscoveryPacket(byte msg_type, int rId, int errstat,
457       int errind, Enumeration ve, Object obj)
458       throws java.io.IOException, EncodingException
459 {
460     byte [] res = null;
461     if (context != null)
462     {
463         res = context.encodeDiscoveryPacket(msg_type, rId, errstat, errind, ve, obj);
464     }
465     return res;
466 }
467 
468 
469 public byte [] encodePacket(byte msg_type, int rId, int errstat,
470       int errind, Enumeration ve, Object obj)
471       throws java.io.IOException, EncodingException
472 {
473     byte [] res = null;
474     if (context != null)
475     {
476         res = context.encodePacket(msg_type, rId, errstat, errind, ve,
477         obj);
478     }
479     return res;
480 }
481 
482 public void sendPacket(byte[] packet)
483 {
484     if (context != null)
485     {
486         context.sendPacket(packet);
487     }
488 }
489 
490 /**
491  * Releases the resources held by this context. This method will
492  * decrement the reference counter. When the reference counter reaches
493  * zero the actual context is removed from the pool and destroyed.
494  */
495 public void destroy()
496 {
497     synchronized(contextPool)
498     {
499         if (context != null)
500         {
501             String hashKey = context.getHashKey();
502 
503             int count = 0;
504             SnmpContextPoolItem item = (SnmpContextPoolItem) contextPool.get(hashKey);
505             if (item != null)
506             {
507                 count = item.getCounter();
508                 count--;
509                 item.setCounter(count);
510             }
511 
512             if (count <= 0)
513             {
514                 contextPool.remove(hashKey);
515                 context.destroy();
516             }
517             context = null;
518         }
519     }
520 }
521 
522 /**
523  * Destroys all the contexts in the pool and empties the pool. 
524  *
525  * @see #destroy()
526  * @since 4_14
527  */
528 public void destroyPool()
529 {
530     Hashtable copyOfPool = null;
531 
532     synchronized(contextPool)
533     {
534         synchronized(contextPool)
535         {
536             copyOfPool = (Hashtable) contextPool.clone();
537         }
538         contextPool.clear();
539     }
540     context = null;
541     hasChanged = true;
542 
543     Enumeration keys = copyOfPool.keys();
544     while (keys.hasMoreElements())
545     {
546         String key = (String) keys.nextElement();
547         SnmpContextPoolItem item = (SnmpContextPoolItem) copyOfPool.get(key);
548         if (item != null)
549         {
550             SnmpContextBasisFace cntxt = (SnmpContextBasisFace) item.getContext();
551             cntxt.destroy();
552         }
553     }
554     copyOfPool.clear();
555 }
556 
557 
558 public boolean isDestroyed()
559 {
560     boolean isDestroyed = true;
561     if (context != null)
562     {
563         isDestroyed = context.isDestroyed();
564     }
565     return isDestroyed;
566 }
567 
568 /**
569  * Returns a context from the pool.
570  * The pre-existing context (if there is any) is destroyed.
571  * This methods checks for an existing context that matches all our
572  * properties. If such a context does not exist, a new one is created and
573  * added to the pool.
574  *
575  * @return A context from the pool
576  * @see #getHashKey
577  */
578 protected SnmpContextv3 getMatchingContext()
579 throws java.io.IOException, IllegalArgumentException
580 {
581     SnmpContextPoolItem item = null;
582     SnmpContextv3 newContext = null;
583     String hashKey = getHashKey();
584 
585     destroy();
586     synchronized(contextPool)
587     {
588         int count=0;
589         if (contextPool.containsKey(hashKey))
590         {
591             item = (SnmpContextPoolItem) contextPool.get(hashKey);
592             newContext = (SnmpContextv3) item.getContext();
593             count = item.getCounter();
594         }
595         else
596         {
597             newContext = new SnmpContextv3(hostname, hostPort, bindAddr, socketType);
598             newContext.setContextEngineId(contextEngineId);
599             newContext.setContextName(contextName);
600             newContext.setUserName(userName);
601             newContext.setUseAuthentication(useAuthentication);
602             newContext.setUserAuthenticationPassword(userAuthenticationPassword);
603             newContext.setAuthenticationProtocol(authenticationProtocol);
604             newContext.setUsePrivacy(usePrivacy);
605             newContext.setUserPrivacyPassword(userPrivacyPassword);
606             newContext.setUsmAgent(usmAgent);
607             newContext.setPrivacyProtocol(privacyProtocol);
608 
609             item = new SnmpContextPoolItem(newContext);
610             contextPool.put(hashKey, item);
611         }
612         hasChanged = false;
613         count++;
614         item.setCounter(count);
615     }
616     return newContext;
617 }
618 
619 /**
620  * Dumps the pool of contexts. This is for debug purposes.
621  * @param title The title of the dump
622  */
623 public void dumpContexts(String title)
624 {
625     try
626     {
627         if (hasChanged == true)
628         {
629             context = getMatchingContext();
630         }
631     }
632     catch (java.io.IOException exc) 
633     {
634         if (AsnObject.debug > 0)
635         {
636             System.out.println(getClass().getName() + ".dumpContexts(): " + exc.getMessage());
637         }
638     }
639 
640     System.out.println(title + " " + contextPool.size() + " context(s)");
641     Enumeration keys = contextPool.keys();
642     int i=0;
643     while (keys.hasMoreElements())
644     {
645         String key = (String) keys.nextElement();
646         SnmpContextPoolItem item = (SnmpContextPoolItem) contextPool.get(key);
647         if (item != null)
648         {
649             int count = item.getCounter();
650             SnmpContextv3 cntxt = (SnmpContextv3) item.getContext();
651 
652             if (cntxt == context)
653             {
654                 System.out.println("\tcurrent context: ");
655             }
656             System.out.println("\tcontext " + i + ": " + key + ", count: " + count
657                 + ", " + cntxt.toString() + "\n"
658                 + ", " + cntxt.getDebugString());
659             i++;
660         }
661     }
662     System.out.println("\thasChanged: " + hasChanged);
663 }
664 
665 
666 /**
667  * Returns the hash key. This key is built out of all properties. It
668  * serves as key for the hashtable of (v3) contexts.
669  *
670  * @return The hash key
671  */
672 public String getHashKey()
673 {
674     StringBuffer buffer = new StringBuffer();
675     buffer.append(hostname);
676     buffer.append("_").append(hostPort);
677     buffer.append("_").append(bindAddr);
678     buffer.append("_").append(socketType);
679     buffer.append("_").append(useAuthentication);
680     buffer.append("_").append(ProtocolNames[authenticationProtocol]);
681     buffer.append("_").append(ProtocolNames[privacyProtocol]);
682     buffer.append("_").append(userAuthenticationPassword);
683     buffer.append("_").append(userName);
684     buffer.append("_").append(usePrivacy);
685     buffer.append("_").append(userPrivacyPassword);
686     buffer.append("_").append(SnmpUtilities.toHexString(contextEngineId));
687     buffer.append("_").append(contextName);
688     buffer.append("_v").append(getVersion());
689 
690     return buffer.toString();
691 }
692 
693 public void addTrapListener(TrapListener l) throws java.io.IOException
694 {
695     if (hasChanged == true || context == null)
696     {
697         context = getMatchingContext();
698     }
699     context.addTrapListener(l);
700 }
701 
702 public void removeTrapListener(TrapListener l) throws java.io.IOException
703 {
704     if (hasChanged == true || context == null)
705     {
706         context = getMatchingContext();
707     }
708     context.removeTrapListener(l);
709 }
710 
711 public void addTrapListener(TrapListener l, int port) throws java.io.IOException
712 {
713     if (hasChanged == true || context == null)
714     {
715         context = getMatchingContext();
716     }
717     context.addTrapListener(l, port);
718 }
719 
720 public void removeTrapListener(TrapListener l, int port) throws java.io.IOException
721 {
722     if (hasChanged == true || context == null)
723     {
724         context = getMatchingContext();
725     }
726     context.removeTrapListener(l, port);
727 }
728 
729 
730 public void addTrapListener(TrapListener l, ListeningContextPool lcontext) throws java.io.IOException
731 {
732     if (hasChanged == true || context == null)
733     {
734         context = getMatchingContext();
735     }
736     context.addTrapListener(l, lcontext);
737 }
738 
739 public void removeTrapListener(TrapListener l, ListeningContextPool lcontext) throws java.io.IOException
740 {
741     if (hasChanged == true || context == null)
742     {
743         context = getMatchingContext();
744     }
745     context.removeTrapListener(l, lcontext);
746 }
747 
748 
749 public void addRequestPduListener(RequestPduListener l) throws java.io.IOException
750 {
751     if (hasChanged == true || context == null)
752     {
753         context = getMatchingContext();
754     }
755     context.addRequestPduListener(l);
756 }
757 
758 public void removeRequestPduListener(RequestPduListener l) throws java.io.IOException
759 {
760     if (hasChanged == true || context == null)
761     {
762         context = getMatchingContext();
763     }
764     context.removeRequestPduListener(l);
765 }
766 
767 public void addRequestPduListener(RequestPduListener l, int port) throws java.io.IOException
768 {
769     if (hasChanged == true || context == null)
770     {
771         context = getMatchingContext();
772     }
773     context.addRequestPduListener(l, port);
774 }
775 
776 public void removeRequestPduListener(RequestPduListener l, int port) throws java.io.IOException
777 {
778     if (hasChanged == true || context == null)
779     {
780         context = getMatchingContext();
781     }
782     context.removeRequestPduListener(l, port);
783 }
784 
785 
786 public void addRequestPduListener(RequestPduListener l, ListeningContextPool lcontext) throws java.io.IOException
787 {
788     if (hasChanged == true || context == null)
789     {
790         context = getMatchingContext();
791     }
792     context.addRequestPduListener(l, lcontext);
793 }
794 
795 public void removeRequestPduListener(RequestPduListener l, ListeningContextPool lcontext) throws java.io.IOException
796 {
797     if (hasChanged == true || context == null)
798     {
799         context = getMatchingContext();
800     }
801     context.removeRequestPduListener(l, lcontext);
802 }
803 
804 
805 public Pdu processIncomingPdu(byte [] message)
806 throws DecodingException, java.io.IOException
807 {
808     if (hasChanged == true || context == null)
809     {
810         context = getMatchingContext();
811     }
812 
813     Pdu pdu = null;
814     pdu = context.processIncomingPdu(message);
815     return pdu;
816 }
817 
818 /**
819  * Returns a string representation of the object.
820  * @return The string
821  */
822 public String toString()
823 {
824     String res = "";
825     try
826     {
827         if (hasChanged == true || context == null)
828         {
829             context = getMatchingContext();
830         }
831         res = context.toString();
832     }
833     catch (java.io.IOException exc) 
834     {
835         if (AsnObject.debug > 0)
836         {
837             System.out.println(getClass().getName() + ".toString(): " + exc.getMessage());
838         }
839     }
840 
841     return res;
842 }
843 
844 /**
845  * This method is not supported. It will throw a CloneNotSupportedException.
846  *
847  * @since 4_14
848  */
849 public Object clone() throws CloneNotSupportedException
850 {
851     throw new CloneNotSupportedException();
852 }
853 
854 }