jock

jock

jock is used for sending and receiving packets. It is run with the -s option to be a listener which becomes a server, or without it to be a client which connects to a listener.

Type the command


jock -?
to learn the options.

Code links

jock.java

Listings

jock.java
package net.dougharris.utility;

import net.dougharris.utility.jockmods.*;

import java.util.logging.Level;
import java.util.logging.Logger;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.ConnectException;
import java.net.UnknownHostException;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.IOException;

public class jock{
  static String options="?-k-A-e-i-o-s-S-v-V-y-b_n_N_c_C_O_I_p_P_h_H_d_D_r_R_w_W_l-L_E_";
  static P cmdArgs;
  static StringBuffer cmdLine;

  /* configuration variables */
  static boolean echo;
  static boolean server;
  static boolean source;
  static boolean serverSource;
  static boolean useStdin;
  static String inFileName;
  static boolean useStdout;
  static String outFileName;
  static int operationCount;
  static int operatorCount;
  static int operatorNumber;
  static Level logLevel;

  /* timing variables */
  static int startDelay;
  static int spinDelay;
  static int minConnectDelay;
  static int maxConnectDelay;

  static InetAddress serverHost;
  static InetAddress clientHost;
  static int serverPort;
  static int clientPort;

  static boolean noDelay;
  static int soLinger;
  static boolean keepAlive;


  static int sizeRead;
  static int sizeReadBuffer;
  static int sizeWrite;
  static int sizeWriteBuffer;

  static int backlog;
  static String processorClassName;
  static Processor processor;
  static Discard discard=new Discard();

  Chargen chargen;

  public static void help(){
    P.rintln("[-s # serverMode][-S # sourceMode]");
    P.rintln("[-e # echoMode][-E echoProcessor]");
    P.rintln("[-h server][-H client]");
    P.rintln("[-p serverPort][-P clientPort]");
    P.rintln("[-i|-I inFileName] [-o|-O outFileName]");
    P.rintln("[-v #light logging] [-V # heavy logging]");
    P.rintln("[-l #log to stderr] [-L logFileName]");
    P.rintln("[-r userReadSize][-R socketReadSize]");
    P.rintln("[-w userWriteSize][-W socketWriteSize]");
    P.rintln("[-n operationCount][-N operatorCount]");
    P.rintln("[-d spinDelay][-D startDelay]");
    P.rintln("[-c connections][-C connections]");
  }

  static class Client implements Runnable{
    int whichOperator;
    Socket clientSocket;

    Client(){
      try{
        whichOperator=operatorNumber++;
        clientSocket = new Socket();
        setSocketArgs(clientSocket);
        logSocketArgs(clientSocket);
        clientSocket.bind(new InetSocketAddress(clientHost, clientPort));
        clientSocket.connect(new InetSocketAddress(serverHost, serverPort));
      } catch(IOException x){
        throw new RuntimeException("Client constructor "+x);
      }
    }

    public void start(){
      new Thread(this).start();
    }

    public void run(){
      try{
        cmdArgs.config("client "+whichOperator+" socket connected.");
        configureAndRun(clientSocket,whichOperator);
        clientSocket.close();
        cmdArgs.config("client "+whichOperator+" socket closed.");
      }catch(IOException x){
        throw new RuntimeException(x);
      }
    }
  }

  static class Server implements Runnable{
    private int whichOperator;
    private Socket serviceSocket;

    Server(ServerSocket listenSocket) throws IOException{
      whichOperator=operatorNumber++;
      serviceSocket = listenSocket.accept();
      cmdArgs.config("server "+whichOperator+" socket accepted.");
      setSocketArgs(serviceSocket);
      logSocketArgs(serviceSocket);
    }

    public void start(){
      new Thread(this).start();
    }

    public void run(){
      try{
        configureAndRun(serviceSocket,whichOperator);
         serviceSocket.close();
        cmdArgs.config("server "+whichOperator+" socket closed.");
      } catch (IOException x){
        throw new RuntimeException(x);
      }
    }
  }

  static class Sender implements Runnable{
    private Socket senderSocket;
    private InputStream iUser;
    private Thread runThread;
    private byte[] bWrite;
    int nWrite;
    int tWrite;
    long tWriteTime;
    private int whichOperator;
    OutputStream oNetwork;

    Sender(Socket senderSocket, int whichOperator){
      this.senderSocket=senderSocket;
      this.whichOperator=whichOperator;
      bWrite = new byte[sizeWrite];
      try{
        if(null!=cmdArgs.getProperty("-I")){
          iUser=new FileInputStream(inFileName);
        } else{
          iUser=useStdin?System.in:new Chargen();
        }
        oNetwork = senderSocket.getOutputStream();
      } catch(IOException x){
        throw new RuntimeException("sender constructor "+x);
      }
    }

    public void start(){
      runThread = new Thread(this);
      runThread.start();
    }

    public void run(){
      cmdArgs.config("sender "+whichOperator+" starting.");
      try{
        P.ause(startDelay);
        cmdArgs.fine(" starting Sender");
        int iterationLimit=operationCount;
	tWrite=0;
	tWriteTime=-cmdArgs.now();
	cmdArgs.fine("Original tWriteTime is "+tWriteTime);
        for (int iterationCount=0;;iterationCount++){
          if ((iterationLimit>0)&&(iterationCount==iterationLimit)) break;
          if (-1==(nWrite=iUser.read(bWrite))) break;
	  tWrite+=nWrite;
          cmdArgs.fine
             (whichOperator+" iteration "+iterationCount
             +" input to write "+nWrite+" total "+tWrite);
          oNetwork.write(bWrite,0,nWrite);
          P.ause(spinDelay);
        }
	tWriteTime+=P.now();
	double ftWriteTime=tWriteTime/1000.0;
        cmdArgs.fine("wrote "+tWrite+ " bytes in "+(ftWriteTime)+" s");
        cmdArgs.fine("writing Bandwidth = "+(tWrite/(ftWriteTime))+" bytes/sec");
        senderSocket.shutdownOutput();
        cmdArgs.config("Sender "+whichOperator+" shutdownOutput.");
      } catch(IOException x){
        throw new RuntimeException(x);
      }
    }
  }

  static class Receiver implements Runnable{
    private Socket receiverSocket;
    private OutputStream oUser;
    private Thread runThread;
    private int whichOperator;
    InputStream iNetwork;

    Receiver(Socket receiverSocket, int whichOperator){
      this.receiverSocket=receiverSocket;
      this.whichOperator=whichOperator;
      try{
        if(null!=cmdArgs.getProperty("-O")){
          oUser=new FileOutputStream(outFileName);
        } else{
          oUser = useStdout?(OutputStream)System.out:discard;
        }
        iNetwork = receiverSocket.getInputStream();
      } catch(IOException x){
        throw new RuntimeException("receiver constructor ",x);
      }
    }

    public void start(){
      runThread = new Thread(this);
      runThread.start();
    }

    public void join(){
      try{runThread.join();}catch(InterruptedException ignored){}
    }

    public void run(){
      cmdArgs.config("Receiver" +whichOperator+" run.");
      byte[] bRead = new byte[sizeRead];
      int nRead;
      int tRead;
      long tReadTime;
      try{
         int iterationLimit=operationCount;
        P.ause(startDelay);
	tRead=0;
	tReadTime= -cmdArgs.now();
        for (int iterationCount=0;;iterationCount++){
          if ((iterationLimit>0)&&(iterationCount==iterationLimit)) break;
          if (-1==(nRead=iNetwork.read(bRead))) break;
	  tRead+=nRead;
          cmdArgs.fine
    (whichOperator+" iteration "+iterationCount+" read "+nRead+" total "+tRead);
          oUser.write(bRead,0, nRead);
          P.ause(spinDelay);
        }
	tReadTime+=P.now();
	double ftReadTime=tReadTime/1000.0;
        cmdArgs.fine("read "+tRead+ " bytes in "+(ftReadTime)+" s");
        cmdArgs.config("Receiver "+whichOperator+" shutdown.");
        cmdArgs.fine("reading Bandwidth = "+(tRead/(ftReadTime))+" bytes/sec");
      } catch(IOException x){
        throw new RuntimeException(x);
      }
    }
  }

  static class ProcessIO implements Runnable{
    private Socket processSocket;
    private InputStream i;
    private OutputStream o;
    private int whichOperator;

    private ProcessIO(Socket processSocket, int whichOperator){
      this.processSocket=processSocket;
      this.whichOperator=whichOperator;
      try{
        this.i=processSocket.getInputStream();
        this.o=processSocket.getOutputStream();
      } catch(IOException x){
        throw new RuntimeException(x);
      }
    }

    public void start(){
      (new Thread(this)).start();
    }

    public void run(){
      processor = (Processor) P.getInstance(processorClassName);
      cmdArgs.config(whichOperator+" run processor.");
      try{
        processor.process(i,o);
        processSocket.shutdownOutput();
        cmdArgs.config("Processor "+whichOperator+" shutdownOutput.");
      } catch(IOException x){
         throw new RuntimeException(x);
      } catch(ProcessorException x){
         throw new RuntimeException(x);
      }
    }
  }

  public static void main(String[] args){
    cmdArgs = P.arseArgs(options,args);
    cmdLine=new StringBuffer();
    cmdLine.append("\"jock");
    for (int i=0;i<args.length;i++){
      cmdLine.append(" ");
      cmdLine.append(args[i]);
    }
    cmdLine.append("\" ");

    setLogging();
    setArgs();
    setNames();

    if (cmdArgs.getFlag("-?")){
      help();
      P.exit(0);
    }

    if (server){
      Listen();
    } else {
      Connect();
    }
  }

/**
  * java.util.logging.Level has 7 levels plus the extremes of NONE and ALL.
  * jock uses four of these levels internally,
  * and uses the -v and -V flags to set them.
  * The default logging if no flags are specified is SEVERE.
  * In the jock code this level is accomplished with the severe() method.
  * This is only used just before throwing a RuntimeException.
  * For a moderate amount of logging, limited to basic information
  * only, the -v flag by itself produces Level.INFO logging.
  * In the jock code this level is accomplished with the info() method.
  * If you would like logging up through addressing, and creating objects,
  * the -V flag produces CONFIG level logging, done in the code with config().
  * Finally, the finest logging that the jock code itself performs is specified
  * using both flags -v and -V, and done in the code by fine().
  * 
  * You may wish to send the logging information to a file, rather than
  * to the default standard error stream, and this is done by giving the
    name of that file as the value of the property -L.
  */
  static void setLogging(){
    logLevel=Level.SEVERE;
    boolean logInfo = cmdArgs.getFlag("-v");
    boolean logFine = cmdArgs.getFlag("-V");
    if (!logFine){
      if (logInfo){ // -v
        logLevel=Level.INFO;
      }
    } else { // logFine
      if (!logInfo){ // -V
        logLevel=Level.CONFIG;
      } else { // -v -V
        logLevel=Level.FINE;
      }
    }
    cmdArgs.setLogLevel(logLevel);
    if (null!=cmdArgs.getProperty("-L")){
      String logFileName=cmdArgs.getProperty("-L");
      cmdArgs.setLogFile(logFileName);
    }
  }

  static void setArgs(){
    cmdArgs.info("cmdline "+cmdLine);
    server      = cmdArgs.getFlag("-s");
    cmdArgs.info("server "+server);
    echo       = cmdArgs.getFlag("-e");
    cmdArgs.info("echo "+echo);
    serverSource = cmdArgs.getFlag("-S");
    cmdArgs.info("serverSource "+serverSource);
    source=!server^serverSource;//either both false or both true
    sizeRead   = cmdArgs.getIntProperty("-r",1024);
    sizeWrite  = cmdArgs.getIntProperty("-w",1024);
    sizeReadBuffer   = cmdArgs.getIntProperty("-R",0);
    sizeWriteBuffer  = cmdArgs.getIntProperty("-W",0);
    useStdin  = cmdArgs.getFlag("-i");
    inFileName  = cmdArgs.getProperty("-I");
    if (null!=inFileName){
      useStdin=true;
    }
    useStdout = cmdArgs.getFlag("-o");
    outFileName  = cmdArgs.getProperty("-O");
    startDelay = cmdArgs.getIntProperty("-D",0);
    spinDelay  = cmdArgs.getIntProperty("-d",0);
    minConnectDelay = cmdArgs.getIntProperty("-c",0);
    maxConnectDelay = cmdArgs.getIntProperty("-C",0);
    operationCount  = cmdArgs.getIntProperty("-n",0);
    operatorCount   = cmdArgs.getIntProperty("-N",1);
    backlog    = cmdArgs.getIntProperty("-b" ,5);
    processorClassName = cmdArgs.getProperty("-E","net.dougharris.utility.jockmods.EchoProcessor");
    if (null!=cmdArgs.getProperty("-E")){
      echo=true;
    }
    if (useStdin&&(null==cmdArgs.getProperty("-n"))){
      operationCount=0;
    }
  }

  static void setSocketArgs(Socket s) throws SocketException{
    if (cmdArgs.getFlag("-y")){
      s.setTcpNoDelay(true);
    }
    cmdArgs.fine(" noDelay  "+s.getTcpNoDelay());
    if (cmdArgs.getFlag("-k")){
      s.setKeepAlive(true);
    }
    cmdArgs.fine(" keepalive  "+s.getKeepAlive());

    /* THIS IS VERY WRONG: trying to set property linger, not what -l is for
    if (null!=cmdArgs.getProperty("-l")){
      soLinger  = cmdArgs.getIntProperty("-l",0);
      s.setSoLinger(true, soLinger);
    }
    cmdArgs.fine(" linger  "+s.getSoLinger());
    */

    if (null!=cmdArgs.getProperty("-W")){
      s.setSendBufferSize(sizeWriteBuffer);
      cmdArgs.fine(" request send Buffer "+sizeWriteBuffer);
    }
    if (null!=cmdArgs.getProperty("-R")){
      s.setReceiveBufferSize(sizeReadBuffer);
      cmdArgs.fine(" request receive Buffer "+sizeReadBuffer);
    }
  }

  static void logSocketArgs(Socket s) throws SocketException{
     cmdArgs.config("send buffer size:"+s.getSendBufferSize());
     cmdArgs.config("receive buffer size:"+s.getReceiveBufferSize());
  }

  static void setServerSocketArgs(ServerSocket s) throws SocketException{
    if (null!=cmdArgs.getProperty("-R")){
      s.setReceiveBufferSize(sizeReadBuffer);
    }
  }

  static void setNames(){
    try{
      InetAddress local=InetAddress.getLocalHost();
      //JDH 
      //JDH On client clientHost is localHost
      //JDH On server clientHost is remoteHost
      //JDH On client serverHost is remoteHost
      //JDH On server serverHost is remoteHost
      //JDH
      String localName=local.getHostName();
      String serverName = (cmdArgs.getProperty("-h",localName));
      serverHost = InetAddress.getByName(serverName);
      serverPort = cmdArgs.getIntProperty("-p",8888);
      String clientName = (cmdArgs.getProperty("-H",server?null:localName));
      clientHost = InetAddress.getByName(clientName);
      clientPort = cmdArgs.getIntProperty("-P", 0);
//System.err.println(">>>>> clientHost <<<<<<<"+ clientHost);
//System.err.println(">>>>> clientPort <<<<<<<"+ clientPort);
//System.err.println(">>>>> serverHost <<<<<<<"+serverHost);
//System.err.println(">>>>> serverPort <<<<<<<"+serverPort);
      cmdArgs.config("server address "+serverHost+":"+serverPort);
      cmdArgs.config("client address "+clientHost+":"+clientPort);
    } catch (UnknownHostException x){
      P.exception(x,1);
    } catch (NumberFormatException x){
      P.exception(x,1);
    }
  }

  static void configureAndRun(Socket s, int whichOperator) throws IOException{
    if (!source){ //this object is not to be the source
      if(echo){
        new ProcessIO(s, whichOperator).run();
      } else {
         new Receiver(s, whichOperator).run();
      }
    } else { // this object is to be the source
      Receiver r=null;
      if (echo){
        r=new Receiver(s,whichOperator);
        r.start();
      }
      new Sender(s,whichOperator).run();
      if (r!=null){
        r.join();
      }
    }
  }

  static void Listen(){
    ServerSocket listenSocket;
    Socket serviceSocket;
    int serverSpawned=0;
    boolean shouldRun = true;
    cmdArgs.config("Running as Listen()");
    try{
      listenSocket = new ServerSocket(serverPort, backlog, serverHost);
      setServerSocketArgs(listenSocket);
      if (!cmdArgs.getFlag("-N")){
        new Server(listenSocket).run();
      } else {
        while(shouldRun){
          if ((operatorCount>0)&&((++serverSpawned)>=operatorCount)){
            break;
          }
          new Server(listenSocket).start();
        }
      }
      listenSocket.close();
    }catch (IOException x){
      throw new RuntimeException(x);
    }
  }

/**
 * This is called to handle Connections, thus from a client,
 * which for jock is equivalent to not having the -s flag set.
 * If the -N propery is not specified then it makes a single connection
 * and when that is completed it dies.  If that property is specified
 * with the value 0 then it keeps making connections at a rate
 * specified by the combined values of the -c/-C properties (what
 * is the default). Otherwise it spawns the specified number of threads,
 * at the specified rate.
**/
  static void Connect(){
    cmdArgs.config("Running Connector");
    if (!cmdArgs.getFlag("-N")){
      new Client().run();
    } else {
      for(int clientsSpawned=0;;clientsSpawned++){
        if ((operatorCount>0)&&(clientsSpawned >= operatorCount)){
          break;
        }
        P.ause(minConnectDelay,maxConnectDelay);
        new Client().start();
      }
    }
  }
}