KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > transport > DefaultUdpTransportMapping


1 /*_############################################################################
2   _##
3   _## SNMP4J - DefaultUdpTransportMapping.java
4   _##
5   _## Copyright 2003-2007 Frank Fock and Jochen Katz (SNMP4J.org)
6   _##
7   _## Licensed under the Apache License, Version 2.0 (the "License");
8   _## you may not use this file except in compliance with the License.
9   _## You may obtain a copy of the License at
10   _##
11   _## http://www.apache.org/licenses/LICENSE-2.0
12   _##
13   _## Unless required by applicable law or agreed to in writing, software
14   _## distributed under the License is distributed on an "AS IS" BASIS,
15   _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   _## See the License for the specific language governing permissions and
17   _## limitations under the License.
18   _##
19   _##########################################################################*/

20
21
22
23
24
25 package org.snmp4j.transport;
26
27 import java.io.IOException JavaDoc;
28 import java.net.*;
29 import java.nio.ByteBuffer JavaDoc;
30
31 import org.snmp4j.log.*;
32 import org.snmp4j.smi.*;
33 import org.snmp4j.SNMP4JSettings;
34
35 /**
36  * The <code>DefaultUdpTransportMapping</code> implements a UDP transport
37  * mapping based on Java standard IO and using an internal thread for
38  * listening on the inbound socket.
39  *
40  * @author Frank Fock
41  * @version 1.7.3
42  */

43 public class DefaultUdpTransportMapping extends UdpTransportMapping {
44
45   private static final LogAdapter logger =
46       LogFactory.getLogger(DefaultUdpTransportMapping.class);
47
48   protected DatagramSocket socket = null;
49   protected ListenThread listener;
50   private int socketTimeout = 1000;
51
52   private int receiveBufferSize = 0; // not set by default
53

54   /**
55    * Creates a UDP transport with an arbitrary local port on all local
56    * interfaces.
57    *
58    * @throws IOException
59    * if socket binding fails.
60    */

61   public DefaultUdpTransportMapping() throws IOException JavaDoc {
62     super(new UdpAddress(InetAddress.getLocalHost(), 0));
63     socket = new DatagramSocket(udpAddress.getPort());
64   }
65
66   /**
67    * Creates a UDP transport with optional reusing the address if is currently
68    * in timeout state (TIME_WAIT) after the connection is closed.
69    *
70    * @param udpAddress
71    * the local address for sending and receiving of UDP messages.
72    * @param reuseAddress
73    * if <code>true</code> addresses are reused which provides faster socket
74    * binding if an application is restarted for instance.
75    * @throws IOException
76    * if socket binding fails.
77    * @since 1.7.3
78    */

79   public DefaultUdpTransportMapping(UdpAddress udpAddress,
80                                     boolean reuseAddress) throws IOException JavaDoc {
81     super(udpAddress);
82     socket = new DatagramSocket(null);
83     socket.setReuseAddress(reuseAddress);
84     final SocketAddress addr =
85         new InetSocketAddress(udpAddress.getInetAddress(),udpAddress.getPort());
86     socket.bind(addr);
87   }
88
89   /**
90    * Creates a UDP transport on the specified address. The address will not be
91    * reused if it is currently in timeout state (TIME_WAIT).
92    *
93    * @param udpAddress
94    * the local address for sending and receiving of UDP messages.
95    * @throws IOException
96    * if socket binding fails.
97    */

98   public DefaultUdpTransportMapping(UdpAddress udpAddress) throws IOException JavaDoc {
99     super(udpAddress);
100     socket = new DatagramSocket(udpAddress.getPort(),
101                                 udpAddress.getInetAddress());
102   }
103
104   public void sendMessage(Address targetAddress, byte[] message)
105       throws java.io.IOException JavaDoc
106   {
107     InetSocketAddress targetSocketAddress =
108         new InetSocketAddress(((UdpAddress)targetAddress).getInetAddress(),
109                               ((UdpAddress)targetAddress).getPort());
110     if (logger.isDebugEnabled()) {
111       logger.debug("Sending message to "+targetAddress+" with length "+
112                    message.length+": "+
113                    new OctetString(message).toHexString());
114     }
115     socket.send(new DatagramPacket(message, message.length,
116                                    targetSocketAddress));
117   }
118
119   /**
120    * Closes the socket and stops the listener thread.
121    *
122    * @throws IOException
123    */

124   public void close() throws IOException JavaDoc {
125     ListenThread l = listener;
126     if (l != null) {
127       l.close();
128       l.interrupt();
129       if (socketTimeout > 0) {
130         try {
131           l.join();
132         }
133         catch (InterruptedException JavaDoc ex) {
134           logger.warn(ex);
135         }
136       }
137       listener = null;
138     }
139     if (!socket.isClosed()) {
140       socket.disconnect();
141       socket.close();
142     }
143   }
144
145   /**
146    * Starts the listener thread that accepts incoming messages. The thread is
147    * started in daemon mode and thus it will not block application terminated.
148    * Nevertheless, the {@link #close()} method should be called to stop the
149    * listen thread gracefully and free associated ressources.
150    *
151    * @throws IOException
152    */

153   public synchronized void listen() throws IOException JavaDoc {
154     if (listener != null) {
155       throw new SocketException("Port already listening");
156     }
157     listener = new ListenThread();
158     // set daemon mode
159
listener.setDaemon(true);
160     listener.start();
161   }
162
163   /**
164    * Changes the priority of the listen thread for this UDP transport mapping.
165    * This method has no effect, if called before {@link #listen()} has been
166    * called for this transport mapping.
167    *
168    * @param newPriority
169    * the new priority.
170    * @see Thread#setPriority
171    * @since 1.2.2
172    */

173   public void setPriority(int newPriority) {
174     ListenThread lt = listener;
175     if (lt != null) {
176       lt.setPriority(newPriority);
177     }
178   }
179
180   /**
181    * Returns the priority of the internal listen thread.
182    * @return
183    * a value between {@link Thread#MIN_PRIORITY} and
184    * {@link Thread#MAX_PRIORITY}.
185    * @since 1.2.2
186    */

187   public int getPriority() {
188     ListenThread lt = listener;
189     if (lt != null) {
190       return lt.getPriority();
191     }
192     else {
193       return Thread.NORM_PRIORITY;
194     }
195   }
196
197   /**
198    * Sets the name of the listen thread for this UDP transport mapping.
199    * This method has no effect, if called before {@link #listen()} has been
200    * called for this transport mapping.
201    *
202    * @param name
203    * the new thread name.
204    * @since 1.6
205    */

206   public void setThreadName(String JavaDoc name) {
207     ListenThread lt = listener;
208     if (lt != null) {
209       lt.setName(name);
210     }
211   }
212
213   /**
214    * Returns the name of the listen thread.
215    * @return
216    * the thread name if in listening mode, otherwise <code>null</code>.
217    * @since 1.6
218    */

219   public String JavaDoc getThreadName() {
220     ListenThread lt = listener;
221     if (lt != null) {
222       return lt.getName();
223     }
224     else {
225       return null;
226     }
227   }
228
229   public void setMaxInboundMessageSize(int maxInboundMessageSize) {
230     this.maxInboundMessageSize = maxInboundMessageSize;
231   }
232
233   public int getSocketTimeout() {
234     return socketTimeout;
235   }
236
237   /**
238    * Gets the requested receive buffer size for the underlying UDP socket.
239    * This size might not reflect the actual size of the receive buffer, which
240    * is implementation specific.
241    * @return
242    * <=0 if the default buffer size of the OS is used, or a value >0 if the
243    * user specified a buffer size.
244    */

245   public int getReceiveBufferSize() {
246     return receiveBufferSize;
247   }
248
249   /**
250    * Sets the receive buffer size, which should be > the maximum inbound message
251    * size. This method has to be called before {@link #listen()} to be
252    * effective.
253    * @param receiveBufferSize
254    * an integer value >0 and > {@link #getMaxInboundMessageSize()}.
255    */

256   public void setReceiveBufferSize(int receiveBufferSize) {
257     if (receiveBufferSize <= 0) {
258       throw new IllegalArgumentException JavaDoc("Receive buffer size must be > 0");
259     }
260     this.receiveBufferSize = receiveBufferSize;
261   }
262
263   public void setSocketTimeout(int socketTimeout) {
264     this.socketTimeout = socketTimeout;
265   }
266
267   public boolean isListening() {
268     return (listener != null);
269   }
270
271   class ListenThread extends Thread JavaDoc {
272
273     private byte[] buf;
274     private volatile boolean stop = false;
275
276
277     public ListenThread() throws SocketException {
278       buf = new byte[getMaxInboundMessageSize()];
279       setName("DefaultUDPTransportMapping_"+getAddress());
280     }
281
282     public void run() {
283       try {
284         socket.setSoTimeout(getSocketTimeout());
285         if (receiveBufferSize > 0) {
286           socket.setReceiveBufferSize(Math.max(receiveBufferSize,
287                                                maxInboundMessageSize));
288         }
289         if (logger.isInfoEnabled()) {
290           logger.info("UDP receive buffer size for socket " +
291                       getAddress() + " is set to: " +
292                       socket.getReceiveBufferSize());
293         }
294       }
295       catch (SocketException ex) {
296         logger.error(ex);
297         setSocketTimeout(0);
298       }
299       while (!stop) {
300         DatagramPacket packet = new DatagramPacket(buf, buf.length,
301                                                    udpAddress.getInetAddress(),
302                                                    udpAddress.getPort());
303         try {
304           socket.receive(packet);
305           if (logger.isDebugEnabled()) {
306             logger.debug("Received message from "+packet.getAddress()+"/"+
307                          packet.getPort()+
308                          " with length "+packet.getLength()+": "+
309                          new OctetString(packet.getData(), 0,
310                                          packet.getLength()).toHexString());
311           }
312           ByteBuffer JavaDoc bis;
313           // If messages are processed asynchronously (i.e. multi-threaded)
314
// then we have to copy the buffer's content here!
315
if (isAsyncMsgProcessingSupported()) {
316             byte[] bytes = new byte[packet.getLength()];
317             System.arraycopy(packet.getData(), 0, bytes, 0, bytes.length);
318             bis = ByteBuffer.wrap(bytes);
319           }
320           else {
321             bis = ByteBuffer.wrap(packet.getData());
322           }
323           fireProcessMessage(new UdpAddress(packet.getAddress(),
324                                             packet.getPort()), bis);
325         }
326         catch (SocketTimeoutException stex) {
327           // ignore
328
}
329         catch (PortUnreachableException purex) {
330           synchronized (DefaultUdpTransportMapping.this) {
331             listener = null;
332           }
333           logger.error(purex);
334           if (logger.isDebugEnabled()) {
335             purex.printStackTrace();
336           }
337           if (SNMP4JSettings.isFowardRuntimeExceptions()) {
338             throw new RuntimeException JavaDoc(purex);
339           }
340           break;
341         }
342         catch (IOException JavaDoc iox) {
343           logger.warn(iox);
344           if (logger.isDebugEnabled()) {
345             iox.printStackTrace();
346           }
347           if (SNMP4JSettings.isFowardRuntimeExceptions()) {
348             throw new RuntimeException JavaDoc(iox);
349           }
350         }
351       }
352       synchronized (DefaultUdpTransportMapping.this) {
353         listener = null;
354         stop = true;
355         socket.close();
356       }
357     }
358
359     public void close() {
360       stop = true;
361     }
362   }
363 }
364
Popular Tags