SDSU CS 696 Emerging Technologies: Java Distributed Computing
Spring Semester, 1999
RMI SocketFactories
Previous    Lecture Notes Index    Next    
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 09-Mar-99

Contents of Doc 13, RMI SocketFactories


References


Creating a Custom RMI Socket Factory Tutorial
Local Copy: http://www-rohan.sdsu.edu/doc/java/jdk1.2/docs/guide/rmi/rmisocketfactory.doc.html
Sun Site: http://java.sun.com/products/jdk/1.2/docs/guide/rmi/rmisocketfactory.doc.html


Java Remote Method Invocation Specification
Local HTML Copy: http://www-rohan.sdsu.edu/doc/java/jdk1.2/docs/guide/rmi/spec/rmiTOC.doc.html
Sun HTML Site: http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html


Doc 13, RMI SocketFactories Slide # 2

RMI and Security


Java provides security manager to provide controls over what client or server can do a machine

Your application needs to insure proper security manager in installed in application

java.securtiy package is useful in encryption, etc.

Other types of security are your application's problem

RMI addresses encrypting of data over the wire

RMI Wire encryption Process

1. Create a custom socket type that does encryption

2. Create and install a socket factory in you RMI application

We will use xor encryption

exclusive or all bytes in a stream by a mask byte
the byte stream is hard to read by untrained users
exclusive or all bytes a second time by the same mask byte to get original byte stream


Doc 13, RMI SocketFactories Slide # 3

Creating a Custom Socket


1. Subclass FilterOutputStream and FilterInputStream to create streams to be used in the socket

2. Subclass java.net.Socket

3. Subclass java.net.ServerSocket

Doc 13, RMI SocketFactories Slide # 4

XorInputStream


public class XorInputStream extends FilterInputStream {
   byte codeMask = 0;
   
      public XorInputStream(InputStream in, byte mask)  {
      super(in);
      codeMask = mask;
   }
   public int read() throws IOException  {
      int input = in.read();
      if ( input < 0 )
         return input;
      else
         return (byte) input ^ codeMask;
   }
   public int read(byte inputBuffer[], int offset, int length) 
      throws IOException  {
      byte[] codedInput = new byte[length];
      int bytesRead = in.read( codedInput );
      
      for (int k = 0; k < bytesRead;k++)
         inputBuffer[offset + k ] = (byte) 
                              (codedInput[k] ^ codeMask);
      return bytesRead;
   }
}

Doc 13, RMI SocketFactories Slide # 5

XorOutputStream


public class XorOutputStream extends FilterOutputStream {
   byte codeMask = 0;
   
   public XorOutputStream(OutputStream out, byte mask)  {
      super(out);
      codeMask = mask;
   }
   public void write(int output) throws IOException  {
      if ( output < 0 ) //not a byte, {
         out.write(output);
      } else
         out.write( ((byte) output) ^ codeMask );
      }
   public void write(byte output[], int offset, int length) 
      throws IOException  {
      byte[] coded = new byte[length];
      for (int i = 0 ; i < length ; i++)  {
         coded[i] = (byte) ( output[offset + i] ^ (byte) codeMask );
      }
      out.write( coded);
   }
}

Doc 13, RMI SocketFactories Slide # 6

XorSocket


public class XorSocket extends java.net.Socket  {
   /* Streams used by socket */
   private InputStream in;
   private OutputStream out;
   private byte xorMask = 0;
   public XorSocket( byte mask) // This is needed!!
      throws IOException  {
      super();
      xorMask = mask;
   }
   public XorSocket(String host, int port, byte mask) 
      throws IOException {
      super(host, port);
      xorMask = mask;
   }

Doc 13, RMI SocketFactories Slide # 7
XorSocket - Continued

   public InputStream getInputStream() 
      throws IOException  {
      if (in == null)  {
         BufferedInputStream buffered = 
            new BufferedInputStream( super.getInputStream() );
         in = new XorInputStream( buffered , xorMask);
      }
      return in;
   }
   public OutputStream getOutputStream() 
      throws IOException  {
      if (out == null)  {
         BufferedOutputStream buffered = 
            new BufferedOutputStream( super.getOutputStream() );
         out = new XorOutputStream(buffered, xorMask);
      }
      return out;
   }
   public synchronized void close() throws IOException  {
      OutputStream out = getOutputStream();
      out.flush();
      super.close();
   }
}

Doc 13, RMI SocketFactories Slide # 8

XorServerSocket


public class XorServerSocket extends ServerSocket 
   {
   private byte xorMask = 0;
   
   public XorServerSocket(int port, byte mask) 
      throws IOException 
      {
      super(port);
      xorMask = mask;
      }
   public XorServerSocket(int port, int backlog, byte mask) 
      throws IOException 
      {
      super(port, backlog);
      xorMask = mask;
      }
   public XorServerSocket(int port, 
                           int backlog,  
                           InetAddress bindAddress, 
                           byte mask) 
      throws IOException 
      {
      super(port, backlog, bindAddress);
      xorMask = mask;
      }
   public Socket accept() throws IOException 
      {
      Socket socket = new XorSocket( xorMask );
      implAccept(socket);
      return socket;
      }
   }

Note ServerSocket uses the Strategy and Prototype patterns

Doc 13, RMI SocketFactories Slide # 9

Creating a Custom RMISocketFactory

We need a SocketFactory for both the client and the server side.

Java.rmi.server.RMIClientSocketFactory

Interface with one method

Socket createSocket(String host, int port)
Create a client socket connected to the specified host and port.

You should also implement the equals() and hashCode() method
If you do not do this, the client does not reuse sockets to the server. There are reports of client creating hundreds of sockets to a server. When the hashCode and equals methods were added to the RMIClientSocketFactory, the client created less than 5 sockets.

All RMIClientSocketFactory subclasses must be serializable

Java.rmi.server.RMIClientSocketFactory

Interface with one method

Socket createServerSocket(String host, int port)
Create a server socket connected to the specified host and port.

I do not think the equals() and hashCode() method are needed in the RMIClientSocketFactory subclasses. The examples from Sun do make RMIClientSocketFactory subclasses serializable.


Doc 13, RMI SocketFactories Slide # 10

XorClientSocketFactory

package whitney.rmi.examples.sockets;
import java.io.IOException;
import java.io.Serializable;
import java.rmi.server.RMIClientSocketFactory;
import java.net.Socket;
import sdsu.net.XorSocket;
public final class XorClientSocketFactory implements 
      RMIClientSocketFactory, Serializable {
   private byte xorMask = 0;
   
   public XorClientSocketFactory( byte mask ) { xorMask = mask; }
   
   public Socket createSocket( String host, int port ) 
      throws IOException {
      return new XorSocket( host, port, xorMask );
   }
   
   public boolean equals(Object aSocketFactory ) {
      if (! (aSocketFactory instanceof XorClientSocketFactory) )
         return false;
      
      byte otherMask = 
         ((XorClientSocketFactory) aSocketFactory).xorMask;
      if ( otherMask == xorMask )
         return true;
      else
         return false;
      }
   
   public int hashCode() { return xorMask; }
   }

Doc 13, RMI SocketFactories Slide # 11

XorServerSocketFactory

package whitney.rmi.examples.sockets;
import java.io.IOException;
import java.io.Serializable;
import java.rmi.server.RMIServerSocketFactory;
import java.net.ServerSocket;
import sdsu.net.XorServerSocket;
public final class XorServerSocketFactory implements 
      RMIServerSocketFactory, Serializable {
   private byte xorMask = 0;
   
   public XorServerSocketFactory( byte mask ) { xorMask = mask; }
   
   public ServerSocket createServerSocket( int port ) 
      throws IOException {
      return new XorServerSocket( port, xorMask );
      }
   
   public boolean equals(Object aSocketFactory ) {
      if (! (aSocketFactory instanceof XorServerSocketFactory) )
         return false;
      
      byte otherMask = 
         ((XorServerSocketFactory) aSocketFactory).xorMask;
      if ( otherMask == xorMask )
         return true;
      else
         return false;
   }
   
   public int hashCode() { return xorMask; }
}

Doc 13, RMI SocketFactories Slide # 12

Using The Socket Factories

Server Side
package whitney.rmi.examples.sockets;
import java.net.InetAddress;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class HelloServer 
   extends UnicastRemoteObject implements Hello  {
   public HelloServer(byte mask ) throws RemoteException  {
      super(0, new XorClientSocketFactory( mask),  
                  new XorServerSocketFactory( mask) );
   }
   public String sayHello()  { return  "Hello World from " + getHostName(); }
   protected static String getHostName()  {
      try  {
         return InetAddress.getLocalHost().getHostName();
      } catch (java.net.UnknownHostException who)  {
         return "Unknown";
      }
   }
   public static void main(String args[]) throws Exception {
      System.setSecurityManager(new RMISecurityManager());
      
      Naming.rebind("rmi://eli.sdsu.edu/HelloA", 
            new HelloServer( (byte)12) );
      Naming.rebind("rmi://eli.sdsu.edu/HelloB", 
            new HelloServer( (byte)42) );
      System.out.println("HelloServer bound in registry");
   }
}

Doc 13, RMI SocketFactories Slide # 13
Client Side
package whitney.rmi.examples.sockets;
import java.rmi.*;
import java.net.MalformedURLException;
public class HelloClient 
   {
   public static void main(String args[]) throws Exception
      {
       Hello remoteA = 
         (Hello) Naming.lookup(  "rmi://eli.sdsu.edu/HelloA");
       System.out.println( "From Server A " +  remoteA.sayHello() );
       Hello remoteB = 
         (Hello) Naming.lookup( "rmi://eli.sdsu.edu/HelloB");
       System.out.println( "From Server B " +  remoteB.sayHello() );
      }
   }
Since a XorClientSocketFactory object is downloaded to the client the XorClientSocketFactory class must be available to the client code at runtime.

Doc 13, RMI SocketFactories Slide # 14

Multiple Socket Factory

import java.io.*;
import java.net.*;
import java.rmi.server.*;
public class MultiClientSocketFactory
   implements RMIClientSocketFactory, Serializable {
   private static RMISocketFactory defaultFactory =
         RMISocketFactory.getDefaultSocketFactory();
   private String protocol;
   private byte[] data;
   public MultiClientSocketFactory(String protocol, byte[] data) {
      this.protocol = protocol;
      this.data = data;
   }  
   
   public Socket createSocket(String host, int port) throws IOException {
      if (protocol.equals("compression")) {
         return new CompressionSocket(host, port);
      } else if (protocol.equals("xor")) {
         if (data == null || data.length != 1)
            throw new IOException("invalid argument for XOR protocol");
         return new XorSocket(host, port, data[0]);
      }
      
      return defaultFactory.createSocket(host, port);
   }
}
We can have a factory return more than type of socket. This example is from Sun’s Creating a Custom RMI Socket Factory tutorial.

Copyright ©, All rights reserved.
1999 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.

Previous    visitors since 09-Mar-99    Next