home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / net / PlainSocketImpl.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  13.1 KB  |  467 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)PlainSocketImpl.java    1.32 98/07/07
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.net;
  16.  
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.io.InterruptedIOException;
  21. import java.io.FileDescriptor;
  22. import java.io.ByteArrayOutputStream;
  23.  
  24. /**
  25.  * Default Socket Implementation. This implementation does
  26.  * not implement any security checks.  It does support SOCKS version 4.
  27.  * Note this class should <b>NOT</b> be public.
  28.  *
  29.  * @author  Steven B. Byrne
  30.  * @version 1.32, 07/07/98
  31.  */
  32. class PlainSocketImpl extends SocketImpl
  33. {
  34.     /* instance variable for SO_TIMEOUT */
  35.     int timeout;   // timeout in millisec
  36.  
  37.     /* SOCKS related constants */
  38.  
  39.     private static final int SOCKS_PROTO_VERS        = 4;
  40.     private static final int SOCKS_REPLY_VERS        = 4;
  41.  
  42.     private static final int COMMAND_CONNECT        = 1;
  43.     private static final int COMMAND_BIND        = 2;
  44.  
  45.     private static final int REQUEST_GRANTED        = 90;
  46.     private static final int REQUEST_REJECTED        = 91;
  47.     private static final int REQUEST_REJECTED_NO_IDENTD  = 92;
  48.     private static final int REQUEST_REJECTED_DIFF_IDENTS = 93;
  49.  
  50.     public static final String socksServerProp        = "socksProxyHost";
  51.     public static final String socksPortProp        = "socksProxyPort";
  52.  
  53.     public static final String socksDefaultPortStr    = "1080";
  54.  
  55.     /**
  56.      * Load net library into runtime.
  57.      */
  58.     static {
  59.     java.security.AccessController.doPrivileged(
  60.           new sun.security.action.LoadLibraryAction("net"));
  61.     initProto();
  62.     }
  63.  
  64.     /**
  65.      * Creates a socket with a boolean that specifies whether this
  66.      * is a stream socket (true) or an unconnected UDP socket (false).
  67.      */
  68.     protected synchronized void create(boolean stream) throws IOException {
  69.     fd = new FileDescriptor();
  70.     socketCreate(stream);
  71.     }
  72.  
  73.     /**
  74.      * Creates a socket and connects it to the specified port on
  75.      * the specified host.
  76.      * @param host the specified host
  77.      * @param port the specified port
  78.      */
  79.     protected void connect(String host, int port)
  80.         throws UnknownHostException, IOException
  81.     {
  82.     IOException pending = null;
  83.     try {
  84.         InetAddress address = InetAddress.getByName(host);
  85.  
  86.         try {
  87.         connectToAddress(address, port);
  88.         return;
  89.         } catch (IOException e) {
  90.         pending = e;
  91.         }
  92.     } catch (UnknownHostException e) {
  93.         pending = e;
  94.     }
  95.  
  96.     // everything failed
  97.     close();
  98.     throw pending;
  99.     }
  100.  
  101.     /**
  102.      * Creates a socket and connects it to the specified address on
  103.      * the specified port.
  104.      * @param address the address
  105.      * @param port the specified port
  106.      */
  107.     protected void connect(InetAddress address, int port) throws IOException {
  108.     this.port = port;
  109.     this.address = address;
  110.  
  111.     try {
  112.         connectToAddress(address, port);
  113.         return;
  114.     } catch (IOException e) {
  115.         // everything failed
  116.         close();
  117.         throw e;
  118.     }
  119.     }
  120.  
  121.     private void connectToAddress(InetAddress address, int port) throws IOException {
  122.     if (usingSocks()) {
  123.         doSOCKSConnect(address, port);
  124.     } else {
  125.         doConnect(address, port);
  126.     }
  127.     }
  128.  
  129.     public void setOption(int opt, Object val) throws SocketException {
  130.     boolean on = true;
  131.     switch (opt) {
  132.         /* check type safety b4 going native.  These should never
  133.          * fail, since only java.Socket* has access to
  134.          * PlainSocketImpl.setOption().
  135.          */
  136.     case SO_LINGER:
  137.         if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
  138.         throw new SocketException("Bad parameter for option");
  139.         if (val instanceof Boolean) {
  140.         /* true only if disabling - enabling should be Integer */
  141.         on = false;
  142.         }
  143.         break;
  144.     case SO_TIMEOUT:
  145.         if (val == null || (!(val instanceof Integer)))
  146.         throw new SocketException("Bad parameter for SO_TIMEOUT");
  147.         int tmp = ((Integer) val).intValue();
  148.         if (tmp < 0)
  149.         throw new IllegalArgumentException("timeout < 0");
  150.         timeout = tmp;
  151.         return;
  152.     case SO_BINDADDR:
  153.         throw new SocketException("Cannot re-bind socket");
  154.     case TCP_NODELAY:
  155.         if (val == null || !(val instanceof Boolean))
  156.         throw new SocketException("bad parameter for TCP_NODELAY");
  157.         on = ((Boolean)val).booleanValue();
  158.         break;
  159.     case SO_SNDBUF:
  160.     case SO_RCVBUF:
  161.         if (val == null || !(val instanceof Integer) ||
  162.         !(((Integer)val).intValue() > 0)) {
  163.         throw new SocketException("bad parameter for SO_SNDBUF " +
  164.                       "or SO_RCVBUF");
  165.         }
  166.         break;
  167.     default:
  168.         throw new SocketException("unrecognized TCP option: " + opt);
  169.     }
  170.     socketSetOption(opt, on, val);
  171.     }
  172.  
  173.     public Object getOption(int opt) throws SocketException {
  174.     if (opt == SO_TIMEOUT) {
  175.         return new Integer(timeout);
  176.     }
  177.     int ret = socketGetOption(opt);
  178.     /*
  179.      * The native socketGetOption() knows about 3 options.
  180.      * The 32 bit value it returns will be interpreted according
  181.      * to what we're asking.  A return of -1 means it understands
  182.      * the option but its turned off.  It will raise a SocketException
  183.      * if "opt" isn't one it understands.
  184.      */
  185.  
  186.     switch (opt) {
  187.     case TCP_NODELAY:
  188.         return (ret == -1) ? new Boolean(false): new Boolean(true);
  189.     case SO_LINGER:
  190.         return (ret == -1) ? new Boolean(false): (Object)(new Integer(ret));
  191.     case SO_BINDADDR:
  192.         InetAddress in = new InetAddress();
  193.         in.address = ret;
  194.         return in;
  195.     case SO_SNDBUF:
  196.         case SO_RCVBUF:
  197.         return new Integer(ret);
  198.     // should never get here
  199.     default:
  200.         return null;
  201.     }
  202.     }
  203.  
  204.     /**
  205.      * Connect to the SOCKS server using the SOCKS connection protocol.
  206.      */
  207.     private void doSOCKSConnect(InetAddress address, int port)
  208.     throws IOException {
  209.     connectToSocksServer();
  210.  
  211.     sendSOCKSCommandPacket(COMMAND_CONNECT, address, port);
  212.  
  213.     int protoStatus = getSOCKSReply();
  214.  
  215.     switch (protoStatus) {
  216.       case REQUEST_GRANTED:
  217.         // connection set up, return control to the socket client
  218.         return;
  219.  
  220.       case REQUEST_REJECTED:
  221.       case REQUEST_REJECTED_NO_IDENTD:
  222.         throw new SocketException("SOCKS server cannot conect to identd");
  223.  
  224.       case REQUEST_REJECTED_DIFF_IDENTS:
  225.         throw new SocketException("User name does not match identd name");
  226.     }
  227.     }
  228.  
  229.  
  230.     /**
  231.      * Read the response from the socks server.  Return the result code.
  232.      */
  233.     private int getSOCKSReply() throws IOException {
  234.     InputStream in = getInputStream();
  235.     byte response[] = new byte[8];
  236.         int bytesReceived = 0;
  237.         int len = response.length;
  238.  
  239.     for (int attempts = 0; bytesReceived<len &&  attempts<3; attempts++) {
  240.         int count = in.read(response, bytesReceived, len - bytesReceived);
  241.         if (count < 0)
  242.         throw new SocketException("Malformed reply from SOCKS server");
  243.         bytesReceived += count;
  244.     }
  245.  
  246.      if (bytesReceived != len) {
  247.          throw new SocketException("Reply from SOCKS server has bad length: " + bytesReceived);
  248.       }
  249.  
  250.     if (response[0] != 0) { // should be version0 
  251.         throw new SocketException("Reply from SOCKS server has bad version " + response[0]);
  252.     }
  253.  
  254.     return response[1];    // the response code
  255.     }
  256.  
  257.     /**
  258.      * Just set up a connection to the SOCKS server and return.  The caller
  259.      * needs to handle the SOCKS initiation protocol with the server after
  260.      * the connection is established.
  261.      */
  262.     private void connectToSocksServer() throws IOException {
  263.  
  264.     String socksServerString = null;
  265.     String socksPortString = null;
  266.  
  267.     socksServerString = (String) java.security.AccessController.doPrivileged(
  268.                new sun.security.action.GetPropertyAction(socksServerProp));
  269.     socksPortString = (String) java.security.AccessController.doPrivileged(
  270.                new sun.security.action.GetPropertyAction(socksPortProp,
  271.                              socksDefaultPortStr));
  272.  
  273.     if (socksServerString == null) {
  274.         // REMIND: this is too trusting of its (internal) callers --
  275.         // needs to robustly assert that SOCKS are in fact being used,
  276.         // and signal an error (in some manner) if SOCKS are not being
  277.         // used.
  278.         return;
  279.     }
  280.  
  281.     InetAddress socksServer = InetAddress.getByName(socksServerString);
  282.  
  283.     int socksServerPort;
  284.     try {
  285.         socksServerPort = Integer.parseInt(socksPortString);
  286.     } catch (Exception e) {
  287.         throw new SocketException("Bad port number format");
  288.     }
  289.  
  290.     doConnect(socksServer, socksServerPort);
  291.     }
  292.  
  293.  
  294.     /**
  295.      * The workhorse of the connection operation.  Tries several times to
  296.      * establish a connection to the given <host, port>.  If unsuccessful,
  297.      * throws an IOException indicating what went wrong.
  298.      */
  299.  
  300.     private void doConnect(InetAddress address, int port) throws IOException {
  301.     IOException pending = null;
  302.  
  303.     for (int i = 0 ; i < 3 ; i++) {
  304.         try {
  305.         socketConnect(address, port);
  306.         return;
  307.         } catch (ProtocolException e) {
  308.         // Try again in case of a protocol exception
  309.         close();
  310.         fd = new FileDescriptor();
  311.         socketCreate(true);
  312.         pending = e;
  313.         } catch (IOException e) {
  314.         // Let someone else deal with this exception
  315.         close();
  316.         throw e;
  317.         }
  318.     }
  319.  
  320.     // failed to connect -- tell our client the bad news
  321.     close();
  322.     throw pending;
  323.     }
  324.  
  325.  
  326.     /**
  327.      * Just creates and sends out to the connected socket a SOCKS command
  328.      * packet.
  329.      */
  330.     private void sendSOCKSCommandPacket(int command, InetAddress address,
  331.                     int port) throws IOException {
  332.  
  333.         byte commandPacket[] = makeCommandPacket(command, address, port);
  334.     OutputStream out = getOutputStream();
  335.  
  336.     out.write(commandPacket);
  337.     }
  338.  
  339.     /**
  340.      * Create and return a SOCKS V4 command packet.
  341.      */
  342.     private byte[] makeCommandPacket(int command, InetAddress address,
  343.                     int port) {
  344.  
  345.     // base packet size = 8, + 1 null byte
  346.     ByteArrayOutputStream byteStream = new ByteArrayOutputStream(8 + 1);
  347.  
  348.     byteStream.write(SOCKS_PROTO_VERS);
  349.     byteStream.write(command);
  350.  
  351.  
  352.     byteStream.write((port >> 8) & 0xff);
  353.     byteStream.write((port >> 0) & 0xff);
  354.  
  355.     byte addressBytes[] = address.getAddress();
  356.     byteStream.write(addressBytes, 0, addressBytes.length);
  357.  
  358.     String userName = (String) java.security.AccessController.doPrivileged(
  359.                new sun.security.action.GetPropertyAction("user.name"));
  360.  
  361.     byte userNameBytes[] = new byte[userName.length()];
  362.     userName.getBytes(0, userName.length(), userNameBytes, 0);
  363.  
  364.     byteStream.write(userNameBytes, 0, userNameBytes.length);
  365.     byteStream.write(0);    // null termination for user name
  366.  
  367.     return byteStream.toByteArray();
  368.     }
  369.  
  370.     /**
  371.      * Returns true if implementation should use the SOCKS protocol
  372.      * (i.e. the user has set the required properties to enable SOCKS to
  373.      * be used).
  374.      */
  375.     private boolean usingSocks() {
  376.     String ssp = (String) java.security.AccessController.doPrivileged(
  377.                new sun.security.action.GetPropertyAction(socksServerProp));
  378.     return (ssp != null);
  379.     }
  380.  
  381.  
  382.     /**
  383.      * Binds the socket to the specified address of the specified local port.
  384.      * @param address the address
  385.      * @param port the port
  386.      */
  387.     protected synchronized void bind(InetAddress address, int lport)
  388.     throws IOException
  389.     {
  390.     socketBind(address, lport);
  391.     }
  392.  
  393.     /**
  394.      * Listens, for a specified amount of time, for connections.
  395.      * @param count the amount of time to listen for connections
  396.      */
  397.     protected synchronized void listen(int count) throws IOException {
  398.     socketListen(count);
  399.     }
  400.  
  401.     /**
  402.      * Accepts connections.
  403.      * @param s the connection
  404.      */
  405.     protected synchronized void accept(SocketImpl s) throws IOException {
  406.     socketAccept(s);
  407.     }
  408.  
  409.     /**
  410.      * Gets an InputStream for this socket.
  411.      */
  412.     protected synchronized InputStream getInputStream() throws IOException {
  413.     return new SocketInputStream(this);
  414.     }
  415.  
  416.     /**
  417.      * Gets an OutputStream for this socket.
  418.      */
  419.     protected synchronized OutputStream getOutputStream() throws IOException {
  420.     return new SocketOutputStream(this);
  421.     }
  422.  
  423.     /**
  424.      * Returns the number of bytes that can be read without blocking.
  425.      */
  426.     protected synchronized int available() throws IOException {
  427.         if (fd == null)
  428.             throw new IOException("Stream closed.");
  429.     return socketAvailable();
  430.     }
  431.  
  432.     /**
  433.      * Closes the socket.
  434.      */
  435.     protected void close() throws IOException {
  436.     if (fd != null) {
  437.         socketClose();
  438.         fd = null;
  439.     }
  440.     }
  441.  
  442.     /**
  443.      * Cleans up if the user forgets to close it.
  444.      */
  445.     protected void finalize() throws IOException {
  446.     close();
  447.     }
  448.  
  449.     private native void socketCreate(boolean isServer) throws IOException;
  450.     private native void socketConnect(InetAddress address, int port)
  451.     throws IOException;
  452.     private native void socketBind(InetAddress address, int port)
  453.     throws IOException;
  454.     private native void socketListen(int count)
  455.     throws IOException;
  456.     private native void socketAccept(SocketImpl s)
  457.     throws IOException;
  458.     private native int socketAvailable()
  459.     throws IOException;
  460.     private native void socketClose()
  461.     throws IOException;
  462.     private static native void initProto();
  463.     private native void socketSetOption(int cmd, boolean on, Object value)
  464.     throws SocketException;
  465.     private native int socketGetOption(int opt) throws SocketException;
  466. }
  467.