001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.activemq.transport.tcp;
018
019 import java.net.Socket;
020 import java.net.SocketException;
021 import java.util.HashMap;
022 import java.util.Map;
023
024 /**
025 * Utilities for determining the values for the bits in the headers of the
026 * outgoing TCP/IP packets that indicate Traffic Class for use in Quality of
027 * Service forwarding policies.
028 */
029 public class QualityOfServiceUtils {
030
031 private static final int MAX_DIFF_SERV = 63;
032 private static final int MIN_DIFF_SERV = 0;
033 private static final Map<String, Integer> DIFF_SERV_NAMES
034 = new HashMap<String, Integer>();
035 /** Common names used for Differentiated Services values. */
036 static {
037
038 DIFF_SERV_NAMES.put("CS0", 0);
039 DIFF_SERV_NAMES.put("CS1", 8);
040 DIFF_SERV_NAMES.put("CS2", 16);
041 DIFF_SERV_NAMES.put("CS3", 24);
042 DIFF_SERV_NAMES.put("CS4", 32);
043 DIFF_SERV_NAMES.put("CS5", 40);
044 DIFF_SERV_NAMES.put("CS6", 48);
045 DIFF_SERV_NAMES.put("CS7", 56);
046 DIFF_SERV_NAMES.put("AF11", 10);
047 DIFF_SERV_NAMES.put("AF12", 12);
048 DIFF_SERV_NAMES.put("AF13", 14);
049 DIFF_SERV_NAMES.put("AF21", 18);
050 DIFF_SERV_NAMES.put("AF22", 20);
051 DIFF_SERV_NAMES.put("AF23", 22);
052 DIFF_SERV_NAMES.put("AF31", 26);
053 DIFF_SERV_NAMES.put("AF32", 28);
054 DIFF_SERV_NAMES.put("AF33", 30);
055 DIFF_SERV_NAMES.put("AF41", 34);
056 DIFF_SERV_NAMES.put("AF42", 36);
057 DIFF_SERV_NAMES.put("AF43", 38);
058 DIFF_SERV_NAMES.put("EF", 46);
059 }
060
061 private static final int MAX_TOS = 255;
062 private static final int MIN_TOS = 0;
063
064 /**
065 * @param value A potential value to be used for Differentiated Services.
066 * @return The corresponding Differentiated Services Code Point (DSCP).
067 * @throws IllegalArgumentException if the value does not correspond to a
068 * Differentiated Services Code Point or setting the DSCP is not
069 * supported.
070 */
071 public static int getDSCP(String value) throws IllegalArgumentException {
072 int intValue = -1;
073
074 // Check the names first.
075 if (DIFF_SERV_NAMES.containsKey(value)) {
076 intValue = DIFF_SERV_NAMES.get(value);
077 } else {
078 try {
079 intValue = Integer.parseInt(value);
080 if (intValue > MAX_DIFF_SERV || intValue < MIN_DIFF_SERV) {
081 throw new IllegalArgumentException("Differentiated Services"
082 + " value: " + intValue + " not in legal range ["
083 + MIN_DIFF_SERV + ", " + MAX_DIFF_SERV + "].");
084 }
085 } catch (NumberFormatException e) {
086 // value must have been a malformed name.
087 throw new IllegalArgumentException("No such Differentiated "
088 + "Services name: " + value);
089 }
090 }
091
092 return adjustDSCPForECN(intValue);
093 }
094
095
096 /**
097 * @param value A potential value to be used for Type of Service.
098 * @return A valid value that can be used to set the Type of Service in the
099 * packet headers.
100 * @throws IllegalArgumentException if the value is not a legal Type of
101 * Service value.
102 */
103 public static int getToS(int value) throws IllegalArgumentException {
104 if (value > MAX_TOS || value < MIN_TOS) {
105 throw new IllegalArgumentException("Type of Service value: "
106 + value + " not in legal range [" + MIN_TOS + ", " + MAX_TOS
107 + ".");
108 }
109 return value;
110 }
111
112 /**
113 * The Differentiated Services values use only 6 of the 8 bits in the field
114 * in the TCP/IP packet header. Make sure any values the system has set for
115 * the other two bits (the ECN bits) are maintained.
116 *
117 * @param dscp The Differentiated Services Code Point.
118 * @return A Differentiated Services Code Point that respects the ECN bits
119 * set on the system.
120 * @throws IllegalArgumentException if setting Differentiated Services is
121 * not supported.
122 */
123 private static int adjustDSCPForECN(int dscp)
124 throws IllegalArgumentException {
125 // The only way to see if there are any values set for the ECN is to
126 // read the traffic class automatically set by the system and isolate
127 // the ECN bits.
128 Socket socket = new Socket();
129 try {
130 int systemTrafficClass = socket.getTrafficClass();
131 // The 1st and 2nd bits of the system traffic class are the ECN
132 // bits.
133 return (dscp << 2) | (systemTrafficClass & 3);
134 } catch (SocketException e) {
135 throw new IllegalArgumentException("Setting Differentiated Services"
136 + " not supported: " + e);
137 }
138 }
139 }