{"action":"created","issue":{"url":"https://api.github.com/repos/jruby/jruby/issues/3230","labels_url":"https://api.github.com/repos/jruby/jruby/issues/3230/labels{/name}","comments_url":"https://api.github.com/repos/jruby/jruby/issues/3230/comments","events_url":"https://api.github.com/repos/jruby/jruby/issues/3230/events","html_url":"https://github.com/jruby/jruby/issues/3230","id":99515035,"number":3230,"title":"BasicSocket#setsockopt doesn't support SO_RCVTIMEO & SO_SNDTIMEO","user":{"login":"agis-","id":827224,"avatar_url":"https://avatars.githubusercontent.com/u/827224?v=3","gravatar_id":"","url":"https://api.github.com/users/agis-","html_url":"https://github.com/agis-","followers_url":"https://api.github.com/users/agis-/followers","following_url":"https://api.github.com/users/agis-/following{/other_user}","gists_url":"https://api.github.com/users/agis-/gists{/gist_id}","starred_url":"https://api.github.com/users/agis-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agis-/subscriptions","organizations_url":"https://api.github.com/users/agis-/orgs","repos_url":"https://api.github.com/users/agis-/repos","events_url":"https://api.github.com/users/agis-/events{/privacy}","received_events_url":"https://api.github.com/users/agis-/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-08-06T20:12:43Z","updated_at":"2015-08-07T19:55:35Z","closed_at":null,"body":"To demonstrate:\r\n\r\n```ruby\r\nrequire 'socket'\r\n\r\nsocket = UNIXSocket.new(\"/path/to/socket.sock\")\r\nsocket.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, false) # => Errno::ENOPROTOOPT: Protocol not available - Protocol not available\r\n```"},"comment":{"url":"https://api.github.com/repos/jruby/jruby/issues/comments/128814930","html_url":"https://github.com/jruby/jruby/issues/3230#issuecomment-128814930","issue_url":"https://api.github.com/repos/jruby/jruby/issues/3230","id":128814930,"user":{"login":"rtyler","id":26594,"avatar_url":"https://avatars.githubusercontent.com/u/26594?v=3","gravatar_id":"","url":"https://api.github.com/users/rtyler","html_url":"https://github.com/rtyler","followers_url":"https://api.github.com/users/rtyler/followers","following_url":"https://api.github.com/users/rtyler/following{/other_user}","gists_url":"https://api.github.com/users/rtyler/gists{/gist_id}","starred_url":"https://api.github.com/users/rtyler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtyler/subscriptions","organizations_url":"https://api.github.com/users/rtyler/orgs","repos_url":"https://api.github.com/users/rtyler/repos","events_url":"https://api.github.com/users/rtyler/events{/privacy}","received_events_url":"https://api.github.com/users/rtyler/received_events","type":"User","site_admin":false},"created_at":"2015-08-07T19:55:35Z","updated_at":"2015-08-07T19:55:35Z","body":"There is a bug here, but the code above won't work in MRI either since `setsockopt(2)` doesn't take simple int options for the `SO_SNDTIMEO` option\r\n\r\nOn MRI (2.1.5):\r\n```\r\n[9] pry(main)> s = UNIXSocket.new('/tmp/rubysock')\r\n=> #<UNIXSocket:fd 10>\r\n[10] pry(main)> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, false)\r\nErrno::EINVAL: Invalid argument - setsockopt(2)\r\n```\r\n\r\nThe reason is that the underlying syscall (`setsockopt(2)`) requires that the socket option be a timeval struct, `man 7 socket` explains these options:\r\n\r\n```\r\n       SO_RCVTIMEO and SO_SNDTIMEO\r\n              Specify the receiving or sending timeouts until reporting an error.  The argument is a struct timeval.  If an input or output function blocks\r\n              for  this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no\r\n              data has been transferred and the timeout has been reached, then -1 is returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS  (for\r\n              connect(2))  just  as  if  the  socket was specified to be nonblocking.  If the timeout is set to zero (the default), then the operation will\r\n              never timeout.  Timeouts only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts\r\n              have no effect for select(2), poll(2), epoll_wait(2), and so on\r\n```\r\n\r\n\r\nSo that sucks, [here's an explanation](https://moret1979.wordpress.com/2014/09/03/socket-read-timeout/) of a work-around in MRI:\r\n\r\nBasically we have to make something that looks like this timeval struct, e.g.\r\n```\r\n[25] pry(main)> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, [0, 0].pack('l_2'))\r\n=> 0\r\n[26] pry(main)> \r\n```\r\n\r\n**RIGHT, so..**\r\n\r\nBack to JRuby (1.7.21):\r\n\r\n```\r\n[2] pry(main)> s = UNIXSocket.new('/tmp/rubysock')\r\n=> #<UNIXSocket:0x102cec62>\r\n[3] pry(main)> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, false)\r\nErrno::ENOPROTOOPT: Protocol not available - Protocol not available\r\nfrom (pry):3:in `evaluate_ruby'\r\n[4] pry(main)> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, [0, 0].pack('l_2'))\r\nErrno::ENOPROTOOPT: Protocol not available - Protocol not available\r\nfrom (pry):5:in `evaluate_ruby'\r\n[5] pry(main)> \r\n```\r\n\r\n\r\nDrats! @headius or @enebo this fails in JRuby 1.7.21 and JRuby 9k, considering that a struct is being passed around by reference in the MRI implementation of this, I'm not sure that this is super simple to correct.\r\n"}}