From 7113237bf329e1245f096787093aed051ea2dd23 Mon Sep 17 00:00:00 2001 From: mkoch Date: Thu, 25 Sep 2003 10:17:00 +0000 Subject: [PATCH] 2003-09-25 Michael Koch * 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 | 49 ++++++ libjava/Makefile.am | 1 + libjava/Makefile.in | 3 +- libjava/gnu/java/nio/DatagramChannelImpl.java | 140 ++++++++++++++--- libjava/gnu/java/nio/NIOConstants.java | 47 ++++++ libjava/gnu/java/nio/SelectionKeyImpl.java | 23 ++- libjava/gnu/java/nio/SelectorImpl.java | 44 +++--- libjava/gnu/java/nio/SocketChannelImpl.java | 217 +++++++++++++++++++++----- 8 files changed, 439 insertions(+), 85 deletions(-) create mode 100644 libjava/gnu/java/nio/NIOConstants.java diff --git a/libjava/ChangeLog b/libjava/ChangeLog index b8769cb..fdcc1c9 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,5 +1,54 @@ 2003-09-25 Michael Koch + * 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 + * java/net/InetAddress.java: Reorder imports, remove implementation comment. (isMulticastAddress): Merged documentation from classpath. diff --git a/libjava/Makefile.am b/libjava/Makefile.am index c8785e2..889d092 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -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 \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index 3275f3c..87b0657 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -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 \ diff --git a/libjava/gnu/java/nio/DatagramChannelImpl.java b/libjava/gnu/java/nio/DatagramChannelImpl.java index dce7dab..a4f46df 100644 --- a/libjava/gnu/java/nio/DatagramChannelImpl.java +++ b/libjava/gnu/java/nio/DatagramChannelImpl.java @@ -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 index 0000000..8a71202 --- /dev/null +++ b/libjava/gnu/java/nio/NIOConstants.java @@ -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; +} diff --git a/libjava/gnu/java/nio/SelectionKeyImpl.java b/libjava/gnu/java/nio/SelectionKeyImpl.java index 72dc20b..df4faa3 100644 --- a/libjava/gnu/java/nio/SelectionKeyImpl.java +++ b/libjava/gnu/java/nio/SelectionKeyImpl.java @@ -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; } diff --git a/libjava/gnu/java/nio/SelectorImpl.java b/libjava/gnu/java/nio/SelectorImpl.java index 9f714cc..a906641 100644 --- a/libjava/gnu/java/nio/SelectorImpl.java +++ b/libjava/gnu/java/nio/SelectorImpl.java @@ -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 ()) { diff --git a/libjava/gnu/java/nio/SocketChannelImpl.java b/libjava/gnu/java/nio/SocketChannelImpl.java index b721c6d..a114b06 100644 --- a/libjava/gnu/java/nio/SocketChannelImpl.java +++ b/libjava/gnu/java/nio/SocketChannelImpl.java @@ -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; } } -- 2.7.4