1 /*
2  * @(#) $Id: ClientCommand.java,v 1.15 2003/07/08 08:13:53 pankaj Exp $
3  *
4  * Copyright (c) 2002-03 by Pankaj Kumar (http://www.pankaj-k.net). 
5  * All rights reserved.
6  *
7  * The license governing the use of this file can be found in the 
8  * root directory of the containing software.
9  */
10package org.jstk.ssl;
11
12
13import java.io.*;
14import java.util.HashMap;
15import java.net.*;
16import javax.net.SocketFactory;
17import javax.net.ssl.SSLSocketFactory;
18import javax.net.ssl.SSLSession;
19import javax.net.ssl.SSLSocket;
20import javax.net.ssl.HttpsURLConnection;
21import javax.net.ssl.HostnameVerifier;
22import org.jstk.*;
23
24public class ClientCommand extends JSTKCommandAdapter {
25    public class ReaderThread extends Thread {
26        private JSTKSocket socket;
27        private JSTKBuffer buf;
28        public ReaderThread(JSTKSocket socket, JSTKBuffer buf){
29            super("ReaderThread");
30            this.socket = socket;
31            this.buf = buf;
32        }
33
34        public void run() {
35            try {
36                int n;
37                while ((n = socket.read(buf)) != -1);
38            } catch (Exception e) { }
39        }
40    }
41
42    public class CustomHostnameVerifier implements HostnameVerifier {
43        private String expectedHostname;
44        public CustomHostnameVerifier(String expectedHostname){
45            this.expectedHostname = expectedHostname;
46        }
47        public boolean verify(String hostname, SSLSession sess){
48            System.out.print("Expected: " + expectedHostname + ", Got: " + hostname + ". ");
49            System.out.print("Proceed(yes/no)?");
50            System.out.flush();
51            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
52            String response = null;
53            try {
54                response = br.readLine();
55            } catch (IOException ioe){
56                response = "no";
57            }
58            if ("yes".equalsIgnoreCase(response.trim()))
59                return true;
60            return false;
61        }
62    }
63
64    private static int outPort = -1;
65    public static int getOutPort(){
66        return outPort;
67    }
68    public static void setOutPort(int port){
69        outPort = port;
70    }
71    private static HashMap defaults = new HashMap();
72    static {
73        defaults.put("host", "localhost");
74        defaults.put("port", "9000");
75        defaults.put("outproto", "TCP");
76        defaults.put("mode", "prompt");
77        defaults.put("bufsize", "8192");
78        defaults.put("num", "2048");
79        defaults.put("action", "write-only");
80    }
81
82    public String briefDescription(){
83        String briefDesc = "simple client for TCP or SSL connections";
84        return briefDesc;
85    }
86
87    public String optionsDescription(){
88        String optionsDesc =
89            "  -host <host>    : Remote host machine name or IP address.[" +
90            defaults.get("host") + "]\n" +
91            "  -port <port>    : Destination port on remote host.[" +
92            defaults.get("port") + "]\n" +
93            "  -outproto <proto>: Outgoing connection protocol (TCP or SSL).[" +
94            defaults.get("outproto") + "]\n" +
95            "  -csfile <csfile>: File having cipher suits to be enabled.\n" +
96            "  -mode <mode>    : Client operation mode(prompt|bench|read-url).[" +
97            defaults.get("mode") + "]\n" +
98            "  -action <action>: What action to take -- applicable for \"bench\" mode\n" +
99            "                      (open-close|write-only|write-read|read-url).[" +
00            defaults.get("action") + "]\n" +
01            "  -bufsize <size> : len. of buf (for bench mode).[" +
02            defaults.get("bufsize") + "]\n" +
03            "  -num <num>      : no. of times buf is written/read(for bench mode).[" +
04            defaults.get("num") + "]\n" +
05            "  -url <httpurl>  : URL to be read (for bench/read-url or read-url).\n" +
06            "  -pattern <pat>  : Fill buffer with this pattern(for bench mode).\n" +
07            "  -verbose        : Verbose output.\n" +
08            "  -conn close     : Close connection with every read-url action.\n" +
09            "  -inetaddr <addr>: Network IP address (useful for multi-homed hosts).\n";
10        return optionsDesc;
11    }
12    public String[] useForms(){
13        String[] useForms = {
14            "[-host <host>] [-port <port>] [-ssl] [-inetaddr <addr>]"
15        };
16        return useForms;
17    }
18    public String[] sampleUses(){
19        String[] sampleUses = {
20            "",
21            "-host venus -port 2950",
22            "-ssl"
23        };
24        return sampleUses;
25    }
26
27    private JSTKResult runRMIClient(JSTKArgs args) throws Exception{
28        int bufsize = Integer.parseInt(args.get("bufsize"));
29        int num = Integer.parseInt(args.get("num"));
30        int port = Integer.parseInt(args.get("port"));
31        String mode = args.get("mode");
32        String action = args.get("action");
33        boolean verbose = Boolean.valueOf(args.get("verbose")).booleanValue();
34        String pattern = args.get("pattern");
35        String host = args.get("host");
36
37        setOutPort(port);
38        RMIServerInterface obj = null;
39        String url = "//" + host + "/RMIServer";
40        try {
41            obj = (RMIServerInterface)java.rmi.Naming.lookup(url);
42        } catch (Exception exc){
43            return new JSTKResult(null, false, "Failed to lookup \"" + url + "\": " + exc);
44        }
45
46        if (mode.equalsIgnoreCase("bench")){
47            int numBytes = 0;
48            byte[] buf = new byte[bufsize];
49            if (action.equalsIgnoreCase("write-only")){
50                long st = System.currentTimeMillis();
51                for (int i = 0; i < num; i++){
52                    obj.writeOnly(buf);
53                    if (verbose)
54                        System.out.println("[" + i + "]Wrote: " + buf.length + " bytes.");
55                    numBytes += buf.length;
56                }
57                long et = System.currentTimeMillis();
58                double writeRate = ((double)numBytes*1000.0)/(et - st);
59                double tt = (et - st)/1000.0;
60
61                System.out.print("Invoked RMI method " + num + " times in " + tt + " seconds.\n");
62                System.out.println(" Write Rate: " + writeRate + " bytes/sec.");
63            } else if (action.equalsIgnoreCase("write-read")){
64                int numRead = 0;
65                long st = System.currentTimeMillis();
66                for (int i = 0; i < num; i++){
67                    byte[] tbuf = obj.writeRead(buf);
68                    if (verbose)
69                        System.out.println("[" + i + "]Wrote: " + buf.length +
70                            " bytes, Read: " + tbuf.length + " bytes.");
71                    numBytes += buf.length;
72                    numRead += tbuf.length;
73                }
74                long et = System.currentTimeMillis();
75                double writeRate = ((double)numBytes*1000.0)/(et - st);
76                double readRate = ((double)numRead*1000.0)/(et - st);
77                double tt = (et - st)/1000.0;
78
79                System.out.print("Invoked RMI method " + num + " times in " + tt + " seconds.\n");
80                System.out.println(" Write Rate: " + writeRate + " bytes/sec.");
81                System.out.println(" Read Rate : " + readRate + " bytes/sec.");
82            } else {
83                return new JSTKResult(null, true, "Unknown action: " + action);
84            }
85        } else if (mode.equalsIgnoreCase("prompt")){
86            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
87            while (true){
88                System.out.print("Enter Message: ");
89                System.out.flush();
90                String inp = br.readLine();
91                if (inp.equalsIgnoreCase("quit"))
92                    break;
93                byte[] tbuf = obj.writeRead(inp.getBytes());
94                System.out.println("Server Returned: " + new String(tbuf));
95            }
96        } else {
97            return new JSTKResult(null, true, "Unknown mode: " + mode);
98        }
99        return new JSTKResult(null, true, "DONE");
00    }
01
02    private JSTKResult processReadURL(JSTKArgs args, int num,
03                int bufsize, String mode, boolean verbose) throws IOException {
04        boolean connClose = false;
05        String urlString = args.get("url");
06        String connString = args.get("conn");
07        if (connString != null && connString.equalsIgnoreCase("close"))
08            connClose = true;
09        if (urlString == null)
10            return new JSTKResult(null, false, "No URL specified");
11
12        System.out.println("  URL          : " + urlString);
13
14        URL url = new URL(urlString);
15        CustomHostnameVerifier custVerifier = new CustomHostnameVerifier(url.getHost());
16        HttpsURLConnection.setDefaultHostnameVerifier(custVerifier);
17        if (mode.equalsIgnoreCase("bench")){
18            long st = System.currentTimeMillis();
19            int numBytes = 0;
20            byte[] buf = new byte[bufsize];
21            for (int i = 0; i < num; i++){
22                HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
23                BufferedInputStream bis = new BufferedInputStream(urlCon.getInputStream());
24                int n;
25                int nread = 0;
26                while ((n = bis.read(buf)) != -1){
27                    nread += n;
28                }
29                if (verbose){
30                    System.out.println("[" + i + "]Read: " + nread + " bytes from: " + urlString);
31                }
32                numBytes += nread;
33                if (connClose)
34                    urlCon.disconnect();
35            }
36            long et = System.currentTimeMillis();
37            double browseRate = ((double)numBytes*1000.0)/(et - st);
38            double tt = (et - st)/1000.0;
39
40            System.out.print("Read URL " + urlString + " " + num + " times in " + tt + " seconds.\n");
41            System.out.println(" Browse Rate: " + browseRate + " bytes/sec.");
42        } else {
43            BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
44            String line;
45            while ((line = br.readLine()) != null){
46                System.out.println(line);
47            }
48        }
49        return new JSTKResult(null, true, "DONE");
50    }
51
52    private JSTKResult runTCPClient(JSTKArgs args) throws Exception{
53        String host = args.get("host");
54        int port = Integer.parseInt(args.get("port"));
55        int bufsize = Integer.parseInt(args.get("bufsize"));
56        int num = Integer.parseInt(args.get("num"));
57        String inetAddrVal = args.get("inetaddr");
58        String mode = args.get("mode");
59        String action = args.get("action");
60        boolean verbose = Boolean.valueOf(args.get("verbose")).booleanValue();
61        String pattern = args.get("pattern");
62        String outproto = args.get("outproto");
63
64        System.out.println("  I/O library  : " + JSTKSocketUtil.getIOLibrary(args, outproto));
65        System.out.println("  Remote Host  : " + host + ", Remote Port: " + port);
66        System.out.println("  -----------------------------------");
67
68        JSTKSocket socket = JSTKSocketUtil.connect(args);
69        JSTKSocketUtil.print(socket, " --> ");
70        if (mode.equalsIgnoreCase("prompt")){
71            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
72            //byte[] buf = new byte[1024];
73            JSTKBuffer buf = JSTKBuffer.getInstance(bufsize, args);
74            while (true){
75                System.out.print("Enter Message: ");
76                System.out.flush();
77                String inp = br.readLine();
78                if (inp.equalsIgnoreCase("quit"))
79                    break;
80                buf.clear();
81                buf.putBytes(inp.getBytes());
82                socket.write(buf);
83                int n = socket.read(buf);
84                System.out.println("Server Returned: " + new String(buf.getBytes()));
85            }
86            socket.close();
87        } else if (mode.equalsIgnoreCase("bench")){
88            JSTKBuffer buf = JSTKBuffer.getInstance(bufsize, args);
89            JSTKBuffer buf1 = JSTKBuffer.getInstance(bufsize, args);
90            (new PatternUtil("00000000")).fillPattern(buf);
91
92            PatternUtil pu = new PatternUtil(pattern);
93
94            long numBytes = 0;
95            if (action.equalsIgnoreCase("write-only")){
96                long st = System.currentTimeMillis();
97                for (int i = 0; i < num; i++){
98                    if (pu.needToFill())
99                        pu.fillPattern(buf);
00                    socket.write(buf);
01                    numBytes += buf.getNBytes();
02                    if (verbose){
03                        System.out.println("[" + i + "]Wrote: " + buf.length() + " bytes.");
04                    }
05                }
06                long et = System.currentTimeMillis();
07                socket.close();
08                double xferRate = (double)(numBytes/(et - st)) *(1000.0/1024.0);
09                double tt = (et - st)/1000.0;
10
11                System.out.print("Sent " + numBytes + " bytes in " + tt + " seconds.\n");
12                System.out.println(" 1-way Xfer Rate: " + xferRate + " KB/sec.");
13            } else if (action.equalsIgnoreCase("write-read")){
14                int numBytesRead = 0;
15                long st = System.currentTimeMillis();
16                for (int i = 0; i < num; i++){
17                    if (pu.needToFill())
18                        pu.fillPattern(buf);
19                    socket.write(buf);
20                    numBytes += buf.getNBytes();
21                    if (verbose){
22                        System.out.println("[" + i + "]Sent: " + buf.length() + " bytes.");
23                    }
24                    int nread = 0;
25                    while (nread < bufsize){
26                        int n = socket.read(buf);
27                        if (n == -1)
28                            break;
29                        nread += n;
30                    }
31                    numBytesRead += nread;
32                }
33                long et = System.currentTimeMillis();
34                socket.close();
35                double xferRate = (double)(numBytes/(et - st)) *(1000.0/1024.0);
36                double tt = (et - st)/1000.0;
37
38                System.out.print("Wrote " + numBytes + "and Read " + numBytesRead + " bytes in " + tt + " seconds.\n");
39                System.out.println(" 2-way Xfer Rate: " + xferRate + " KB/sec.");
40            } else if (action.equalsIgnoreCase("open-close")){
41                socket.close(); // First connection not counted in the benchmark.
42                boolean invalidate = Boolean.valueOf(args.get("invalidate")).booleanValue();
43                long st = System.currentTimeMillis();
44                for (int i = 0; i < num; i++){
45                    socket = JSTKSocketUtil.connect(args);
46                    if (verbose)
47                        System.out.println("[" + i + "]Opened Socket ...");
48
49                    if (invalidate && socket.getSocket() instanceof SSLSocket){
50                        if (verbose)
51                            System.out.println("[" + i + "]Invalidating the SSLSession ...");
52                        SSLSocket sslSock = (SSLSocket)socket.getSocket();
53                        SSLSession sess = sslSock.getSession();
54                        sess.invalidate();
55                    }
56
57                    socket.close();
58                    if (verbose)
59                        System.out.println("[" + i + "]Closed Socket ...");
60                }
61                long et = System.currentTimeMillis();
62                double connRate = ((double)num*1000.0)/(et - st);
63                double tt = (et - st)/1000.0;
64
65                System.out.print("" + num + " connections in " + tt + " seconds.\n");
66                System.out.println(" Connection Rate: " + connRate + " connections/sec.");
67            } else if (action.equalsIgnoreCase("read-url")){
68                socket.close(); // First connection not counted in the benchmark.
69                long st = System.currentTimeMillis();
70                for (int i = 0; i < num; i++){
71                    socket = JSTKSocketUtil.connect(args);
72                    socket.close();
73                }
74                long et = System.currentTimeMillis();
75                double connRate = ((double)num*1000.0)/(et - st);
76                double tt = (et - st)/1000.0;
77
78                System.out.print("" + num + " connections in " + tt + " seconds.\n");
79                System.out.println(" Connection Rate: " + connRate + " connections/sec.");
80            } else {
81                return new JSTKResult(null, false, "Unknown action: " + action);
82            }
83        } else {
84            return new JSTKResult(null, false, "Unknown mode: " + mode);
85        }
86        return new JSTKResult(null, true, "DONE");
87    }
88
89    private JSTKResult runSSLClient(JSTKArgs args) throws Exception{
90        String[] csarray = JSTKSocketUtil.getCSFileCipherSuites(args);
91        if (csarray != null){
92            System.out.println("  Cipher Suites to be enabled   : ");
93            for (int i = 0; i < csarray.length; i++)
94                System.out.println("         " + csarray[i]);
95        }
96        return runTCPClient(args);
97    }
98
99    public Object execute(JSTKArgs args) throws JSTKException{
00        try {
01            args.setDefaults(defaults);
02            String host = args.get("host");
03            int port = Integer.parseInt(args.get("port"));
04            int bufsize = Integer.parseInt(args.get("bufsize"));
05            int num = Integer.parseInt(args.get("num"));
06            String inetAddrVal = args.get("inetaddr");
07            String mode = args.get("mode");
08            String action = args.get("action");
09            boolean verbose = Boolean.valueOf(args.get("verbose")).booleanValue();
10            String pattern = args.get("pattern");
11            String outproto = args.get("outproto");
12            String urlString = args.get("url");
13
14            if (urlString != null){
15                if (urlString.startsWith("https"))
16                    outproto = "HTTPS";
17                else if (urlString.startsWith("http"))
18                    outproto = "HTTP";
19                else
20                    return new JSTKResult(null, false, "Unknown URL format: " + urlString);
21            }
22
23            System.out.println("  Client Mode  : " + mode);
24            System.out.println("  OUT protocol : " + outproto);
25
26
27            if (mode.equalsIgnoreCase("bench")){
28                System.out.println("  Client Action: " + action);
29                System.out.println("  Buffer Size  : " + bufsize);
30                System.out.println("  Iterations   : " + num);
31            }
32
33            if (outproto.equalsIgnoreCase("RMI") || outproto.equalsIgnoreCase("SRMI")){
34                return runRMIClient(args);
35            } else if (outproto.equalsIgnoreCase("TCP")){
36                return runTCPClient(args);
37            } else if (outproto.equalsIgnoreCase("SSL")){
38                return runSSLClient(args);
39            } else if (outproto.equalsIgnoreCase("HTTP")){
40                return processReadURL(args, num, bufsize, mode, verbose);
41            } else if (outproto.equalsIgnoreCase("HTTPS")){
42                return processReadURL(args, num, bufsize, mode, verbose);
43            }
44            return new JSTKResult(null, false, "Unknown OUT Protocol: " + outproto);
45        } catch (Exception exc){
46            throw new JSTKException("ClientCommand execution failed", exc);
47        }
48    }
49
50    public static void main(String[] args) throws Exception {
51        JSTKOptions opts = new JSTKOptions();
52        opts.parse(args, 0);
53        ClientCommand clientCmd = new ClientCommand();
54        JSTKResult result = (JSTKResult)clientCmd.execute(opts);
55        System.out.println(result.getText());
56        System.exit(result.isSuccess()? 0 : 1);
57    }
58}
59