Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions core/src/main/java/org/jruby/RubyIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -2042,8 +2042,6 @@ protected IRubyObject rbIoClose(ThreadContext context) {

fptr.finalizeFlush(context, false);

fptr.finalizeFlush(context, false);

// interrupt waiting threads
fptr.interruptBlockingThreads(context);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ private void doBind(ThreadContext context, Channel channel, InetSocketAddress ia
throw SocketUtils.sockerr(runtime, "bind(2): unknown host");
}
catch (SocketException e) {
handleSocketException(runtime, e, "bind(2)", iaddr);
throw buildSocketException(runtime, e, "bind(2)", iaddr);
}
catch (IOException e) {
throw sockerr(runtime, "bind(2): name or service not known", e);
Expand Down
39 changes: 20 additions & 19 deletions core/src/main/java/org/jruby/ext/socket/RubySocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
package org.jruby.ext.socket;

import java.io.IOException;
import java.net.ConnectException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
Expand All @@ -48,6 +49,7 @@
import java.util.regex.Pattern;

import jnr.constants.platform.AddressFamily;
import jnr.constants.platform.Errno;
import jnr.constants.platform.INAddr;
import jnr.constants.platform.IPProto;
import jnr.constants.platform.NameInfo;
Expand All @@ -70,6 +72,7 @@
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
Expand Down Expand Up @@ -572,7 +575,10 @@ else if (channel instanceof DatagramChannel) {
throw SocketUtils.sockerr(runtime, "connect(2): unknown host");
}
catch (SocketException e) {
handleSocketException(runtime, e, "connect(2)", addr);
// Subclasses of SocketException all indicate failure to connect, which leaves the channel closed.
// At this point the socket channel is no longer usable, so we clean up.
getOpenFile().cleanup(runtime, true);
throw buildSocketException(runtime, e, "connect(2)", addr);
}
catch (IOException e) {
throw sockerr(runtime, "connect(2): name or service not known", e);
Expand Down Expand Up @@ -609,7 +615,7 @@ else if (channel instanceof DatagramChannel) {
throw SocketUtils.sockerr(runtime, "bind(2): unknown host");
}
catch (SocketException e) {
handleSocketException(runtime, e, "bind(2)", iaddr); // throws
throw buildSocketException(runtime, e, "bind(2)", iaddr); // throws
}
catch (IOException e) {
throw sockerr(runtime, "bind(2): name or service not known", e);
Expand All @@ -619,36 +625,31 @@ else if (channel instanceof DatagramChannel) {
}
}

static void handleSocketException(final Ruby runtime, final SocketException ex,
static RaiseException buildSocketException(final Ruby runtime, final SocketException ex,
final String caller, final SocketAddress addr) {

final Errno errno = Helpers.errnoFromException(ex);
final String callerWithAddr = caller + " for " + formatAddress(addr);

if (errno != null) {
return runtime.newErrnoFromErrno(errno, caller);
}

final String message = ex.getMessage();
if ( message != null ) {
switch ( message ) {
case "permission denied" :
case "Permission denied" :
if ( addr == null ) {
throw runtime.newErrnoEACCESError(caller + " - " + message);
}
throw runtime.newErrnoEACCESError("Address already in use - " + caller + " for " + formatAddress(addr));
case "Address already in use" :
throw runtime.newErrnoEADDRINUSEError(caller + " for " + formatAddress(addr));
case "Protocol family unavailable" :
throw runtime.newErrnoEADDRNOTAVAILError(caller + " for " + formatAddress(addr));
}

if (message != null) {
// This is ugly, but what can we do, Java provides the same exception type
// for different situations, so we differentiate the errors
// based on the exception's message.
if (ALREADY_BOUND_PATTERN.matcher(message).find()) {
throw runtime.newErrnoEINVALError(caller + " - " + message);
return runtime.newErrnoEINVALError(callerWithAddr);
}
if (ADDR_NOT_AVAIL_PATTERN.matcher(message).find()) {
throw runtime.newErrnoEADDRNOTAVAILError(caller + " - " + message);
return runtime.newErrnoEADDRNOTAVAILError(callerWithAddr);
}
}

throw runtime.newErrnoEADDRINUSEError(caller + " - " + message);
return runtime.newIOError(callerWithAddr);
}

private static CharSequence formatAddress(final SocketAddress addr) {
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/org/jruby/runtime/Helpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,15 @@ public static Errno errnoFromException(Throwable t) {
return Errno.EMSGSIZE;
case "Is a directory":
return Errno.EISDIR;
case "Operation timed out":
return Errno.ETIMEDOUT;
case "No route to host":
return Errno.EHOSTUNREACH;
case "permission denied":
case "Permission denied":
return Errno.EACCES;
case "Protocol family unavailable":
return Errno.EADDRNOTAVAIL;
}
}
return null;
Expand Down