/* * Copyright (C) 2005 Luca Veltri - University of Parma - Italy * * This source code 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 source code 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 source code; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author(s): * Luca Veltri (luca.veltri@unipr.it) */ package local.net; import org.zoolu.tools.LogLevel; import java.net.*; import java.io.InterruptedIOException; /** UdpRelay implements a direct UDP datagram relay agent. * It receives UDP packets at a local port and relays them toward a remote UDP socket * (destination address/port). */ public class UdpRelay extends Thread { // The maximum IP packet size //public static final int MAX_PKT_SIZE=65536; public static final int MAX_PKT_SIZE=2000; /** Local receiver/sender port */ int local_port; /** Remote source address */ String src_addr; /** Remote source port */ int src_port; /** Destination address */ String dest_addr; /** Destination port */ int dest_port; /** Whether it is running */ boolean stop; /** Maximum time that the UDP relay can remain active after been halted (in milliseconds) */ int socket_to=3000; // 3sec /** Maximum time that the UDP relay remains active without receiving UDP datagrams (in seconds) */ int alive_to=60; // 1min /** UdpRelay listener */ UdpRelayListener listener; /** Creates a new UDP relay and starts it. * <p> The UdpRelay remains active until method halt() is called. */ public UdpRelay(int local_port, String dest_addr, int dest_port, UdpRelayListener listener) { init(local_port,dest_addr,dest_port,0,listener); start(); } /** Creates a new UDP relay and starts it. * <p> The UdpRelay will automatically stop after <i>alive_time</i> seconds * of idle time (i.e. without receiving UDP datagrams) */ public UdpRelay(int local_port, String dest_addr, int dest_port, int alive_time, UdpRelayListener listener) { init(local_port,dest_addr,dest_port,alive_time,listener); start(); } /** Inits a new UDP relay */ private void init(int local_port, String dest_addr, int dest_port, int alive_time, UdpRelayListener listener) { this.local_port=local_port; this.dest_addr=dest_addr; this.dest_port=dest_port; this.alive_to=alive_time; this.listener=listener; src_addr="0.0.0.0"; src_port=0; stop=false; } /** Gets the local receiver/sender port */ public int getLocalPort() { return local_port; } /** Gets the destination address */ /*public String getDestAddress() { return dest_addr; }*/ /** Gets the destination port */ /*public int getDestPort() { return dest_port; }*/ /** Sets a new destination address */ public UdpRelay setDestAddress(String dest_addr) { this.dest_addr=dest_addr; return this; } /** Sets a new destination port */ public UdpRelay setDestPort(int dest_port) { this.dest_port=dest_port; return this; } /** Whether the UDP relay is running */ public boolean isRunning() { return !stop; } /** Stops the UDP relay */ public void halt() { stop=true; } /** Sets the maximum time that the UDP relay can remain active after been halted */ public void setSoTimeout(int so_to) { socket_to=so_to; } /** Gets the maximum time that the UDP relay can remain active after been halted */ public int getSoTimeout() { return socket_to; } /** Redirect packets received from remote source addr/port to destination addr/port */ public void run() { //System.out.println("DEBUG: starting UdpRelay "+toString()+" (it expires after "+alive_to+" sec)"); try { DatagramSocket socket=new DatagramSocket(local_port); byte []buf=new byte[MAX_PKT_SIZE]; socket.setSoTimeout(socket_to); // datagram packet DatagramPacket packet=new DatagramPacket(buf, buf.length); // convert alive_to in milliseconds long keepalive_to=((1000)*(long)alive_to)-socket_to; // end time long expire=System.currentTimeMillis()+keepalive_to; // whether reset the receiver //boolean reset=true; while(!stop) { // non-blocking receiver try { socket.receive(packet); } catch (InterruptedIOException ie) { // if expired, stop relaying if (alive_to>0 && System.currentTimeMillis()>expire) halt(); continue; } // check whether the source address and port are changed if (src_port!=packet.getPort() || !src_addr.equals(packet.getAddress().getHostAddress().toString())) { src_port=packet.getPort(); src_addr=packet.getAddress().getHostAddress(); if (listener!=null) listener.onUdpRelaySourceChanged(this,src_addr,src_port); } // relay packet.setAddress(InetAddress.getByName(dest_addr)); packet.setPort(dest_port); socket.send(packet); // reset packet=new DatagramPacket(buf, buf.length); expire=System.currentTimeMillis()+keepalive_to; } socket.close(); if (listener!=null) listener.onUdpRelayTerminated(this); } catch (Exception e) { e.printStackTrace(); } //System.out.println("DEBUG: closing UdpRelay "+toString())"); } /** Gets a String representation of the Object */ public String toString() { return Integer.toString(local_port)+"-->"+dest_addr+":"+dest_port; } // ********************************** MAIN ********************************* /** The main method. */ public static void main(String[] args) { if (args.length<3) { System.out.println("usage:\n java UdpRelay <local_port> <address> <port> [ <alive_time> ]"); System.exit(0); } int local_port=Integer.parseInt(args[0]); int remote_port=Integer.parseInt(args[2]); String remote_address=args[1]; int alive_time=0; if (args.length>3) alive_time=Integer.parseInt(args[3]); new UdpRelay(local_port,remote_address,remote_port,alive_time,null); } }