1 /* PlainSocketImpl.java -- Default socket implementation
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
42 import gnu.java.nio.SocketChannelImpl;
43 import gnu.java.nio.VMChannel;
45 import java.io.InputStream;
46 import java.io.IOException;
47 import java.io.InterruptedIOException;
48 import java.io.OutputStream;
49 import java.net.InetAddress;
50 import java.net.InetSocketAddress;
51 import java.net.SocketAddress;
52 import java.net.SocketException;
53 import java.net.SocketImpl;
54 import java.net.SocketTimeoutException;
55 import java.nio.ByteBuffer;
58 * Written using on-line Java Platform 1.2 API Specification, as well
59 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
60 * Status: Believed complete and correct.
64 * Unless the application installs its own SocketImplFactory, this is the
65 * default socket implemetation that will be used. It simply uses a
66 * combination of Java and native routines to implement standard BSD
67 * style sockets of family AF_INET and types SOCK_STREAM and SOCK_DGRAM
69 * @author Per Bothner (bothner@cygnus.com)
70 * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
71 * @author Aaron M. Renn (arenn@urbanophile.com)
73 public class PlainSocketImpl extends SocketImpl
77 * The underlying plain socket VM implementation.
79 protected VMPlainSocketImpl impl;
82 * A cached copy of the in stream for reading from the socket.
84 private InputStream in;
87 * A cached copy of the out stream for writing to the socket.
89 private OutputStream out;
92 * Indicates whether a channel initiated whatever operation
93 * is being invoked on this socket.
95 private boolean inChannelOperation;
98 * The socket channel we use for IO operation. Package-private for
99 * use by inner classes.
101 SocketChannelImpl channel;
104 * Indicates whether we should ignore whether any associated
105 * channel is set to non-blocking mode. Certain operations
106 * throw an <code>IllegalBlockingModeException</code> if the
107 * associated channel is in non-blocking mode, <i>except</i>
108 * if the operation is invoked by the channel itself.
110 public final boolean isInChannelOperation()
112 return inChannelOperation;
116 * Sets our indicator of whether an I/O operation is being
117 * initiated by a channel.
119 public final void setInChannelOperation(boolean b)
121 inChannelOperation = b;
125 * Default do nothing constructor.
127 public PlainSocketImpl()
129 this.impl = new VMPlainSocketImpl();
133 * Sets the specified option on a socket to the passed in object. For
134 * options that take an integer argument, the passed in object is an
135 * Integer. The option_id parameter is one of the defined constants in
138 * @param optionId The identifier of the option
139 * @param value The value to set the option to
141 * @throws SocketException if an error occurs
143 public void setOption(int optionId, Object value) throws SocketException
148 case IP_MULTICAST_LOOP:
158 impl.setOption(optionId, value);
161 throw new SocketException("Unrecognized TCP option: " + optionId);
166 * Returns the current setting of the specified option. The Object returned
167 * will be an Integer for options that have integer values. The option_id
168 * is one of the defined constants in this interface.
170 * @param optionId the option identifier
172 * @return the current value of the option
174 * @throws SocketException if an error occurs
176 public Object getOption(int optionId) throws SocketException
178 if (optionId == SO_BINDADDR)
182 return channel.getVMChannel().getLocalAddress().getAddress();
184 catch (IOException ioe)
186 SocketException se = new SocketException();
192 // This filters options which are invalid for TCP.
196 case IP_MULTICAST_LOOP:
206 return impl.getOption(optionId);
208 throw new SocketException("Unrecognized TCP option: " + optionId);
213 public void shutdownInput() throws IOException
215 impl.shutdownInput();
218 public void shutdownOutput() throws IOException
220 impl.shutdownOutput();
224 * Creates a new socket that is not bound to any local address/port and
225 * is not connected to any remote address/port. The stream parameter will be
226 * ignored since PlainSocketImpl always is a stream socket. Datagram sockets
227 * are handled by PlainDatagramSocketImpl.
229 * @param stream <code>true</code> for stream sockets, <code>false</code> for
232 protected synchronized void create(boolean stream) throws IOException
234 channel = new SocketChannelImpl(false);
235 VMChannel vmchannel = channel.getVMChannel();
236 vmchannel.initSocket(stream);
237 channel.configureBlocking(true);
238 impl.getState().setChannelFD(vmchannel.getState());
242 * Connects to the remote hostname and port specified as arguments.
244 * @param hostname the remote hostname to connect to
245 * @param port the remote port to connect to
247 * @throws IOException If an error occurs
249 protected synchronized void connect(String hostname, int port)
252 connect(InetAddress.getByName(hostname), port);
256 * Connects to the remote address and port specified as arguments.
258 * @param addr the remote address to connect to
259 * @param port the remote port to connect to
261 * @throws IOException If an error occurs
263 protected void connect(InetAddress addr, int port) throws IOException
265 connect(new InetSocketAddress(addr, port), 0);
269 * Connects to the remote socket address with a specified timeout.
271 * @param address the remote address to connect to
272 * @param timeout the timeout to use for this connect, 0 means infinite.
274 * @throws IOException If an error occurs
276 protected synchronized void connect(SocketAddress address, int timeout)
281 boolean connected = channel.connect(address, timeout);
283 throw new SocketTimeoutException("connect timed out");
285 // Using the given SocketAddress is important to preserve
286 // hostnames given by the caller.
287 InetSocketAddress addr = (InetSocketAddress) address;
288 this.address = addr.getAddress();
289 this.port = addr.getPort();
293 * Binds to the specified port on the specified addr. Note that this addr
294 * must represent a local IP address. **** How bind to INADDR_ANY? ****
296 * @param addr the address to bind to
297 * @param port the port number to bind to
299 * @throws IOException if an error occurs
301 protected synchronized void bind(InetAddress addr, int port)
306 impl.bind(new InetSocketAddress(addr, port));
307 localport = channel.getVMChannel().getLocalAddress().getPort();
311 * Starts listening for connections on a socket. The queuelen parameter
312 * is how many pending connections will queue up waiting to be serviced
313 * before being accept'ed. If the queue of pending requests exceeds this
314 * number, additional connections will be refused.
316 * @param queuelen The length of the pending connection queue
318 * @throws IOException If an error occurs
320 protected synchronized void listen(int queuelen)
323 impl.listen(queuelen);
327 * Accepts a new connection on this socket and returns in in the
328 * passed in SocketImpl.
330 * @param impl The SocketImpl object to accept this connection.
332 protected synchronized void accept(SocketImpl impl)
337 if (!(impl instanceof PlainSocketImpl))
338 throw new IOException("incompatible SocketImpl: "
339 + impl.getClass().getName());
340 PlainSocketImpl that = (PlainSocketImpl) impl;
341 VMChannel c = channel.getVMChannel().accept();
342 that.impl.getState().setChannelFD(c.getState());
343 that.channel = new SocketChannelImpl(c);
344 that.setOption(SO_REUSEADDR, Boolean.TRUE);
345 // Reset the inherited timeout.
346 that.setOption(SO_TIMEOUT, Integer.valueOf(0));
351 * Returns the number of bytes that the caller can read from this socket
354 * @return the number of readable bytes before blocking
356 * @throws IOException if an error occurs
358 protected int available() throws IOException
361 throw new SocketException("not connected");
362 return channel.getVMChannel().available();
366 * Closes the socket. This will cause any InputStream or OutputStream
367 * objects for this Socket to be closed as well.
370 * Note that if the SO_LINGER option is set on this socket, then the
371 * operation could block.
374 * @throws IOException if an error occurs
376 protected void close() throws IOException
378 if (impl.getState().isValid())
385 public void sendUrgentData(int data) throws IOException
387 impl.sendUrgentData(data);
391 * Returns an InputStream object for reading from this socket. This will
392 * be an instance of SocketInputStream.
394 * @return An input stream attached to the socket.
396 * @exception IOException If an error occurs
398 protected synchronized InputStream getInputStream() throws IOException
401 in = new SocketInputStream();
407 * Returns an OutputStream object for writing to this socket. This will
408 * be an instance of SocketOutputStream.
410 * @return An output stream attached to the socket.
412 * @exception IOException If an error occurs
414 protected synchronized OutputStream getOutputStream() throws IOException
417 out = new SocketOutputStream();
422 public VMChannel getVMChannel()
426 return channel.getVMChannel();
430 * @see java.net.SocketImpl#getInetAddress()
432 protected InetAddress getInetAddress()
439 InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
442 // To mimic behavior of the RI the InetAddress instance which was
443 // used to establish the connection is returned instead of one that
444 // was created by the native layer (this preserves exact hostnames).
448 return remote.getAddress();
450 catch (IOException ioe)
457 * @see java.net.SocketImpl#getLocalPort()
459 protected int getLocalPort()
465 InetSocketAddress local = channel.getVMChannel().getLocalAddress();
468 return local.getPort();
470 catch (IOException ioe)
476 public InetSocketAddress getLocalAddress()
482 return channel.getVMChannel().getLocalAddress();
484 catch (IOException ioe)
491 * @see java.net.SocketImpl#getPort()
493 protected int getPort()
500 InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
503 return remote.getPort();
505 catch (IOException ioe)
512 * This class contains an implementation of <code>InputStream</code> for
513 * sockets. It in an internal only class used by <code>PlainSocketImpl</code>.
515 * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
517 final class SocketInputStream
521 * Returns the number of bytes available to be read before blocking
523 public int available() throws IOException
525 return PlainSocketImpl.this.available();
529 * This method not only closes the stream, it closes the underlying socket
530 * (and thus any connection) and invalidates any other Input/Output streams
531 * for the underlying impl object
533 public void close() throws IOException
535 PlainSocketImpl.this.close();
539 * Reads the next byte of data and returns it as an int.
541 * @return The byte read (as an int) or -1 if end of stream);
543 * @exception IOException If an error occurs.
545 public int read() throws IOException
548 throw new SocketException("not connected");
553 return channel.getVMChannel().read();
555 catch (SocketTimeoutException ste)
559 catch (InterruptedIOException iioe)
561 // Ignore; NIO may throw this; net io shouldn't
567 * Reads up to len bytes of data into the caller supplied buffer starting
568 * at offset bytes from the start of the buffer
570 * @param buf The buffer
571 * @param offset Offset into the buffer to start reading from
572 * @param len The number of bytes to read
574 * @return The number of bytes actually read or -1 if end of stream
576 * @exception IOException If an error occurs.
578 public int read (byte[] buf, int offset, int len) throws IOException
581 throw new SocketException("not connected");
582 ByteBuffer b = ByteBuffer.wrap(buf, offset, len);
587 return channel.read(b);
589 catch (SocketTimeoutException ste)
593 catch (InterruptedIOException iioe)
595 // Ignored; NIO may throw this; net IO not.
602 * This class is used internally by <code>PlainSocketImpl</code> to be the
603 * <code>OutputStream</code> subclass returned by its
604 * <code>getOutputStream method</code>. It expects only to be used in that
607 * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
609 final class SocketOutputStream
613 * This method closes the stream and the underlying socket connection. This
614 * action also effectively closes any other InputStream or OutputStream
615 * object associated with the connection.
617 * @exception IOException If an error occurs
619 public void close() throws IOException
621 PlainSocketImpl.this.close();
625 * Writes a byte (passed in as an int) to the given output stream
627 * @param b The byte to write
629 * @exception IOException If an error occurs
631 public void write(int b) throws IOException
634 throw new SocketException("not connected");
639 channel.getVMChannel().write(b);
642 catch (InterruptedIOException iioe)
650 * Writes len number of bytes from the array buf to the stream starting
651 * at offset bytes into the buffer.
653 * @param buf The buffer
654 * @param offset Offset into the buffer to start writing from
655 * @param len The number of bytes to write
657 * @exception IOException If an error occurs.
659 public void write (byte[] buf, int offset, int len) throws IOException
662 throw new SocketException("not connected");
663 ByteBuffer b = ByteBuffer.wrap(buf, offset, len);
664 while (b.hasRemaining())
668 if (channel.write(b) == -1)
669 throw new IOException("channel has been closed");
671 catch (InterruptedIOException iioe)