Source for gnu.java.nio.SocketChannelImpl

   1: /* SocketChannelImpl.java -- 
   2:    Copyright (C) 2002, 2003, 2004, 2006, 2007 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.nio;
  40: 
  41: import gnu.java.net.PlainSocketImpl;
  42: 
  43: import java.io.IOException;
  44: import java.io.InputStream;
  45: import java.io.OutputStream;
  46: import java.net.InetSocketAddress;
  47: import java.net.Socket;
  48: import java.net.SocketAddress;
  49: import java.net.SocketTimeoutException;
  50: import java.nio.ByteBuffer;
  51: import java.nio.channels.AlreadyConnectedException;
  52: import java.nio.channels.ClosedChannelException;
  53: import java.nio.channels.ConnectionPendingException;
  54: import java.nio.channels.NoConnectionPendingException;
  55: import java.nio.channels.NotYetConnectedException;
  56: import java.nio.channels.SelectionKey;
  57: import java.nio.channels.Selector;
  58: import java.nio.channels.SocketChannel;
  59: import java.nio.channels.UnresolvedAddressException;
  60: import java.nio.channels.UnsupportedAddressTypeException;
  61: import java.nio.channels.spi.SelectorProvider;
  62: 
  63: public final class SocketChannelImpl extends SocketChannel
  64: {
  65:   private PlainSocketImpl impl;
  66:   private NIOSocket socket;
  67:   private boolean connectionPending;
  68: 
  69:   SocketChannelImpl (SelectorProvider provider)
  70:     throws IOException
  71:   {
  72:     super (provider);
  73:     impl = new PlainSocketImpl();
  74:     impl.create(true);
  75:     socket = new NIOSocket (impl, this);
  76:     configureBlocking(true);
  77:   }
  78:   
  79:   SocketChannelImpl (SelectorProvider provider,
  80:                      NIOSocket socket)
  81:     throws IOException
  82:   {
  83:     super (provider);
  84:     this.impl = socket.getPlainSocketImpl();
  85:     this.socket = socket;
  86:   }
  87: 
  88:   public void finalizer()
  89:   {
  90:     if (isConnected())
  91:       {
  92:         try
  93:           {
  94:             close ();
  95:           }
  96:         catch (Exception e)
  97:           {
  98:           }
  99:       }
 100:   }
 101: 
 102:   PlainSocketImpl getPlainSocketImpl()
 103:   {
 104:     return impl;
 105:   }
 106: 
 107:   int getNativeFD()
 108:   {
 109:     return socket.getPlainSocketImpl().getNativeFD();
 110:   }
 111: 
 112:   protected void implCloseSelectableChannel () throws IOException
 113:   {
 114:     socket.close();
 115:   }
 116: 
 117:   protected void implConfigureBlocking (boolean blocking) throws IOException
 118:   {
 119:     socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
 120:   }   
 121: 
 122:   public boolean connect (SocketAddress remote) throws IOException
 123:   {
 124:     if (!isOpen())
 125:       throw new ClosedChannelException();
 126:     
 127:     if (isConnected())
 128:       throw new AlreadyConnectedException();
 129: 
 130:     if (connectionPending)
 131:       throw new ConnectionPendingException();
 132: 
 133:     if (!(remote instanceof InetSocketAddress))
 134:       throw new UnsupportedAddressTypeException();
 135: 
 136:     if (((InetSocketAddress) remote).isUnresolved())
 137:       throw new UnresolvedAddressException();
 138:     
 139:     try
 140:       {
 141:         socket.getPlainSocketImpl().setInChannelOperation(true);
 142:           // indicate that a channel is initiating the accept operation
 143:           // so that the socket ignores the fact that we might be in
 144:           // non-blocking mode.
 145:         
 146:         if (isBlocking())
 147:           {
 148:             // Do blocking connect.
 149:             socket.connect (remote);
 150:             return true;
 151:           }
 152: 
 153:         // Do non-blocking connect.
 154:         try
 155:           {
 156:             socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
 157:             return true;
 158:           }
 159:         catch (SocketTimeoutException e)
 160:           {
 161:             connectionPending = true;
 162:             return false;
 163:           }
 164:       }
 165:     finally
 166:       {
 167:         socket.getPlainSocketImpl().setInChannelOperation(false);
 168:       }
 169:   }
 170:     
 171:   public boolean finishConnect ()
 172:     throws IOException
 173:   {
 174:     if (!isOpen())
 175:       throw new ClosedChannelException();
 176:     
 177:     if (!isConnected() && !connectionPending)
 178:       throw new NoConnectionPendingException();
 179:     
 180:     if (isConnected())
 181:       return true;
 182: 
 183:     // FIXME: Handle blocking/non-blocking mode.
 184: 
 185:     Selector selector = provider().openSelector();
 186:     register(selector, SelectionKey.OP_CONNECT);
 187: 
 188:     if (isBlocking())
 189:       {
 190:         selector.select(); // blocking until channel is connected.
 191:         connectionPending = false;
 192:         return true;
 193:       }
 194: 
 195:     int ready = selector.selectNow(); // non-blocking
 196:     if (ready == 1)
 197:       {
 198:         connectionPending = false;
 199:         return true;
 200:       }
 201: 
 202:     return false;
 203:   }
 204: 
 205:   public boolean isConnected ()
 206:   {
 207:     return socket.isConnected();
 208:   }
 209:     
 210:   public boolean isConnectionPending ()
 211:   {
 212:     return connectionPending;
 213:   }
 214:     
 215:   public Socket socket ()
 216:   {
 217:     return socket;
 218:   }
 219: 
 220:   public int read(ByteBuffer dst) throws IOException
 221:   {
 222:     if (!isConnected())
 223:       throw new NotYetConnectedException();
 224:     
 225:     byte[] data;
 226:     int offset = 0;
 227:     InputStream input = socket.getInputStream();
 228:     int available = input.available();
 229:     int len = dst.remaining();
 230:     
 231:     if ((! isBlocking()) && available == 0)
 232:       return 0;
 233:     
 234:     if (dst.hasArray())
 235:       {
 236:         offset = dst.arrayOffset() + dst.position();
 237:         data = dst.array();
 238:       }
 239:     else
 240:       {
 241:         data = new byte [len];
 242:       }
 243: 
 244:     int readBytes = 0;
 245:     boolean completed = false;
 246: 
 247:     try
 248:       {
 249:         begin();
 250:         socket.getPlainSocketImpl().setInChannelOperation(true);
 251:         readBytes = input.read (data, offset, len);
 252:         completed = true;
 253:       }
 254:     finally
 255:       {
 256:         end (completed);
 257:         socket.getPlainSocketImpl().setInChannelOperation(false);
 258:       }
 259: 
 260:     if (readBytes > 0)
 261:       if (dst.hasArray())
 262:     {
 263:       dst.position (dst.position() + readBytes);
 264:     }
 265:       else
 266:         {
 267:           dst.put (data, offset, readBytes);
 268:         }
 269: 
 270:     return readBytes;
 271:   }
 272:     
 273:   public long read (ByteBuffer[] dsts, int offset, int length)
 274:     throws IOException
 275:   {
 276:     if (!isConnected())
 277:       throw new NotYetConnectedException();
 278:     
 279:     if ((offset < 0)
 280:         || (offset > dsts.length)
 281:         || (length < 0)
 282:         || (length > (dsts.length - offset)))
 283:       throw new IndexOutOfBoundsException();
 284:       
 285:     long readBytes = 0;
 286: 
 287:     for (int index = offset; index < length; index++)
 288:       readBytes += read (dsts [index]);
 289: 
 290:     return readBytes;
 291:   }
 292:      
 293:   public int write (ByteBuffer src)
 294:     throws IOException
 295:   {
 296:     if (!isConnected())
 297:       throw new NotYetConnectedException();
 298:     
 299:     byte[] data;
 300:     int offset = 0;
 301:     int len = src.remaining();
 302:     
 303:     if (!src.hasArray())
 304:       {
 305:         data = new byte [len];
 306:         src.get (data, 0, len);
 307:       }
 308:     else
 309:       {
 310:         offset = src.arrayOffset() + src.position();
 311:         data = src.array();
 312:       }
 313: 
 314:     OutputStream output = socket.getOutputStream();
 315:     boolean completed = false;
 316: 
 317:     try
 318:       {
 319:         begin();
 320:         socket.getPlainSocketImpl().setInChannelOperation(true);
 321:         output.write (data, offset, len);
 322:         completed = true;
 323:       }
 324:     finally
 325:       {
 326:         end (completed);
 327:         socket.getPlainSocketImpl().setInChannelOperation(false);
 328:       }
 329: 
 330:     if (src.hasArray())
 331:       {
 332:     src.position (src.position() + len);
 333:       }
 334:     
 335:     return len;
 336:   }
 337: 
 338:   public long write (ByteBuffer[] srcs, int offset, int length)
 339:     throws IOException
 340:   {
 341:     if (!isConnected())
 342:       throw new NotYetConnectedException();
 343:     
 344:     if ((offset < 0)
 345:         || (offset > srcs.length)
 346:         || (length < 0)
 347:         || (length > (srcs.length - offset)))
 348:       throw new IndexOutOfBoundsException();
 349:       
 350:     long writtenBytes = 0;
 351: 
 352:     for (int index = offset; index < length; index++)
 353:       writtenBytes += write (srcs [index]);
 354: 
 355:     return writtenBytes;
 356:   }
 357: }