001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.net;
006:
007: import com.tc.util.runtime.Os;
008:
009: import java.io.IOException;
010: import java.nio.channels.ClosedSelectorException;
011: import java.util.Properties;
012: import java.util.regex.Matcher;
013: import java.util.regex.Pattern;
014:
015: /**
016: * Helper methods to work around various NIO issues on different platforms.
017: */
018: public class NIOWorkarounds {
019:
020: private NIOWorkarounds() {
021: //
022: }
023:
024: /**
025: * Determine whether this IOException should be ignored on Windows. Checks
026: * for an IOException("A non-blocking socket operation could not be completed immediately")
027: * as in http://developer.java.sun.com/developer/bugParade/bugs/4854354.html.
028: * @param ioe Exception to check
029: * @return True if should be ignored on Windows
030: */
031: public static boolean windowsWritevWorkaround(IOException ioe) {
032: final String err = ioe.getMessage();
033: if (null != err) {
034: // java.io.IOException can be thrown here, but it should be ignored on windows
035: // http://developer.java.sun.com/developer/bugParade/bugs/4854354.html
036: if (err
037: .equals("A non-blocking socket operation could not be completed immediately")) {
038: if (Os.isWindows()) {
039: return true;
040: }
041: }
042: }
043:
044: return false;
045: }
046:
047: /**
048: * Workaround bug in Sun VM when select() gets interrupted and throws
049: * IOException("Interrupted system call").
050: *
051: * See Sun bug 4504001 (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504001)
052: * @param ioe Exception to examine
053: * @return True if exception should be ignored on Linux
054: */
055: public static boolean linuxSelectWorkaround(IOException ioe) {
056: if (Os.isLinux()) {
057: String msg = ioe.getMessage();
058: if ("Interrupted system call".equals(msg)) {
059: return true;
060: }
061: }
062:
063: return false;
064: }
065:
066: /**
067: * Force use of poll based NIO selector on Solaris 10 to work around
068: * Sun bug 6322825. This is done by setting the System property
069: * java.nio.channels.spi.SelectorProvider to "sun.nio.ch.PollSelectorProvider".
070: * The workaround is only applied on Solaris 10, JDK < 1.6.
071: *
072: * See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6322825
073: */
074: public static void solaris10Workaround() {
075: boolean workaround = solaris10Workaround(System.getProperties());
076: if (workaround) {
077: String prev = System
078: .getProperty("java.nio.channels.spi.SelectorProvider");
079: System.setProperty(
080: "java.nio.channels.spi.SelectorProvider",
081: "sun.nio.ch.PollSelectorProvider");
082:
083: String msg = "\nWARNING: Terracotta is forcing the use of poll based NIO selector to workaround Sun bug 6322825\n";
084: if (prev != null) {
085: msg += "This overrides the previous value of " + prev
086: + "\n";
087: }
088: System.err.println(msg.toString());
089: }
090: }
091:
092: /**
093: * Determine whether the Solaris 10 workaround should be applied.
094: * see LKC-2436 and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6322825
095: *
096: * @return true if the workaround should be applied
097: */
098: static boolean solaris10Workaround(Properties props) {
099: String vendor = props.getProperty("java.vendor", "");
100: String osName = props.getProperty("os.name", "");
101: String osVersion = props.getProperty("os.version", "");
102: String javaVersion = props.getProperty("java.version", "");
103:
104: if (vendor.toLowerCase().startsWith("sun")
105: && "SunOS".equals(osName) && "5.10".equals(osVersion)) {
106: if (javaVersion.matches("^1\\.[12345]\\..*")) { // bug is fixed in 1.6+ (supposedly)
107: // Bug is fixed in 1.5.0_08+ (again, supposedly)
108: Pattern p = Pattern.compile("^1\\.5\\.0_(\\d\\d)$");
109: Matcher m = p.matcher(javaVersion);
110: if (m.matches()) {
111: String minorRev = m.group(1);
112: int ver = Integer.parseInt(minorRev);
113: if (ver >= 8) {
114: return false;
115: }
116: }
117:
118: return true;
119: }
120: }
121: return false;
122: }
123:
124: /**
125: * Determine whether the NPE should be ignored due to bug 6427854.
126: * See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6427854
127: * @param npe Exception to examine
128: * @return True if exception should be ignored
129: */
130: public static boolean selectorOpenRace(NullPointerException npe) {
131: StackTraceElement source = npe.getStackTrace()[0];
132: if (source.getClassName().equals("sun.nio.ch.Util")
133: && source.getMethodName().equals("atBugLevel")) {
134: return true;
135: }
136: return false;
137: }
138:
139: /**
140: * Apply Solaris 10 workaround if applicable.
141: * @param args Ignored
142: */
143: public static void main(String args[]) {
144: NIOWorkarounds.solaris10Workaround();
145: }
146:
147: /**
148: * Determine whether to retry during connect on Windows
149: * @param cse Exception to examine
150: * @return True if should retry
151: */
152: public static boolean windowsConnectWorkaround(
153: ClosedSelectorException cse) {
154: // see DEV-671
155: if (!Os.isWindows()) {
156: return false;
157: }
158:
159: StackTraceElement[] stackTrace = cse.getStackTrace();
160: if (stackTrace.length < 3) {
161: return false;
162: }
163:
164: StackTraceElement f1 = stackTrace[0];
165: StackTraceElement f2 = stackTrace[1];
166: StackTraceElement f3 = stackTrace[2];
167:
168: return f1.getClassName().equals("sun.nio.ch.SelectorImpl")
169: && f1.getMethodName().equals("lockAndDoSelect")
170: && f2.getClassName().equals("sun.nio.ch.SelectorImpl")
171: && f2.getMethodName().equals("selectNow")
172: && f3.getClassName().equals("sun.nio.ch.Util")
173: && f3.getMethodName()
174: .equals("releaseTemporarySelector");
175: }
176:
177: }
|