001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.net;
005:
006: import com.tc.process.StreamCollector;
007: import com.tc.util.runtime.Os;
008:
009: import java.io.BufferedReader;
010: import java.io.File;
011: import java.io.FileInputStream;
012: import java.io.IOException;
013: import java.io.InputStreamReader;
014: import java.io.StringBufferInputStream;
015: import java.io.StringReader;
016: import java.util.Properties;
017: import java.util.regex.Matcher;
018: import java.util.regex.Pattern;
019:
020: // http://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html can tell you alot about what this class is about
021:
022: public class EphemeralPorts {
023:
024: private static Range range = null;
025:
026: public synchronized static Range getRange() {
027: if (range == null) {
028: range = findRange();
029: }
030: return range;
031: }
032:
033: private static Range findRange() {
034: if (Os.isLinux()) {
035: return new Linux().getRange();
036: }
037: if (Os.isSolaris()) {
038: return new Solaris().getRange();
039: }
040: if (Os.isMac()) {
041: return new Mac().getRange();
042: }
043: if (Os.isWindows()) {
044: return new Windows().getRange();
045: }
046:
047: throw new AssertionError("No support for this OS: "
048: + Os.getOsName());
049: }
050:
051: public static class Range {
052: private final int upper;
053: private final int lower;
054:
055: private Range(int lower, int upper) {
056: this .lower = lower;
057: this .upper = upper;
058: }
059:
060: public int getUpper() {
061: return upper;
062: }
063:
064: public int getLower() {
065: return lower;
066: }
067:
068: public String toString() {
069: return lower + " " + upper;
070: }
071:
072: }
073:
074: private interface RangeGetter {
075: Range getRange();
076: }
077:
078: private static class Solaris implements RangeGetter {
079: public Range getRange() {
080: Exec exec = new Exec(new String[] { "/usr/sbin/ndd",
081: "/dev/tcp", "tcp_smallest_anon_port" });
082: final String lower;
083: try {
084: lower = exec.execute(Exec.STDOUT);
085: } catch (Exception e) {
086: throw new RuntimeException(e);
087: }
088:
089: exec = new Exec(new String[] { "/usr/sbin/ndd", "/dev/tcp",
090: "tcp_largest_anon_port" });
091: final String upper;
092: try {
093: upper = exec.execute(Exec.STDOUT);
094: } catch (Exception e) {
095: throw new RuntimeException(e);
096: }
097:
098: int low = Integer.parseInt(lower.replaceAll("\n", ""));
099: int high = Integer.parseInt(upper.replaceAll("\n", ""));
100:
101: return new Range(low, high);
102: }
103: }
104:
105: private static class Windows implements RangeGetter {
106: private static final int DEFAULT_LOWER = 1024;
107: private static final int DEFAULT_UPPER = 5000;
108:
109: public Range getRange() {
110: try {
111: // use reg.exe if available to see if MaxUserPort is tweaked
112: String sysRoot = Os.findWindowsSystemRoot();
113: if (sysRoot != null) {
114: File regExe = new File(
115: new File(sysRoot, "system32"), "reg.exe");
116: if (regExe.exists()) {
117: String[] cmd = new String[] {
118: regExe.getAbsolutePath(),
119: "query",
120: "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
121: "/v", "MaxUserPort" };
122: Exec exec = new Exec(cmd);
123: BufferedReader reader = new BufferedReader(
124: new StringReader(exec
125: .execute(Exec.STDOUT)));
126:
127: Pattern pattern = Pattern
128: .compile("^.*MaxUserPort\\s+REG_DWORD\\s+0x(\\p{XDigit}+)");
129: String line = null;
130: while ((line = reader.readLine()) != null) {
131: Matcher matcher = pattern.matcher(line);
132: if (matcher.matches()) {
133: int val = Integer.parseInt(matcher
134: .group(1), 16);
135: return new Range(DEFAULT_LOWER, val);
136: }
137: }
138: }
139: }
140: } catch (Exception e) {
141: e.printStackTrace();
142: }
143:
144: return new Range(DEFAULT_LOWER, DEFAULT_UPPER);
145: }
146: }
147:
148: private static class Mac implements RangeGetter {
149: public Range getRange() {
150: Exec exec = new Exec(new String[] { "sysctl",
151: "net.inet.ip.portrange" });
152: final String output;
153: try {
154: output = exec.execute(Exec.STDOUT);
155: } catch (Exception e) {
156: throw new RuntimeException(e);
157: }
158:
159: Properties props = new Properties();
160: try {
161: props.load(new StringBufferInputStream(output));
162: } catch (IOException e) {
163: throw new RuntimeException(e);
164: }
165:
166: int low = Integer.parseInt(props
167: .getProperty("net.inet.ip.portrange.hifirst"));
168: int high = Integer.parseInt(props
169: .getProperty("net.inet.ip.portrange.hilast"));
170:
171: return new Range(low, high);
172: }
173: }
174:
175: private static class Linux implements RangeGetter {
176: private static final String source = "/proc/sys/net/ipv4/ip_local_port_range";
177:
178: public Range getRange() {
179: File src = new File(source);
180: if (!src.exists() || !src.canRead()) {
181: throw new RuntimeException("Cannot access " + source);
182: }
183:
184: BufferedReader reader = null;
185: try {
186: reader = new BufferedReader(new InputStreamReader(
187: new FileInputStream(src)));
188: String data = reader.readLine();
189: String[] parts = data.split("[ \\t]");
190: if (parts.length != 2) {
191: throw new RuntimeException(
192: "Wrong number of tokens (" + parts.length
193: + ") in " + data);
194: }
195:
196: int low = Integer.parseInt(parts[0]);
197: int high = Integer.parseInt(parts[1]);
198:
199: return new Range(low, high);
200: } catch (IOException ioe) {
201: throw new RuntimeException(ioe);
202: } finally {
203: if (reader != null) {
204: try {
205: reader.close();
206: } catch (IOException e) {
207: //
208: }
209: }
210: }
211: }
212: }
213:
214: private static class Exec {
215: static final int STDOUT = 1;
216: static final int STDERR = 2;
217:
218: private final String[] cmd;
219:
220: Exec(String cmd[]) {
221: this .cmd = cmd;
222: }
223:
224: String execute(int stream) throws IOException,
225: InterruptedException {
226: if ((stream != STDOUT) && (stream != STDERR)) {
227: throw new IllegalArgumentException("bad stream: "
228: + stream);
229: }
230:
231: Process proc = Runtime.getRuntime().exec(cmd);
232: proc.getOutputStream().close();
233:
234: StreamCollector out = new StreamCollector(proc
235: .getInputStream());
236: StreamCollector err = new StreamCollector(proc
237: .getErrorStream());
238: out.start();
239: err.start();
240:
241: proc.waitFor(); // ignores process exit code
242:
243: out.join();
244: err.join();
245:
246: if (stream == STDOUT) {
247: return out.toString();
248: }
249: return err.toString();
250: }
251:
252: }
253:
254: }
|