1 package org.jgroups.util; 2 3 import org.jgroups.Global; 4 5 import java.net.*; 6 import java.rmi.server.UID; 7 import java.util.ArrayList; 8 import java.util.List; 9 import java.util.StringTokenizer; 10 11 /** 12 * Manages resources such as multicast addresses and multicast ports, and TCP 13 * ports. This class is mainly used for running unit tests in parallel (TestNG) 14 * and preventing clusters intended to be separate from joining each other. 15 * 16 * @author Bela Ban 17 */ 18 public class ResourceManager { 19 private static final IpAddressRep rep; 20 private static short mcast_port; 21 private static short tcp_port; 22 private static SocketFactory socket_factory=new DefaultSocketFactory(); 23 24 static { 25 26 StackType type=Util.getIpStackType(); 27 28 String tmp_addr = System.getProperty(Global.INITIAL_MCAST_ADDR, 29 type == StackType.IPv6? "ff0e::9:9:9" : "230.1.1.1"); 30 mcast_port = Short.valueOf(System.getProperty(Global.INITIAL_MCAST_PORT, "7000")); 31 tcp_port = Short.valueOf(System.getProperty(Global.INITIAL_TCP_PORT, "10000")); 32 try { 33 InetAddress tmp = InetAddress.getByName(tmp_addr); 34 if (!tmp.isMulticastAddress()) 35 throw new IllegalArgumentException("initial multicast address " + tmp_addr + " is not a valid multicast address"); 36 37 if (tmp instanceof Inet4Address) 38 rep = new IPv4AddressRep(tmp_addr); 39 else 40 rep = new IPv6AddressRep(tmp_addr); 41 42 } catch (UnknownHostException e) { 43 throw new RuntimeException("initial multicast address " + tmp_addr + " is incorrect", e); 44 } 45 } 46 ResourceManager()47 private ResourceManager() { 48 } 49 50 /** 51 * Returns the next available multicast address, e.g. "228.1.2.3". This 52 * class is a JVM singleton 53 * 54 * @return 55 */ getNextMulticastAddress()56 public static String getNextMulticastAddress() { 57 return rep.nextAddress(); 58 } 59 getNextMulticastPort(InetAddress bind_addr)60 public static synchronized short getNextMulticastPort(InetAddress bind_addr) throws Exception { 61 short port = mcast_port; 62 try { 63 DatagramSocket sock = Util.createDatagramSocket(socket_factory, "jgroups.temp.resourcemgr.mcast_sock", bind_addr, port); 64 port = (short) sock.getLocalPort(); 65 socket_factory.close(sock); 66 return port; 67 } finally { 68 mcast_port = (short) (port + 1); 69 } 70 } 71 getNextTcpPorts(InetAddress bind_addr, int num_requested_ports)72 public static synchronized List<Short> getNextTcpPorts(InetAddress bind_addr, int num_requested_ports) throws Exception { 73 short port = tcp_port++; 74 List<Short> retval = new ArrayList<Short>(num_requested_ports); 75 76 for (int i = 0; i < num_requested_ports; i++) { 77 ServerSocket sock = Util.createServerSocket(socket_factory, "jgroups.temp.resourcemgr.srv_sock", bind_addr, port); 78 port = (short) sock.getLocalPort(); 79 retval.add(port); 80 tcp_port = ++port; 81 socket_factory.close(sock); 82 } 83 return retval; 84 } 85 getUniqueClusterName(String base_name)86 public static String getUniqueClusterName(String base_name) { 87 return base_name != null ? base_name + "-" + new UID().toString() 88 : new UID().toString(); 89 } 90 getUniqueClusterName()91 public static String getUniqueClusterName() { 92 return getUniqueClusterName(null); 93 } 94 main(String[] args)95 public static void main(String[] args) throws Exception { 96 List<Short> ports = getNextTcpPorts(InetAddress.getByName("192.168.1.5"), 15); 97 System.out.println("ports = " + ports); 98 99 ports = getNextTcpPorts(InetAddress.getByName("192.168.1.5"), 5); 100 System.out.println("ports = " + ports); 101 102 } 103 104 /* 105 * Interface for IpAddress representations 106 */ 107 public interface IpAddressRep { nextAddress()108 public String nextAddress(); 109 } 110 111 /** Representation of an IPv4 address */ 112 static class IPv4AddressRep implements IpAddressRep { 113 short a = 225, b = MIN, c = MIN, d = MIN; 114 115 private static final short MIN = 1, MAX = 250; 116 private static final char DOT = '.'; 117 IPv4AddressRep(String initial_addr)118 IPv4AddressRep(String initial_addr) { 119 StringTokenizer tok = new StringTokenizer(initial_addr, ".", false); 120 a = Short.valueOf(tok.nextToken()); 121 b = Short.valueOf(tok.nextToken()); 122 c = Short.valueOf(tok.nextToken()); 123 d = Short.valueOf(tok.nextToken()); 124 } 125 nextAddress()126 public synchronized String nextAddress() { 127 StringBuilder sb = new StringBuilder(); 128 sb.append(a).append(DOT).append(b).append(DOT).append(c) 129 .append(DOT).append(d); 130 increment(); 131 return sb.toString(); 132 } 133 increment()134 private void increment() { 135 d++; 136 if (d > MAX) { 137 d = MIN; 138 c++; 139 if (c > MAX) { 140 c = MIN; 141 b++; 142 if (b > MAX) { 143 b = MIN; 144 a++; 145 if (a > MAX) 146 a = 225; 147 } 148 } 149 } 150 } 151 } 152 153 /** Representation of an IPv6 address */ 154 static class IPv6AddressRep implements IpAddressRep { 155 156 byte[] bv = null; 157 InetAddress address = null; 158 159 private static boolean carry = false; 160 IPv6AddressRep(String initial_addr)161 IPv6AddressRep(String initial_addr) { 162 163 try { 164 address = InetAddress.getByName(initial_addr); 165 } catch (UnknownHostException e) { 166 // 167 throw new RuntimeException ("Multicast address " + initial_addr + " has incorrect format", e) ; 168 } catch (SecurityException e) { 169 // 170 throw new RuntimeException ("Security violation in accessing multicast address " + initial_addr, e) ; 171 } 172 173 // get the byte representation 174 bv = address.getAddress(); 175 } 176 nextAddress()177 public synchronized String nextAddress() { 178 // build the existing address, then create the next one 179 try { 180 address = InetAddress.getByAddress(bv); 181 } catch (UnknownHostException e) { 182 // 183 throw new RuntimeException ("Multicast address has incorrect length", e) ; 184 } 185 increment(); 186 187 // strings are returned as hostname/IP address, so remove the hostname prefix 188 // before returning the string 189 String addressWithHostname = address.toString(); 190 191 return addressWithHostname.substring(addressWithHostname.indexOf('/')+1) ; 192 } 193 increment()194 private void increment() { 195 196 // process hex digits from right to left 197 for (int i = bv.length - 1; i >= 0; i--) { 198 199 // increment the ith byte 200 bv[i] =incrementHexValue(bv[i]); 201 202 // if carry, increment (i-1)th byte 203 if (carry) { 204 carry = false; 205 continue; 206 } 207 // otherwise, we are done 208 return ; 209 } 210 // if we reach here, incrementing no longer possible 211 throw new RuntimeException ("Cannot increment multicast address ") ; 212 } 213 214 // increments a byte in hex and notes if carry req'd 215 // these bytes contain 2's complement representations 216 // of hex values "00" through "ff" incrementHexValue(byte b)217 private static byte incrementHexValue(byte b) { 218 219 // "00" to "7e" 220 if (b >= 0 && b < 127) 221 return (byte) (b + (byte) 1); 222 // "7f" 223 else if (b == 127) { 224 return (byte) -128; 225 } 226 // "80" to "fe" 227 else if (b >= -128 && b < -1) { 228 return (byte) (b + (byte) 1); 229 } 230 // "ff" 231 else if (b == -1) { 232 carry = true; 233 return (byte) 0; 234 } 235 return 0; 236 } 237 } 238 } 239