/* Copyright (C) 2012 Brian P. Hinz * * This 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 of the License, or * (at your option) any later version. * * This software 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 this software; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package com.tigervnc.network; import java.io.IOException; import java.net.SocketAddress; import java.nio.*; import java.nio.channels.*; import java.nio.channels.spi.SelectorProvider; import java.util.Set; import java.util.Iterator; import com.tigervnc.rdr.Exception; public class SocketDescriptor implements FileDescriptor { public SocketDescriptor() throws Exception { DefaultSelectorProvider(); try { channel = SocketChannel.open(); channel.configureBlocking(false); writeSelector = Selector.open(); readSelector = Selector.open(); } catch (IOException e) { throw new Exception(e.getMessage()); } try { channel.register(writeSelector, SelectionKey.OP_WRITE); channel.register(readSelector, SelectionKey.OP_READ); } catch (java.nio.channels.ClosedChannelException e) { throw new Exception(e.getMessage()); } } public void shutdown() throws IOException { try { channel.socket().shutdownInput(); channel.socket().shutdownOutput(); } catch(IOException e) { throw new IOException(e.getMessage()); } } public void close() throws IOException { try { channel.close(); } catch(IOException e) { throw new IOException(e.getMessage()); } } private static SelectorProvider DefaultSelectorProvider() { // kqueue() selector provider on OS X is not working, fall back to select() for now String os = System.getProperty("os.name"); if (os.startsWith("Mac OS X")) System.setProperty("java.nio.channels.spi.SelectorProvider","sun.nio.ch.PollSelectorProvider"); return SelectorProvider.provider(); } synchronized public int read(byte[] buf, int bufPtr, int length) throws Exception { int n; ByteBuffer b = ByteBuffer.allocate(length); try { n = channel.read(b); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } if (n <= 0) return (n == 0) ? -1 : 0; b.flip(); b.get(buf, bufPtr, n); b.clear(); return n; } synchronized public int write(byte[] buf, int bufPtr, int length) throws Exception { int n; ByteBuffer b = ByteBuffer.allocate(length); b.put(buf, bufPtr, length); b.flip(); try { n = channel.write(b); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } b.clear(); return n; } synchronized public int select(int interestOps, Integer timeout) throws Exception { int n; Selector selector; if ((interestOps & SelectionKey.OP_READ) != 0) { selector = readSelector; } else { selector = writeSelector; } selector.selectedKeys().clear(); try { if (timeout == null) { n = selector.select(); } else { int tv = timeout.intValue(); switch(tv) { case 0: n = selector.selectNow(); break; default: n = selector.select((long)tv); break; } } } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } return n; } public int write(ByteBuffer buf) throws Exception { int n = 0; try { n = channel.write(buf); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } return n; } public long write(ByteBuffer[] buf, int offset, int length) throws IOException { long n = 0; try { n = channel.write(buf, offset, length); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } return n; } public int read(ByteBuffer buf) throws IOException { int n = 0; try { n = channel.read(buf); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } return n; } public long read(ByteBuffer[] buf, int offset, int length) throws IOException { long n = 0; try { n = channel.read(buf, offset, length); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } return n; } public java.net.Socket socket() { return channel.socket(); } public SocketAddress getRemoteAddress() throws IOException { if (isConnected()) return channel.socket().getRemoteSocketAddress(); return null; } public SocketAddress getLocalAddress() throws IOException { if (isConnected()) return channel.socket().getLocalSocketAddress(); return null; } public boolean isConnectionPending() { return channel.isConnectionPending(); } public boolean connect(SocketAddress remote) throws IOException { return channel.connect(remote); } public boolean finishConnect() throws IOException { return channel.finishConnect(); } public boolean isConnected() { return channel.isConnected(); } protected void implConfigureBlocking(boolean block) throws IOException { channel.configureBlocking(block); } protected synchronized void implCloseSelectableChannel() throws IOException { channel.close(); notifyAll(); } protected void setChannel(SocketChannel channel_) { try { if (channel != null) channel.close(); if (readSelector != null) readSelector.close(); if (writeSelector != null) writeSelector.close(); channel = channel_; channel.configureBlocking(false); writeSelector = Selector.open(); readSelector = Selector.open(); } catch (java.io.IOException e) { throw new Exception(e.getMessage()); } try { channel.register(writeSelector, SelectionKey.OP_WRITE); channel.register(readSelector, SelectionKey.OP_READ); } catch (java.nio.channels.ClosedChannelException e) { System.out.println(e.toString()); } } protected SocketChannel channel; protected Selector writeSelector; protected Selector readSelector; }