diff --git a/ext/rubymain.cpp b/ext/rubymain.cpp index b5e0425ce..a87267cc4 100644 --- a/ext/rubymain.cpp +++ b/ext/rubymain.cpp @@ -583,6 +583,44 @@ static VALUE t_get_sock_opt (VALUE self, VALUE signature, VALUE lev, VALUE optna return rb_str_new(buf, len); } +/************** +t_set_sock_opt +**************/ + +static VALUE t_set_sock_opt (VALUE self, VALUE signature, VALUE lev, VALUE optname, VALUE optval) +{ + int fd = evma_get_file_descriptor (NUM2ULONG (signature)); + int level = NUM2INT(lev), option = NUM2INT(optname); + int i; + void *v; + socklen_t len; + + switch (TYPE(optval)) { + case T_FIXNUM: + i = FIX2INT(optval); + goto numval; + case T_FALSE: + i = 0; + goto numval; + case T_TRUE: + i = 1; + numval: + v = (void*)&i; len = sizeof(i); + break; + default: + StringValue(optval); + v = RSTRING_PTR(optval); + len = RSTRING_LENINT(optval); + break; + } + + + if (setsockopt(fd, level, option, v, len) < 0) + rb_sys_fail("setsockopt"); + + return INT2FIX(0); +} + /******************** t_is_notify_readable ********************/ @@ -1133,6 +1171,7 @@ extern "C" void Init_rubyeventmachine() rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 2); rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1); rb_define_module_function (EmModule, "get_sock_opt", (VALUE (*)(...))t_get_sock_opt, 3); + rb_define_module_function (EmModule, "set_sock_opt", (VALUE (*)(...))t_set_sock_opt, 4); rb_define_module_function (EmModule, "set_notify_readable", (VALUE (*)(...))t_set_notify_readable, 2); rb_define_module_function (EmModule, "set_notify_writable", (VALUE (*)(...))t_set_notify_writable, 2); rb_define_module_function (EmModule, "is_notify_readable", (VALUE (*)(...))t_is_notify_readable, 1); diff --git a/lib/em/connection.rb b/lib/em/connection.rb index 83b11fd00..14c3388dd 100644 --- a/lib/em/connection.rb +++ b/lib/em/connection.rb @@ -270,6 +270,10 @@ def get_sock_opt level, option EventMachine::get_sock_opt @signature, level, option end + def set_sock_opt level, optname, optval + EventMachine::set_sock_opt @signature, level, optname, optval + end + # A variant of {#close_connection}. # All of the descriptive comments given for close_connection also apply to # close_connection_after_writing, *with one exception*: if the connection has diff --git a/tests/test_set_sock_opt.rb b/tests/test_set_sock_opt.rb new file mode 100644 index 000000000..3d3020a94 --- /dev/null +++ b/tests/test_set_sock_opt.rb @@ -0,0 +1,37 @@ +require 'em_test_helper' +require 'socket' + +class TestSetSockOpt < Test::Unit::TestCase + + if EM.respond_to? :set_sock_opt + def setup + assert(!EM.reactor_running?) + end + + def teardown + assert(!EM.reactor_running?) + end + + #------------------------------------- + + def test_set_sock_opt + test = self + EM.run do + EM.connect 'google.com', 80, Module.new { + define_method :post_init do + val = set_sock_opt Socket::SOL_SOCKET, Socket::SO_DEBUG, true + test.assert_equal 0, val + EM.stop + end + } + end + end + else + warn "EM.set_sock_opt not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_set_sock_opt_unsupported + assert true + end + end +end