/* This file is part of leafdigital leafChat. leafChat 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. leafChat 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 leafChat. If not, see <http://www.gnu.org/licenses/>. Copyright 2011 Samuel Marshall. */ package com.leafdigital.net; import java.io.*; import java.net.*; import com.leafdigital.net.api.Network.Port; import leafchat.core.api.PluginContext; /** SOCKS5 implementation of listening port */ public class SOCKS5Port extends SOCKS5Base implements Port { private InetAddress publicAddress; private int publicPort; private InetAddress connectedAddress; /** * @param remoteHost Remote address that can connect * @param context Plugin context * @throws IOException Error creating port */ public SOCKS5Port(String remoteHost,PluginContext context) throws IOException { super(context); boolean ok=false; try { output.write(5); // Version 5 output.write(2); // 'Bind' output.write(0); // Reserved writeAddress(remoteHost,0); // Hopefully we can send port 0 at least! output.flush(); input.read(); // Version number, ignored int reply=input.read(); if(reply!=0) throw new SOCKS5Exception(reply); input.read(); // Reserved byte, ignored InetSocketAddress result=readAddress(); // Bind address publicAddress=result.getAddress(); publicPort=result.getPort(); // And we should be good to go! setSoTimeout(0); ok=true; } catch(SocketTimeoutException e) { throw new SOCKS5Exception("Timeout when communicating with proxy. Check proxy address and port are correct.",e); } catch(IOException e) { if(e instanceof SOCKS5Exception) throw e; throw new SOCKS5Exception("Error communicating with proxy. Check proxy address and port are correct.",e); } finally { if(!ok) close(); } } @Override public Socket accept() throws IOException { return accept(0); } @Override public Socket accept(int timeout) throws IOException { if(connectedAddress!=null) throw new IOException("May not call accept() twice from SOCKS5 port"); setSoTimeout(timeout); try { input.read(); // Version number (ignored) int reply=input.read(); if(reply!=0) throw new SOCKS5Exception(reply); input.read(); // Reserved byte, ignored InetSocketAddress result=readAddress(); // Bind address connectedAddress=result.getAddress(); return this; } catch(SocketTimeoutException e) { throw e; } catch(IOException e) { throw new SOCKS5Exception("Error communicating with proxy, perhaps a listening port timeout",e); } } @Override public void close() throws IOException { // Don't really close the socket! This is just supposed to close the // 'listening' socket, and there isn't one, so it does nothing. } @Override public InetAddress getInetAddress() { return connectedAddress!=null ? connectedAddress : super.getInetAddress(); } @Override public InetAddress getPublicAddress() { return publicAddress; } @Override public int getPublicPort() { return publicPort; } }