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.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +70 -16
  3. data/lib/rubysl/socket.rb +201 -1396
  4. data/lib/rubysl/socket/ancillary_data.rb +56 -0
  5. data/lib/rubysl/socket/bsd.rb +28 -0
  6. data/lib/rubysl/socket/error.rb +67 -0
  7. data/lib/rubysl/socket/foreign.rb +324 -0
  8. data/lib/rubysl/socket/foreign/addrinfo.rb +10 -0
  9. data/lib/rubysl/socket/foreign/hostent.rb +36 -0
  10. data/lib/rubysl/socket/foreign/ifaddrs.rb +129 -0
  11. data/lib/rubysl/socket/foreign/iovec.rb +18 -0
  12. data/lib/rubysl/socket/foreign/linger.rb +41 -0
  13. data/lib/rubysl/socket/foreign/msghdr.rb +41 -0
  14. data/lib/rubysl/socket/foreign/servent.rb +17 -0
  15. data/lib/rubysl/socket/foreign/sockaddr.rb +21 -0
  16. data/lib/rubysl/socket/foreign/sockaddr_in.rb +25 -0
  17. data/lib/rubysl/socket/foreign/sockaddr_in6.rb +25 -0
  18. data/lib/rubysl/socket/foreign/sockaddr_un.rb +29 -0
  19. data/lib/rubysl/socket/ipv6.rb +38 -0
  20. data/lib/rubysl/socket/linux.rb +16 -0
  21. data/lib/rubysl/socket/socket_options.rb +84 -0
  22. data/lib/rubysl/socket/version.rb +1 -1
  23. data/lib/socket.rb +45 -1
  24. data/lib/socket/addrinfo.rb +453 -0
  25. data/lib/socket/ancillary_data.rb +114 -0
  26. data/lib/socket/basic_socket.rb +295 -0
  27. data/lib/socket/constants.rb +41 -0
  28. data/lib/socket/ifaddr.rb +29 -0
  29. data/lib/socket/ip_socket.rb +37 -0
  30. data/lib/socket/mri.rb +928 -0
  31. data/lib/socket/option.rb +96 -0
  32. data/lib/socket/socket.rb +353 -0
  33. data/lib/socket/socket_error.rb +2 -0
  34. data/lib/socket/tcp_server.rb +78 -0
  35. data/lib/socket/tcp_socket.rb +109 -0
  36. data/lib/socket/udp_socket.rb +73 -0
  37. data/lib/socket/unix_server.rb +35 -0
  38. data/lib/socket/unix_socket.rb +78 -0
  39. data/rubysl-socket.gemspec +15 -10
  40. metadata +78 -293
  41. data/.gitignore +0 -17
  42. data/.travis.yml +0 -9
  43. data/Gemfile +0 -4
  44. data/Rakefile +0 -1
  45. data/spec/addrinfo/afamily_spec.rb +0 -5
  46. data/spec/addrinfo/bind_spec.rb +0 -5
  47. data/spec/addrinfo/canonname_spec.rb +0 -5
  48. data/spec/addrinfo/connect_from_spec.rb +0 -5
  49. data/spec/addrinfo/connect_spec.rb +0 -5
  50. data/spec/addrinfo/connect_to_spec.rb +0 -5
  51. data/spec/addrinfo/family_addrinfo_spec.rb +0 -5
  52. data/spec/addrinfo/foreach_spec.rb +0 -5
  53. data/spec/addrinfo/getaddrinfo_spec.rb +0 -5
  54. data/spec/addrinfo/getnameinfo_spec.rb +0 -5
  55. data/spec/addrinfo/inspect_sockaddr_spec.rb +0 -5
  56. data/spec/addrinfo/inspect_spec.rb +0 -5
  57. data/spec/addrinfo/ip_address_spec.rb +0 -5
  58. data/spec/addrinfo/ip_port_spec.rb +0 -5
  59. data/spec/addrinfo/ip_spec.rb +0 -9
  60. data/spec/addrinfo/ip_unpack_spec.rb +0 -5
  61. data/spec/addrinfo/ipv4_loopback_spec.rb +0 -5
  62. data/spec/addrinfo/ipv4_multicast_spec.rb +0 -5
  63. data/spec/addrinfo/ipv4_private_spec.rb +0 -5
  64. data/spec/addrinfo/ipv4_spec.rb +0 -5
  65. data/spec/addrinfo/ipv6_linklocal_spec.rb +0 -5
  66. data/spec/addrinfo/ipv6_loopback_spec.rb +0 -5
  67. data/spec/addrinfo/ipv6_mc_global_spec.rb +0 -5
  68. data/spec/addrinfo/ipv6_mc_linklocal_spec.rb +0 -5
  69. data/spec/addrinfo/ipv6_mc_nodelocal_spec.rb +0 -5
  70. data/spec/addrinfo/ipv6_mc_orglocal_spec.rb +0 -5
  71. data/spec/addrinfo/ipv6_mc_sitelocal_spec.rb +0 -5
  72. data/spec/addrinfo/ipv6_multicast_spec.rb +0 -5
  73. data/spec/addrinfo/ipv6_sitelocal_spec.rb +0 -5
  74. data/spec/addrinfo/ipv6_spec.rb +0 -5
  75. data/spec/addrinfo/ipv6_to_ipv4_spec.rb +0 -5
  76. data/spec/addrinfo/ipv6_unspecified_spec.rb +0 -5
  77. data/spec/addrinfo/ipv6_v4compat_spec.rb +0 -5
  78. data/spec/addrinfo/ipv6_v4mapped_spec.rb +0 -5
  79. data/spec/addrinfo/listen_spec.rb +0 -5
  80. data/spec/addrinfo/marshal_dump_spec.rb +0 -5
  81. data/spec/addrinfo/marshal_load_spec.rb +0 -5
  82. data/spec/addrinfo/pfamily_spec.rb +0 -5
  83. data/spec/addrinfo/protocol_spec.rb +0 -5
  84. data/spec/addrinfo/socktype_spec.rb +0 -5
  85. data/spec/addrinfo/tcp_spec.rb +0 -5
  86. data/spec/addrinfo/to_s_spec.rb +0 -5
  87. data/spec/addrinfo/to_sockaddr_spec.rb +0 -5
  88. data/spec/addrinfo/udp_spec.rb +0 -5
  89. data/spec/addrinfo/unix_path_spec.rb +0 -5
  90. data/spec/addrinfo/unix_spec.rb +0 -9
  91. data/spec/basicsocket/close_read_spec.rb +0 -42
  92. data/spec/basicsocket/close_write_spec.rb +0 -42
  93. data/spec/basicsocket/do_not_reverse_lookup_spec.rb +0 -78
  94. data/spec/basicsocket/for_fd_spec.rb +0 -37
  95. data/spec/basicsocket/getpeername_spec.rb +0 -24
  96. data/spec/basicsocket/getsockname_spec.rb +0 -27
  97. data/spec/basicsocket/getsockopt_spec.rb +0 -54
  98. data/spec/basicsocket/ioctl_spec.rb +0 -22
  99. data/spec/basicsocket/recv_nonblock_spec.rb +0 -6
  100. data/spec/basicsocket/recv_spec.rb +0 -76
  101. data/spec/basicsocket/send_spec.rb +0 -81
  102. data/spec/basicsocket/setsockopt_spec.rb +0 -333
  103. data/spec/basicsocket/shutdown_spec.rb +0 -5
  104. data/spec/constants/constants_spec.rb +0 -63
  105. data/spec/fixtures/classes.rb +0 -174
  106. data/spec/fixtures/send_io.txt +0 -1
  107. data/spec/ipsocket/addr_spec.rb +0 -72
  108. data/spec/ipsocket/getaddress_spec.rb +0 -26
  109. data/spec/ipsocket/peeraddr_spec.rb +0 -79
  110. data/spec/ipsocket/recvfrom_spec.rb +0 -64
  111. data/spec/option/int_spec.rb +0 -27
  112. data/spec/option/linger_spec.rb +0 -52
  113. data/spec/option/new_spec.rb +0 -32
  114. data/spec/shared/pack_sockaddr.rb +0 -26
  115. data/spec/shared/partially_closable_sockets.rb +0 -13
  116. data/spec/shared/recv_nonblock.rb +0 -33
  117. data/spec/shared/socketpair.rb +0 -35
  118. data/spec/socket/accept_nonblock_spec.rb +0 -27
  119. data/spec/socket/accept_spec.rb +0 -1
  120. data/spec/socket/bind_spec.rb +0 -80
  121. data/spec/socket/connect_nonblock_spec.rb +0 -62
  122. data/spec/socket/connect_spec.rb +0 -1
  123. data/spec/socket/for_fd_spec.rb +0 -29
  124. data/spec/socket/getaddrinfo_spec.rb +0 -120
  125. data/spec/socket/gethostbyaddr_spec.rb +0 -1
  126. data/spec/socket/gethostbyname_spec.rb +0 -26
  127. data/spec/socket/gethostname_spec.rb +0 -9
  128. data/spec/socket/getnameinfo_spec.rb +0 -57
  129. data/spec/socket/getservbyname_spec.rb +0 -24
  130. data/spec/socket/listen_spec.rb +0 -21
  131. data/spec/socket/new_spec.rb +0 -109
  132. data/spec/socket/pack_sockaddr_in_spec.rb +0 -6
  133. data/spec/socket/pack_sockaddr_un_spec.rb +0 -6
  134. data/spec/socket/pair_spec.rb +0 -6
  135. data/spec/socket/recvfrom_nonblock_spec.rb +0 -1
  136. data/spec/socket/recvfrom_spec.rb +0 -1
  137. data/spec/socket/sockaddr_in_spec.rb +0 -6
  138. data/spec/socket/sockaddr_un_spec.rb +0 -6
  139. data/spec/socket/socket_spec.rb +0 -37
  140. data/spec/socket/socketpair_spec.rb +0 -6
  141. data/spec/socket/sysaccept_spec.rb +0 -1
  142. data/spec/socket/unpack_sockaddr_in_spec.rb +0 -16
  143. data/spec/socket/unpack_sockaddr_un_spec.rb +0 -2
  144. data/spec/tcpserver/accept_nonblock_spec.rb +0 -30
  145. data/spec/tcpserver/accept_spec.rb +0 -60
  146. data/spec/tcpserver/gets_spec.rb +0 -17
  147. data/spec/tcpserver/listen_spec.rb +0 -1
  148. data/spec/tcpserver/new_spec.rb +0 -88
  149. data/spec/tcpserver/output_spec.rb +0 -8
  150. data/spec/tcpserver/readpartial_spec.rb +0 -8
  151. data/spec/tcpserver/sysaccept_spec.rb +0 -1
  152. data/spec/tcpsocket/gethostbyname_spec.rb +0 -62
  153. data/spec/tcpsocket/new_spec.rb +0 -5
  154. data/spec/tcpsocket/open_spec.rb +0 -5
  155. data/spec/tcpsocket/partially_closable_spec.rb +0 -20
  156. data/spec/tcpsocket/recv_nonblock_spec.rb +0 -31
  157. data/spec/tcpsocket/setsockopt_spec.rb +0 -49
  158. data/spec/tcpsocket/shared/new.rb +0 -85
  159. data/spec/udpsocket/bind_spec.rb +0 -33
  160. data/spec/udpsocket/connect_spec.rb +0 -1
  161. data/spec/udpsocket/new_spec.rb +0 -1
  162. data/spec/udpsocket/open_spec.rb +0 -12
  163. data/spec/udpsocket/recvfrom_nonblock_spec.rb +0 -1
  164. data/spec/udpsocket/send_spec.rb +0 -57
  165. data/spec/unixserver/accept_nonblock_spec.rb +0 -33
  166. data/spec/unixserver/accept_spec.rb +0 -64
  167. data/spec/unixserver/for_fd_spec.rb +0 -32
  168. data/spec/unixserver/new_spec.rb +0 -5
  169. data/spec/unixserver/open_spec.rb +0 -25
  170. data/spec/unixserver/shared/new.rb +0 -23
  171. data/spec/unixsocket/addr_spec.rb +0 -37
  172. data/spec/unixsocket/new_spec.rb +0 -5
  173. data/spec/unixsocket/open_spec.rb +0 -26
  174. data/spec/unixsocket/pair_spec.rb +0 -38
  175. data/spec/unixsocket/partially_closable_spec.rb +0 -25
  176. data/spec/unixsocket/path_spec.rb +0 -29
  177. data/spec/unixsocket/peeraddr_spec.rb +0 -29
  178. data/spec/unixsocket/recv_io_spec.rb +0 -40
  179. data/spec/unixsocket/recvfrom_spec.rb +0 -48
  180. data/spec/unixsocket/send_io_spec.rb +0 -30
  181. 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