Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4468846

Backward incompatible change to unconnected Socket handling.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.4.0
    • core-libs
    • generic
    • generic



      Name: bsC130419 Date: 06/12/2001


      java version "1.4.0-beta"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta-b65)
      Java HotSpot(TM) Client VM (build 1.4.0-beta-b65, mixed mode)

      When using the protected Socket constructor that takes a SocketImpl, and
      binding and making the connection via the SocketImpl, the new error handling in
      the Socket class throws a SocketException when getting the InputStream or the
      OutputStream of the Socket.

      The source code below is a simple application that connects to an "echo"
      server. It could easily be implemented without using the Socket(SocketImpl)
      constructor, but serves to illustrate the problem:


      import java.io.InputStream;
      import java.io.OutputStream;
      import java.io.IOException;
      import java.net.InetAddress;
      import java.net.Socket;
      import java.net.SocketException;
      import java.net.SocketImpl;

      /**
       * A simple subclass of Socket that uses the protected Socket() constructor that
       * takes a SocketImpl.
       */
      public class UnconnectedSocketTest extends Socket {
          public UnconnectedSocketTest(UnconnectedSocketImpl impl, String address)
              throws IOException
          {
              super(impl);
              try {
                  impl.bind(InetAddress.getLocalHost(), 0);
                  impl.connect(InetAddress.getByName(address), 7);
              } catch (IOException e) {
                  impl.close();
                  throw e;
              }
          }

          public static final void main(String[] args) throws IOException {
              if (args.length != 1) {
                  System.out.println("Usage: java UnconnectedSocketTest <address>");
                  System.exit(-1);
              }
              
              Socket s = new UnconnectedSocketTest(new UnconnectedSocketImpl(),
                                                   args[0]);

              new ReadWriteThread(s.getInputStream(), System.out).start();
              new ReadWriteThread(System.in, s.getOutputStream()).start();
          }
      }

      class UnconnectedSocketImpl extends SocketImpl {
          private InetAddress localAddr;
          private int localPort;
          private Socket socket;

          UnconnectedSocketImpl() {}

          protected void bind(InetAddress host, int port) throws IOException {
              localAddr = host;
              localPort = port;
          }

          protected void connect(InetAddress address, int port) throws IOException {
              socket = new Socket(address, port, localAddr, localPort);
          }
          protected void close() throws IOException {
              socket.close();
          }
          protected InputStream getInputStream() throws IOException {
              return socket.getInputStream();
          }
          protected OutputStream getOutputStream() throws IOException {
              return socket.getOutputStream();
          }
          public void setOption(int opt, Object val) throws SocketException {
              throw new SocketException("setOption not implemented");
          }
          public Object getOption(int opt) throws SocketException {
              throw new SocketException("getOption not implemented");
          }
          protected int available() throws IOException {
              throw new SocketException("available not implemented");
          }
          protected void accept(SocketImpl s) throws IOException {
              throw new IOException("accept not implemented");
          }
          protected void listen(int backlog) throws IOException {
              throw new IOException("listen not implemented");
          }
          protected void connect(String host, int port) throws IOException {
              throw new IOException("connect(host,port) not implemented");
          }
          protected void create(boolean stream) throws IOException {
              throw new IOException("create not implemented");
          }
          
      }

      class ReadWriteThread extends Thread {
          OutputStream write;
          InputStream read;

          ReadWriteThread(InputStream read, OutputStream write) {
              super();
              this.read = read;
              this.write = write;
          }
              
          public void run() {
              while (true) {
                  try {
                      int available = read.available();
                      if (available > 0) {
                          byte[] buffer = new byte[available];
                          read.read(buffer, 0, available);
                          write.write(buffer, 0, available);
                      } else {
                          try {
                              Thread.sleep(1000);
                          } catch (InterruptedException e) {}
                      }
                  } catch (IOException e) {}
              }
          }
      }


      Upon running this in a 1.1, 1.2 or 1.3 JVM, the behaviour is that standard
      input is sent to the echo server, and whatever the server sends back is
      displayed on standard output.

      Under 1.4-beta, the following error occurs:
      Exception in thread "main" java.net.SocketException: Socket is not connected
              at java.net.Socket.getOutputStream(Socket.java:587)
              at UnconnectedSocketTest.main(UnconnectedSocketTest.java:32)

      This is definitely untrue, as a network trace shows the SYN and SYN-ACK packets
      being sent across.


      This is being caused by the private boolean variable "connected" in the Socket
      class, which is unable to be set from subclasses of Socket except by calling
      the "connect" method - which is not present in earlier versions. Also, this
      method actually performs a connect, which is often not the desired behaviour
      when using the unconnected Socket constructor.

      Backward compatibility is essential!
      (Review ID: 126356)
      ======================================================================

            Unassigned Unassigned
            bstrathesunw Bill Strathearn (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: