/* * SSL/TLS implementation of ReadableByteChannel and WritableByteChannel * * 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.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.security.Principal; import java.util.Optional; import javax.net.SocketFactory; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import com.github.perlundq.yajsync.internal.util.Environment; public class SSLChannel implements DuplexByteChannel { private final InputStream _is; private final OutputStream _os; private final SSLSocket _sslSocket; public SSLChannel(SSLSocket sslSocket, int timeout) throws IOException { assert Environment.hasAllocateDirectArray() || !Environment.isAllocateDirect(); _sslSocket = sslSocket; _sslSocket.setSoTimeout(timeout); _is = _sslSocket.getInputStream(); _os = _sslSocket.getOutputStream(); } public static SSLChannel open(String address, int port, int contimeout, int timeout) throws IOException { SocketFactory factory = SSLSocketFactory.getDefault(); InetSocketAddress socketAddress = new InetSocketAddress(address, port); Socket sock = factory.createSocket(); sock.connect(socketAddress, contimeout); return new SSLChannel((SSLSocket) sock, timeout); } @Override public String toString() { return _sslSocket.toString(); } @Override public void close() throws IOException { _sslSocket.close(); // will implicitly close _is and _os also } @Override public boolean isOpen() { return !_sslSocket.isClosed(); } @Override public int write(ByteBuffer src) throws IOException { byte[] buf = src.array(); int offset = src.arrayOffset() + src.position(); int len = src.remaining(); _os.write(buf, offset, len); src.position(src.position() + len); return len; } @Override public int read(ByteBuffer dst) throws IOException { 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 InetAddress peerAddress() { InetAddress address = _sslSocket.getInetAddress(); if (address == null) { throw new IllegalStateException(String.format( "unable to determine remote address of %s - not connected", _sslSocket)); } return address; } @Override public Optional<Principal> peerPrincipal() { try { return Optional.of(_sslSocket.getSession().getPeerPrincipal()); } catch (SSLPeerUnverifiedException e) { return Optional.empty(); } } }