Reflector : Server « Network Protocol « Java






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);
}

           
         
    
  








Related examples in the same category

1.A generic framework for a flexible, multi-threaded server
2.Server allows connections on socket 6123Server allows connections on socket 6123
3.This server displays messages to a single clientThis server displays messages to a single client
4.The client can specify information to control the output of a serverThe client can specify information to control the output of a server
5.A server can use specialized streams to deliver typed dataA server can use specialized streams to deliver typed data
6.Serve entire objects using ObjectOutputStreamServe entire objects using ObjectOutputStream
7.A multithreaded serverA multithreaded server
8.Base class to build multithreaded servers easily
9.Manage a pool of threads for clients
10.Client estimates the speed of the network connection to the server
11.This server retrieves the time using the RFC867 protocol.This server retrieves the time using the RFC867 protocol.
12.Quote Server
13.Logging Server based on SocketServer
14.Client and Server Demo
15.Simple Http Server