Java tutorial
/** * The utillib library. * More information is available at http://www.jinchess.com/. * Copyright (C) 2002 Alexander Maryanovsky. * All rights reserved. * * The utillib library is free software; you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * The utillib library 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with utillib library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.io.*; import java.net.Socket; import java.net.ServerSocket; /** * Implements a TCP/IP bounce utility (proxy). You run bounce specifying which * port to listen on, which host and on which port to connect to and it will * act as a proxy relaying information between anyone who connects to it and the * specified server. */ public class Bounce { /** * The main method. */ public static void main(String[] args) { if (args.length < 3) { printUsage(); System.exit(1); } int localPort; try { localPort = Integer.parseInt(args[0]); } catch (NumberFormatException e) { System.err.println("Bad local port value: " + args[0]); printUsage(); System.exit(2); return; } String hostname = args[1]; int remotePort; try { remotePort = Integer.parseInt(args[2]); } catch (NumberFormatException e) { System.err.println("Bad remote port value: " + args[2]); printUsage(); System.exit(3); return; } boolean shouldLog = args.length > 3 ? Boolean.valueOf(args[3]).booleanValue() : false; int numConnections = 0; try { ServerSocket ssock = new ServerSocket(localPort); while (true) { Socket incomingSock = ssock.accept(); Socket outgoingSock = new Socket(hostname, remotePort); numConnections++; InputStream incomingIn = incomingSock.getInputStream(); InputStream outgoingIn = outgoingSock.getInputStream(); OutputStream incomingOut = incomingSock.getOutputStream(); OutputStream outgoingOut = outgoingSock.getOutputStream(); if (shouldLog) { String incomingLogName = "in-log-" + incomingSock.getInetAddress().getHostName() + "(" + localPort + ")-" + numConnections + ".dat"; String outgoingLogName = "out-log-" + hostname + "(" + remotePort + ")-" + numConnections + ".dat"; OutputStream incomingLog = new FileOutputStream(incomingLogName); incomingOut = new MultiOutputStream(incomingOut, incomingLog); OutputStream outgoingLog = new FileOutputStream(outgoingLogName); outgoingOut = new MultiOutputStream(outgoingOut, outgoingLog); } PumpThread t1 = new PumpThread(incomingIn, outgoingOut); PumpThread t2 = new PumpThread(outgoingIn, incomingOut); t1.start(); t2.start(); } } catch (IOException e) { e.printStackTrace(); System.exit(3); } } /** * Dumps usage information to the standard error stream. */ private static void printUsage() { System.err.println("Bounce Utility"); System.err.println("Copyright (C) 2002 Alexander Maryanovsky"); System.err.println(); System.err.println("Usage: java free.util.Bounce localPort hostname remotePort [shouldLog]"); System.out.println(); System.out.println("Version 1.01 - 31 Nov. 2002"); } } /** * The utillib library. * More information is available at http://www.jinchess.com/. * Copyright (C) 2002 Alexander Maryanovsky. * All rights reserved. * * The utillib library is free software; you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * The utillib library 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with utillib library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * An <code>OutputStream</code> which relays all data written into it into a * list of given <code>OutputStreams</code>. */ class MultiOutputStream extends OutputStream { /** * An array containing the OutputStreams we're relaying data to. */ private final OutputStream[] streams; /** * Creates a new <code>MultiOutputStream</code> which relays data to the * specified two <code>OutputStreams</code>. Any <code>null</code> values * will be silently ignored. */ public MultiOutputStream(OutputStream out1, OutputStream out2) { this(new OutputStream[] { out1, out2 }); } /** * Creates a new <code>MultiOutputStream</code> which relays data to the * specified <code>OutputStreams</code>. Any <code>null</code> items in the * array will be silently ignored. */ public MultiOutputStream(OutputStream[] streams) { if (streams == null) throw new IllegalArgumentException("Specified array may not be null"); int count = 0; for (int i = 0; i < streams.length; i++) if (streams[i] != null) count++; this.streams = new OutputStream[count]; count = 0; for (int i = 0; i < streams.length; i++) { OutputStream stream = streams[i]; if (stream != null) this.streams[count++] = stream; } } /** * Closes all the underlying <code>OutputStreams</code>. */ public void close() throws IOException { for (int i = 0; i < streams.length; i++) streams[i].close(); } /** * Flushes all the underlying <code>OutputStreams</code>. */ public void flush() throws IOException { for (int i = 0; i < streams.length; i++) streams[i].flush(); } /** * Writes the specified <code>byte</code> into the underlying * <code>OutputStreams</code>. */ public void write(int b) throws IOException { for (int i = 0; i < streams.length; i++) streams[i].write(b); } /** * Writes the specified amount of bytes from the given byte array starting * at the specified offset to the underlying <code>OutputStreams</code>. */ public void write(byte[] arr, int offset, int length) throws IOException { for (int i = 0; i < streams.length; i++) streams[i].write(arr, offset, length); } } /** * The utillib library. * More information is available at http://www.jinchess.com/. * Copyright (C) 2002 Alexander Maryanovsky. * All rights reserved. * * The utillib library is free software; you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * The utillib library 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with utillib library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * A thread which pumps information read from a given input stream into the * given output stream. */ class PumpThread extends Thread { /** * The InputStream. */ private final InputStream in; /** * The OutputStream. */ private final OutputStream out; /** * The buffer we're using. */ private final byte[] buffer; /** * The IOException thrown while reading or writing information, or null if * none. */ private IOException exception; /** * Creates a new PumpThread which will pump information from the given * InputStream into the given OutputStream. */ public PumpThread(InputStream in, OutputStream out) { this(in, out, 2048); } /** * Creates a new PumpThread which will pump information from the given * InputStream into the given OutputStream and will use a buffer of the given * size. */ public PumpThread(InputStream in, OutputStream out, int bufSize) { this(in, out, new byte[bufSize]); } /** * Creates a new PumpThread which will pump information from the given * InputStream into the given OutputStream and will use the given buffer. */ public PumpThread(InputStream in, OutputStream out, byte[] buffer) { this.in = in; this.out = out; this.buffer = buffer; } /** * Does the actual pumping. */ public void run() { try { while (true) { int count = in.read(buffer); if (count <= 0) return; out.write(buffer, 0, count); } } catch (IOException e) { exception = e; } } /** * Returns the exception thrown while reading or writing, or <code>null</code> * if it finished normally, without throwing an exception (read returned -1). * * @throws IllegalStateException if the thread is still alive. */ public IOException getException() { if (isAlive()) throw new IllegalStateException("The thread is still alive"); return exception; } }