/*
 * 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.net.*;
import java.io.InterruptedIOException;
import java.util.Vector;


/** UdpMultiRelay implements an UDP multiple relay agent. 
  * It receives UDP packets at a local port and relays them
  * toward a list of remote UDP sockets (a list of address/port pairs).
  */
public class UdpMultiRelay extends Thread
{
   /** Source port */
   int local_port;  
   /** Destination sockets */
   Vector dest_sockets;  
   /** Destination socket of remote host to which the packets must not be relayed */
   SocketAddress no_relay_dest_socket;  

   /** Whether it is running */
   boolean stop;
   /** Maximum time that the UDP relay can remain active after been halted */
   int socket_to=3000; // 3sec 

  
   /** Creates a new UDP relay and starts it */
   public UdpMultiRelay(int local_port, Vector dest_sockets, SocketAddress no_dest_socket)
   {  init(local_port,dest_sockets,no_dest_socket);
      start();
   }
    
   /** Creates a new UDP relay and starts it */
   public UdpMultiRelay(int local_port, Vector dest_sockets)
   {  init(local_port,dest_sockets,null);
      start();
   }

   /** Inits a new UDP relay and starts it */
   private void init(int local_port, Vector dest_sockets, SocketAddress no_dest_socket)
   {  this.local_port=local_port;     
      this.dest_sockets=dest_sockets;
      this.no_relay_dest_socket=no_dest_socket;
      stop=false;
   }

   /** Gets the local port */
   public int getLocalPort()
   {  return local_port;
   }

   /** Gets the destination sockets */
   public Vector getDestSockets()
   {  return dest_sockets;
   }

   /** Gets the destination socket to which the packets must not be relayed */
   public SocketAddress getNoRelayDestSocket()
   {  return no_relay_dest_socket;
   }

   /** 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 from source addr/port to destination addr/port  */
   public void run()
   {  try	
      {  UdpSocket socket=new UdpSocket(local_port);
         byte []buf = new byte[2000];
         
         socket.setSoTimeout(socket_to);
         while(!stop)
         {  UdpPacket packet = new UdpPacket(buf, buf.length);          
            
            // non-blocking receiver
            try
            {  socket.receive(packet);           
            }
            catch (InterruptedIOException ie) { continue; }
            
            for (int i=0; i<dest_sockets.size(); i++)
            {  try
               {  SocketAddress dest=(SocketAddress)dest_sockets.elementAt(i);
                  if (no_relay_dest_socket==null || !dest.equals(no_relay_dest_socket))
                  {  packet.setIpAddress(dest.getAddress());
                     packet.setPort(dest.getPort());
                     socket.send(packet);
                     //System.out.print("*");
                  }
                  //else System.out.print(".");
               }
               catch (ArrayIndexOutOfBoundsException e) { }
            }
         }
         socket.close();
      }
      catch (Exception e) { e.printStackTrace(); } 
   }  
   
}
 