rubysl-socket 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -16
- data/lib/rubysl/socket.rb +201 -1396
- data/lib/rubysl/socket/ancillary_data.rb +56 -0
- data/lib/rubysl/socket/bsd.rb +28 -0
- data/lib/rubysl/socket/error.rb +67 -0
- data/lib/rubysl/socket/foreign.rb +324 -0
- data/lib/rubysl/socket/foreign/addrinfo.rb +10 -0
- data/lib/rubysl/socket/foreign/hostent.rb +36 -0
- data/lib/rubysl/socket/foreign/ifaddrs.rb +129 -0
- data/lib/rubysl/socket/foreign/iovec.rb +18 -0
- data/lib/rubysl/socket/foreign/linger.rb +41 -0
- data/lib/rubysl/socket/foreign/msghdr.rb +41 -0
- data/lib/rubysl/socket/foreign/servent.rb +17 -0
- data/lib/rubysl/socket/foreign/sockaddr.rb +21 -0
- data/lib/rubysl/socket/foreign/sockaddr_in.rb +25 -0
- data/lib/rubysl/socket/foreign/sockaddr_in6.rb +25 -0
- data/lib/rubysl/socket/foreign/sockaddr_un.rb +29 -0
- data/lib/rubysl/socket/ipv6.rb +38 -0
- data/lib/rubysl/socket/linux.rb +16 -0
- data/lib/rubysl/socket/socket_options.rb +84 -0
- data/lib/rubysl/socket/version.rb +1 -1
- data/lib/socket.rb +45 -1
- data/lib/socket/addrinfo.rb +453 -0
- data/lib/socket/ancillary_data.rb +114 -0
- data/lib/socket/basic_socket.rb +295 -0
- data/lib/socket/constants.rb +41 -0
- data/lib/socket/ifaddr.rb +29 -0
- data/lib/socket/ip_socket.rb +37 -0
- data/lib/socket/mri.rb +928 -0
- data/lib/socket/option.rb +96 -0
- data/lib/socket/socket.rb +353 -0
- data/lib/socket/socket_error.rb +2 -0
- data/lib/socket/tcp_server.rb +78 -0
- data/lib/socket/tcp_socket.rb +109 -0
- data/lib/socket/udp_socket.rb +73 -0
- data/lib/socket/unix_server.rb +35 -0
- data/lib/socket/unix_socket.rb +78 -0
- data/rubysl-socket.gemspec +15 -10
- metadata +78 -293
- data/.gitignore +0 -17
- data/.travis.yml +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/spec/addrinfo/afamily_spec.rb +0 -5
- data/spec/addrinfo/bind_spec.rb +0 -5
- data/spec/addrinfo/canonname_spec.rb +0 -5
- data/spec/addrinfo/connect_from_spec.rb +0 -5
- data/spec/addrinfo/connect_spec.rb +0 -5
- data/spec/addrinfo/connect_to_spec.rb +0 -5
- data/spec/addrinfo/family_addrinfo_spec.rb +0 -5
- data/spec/addrinfo/foreach_spec.rb +0 -5
- data/spec/addrinfo/getaddrinfo_spec.rb +0 -5
- data/spec/addrinfo/getnameinfo_spec.rb +0 -5
- data/spec/addrinfo/inspect_sockaddr_spec.rb +0 -5
- data/spec/addrinfo/inspect_spec.rb +0 -5
- data/spec/addrinfo/ip_address_spec.rb +0 -5
- data/spec/addrinfo/ip_port_spec.rb +0 -5
- data/spec/addrinfo/ip_spec.rb +0 -9
- data/spec/addrinfo/ip_unpack_spec.rb +0 -5
- data/spec/addrinfo/ipv4_loopback_spec.rb +0 -5
- data/spec/addrinfo/ipv4_multicast_spec.rb +0 -5
- data/spec/addrinfo/ipv4_private_spec.rb +0 -5
- data/spec/addrinfo/ipv4_spec.rb +0 -5
- data/spec/addrinfo/ipv6_linklocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_loopback_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_global_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_linklocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_nodelocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_orglocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_sitelocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_multicast_spec.rb +0 -5
- data/spec/addrinfo/ipv6_sitelocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_spec.rb +0 -5
- data/spec/addrinfo/ipv6_to_ipv4_spec.rb +0 -5
- data/spec/addrinfo/ipv6_unspecified_spec.rb +0 -5
- data/spec/addrinfo/ipv6_v4compat_spec.rb +0 -5
- data/spec/addrinfo/ipv6_v4mapped_spec.rb +0 -5
- data/spec/addrinfo/listen_spec.rb +0 -5
- data/spec/addrinfo/marshal_dump_spec.rb +0 -5
- data/spec/addrinfo/marshal_load_spec.rb +0 -5
- data/spec/addrinfo/pfamily_spec.rb +0 -5
- data/spec/addrinfo/protocol_spec.rb +0 -5
- data/spec/addrinfo/socktype_spec.rb +0 -5
- data/spec/addrinfo/tcp_spec.rb +0 -5
- data/spec/addrinfo/to_s_spec.rb +0 -5
- data/spec/addrinfo/to_sockaddr_spec.rb +0 -5
- data/spec/addrinfo/udp_spec.rb +0 -5
- data/spec/addrinfo/unix_path_spec.rb +0 -5
- data/spec/addrinfo/unix_spec.rb +0 -9
- data/spec/basicsocket/close_read_spec.rb +0 -42
- data/spec/basicsocket/close_write_spec.rb +0 -42
- data/spec/basicsocket/do_not_reverse_lookup_spec.rb +0 -78
- data/spec/basicsocket/for_fd_spec.rb +0 -37
- data/spec/basicsocket/getpeername_spec.rb +0 -24
- data/spec/basicsocket/getsockname_spec.rb +0 -27
- data/spec/basicsocket/getsockopt_spec.rb +0 -54
- data/spec/basicsocket/ioctl_spec.rb +0 -22
- data/spec/basicsocket/recv_nonblock_spec.rb +0 -6
- data/spec/basicsocket/recv_spec.rb +0 -76
- data/spec/basicsocket/send_spec.rb +0 -81
- data/spec/basicsocket/setsockopt_spec.rb +0 -333
- data/spec/basicsocket/shutdown_spec.rb +0 -5
- data/spec/constants/constants_spec.rb +0 -63
- data/spec/fixtures/classes.rb +0 -174
- data/spec/fixtures/send_io.txt +0 -1
- data/spec/ipsocket/addr_spec.rb +0 -72
- data/spec/ipsocket/getaddress_spec.rb +0 -26
- data/spec/ipsocket/peeraddr_spec.rb +0 -79
- data/spec/ipsocket/recvfrom_spec.rb +0 -64
- data/spec/option/int_spec.rb +0 -27
- data/spec/option/linger_spec.rb +0 -52
- data/spec/option/new_spec.rb +0 -32
- data/spec/shared/pack_sockaddr.rb +0 -26
- data/spec/shared/partially_closable_sockets.rb +0 -13
- data/spec/shared/recv_nonblock.rb +0 -33
- data/spec/shared/socketpair.rb +0 -35
- data/spec/socket/accept_nonblock_spec.rb +0 -27
- data/spec/socket/accept_spec.rb +0 -1
- data/spec/socket/bind_spec.rb +0 -80
- data/spec/socket/connect_nonblock_spec.rb +0 -62
- data/spec/socket/connect_spec.rb +0 -1
- data/spec/socket/for_fd_spec.rb +0 -29
- data/spec/socket/getaddrinfo_spec.rb +0 -120
- data/spec/socket/gethostbyaddr_spec.rb +0 -1
- data/spec/socket/gethostbyname_spec.rb +0 -26
- data/spec/socket/gethostname_spec.rb +0 -9
- data/spec/socket/getnameinfo_spec.rb +0 -57
- data/spec/socket/getservbyname_spec.rb +0 -24
- data/spec/socket/listen_spec.rb +0 -21
- data/spec/socket/new_spec.rb +0 -109
- data/spec/socket/pack_sockaddr_in_spec.rb +0 -6
- data/spec/socket/pack_sockaddr_un_spec.rb +0 -6
- data/spec/socket/pair_spec.rb +0 -6
- data/spec/socket/recvfrom_nonblock_spec.rb +0 -1
- data/spec/socket/recvfrom_spec.rb +0 -1
- data/spec/socket/sockaddr_in_spec.rb +0 -6
- data/spec/socket/sockaddr_un_spec.rb +0 -6
- data/spec/socket/socket_spec.rb +0 -37
- data/spec/socket/socketpair_spec.rb +0 -6
- data/spec/socket/sysaccept_spec.rb +0 -1
- data/spec/socket/unpack_sockaddr_in_spec.rb +0 -16
- data/spec/socket/unpack_sockaddr_un_spec.rb +0 -2
- data/spec/tcpserver/accept_nonblock_spec.rb +0 -30
- data/spec/tcpserver/accept_spec.rb +0 -60
- data/spec/tcpserver/gets_spec.rb +0 -17
- data/spec/tcpserver/listen_spec.rb +0 -1
- data/spec/tcpserver/new_spec.rb +0 -88
- data/spec/tcpserver/output_spec.rb +0 -8
- data/spec/tcpserver/readpartial_spec.rb +0 -8
- data/spec/tcpserver/sysaccept_spec.rb +0 -1
- data/spec/tcpsocket/gethostbyname_spec.rb +0 -62
- data/spec/tcpsocket/new_spec.rb +0 -5
- data/spec/tcpsocket/open_spec.rb +0 -5
- data/spec/tcpsocket/partially_closable_spec.rb +0 -20
- data/spec/tcpsocket/recv_nonblock_spec.rb +0 -31
- data/spec/tcpsocket/setsockopt_spec.rb +0 -49
- data/spec/tcpsocket/shared/new.rb +0 -85
- data/spec/udpsocket/bind_spec.rb +0 -33
- data/spec/udpsocket/connect_spec.rb +0 -1
- data/spec/udpsocket/new_spec.rb +0 -1
- data/spec/udpsocket/open_spec.rb +0 -12
- data/spec/udpsocket/recvfrom_nonblock_spec.rb +0 -1
- data/spec/udpsocket/send_spec.rb +0 -57
- data/spec/unixserver/accept_nonblock_spec.rb +0 -33
- data/spec/unixserver/accept_spec.rb +0 -64
- data/spec/unixserver/for_fd_spec.rb +0 -32
- data/spec/unixserver/new_spec.rb +0 -5
- data/spec/unixserver/open_spec.rb +0 -25
- data/spec/unixserver/shared/new.rb +0 -23
- data/spec/unixsocket/addr_spec.rb +0 -37
- data/spec/unixsocket/new_spec.rb +0 -5
- data/spec/unixsocket/open_spec.rb +0 -26
- data/spec/unixsocket/pair_spec.rb +0 -38
- data/spec/unixsocket/partially_closable_spec.rb +0 -25
- data/spec/unixsocket/path_spec.rb +0 -29
- data/spec/unixsocket/peeraddr_spec.rb +0 -29
- data/spec/unixsocket/recv_io_spec.rb +0 -40
- data/spec/unixsocket/recvfrom_spec.rb +0 -48
- data/spec/unixsocket/send_io_spec.rb +0 -30
- data/spec/unixsocket/shared/new.rb +0 -25
@@ -0,0 +1,114 @@
|
|
1
|
+
class Socket < BasicSocket
|
2
|
+
class AncillaryData
|
3
|
+
attr_reader :family, :level, :type
|
4
|
+
|
5
|
+
def self.int(family, level, type, integer)
|
6
|
+
new(family, level, type, [integer].pack('I'))
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.unix_rights(*ios)
|
10
|
+
descriptors = ios.map do |io|
|
11
|
+
unless io.is_a?(IO)
|
12
|
+
raise TypeError, "IO expected, got #{io.class} instead"
|
13
|
+
end
|
14
|
+
|
15
|
+
io.fileno
|
16
|
+
end
|
17
|
+
|
18
|
+
instance = new(:UNIX, :SOCKET, :RIGHTS, descriptors.pack('I*'))
|
19
|
+
|
20
|
+
# MRI sets this using a hidden instance variable ("unix_rights"). Because
|
21
|
+
# you can't set hidden instance variables from within Ruby we'll have to
|
22
|
+
# use a regular instance variable. Lets hope people don't mess with it.
|
23
|
+
instance.instance_variable_set(:@unix_rights, ios)
|
24
|
+
|
25
|
+
instance
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.ip_pktinfo(addr, ifindex, spec_dst = nil)
|
29
|
+
spec_dst ||= addr
|
30
|
+
|
31
|
+
instance = new(:INET, :IP, :PKTINFO, '')
|
32
|
+
pkt_info = [
|
33
|
+
Addrinfo.ip(addr.ip_address),
|
34
|
+
ifindex,
|
35
|
+
Addrinfo.ip(spec_dst.ip_address)
|
36
|
+
]
|
37
|
+
|
38
|
+
instance.instance_variable_set(:@ip_pktinfo, pkt_info)
|
39
|
+
|
40
|
+
instance
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.ipv6_pktinfo(addr, ifindex)
|
44
|
+
instance = new(:INET6, :IPV6, :PKTINFO, '')
|
45
|
+
pkt_info = [Addrinfo.ip(addr.ip_address), ifindex]
|
46
|
+
|
47
|
+
instance.instance_variable_set(:@ipv6_pktinfo, pkt_info)
|
48
|
+
|
49
|
+
instance
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(family, level, type, data)
|
53
|
+
@family = RubySL::Socket.address_family(family)
|
54
|
+
@data = RubySL::Socket.coerce_to_string(data)
|
55
|
+
@level = RubySL::Socket::AncillaryData.level(level)
|
56
|
+
@type = RubySL::Socket::AncillaryData.type(@family, @level, type)
|
57
|
+
end
|
58
|
+
|
59
|
+
def cmsg_is?(level, type)
|
60
|
+
level = RubySL::Socket::AncillaryData.level(level)
|
61
|
+
type = RubySL::Socket::AncillaryData.type(@family, level, type)
|
62
|
+
|
63
|
+
@level == level && @type == type
|
64
|
+
end
|
65
|
+
|
66
|
+
def int
|
67
|
+
unpacked = @data.unpack('I')[0]
|
68
|
+
|
69
|
+
unless unpacked
|
70
|
+
raise TypeError, 'data could not be unpacked into a Fixnum'
|
71
|
+
end
|
72
|
+
|
73
|
+
unpacked
|
74
|
+
end
|
75
|
+
|
76
|
+
def unix_rights
|
77
|
+
if @level != Socket::SOL_SOCKET or @type != Socket::SCM_RIGHTS
|
78
|
+
raise TypeError, 'SCM_RIGHTS ancillary data expected'
|
79
|
+
end
|
80
|
+
|
81
|
+
@unix_rights
|
82
|
+
end
|
83
|
+
|
84
|
+
def data
|
85
|
+
if @ip_pktinfo or @ipv6_pktinfo
|
86
|
+
raise NotImplementedError,
|
87
|
+
'AncillaryData#data is not supported as its output depends on ' \
|
88
|
+
'MRI specific internals, use #ip_pktinfo or #ipv6_pktinfo instead'
|
89
|
+
else
|
90
|
+
@data
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def ip_pktinfo
|
95
|
+
addr, ifindex, spec = @ip_pktinfo
|
96
|
+
|
97
|
+
[addr.dup, ifindex, spec.dup]
|
98
|
+
end
|
99
|
+
|
100
|
+
def ipv6_pktinfo
|
101
|
+
addr, ifindex = @ipv6_pktinfo
|
102
|
+
|
103
|
+
[addr.dup, ifindex]
|
104
|
+
end
|
105
|
+
|
106
|
+
def ipv6_pktinfo_addr
|
107
|
+
ipv6_pktinfo[0]
|
108
|
+
end
|
109
|
+
|
110
|
+
def ipv6_pktinfo_ifindex
|
111
|
+
ipv6_pktinfo[1]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
class BasicSocket < IO
|
2
|
+
def self.for_fd(fixnum)
|
3
|
+
sock = allocate
|
4
|
+
|
5
|
+
IO.setup(sock, fixnum, nil, true)
|
6
|
+
|
7
|
+
sock
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.do_not_reverse_lookup=(setting)
|
11
|
+
@no_reverse_lookup = setting
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.do_not_reverse_lookup
|
15
|
+
@no_reverse_lookup = true unless defined?(@no_reverse_lookup)
|
16
|
+
@no_reverse_lookup
|
17
|
+
end
|
18
|
+
|
19
|
+
def do_not_reverse_lookup=(setting)
|
20
|
+
@no_reverse_lookup = setting
|
21
|
+
end
|
22
|
+
|
23
|
+
def do_not_reverse_lookup
|
24
|
+
@no_reverse_lookup
|
25
|
+
end
|
26
|
+
|
27
|
+
def getsockopt(level, optname)
|
28
|
+
sockname = RubySL::Socket::Foreign.getsockname(descriptor)
|
29
|
+
family = RubySL::Socket.family_for_sockaddr_in(sockname)
|
30
|
+
level = RubySL::Socket::SocketOptions.socket_level(level, family)
|
31
|
+
optname = RubySL::Socket::SocketOptions.socket_option(level, optname)
|
32
|
+
data = RubySL::Socket::Foreign.getsockopt(descriptor, level, optname)
|
33
|
+
|
34
|
+
Socket::Option.new(family, level, optname, data)
|
35
|
+
end
|
36
|
+
|
37
|
+
def setsockopt(level_or_option, optname = nil, optval = nil)
|
38
|
+
if level_or_option and optname and optval
|
39
|
+
if level_or_option.is_a?(Socket::Option)
|
40
|
+
raise TypeError,
|
41
|
+
'expected the first argument to be a Fixnum, Symbol, or String'
|
42
|
+
end
|
43
|
+
|
44
|
+
level = level_or_option
|
45
|
+
elsif level_or_option.is_a?(Socket::Option)
|
46
|
+
raise(ArgumentError, 'given 2, expected 1') if optname
|
47
|
+
|
48
|
+
level = level_or_option.level
|
49
|
+
optname = level_or_option.optname
|
50
|
+
optval = level_or_option.data
|
51
|
+
else
|
52
|
+
raise TypeError,
|
53
|
+
'expected the first argument to be a Fixnum, Symbol, String, or Socket::Option'
|
54
|
+
end
|
55
|
+
|
56
|
+
optval = 1 if optval == true
|
57
|
+
optval = 0 if optval == false
|
58
|
+
|
59
|
+
sockname = RubySL::Socket::Foreign.getsockname(descriptor)
|
60
|
+
family = RubySL::Socket.family_for_sockaddr_in(sockname)
|
61
|
+
level = RubySL::Socket::SocketOptions.socket_level(level, family)
|
62
|
+
optname = RubySL::Socket::SocketOptions.socket_option(level, optname)
|
63
|
+
error = 0
|
64
|
+
|
65
|
+
if optval.is_a?(Fixnum)
|
66
|
+
RubySL::Socket::Foreign.memory_pointer(:socklen_t) do |pointer|
|
67
|
+
pointer.write_int(optval)
|
68
|
+
|
69
|
+
error = RubySL::Socket::Foreign
|
70
|
+
.setsockopt(descriptor, level, optname, pointer, pointer.total)
|
71
|
+
end
|
72
|
+
elsif optval.is_a?(String)
|
73
|
+
RubySL::Socket::Foreign.memory_pointer(optval.bytesize) do |pointer|
|
74
|
+
pointer.write_string(optval)
|
75
|
+
|
76
|
+
error = RubySL::Socket::Foreign
|
77
|
+
.setsockopt(descriptor, level, optname, pointer, optval.bytesize)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
raise TypeError, 'socket option should be a Fixnum, String, true, or false'
|
81
|
+
end
|
82
|
+
|
83
|
+
Errno.handle('unable to set socket option') if error < 0
|
84
|
+
|
85
|
+
0
|
86
|
+
end
|
87
|
+
|
88
|
+
def getsockname
|
89
|
+
RubySL::Socket::Foreign.getsockname(descriptor)
|
90
|
+
end
|
91
|
+
|
92
|
+
def getpeername
|
93
|
+
RubySL::Socket::Foreign.getpeername(descriptor)
|
94
|
+
end
|
95
|
+
|
96
|
+
def send(message, flags, dest_sockaddr = nil)
|
97
|
+
bytes = message.bytesize
|
98
|
+
bytes_sent = 0
|
99
|
+
|
100
|
+
if dest_sockaddr.is_a?(Addrinfo)
|
101
|
+
dest_sockaddr = dest_sockaddr.to_sockaddr
|
102
|
+
end
|
103
|
+
|
104
|
+
RubySL::Socket::Foreign.char_pointer(bytes) do |buffer|
|
105
|
+
buffer.write_string(message)
|
106
|
+
|
107
|
+
if dest_sockaddr.is_a?(String)
|
108
|
+
addr = RubySL::Socket.sockaddr_class_for_socket(self)
|
109
|
+
.with_sockaddr(dest_sockaddr)
|
110
|
+
|
111
|
+
begin
|
112
|
+
bytes_sent = RubySL::Socket::Foreign
|
113
|
+
.sendto(descriptor, buffer, bytes, flags, addr, addr.size)
|
114
|
+
ensure
|
115
|
+
addr.free
|
116
|
+
end
|
117
|
+
else
|
118
|
+
bytes_sent = RubySL::Socket::Foreign
|
119
|
+
.send(descriptor, buffer, bytes, flags)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
RubySL::Socket::Error.write_error('send(2)', self) if bytes_sent < 0
|
124
|
+
|
125
|
+
bytes_sent
|
126
|
+
end
|
127
|
+
|
128
|
+
def recv(bytes_to_read, flags = 0)
|
129
|
+
return socket_recv(bytes_to_read, flags, 0)
|
130
|
+
end
|
131
|
+
|
132
|
+
def recvmsg(max_msg_len = nil, flags = 0, *_)
|
133
|
+
socket_type = getsockopt(:SOCKET, :TYPE).int
|
134
|
+
|
135
|
+
if socket_type == Socket::SOCK_STREAM
|
136
|
+
grow_msg = false
|
137
|
+
else
|
138
|
+
grow_msg = max_msg_len.nil?
|
139
|
+
end
|
140
|
+
|
141
|
+
flags |= Socket::MSG_PEEK if grow_msg
|
142
|
+
|
143
|
+
msg_len = max_msg_len || 4096
|
144
|
+
|
145
|
+
loop do
|
146
|
+
msg_buffer = RubySL::Socket::Foreign.char_pointer(msg_len)
|
147
|
+
address = RubySL::Socket.sockaddr_class_for_socket(self).new
|
148
|
+
io_vec = RubySL::Socket::Foreign::Iovec.with_buffer(msg_buffer)
|
149
|
+
header = RubySL::Socket::Foreign::Msghdr.with_buffers(address, io_vec)
|
150
|
+
|
151
|
+
begin
|
152
|
+
need_more = false
|
153
|
+
|
154
|
+
msg_size = RubySL::Socket::Foreign
|
155
|
+
.recvmsg(descriptor, header.pointer, flags)
|
156
|
+
|
157
|
+
RubySL::Socket::Error.read_error('recvmsg(2)', self) if msg_size < 0
|
158
|
+
|
159
|
+
if grow_msg and header.message_truncated?
|
160
|
+
need_more = true
|
161
|
+
msg_len *= 2
|
162
|
+
end
|
163
|
+
|
164
|
+
next if need_more
|
165
|
+
|
166
|
+
# When a socket is actually connected the address structure is not used.
|
167
|
+
if header.address_size > 0
|
168
|
+
addr = Addrinfo.new(address.to_s, address.family, socket_type)
|
169
|
+
else
|
170
|
+
addr = Addrinfo.new([Socket::AF_UNSPEC], nil, socket_type)
|
171
|
+
end
|
172
|
+
|
173
|
+
return msg_buffer.read_string(msg_size), addr, header.flags
|
174
|
+
ensure
|
175
|
+
msg_buffer.free
|
176
|
+
address.free
|
177
|
+
io_vec.free
|
178
|
+
header.free
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
nil
|
183
|
+
end
|
184
|
+
|
185
|
+
def recvmsg_nonblock(max_msg_len = nil, flags = 0, *_)
|
186
|
+
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
|
187
|
+
|
188
|
+
recvmsg(max_msg_len, flags | Socket::MSG_DONTWAIT)
|
189
|
+
end
|
190
|
+
|
191
|
+
def sendmsg(message, flags = 0, dest_sockaddr = nil, *_)
|
192
|
+
msg_buffer = RubySL::Socket::Foreign.char_pointer(message.bytesize)
|
193
|
+
io_vec = RubySL::Socket::Foreign::Iovec.with_buffer(msg_buffer)
|
194
|
+
header = RubySL::Socket::Foreign::Msghdr.new
|
195
|
+
address = nil
|
196
|
+
|
197
|
+
begin
|
198
|
+
msg_buffer.write_string(message)
|
199
|
+
|
200
|
+
header.message = io_vec
|
201
|
+
|
202
|
+
if dest_sockaddr.is_a?(Addrinfo)
|
203
|
+
dest_sockaddr = dest_sockaddr.to_sockaddr
|
204
|
+
end
|
205
|
+
|
206
|
+
if dest_sockaddr.is_a?(String)
|
207
|
+
address = RubySL::Socket::Foreign::SockaddrIn
|
208
|
+
.with_sockaddr(dest_sockaddr)
|
209
|
+
|
210
|
+
header.address = address
|
211
|
+
end
|
212
|
+
|
213
|
+
num_bytes = RubySL::Socket::Foreign
|
214
|
+
.sendmsg(descriptor, header.pointer, flags)
|
215
|
+
|
216
|
+
RubySL::Socket::Error.read_error('sendmsg(2)', self) if num_bytes < 0
|
217
|
+
|
218
|
+
num_bytes
|
219
|
+
ensure
|
220
|
+
address.free if address
|
221
|
+
header.free
|
222
|
+
io_vec.free
|
223
|
+
msg_buffer.free
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def sendmsg_nonblock(message, flags = 0, dest_sockaddr = nil, *_)
|
228
|
+
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
|
229
|
+
|
230
|
+
sendmsg(message, flags | Socket::MSG_DONTWAIT, dest_sockaddr)
|
231
|
+
end
|
232
|
+
|
233
|
+
def close_read
|
234
|
+
ensure_open
|
235
|
+
|
236
|
+
if @mode & ACCMODE == RDONLY
|
237
|
+
return close
|
238
|
+
end
|
239
|
+
|
240
|
+
RubySL::Socket::Foreign.shutdown(descriptor, 0)
|
241
|
+
|
242
|
+
@mode = WRONLY
|
243
|
+
|
244
|
+
nil
|
245
|
+
end
|
246
|
+
|
247
|
+
def close_write
|
248
|
+
ensure_open
|
249
|
+
|
250
|
+
if @mode & ACCMODE == WRONLY
|
251
|
+
return close
|
252
|
+
end
|
253
|
+
|
254
|
+
RubySL::Socket::Foreign.shutdown(descriptor, 1)
|
255
|
+
|
256
|
+
@mode = RDONLY
|
257
|
+
|
258
|
+
nil
|
259
|
+
end
|
260
|
+
|
261
|
+
def recv_nonblock(bytes_to_read, flags = 0)
|
262
|
+
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
|
263
|
+
|
264
|
+
RubySL::Socket::Error.wrap_read_nonblock do
|
265
|
+
socket_recv(bytes_to_read, flags, 0)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def shutdown(how = Socket::SHUT_RDWR)
|
270
|
+
how = RubySL::Socket.shutdown_option(how)
|
271
|
+
err = RubySL::Socket::Foreign.shutdown(descriptor, how)
|
272
|
+
|
273
|
+
Errno.handle('shutdown(2)') unless err == 0
|
274
|
+
|
275
|
+
0
|
276
|
+
end
|
277
|
+
|
278
|
+
# MRI defines this method in BasicSocket and stuffs all logic in it. Since
|
279
|
+
# inheriting classes behave differently we overwrite this method in said
|
280
|
+
# classes. The method here exists so that code such as the following still
|
281
|
+
# works: BasicSocket.method_defined?(:local_address).
|
282
|
+
def local_address
|
283
|
+
raise NotImplementedError,
|
284
|
+
'This method must be implemented by classes inheriting from BasicSocket'
|
285
|
+
end
|
286
|
+
|
287
|
+
def remote_address
|
288
|
+
raise NotImplementedError,
|
289
|
+
'This method must be implemented by classes inheriting from BasicSocket'
|
290
|
+
end
|
291
|
+
|
292
|
+
def getpeereid
|
293
|
+
RubySL::Socket::Foreign.getpeereid(descriptor)
|
294
|
+
end
|
295
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Socket < BasicSocket
|
2
|
+
module Constants
|
3
|
+
all_valid = RubySL::Socket.constant_pairs
|
4
|
+
|
5
|
+
all_valid.each {|name, value| const_set name, Integer(value) }
|
6
|
+
|
7
|
+
# MRI compat. socket is a pretty screwed up API. All the constants in Constants
|
8
|
+
# must also be directly accessible on Socket itself. This means it's not enough
|
9
|
+
# to include Constants into Socket, because Socket#const_defined? must be able
|
10
|
+
# to see constants like AF_INET6 directly on Socket, but #const_defined? doesn't
|
11
|
+
# check inherited constants. O_o
|
12
|
+
#
|
13
|
+
all_valid.each {|name, value| Socket.const_set name, Integer(value) }
|
14
|
+
|
15
|
+
|
16
|
+
afamilies = all_valid.to_a.select { |name,| name =~ /^AF_/ }
|
17
|
+
afamilies.map! {|name, value| [value.to_i, name] }
|
18
|
+
|
19
|
+
pfamilies = all_valid.to_a.select { |name,| name =~ /^PF_/ }
|
20
|
+
pfamilies.map! {|name, value| [value.to_i, name] }
|
21
|
+
|
22
|
+
AF_TO_FAMILY = Hash[*afamilies.flatten]
|
23
|
+
PF_TO_FAMILY = Hash[*pfamilies.flatten]
|
24
|
+
|
25
|
+
# MRI defines these constants manually, thus our FFI generators don't pick
|
26
|
+
# them up.
|
27
|
+
EAI_ADDRFAMILY = 1
|
28
|
+
EAI_NODATA = 7
|
29
|
+
IPPORT_USERRESERVED = 5000
|
30
|
+
|
31
|
+
# This constant is hidden behind a #ifdef __GNU on Linux, meaning it won't
|
32
|
+
# be available when using clang.
|
33
|
+
unless const_defined?(:SCM_CREDENTIALS)
|
34
|
+
SCM_CREDENTIALS = 2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
[:EAI_ADDRFAMILY, :EAI_NODATA, :IPPORT_USERRESERVED, :SCM_CREDENTIALS].each do |const|
|
39
|
+
const_set(const, Constants.const_get(const))
|
40
|
+
end
|
41
|
+
end
|