Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow reusing of datagram socket/setting bind device #662

Merged
merged 1 commit into from
Dec 18, 2015

Conversation

verxx
Copy link

@verxx verxx commented Dec 3, 2015

  • create new function open_datagram_socket_with_reuseaddr
    • the SO_REUSEADDR flag needs to be set before we call the bind on the socket
  • add the support to be able to set_sock_opt with SO_BINDTODEVICE
    • this takes in a struct with an interface name set inside of it

@sodabrew
Copy link
Member

sodabrew commented Dec 3, 2015

This looks pretty good! Could you redo the spacing on the C/C++ changes using tabs instead of spaces, in order to match the code already there?

struct ifreq interface; // create struct
StringValue(optval); // parse the ruby string

strncpy(interface.ifr_name, RSTRING_PTR(optval), IFNAMSIZ); // copy interface to struct
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be StringValueCStr(optval) to ensure that it is nul-terminated. The RSTRING_PTR can point to a Ruby value that doesn't have a nul-terminator; you need RSTRING_LEN to read only the number of valid bytes. And since strncpy does not guarantee a nul-terminator, if the Ruby string doesn't provide one then you may get quite a bit of garbage in there!

@sodabrew
Copy link
Member

sodabrew commented Dec 3, 2015

I might suggest that the REUSEADDR should go directly into the existing open_datagram_socket function, since the corresponding TCP function already sets SO_REUSEADDR.

@verxx
Copy link
Author

verxx commented Dec 8, 2015

I didn't include the RESUSEADDR into the existing open_datagram_socket function because it alters the function parameters and causes one of the tests to fail because it relies on the last args parameter. I'm not sure if changing this will break any other projects or not.

I will address the other comments this week.

@sodabrew
Copy link
Member

sodabrew commented Dec 8, 2015

I wouldn't even make it configurable, this should be the behavior in order to remain consistent with the TCP version of the function. I would merge this for the 1.2.0 release so that it won't be a surprise 1.0.x change.

@verxx
Copy link
Author

verxx commented Dec 14, 2015

Any thing else I need to fix?

@sodabrew
Copy link
Member

Thanks for the ping! I hadn't checked back to see the updated commits. Could you squash the updates into the original commit?

@verxx
Copy link
Author

verxx commented Dec 15, 2015

Ok. Done! Thanks for replying. Let me know if there's anything else.

@@ -67,6 +69,10 @@ typedef int SOCKET;
#endif
#endif /* OS_SOLARIS8 */

#ifndef SO_BINDTODEVICE
#define SO_BINDTODEVICE 25
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some reading on this, and it's a linux-only option. I don't think we should define the value if it is not present; that's an indication that the platform does not support it.

@verxx
Copy link
Author

verxx commented Dec 15, 2015

Yup. You're right. Should be fixed now.

@sodabrew
Copy link
Member

This looks really good. I definitely want to merge the SO_REUSEADDR code.

However, it turns out you may not need any special code to support SO_BINDTODEVICE after all... sorry it took me so many iterations before reading up on alternative approaches. The Ruby documentation for setsockopt shows how to generate a packed struct here:
http://ruby-doc.org/stdlib-1.8.7/libdoc/socket/rdoc/BasicSocket.html#method-i-setsockopt-label-Parameters
and looking at the struct ifreq which has the interface char array right at the beginning:
https://bytes.com/topic/python/answers/30563-passing-argument-setsockopt-socket-sol_socket-so_bindtodevice-intr
and
http://stackoverflow.com/questions/9127311/how-can-you-choose-the-network-interface-via-which-udp-broadcast-packet-is-sent

you should be able to do the device binding like this (note the explicit nul byte in the Ruby string):

EM.run do
  EM.connect "example.com", 80, Module.new {
    define_method :post_init do
      set_sock_opt Socket::SOL_SOCKET, Socket::SO_BINDTODEVICE, "eth0\0"
      EM.stop
    end
  }
end

I tried this with "eth0\0" and got a successful response from set_sock_opt, and with "eth4\0" on a system that had no eth4, and got an appropriate error: lib/em/connection.rb:280:inset_sock_opt: No such device - setsockopt (Errno::ENODEV)

Granted that it is slightly gross to fake the struct, it is consistent with Ruby's own setsockopt. Actually I think I could replace the EM implementation of set_sock_opt with a wrapper around Ruby's own setsockopt on the Ruby side and remove this C function entirely!

@verxx verxx force-pushed the master branch 4 times, most recently from 960cd84 to e9c9fe0 Compare December 16, 2015 22:53
@verxx
Copy link
Author

verxx commented Dec 16, 2015

Ok I verified that it works. New change is ready. I think I was using 1.0.0 which I believe was not working for this correctly.

Btw, I would agree with your wrapper idea. That way the code is not duplicated.

#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
//#include <net/if.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove the commented lines too :)

@verxx verxx force-pushed the master branch 2 times, most recently from 21d582e to 7bbacfc Compare December 17, 2015 01:27
- open_datagram_socket no sets the SO_REUSEADDR flag on the socket
  - the SO_REUSEADDR flag needs to be set before we call bind on the socket
@sodabrew sodabrew added this to the v1.2.0 milestone Dec 17, 2015
@verxx
Copy link
Author

verxx commented Dec 17, 2015

Fixed :) Thanks!

sodabrew added a commit that referenced this pull request Dec 18, 2015
Allow reusing of datagram socket
@sodabrew sodabrew merged commit 076a526 into eventmachine:master Dec 18, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants