UpdateServer.java :  » Net » customdns » CustomDNS » Java Open Source

Java Open Source » Net » customdns 
customdns » CustomDNS » UpdateServer.java
package CustomDNS;

import java.lang.Exception;
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;

import net.espeak.infra.cci.exception.*;
import net.espeak.jesi.*;

import ZoneRegistrarIntf;
import ZoneAuthenticatorIntf;

import CustomDNS.UpdateProtocol;
import CustomDNS.UpdateProtocol.ServerResponse;


/*************************************************************************
 *  TCP/IP server for our custom update protocol.
 *************************************************************************
 *  We listen on a TCP/IP port. Clients connect to us to update their
 *  address records.
 */

public class UpdateServer {

    // Timeout values, in milliseconds. These are pretty arbitrary. We're
    // just trying to shut down unused connections promptly.
    static private final int TCP_TIMEOUT = 60000;

    // Instance variables.
    private String zone;
    private ZoneRegistrarIntf registrar;
    private ZoneAuthenticatorIntf authenticator;
    private short port;


    /*********************************************************************
     *  Start a new update server.
     *********************************************************************
     *  @param args Our command-line arguments. Pass an espeak connection
     *  properties file and customdns.prop.
     *  @see CustomDNS.Configuration
     */

    public UpdateServer (String zone, short port,
       ZoneRegistrarIntf registrar,
       ZoneAuthenticatorIntf authenticator)
      throws IOException
    {
  this.zone = zone;
  this.registrar = registrar;
  this.authenticator = authenticator;
  this.port = port;
  startServer();
    }
    
    // Connect the server to a TCP/IP port and listen for requests.
    // TODO - We should spawn a listener thread.
    private void startServer ()
  throws IOException
    {
  ServerSocket listener = new ServerSocket(this.port);
  while (true) {
      final Socket socket = listener.accept();
      socket.setSoTimeout(TCP_TIMEOUT);
      Thread handler = new Thread(new Runnable() {
    public void run () {
        handleConnection(socket);
    }
      });
      handler.start();
  }
    }

    // Handle a single client connection.
    private void handleConnection (Socket socket) {
  try {
      Reader rawin = new InputStreamReader(socket.getInputStream());
      BufferedReader in = new BufferedReader(rawin);
      Writer out = new OutputStreamWriter(socket.getOutputStream());
      InetAddress remoteAddress = socket.getInetAddress();
      runCommandLoop(in, out, remoteAddress);
  } catch (Exception e) {
      System.err.println(e.toString());
  } finally {
      try {
    socket.close();
      } catch (IOException e) {}
  } 
    }

    // End the current command and send a response code.
    // We throw an exception to end the current command
    // and print a response across the network. For example:
    //   500 Unknown error
    // Yes, this a pretty odd way of doing things. But it saves a lot
    // of ugly state flags in runCommandLoop.
    private void sendResponse(int code, String message)
  throws ServerResponse
    {
  throw new ServerResponse(code, message);
    }

    // Run our command loop.
    private void runCommandLoop (BufferedReader in, Writer out,
         InetAddress remoteAddress)
  throws IOException
    {
  String username = null;
  String password = null;

  UpdateProtocol.writeLine(out, "201 1.0 CustomDNS Update Server Ready");
  while (true) {
      try {
    // Get our command.
    String commandLine = in.readLine();
    if (commandLine == null)
        return;
    StringTokenizer tokens = new StringTokenizer(commandLine);
    int tokenCount = tokens.countTokens();
    if (tokenCount == 0)
        sendResponse(UpdateProtocol.STATUS_SYNTAX_ERROR,
         "No command specified");
    String command = tokens.nextToken().toUpperCase();
    
    // Handle our command.
    if (command.equals("QUIT")) {

        // Bail out of our command loop.
        break;

    } else if (command.equals("AUTH")) {

        // Parse our arguments.
        if (tokenCount != 5)
      sendResponse(UpdateProtocol.STATUS_SYNTAX_ERROR,
             "Wrong number of arguments");
        String authZone = tokens.nextToken();
        String authType = tokens.nextToken().toUpperCase();
        username = tokens.nextToken();
        password = tokens.nextToken();

        // Do some error checking.
        if (!this.zone.equals(authZone))
      sendResponse(UpdateProtocol.STATUS_UNKNOWN_ZONE,
             "Unknown zone");
        if (!authType.equals("PASS"))
      sendResponse(UpdateProtocol.STATUS_UNKNOWN_AUTH_TYPE,
             "Unknown authentication type");

        // Send back an optimistic response.
        sendResponse(UpdateProtocol.STATUS_AUTH_ACCEPTED,
         "Authentication accepted");

    } else if (command.equals("ADDRESS")) {

        // Parse our arguments.
        if (tokenCount != 3)
      sendResponse(UpdateProtocol.STATUS_SYNTAX_ERROR,
             "Wrong number of arguments");
        String hostname = tokens.nextToken().toLowerCase();
        String address = tokens.nextToken();

        // Check the user's privileges.
        approveUpdate(username, password, hostname);

        if (address.toUpperCase().equals("AUTOMATIC")) {
      // Use the address of the remote end of our
      // socket.
      address = remoteAddress.getHostAddress();
        } else {
      // Sanity-check the address field.
      address = cleanUpAddress(address);
        }

        // Attempt to perform the update.
        try {
      registrar.registerAddressForHost(hostname, address);
        } catch (ESInvocationException e) {
      sendResponse(UpdateProtocol.STATUS_NO_UPDATE,
             "Unable to update address");
        }
        sendResponse(UpdateProtocol.STATUS_OK,
         "Address updated");

    } else {
        sendResponse(UpdateProtocol.STATUS_UNKNOWN_COMMAND,
         "Unknown command");
    }
      } catch (ServerResponse e) {
    UpdateProtocol.writeLine(out, e.getMessage());
      }
  }
  UpdateProtocol.writeLine(out, "200 Goodbye");
    }

    // Authenticate the user.
    private void approveUpdate (String user, String password, String host)
  throws ServerResponse
    {
  if (user == null || password == null)
      sendResponse(UpdateProtocol.STATUS_WRONG_STATE,
       "Must use AUTH command before ADDRESS");
  try {
      if (!authenticator.authenticateUser(user, password, host))
    sendResponse(UpdateProtocol.STATUS_NOT_ALLOWED,
           "Update not allowed");
  } catch (ESInvocationException e) {
      sendResponse(UpdateProtocol.STATUS_COULD_NOT_AUTH,
       "Couldn't peform authentication");
  }
    }

    // Try to bash our address into something safe.
    // (We don't want to put garbage into the database.)
    // This has the unfortunate side effect of allowing users to supply
    // hostnames as addresses, and cause us to do a real lookup.
    private String cleanUpAddress (String address)
  throws ServerResponse
    {
  String result = null;
  try {
      InetAddress inetaddr = InetAddress.getByName(address);
      result = inetaddr.getHostAddress();
  } catch (UnknownHostException e) {
      sendResponse(UpdateProtocol.STATUS_MALFORMED_ADDRESS,
       "Malformed address");
  }
  return result;
    }


    /*********************************************************************
     *  Start a new update server.
     *********************************************************************
     *  @param args Our command-line arguments. Pass an espeak connection
     *  properties file and customdns.prop.
     *  @see CustomDNS.Configuration
     */
    
    public static void main (String [] args) {
  String appname = "CustomDNS.UpdateServer";
  try {
      // Parse our command line arguments, and get the configuration
      // information we'll be needing.
      Configuration config = Configuration.parseArguments(appname, args);
      String zone = config.getProperty("customdns.updateserver.zone");
      String defaultPort = Short.toString(UpdateProtocol.DEFAULT_PORT);
      String portstr = config.getProperty("customdns.updateserver.port",
            defaultPort);
      short port = Short.parseShort(portstr);
      String connfile = config.getConnectionFile();
      
      // Connect to e-speak, and find our zone registarar and
      // zone authentator.
      ESConnection core = new ESConnection(connfile);
      ESQuery query = new ESQuery("Name == '" + zone + "'");
      String intfName = "ZoneRegistrarIntf";
      ESServiceFinder finder = new ESServiceFinder(core, intfName);
      ZoneRegistrarIntf reg = (ZoneRegistrarIntf) finder.find(query);
      intfName = "ZoneAuthenticatorIntf";
      finder = new ESServiceFinder(core, intfName);
      ZoneAuthenticatorIntf auth = (ZoneAuthenticatorIntf)
    finder.find(query);

      // Start our server.
      System.err.println("CustomDNS.UpdateServer: Starting.");
      new UpdateServer(zone, port, reg, auth);
  } catch (Exception e) {
      System.err.println("CustomDNS.UpdateServer: " + e.toString());
      System.exit(1);
  }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.