home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1997 May / Pcwk0597.iso / sybase / starbuck / java.z / PlainSocketImpl.java < prev    next >
Text File  |  1996-05-03  |  10KB  |  372 lines

  1. /*
  2.  * @(#)PlainSocketImpl.java    1.17 96/02/29 Jonathan Payne
  3.  *
  4.  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.net;
  21.  
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.io.InterruptedIOException;
  26. import java.io.FileDescriptor;
  27. import java.io.ByteArrayOutputStream;
  28.  
  29. /**
  30.  * Default Socket Implementation. This implementation does
  31.  * not implement any security checks.  It does support SOCKS version 4.
  32.  * Note this class should <b>NOT</b> be public.
  33.  *
  34.  * @version     1.17, 29 Feb 1996
  35.  * @author     Jonathan Payne
  36.  * @author     Arthur van Hoff
  37.  * @author    Steven B. Byrne
  38.  */
  39. class PlainSocketImpl extends SocketImpl
  40. {
  41.     /* SOCKS related constants */
  42.  
  43.     private static final int SOCKS_PROTO_VERS        = 4;
  44.     private static final int SOCKS_REPLY_VERS        = 4;
  45.  
  46.     private static final int COMMAND_CONNECT        = 1;
  47.     private static final int COMMAND_BIND        = 2;
  48.  
  49.     private static final int REQUEST_GRANTED        = 90;
  50.     private static final int REQUEST_REJECTED        = 91;
  51.     private static final int REQUEST_REJECTED_NO_IDENTD  = 92;
  52.     private static final int REQUEST_REJECTED_DIFF_IDENTS = 93;
  53.  
  54.     public static final String socksServerProp        = "socksProxyHost";
  55.     public static final String socksPortProp        = "socksProxyPort";
  56.  
  57.     public static final String socksDefaultPortStr    = "1080";
  58.  
  59.     /**
  60.      * Load net library into runtime.
  61.      */
  62.     static {
  63.     System.loadLibrary("net");
  64.     }
  65.  
  66.     /**
  67.      * Creates a socket with a boolean that specifies whether this
  68.      * is a stream socket or a datagram socket.
  69.      * @param stream the stream to be created
  70.      */
  71.     protected synchronized void create(boolean stream) throws IOException {
  72.     fd = new FileDescriptor();
  73.     socketCreate(stream);
  74.     }
  75.  
  76.     /** 
  77.      * Creates a socket and connects it to the specified port on
  78.      * the specified host.
  79.      * @param host the specified host
  80.      * @param port the specified port 
  81.      */
  82.     protected void connect(String host, int port)
  83.         throws UnknownHostException, IOException
  84.     {
  85.     IOException pending = null;
  86.     try {
  87.         InetAddress address = InetAddress.getByName(host);
  88.  
  89.         try {
  90.         connectToAddress(address, port);
  91.         return;
  92.         } catch (IOException e) {
  93.         pending = e;
  94.         }
  95.     } catch (UnknownHostException e) {
  96.         pending = e;
  97.     }
  98.  
  99.     // everything failed
  100.     socketClose();
  101.     throw pending;
  102.     }
  103.  
  104.     /** 
  105.      * Creates a socket and connects it to the specified address on
  106.      * the specified port.
  107.      * @param address the address
  108.      * @param port the specified port
  109.      */
  110.     protected void connect(InetAddress address, int port) throws IOException {
  111.     this.port = port;
  112.     this.address = address;
  113.  
  114.     try {
  115.         connectToAddress(address, port);
  116.         return;
  117.     } catch (IOException e) {
  118.         // everything failed
  119.         socketClose();
  120.         throw e;
  121.     }
  122.     }
  123.  
  124.     private void connectToAddress(InetAddress address, int port) throws IOException {
  125.     if (usingSocks()) {
  126.         doSOCKSConnect(address, port);
  127.     } else {
  128.         doConnect(address, port);
  129.     }
  130.     }
  131.     
  132.     /**
  133.      * Connect to the SOCKS server using the SOCKS connection protocol.
  134.      */
  135.     private void doSOCKSConnect(InetAddress address, int port) throws IOException {
  136.     connectToSocksServer();
  137.  
  138.     sendSOCKSCommandPacket(COMMAND_CONNECT, address, port);
  139.  
  140.     int protoStatus = getSOCKSReply();
  141.  
  142.     switch (protoStatus) {
  143.       case REQUEST_GRANTED:
  144.         // connection set up, return control to the socket client
  145.         return;
  146.  
  147.       case REQUEST_REJECTED:
  148.       case REQUEST_REJECTED_NO_IDENTD:
  149.         throw new SocketException("SOCKS server cannot conect to identd");
  150.  
  151.       case REQUEST_REJECTED_DIFF_IDENTS:
  152.         throw new SocketException("User name does not match identd name");
  153.     }
  154.     }
  155.     
  156.  
  157.     /**
  158.      * Read the response from the socks server.  Return the result code.
  159.      */
  160.     private int getSOCKSReply() throws IOException {
  161.     InputStream in = getInputStream();
  162.  
  163.     // REMIND: this could deal with reading < 8 bytes and buffering
  164.     // them up.
  165.  
  166.     byte response[] = new byte[8];
  167.  
  168.     int code;
  169.     if ((code = in.read(response)) != response.length) {
  170.         throw new SocketException("Malformed reply from SOCKS server");
  171.     }
  172.  
  173.     if (response[0] != 0) { // should be version 0
  174.         throw new SocketException("Malformed reply from SOCKS server");
  175.     }
  176.  
  177.     return response[1];    // the response code
  178.     }
  179.  
  180.     /**
  181.      * Just set up a connection to the SOCKS server and return.  The caller
  182.      * needs to handle the SOCKS initiation protocol with the server after
  183.      * the connection is established.
  184.      */
  185.     private void connectToSocksServer() throws IOException {
  186.  
  187.     String socksServerString = System.getProperty(socksServerProp);
  188.     if (socksServerString == null) {
  189.         // REMIND: this is too trusting of its (internal) callers --
  190.         // needs to robustly assert that SOCKS are in fact being used,
  191.         // and signal an error (in some manner) if SOCKS are not being
  192.         // used.
  193.         return;
  194.     }
  195.  
  196.     InetAddress socksServer = InetAddress.getByName(socksServerString);
  197.  
  198.     String socksPortString = System.getProperty(socksPortProp,
  199.                             socksDefaultPortStr);
  200.  
  201.     int socksServerPort;
  202.     try {
  203.         socksServerPort = Integer.parseInt(socksPortString);
  204.     } catch (Exception e) {
  205.         throw new SocketException("Bad port number format");
  206.     }
  207.     
  208.     doConnect(socksServer, socksServerPort);
  209.     }
  210.  
  211.  
  212.     /**
  213.      * The workhorse of the connection operation.  Tries several times to
  214.      * establish a connection to the given <host, port>.  If unsuccessful,
  215.      * throws an IOException indicating what went wrong.
  216.      */
  217.  
  218.     private void doConnect(InetAddress address, int port) throws IOException {
  219.     IOException pending = null;
  220.  
  221.     for (int i = 0 ; i < 3 ; i++) {
  222.         try {
  223.         socketConnect(address, port);
  224.         return;
  225.         } catch (ProtocolException e) {
  226.         // Try again in case of a protocol exception
  227.         socketClose();
  228.         fd = new FileDescriptor();
  229.         socketCreate(true);
  230.         pending = e;
  231.         } catch (IOException e) {
  232.         // Let someone else deal with this exception
  233.         socketClose();
  234.         throw e;
  235.         }
  236.     }
  237.  
  238.     // failed to connect -- tell our client the bad news
  239.     socketClose();
  240.     throw pending;
  241.     }
  242.  
  243.  
  244.     /**
  245.      * Just creates and sends out to the connected socket a SOCKS command
  246.      * packet.
  247.      */
  248.     private void sendSOCKSCommandPacket(int command, InetAddress address,
  249.                     int port) throws IOException {
  250.     
  251.         byte commandPacket[] = makeCommandPacket(command, address, port);
  252.     OutputStream out = getOutputStream();
  253.  
  254.     out.write(commandPacket);
  255.     }
  256.  
  257.     /**
  258.      * Create and return a SOCKS V4 command packet.
  259.      */
  260.     private byte[] makeCommandPacket(int command, InetAddress address,
  261.                     int port) { 
  262.  
  263.     // base packet size = 8, + 1 null byte 
  264.     ByteArrayOutputStream byteStream = new ByteArrayOutputStream(8 + 1);
  265.  
  266.     byteStream.write(SOCKS_PROTO_VERS);
  267.     byteStream.write(command);
  268.  
  269.  
  270.     byteStream.write((port >> 8) & 0xff);
  271.     byteStream.write((port >> 0) & 0xff);
  272.  
  273.     byte addressBytes[] = address.getAddress();
  274.     byteStream.write(addressBytes, 0, addressBytes.length);
  275.  
  276.     String userName = System.getProperty("user.name");
  277.     byte userNameBytes[] = new byte[userName.length()];
  278.     userName.getBytes(0, userName.length(), userNameBytes, 0);
  279.  
  280.     byteStream.write(userNameBytes, 0, userNameBytes.length);
  281.     byteStream.write(0);    // null termination for user name
  282.  
  283.     return byteStream.toByteArray();
  284.     }
  285.  
  286.     /**
  287.      * Returns true if implementation should use the SOCKS protocol
  288.      * (i.e. the user has set the required properties to enable SOCKS to
  289.      * be used).
  290.      */
  291.     private boolean usingSocks() {
  292.     return (System.getProperty(socksServerProp) != null);
  293.     }
  294.     
  295.  
  296.     /**
  297.      * Binds the socket to the specified address of the specified local port.
  298.      * @param address the address
  299.      * @param port the port
  300.      */
  301.     protected synchronized void bind(InetAddress address, int lport) 
  302.     throws IOException
  303.     {
  304.     socketBind(address, lport);
  305.     }
  306.  
  307.     /**
  308.      * Listens, for a specified amount of time, for connections.
  309.      * @param count the amount of time to listen for connections
  310.      */
  311.     protected synchronized void listen(int count) throws IOException {
  312.     socketListen(count);
  313.     }
  314.  
  315.     /**
  316.      * Accepts connections.
  317.      * @param s the connection
  318.      */
  319.     protected synchronized void accept(SocketImpl s) throws IOException {
  320.     socketAccept(s);
  321.     }
  322.  
  323.     /**
  324.      * Gets an InputStream for this socket.
  325.      */
  326.     protected synchronized InputStream getInputStream() throws IOException {
  327.     return new SocketInputStream(this);
  328.     }
  329.  
  330.     /**
  331.      * Gets an OutputStream for this socket.
  332.      */
  333.     protected synchronized OutputStream getOutputStream() throws IOException {
  334.     return new SocketOutputStream(this);
  335.     }
  336.  
  337.     /**
  338.      * Returns the number of bytes that can be read without blocking.
  339.      */
  340.     protected synchronized int available() throws IOException {
  341.     return socketAvailable();
  342.     }
  343.  
  344.     /**
  345.      * Closes the socket.
  346.      */
  347.     protected synchronized void close() throws IOException {
  348.     if (fd != null) socketClose();
  349.     }
  350.  
  351.     /**
  352.      * Cleans up if the user forgets to close it.
  353.      */
  354.     protected synchronized void finalize() throws IOException {
  355.     if (fd != null) socketClose();
  356.     }
  357.  
  358.     private native void socketCreate(boolean stream) throws IOException;
  359.     private native void socketConnect(InetAddress address, int port)
  360.     throws IOException;
  361.     private native void socketBind(InetAddress address, int port)
  362.     throws IOException;
  363.     private native void socketListen(int count)
  364.     throws IOException;
  365.     private native void socketAccept(SocketImpl s)
  366.     throws IOException;
  367.     private native int socketAvailable()
  368.     throws IOException;
  369.     private native void socketClose()
  370.     throws IOException;
  371. }
  372.