OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / net / PlainDatagramSocketImpl.java
1 /* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
2    Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10  
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.java.net;
40
41 import gnu.java.nio.VMChannel;
42
43 import java.io.IOException;
44 import java.io.InterruptedIOException;
45 import java.net.DatagramPacket;
46 import java.net.DatagramSocketImpl;
47 import java.net.InetAddress;
48 import java.net.InetSocketAddress;
49 import java.net.NetworkInterface;
50 import java.net.SocketAddress;
51 import java.net.SocketException;
52 import java.net.SocketTimeoutException;
53 import java.nio.ByteBuffer;
54
55 /**
56  * Written using on-line Java Platform 1.2 API Specification, as well
57  * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
58  * Status:  Believed complete and correct.
59  */
60
61 /**
62  * This is the default socket implementation for datagram sockets.
63  * It makes native calls to C routines that implement BSD style
64  * SOCK_DGRAM sockets in the AF_INET family.
65  *
66  * @author Aaron M. Renn (arenn@urbanophile.com)
67  * @author Warren Levy (warrenl@cygnus.com)
68  */
69 public final class PlainDatagramSocketImpl extends DatagramSocketImpl
70 {
71   private final VMChannel channel;
72   
73   /**
74    * The platform-specific socket implementation.
75    */
76   private final VMPlainSocketImpl impl;
77   
78   /**
79    * Lock object to serialize threads wanting to receive 
80    */
81   private final Object RECEIVE_LOCK = new Object();
82   
83   /**
84    * Lock object to serialize threads wanting to send 
85    */
86   private final Object SEND_LOCK = new Object();
87
88   /**
89    * Default do nothing constructor
90    */
91   public PlainDatagramSocketImpl() throws IOException
92   {
93     channel = new VMChannel();
94     impl = new VMPlainSocketImpl(channel);
95   }
96
97   /*protected void finalize() throws Throwable
98   {
99     synchronized (this)
100       {
101         if (channel.getState().isValid())
102           close();
103       }
104     super.finalize();
105   }*/
106
107   /*public int getNativeFD()
108   {
109     return native_fd;
110   }*/
111
112   /**
113    * Binds this socket to a particular port and interface
114    *
115    * @param port The port to bind to
116    * @param addr The address to bind to
117    *
118    * @exception SocketException If an error occurs
119    */
120   protected synchronized void bind(int port, InetAddress addr)
121     throws SocketException
122   {
123     try
124       {
125         impl.bind(new InetSocketAddress(addr, port));
126       }
127     catch (SocketException se)
128       {
129         throw se;
130       }
131     catch (IOException ioe)
132       {
133         SocketException se = new SocketException();
134         se.initCause(ioe);
135         throw se;
136       }
137   }
138
139   /**
140    * Creates a new datagram socket
141    *
142    * @exception SocketException If an error occurs
143    */
144   protected synchronized void create() throws SocketException
145   {
146     try
147       {
148         channel.initSocket(false);
149       }
150     catch (SocketException se)
151       {
152         throw se;
153       }
154     catch (IOException ioe)
155       {
156         SocketException se = new SocketException();
157         se.initCause(ioe);
158         throw se;
159       }
160   }
161
162   /**
163    * Connects to the remote address and port specified as arguments.
164    *
165    * @param addr The remote address to connect to
166    * @param port The remote port to connect to
167    *
168    * @exception SocketException If an error occurs
169    */
170   protected void connect(InetAddress addr, int port) throws SocketException
171   {
172     channel.connect(new InetSocketAddress(addr, port), 0);
173   }
174
175   /**
176    * Disconnects the socket.
177    *
178    * @since 1.4
179    */
180   protected void disconnect()
181   {
182     synchronized (this)
183       {
184         try
185           {
186             if (channel.getState().isValid())
187               channel.disconnect();
188           }
189         catch (IOException ioe)
190           {
191           }
192       }
193   }
194
195   /**
196    * Sets the Time to Live value for the socket
197    *
198    * @param ttl The new TTL value
199    *
200    * @exception IOException If an error occurs
201    */
202   protected synchronized void setTimeToLive(int ttl) throws IOException
203   {
204     impl.setTimeToLive(ttl);
205   }
206
207   /**
208    * Gets the Time to Live value for the socket
209    *
210    * @return The TTL value
211    *
212    * @exception IOException If an error occurs
213    */
214   protected synchronized int getTimeToLive() throws IOException
215   {
216     return impl.getTimeToLive();
217   }
218
219   protected int getLocalPort()
220   {
221     if (channel == null)
222       return -1;
223
224     try
225       {
226         InetSocketAddress local = channel.getLocalAddress();
227         if (local == null)
228           return -1;
229         return local.getPort();
230       }
231     catch (IOException ioe)
232       {
233         return -1;
234       }
235   }
236
237   /**
238    * Sends a packet of data to a remote host
239    *
240    * @param packet The packet to send
241    *
242    * @exception IOException If an error occurs
243    */
244   protected void send(DatagramPacket packet) throws IOException
245   {
246     synchronized (SEND_LOCK)
247       {
248         ByteBuffer buf = ByteBuffer.wrap(packet.getData(),
249                                          packet.getOffset(),
250                                          packet.getLength());
251         InetAddress remote = packet.getAddress();
252         int port = packet.getPort();
253         if (remote == null)
254           throw new NullPointerException();
255         if (port <= 0)
256           throw new SocketException("invalid port " + port);
257         while (true)
258           {
259             try
260               {
261                 channel.send(buf, new InetSocketAddress(remote, port));
262                 break;
263               }
264             catch (InterruptedIOException ioe)
265               {
266                 // Ignore; interrupted system call.
267               }
268           }
269       }
270   }
271
272   /**
273    * Receives a UDP packet from the network
274    *
275    * @param packet The packet to fill in with the data received
276    *
277    * @exception IOException IOException If an error occurs
278    */
279   protected void receive(DatagramPacket packet)
280     throws IOException
281   {
282     synchronized(RECEIVE_LOCK)
283       {
284         ByteBuffer buf = ByteBuffer.wrap(packet.getData(),
285                                          packet.getOffset(),
286                                          packet.getLength());
287         SocketAddress addr = null;
288         while (true)
289           {
290             try
291               {
292                 addr = channel.receive(buf);
293                 break;
294               }
295             catch (SocketTimeoutException ste)
296               {
297                 throw ste;
298               }
299             catch (InterruptedIOException iioe)
300               {
301                 // Ignore. Loop.
302               }
303           }
304         if (addr != null)
305           packet.setSocketAddress(addr);
306         packet.setLength(buf.position() - packet.getOffset());
307       }
308   }
309
310
311   /**
312    * Sets the value of an option on the socket
313    *
314    * @param optionId The identifier of the option to set
315    * @param value The value of the option to set
316    *
317    * @exception SocketException If an error occurs
318    */
319   public synchronized void setOption(int optionId, Object value)
320     throws SocketException
321   {
322     switch (optionId)
323       {
324         case IP_MULTICAST_IF:
325         case IP_MULTICAST_IF2:
326           impl.setMulticastInterface(optionId, (InetAddress) value);
327           break;
328
329         case IP_MULTICAST_LOOP:
330         case SO_BROADCAST:
331         case SO_KEEPALIVE:
332         case SO_OOBINLINE:
333         case TCP_NODELAY:
334         case IP_TOS:
335         case SO_LINGER:
336         case SO_RCVBUF:
337         case SO_SNDBUF:
338         case SO_TIMEOUT:
339         case SO_REUSEADDR:
340           impl.setOption(optionId, value);
341           return;
342
343       default:
344         throw new SocketException("cannot set option " + optionId);
345       }
346   }
347
348   /**
349    * Retrieves the value of an option on the socket
350    *
351    * @param optionId The identifier of the option to retrieve
352    *
353    * @return The value of the option
354    *
355    * @exception SocketException If an error occurs
356    */
357   public synchronized Object getOption(int optionId)
358     throws SocketException
359   {
360     if (optionId == SO_BINDADDR)
361       {
362         try
363           {
364             InetSocketAddress local = channel.getLocalAddress();
365             if (local == null)
366               return null;
367             return local.getAddress();
368           }
369         catch (SocketException se)
370           {
371             throw se;
372           }
373         catch (IOException ioe)
374           {
375             SocketException se = new SocketException();
376             se.initCause(ioe);
377             throw se;
378           }
379       }
380     if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
381       return impl.getMulticastInterface(optionId);
382
383     return impl.getOption(optionId);
384   }
385
386   /**
387    * Closes the socket
388    */
389   protected synchronized void close()
390   {
391     try
392       {
393         if (channel.getState().isValid())
394           channel.close();
395       }
396     catch (IOException ioe)
397       {
398       }
399   }
400
401   /**
402    * Gets the Time to Live value for the socket
403    *
404    * @return The TTL value
405    *
406    * @exception IOException If an error occurs
407    *
408    * @deprecated 1.2
409    */
410   protected synchronized byte getTTL() throws IOException
411   {
412     return (byte) getTimeToLive();
413   }
414
415   /**
416    * Sets the Time to Live value for the socket
417    *
418    * @param ttl The new TTL value
419    *
420    * @exception IOException If an error occurs
421    *
422    * @deprecated 1.2
423    */
424   protected synchronized void setTTL(byte ttl) throws IOException
425   {
426     setTimeToLive(((int) ttl) & 0xFF);
427   }
428
429   /**
430    * Joins a multicast group
431    *
432    * @param addr The group to join
433    *
434    * @exception IOException If an error occurs
435    */
436   protected synchronized void join(InetAddress addr) throws IOException
437   {
438     impl.join(addr);
439   }
440
441   /**
442    * Leaves a multicast group
443    *
444    * @param addr The group to leave
445    *
446    * @exception IOException If an error occurs
447    */
448   protected synchronized void leave(InetAddress addr) throws IOException
449   {
450     impl.leave(addr);
451   }
452
453   /**
454    * What does this method really do?
455    */
456   protected synchronized int peek(InetAddress addr) throws IOException
457   {
458     throw new IOException("Not Implemented Yet");
459   }
460
461   public int peekData(DatagramPacket packet)
462   {
463     throw new InternalError
464       ("PlainDatagramSocketImpl::peekData is not implemented");
465   }
466
467   public void joinGroup(SocketAddress address, NetworkInterface netIf)
468     throws IOException
469   {
470     if (address == null)
471       throw new NullPointerException();
472     if (!(address instanceof InetSocketAddress))
473       throw new SocketException("unknown address type");
474     impl.joinGroup((InetSocketAddress) address, netIf);
475   }
476
477   public void leaveGroup(SocketAddress address, NetworkInterface netIf)
478     throws IOException
479   {
480     if (address == null)
481       throw new NullPointerException();
482     if (!(address instanceof InetSocketAddress))
483       throw new SocketException("unknown address type");
484     impl.leaveGroup((InetSocketAddress) address, netIf);
485   }
486 }