2003-09-25 Michael Koch <konqueror@gmx.de>
authormkoch <mkoch@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 25 Sep 2003 10:17:00 +0000 (10:17 +0000)
committermkoch <mkoch@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 25 Sep 2003 10:17:00 +0000 (10:17 +0000)
* gnu/java/nio/DatagramChannelImpl.java
(DatagramChannelImpl): Made class final.
(blocking): Made private.
(socket): Made it a NIODatagramSocket and private.
(DatagramChannelImpl): create NIODatagramSocket instead of
DatagramSocket.
(implConfigureBlocking): Set socket timeout.
(connect): Check that channel is not closed.
(write): Implemented.
(write): Rewritten.
(read): Implemented.
(read): Rewritten.
(receive): Implemented.
(send): Implemented.
* gnu/java/nio/SelectionKeyImpl.java
(readyOps): Made private.
(interestOps): Made private.
(impl): Made private.
(ch): Made private.
(readyOps): Check if selection key is valid.
(interestOps): Likewise.
* gnu/java/nio/SelectorImpl.java
(closed): Removed.
(keys): Made private.
(selected): Made private.
(finalize): New method.
(implCloseSelector): Rewritten.
(keys): Return unmodifiable Set.
(deregisterCancelledKeys): Fixed typo in method name.
* gnu/java/nio/SocketChannelImpl.java
(SocketChannelImpl): Made class final.
(socket): Made it a NIOSocket and private.
(blocking): Made private.
(connected): Made private.
(connectionPending): New member variable.
(SocketChannelImpl): New implementation.
(finalizer): Use isConnected().
(connect): Rewritten.
(finishConnect): Throws IOException, implemented.
(isConnectionPending): Return connectionPending.
(read): Rewritten.
(write): Rewritten.
* gnu/java/nio/NIOConstants.java: New file.
* Makefile.am (ordinary_java_source_files):
Added gnu/java/nio/NIOConstants.java.
* Makefile.in: Regenerated.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@71769 138bc75d-0d04-0410-961f-82ee72b054a4

libjava/ChangeLog
libjava/Makefile.am
libjava/Makefile.in
libjava/gnu/java/nio/DatagramChannelImpl.java
libjava/gnu/java/nio/NIOConstants.java [new file with mode: 0644]
libjava/gnu/java/nio/SelectionKeyImpl.java
libjava/gnu/java/nio/SelectorImpl.java
libjava/gnu/java/nio/SocketChannelImpl.java

index b8769cb..fdcc1c9 100644 (file)
@@ -1,5 +1,54 @@
 2003-09-25  Michael Koch  <konqueror@gmx.de>
 
+       * gnu/java/nio/DatagramChannelImpl.java
+       (DatagramChannelImpl): Made class final.
+       (blocking): Made private.
+       (socket): Made it a NIODatagramSocket and private.
+       (DatagramChannelImpl): create NIODatagramSocket instead of
+       DatagramSocket.
+       (implConfigureBlocking): Set socket timeout.
+       (connect): Check that channel is not closed.
+       (write): Implemented.
+       (write): Rewritten.
+       (read): Implemented.
+       (read): Rewritten.
+       (receive): Implemented.
+       (send): Implemented.
+       * gnu/java/nio/SelectionKeyImpl.java
+       (readyOps): Made private.
+       (interestOps): Made private.
+       (impl): Made private.
+       (ch): Made private.
+       (readyOps): Check if selection key is valid.
+       (interestOps): Likewise.
+       * gnu/java/nio/SelectorImpl.java
+       (closed): Removed.
+       (keys): Made private.
+       (selected): Made private.
+       (finalize): New method.
+       (implCloseSelector): Rewritten.
+       (keys): Return unmodifiable Set.
+       (deregisterCancelledKeys): Fixed typo in method name.
+       * gnu/java/nio/SocketChannelImpl.java
+       (SocketChannelImpl): Made class final.
+       (socket): Made it a NIOSocket and private.
+       (blocking): Made private.
+       (connected): Made private.
+       (connectionPending): New member variable.
+       (SocketChannelImpl): New implementation.
+       (finalizer): Use isConnected().
+       (connect): Rewritten.
+       (finishConnect): Throws IOException, implemented.
+       (isConnectionPending): Return connectionPending.
+       (read): Rewritten.
+       (write): Rewritten.
+       * gnu/java/nio/NIOConstants.java: New file.
+       * Makefile.am (ordinary_java_source_files):
+       Added gnu/java/nio/NIOConstants.java.
+       * Makefile.in: Regenerated.
+
+2003-09-25  Michael Koch  <konqueror@gmx.de>
+
        * java/net/InetAddress.java:
        Reorder imports, remove implementation comment.
        (isMulticastAddress): Merged documentation from classpath.
index c8785e2..889d092 100644 (file)
@@ -2184,6 +2184,7 @@ gnu/java/net/PlainDatagramSocketImpl.java \
 gnu/java/net/PlainSocketImpl.java \
 gnu/java/nio/DatagramChannelImpl.java \
 gnu/java/nio/FileLockImpl.java \
+gnu/java/nio/NIOConstants.java \
 gnu/java/nio/NIODatagramSocket.java \
 gnu/java/nio/NIOSocket.java \
 gnu/java/nio/PipeImpl.java \
index 3275f3c..87b0657 100644 (file)
@@ -1902,6 +1902,7 @@ gnu/java/net/PlainDatagramSocketImpl.java \
 gnu/java/net/PlainSocketImpl.java \
 gnu/java/nio/DatagramChannelImpl.java \
 gnu/java/nio/FileLockImpl.java \
+gnu/java/nio/NIOConstants.java \
 gnu/java/nio/NIODatagramSocket.java \
 gnu/java/nio/NIOSocket.java \
 gnu/java/nio/PipeImpl.java \
@@ -3025,7 +3026,7 @@ DEP_FILES =  .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
 .deps/gnu/java/net/natPlainDatagramSocketImpl.P \
 .deps/gnu/java/net/natPlainSocketImpl.P \
 .deps/gnu/java/nio/DatagramChannelImpl.P \
-.deps/gnu/java/nio/FileLockImpl.P \
+.deps/gnu/java/nio/FileLockImpl.P .deps/gnu/java/nio/NIOConstants.P \
 .deps/gnu/java/nio/NIODatagramSocket.P .deps/gnu/java/nio/NIOSocket.P \
 .deps/gnu/java/nio/PipeImpl.P .deps/gnu/java/nio/SelectionKeyImpl.P \
 .deps/gnu/java/nio/SelectorImpl.P \
index dce7dab..a4f46df 100644 (file)
@@ -1,5 +1,5 @@
 /* DatagramChannelImpl.java -- 
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -39,23 +39,30 @@ exception statement from your version. */
 package gnu.java.nio;
 
 import java.io.IOException;
+import java.net.DatagramPacket;
 import java.net.DatagramSocket;
+import gnu.java.net.PlainDatagramSocketImpl;
 import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
 import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
 import java.nio.channels.DatagramChannel;
 import java.nio.channels.NotYetConnectedException;
 import java.nio.channels.spi.SelectorProvider;
 
-public class DatagramChannelImpl extends DatagramChannel
+/**
+ * @author Michael Koch
+ */
+public final class DatagramChannelImpl extends DatagramChannel
 {
-  boolean blocking = false;
-  DatagramSocket socket;
+  private NIODatagramSocket socket;
+  private boolean blocking = false;
   
   protected DatagramChannelImpl (SelectorProvider provider)
     throws IOException
   {
     super (provider);
-    socket = new DatagramSocket ();
+    socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
   }
     
   public DatagramSocket socket ()
@@ -72,12 +79,16 @@ public class DatagramChannelImpl extends DatagramChannel
   protected void implConfigureBlocking (boolean blocking)
     throws IOException
   {
-    this.blocking = blocking; // FIXME
+    socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+    this.blocking = blocking;
   }
 
   public DatagramChannel connect (SocketAddress remote)
     throws IOException
   {
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
     socket.connect (remote);
     return this;
   }
@@ -100,19 +111,25 @@ public class DatagramChannelImpl extends DatagramChannel
     if (!isConnected ())
       throw new NotYetConnectedException ();
     
-    throw new Error ("Not implemented");
+    return send (src, socket.getRemoteSocketAddress());
   }
 
   public long write (ByteBuffer[] srcs, int offset, int length)
     throws IOException
   {
-    // FIXME: Should we throw an exception if offset and/or length
-    // have wrong values ?
-
+    if (!isConnected())
+      throw new NotYetConnectedException();
+
+    if ((offset < 0)
+        || (offset > srcs.length)
+        || (length < 0)
+        || (length > (srcs.length - offset)))
+      throw new IndexOutOfBoundsException();
+      
     long result = 0;
 
-    for (int i = offset; i < offset + length; i++)
-      result += write (srcs [i]);
+    for (int index = offset; index < offset + length; index++)
+      result += write (srcs [index]);
 
     return result;
   }
@@ -123,19 +140,27 @@ public class DatagramChannelImpl extends DatagramChannel
     if (!isConnected ())
       throw new NotYetConnectedException ();
     
-    throw new Error ("Not implemented");
+    int remaining = dst.remaining();
+    receive (dst);
+    return remaining - dst.remaining();
   }
     
   public long read (ByteBuffer[] dsts, int offset, int length)
     throws IOException
   {
-    // FIXME: Should we throw an exception if offset and/or length
-    // have wrong values ?
-
+    if (!isConnected())
+      throw new NotYetConnectedException();
+    
+    if ((offset < 0)
+        || (offset > dsts.length)
+        || (length < 0)
+        || (length > (dsts.length - offset)))
+      throw new IndexOutOfBoundsException();
+      
     long result = 0;
 
-    for (int i = offset; i < offset + length; i++)
-      result += read (dsts [i]);
+    for (int index = offset; index < offset + length; index++)
+      result += read (dsts [index]);
 
     return result;
   }
@@ -143,12 +168,87 @@ public class DatagramChannelImpl extends DatagramChannel
   public SocketAddress receive (ByteBuffer dst)
     throws IOException
   {
-    throw new Error ("Not implemented");
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
+    try
+      {
+        DatagramPacket packet;
+        int len = dst.remaining();
+        
+        if (dst.hasArray())
+          {
+            packet = new DatagramPacket (dst.array(),
+                                         dst.arrayOffset() + dst.position(),
+                                         len);
+          }
+        else
+          {
+            packet = new DatagramPacket (new byte [len], len);
+          }
+
+        boolean completed = false;
+
+        try
+          {
+            begin();
+            socket.receive (packet);
+            completed = true;
+          }
+        finally
+          {
+            end (completed);
+          }
+
+        if (!dst.hasArray())
+          {
+            dst.put (packet.getData(), packet.getOffset(), packet.getLength());
+          }
+
+        // FIMXE: remove this testing code.
+        for (int i = 0; i < packet.getLength(); i++)
+          {
+            System.out.println ("Byte " + i + " has value " + packet.getData() [packet.getOffset() + i]);
+          }
+
+        return packet.getSocketAddress();
+      }
+    catch (SocketTimeoutException e)
+      {
+        return null;
+      }
   }
     
   public int send (ByteBuffer src, SocketAddress target)
     throws IOException
   {
-    throw new Error ("Not implemented");
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
+    byte[] buffer;
+    int offset = 0;
+    int len = src.remaining();
+    
+    if (src.hasArray())
+      {
+        buffer = src.array();
+        offset = src.arrayOffset() + src.position();
+      }
+    else
+      {
+        buffer = new byte [len];
+        src.get (buffer);
+      }
+
+    DatagramPacket packet = new DatagramPacket (buffer, offset, len, target);
+
+    // FIMXE: remove this testing code.
+    for (int i = 0; i < packet.getLength(); i++)
+      {
+        System.out.println ("Byte " + i + " has value " + packet.getData() [packet.getOffset() + i]);
+      }
+
+    socket.send (packet);
+    return len;
   }
 }
diff --git a/libjava/gnu/java/nio/NIOConstants.java b/libjava/gnu/java/nio/NIOConstants.java
new file mode 100644 (file)
index 0000000..8a71202
--- /dev/null
@@ -0,0 +1,47 @@
+/* NIOConstants.java --
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+/**
+ * @author Michael Koch
+ */
+public final class NIOConstants
+{
+  public static final int DEFAULT_TIMEOUT = 50;
+}
index 72dc20b..df4faa3 100644 (file)
@@ -1,5 +1,5 @@
 /* SelectionKeyImpl.java -- 
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -37,6 +37,7 @@ exception statement from your version. */
 
 package gnu.java.nio;
 
+import java.nio.channels.CancelledKeyException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
@@ -45,10 +46,10 @@ import java.nio.channels.spi.AbstractSelectionKey;
 public class SelectionKeyImpl extends AbstractSelectionKey
 {
   int fd;
-  int readyOps;
-  int interestOps;
-  SelectorImpl impl;
-  SelectableChannel ch;
+  private int readyOps;
+  private int interestOps;
+  private SelectorImpl impl;
+  private SelectableChannel ch;
 
   public SelectionKeyImpl (SelectableChannel ch, SelectorImpl impl, int fd)
   {
@@ -64,22 +65,34 @@ public class SelectionKeyImpl extends AbstractSelectionKey
 
   public int readyOps ()
   {
+    if (!isValid())
+      throw new CancelledKeyException();
+    
     return readyOps;
   }
 
   public SelectionKey readyOps (int ops)
   {
+    if (!isValid())
+      throw new CancelledKeyException();
+    
     readyOps = ops;
     return this;
   }
 
   public int interestOps ()
   {
+    if (!isValid())
+      throw new CancelledKeyException();
+    
     return interestOps;    
   }
 
   public SelectionKey interestOps (int ops)
   {
+    if (!isValid())
+      throw new CancelledKeyException();
+    
     interestOps = ops;
     return this;
   }
index 9f714cc..a906641 100644 (file)
@@ -1,5 +1,5 @@
 /* SelectorImpl.java -- 
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003  Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -37,6 +37,7 @@ exception statement from your version. */
 
 package gnu.java.nio;
 
+import java.io.IOException;
 import java.nio.channels.ClosedSelectorException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
@@ -44,14 +45,15 @@ import java.nio.channels.Selector;
 import java.nio.channels.spi.AbstractSelectableChannel;
 import java.nio.channels.spi.AbstractSelector;
 import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 
 public class SelectorImpl extends AbstractSelector
 {
-  boolean closed = false;
-  Set keys, selected, canceled;
+  private Set keys;
+  private Set selected;
 
   public SelectorImpl (SelectorProvider provider)
   {
@@ -59,12 +61,23 @@ public class SelectorImpl extends AbstractSelector
     
     keys = new HashSet ();
     selected = new HashSet ();
-    canceled = new HashSet ();
   }
 
-  public Set keys ()
+  protected void finalize() throws Throwable
   {
-    return keys;
+    close();
+  }
+
+  protected final void implCloseSelector()
+    throws IOException
+  {
+    // FIXME: We surely need to do more here.
+    wakeup();
+  }
+
+  public final Set keys()
+  {
+    return Collections.unmodifiableSet (keys);
   }
     
   public int selectNow ()
@@ -120,10 +133,8 @@ public class SelectorImpl extends AbstractSelector
 
   public int select (long timeout)
   {
-    if (closed)
-      {
-        throw new ClosedSelectorException ();
-      }
+    if (!isOpen())
+      throw new ClosedSelectorException ();
 
     if (keys == null)
            {
@@ -132,7 +143,7 @@ public class SelectorImpl extends AbstractSelector
 
     int ret = 0;
 
-    deregisterCanceledKeys ();
+    deregisterCancelledKeys();
 
     // Set only keys with the needed interest ops into the arrays.
     int[] read = getFDsAsArray (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT);
@@ -202,7 +213,7 @@ public class SelectorImpl extends AbstractSelector
         key.readyOps (key.interestOps () & ops);
       }
 
-    deregisterCanceledKeys ();
+    deregisterCancelledKeys();
     return ret;
   }
     
@@ -226,14 +237,9 @@ public class SelectorImpl extends AbstractSelector
     selected.add (k);
   }
 
-  protected void implCloseSelector ()
-  {
-    closed = true;
-  }
-
-  private void deregisterCanceledKeys ()
+  private void deregisterCancelledKeys ()
   {
-    Iterator it = canceled.iterator ();
+    Iterator it = cancelledKeys().iterator();
 
     while (it.hasNext ())
       {
index b721c6d..a114b06 100644 (file)
@@ -1,5 +1,5 @@
 /* SocketChannelImpl.java -- 
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,32 +38,55 @@ exception statement from your version. */
 
 package gnu.java.nio;
 
+import java.io.InputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import gnu.java.net.PlainSocketImpl;
 import java.net.Socket;
 import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
 import java.nio.ByteBuffer;
 import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
 import java.nio.channels.SocketChannel;
+import java.nio.channels.Selector;
+import java.nio.channels.SelectionKey;
 import java.nio.channels.spi.SelectorProvider;
 import gnu.classpath.Configuration;
 
-public class SocketChannelImpl extends SocketChannel
+public final class SocketChannelImpl extends SocketChannel
 {
-  Socket socket;
-  boolean blocking = true;
-  boolean connected = false;
+  private NIOSocket socket;
+  private boolean blocking = true;
+  private boolean connected = false;
+  private boolean connectionPending = false;
 
-  public SocketChannelImpl (SelectorProvider provider)               
+  SocketChannelImpl (SelectorProvider provider)
+    throws IOException
   {
     super (provider);
-    socket = new Socket ();
+    socket = new NIOSocket (new PlainSocketImpl(), this);
+  }
+  
+  SocketChannelImpl (SelectorProvider provider,
+                     NIOSocket socket)
+    throws IOException
+  {
+    super (provider);
+    this.socket = socket;
+    this.connected = socket.isConnected();
   }
 
   public void finalizer()
   {
-    if (connected)
+    if (isConnected())
       {
         try
           {
@@ -83,21 +106,82 @@ public class SocketChannelImpl extends SocketChannel
 
   protected void implConfigureBlocking (boolean blocking) throws IOException
   {
-    this.blocking = blocking; // FIXME
+    socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+    this.blocking = blocking;
   }   
 
   public boolean connect (SocketAddress remote) throws IOException
   {
-    if (connected)
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
+    if (isConnected())
       throw new AlreadyConnectedException();
-       
-    socket.connect (remote, 50);
-    connected = true;
-    return blocking; // FIXME
+
+    if (connectionPending)
+      throw new ConnectionPendingException();
+
+    if (!(remote instanceof InetSocketAddress))
+      throw new UnsupportedAddressTypeException();
+
+    if (((InetSocketAddress) remote).isUnresolved())
+      throw new UnresolvedAddressException();
+    
+    if (blocking)
+      {
+        // Do blocking connect.
+        socket.connect (remote);
+        connected = true;
+        return true;
+      }
+
+    // Do non-blocking connect.
+    try
+      {
+        socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
+        connected = true;
+        return true;
+      }
+    catch (SocketTimeoutException e)
+      {
+        connectionPending = true;
+        return false;
+      }
   }
     
   public boolean finishConnect ()
+    throws IOException
   {
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
+    if (!connectionPending)
+      throw new NoConnectionPendingException();
+    
+    if (isConnected())
+      return true;
+
+    // FIXME: Handle blocking/non-blocking mode.
+
+    Selector selector = provider().openSelector();
+    register (selector, SelectionKey.OP_CONNECT);
+
+    if (isBlocking())
+      {
+        selector.select(); // blocking until channel is connected.
+        connected = true;
+        connectionPending = false;
+        return true;
+      }
+
+    int ready = selector.selectNow(); // non-blocking
+    if (ready == 1)
+      {
+        connected = true;
+        connectionPending = false;
+        return true;
+      }
+
     return false;
   }
 
@@ -108,7 +192,7 @@ public class SocketChannelImpl extends SocketChannel
     
   public boolean isConnectionPending ()
   {
-    return blocking ? true : false;
+    return connectionPending;
   }
     
   public Socket socket ()
@@ -118,67 +202,120 @@ public class SocketChannelImpl extends SocketChannel
 
   public int read (ByteBuffer dst) throws IOException
   {
+    if (!connected)
+      throw new NotYetConnectedException();
+    
     byte[] data;
-    int bytes = 0;
-    int len = dst.remaining ();
+    int offset = 0;
+    int len = dst.remaining();
        
-    if (!dst.hasArray ())
+    if (dst.hasArray())
       {
-        data = new byte [len];
-        dst.get (data, 0, len);
+        offset = dst.arrayOffset() + dst.position();
+        data = dst.array();
       }
     else
       {
-        data = dst.array ();
+        data = new byte [len];
       }
+
+    InputStream input = socket.getInputStream();
+    int available = input.available();
+
+    if (available == 0)
+      return 0;
     
-    return socket.getInputStream().read (data, 0, len);
+    if (len > available)
+      len = available;
+
+    int readBytes = 0;
+    boolean completed = false;
+
+    try
+      {
+        begin();
+        readBytes = input.read (data, offset, len);
+        completed = true;
+      }
+    finally
+      {
+        end (completed);
+      }
+
+    if (readBytes > 0
+        && !dst.hasArray())
+      {
+        dst.put (data);
+      }
+
+    return readBytes;
   }
     
   public long read (ByteBuffer[] dsts, int offset, int length)
     throws IOException
   {
-    long bytes = 0;
+    if (!connected)
+      throw new NotYetConnectedException();
+    
+    if ((offset < 0)
+        || (offset > dsts.length)
+        || (length < 0)
+        || (length > (dsts.length - offset)))
+      throw new IndexOutOfBoundsException();
+      
+    long readBytes = 0;
 
-    for (int i = offset; i < length; i++)
-      {
-        bytes += read (dsts [i]);
-      }
+    for (int index = offset; index < length; index++)
+      readBytes += read (dsts [index]);
 
-    return bytes;
+    return readBytes;
   }
      
   public int write (ByteBuffer src)
     throws IOException
   {
+    if (!connected)
+      throw new NotYetConnectedException();
+    
     byte[] data;
-    int bytes = 0;
-    int len = src.remaining ();
+    int offset = 0;
+    int len = src.remaining();
     
-    if (!src.hasArray ())
+    if (!src.hasArray())
       {
         data = new byte [len];
         src.get (data, 0, len);
       }
     else
       {
-        data = src.array ();
+        offset = src.arrayOffset() + src.position();
+        data = src.array();
       }
-   
-    socket.getOutputStream().write (data, 0, len);
+
+    System.out.println ("INTERNAL: writing to socket outputstream");
+    
+    OutputStream output = socket.getOutputStream();
+    output.write (data, offset, len);
     return len;
   }
 
   public long write (ByteBuffer[] srcs, int offset, int length)
     throws IOException
   {
-    long bytes = 0;
+    if (!connected)
+      throw new NotYetConnectedException();
+    
+    if ((offset < 0)
+        || (offset > srcs.length)
+        || (length < 0)
+        || (length > (srcs.length - offset)))
+      throw new IndexOutOfBoundsException();
+      
+    long writtenBytes = 0;
 
-    for (int i = offset; i < length; i++)
-      {
-        bytes += write (srcs [i]);
-      }
+    for (int index = offset; index < length; index++)
+      writtenBytes += write (srcs [index]);
 
-    return bytes;
+    return writtenBytes;
   }
 }