Mega Code Archive

 
Categories / Java / Network Protocol
 

Reflector

import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.UnknownHostException; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; public class Reflector implements Runnable {   // valid names found in the config file:   public static final String MODE = "Mode";   public static final String SOURCE_IP = "SourceIP";   public static final String SOURCE_PORT = "SourcePort";   public static final String DEST_IP = "DestIP";   public static final String DEST_PORT = "DestPort";   // valid modes in the config file, unicast to   // multicast or multicast to unicast   public static final String INPUT_UNITOMULTI = "UNI_TO_MULTI";   public static final String INPUT_MULTITOUNI = "MULTI_TO_UNI";   // possible modes the reflector can be set to:   public static final int MODE_NONE = 0;   public static final int MODE_UNI_TO_MULTI = 1;   public static final int MODE_MULTI_TO_UNI = 2;   // variables to indicate source or destination   public static final int SOURCE = 1;   public static final int DEST = 2;   // min and max network ports allowed   public static final int MIN_PORT = 1024;   public static final int MAX_PORT = 65095;   // which mode the reflector is being run in:   private int mode = 0;   // source and destination hold variables:   private Address source;   private Hashtable dest;   private Address hold_dest = null;   // logging toggle and logger class   boolean logging = true;   Logger logger;   public Reflector() {   }   public void run() {     // validate the config file     if (readConfig() != 0) {       System.err.println("Error parsing config file\n");       System.exit(-1);     }     // start the logger     logger = new Logger(logging);     // spawn a thread to listen for packets     ReflectorListener listener = new ReflectorListener(source, mode, logger);     System.out.println("Listening on " + source.toString());     // spawn threads for each source address packets     // are to be forwarded on. Register each thread as     // PacketListenerInterface with the listener thread.     System.out.println("Sending on:");     for (Enumeration e = dest.elements(); e.hasMoreElements();) {       Address a = (Address) e.nextElement();       ReflectorSender sender = new ReflectorSender(a, mode, logger);       sender.start();       listener.addPacketListener((PacketListenerInterface) sender);       System.out.println("           " + a.toString());     }     // start the listener     listener.start();   }   public int readConfig() {     // validate the contents of the config file     BufferedReader input = null;     String name, value, inputLine = null;     dest = new Hashtable();     // open and read the config file     try {       input = new BufferedReader(new FileReader("reflector.conf"));       inputLine = input.readLine();     } catch (IOException e) {       System.err.println("Error reading reflector.conf.");       return (-1);     }     // loop until entire config file is read     while (inputLine != null) {       // skip comments:       if (inputLine.charAt(0) != '#') {         // extract a name/value pair, and branch         // based on the name:         StringTokenizer tokenizer = new StringTokenizer(inputLine, "=");         name = tokenizer.nextToken();         value = tokenizer.nextToken();         if (name == null) {           System.out.println("no name");           continue;         } else if (name.equals(MODE)) {           if (setMode(value) != 0) {             System.err.println("Error setting mode to " + value);             return (-1);           }         } else if (name.equals(SOURCE_IP)) {           if (setSourceIP(value) != 0) {             System.err.println("Error setting src IP address to "                 + value);             return (-1);           }         } else if (name.equals(SOURCE_PORT)) {           if (setSourcePort(value) != 0) {             System.err                 .println("Error setting src port to " + value);             return (-1);           }         } else if (name.equals(DEST_IP)) {           if (setDestIP(value) != 0) {             System.err.println("Error setting dest IP address to "                 + value);             return (-1);           }         } else if (name.equals(DEST_PORT)) {           if (setDestPort(value) != 0) {             System.err.println("Error setting dest port to "                 + value);             return (-1);           }         } else {           System.err.println("Skipping invalid config file value: "               + name);         }       }       // read next line in the config file       try {         inputLine = input.readLine();       } catch (IOException e) {         System.err.println("Error reading reflector.conf.");         return (-1);       }     }     // close the config file     try {       input.close();     } catch (IOException e) {       System.err.println("Error closing reflector.conf.");       return (-1);     }     // validate that the combined contents of the config file     // make sense     if (!isConfigValid()) {       System.err.println("Configuration file is not complete.");       return (-1);     }     return (0);   }   private int setMode(String value) {     // validate and set the mode from the config file     if (value.equals(INPUT_UNITOMULTI)) {       mode = MODE_UNI_TO_MULTI;       return (0);     } else if (value.equals(INPUT_MULTITOUNI)) {       mode = MODE_MULTI_TO_UNI;       return (0);     } else {       return (-1);     }   }   private int setSourceIP(String value) {     // validate and set the source IP from the config file     // call modeToAddress to validate IP address     InetAddress inet = modeToAddress(value, SOURCE);     if (inet == null)       return -1;     if (source != null) {       if (source.getAddress() != null)         System.err.println("Warning: overwriting src address "             + source.getAddress().getHostAddress() + " with "             + inet.getHostAddress() + ".");       source.setAddress(inet);     } else {       source = new Address(inet);     }     return (0);   }   private int setSourcePort(String value) {     // validate and set the source port from the config file     int port;     try {       port = Integer.parseInt(value);     } catch (NumberFormatException nfe) {       return (-1);     }     if ((port < MIN_PORT) || (port > 65095))       return (-1);     if (source != null) {       if (source.getPort() != 0)         System.err.println("Warning: overwriting src port "             + source.getPort() + " with port " + port + ".");       source.setPort(port);     } else {       source = new Address(port);     }     return (0);   }   private int setDestIP(String value) {     // validate and set the dest IP from the config file     // call modeToAddress to validate IP address     InetAddress inet = modeToAddress(value, DEST);     if (inet == null)       return -1;     if (hold_dest != null) {       if (hold_dest.getAddress() != null)         System.err.println("Warning: overwriting dest address "             + hold_dest.getAddress().getHostAddress() + " with "             + inet.getHostAddress() + ".");       hold_dest.setAddress(inet);       if (hold_dest.isComplete())         return (addDest());     } else {       hold_dest = new Address(inet);     }     return (0);   }   private int setDestPort(String value) {     // validate and set the dest port from the config file     int port;     try {       port = Integer.parseInt(value);     } catch (NumberFormatException nfe) {       return (-1);     }     if ((port < MIN_PORT) || (port > MAX_PORT))       return (-1);     if (hold_dest != null) {       if (hold_dest.getPort() != 0)         System.err.println("Warning: overwriting dest port "             + hold_dest.getPort() + " with port " + port + ".");       hold_dest.setPort(port);       if (hold_dest.isComplete())         return (addDest());     } else {       hold_dest = new Address(port);     }     return (0);   }   private int addDest() {     // once both a dest IP and port have been read, add them     // to our vector of all destinations.     switch (mode) {     case MODE_UNI_TO_MULTI:       if (!dest.isEmpty()) {         System.err.println("Warning: dest address overwritten");         dest.clear();       }       dest.put(hold_dest.toString(), hold_dest);       break;     case MODE_MULTI_TO_UNI:       dest.put(hold_dest.toString(), hold_dest);       break;     default:       // no mode set       System.err.println("Destination " + hold_dest.toString()           + " skipped because no mode set.");       hold_dest = null;       return (-1);     }     hold_dest = null;     return (0);   }   private InetAddress modeToAddress(String value, int type) {     // validate the IP Address based on its text value, its     // type (DEST or SOURCE), and the mode (UNI_TO_MULTI or     // MULTI_TO_UNI). Returns an InetAddress if succesfull and     // null on failure.     InetAddress inet;     if ((type != DEST) && (type != SOURCE)) {       System.err.println("Invalid type passed to modeToAddress (" + type           + ")");       return (null);     }     switch (mode) {     case MODE_UNI_TO_MULTI:       if (type == DEST)         inet = returnValidMCIP(value);       else         inet = returnValidIP(value);       break;     case MODE_MULTI_TO_UNI:       if (type == DEST)         inet = returnValidIP(value);       else         inet = returnValidMCIP(value);       break;     default:       // no mode set       System.err.println("Error: No Mode Selected.");       return (null);     }     if (inet == null)       System.err.println("Invalid dest IP address (" + value + ").");     return (inet);   }   private InetAddress returnValidIP(String IP) {     // return InetAddress if IP is valid, null otherwise     InetAddress inet;     try {       inet = InetAddress.getByName(IP);     } catch (UnknownHostException e) {       return (null);     }     return (inet);   }   private InetAddress returnValidMCIP(String IP) {     // return InetAddress if IP is valid multicast addr,     // null otherwise     InetAddress inet = returnValidIP(IP);     if (inet.isMulticastAddress()) {       return (inet);     } else {       return (null);     }   }   public boolean isConfigValid() {     // validate that the mode, source IP/port, and     // dest IP(s)/port(s) are all valid and a valid     // combination.     if (mode == MODE_NONE) {       System.err.println("No mode selected.");       return (false);     }     if (!source.isComplete()) {       if ((source.getPort() != 0) && (mode == MODE_UNI_TO_MULTI)) {         // if source is unicast local IP is implied         try {           source.setAddress(InetAddress.getLocalHost());         } catch (UnknownHostException e) {           System.err.println("Incomplete source address.");           return (false);         }       } else {         System.err.println("Incomplete source address.");         return (false);       }     }     if (dest.isEmpty()) {       System.err.println("No destination addresses.");       return (false);     }     for (Enumeration e = dest.elements(); e.hasMoreElements();) {       Address a = (Address) e.nextElement();       if (!a.isComplete()) {         System.err.println("Incompete destination address.");         return (false);       }     }     return (true);   }   public static void main(String args[]) {     Reflector r = new Reflector();     r.run();   } } //Address class is used to store an IP address and port //combination. class Address {   private InetAddress address = null;   private int port = 0;   public Address(InetAddress address, int port) {     this.address = address;     this.port = port;   }   public Address(InetAddress address) {     this.address = address;   }   public Address(int port) {     this.port = port;   }   public InetAddress getAddress() {     return (address);   }   public int getPort() {     return (port);   }   public void setPort(int port) {     this.port = port;   }   public void setAddress(InetAddress address) {     this.address = address;   }   public boolean isComplete() {     // return true if both IP and port are populated,     // false otherwise.     if ((address != null) && (port != 0))       return (true);     else       return (false);   }   public String toString() {     // return a string representation of the IP/port.     String str;     if (address == null)       str = "";     else       str = address.getHostAddress();     str = str + "/" + port;     return (str);   } } //Logger class opens and writes to the log file //if boolean true is passed as constructor argument. class Logger {   private boolean logging;   private FileWriter logfile;   public Logger(boolean logging) {     this.logging = logging;     if (logging) {       try {         // open logfile for append         logfile = new FileWriter("reflector.log", true);       } catch (IOException e) {         System.err.println("Error opening log file.");       }       log("Reflector started: " + new Date());     }   }   public void log(String str) {     // write string to logfile     // if logging disabled return     if (!logging)       return;     try {       logfile.write(str + "\n");       logfile.flush();     } catch (IOException e) {       System.err.println("Error writing to log file.");     }   } } //ReflectorSender creates a unicast or multicast socket //and is registered to receive incoming packet notifications //via the PacketListenerInterface. Incoming packets //are forwarded on the outgoing socket. class ReflectorSender extends Thread implements PacketListenerInterface {   private InetAddress sendAddr;   private int sendPort;   private int mode;   private DatagramSocket ds = null;   private Logger logger;   public ReflectorSender(Address a, int mode, Logger logger) {     sendAddr = a.getAddress();     sendPort = a.getPort();     this.mode = mode;     this.logger = logger;   }   public void run() {     // initialize a DatagramSocket or MulticastSocket     // based on the mode:     switch (mode) {     case Reflector.MODE_MULTI_TO_UNI:       ds = initUnicastSocket();       break;     case Reflector.MODE_UNI_TO_MULTI:       ds = (DatagramSocket) initMulticastSocket();       break;     default:       break;     }   }   private MulticastSocket initMulticastSocket() {     // initialize a MulticastSocket     MulticastSocket mc;     try {       mc = new MulticastSocket(sendPort);     } catch (Exception e) {       e.printStackTrace();       return (null);     }     return (mc);   }   private DatagramSocket initUnicastSocket() {     // initialize a DatagramSocket     DatagramSocket ds;     try {       ds = new DatagramSocket(sendPort);     } catch (Exception e) {       e.printStackTrace();       return (null);     }     return (ds);   }   public void packetReceived(DatagramPacket packet) {     // An incoming packet has been received. Override     // the old packet addressing to the new outgoing     // addressing, send it and log it.     try {       packet.setAddress(sendAddr);       packet.setPort(sendPort);       ds.send(packet);       logger.log("Packet forwarded to "           + packet.getAddress().getHostAddress() + "/"           + packet.getPort() + ", " + packet.getLength() + " bytes");     } catch (IOException e) {       System.err.println("Error sending packet");       e.printStackTrace();     }   } } //ReflectorListener thread listens for packets //and notifies one or more interested threads //who register as PacketListenerInterfaces. class ReflectorListener extends Thread {   private InetAddress listenAddr;   private int listenPort;   private int mode;   private Vector packetListeners;   private Logger logger;   private static final int MAX_PACKET_SIZE = 1500;   public ReflectorListener(Address a, int mode, Logger logger) {     listenAddr = a.getAddress();     listenPort = a.getPort();     this.mode = mode;     this.logger = logger;     packetListeners = new Vector();   }   public void run() {     // create a unicast or multicast socket     // depending on the mode and listen for packets.     switch (mode) {     case Reflector.MODE_UNI_TO_MULTI:       DatagramSocket ds = initUnicastSocket();       if (ds != null)         listen(ds);       break;     case Reflector.MODE_MULTI_TO_UNI:       MulticastSocket mc = initMulticastSocket();       if (mc != null)         listen((DatagramSocket) mc);       break;     default:       break;     }   }   private MulticastSocket initMulticastSocket() {     // initialize a MulticastSocket and join the group     MulticastSocket mc;     try {       mc = new MulticastSocket(listenPort);       mc.joinGroup(listenAddr);     } catch (Exception e) {       System.err.println("Failed to create MulticastSocket on " + "port "           + listenPort);       return (null);     }     return (mc);   }   private DatagramSocket initUnicastSocket() {     // initialize a DatagramSocket     DatagramSocket ds;     try {       ds = new DatagramSocket(listenPort);     } catch (Exception e) {       System.err.println("Failed to create DatagramSocket on " + "port "           + listenPort);       return (null);     }     return (ds);   }   private void listen(DatagramSocket ds) {     // loop forever listening to packets, when they     // arrive log them and notify all interested threads.     byte[] buffer;     DatagramPacket packet;     while (true) {       try {         buffer = new byte[MAX_PACKET_SIZE];         packet = new DatagramPacket(buffer, buffer.length);         ds.receive(packet);         logger.log("Packet received, " + packet.getLength() + " bytes");         eventNotify(packet);       } catch (IOException e) {         System.err.println("Error receiving packet\n");         e.printStackTrace();       }     }   }   public void addPacketListener(PacketListenerInterface pl) {     // add interested thread to listeners vector     packetListeners.addElement(pl);   }   public void removePacketListener(PacketListenerInterface pl) {     // remove thread to listeners vector     packetListeners.removeElement(pl);   }   private void eventNotify(DatagramPacket packet) {     // notify all registered threads that a packet has arrived     // using the packetReceived(DatagramPacket) method.     for (Enumeration e = packetListeners.elements(); e.hasMoreElements();) {       PacketListenerInterface pl = (PacketListenerInterface) e           .nextElement();       pl.packetReceived(packet);     }   } } //PacketListenerInterface used by threads that need to //be notified of datagram packet receipt. A single //interface function packetReceived passes the packet //information to the thread requiring the information. interface PacketListenerInterface {   public void packetReceived(DatagramPacket packet); }