/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.transport.tcp; import java.net.Socket; import java.net.SocketException; import java.util.HashMap; import java.util.Map; /** * Utilities for determining the values for the bits in the headers of the * outgoing TCP/IP packets that indicate Traffic Class for use in Quality of * Service forwarding policies. */ public class QualityOfServiceUtils { private static final int MAX_DIFF_SERV = 63; private static final int MIN_DIFF_SERV = 0; private static final Map<String, Integer> DIFF_SERV_NAMES = new HashMap<String, Integer>(); /** Common names used for Differentiated Services values. */ static { DIFF_SERV_NAMES.put("CS0", 0); DIFF_SERV_NAMES.put("CS1", 8); DIFF_SERV_NAMES.put("CS2", 16); DIFF_SERV_NAMES.put("CS3", 24); DIFF_SERV_NAMES.put("CS4", 32); DIFF_SERV_NAMES.put("CS5", 40); DIFF_SERV_NAMES.put("CS6", 48); DIFF_SERV_NAMES.put("CS7", 56); DIFF_SERV_NAMES.put("AF11", 10); DIFF_SERV_NAMES.put("AF12", 12); DIFF_SERV_NAMES.put("AF13", 14); DIFF_SERV_NAMES.put("AF21", 18); DIFF_SERV_NAMES.put("AF22", 20); DIFF_SERV_NAMES.put("AF23", 22); DIFF_SERV_NAMES.put("AF31", 26); DIFF_SERV_NAMES.put("AF32", 28); DIFF_SERV_NAMES.put("AF33", 30); DIFF_SERV_NAMES.put("AF41", 34); DIFF_SERV_NAMES.put("AF42", 36); DIFF_SERV_NAMES.put("AF43", 38); DIFF_SERV_NAMES.put("EF", 46); } private static final int MAX_TOS = 255; private static final int MIN_TOS = 0; /** * @param value A potential value to be used for Differentiated Services. * @return The corresponding Differentiated Services Code Point (DSCP). * @throws IllegalArgumentException if the value does not correspond to a * Differentiated Services Code Point or setting the DSCP is not * supported. */ public static int getDSCP(String value) throws IllegalArgumentException { int intValue = -1; // Check the names first. if (DIFF_SERV_NAMES.containsKey(value)) { intValue = DIFF_SERV_NAMES.get(value); } else { try { intValue = Integer.parseInt(value); if (intValue > MAX_DIFF_SERV || intValue < MIN_DIFF_SERV) { throw new IllegalArgumentException("Differentiated Services" + " value: " + intValue + " not in legal range [" + MIN_DIFF_SERV + ", " + MAX_DIFF_SERV + "]."); } } catch (NumberFormatException e) { // value must have been a malformed name. throw new IllegalArgumentException("No such Differentiated " + "Services name: " + value); } } return adjustDSCPForECN(intValue); } /** * @param value A potential value to be used for Type of Service. * @return A valid value that can be used to set the Type of Service in the * packet headers. * @throws IllegalArgumentException if the value is not a legal Type of * Service value. */ public static int getToS(int value) throws IllegalArgumentException { if (value > MAX_TOS || value < MIN_TOS) { throw new IllegalArgumentException("Type of Service value: " + value + " not in legal range [" + MIN_TOS + ", " + MAX_TOS + "."); } return value; } /** * The Differentiated Services values use only 6 of the 8 bits in the field * in the TCP/IP packet header. Make sure any values the system has set for * the other two bits (the ECN bits) are maintained. * * @param dscp The Differentiated Services Code Point. * @return A Differentiated Services Code Point that respects the ECN bits * set on the system. * @throws IllegalArgumentException if setting Differentiated Services is * not supported. */ private static int adjustDSCPForECN(int dscp) throws IllegalArgumentException { // The only way to see if there are any values set for the ECN is to // read the traffic class automatically set by the system and isolate // the ECN bits. Socket socket = new Socket(); try { int systemTrafficClass = socket.getTrafficClass(); // The 1st and 2nd bits of the system traffic class are the ECN // bits. return (dscp << 2) | (systemTrafficClass & 3); } catch (SocketException e) { throw new IllegalArgumentException("Setting Differentiated Services" + " not supported: " + e); } } }