JDK-6218464 : multiple calls of Socket.setTrafficClass() do not work
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 1.4.2
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2005-01-18
  • Updated: 2017-05-16
  • Resolved: 2005-08-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 betaFixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.4.2_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)
Java HotSpot(TM) Client VM (build 1.4.2_03-b02, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

EXTRA RELEVANT SYSTEM CONFIGURATION :
registration key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\DisableUserTOSSetting
is set as 0 (REG_DWORD)


A DESCRIPTION OF THE PROBLEM :
The first call of setTrafficClass(xx) works, but additional calls on the same socket (after writing some bytes) are not reliable.

Even though getTrafficClass always returns the most recent tc value set by setTrafficClass, a network tool such as ethereal (http://ethereal.com) shows that the DSCP code is not changed correctly in the following case:
1. No call of setTrafficClass(0) change the DSCP code of the TCP package.
2. The third call of setTrafficClass(x), if tc is different from the second call, may not change the DSCP code; if tc is the same as in the second call, may change the DSCP code to another value.

I used two simple Java programs as client and server, as attached at the end. I ran the server on a Linux (FC3) machine, and the client on the Intel/Win2K machine as described above. The client loops on setting the traffic class and then writing a block of bytes to the server. The server simply print it out. I ran ethereal on the client Win2K and captured the traffic with the filter "host xxx.xxx.xxx.xxx" where the server IP was used. The server is run by "java SimpleSocketServer <port>" on Linux, and run many client sessions like the following (start ethereal capture first, run the client, and stop capturing, and start the next session...):
"...\j2sdk1.4.2_03\bin\java -cp . TOS <server> <port> 1460 34 46 34 46" where 1460 is the TCP packet (data) size so that each block written by Java code is actually transfered in a single TCP packet (otherwise, the problem will be more complicated).

==============TOS.java==========================
import java.io.*;
import java.net.*;
import java.util.Arrays;

public class TOS {

    public static void main(String[] args) throws Exception {
        if (args.length <4) {
            System.err.println("Arguments: <host> <port> <size> <tc1> <tc2> ...");
            return;
        }

        Socket socket = new Socket(args[0], Integer.parseInt(args[1]));
        socket.setTcpNoDelay(true);
        OutputStream os = socket.getOutputStream();
        byte[] bytes = new byte[Integer.parseInt(args[2])];
        for (int i=3; i<args.length; i++) {
            int tc = Integer.parseInt(args[i]);
            byte[] s = ("TC="+tc).getBytes();
            Arrays.fill(bytes, (byte)0);
            System.arraycopy(s, 0, bytes, 0, s.length);
            socket.setTrafficClass(tc);
            os.write(bytes);
            System.out.println("Set Traffic class to "+tc+", got "+
                               socket.getTrafficClass());
            os.flush();
        }
        os.close();
        socket.close();
    }
}
===========SimpleSocketServer.java===================
import java.io.*;
import java.net.*;

public class SimpleSocketServer {
    static int nextId = 0;
    static class Worker extends Thread {
        private Socket socket;
        private int id;

        Worker(Socket socket) {
            this.socket = socket;
            id = nextId ++;
        }
        public void run() {
            try {
                InputStream is = socket.getInputStream();
                byte[] buffer = new byte[1024];
                while (true) {
                    int n = is.read(buffer);
                    if (n < 0) {
                        break;
                    }
                    System.out.println("Worker "+id+" read: "+n+" bytes");
                }
                is.close();
                socket.close();
            } catch (Exception x) {
                x.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("Arguments: <port>");
            return;
        }
        final ServerSocket server = new ServerSocket(Integer.parseInt(args[0]));
        System.out.println("Start server at "+server.getLocalSocketAddress());
        Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    try {
                        server.close();
                    } catch (Exception x) {
                        x.printStackTrace();
                    }
                }
            });
        while (true) {
            new Worker(server.accept()).start();
        }
    }
    

}
==================================================

This problem does not occur in Linux (Fedora Core 2)
Thanks




REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
No workaround!
###@###.### 2005-1-18 14:33:22 GMT

Comments
EVALUATION It's implementation specific if the type-of-service field can be changed after the TCP connection is established. So this is actually a javadoc issue. Keyword "mustang-doc" added and will update the javadoc to talk about this behavior. ###@###.### 2005-04-20 10:08:10 GMT
20-04-2005