diff options
Diffstat (limited to 'libjava/java/net')
| -rw-r--r-- | libjava/java/net/PlainSocketImpl.java | 129 | ||||
| -rw-r--r-- | libjava/java/net/natPlainSocketImpl.cc | 253 | 
2 files changed, 367 insertions, 15 deletions
| diff --git a/libjava/java/net/PlainSocketImpl.java b/libjava/java/net/PlainSocketImpl.java index 49155d942b7..81df4873850 100644 --- a/libjava/java/net/PlainSocketImpl.java +++ b/libjava/java/net/PlainSocketImpl.java @@ -1,6 +1,6 @@  // PlainSocketImpl.java - Implementation of SocketImpl. -/* Copyright (C) 1999  Free Software Foundation +/* Copyright (C) 1999 , 2002 Free Software Foundation     This file is part of libgcj. @@ -11,17 +11,16 @@ details.  */  package java.net;  import java.io.*; -/** - * @author Per Bothner <bothner@cygnus.com> - * @date February 22, 1999. - */  /** + * The standard GCJ socket implementation.   * Written using on-line Java Platform 1.2 API Specification, as well   * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).   * Status:  Believed complete and correct. + * + * @author Per Bothner <bothner@cygnus.com> + * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>   */ -  class PlainSocketImpl extends SocketImpl  {    // These fields are mirrored for use in native code to avoid cpp conflicts @@ -35,6 +34,18 @@ class PlainSocketImpl extends SocketImpl                     _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,                     _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF; +  /** +   * The OS file handle representing the socket. +   * This is used for reads and writes to/from the socket and +   * to close it. +   * +   * {@link SocketImpl#fd} is created from this like so: +   * <pre> +   *   fd = new FileDescriptor (fnum); +   * </pre> +   * +   * When the socket is closed this is reset to -1. +   */    int fnum = -1;    // This value is set/read by setOption/getOption. @@ -62,37 +73,127 @@ class PlainSocketImpl extends SocketImpl    protected native void listen (int backlog) throws IOException;    private native void accept (PlainSocketImpl s) throws IOException; +    protected void accept (SocketImpl s) throws IOException    {      accept((PlainSocketImpl) s);    } +  protected native int available() throws IOException; + +  protected native void close () throws IOException; + + +  // Stream handling. + +  /** A cached copy of the in stream for reading from the socket.  */    private InputStream in; + +  /** A cached copy of the out stream for writing to the socket.  */    private OutputStream out; + +  // The native read methods. + +  private native int read() throws IOException; + +  private native int read(byte[] buffer, int offset, int count) +    throws IOException; + + +  // The native write methods. + +  private native void write(int c) throws IOException; + +  private native void write(byte[] buffer, int offset, int count) +    throws IOException; + + +  /** @return the input stream attached to the socket. +   */    protected InputStream getInputStream() throws IOException    { -    // FIXME: TODO - Implement class SocketInputStream timeouts in read();      if (in == null) -      in = new FileInputStream (fd); +      in = new SocketInputStream();      return in;    } +  /** @return the output stream attached to the socket. +   */    protected OutputStream getOutputStream() throws IOException    {      if (out == null) -      out = new FileOutputStream (fd); +      out = new SocketOutputStream();      return out;    } -  protected int available () throws IOException +  /** +   * A stream which reads from the socket implementation. +   * +   * @author Nic Ferrier <nferrier@tapsellferrier.co.uk> +   */ +  class SocketInputStream +    extends InputStream    { -    return in.available(); +    SocketInputStream() +    { +    } +     +    public final void close() throws IOException +    { +      PlainSocketImpl.this.close(); +    } + +    public final int available() throws IOException +    { +      return PlainSocketImpl.this.available(); +    } + +    public final int read() throws IOException +    { +      return PlainSocketImpl.this.read(); +    } + +    public final int read(byte[] buffer, int offset, int length) +      throws IOException +    { +      return PlainSocketImpl.this.read(buffer, offset, length); +    } + +    public final int read(byte[] buffer) +      throws IOException +    { +      return PlainSocketImpl.this.read(buffer, 0, buffer.length); +    }    } -  protected void close () throws IOException +  /** A stream which writes to the socket implementation. +   * +   * @author Nic Ferrier  <nferrier@tapsellferrier.co.uk> +   */ +  class SocketOutputStream +    extends OutputStream    { -    if (fd.valid()) -      fd.close(); +    public final void close() throws IOException +    { +      PlainSocketImpl.this.close(); +    } + +    public final void write(int c) throws IOException +    { +      PlainSocketImpl.this.write(c); +    } + +    public final void write(byte[] buffer, int offset, int length) +      throws IOException +    { +      PlainSocketImpl.this.write(buffer, offset, length); +    } + +    public final void write(byte[] buffer) +      throws IOException +    { +      PlainSocketImpl.this.write(buffer, 0, buffer.length); +    }    }  } diff --git a/libjava/java/net/natPlainSocketImpl.cc b/libjava/java/net/natPlainSocketImpl.cc index 0367d4f24e9..cc8dca11830 100644 --- a/libjava/java/net/natPlainSocketImpl.cc +++ b/libjava/java/net/natPlainSocketImpl.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 1998, 1999, 2000  Free Software Foundation +/* Copyright (C) 1998, 1999, 2000 , 2002 Free Software Foundation     This file is part of libgcj. @@ -85,6 +85,9 @@ _Jv_accept (int fd, struct sockaddr *addr, socklen_t *addrlen)  #include <java/lang/Boolean.h>  #include <java/lang/Class.h>  #include <java/lang/Integer.h> +#include <java/lang/Thread.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h>  #define BooleanClass java::lang::Boolean::class$ @@ -327,6 +330,254 @@ java::net::PlainSocketImpl::accept (java::net::PlainSocketImpl *s)    throw new java::io::IOException (JvNewStringUTF (strerr));  } +// Close(shutdown) the socket. +void +java::net::PlainSocketImpl::close() +{ +  // should we use shutdown here? how would that effect so_linger? +  int res = ::close (fnum); + +  if (res == -1) +    { +      // These three errors are not errors according to tests performed +      // on the reference implementation. +      if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF) +	throw new java::io::IOException  (JvNewStringUTF (strerror (errno))); +    } +  // Safe place to reset the file pointer. +  fnum = -1; +} + +// Write a byte to the socket. +void +java::net::PlainSocketImpl::write(jint b) +{ +  jbyte d =(jbyte) b; +  int r = 0; + +  while (r != 1) +    { +      r = ::write (fnum, &d, 1); +      if (r == -1) +	{ +	  if (java::lang::Thread::interrupted()) +	    { +	      java::io::InterruptedIOException *iioe +		= new java::io::InterruptedIOException  +		(JvNewStringLatin1 (strerror (errno))); +	      iioe->bytesTransferred = 0; +	      throw iioe; +	    } +	  // Some errors should not cause exceptions. +	  if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF) +	    throw new java::io::IOException (JvNewStringUTF (strerror (errno))); +	} +    } +} + +// Write some bytes to the socket. +void +java::net::PlainSocketImpl::write(jbyteArray b, jint offset, jint len) +{ +  if (! b) +    throw new java::lang::NullPointerException; +  if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b)) +    throw new java::lang::ArrayIndexOutOfBoundsException; + +  jbyte *bytes = elements (b) + offset; +  int written = 0; +  while (len > 0) +    { +      int r = ::write (fnum, bytes, len); +      if (r == -1) +        { +	  if (java::lang::Thread::interrupted()) +	    { +	      java::io::InterruptedIOException *iioe +		= new java::io::InterruptedIOException +		(JvNewStringLatin1 (strerror (errno))); +	      iioe->bytesTransferred = written; +	      throw iioe; +	    } +	  // Some errors should not cause exceptions. +	  if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF) +	    throw new java::io::IOException (JvNewStringUTF (strerror (errno))); +	} +      written += r; +      len -= r; +      bytes += r; +    } +} + + +// Read a single byte from the socket. +jint +java::net::PlainSocketImpl::read(void) +{ +  jbyte b; + +  // Do timeouts via select. +  if (timeout > 0) +  { +    // Create the file descriptor set. +    fd_set read_fds; +    FD_ZERO (&read_fds); +    FD_SET (fnum,&read_fds); +    // Create the timeout struct based on our internal timeout value. +    struct timeval timeout_value; +    timeout_value.tv_sec = timeout / 1000; +    timeout_value.tv_usec = (timeout % 1000) * 1000; +    // Select on the fds. +    int sel_retval = _Jv_select (fnum + 1, &read_fds, NULL, NULL, &timeout_value); +    // If select returns 0 we've waited without getting data... +    // that means we've timed out. +    if (sel_retval == 0) +      throw new java::io::InterruptedIOException +	(JvNewStringUTF ("read timed out") ); +    // If select returns ok we know we either got signalled or read some data... +    // either way we need to try to read. +  } +  int r = ::read (fnum, &b, 1); + +  if (r == 0) +    return -1; +  if (java::lang::Thread::interrupted()) +    { +      java::io::InterruptedIOException *iioe = +	new java::io::InterruptedIOException +	(JvNewStringUTF("read interrupted")); +      iioe->bytesTransferred = r == -1 ? 0 : r; +      throw iioe; +    } +  else if (r == -1) +    { +      // Some errors cause us to return end of stream... +      if (errno == ENOTCONN) +	return -1; +      // Other errors need to be signalled. +      throw new java::io::IOException (JvNewStringUTF (strerror (errno))); +    } +  return b & 0xFF; +} + +// Read count bytes into the buffer, starting at offset. +jint +java::net::PlainSocketImpl::read(jbyteArray buffer, jint offset, jint count) +{ +  if (! buffer) +    throw new java::lang::NullPointerException; +  jsize bsize = JvGetArrayLength (buffer); +  if (offset < 0 || count < 0 || offset + count > bsize) +    throw new java::lang::ArrayIndexOutOfBoundsException; +  jbyte *bytes = elements (buffer) + offset; + +  // Do timeouts via select. +  if (timeout > 0) +  { +    // Create the file descriptor set. +    fd_set read_fds; +    FD_ZERO (&read_fds); +    FD_SET (fnum, &read_fds); +    // Create the timeout struct based on our internal timeout value. +    struct timeval timeout_value; +    timeout_value.tv_sec = timeout / 1000; +    timeout_value.tv_usec =(timeout % 1000) * 1000; +    // Select on the fds. +    int sel_retval = _Jv_select (fnum + 1, &read_fds, NULL, NULL, &timeout_value); +    // We're only interested in the 0 return. +    // error returns still require us to try to read  +    // the socket to see what happened. +    if (sel_retval == 0) +      { +	java::io::InterruptedIOException *iioe = +	  new java::io::InterruptedIOException +	  (JvNewStringUTF ("read interrupted")); +	iioe->bytesTransferred = 0; +	throw iioe; +      } +  } +  // Read the socket. +  int r = ::recv (fnum, bytes, count, 0); +  if (r == 0) +    return -1; +  if (java::lang::Thread::interrupted()) +    { +      java::io::InterruptedIOException *iioe = +	new java::io::InterruptedIOException +	(JvNewStringUTF ("read interrupted")); +      iioe->bytesTransferred = r == -1 ? 0 : r; +      throw iioe; +    } +  else if (r == -1) +    { +      // Some errors cause us to return end of stream... +      if (errno == ENOTCONN) +	return -1; +      // Other errors need to be signalled. +      throw new java::io::IOException (JvNewStringUTF (strerror (errno))); +    } +  return r; +} + +// How many bytes are available? +jint +java::net::PlainSocketImpl::available(void) +{ +#if defined(FIONREAD) || defined(HAVE_SELECT) +  long num = 0; +  int r = 0; +  bool num_set = false; + +#if defined(FIONREAD) +  r = ::ioctl (fnum, FIONREAD, &num); +  if (r == -1 && errno == ENOTTY) +    { +      // If the ioctl doesn't work, we don't care. +      r = 0; +      num = 0; +    } +  else +    num_set = true; +#elif defined(HAVE_SELECT) +  if (fnum < 0) +    { +      errno = EBADF; +      r = -1; +    } +#endif + +  if (r == -1) +    { +    posix_error: +      throw new java::io::IOException(JvNewStringUTF(strerror(errno))); + +    } + +  // If we didn't get anything we can use select. + +#if defined(HAVE_SELECT) +  if (! num_set) +    { +      fd_set rd; +      FD_ZERO (&rd); +      FD_SET (fnum, &rd); +      struct timeval tv; +      tv.tv_sec = 0; +      tv.tv_usec = 0; +      r = _Jv_select (fnum + 1, &rd, NULL, NULL, &tv); +      if(r == -1) +	goto posix_error; +      num = r == 0 ? 0 : 1; +    } +#endif /* HAVE_SELECT */ + +  return (jint) num; +#else +  throw new java::io::IOException (JvNewStringUTF ("unimplemented")); +#endif + } + +  void  java::net::PlainSocketImpl::setOption (jint optID, java::lang::Object *value)  { | 

