/* * Copyright (C) 2014 Per Lundqvist * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ package com.github.perlundq.yajsync.net; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.security.Principal; import java.util.Optional; import com.github.perlundq.yajsync.internal.util.Environment; public class StandardSocketChannel implements DuplexByteChannel { private final InputStream _is; private final SocketChannel _socketChannel; private final int _timeout; public StandardSocketChannel(SocketChannel socketChannel, int timeout) throws IOException { if (timeout > 0) { assert Environment.hasAllocateDirectArray() || !Environment.isAllocateDirect(); } _socketChannel = socketChannel; _timeout = timeout; _socketChannel.socket().setSoTimeout(timeout); _is = _socketChannel.socket().getInputStream(); } public static StandardSocketChannel open(String address, int port, int contimeout, int timeout) throws IOException { InetSocketAddress socketAddress = new InetSocketAddress(address, port); SocketChannel socketChannel = SocketChannel.open(); socketChannel.socket().connect(socketAddress, contimeout); return new StandardSocketChannel(socketChannel, timeout); } @Override public String toString() { return _socketChannel.toString(); } @Override public boolean isOpen() { return _socketChannel.isOpen(); } @Override public void close() throws IOException { _socketChannel.close(); } @Override public int read(ByteBuffer dst) throws IOException { if (_timeout == 0) { return _socketChannel.read(dst); } byte[] buf = dst.array(); int offset = dst.arrayOffset() + dst.position(); int len = dst.remaining(); int n = _is.read(buf, offset, len); if (n != -1) { dst.position(dst.position() + n); } return n; } @Override public int write(ByteBuffer src) throws IOException { return _socketChannel.write(src); } @Override public InetAddress peerAddress() { try { InetSocketAddress socketAddress = (InetSocketAddress) _socketChannel.getRemoteAddress(); if (socketAddress == null) { throw new IllegalStateException(String.format( "unable to determine remote address of %s - not connected", _socketChannel)); } InetAddress addrOrNull = socketAddress.getAddress(); if (addrOrNull == null) { throw new IllegalStateException(String.format( "unable to determine address of %s - unresolved", socketAddress)); } return addrOrNull; } catch (IOException e) { throw new IllegalStateException(e); } } @Override public Optional<Principal> peerPrincipal() { return Optional.empty(); } }