diff --git a/lib/socket.rb b/lib/socket.rb index 094f355589..373dd621d3 100644 --- a/lib/socket.rb +++ b/lib/socket.rb @@ -9,6 +9,20 @@ class SocketError < StandardError class BasicSocket < IO + class << self + def from_descriptor(fixnum) + sock = allocate() + sock.from_descriptor(fixnum) + return sock + end + + alias :for_fd :from_descriptor + end + + def from_descriptor(fixnum) + IO.setup self, fixnum, nil, true + return self + end def self.do_not_reverse_lookup=(setting) @no_reverse_lookup = setting @@ -93,6 +107,38 @@ def recv(bytes_to_read, flags = 0) return socket_recv(bytes_to_read, flags, 0) end + def close_read + ensure_open_and_readable + + # If we were only in readonly mode, close it all together + if @mode & ACCMODE == RDONLY + return close + end + + # MRI doesn't check if shutdown worked, so we don't. + Socket::Foreign.shutdown @descriptor, 0 + + @mode = @mode & ~RDONLY + + nil + end + + def close_write + ensure_open_and_writable + + # If we were only in writeonly mode, close it all together + if @mode & ACCMODE == WRONLY + return close + end + + Socket::Foreign.shutdown @descriptor, 1 + + # Remove write from the mode bits + @mode = @mode & ~WRONLY + + nil + end + # # Sets socket nonblocking and reads up to given number of bytes. # @@ -108,25 +154,6 @@ def recv_nonblock(bytes_to_read, flags = 0) # -# @todo Fix. This is horrible. --rue -# -# # -# # Only close the read stream. -# # -# # This affects all processes using this stream! -# # -# def close_read() -# shutdown Socket::SHUT_RD -# end -# -# # -# # Only close the write stream. -# # -# # This affects all processes using this stream! -# # -# def close_write() -# shutdown Socket::SHUT_WR -# end end @@ -170,6 +197,7 @@ class AddrInfo < FFI::Struct attach_function :accept, [:int, :pointer, :pointer], :int attach_function :close, [:int], :int + attach_function :shutdown, [:int, :int], :int attach_function :listen, [:int, :int], :int attach_function :socket, [:int, :int, :int], :int attach_function :send, [:int, :pointer, :int, :int], :int @@ -609,12 +637,36 @@ def self.unpack_sockaddr_in(sockaddr) end end - def self.socketpair(domain, type, protocol) + def self.socketpair(domain, type, protocol, klass=self) + if domain.kind_of? String + if domain.prefix? "AF_" or domain.prefix? "PF_" + begin + domain = Socket::Constants.const_get(domain) + rescue NameError + raise SocketError, "unknown socket domain #{domani}" + end + else + raise SocketError, "unknown socket domain #{domani}" + end + end + + if type.kind_of? String + if type.prefix? "SOCK_" + begin + type = Socket::Constants.const_get(type) + rescue NameError + raise SocketError, "unknown socket type #{type}" + end + else + raise SocketError, "unknown socket type #{type}" + end + end + FFI::MemoryPointer.new :int, 2 do |mp| Socket::Foreign.socketpair(domain, type, protocol, mp) fd0, fd1 = mp.read_array_of_int(2) - [ from_descriptor(fd0), from_descriptor(fd1) ] + [ klass.from_descriptor(fd0), klass.from_descriptor(fd1) ] end end @@ -654,21 +706,6 @@ def initialize(family, socket_type, protocol) IO.setup self, descriptor, nil, true end - class << self - def from_descriptor(fixnum) - sock = allocate() - sock.from_descriptor(fixnum) - return sock - end - - alias :for_fd :from_descriptor - end - - def from_descriptor(fixnum) - IO.setup self, fixnum, nil, true - return self - end - def bind(server_sockaddr) err = Socket::Foreign.bind(descriptor, server_sockaddr) Errno.handle 'bind(2)' unless err == 0 @@ -692,7 +729,6 @@ def connect(*args) return 0 end - end class UNIXSocket < BasicSocket @@ -711,6 +747,11 @@ def initialize(path) end private :initialize + def from_descriptor(fixnum) + super + @path = "" + end + def unix_setup(server = false) status = nil phase = 'socket(2)' @@ -757,12 +798,13 @@ def peeraddr ["AF_UNIX", sock_path] end - def from_descriptor(descriptor) - IO.setup self, descriptor, nil, true + class << self + def socketpair(type=Socket::SOCK_STREAM, protocol=0) + Socket.socketpair(Socket::PF_UNIX, type, protocol, self) + end - self + alias_method :pair, :socketpair end - private :from_descriptor end diff --git a/spec/tags/ruby/library/socket/basicsocket/close_read_tags.txt b/spec/tags/ruby/library/socket/basicsocket/close_read_tags.txt index dd82d83174..c1ae14405f 100644 --- a/spec/tags/ruby/library/socket/basicsocket/close_read_tags.txt +++ b/spec/tags/ruby/library/socket/basicsocket/close_read_tags.txt @@ -1,5 +1,3 @@ fails:Socket::BasicSocket#close_read closes the reading end of the socket fails:Socket::BasicSocket#close_read it works on sockets with closed ends -fails:Socket::BasicSocket#close_read does not close the socket fails:Socket::BasicSocket#close_read fully closes the socket if it was already closed for writing -fails:Socket::BasicSocket#close_read returns nil diff --git a/spec/tags/ruby/library/socket/basicsocket/close_write_tags.txt b/spec/tags/ruby/library/socket/basicsocket/close_write_tags.txt index dbc1763f8f..66334966a5 100644 --- a/spec/tags/ruby/library/socket/basicsocket/close_write_tags.txt +++ b/spec/tags/ruby/library/socket/basicsocket/close_write_tags.txt @@ -1,5 +1,3 @@ fails:Socket::BasicSocket#close_write closes the writing end of the socket fails:Socket::BasicSocket#close_write works on sockets with closed write ends -fails:Socket::BasicSocket#close_write does not close the socket fails:Socket::BasicSocket#close_write fully closes the socket if it was already closed for reading -fails:Socket::BasicSocket#close_write returns nil diff --git a/spec/tags/ruby/library/socket/tcpsocket/partially_closable_tags.txt b/spec/tags/ruby/library/socket/tcpsocket/partially_closable_tags.txt deleted file mode 100644 index 891cbb265f..0000000000 --- a/spec/tags/ruby/library/socket/tcpsocket/partially_closable_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:TCPSocket partial closability if the write end is closed then the other side can read past EOF without blocking -fails:TCPSocket partial closability closing the write end ensures that the other side can read until EOF diff --git a/spec/tags/ruby/library/socket/udpsocket/bind_tags.txt b/spec/tags/ruby/library/socket/udpsocket/bind_tags.txt deleted file mode 100644 index 94b003c696..0000000000 --- a/spec/tags/ruby/library/socket/udpsocket/bind_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:UDPSocket.bind receives a hostname and a port diff --git a/spec/tags/ruby/library/socket/unixsocket/pair_tags.txt b/spec/tags/ruby/library/socket/unixsocket/pair_tags.txt deleted file mode 100644 index 200140f495..0000000000 --- a/spec/tags/ruby/library/socket/unixsocket/pair_tags.txt +++ /dev/null @@ -1,6 +0,0 @@ -fails:UNIXSocket#pair returns a pair of connected sockets -fails:UNIXSocket#pair returns sockets with no name -fails:UNIXSocket#pair returns sockets with no address -fails:UNIXSocket#pair returns sockets with no peeraddr -fails:UNIXSocket#pair if the write end is closed then the other side can read past EOF without blocking -fails:UNIXSocket#pair closing the write end ensures that the other side can read until EOF diff --git a/spec/tags/ruby/library/socket/unixsocket/partially_closable_tags.txt b/spec/tags/ruby/library/socket/unixsocket/partially_closable_tags.txt deleted file mode 100644 index 578640c9aa..0000000000 --- a/spec/tags/ruby/library/socket/unixsocket/partially_closable_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:UNIXSocket partial closability if the write end is closed then the other side can read past EOF without blocking -fails:UNIXSocket partial closability closing the write end ensures that the other side can read until EOF