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 */ 017package org.apache.activemq.transport.tcp; 018 019import java.net.Socket; 020import java.net.SocketException; 021import java.util.HashMap; 022import 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 */ 029public 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}