|
@@ -61,6 +61,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
61
|
61
|
|
62
|
62
|
import javax.net.ssl.KeyManager;
|
63
|
63
|
import javax.net.ssl.SSLContext;
|
|
64
|
+import javax.net.ssl.SSLSocket;
|
64
|
65
|
import javax.net.ssl.SSLSocketFactory;
|
65
|
66
|
import javax.net.ssl.TrustManager;
|
66
|
67
|
import javax.net.ssl.X509TrustManager;
|
|
@@ -232,6 +233,15 @@ public class IRCParser implements SecureParser, EncodingParser, Runnable {
|
232
|
233
|
|
233
|
234
|
/** This is the socket used for reading from/writing to the IRC server. */
|
234
|
235
|
private Socket socket;
|
|
236
|
+
|
|
237
|
+ /**
|
|
238
|
+ * The underlying socket used for reading/writing to the IRC server.
|
|
239
|
+ * For normal sockets this will be the same as {@link #socket} but for SSL
|
|
240
|
+ * connections this will be the underlying {@link Socket} while
|
|
241
|
+ * {@link #socket} will be an {@link SSLSocket}.
|
|
242
|
+ */
|
|
243
|
+ private Socket rawSocket;
|
|
244
|
+
|
235
|
245
|
/** Used for writing to the server. */
|
236
|
246
|
private OutputQueue out;
|
237
|
247
|
/** The encoder to use to encode incoming lines. */
|
|
@@ -774,6 +784,8 @@ public class IRCParser implements SecureParser, EncodingParser, Runnable {
|
774
|
784
|
socket.connect(new InetSocketAddress(server.getHost(), server.getPort()), connectTimeout);
|
775
|
785
|
}
|
776
|
786
|
|
|
787
|
+ rawSocket = socket;
|
|
788
|
+
|
777
|
789
|
if (server.getSSL()) {
|
778
|
790
|
callDebugInfo(DEBUG_SOCKET, "Server is SSL.");
|
779
|
791
|
|
|
@@ -784,7 +796,14 @@ public class IRCParser implements SecureParser, EncodingParser, Runnable {
|
784
|
796
|
|
785
|
797
|
final SSLSocketFactory socketFactory = sc.getSocketFactory();
|
786
|
798
|
socket = socketFactory.createSocket(socket, server.getHost(), server.getPort(), false);
|
787
|
|
-
|
|
799
|
+
|
|
800
|
+ // Manually start a handshake so we get proper SSL errors here,
|
|
801
|
+ // and so that we can control the connection timeout
|
|
802
|
+ final int timeout = socket.getSoTimeout();
|
|
803
|
+ socket.setSoTimeout(10000);
|
|
804
|
+ ((SSLSocket) socket).startHandshake();
|
|
805
|
+ socket.setSoTimeout(timeout);
|
|
806
|
+
|
788
|
807
|
currentSocketState = SocketState.OPENING;
|
789
|
808
|
}
|
790
|
809
|
|
|
@@ -902,7 +921,12 @@ public class IRCParser implements SecureParser, EncodingParser, Runnable {
|
902
|
921
|
/** Close socket on destroy. */
|
903
|
922
|
@Override
|
904
|
923
|
protected void finalize() throws Throwable {
|
905
|
|
- try { socket.close(); }
|
|
924
|
+ try {
|
|
925
|
+ // See note at disconnect() method for why we close rawSocket.
|
|
926
|
+ if (rawSocket != null) {
|
|
927
|
+ rawSocket.close();
|
|
928
|
+ }
|
|
929
|
+ }
|
906
|
930
|
catch (IOException e) {
|
907
|
931
|
callDebugInfo(DEBUG_SOCKET, "Could not close socket");
|
908
|
932
|
}
|
|
@@ -1713,7 +1737,13 @@ public class IRCParser implements SecureParser, EncodingParser, Runnable {
|
1713
|
1737
|
}
|
1714
|
1738
|
|
1715
|
1739
|
try {
|
1716
|
|
- if (socket != null) { socket.close(); }
|
|
1740
|
+ // SSLSockets try to close nicely and read data from the socket,
|
|
1741
|
+ // which seems to hang indefinitely in some circumstances. We don't
|
|
1742
|
+ // like indefinite hangs, so just close the underlying socket
|
|
1743
|
+ // direct.
|
|
1744
|
+ if (rawSocket != null) {
|
|
1745
|
+ rawSocket.close();
|
|
1746
|
+ }
|
1717
|
1747
|
} catch (IOException e) {
|
1718
|
1748
|
/* Do Nothing */
|
1719
|
1749
|
} finally {
|