Details

    • Type: Bug Bug
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: JRuby 1.7.0.pre1
    • Fix Version/s: JRuby 1.7.0.pre2
    • Component/s: Core Classes/Modules
    • Labels:
      None
    • Environment:
      Mac OS X 10.7.4
    • Number of attachments :
      0

      Description

      In trying to make BERTRPC (https://github.com/mojombo/bertrpc) connections from JRuby, I stumbled on this exception:

      NoMethodError: undefined method `recvfrom' for #<Socket:fd>

      I don't know much about socket programming, unfortunately, but BERTRPC is doing something like this:

      require "socket"
      addr = Socket.getaddrinfo("localhost", nil, Socket::AF_INET)
      sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
      sock.connect(Socket.pack_sockaddr_in(8000, addr[0][3]))
      sock.recvfrom(123)

      On MRI, Socket#recvfrom exists, but on JRuby it does not.

      Any help would be appreciated – I hope I'm missing something simple. (If there's a workaround I could apply to BERTRPC, that would help me a ton in the meantime.)

        Activity

        Hide
        Charles Oliver Nutter added a comment -

        The problem here is that there's no way in Java for us to match recvfrom behavior for normal TCP sockets. It might be possible for us to add it for datagram sockets, however.

        It's also possible that recvfrom can just be an alias for read when doing TCP sockets. Will have to research that a bit.

        Show
        Charles Oliver Nutter added a comment - The problem here is that there's no way in Java for us to match recvfrom behavior for normal TCP sockets. It might be possible for us to add it for datagram sockets, however. It's also possible that recvfrom can just be an alias for read when doing TCP sockets. Will have to research that a bit.
        Hide
        Bryan Helmkamp added a comment -

        FWIW, changing "recvfrom" to "read" works in my 5 second, try-this-locally-one-time test.

        Show
        Bryan Helmkamp added a comment - FWIW, changing "recvfrom" to "read" works in my 5 second, try-this-locally-one-time test.
        Hide
        Charles Oliver Nutter added a comment -

        Yeah, so the problem I'm running into is that there's incredibly few tests for recvfrom anywhere in Rubydom. I found a small cluster of tests in MRI's test/socket/test_addrinfo.rb but they're dependent on AddrInfo being in better shape than it is for us. There's none in RubySpec or any other suite.

        The following patch essentially just makes Socket#recvfrom and recvfrom_nonblock defer to BasicSocket's impl of recv, which is largely what MRI does...but I have no code for confirming it. The BasicSocket recv logic also appears to assume stream-based sockets...which is fine for your case, but would break for UDP or UNIX sockets.

        Writing tests for features we're missing or have implemented incorrectly would be a great way to help this bug move forward. If it's possible for you to build JRuby, you could also test out this patch and see if it works well enough for BERTRPC.

        diff --git a/src/org/jruby/ext/socket/RubySocket.java b/src/org/jruby/ext/socket/RubySocket.java
        index 52d7bd1..b7751f7 100644
        --- a/src/org/jruby/ext/socket/RubySocket.java
        +++ b/src/org/jruby/ext/socket/RubySocket.java
        @@ -215,6 +215,26 @@ public class RubySocket extends RubyBasicSocket {
                 return RubyFixnum.zero(context.getRuntime());
             }
         
        +    @JRubyMethod
        +    public IRubyObject recvfrom(ThreadContext context, IRubyObject length) {
        +        return super.recv(context, length);
        +    }
        +
        +    @JRubyMethod
        +    public IRubyObject recvfrom(ThreadContext context, IRubyObject length, IRubyObject flags) {
        +        return super.recv(context, length, flags);
        +    }
        +
        +    @JRubyMethod
        +    public IRubyObject recvfrom_nonblock(ThreadContext context, IRubyObject length) {
        +        return super.recv_nonblock(context, length);
        +    }
        +
        +    @JRubyMethod
        +    public IRubyObject recvfrom_nonblock(ThreadContext context, IRubyObject length, IRubyObject flags) {
        +        return super.recv_nonblock(context, length, flags);
        +    }
        +
             @JRubyMethod(notImplemented = true)
             public IRubyObject listen(ThreadContext context, IRubyObject backlog) {
                 throw SocketUtils.sockerr(context.runtime, JRUBY_SERVER_SOCKET_ERROR);
        @@ -224,6 +244,7 @@ public class RubySocket extends RubyBasicSocket {
             public IRubyObject accept(ThreadContext context) {
                 throw SocketUtils.sockerr(context.runtime, JRUBY_SERVER_SOCKET_ERROR);
             }
        +
             @JRubyMethod(meta = true)
             public static IRubyObject gethostname(ThreadContext context, IRubyObject recv) {
                 return SocketUtils.gethostname(context);
        
        Show
        Charles Oliver Nutter added a comment - Yeah, so the problem I'm running into is that there's incredibly few tests for recvfrom anywhere in Rubydom. I found a small cluster of tests in MRI's test/socket/test_addrinfo.rb but they're dependent on AddrInfo being in better shape than it is for us. There's none in RubySpec or any other suite. The following patch essentially just makes Socket#recvfrom and recvfrom_nonblock defer to BasicSocket's impl of recv, which is largely what MRI does...but I have no code for confirming it. The BasicSocket recv logic also appears to assume stream-based sockets...which is fine for your case, but would break for UDP or UNIX sockets. Writing tests for features we're missing or have implemented incorrectly would be a great way to help this bug move forward. If it's possible for you to build JRuby, you could also test out this patch and see if it works well enough for BERTRPC. diff --git a/src/org/jruby/ext/socket/RubySocket.java b/src/org/jruby/ext/socket/RubySocket.java index 52d7bd1..b7751f7 100644 --- a/src/org/jruby/ext/socket/RubySocket.java +++ b/src/org/jruby/ext/socket/RubySocket.java @@ -215,6 +215,26 @@ public class RubySocket extends RubyBasicSocket { return RubyFixnum.zero(context.getRuntime()); } + @JRubyMethod + public IRubyObject recvfrom(ThreadContext context, IRubyObject length) { + return super.recv(context, length); + } + + @JRubyMethod + public IRubyObject recvfrom(ThreadContext context, IRubyObject length, IRubyObject flags) { + return super.recv(context, length, flags); + } + + @JRubyMethod + public IRubyObject recvfrom_nonblock(ThreadContext context, IRubyObject length) { + return super.recv_nonblock(context, length); + } + + @JRubyMethod + public IRubyObject recvfrom_nonblock(ThreadContext context, IRubyObject length, IRubyObject flags) { + return super.recv_nonblock(context, length, flags); + } + @JRubyMethod(notImplemented = true) public IRubyObject listen(ThreadContext context, IRubyObject backlog) { throw SocketUtils.sockerr(context.runtime, JRUBY_SERVER_SOCKET_ERROR); @@ -224,6 +244,7 @@ public class RubySocket extends RubyBasicSocket { public IRubyObject accept(ThreadContext context) { throw SocketUtils.sockerr(context.runtime, JRUBY_SERVER_SOCKET_ERROR); } + @JRubyMethod(meta = true) public static IRubyObject gethostname(ThreadContext context, IRubyObject recv) { return SocketUtils.gethostname(context);
        Hide
        Charles Oliver Nutter added a comment -

        I'm just going to go ahead and commit this patch, since it's unlikely to make things worse, but we really need someone to write a few tests for recvfrom and recvfrom_nonblock.

        Show
        Charles Oliver Nutter added a comment - I'm just going to go ahead and commit this patch, since it's unlikely to make things worse , but we really need someone to write a few tests for recvfrom and recvfrom_nonblock.
        Hide
        Charles Oliver Nutter added a comment -
        commit 97409f48890b8ae132eec4d2d3e88ecf0395714f
        Author: Charles Oliver Nutter <headius@headius.com>
        Date:   Thu Jul 5 15:39:07 2012 -0500
        
            Fix JRUBY-6761
            
            NoMethodError: undefined method `recvfrom' for #<Socket:fd>
            
            For now I'm just implementing Socket#recvfrom and
            recvfrom_nonblock to use the BasicSocket versions, which are
            largely just "read". This will work ok for TCP sockets, but we'll
            need additional work to make these aware of UDP and UNIX sockets
            in the same way as the other Socket methods.
            
            We also need tests; RubySpec has none and MRI's suite only has
            a handful.
        
        :100644 100644 52d7bd1... b7751f7... M	src/org/jruby/ext/socket/RubySocket.java
        
        Show
        Charles Oliver Nutter added a comment - commit 97409f48890b8ae132eec4d2d3e88ecf0395714f Author: Charles Oliver Nutter <headius@headius.com> Date: Thu Jul 5 15:39:07 2012 -0500 Fix JRUBY-6761 NoMethodError: undefined method `recvfrom' for #<Socket:fd> For now I'm just implementing Socket#recvfrom and recvfrom_nonblock to use the BasicSocket versions, which are largely just "read". This will work ok for TCP sockets, but we'll need additional work to make these aware of UDP and UNIX sockets in the same way as the other Socket methods. We also need tests; RubySpec has none and MRI's suite only has a handful. :100644 100644 52d7bd1... b7751f7... M src/org/jruby/ext/socket/RubySocket.java
        Hide
        Charles Oliver Nutter added a comment -

        We'll be optimistic about this and call it fixed. The method is there now, and likely works fine for most uses.

        Show
        Charles Oliver Nutter added a comment - We'll be optimistic about this and call it fixed. The method is there now, and likely works fine for most uses.

          People

          • Assignee:
            Charles Oliver Nutter
            Reporter:
            Bryan Helmkamp
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: