Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby-openssl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 626b12b455c0
Choose a base ref
...
head repository: jruby/jruby-openssl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d5c61c1d75ad
Choose a head ref
  • 3 commits
  • 1 file changed
  • 1 contributor

Commits on Nov 21, 2015

  1. Copy the full SHA
    32e7fd6 View commit details
  2. support SSLSocket#accept_nonblock/connect_nonblock with exception: false

    adding Ruby 2.3 compatibility
    kares committed Nov 21, 2015
    Copy the full SHA
    9bd2336 View commit details
  3. Copy the full SHA
    d5c61c1 View commit details
Showing with 69 additions and 52 deletions.
  1. +69 −52 src/main/java/org/jruby/ext/openssl/SSLSocket.java
121 changes: 69 additions & 52 deletions src/main/java/org/jruby/ext/openssl/SSLSocket.java
Original file line number Diff line number Diff line change
@@ -80,15 +80,15 @@ public class SSLSocket extends RubyObject {

private static final long serialVersionUID = -2084816623554406237L;

private static ObjectAllocator SSLSOCKET_ALLOCATOR = new ObjectAllocator() {
private static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new SSLSocket(runtime, klass);
}
};

public static void createSSLSocket(final Ruby runtime, final RubyModule SSL) { // OpenSSL::SSL
final ThreadContext context = runtime.getCurrentContext();
RubyClass SSLSocket = SSL.defineClassUnder("SSLSocket", runtime.getObject(), SSLSOCKET_ALLOCATOR);
RubyClass SSLSocket = SSL.defineClassUnder("SSLSocket", runtime.getObject(), ALLOCATOR);
// SSLSocket.addReadAttribute(context, "io");
// SSLSocket.defineAlias("to_io", "io");
// SSLSocket.addReadAttribute(context, "context");
@@ -208,19 +208,23 @@ public IRubyObject set_sync(final ThreadContext context, final IRubyObject sync)

@JRubyMethod
public IRubyObject connect(final ThreadContext context) {
return connectImpl(context, true);
return connectImpl(context, true, true);
}

@JRubyMethod
public IRubyObject connect_nonblock(ThreadContext context) {
return connectImpl(context, false);
public IRubyObject connect_nonblock(final ThreadContext context) {
return connectImpl(context, false, true);
}

private SSLSocket connectImpl(final ThreadContext context, final boolean blocking) {
final Ruby runtime = context.runtime;
@JRubyMethod
public IRubyObject connect_nonblock(final ThreadContext context, IRubyObject opts) {
return connectImpl(context, false, getExceptionOpt(context, opts));
}

private IRubyObject connectImpl(final ThreadContext context, final boolean blocking, final boolean exception) {

if ( ! sslContext.isProtocolForClient() ) {
throw newSSLError(runtime, "called a function you should not call");
throw newSSLError(context.runtime, "called a function you should not call");
}

try {
@@ -231,53 +235,58 @@ private SSLSocket connectImpl(final ThreadContext context, final boolean blockin
handshakeStatus = engine.getHandshakeStatus();
initialHandshake = true;
}
doHandshake(blocking);
final IRubyObject ex = doHandshake(blocking, exception);
if ( ex != null ) return ex; // :wait_readable | :wait_writable
}
catch (SSLHandshakeException e) {
//debugStackTrace(runtime, e);
// unlike server side, client should close outbound channel even if
// we have remaining data to be sent.
forceClose();
throw newSSLErrorFromHandshake(runtime, e);
throw newSSLErrorFromHandshake(context.runtime, e);
}
catch (NoSuchAlgorithmException e) {
debugStackTrace(runtime, e);
debugStackTrace(context.runtime, e);
forceClose();
throw newSSLError(runtime, e);
throw newSSLError(context.runtime, e);
}
catch (KeyManagementException e) {
debugStackTrace(runtime, e);
debugStackTrace(context.runtime, e);
forceClose();
throw newSSLError(runtime, e);
throw newSSLError(context.runtime, e);
}
catch (IOException e) {
//debugStackTrace(runtime, e);
//debugStackTrace(context.runtime, e);
forceClose();
throw newSSLError(runtime, e);
throw newSSLError(context.runtime, e);
}
return this;
}

@JRubyMethod
public IRubyObject accept(ThreadContext context) {
return acceptImpl(context, true);
public IRubyObject accept(final ThreadContext context) {
return acceptImpl(context, true, true);
}

@JRubyMethod
public IRubyObject accept_nonblock(final ThreadContext context) {
return acceptImpl(context, false, true);
}

@JRubyMethod
public IRubyObject accept_nonblock(ThreadContext context) {
return acceptImpl(context, false);
public IRubyObject accept_nonblock(final ThreadContext context, IRubyObject opts) {
return acceptImpl(context, false, getExceptionOpt(context, opts));
}

@Deprecated
public SSLSocket acceptCommon(ThreadContext context, boolean blocking) {
return acceptImpl(context, blocking);
return (SSLSocket) acceptImpl(context, blocking, true);
}

private SSLSocket acceptImpl(final ThreadContext context, final boolean blocking) {
final Ruby runtime = context.runtime;
private IRubyObject acceptImpl(final ThreadContext context, final boolean blocking, final boolean exception) {

if ( ! sslContext.isProtocolForServer() ) {
throw newSSLError(runtime, "called a function you should not call");
throw newSSLError(context.runtime, "called a function you should not call");
}

try {
@@ -302,42 +311,43 @@ private SSLSocket acceptImpl(final ThreadContext context, final boolean blocking
handshakeStatus = engine.getHandshakeStatus();
initialHandshake = true;
}
doHandshake(blocking);
final IRubyObject ex = doHandshake(blocking, exception);
if ( ex != null ) return ex; // :wait_readable | :wait_writable
}
catch (SSLHandshakeException e) {
final String msg = e.getMessage();
// updated JDK (>= 1.7.0_75) with deprecated SSL protocols :
// javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
if ( e.getCause() == null && msg != null &&
msg.contains("(protocol is disabled or cipher suites are inappropriate)") ) {
debug(runtime, sslContext.getProtocol() + " protocol has been deactivated and is not available by default\n see the java.security.Security property jdk.tls.disabledAlgorithms in <JRE_HOME>/lib/security/java.security file");
debug(context.runtime, sslContext.getProtocol() + " protocol has been deactivated and is not available by default\n see the java.security.Security property jdk.tls.disabledAlgorithms in <JRE_HOME>/lib/security/java.security file");
}
else {
debugStackTrace(runtime, e);
debugStackTrace(context.runtime, e);
}
throw newSSLErrorFromHandshake(runtime, e);
throw newSSLErrorFromHandshake(context.runtime, e);
}
catch (NoSuchAlgorithmException e) {
debugStackTrace(runtime, e);
throw newSSLError(runtime, e);
debugStackTrace(context.runtime, e);
throw newSSLError(context.runtime, e);
}
catch (KeyManagementException e) {
debugStackTrace(runtime, e);
throw newSSLError(runtime, e);
debugStackTrace(context.runtime, e);
throw newSSLError(context.runtime, e);
}
catch (IOException e) {
debugStackTrace(runtime, e);
throw newSSLError(runtime, e);
debugStackTrace(context.runtime, e);
throw newSSLError(context.runtime, e);
}
catch (RaiseException e) {
throw e;
}
catch (RuntimeException e) {
debugStackTrace(runtime, e);
debugStackTrace(context.runtime, e);
if ( "Could not generate DH keypair".equals( e.getMessage() ) ) {
throw SSL.handleCouldNotGenerateDHKeyPairError(runtime, e);
throw SSL.handleCouldNotGenerateDHKeyPairError(context.runtime, e);
}
throw newSSLError(runtime, e);
throw newSSLError(context.runtime, e);
}
return this;
}
@@ -477,11 +487,17 @@ private static void writeWouldBlock(final Ruby runtime, final boolean exception,
}

private void doHandshake(final boolean blocking) throws IOException {
doHandshake(blocking, true);
}

// might return :wait_readable | :wait_writable in case (true, false)
private IRubyObject doHandshake(final boolean blocking, final boolean exception) throws IOException {
while (true) {
boolean ready = waitSelect(SelectionKey.OP_READ | SelectionKey.OP_WRITE, blocking, true) == Boolean.TRUE;
Object sel = waitSelect(SelectionKey.OP_READ | SelectionKey.OP_WRITE, blocking, exception);
if ( sel instanceof IRubyObject ) return (IRubyObject) sel; // :wait_readable | :wait_writable

// if not blocking, raise EAGAIN
if ( ! blocking && ! ready ) {
if ( ! blocking && sel != Boolean.TRUE ) {
throw getRuntime().newErrnoEAGAINError("Resource temporarily unavailable");
}

@@ -491,7 +507,7 @@ private void doHandshake(final boolean blocking) throws IOException {
case FINISHED:
case NOT_HANDSHAKING:
if ( initialHandshake ) finishInitialHandshake();
return;
return null; // OK
case NEED_TASK:
doTasks();
break;
@@ -503,7 +519,8 @@ private void doHandshake(final boolean blocking) throws IOException {
// does not mean writable. we explicitly wait for readable channel to avoid
// busy loop.
if (initialHandshake && status == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
waitSelect(SelectionKey.OP_READ, blocking, true);
sel = waitSelect(SelectionKey.OP_READ, blocking, exception);
if ( sel instanceof IRubyObject ) return (IRubyObject) sel; // :wait_readable
}
break;
case NEED_WRAP:
@@ -685,7 +702,7 @@ private void doShutdown() throws IOException {
flushData(true);
}

private IRubyObject do_sysread(final ThreadContext context,
private IRubyObject sysreadImpl(final ThreadContext context,
IRubyObject len, IRubyObject buff, final boolean blocking, final boolean exception) {
final Ruby runtime = context.runtime;

@@ -746,12 +763,12 @@ private IRubyObject do_sysread(final ThreadContext context,

@JRubyMethod
public IRubyObject sysread(ThreadContext context, IRubyObject len) {
return do_sysread(context, len, null, true, true);
return sysreadImpl(context, len, null, true, true);
}

@JRubyMethod
public IRubyObject sysread(ThreadContext context, IRubyObject len, IRubyObject buff) {
return do_sysread(context, len, buff, true, true);
return sysreadImpl(context, len, buff, true, true);
}

@Deprecated // @JRubyMethod(rest = true, required = 1, optional = 1)
@@ -768,20 +785,20 @@ public IRubyObject sysread(ThreadContext context, IRubyObject[] args) {

@JRubyMethod
public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject len) {
return do_sysread(context, len, null, false, true);
return sysreadImpl(context, len, null, false, true);
}

@JRubyMethod
public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject len, IRubyObject arg) {
if ( arg instanceof RubyHash ) { // exception: false
return do_sysread(context, len, null, false, getExceptionOpt(context, arg));
return sysreadImpl(context, len, null, false, getExceptionOpt(context, arg));
}
return do_sysread(context, len, arg, false, true); // buffer arg
return sysreadImpl(context, len, arg, false, true); // buffer arg
}

@JRubyMethod
public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject len, IRubyObject buff, IRubyObject opts) {
return do_sysread(context, len, buff, false, getExceptionOpt(context, opts));
return sysreadImpl(context, len, buff, false, getExceptionOpt(context, opts));
}


@@ -799,7 +816,7 @@ public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject[] args) {
return null; // won't happen as checkArgumentCount raises
}

private IRubyObject do_syswrite(final ThreadContext context,
private IRubyObject syswriteImpl(final ThreadContext context,
final IRubyObject arg, final boolean blocking, final boolean exception) {
final Ruby runtime = context.runtime;
try {
@@ -828,17 +845,17 @@ private IRubyObject do_syswrite(final ThreadContext context,

@JRubyMethod
public IRubyObject syswrite(ThreadContext context, IRubyObject arg) {
return do_syswrite(context, arg, true, true);
return syswriteImpl(context, arg, true, true);
}

@JRubyMethod
public IRubyObject syswrite_nonblock(ThreadContext context, IRubyObject arg) {
return do_syswrite(context, arg, false, true);
return syswriteImpl(context, arg, false, true);
}

@JRubyMethod
public IRubyObject syswrite_nonblock(ThreadContext context, IRubyObject arg, IRubyObject opts) {
return do_syswrite(context, arg, false, getExceptionOpt(context, opts));
return syswriteImpl(context, arg, false, getExceptionOpt(context, opts));
}

private static boolean getExceptionOpt(final ThreadContext context, final IRubyObject opts) {