Add 'src/be/nikiroo/utils/' from commit '46add0670fdee4bd936a13fe2448c5e20a7ffd0a'
[nikiroo-utils.git] / src / be / nikiroo / utils / serial / server / Server.java
index f6dd7d86a13cbf94c4c08279458ae3724b8b2f5b..04701590e1c669c7d2dd143e7c9d3e921052b5b5 100644 (file)
@@ -4,13 +4,6 @@ import java.io.IOException;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
 
 import be.nikiroo.utils.TraceHandler;
 
@@ -24,10 +17,10 @@ import be.nikiroo.utils.TraceHandler;
  * @author niki
  */
 abstract class Server implements Runnable {
-       static private final String[] ANON_CIPHERS = getAnonCiphers();
+       protected final String key;
+       protected long id = 0;
 
        private final String name;
-       private final boolean ssl;
        private final Object lock = new Object();
        private final Object counterLock = new Object();
 
@@ -38,6 +31,9 @@ abstract class Server implements Runnable {
        private boolean exiting = false;
        private int counter;
 
+       private long bytesReceived;
+       private long bytesSent;
+
        private TraceHandler tracer = new TraceHandler();
 
        /**
@@ -58,8 +54,32 @@ abstract class Server implements Runnable {
         *            the port to listen on, or 0 to assign any unallocated port
         *            found (which can later on be queried via
         *            {@link Server#getPort()}
-        * @param ssl
-        *            use a SSL connection (or not)
+        * @param key
+        *            an optional key to encrypt all the communications (if NULL,
+        *            everything will be sent in clear text)
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        * @throws UnknownHostException
+        *             if the IP address of the host could not be determined
+        * @throws IllegalArgumentException
+        *             if the port parameter is outside the specified range of valid
+        *             port values, which is between 0 and 65535, inclusive
+        */
+       public Server(int port, String key) throws IOException {
+               this((String) null, port, key);
+       }
+
+       /**
+        * Create a new server that will start listening on the network when
+        * {@link Server#start()} is called.
+        * <p>
+        * All the communications will happen in plain text.
+        * 
+        * @param name
+        *            the server name (only used for debug info and traces)
+        * @param port
+        *            the port to listen on
         * 
         * @throws IOException
         *             in case of I/O error
@@ -69,8 +89,8 @@ abstract class Server implements Runnable {
         *             if the port parameter is outside the specified range of valid
         *             port values, which is between 0 and 65535, inclusive
         */
-       public Server(int port, boolean ssl) throws IOException {
-               this((String) null, port, ssl);
+       public Server(String name, int port) throws IOException {
+               this(name, port, null);
        }
 
        /**
@@ -81,8 +101,9 @@ abstract class Server implements Runnable {
         *            the server name (only used for debug info and traces)
         * @param port
         *            the port to listen on
-        * @param ssl
-        *            use a SSL connection (or not)
+        * @param key
+        *            an optional key to encrypt all the communications (if NULL,
+        *            everything will be sent in clear text)
         * 
         * @throws IOException
         *             in case of I/O error
@@ -92,11 +113,11 @@ abstract class Server implements Runnable {
         *             if the port parameter is outside the specified range of valid
         *             port values, which is between 0 and 65535, inclusive
         */
-       public Server(String name, int port, boolean ssl) throws IOException {
+       public Server(String name, int port, String key) throws IOException {
                this.name = name;
                this.port = port;
-               this.ssl = ssl;
-               this.ss = createSocketServer(port, ssl);
+               this.key = key;
+               this.ss = new ServerSocket(port);
 
                if (this.port == 0) {
                        this.port = this.ss.getLocalPort();
@@ -146,6 +167,24 @@ abstract class Server implements Runnable {
                return port;
        }
 
+       /**
+        * The total amount of bytes received.
+        * 
+        * @return the amount of bytes received
+        */
+       public long getBytesReceived() {
+               return bytesReceived;
+       }
+
+       /**
+        * The total amount of bytes sent.
+        * 
+        * @return the amount of bytes sent
+        */
+       public long getBytesSent() {
+               return bytesSent;
+       }
+
        /**
         * Start the server (listen on the network for new connections).
         * <p>
@@ -192,16 +231,7 @@ abstract class Server implements Runnable {
 
                try {
                        tracer.trace(name + ": server starting on port " + port + " ("
-                                       + (ssl ? "SSL" : "plain text") + ")");
-
-                       String ciphers = "";
-                       for (String cipher : getAnonCiphers()) {
-                               if (!ciphers.isEmpty()) {
-                                       ciphers += ", ";
-                               }
-                               ciphers += cipher;
-                       }
-                       tracer.trace("Available SSL ciphers: " + ciphers);
+                                       + (key != null ? "encrypted" : "plain text") + ")");
 
                        while (started && !exiting) {
                                count(1);
@@ -209,10 +239,16 @@ abstract class Server implements Runnable {
                                new Thread(new Runnable() {
                                        @Override
                                        public void run() {
+                                               ConnectActionServer action = null;
                                                try {
-                                                       createConnectActionServer(s).connect();
+                                                       action = createConnectActionServer(s);
+                                                       action.connect();
                                                } finally {
                                                        count(-1);
+                                                       if (action != null) {
+                                                               bytesReceived += action.getBytesReceived();
+                                                               bytesSent += action.getBytesSent();
+                                                       }
                                                }
                                        }
                                }).start();
@@ -288,8 +324,7 @@ abstract class Server implements Runnable {
                                exiting = true;
 
                                try {
-                                       new ConnectActionClientObject(createSocket(null, port, ssl))
-                                                       .connect();
+                                       getConnectionToMe().connect();
                                        long time = 0;
                                        while (ss != null && timeout > 0 && timeout > time) {
                                                Thread.sleep(10);
@@ -313,6 +348,20 @@ abstract class Server implements Runnable {
                }
        }
 
+       /**
+        * Return a connection to this server (used by the Exit code to send an exit
+        * message).
+        * 
+        * @return the connection
+        * 
+        * @throws UnknownHostException
+        *             the host should always be NULL (localhost)
+        * @throws IOException
+        *             in case of I/O error
+        */
+       abstract protected ConnectActionClient getConnectionToMe()
+                       throws UnknownHostException, IOException;
+
        /**
         * Change the number of currently serviced actions.
         * 
@@ -342,89 +391,29 @@ abstract class Server implements Runnable {
        }
 
        /**
-        * Create a {@link Socket}.
-        * 
-        * @param host
-        *            the host to connect to
-        * @param port
-        *            the port to connect to
-        * @param ssl
-        *            TRUE for SSL mode (or FALSE for plain text mode)
+        * Return the next ID to use.
         * 
-        * @return the {@link Socket}
-        * 
-        * @throws IOException
-        *             in case of I/O error
-        * @throws UnknownHostException
-        *             if the host is not known
-        * @throws IllegalArgumentException
-        *             if the port parameter is outside the specified range of valid
-        *             port values, which is between 0 and 65535, inclusive
+        * @return the next ID
         */
-       static Socket createSocket(String host, int port, boolean ssl)
-                       throws IOException {
-               Socket s;
-               if (ssl) {
-                       s = SSLSocketFactory.getDefault().createSocket(host, port);
-                       if (s instanceof SSLSocket) {
-                               // Should always be the case
-                               ((SSLSocket) s).setEnabledCipherSuites(ANON_CIPHERS);
-                       }
-               } else {
-                       s = new Socket(host, port);
-               }
-
-               return s;
+       protected synchronized long getNextId() {
+               return id++;
        }
 
        /**
-        * Create a {@link ServerSocket}.
-        * 
-        * @param port
-        *            the port to accept connections on
-        * @param ssl
-        *            TRUE for SSL mode (or FALSE for plain text mode)
-        * 
-        * @return the {@link ServerSocket}
-        * 
-        * @throws IOException
-        *             in case of I/O error
-        * @throws UnknownHostException
-        *             if the IP address of the host could not be determined
-        * @throws IllegalArgumentException
-        *             if the port parameter is outside the specified range of valid
-        *             port values, which is between 0 and 65535, inclusive
-        */
-       static ServerSocket createSocketServer(int port, boolean ssl)
-                       throws IOException {
-               ServerSocket ss;
-               if (ssl) {
-                       ss = SSLServerSocketFactory.getDefault().createServerSocket(port);
-                       if (ss instanceof SSLServerSocket) {
-                               // Should always be the case
-                               ((SSLServerSocket) ss).setEnabledCipherSuites(ANON_CIPHERS);
-                       }
-               } else {
-                       ss = new ServerSocket(port);
-               }
-
-               return ss;
-       }
-
-       /**
-        * Return all the supported ciphers that do not use authentication.
+        * Method called when
+        * {@link ServerObject#onRequest(ConnectActionServerObject, Object, long)}
+        * has successfully finished.
+        * <p>
+        * Can be used to know how much data was transmitted.
         * 
-        * @return the list of such supported ciphers
+        * @param id
+        *            the ID used to identify the request
+        * @param bytesReceived
+        *            the bytes received during the request
+        * @param bytesSent
+        *            the bytes sent during the request
         */
-       public static String[] getAnonCiphers() {
-               List<String> anonCiphers = new ArrayList<String>();
-               for (String cipher : ((SSLSocketFactory) SSLSocketFactory.getDefault())
-                               .getSupportedCipherSuites()) {
-                       if (cipher.contains("_anon_")) {
-                               anonCiphers.add(cipher);
-                       }
-               }
-
-               return anonCiphers.toArray(new String[] {});
+       @SuppressWarnings("unused")
+       protected void onRequestDone(long id, long bytesReceived, long bytesSent) {
        }
 }