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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f3b12ba7bc284541c822a2be672b672eb7995fb
4
- data.tar.gz: 333c94597723d56146d62356a79911cae7b6f20d
3
+ metadata.gz: 562ed559cd440cd82723928244bf9c0cf26ce180
4
+ data.tar.gz: 38e38e4237bad622ab117187d81d8110be7d674a
5
5
  SHA512:
6
- metadata.gz: 8bfb34861ad3ece28bef646c70f19df868eb769838a8b938d8c40504fa775b96ab8efeb79cbd72266a93369d58515ec7d54f7aa7ee1f163e300b034f61163d87
7
- data.tar.gz: dbaacaaef813fd72d52a5f37e4945da2f6c4873c915205d819c8b061859b6df8ec6fb4a7cd1a064276cc59f07fa30d0a79c5f2ef788865e04beb40bd80b17d79
6
+ metadata.gz: 90d29f351d1005511ba0c1127dd2e51f3a25e4b74084f7e77e8af847a26fefb24c62b5ec0cae6307cedea1e44196ff4911791534eb464742f4fb890c3731229a
7
+ data.tar.gz: 9d161931b8bf02aeffd1f6e5325e9eec9b26bb6889c186b4785b34ffd3d3f36b04c3903a5fa0a750e3aaac1719abc663f7506d61ecf408c9f06d9084079f6031
data/README.md CHANGED
@@ -1,29 +1,83 @@
1
- # Rubysl::Socket
1
+ # rubysl-socket
2
2
 
3
- TODO: Write a gem description
3
+ An implementation of the Ruby socket standard library for Rubinius, written
4
+ using Ruby and FFI (and a tiny bit of C++ defined in Rubinius itself). More
5
+ information about the socket standard library can be found at
6
+ <http://ruby-doc.org/stdlib/libdoc/socket/rdoc/index.html>.
4
7
 
5
- ## Installation
8
+ Please note that **only** Rubinius is officially supported. While other Ruby
9
+ implementations are free to use rubysl-socket according to its license we do not
10
+ provide any support for this.
11
+
12
+ Issues for the socket standard library in general should be reported at
13
+ <https://bugs.ruby-lang.org/>, **only** use this project's issue tracker for
14
+ reporting issues with the Gem itself (e.g. something isn't implemented
15
+ correctly).
6
16
 
7
- Add this line to your application's Gemfile:
17
+ ## Target
8
18
 
9
- gem 'rubysl-socket'
19
+ The 2.0 branch of rubysl-socket targets Ruby 2.x, other Ruby versions are
20
+ currently not supported.
10
21
 
11
- And then execute:
22
+ ## Unsupported Features
12
23
 
13
- $ bundle
24
+ Currently the use of ancillary data is not supported. While
25
+ `Socket::AncillaryData` exists and is implemented for the most part it's not
26
+ used by `BasicSocket#sendmsg` and `BasicSocket#recvmsg`. Extracting/building
27
+ ancillary data requires the use of platform specific macros and these can't be
28
+ easily bound to Ruby via FFI. Using a C extension only adds more complexity for
29
+ a feature that will most likely be rarely used, if ever.
14
30
 
15
- Or install it yourself as:
31
+ ## Requirements
16
32
 
17
- $ gem install rubysl-socket
33
+ * Rubinius 2.10 or newer
34
+ * A POSIX compliant operating system
18
35
 
19
- ## Usage
36
+ Windows is currently not supported and there are no plans to support it for the
37
+ foreseeable future. The Rubinius team sadly lacks the capacity and experience to
38
+ support Windows besides also supporting the countless Linux and BSD
39
+ distributions out there.
40
+
41
+ ## Installation
20
42
 
21
- TODO: Write usage instructions here
43
+ By default rubysl-socket is already installed when you install Rubinius.
44
+ Currently updating rubysl-socket requires re-installing Rubinius, in the future
45
+ you can simply update rubysl-socket by running `gem update rubysl-socket`.
22
46
 
23
47
  ## Contributing
24
48
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
49
+ In general the contributing guidelines are the same as Rubinius
50
+ (<http://rubinius.com/doc/en/contributing/>). The structure of this repository
51
+ is as following:
52
+
53
+ * `lib/rubysl/socket/`: contains all code living under the `RubySL::Socket`
54
+ namespace, mostly used for FFI code, helper methods, etc.
55
+ * `lib/socket/`: contains the code of the public socket APIs such as `Socket`,
56
+ `TCPSocket`, etc. Code in this directory should not refer to the `Rubinius`
57
+ namespace directly, instead use (or create) methods defined under the
58
+ `RubySL::Socket` namespace.
59
+ * `spec/`: all mspec specs
60
+
61
+ To get started, clone the directory and install all Gems:
62
+
63
+ bundle install
64
+
65
+ You'll want to do this for both your local CRuby and Rubinius installations.
66
+
67
+ Running the specs under CRuby works as following:
68
+
69
+ mspec spec/path/to/file_spec.rb
70
+
71
+ Running the specs under Rubinius requires an extra environment variable so
72
+ Rubinius loads the local rubysl-socket copy instead of the installed one:
73
+
74
+ RUBYLIB=.:lib mspec spec/path/to/file_spec.rb
75
+
76
+ All specs **must** pass on both CRuby and Rubinius.
77
+
78
+ ## License
79
+
80
+ rubysl-socket is licensed under the BSD license unless stated otherwise, a copy
81
+ of this license can be found in the file "LICENSE". The MRI source code found in
82
+ `lib/socket/mri.rb` is licensed under the same license as Ruby, a copy of this
83
+ license can be found in the file itself.
@@ -1,1520 +1,325 @@
1
- require "rubysl/socket/version"
2
- require "fcntl"
3
-
4
- class SocketError < StandardError
5
- end
6
-
7
- # @todo Socket#accept[_nonblock]
8
- # @todo UNIXServer#accept[_nonblock]
9
- # @todo UDPSocket#recvfrom
10
-
11
- class BasicSocket < IO
12
- FFI = Rubinius::FFI
13
-
14
- class << self
15
- def from_descriptor(fixnum)
16
- sock = allocate()
17
- sock.from_descriptor(fixnum)
18
- return sock
19
- end
20
-
21
- alias :for_fd :from_descriptor
22
- end
23
-
24
- def from_descriptor(fixnum)
25
- IO.setup self, fixnum, nil, true
26
- return self
27
- end
28
-
29
- def self.do_not_reverse_lookup=(setting)
30
- @no_reverse_lookup = setting
31
- end
32
-
33
- def self.do_not_reverse_lookup
34
- @no_reverse_lookup = true unless defined? @no_reverse_lookup
35
- @no_reverse_lookup
36
- end
37
-
38
- def do_not_reverse_lookup=(setting)
39
- @no_reverse_lookup = setting
40
- end
41
-
42
- def do_not_reverse_lookup
43
- @no_reverse_lookup
44
- end
45
-
46
- def getsockopt(level, optname)
47
- data = Socket::Foreign.getsockopt(descriptor, level, optname)
48
-
49
- sockaddr = Socket::Foreign.getsockname(descriptor)
50
- family, = Socket::Foreign.getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV
51
- Socket::Option.new(family, level, optname, data)
52
- end
53
-
54
- def setsockopt(level_or_option, optname=nil, optval=nil)
55
- level = nil
56
-
57
- case level_or_option
58
- when Socket::Option
59
- if !optname.nil?
60
- raise ArgumentError, "given 2, expected 3"
61
- end
62
- level = level_or_option.level
63
- optname = level_or_option.optname
64
- optval = level_or_option.data
65
- else
66
- if level_or_option.nil? or optname.nil?
67
- nb_arg = 3 - [level_or_option, optname, optval].count(nil)
68
- raise ArgumentError, "given #{nb_arg}, expected 3"
69
- end
70
- level = level_or_option
71
- end
72
-
73
- optval = 1 if optval == true
74
- optval = 0 if optval == false
75
-
76
- error = 0
77
-
78
- sockname = Socket::Foreign.getsockname descriptor
79
- family = Socket::Foreign.getnameinfo(sockname).first
80
-
81
- level = level_arg(family, level)
82
- optname = optname_arg(level, optname)
83
-
84
- case optval
85
- when Fixnum then
86
- FFI::MemoryPointer.new :socklen_t do |val|
87
- val.write_int optval
88
- error = Socket::Foreign.setsockopt(descriptor, level,
89
- optname, val,
90
- val.total)
91
- end
92
- when String then
93
- FFI::MemoryPointer.new optval.bytesize do |val|
94
- val.write_string optval, optval.bytesize
95
- error = Socket::Foreign.setsockopt(descriptor, level,
96
- optname, val,
97
- optval.size)
98
- end
99
- else
100
- raise TypeError, "socket option should be a String, a Fixnum, true, or false"
101
- end
102
-
103
- Errno.handle "Unable to set socket option" unless error == 0
104
-
105
- return 0
106
- end
107
-
108
- def getsockname()
109
- return Socket::Foreign.getsockname(descriptor)
110
- end
111
-
112
- #
113
- # Obtain peername information for this socket.
114
- #
115
- # @see Socket.getpeername
116
- #
117
- def getpeername()
118
- Socket::Foreign.getpeername @descriptor
119
- end
120
-
121
- #
122
- #
123
- #
124
- def send(message, flags, to = nil)
125
- connect to if to
126
-
127
- bytes = message.bytesize
128
- bytes_sent = 0
129
-
130
- FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
131
- buffer.write_string message, bytes
132
- bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
133
- Errno.handle 'send(2)' if bytes_sent < 0
134
- end
135
-
136
- bytes_sent
137
- end
138
-
139
- def recvfrom(bytes_to_read, flags = 0)
140
- # FIXME 0 is knowledge from io.cpp
141
- return socket_recv(bytes_to_read, flags, 0)
142
- end
143
-
144
- def recv(bytes_to_read, flags = 0)
145
- # FIXME 0 is knowledge from io.cpp
146
- return socket_recv(bytes_to_read, flags, 0)
147
- end
148
-
149
- def close_read
150
- ensure_open
151
-
152
- # If we were only in readonly mode, close it all together
153
- if @mode & ACCMODE == RDONLY
154
- return close
155
- end
156
-
157
- # MRI doesn't check if shutdown worked, so we don't.
158
- Socket::Foreign.shutdown @descriptor, 0
159
-
160
- @mode = WRONLY
161
-
162
- nil
163
- end
164
-
165
- def close_write
166
- ensure_open
167
-
168
- # If we were only in writeonly mode, close it all together
169
- if @mode & ACCMODE == WRONLY
170
- return close
1
+ module RubySL
2
+ module Socket
3
+ def self.bsd_support?
4
+ Rubinius.bsd? || Rubinius.darwin?
171
5
  end
172
6
 
173
- Socket::Foreign.shutdown @descriptor, 1
174
-
175
- # Mark it as read only
176
- @mode = RDONLY
177
-
178
- nil
179
- end
180
-
181
- #
182
- # Sets socket nonblocking and reads up to given number of bytes.
183
- #
184
- # @todo Should EWOULDBLOCK be passed unchanged? --rue
185
- #
186
- def recv_nonblock(bytes_to_read, flags = 0)
187
- fcntl Fcntl::F_SETFL, Fcntl::O_NONBLOCK
188
- socket_recv bytes_to_read, flags, 0
189
- rescue Errno::EWOULDBLOCK
190
- raise Errno::EAGAIN
191
- end
192
-
193
- def shutdown(how = 2)
194
- err = Socket::Foreign.shutdown @descriptor, how
195
- Errno.handle "shutdown" unless err == 0
196
- end
197
-
198
- private
199
-
200
- def level_arg(family, level)
201
- case level
202
- when Symbol, String
203
- if Socket::Constants.const_defined?(level)
204
- Socket::Constants.const_get(level)
205
- else
206
- if is_ip_family?(family)
207
- ip_level_to_int(level)
208
- else
209
- unknown_level_to_int(level)
210
- end
211
- end
212
- else
213
- level
214
- end
215
- end
216
-
217
- def optname_arg(level, optname)
218
- case optname
219
- when Symbol, String
220
- if Socket::Constants.const_defined?(optname)
221
- Socket::Constants.const_get(optname)
222
- else
223
- case(level)
224
- when Socket::Constants::SOL_SOCKET
225
- constant("SO", optname)
226
- when Socket::Constants::IPPROTO_IP
227
- constant("IP", optname)
228
- when Socket::Constants::IPPROTO_TCP
229
- constant("TCP", optname)
230
- when Socket::Constants::IPPROTO_UDP
231
- constant("UDP", optname)
232
- else
233
- if Socket::Constants.const_defined?(Socket::Constants::IPPROTO_IPV6) &&
234
- level == Socket::Constants::IPPROTO_IPV6
235
- constant("IPV6", optname)
236
- else
237
- optname
238
- end
239
- end
240
- end
241
- else
242
- optname
243
- end
244
- end
245
-
246
- def is_ip_family?(family)
247
- family == "AF_INET" || family == "AF_INET6"
248
- end
249
-
250
- def ip_level_to_int(level)
251
- prefixes = ["IPPROTO", "SOL"]
252
- prefixes.each do |prefix|
253
- if Socket::Constants.const_defined?("#{prefix}_#{level}")
254
- return Socket::Constants.const_get("#{prefix}_#{level}")
255
- end
256
- end
257
- end
258
-
259
- def unknown_level_to_int(level)
260
- constant("SOL", level)
261
- end
262
-
263
- def constant(prefix, suffix)
264
- if Socket::Constants.const_defined?("#{prefix}_#{suffix}")
265
- Socket::Constants.const_get("#{prefix}_#{suffix}")
266
- end
267
- end
268
-
269
- end
270
-
271
- class Socket < BasicSocket
272
- FFI = Rubinius::FFI
273
-
274
- # @todo Is omitting empty-value constants reasonable? --rue
275
- module Constants
276
- all_valid = FFI.config_hash("socket").reject {|name, value| value.empty? }
277
-
278
- all_valid.each {|name, value| const_set name, Integer(value) }
279
-
280
- # MRI compat. socket is a pretty screwed up API. All the constants in Constants
281
- # must also be directly accessible on Socket itself. This means it's not enough
282
- # to include Constants into Socket, because Socket#const_defined? must be able
283
- # to see constants like AF_INET6 directly on Socket, but #const_defined? doesn't
284
- # check inherited constants. O_o
285
- #
286
- all_valid.each {|name, value| Socket.const_set name, Integer(value) }
287
-
288
-
289
- afamilies = all_valid.to_a.select { |name,| name =~ /^AF_/ }
290
- afamilies.map! {|name, value| [value.to_i, name] }
291
-
292
- pfamilies = all_valid.to_a.select { |name,| name =~ /^PF_/ }
293
- pfamilies.map! {|name, value| [value.to_i, name] }
294
-
295
- AF_TO_FAMILY = Hash[*afamilies.flatten]
296
- PF_TO_FAMILY = Hash[*pfamilies.flatten]
297
- end
298
-
299
- module Foreign
300
- extend FFI::Library
301
-
302
- class Addrinfo < FFI::Struct
303
- config("rbx.platform.addrinfo", :ai_flags, :ai_family, :ai_socktype,
304
- :ai_protocol, :ai_addrlen, :ai_addr, :ai_canonname, :ai_next)
305
- end
306
-
307
- class Linger < FFI::Struct
308
- config("rbx.platform.linger", :l_onoff, :l_linger)
309
- end
310
-
311
- attach_function :_bind, "bind", [:int, :pointer, :socklen_t], :int
312
- attach_function :_connect, "connect", [:int, :pointer, :socklen_t], :int
313
-
314
- attach_function :accept, [:int, :pointer, :pointer], :int
315
- attach_function :close, [:int], :int
316
- attach_function :shutdown, [:int, :int], :int
317
- attach_function :listen, [:int, :int], :int
318
- attach_function :socket, [:int, :int, :int], :int
319
- attach_function :send, [:int, :pointer, :size_t, :int], :ssize_t
320
- attach_function :recv, [:int, :pointer, :size_t, :int], :ssize_t
321
- attach_function :recvfrom, [:int, :pointer, :size_t, :int,
322
- :pointer, :pointer], :int
323
-
324
- attach_function :_getsockopt,
325
- "getsockopt", [:int, :int, :int, :pointer, :pointer], :int
326
- attach_function :_getaddrinfo,
327
- "getaddrinfo", [:string, :string, :pointer, :pointer], :int
328
-
329
- attach_function :gai_strerror, [:int], :string
330
- attach_function :setsockopt, [:int, :int, :int, :pointer, :socklen_t], :int
331
- attach_function :freeaddrinfo, [:pointer], :void
332
- attach_function :_getpeername, "getpeername", [:int, :pointer, :pointer], :int
333
- attach_function :_getsockname, "getsockname", [:int, :pointer, :pointer], :int
334
-
335
- attach_function :socketpair, [:int, :int, :int, :pointer], :int
336
-
337
- attach_function :gethostname, [:pointer, :size_t], :int
338
- attach_function :getservbyname, [:pointer, :pointer], :pointer
339
-
340
- attach_function :htons, [:uint16_t], :uint16_t
341
- attach_function :ntohs, [:uint16_t], :uint16_t
342
-
343
- attach_function :_getnameinfo,
344
- "getnameinfo", [:pointer, :socklen_t, :pointer, :socklen_t,
345
- :pointer, :socklen_t, :int], :int
346
-
347
- def self.bind(descriptor, sockaddr)
348
- FFI::MemoryPointer.new :char, sockaddr.bytesize do |sockaddr_p|
349
- sockaddr_p.write_string sockaddr, sockaddr.bytesize
350
-
351
- _bind descriptor, sockaddr_p, sockaddr.bytesize
352
- end
7
+ def self.linux_support?
8
+ Rubinius.linux?
353
9
  end
354
10
 
355
- def self.connect(descriptor, sockaddr)
356
- err = 0
357
- FFI::MemoryPointer.new :char, sockaddr.bytesize do |sockaddr_p|
358
- sockaddr_p.write_string sockaddr, sockaddr.bytesize
359
-
360
- err = _connect descriptor, sockaddr_p, sockaddr.bytesize
361
- end
362
-
363
- err
11
+ def self.unix_socket_support?
12
+ ::Socket::Constants.const_defined?(:AF_UNIX)
364
13
  end
365
14
 
366
- def self.getsockopt(descriptor, level, optname)
367
- FFI::MemoryPointer.new 256 do |val| # HACK magic number
368
- FFI::MemoryPointer.new :socklen_t do |length|
369
- length.write_int 256 # HACK magic number
370
-
371
- err = _getsockopt descriptor, level, optname, val, length
15
+ def self.aliases_for_hostname(hostname)
16
+ pointer = Foreign.gethostbyname(hostname)
372
17
 
373
- Errno.handle "Unable to get socket option" unless err == 0
374
-
375
- return val.read_string(length.read_int)
376
- end
377
- end
18
+ Foreign::Hostent.new(pointer).aliases
378
19
  end
379
20
 
380
- def self.getaddrinfo(host, service = nil, family = nil, socktype = nil, protocol = nil, flags = nil)
381
- hints = Addrinfo.new
382
- hints[:ai_family] = family || 0
383
- hints[:ai_socktype] = socktype || 0
384
- hints[:ai_protocol] = protocol || 0
385
- hints[:ai_flags] = flags || 0
386
-
387
- if host && (host.empty? || host == '<any>')
388
- host = "0.0.0.0"
389
- elsif host == '<broadcast>'
390
- host = '255.255.255.255'
391
- end
392
-
393
- res_p = FFI::MemoryPointer.new :pointer
394
-
395
- err = _getaddrinfo host, service, hints.pointer, res_p
396
-
397
- raise SocketError, gai_strerror(err) unless err == 0
398
-
399
- ptr = res_p.read_pointer
400
-
401
- return [] unless ptr
402
-
403
- res = Addrinfo.new ptr
404
-
405
- addrinfos = []
406
-
407
- while true
408
- addrinfo = []
409
- addrinfo << res[:ai_flags]
410
- addrinfo << res[:ai_family]
411
- addrinfo << res[:ai_socktype]
412
- addrinfo << res[:ai_protocol]
413
- addrinfo << res[:ai_addr].read_string(res[:ai_addrlen])
414
- addrinfo << res[:ai_canonname]
415
-
416
- addrinfos << addrinfo
417
-
418
- break unless res[:ai_next]
419
-
420
- res = Addrinfo.new res[:ai_next]
21
+ def self.sockaddr_class_for_socket(socket)
22
+ if socket.is_a?(::UNIXSocket)
23
+ return Foreign::SockaddrUn
421
24
  end
422
25
 
423
- return addrinfos
424
- ensure
425
- hints.free if hints
426
-
427
- if res_p
428
- ptr = res_p.read_pointer
429
-
430
- # Be sure to feed a legit pointer to freeaddrinfo
431
- if ptr and !ptr.null?
432
- freeaddrinfo ptr
433
- end
434
- res_p.free
435
- end
436
- end
437
-
438
- def self.getaddress(host)
439
- addrinfos = getaddrinfo(host)
440
- unpack_sockaddr_in(addrinfos.first[4], false).first
441
- end
442
-
443
- def self.getnameinfo(sockaddr, flags = Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV,
444
- reverse_lookup = !BasicSocket.do_not_reverse_lookup)
445
- name_info = []
446
- value = nil
447
-
448
- FFI::MemoryPointer.new :char, sockaddr.bytesize do |sockaddr_p|
449
- FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXHOST do |node|
450
- FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXSERV do |service|
451
- sockaddr_p.write_string sockaddr, sockaddr.bytesize
452
-
453
- if reverse_lookup then
454
- err = _getnameinfo(sockaddr_p, sockaddr.bytesize,
455
- node, Socket::Constants::NI_MAXHOST, nil, 0, 0)
456
-
457
- name_info[2] = node.read_string if err == 0
458
- end
459
-
460
- err = _getnameinfo(sockaddr_p, sockaddr.bytesize,
461
- node, Socket::Constants::NI_MAXHOST,
462
- service, Socket::Constants::NI_MAXSERV,
463
- flags)
464
-
465
- unless err == 0 then
466
- raise SocketError, gai_strerror(err)
467
- end
468
-
469
- sa_family = SockAddr_In.new(sockaddr)[:sin_family]
470
-
471
- name_info[0] = Socket::Constants::AF_TO_FAMILY[sa_family]
472
- name_info[1] = service.read_string
473
- name_info[3] = node.read_string
474
- end
475
- end
26
+ # Socket created using for example Socket.unix('foo')
27
+ if socket.is_a?(::Socket) and
28
+ socket.instance_variable_get(:@family) == ::Socket::AF_UNIX
29
+ return Foreign::SockaddrUn
476
30
  end
477
31
 
478
- name_info[2] = name_info[3] if name_info[2].nil?
479
- name_info
480
- end
481
-
482
- def self.getpeername(descriptor)
483
- FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
484
- FFI::MemoryPointer.new :socklen_t do |len_p|
485
- len_p.write_int 128
486
-
487
- err = _getpeername descriptor, sockaddr_storage_p, len_p
488
-
489
- Errno.handle 'getpeername(2)' unless err == 0
490
-
491
- sockaddr_storage_p.read_string len_p.read_int
492
- end
32
+ case address_info(:getsockname, socket)[0]
33
+ when 'AF_INET6'
34
+ Foreign::SockaddrIn6
35
+ when 'AF_UNIX'
36
+ Foreign::SockaddrUn
37
+ else
38
+ Foreign::SockaddrIn
493
39
  end
494
40
  end
495
41
 
496
- def self.getsockname(descriptor)
497
- FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
498
- FFI::MemoryPointer.new :socklen_t do |len_p|
499
- len_p.write_int 128
42
+ def self.accept(source, new_class)
43
+ raise IOError, 'socket has been closed' if source.closed?
500
44
 
501
- err = _getsockname descriptor, sockaddr_storage_p, len_p
45
+ sockaddr = sockaddr_class_for_socket(source).new
502
46
 
503
- Errno.handle 'getsockname(2)' unless err == 0
47
+ begin
48
+ fd = RubySL::Socket::Foreign.memory_pointer(:int) do |size_p|
49
+ size_p.write_int(sockaddr.size)
504
50
 
505
- sockaddr_storage_p.read_string len_p.read_int
51
+ RubySL::Socket::Foreign
52
+ .accept(source.descriptor, sockaddr.pointer, size_p)
506
53
  end
507
- end
508
- end
509
-
510
- def self.pack_sockaddr_in(host, port, family, type, flags)
511
- hints = Addrinfo.new
512
- hints[:ai_family] = family
513
- hints[:ai_socktype] = type
514
- hints[:ai_flags] = flags
515
-
516
- if host && host.empty?
517
- host = "0.0.0.0"
518
- end
519
-
520
- res_p = FFI::MemoryPointer.new :pointer
521
-
522
- err = _getaddrinfo host, port.to_s, hints.pointer, res_p
523
-
524
- raise SocketError, gai_strerror(err) unless err == 0
525
-
526
- return [] if res_p.read_pointer.null?
527
54
 
528
- res = Addrinfo.new res_p.read_pointer
55
+ Error.read_error('accept(2)', source) if fd < 0
529
56
 
530
- return res[:ai_addr].read_string(res[:ai_addrlen])
57
+ socket = new_class.allocate
531
58
 
532
- ensure
533
- hints.free if hints
59
+ IO.setup(socket, fd, nil, true)
60
+ socket.binmode
534
61
 
535
- if res_p then
536
- ptr = res_p.read_pointer
62
+ socktype = source.getsockopt(:SOCKET, :TYPE).int
63
+ addrinfo = Addrinfo.new(sockaddr.to_s, sockaddr.family, socktype)
537
64
 
538
- freeaddrinfo ptr if ptr and not ptr.null?
539
-
540
- res_p.free
65
+ return socket, addrinfo
66
+ ensure
67
+ sockaddr.free
541
68
  end
542
69
  end
543
70
 
544
- def self.unpack_sockaddr_in(sockaddr, reverse_lookup)
545
- family, port, host, ip = getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV, reverse_lookup
546
- # On some systems this doesn't fail for families other than AF_INET(6)
547
- # so we raise manually here.
548
- raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr' unless family =~ /AF_INET/
549
- return host, ip, port.to_i
550
- end
551
- end
552
-
553
- module ListenAndAccept
554
- include IO::Socketable
555
-
556
- def listen(backlog)
557
- backlog = Rubinius::Type.coerce_to backlog, Fixnum, :to_int
558
-
559
- err = Socket::Foreign.listen descriptor, backlog
560
-
561
- Errno.handle 'listen(2)' unless err == 0
71
+ def self.accept_nonblock(source, new_class)
72
+ source.fcntl(::Fcntl::F_SETFL, ::Fcntl::O_NONBLOCK)
562
73
 
563
- err
74
+ accept(source, new_class)
564
75
  end
565
76
 
566
- def accept
567
- return if closed?
77
+ def self.listen(source, backlog)
78
+ backlog = Rubinius::Type.coerce_to(backlog, Fixnum, :to_int)
79
+ err = Foreign.listen(source.descriptor, backlog)
568
80
 
569
- fd = super
81
+ Error.read_error('listen(2)', source) if err < 0
570
82
 
571
- socket = self.class.superclass.allocate
572
- IO.setup socket, fd, nil, true
573
- socket.binmode
574
- socket
83
+ 0
575
84
  end
576
85
 
577
- #
578
- # Set nonblocking and accept.
579
- #
580
- def accept_nonblock
581
- return if closed?
582
-
583
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
584
-
585
- fd = nil
586
- sockaddr = nil
587
-
588
- FFI::MemoryPointer.new 1024 do |sockaddr_p| # HACK from MRI
589
- FFI::MemoryPointer.new :int do |size_p|
590
- fd = Socket::Foreign.accept descriptor, sockaddr_p, size_p
591
- end
86
+ def self.family_for_sockaddr_in(sockaddr)
87
+ case sockaddr.bytesize
88
+ when 28
89
+ ::Socket::AF_INET6
90
+ when 16
91
+ ::Socket::AF_INET
92
+ # UNIX socket addresses can have a variable size as sometimes any trailing
93
+ # null bytes are stripped (e.g. when calling UNIXServer#getsockname).
94
+ else
95
+ ::Socket::AF_UNIX
592
96
  end
593
-
594
- Errno.handle 'accept(2)' if fd < 0
595
-
596
- # TCPServer -> TCPSocket etc. *sigh*
597
- socket = self.class.superclass.allocate
598
- IO.setup socket, fd, nil, true
599
- socket
600
- end
601
-
602
- end
603
-
604
- include Socket::ListenAndAccept
605
-
606
- class SockAddr_In < FFI::Struct
607
- config("rbx.platform.sockaddr_in", :sin_family, :sin_port, :sin_addr, :sin_zero)
608
-
609
- def initialize(sockaddrin)
610
- @p = FFI::MemoryPointer.new sockaddrin.bytesize
611
- @p.write_string(sockaddrin, sockaddrin.bytesize)
612
- super(@p)
613
- end
614
-
615
- def to_s
616
- @p.read_string(@p.total)
617
97
  end
618
98
 
619
- end
620
-
621
- class Option
622
- attr_reader :family, :level, :optname, :data
623
-
624
- def self.bool(family, level, optname, bool)
625
- data = [(bool ? 1 : 0)].pack('i')
626
- new family, level, optname, data
627
- end
628
-
629
- def self.int(family, level, optname, integer)
630
- new family, level, optname, [integer].pack('i')
99
+ def self.constant_pairs
100
+ Rubinius::FFI.config_hash('socket').reject { |name, value| value.empty? }
631
101
  end
632
102
 
633
- def self.linger(onoff, secs)
634
- linger = Socket::Foreign::Linger.new
635
-
636
- case onoff
637
- when Integer
638
- linger[:l_onoff] = onoff
103
+ def self.coerce_to_string(object)
104
+ if object.is_a?(String) or object.is_a?(Symbol)
105
+ object.to_s
106
+ elsif object.respond_to?(:to_str)
107
+ Rubinius::Type.coerce_to(object, String, :to_str)
639
108
  else
640
- linger[:l_onoff] = onoff ? 1 : 0
109
+ raise TypeError, "no implicit conversion of #{object.inspect} into Integer"
641
110
  end
642
- linger[:l_linger] = secs
643
-
644
- p = linger.to_ptr
645
- data = p.read_string(p.total)
646
-
647
- new :UNSPEC, :SOCKET, :LINGER, data
648
- end
649
-
650
- def initialize(family, level, optname, data)
651
- @family = family_arg(family)
652
- @family_name = family
653
- @level = level_arg(@family, level)
654
- @level_name = level
655
- @optname = optname_arg(@level, optname)
656
- @opt_name = optname
657
- @data = data
658
111
  end
659
112
 
660
- def unpack(template)
661
- @data.unpack template
113
+ def self.family_prefix?(family)
114
+ family.start_with?('AF_') || family.start_with?('PF_')
662
115
  end
663
116
 
664
- def inspect
665
- "#<#{self.class}: #@family_name #@level_name #@opt_name #{@data.inspect}>"
666
- end
667
-
668
- def bool
669
- unless @data.length == Rubinius::FFI.type_size(:int)
670
- raise TypeError, "size differ. expected as sizeof(int)=" +
671
- "#{Rubinius::FFI.type_size(:int)} but #{@data.length}"
117
+ def self.prefix_with(name, prefix)
118
+ unless name.start_with?(prefix)
119
+ name = "#{prefix}#{name}"
672
120
  end
673
121
 
674
- i = @data.unpack('i').first
675
- i == 0 ? false : true
676
- end
677
-
678
- def int
679
- unless @data.length == Rubinius::FFI.type_size(:int)
680
- raise TypeError, "size differ. expected as sizeof(int)=" +
681
- "#{Rubinius::FFI.type_size(:int)} but #{@data.length}"
682
- end
683
- @data.unpack('i').first
122
+ name
684
123
  end
685
124
 
686
- def linger
687
- if @level != Socket::SOL_SOCKET || @optname != Socket::SO_LINGER
688
- raise TypeError, "linger socket option expected"
689
- end
690
- if @data.bytesize != FFI.config("linger.sizeof")
691
- raise TypeError, "size differ. expected as sizeof(struct linger)=" +
692
- "#{FFI.config("linger.sizeof")} but #{@data.length}"
693
- end
125
+ def self.prefixed_socket_constant(name, prefix, &block)
126
+ prefixed = prefix_with(name, prefix)
694
127
 
695
- linger = Socket::Foreign::Linger.new
696
- linger.to_ptr.write_string @data, @data.bytesize
128
+ socket_constant(prefixed, &block)
129
+ end
697
130
 
698
- onoff = nil
699
- case linger[:l_onoff]
700
- when 0 then onoff = false
701
- when 1 then onoff = true
702
- else onoff = linger[:l_onoff].to_i
131
+ def self.socket_constant(name)
132
+ if ::Socket.const_defined?(name)
133
+ ::Socket.const_get(name)
134
+ else
135
+ raise SocketError, yield
703
136
  end
704
-
705
- [onoff, linger[:l_linger].to_i]
706
137
  end
707
138
 
708
- alias :to_s :data
709
-
710
-
711
- private
712
-
713
- def family_arg(family)
139
+ def self.address_family(family)
714
140
  case family
715
141
  when Symbol, String
716
142
  f = family.to_s
717
- if f[0..2] != 'AF_'
143
+
144
+ unless family_prefix?(f)
718
145
  f = 'AF_' + f
719
146
  end
720
- Socket.const_get f
721
- when Integer
722
- family
723
- else
724
- raise SocketError, "unknown socket domain: #{family}"
725
- end
726
- rescue NameError
727
- raise SocketError, "unknown socket domain: #{family}"
728
- end
729
147
 
730
- def level_arg(family, level)
731
- case level
732
- when Symbol, String
733
- if Socket::Constants.const_defined?(level)
734
- Socket::Constants.const_get(level)
148
+ if ::Socket.const_defined?(f)
149
+ ::Socket.const_get(f)
735
150
  else
736
- if is_ip_family?(family)
737
- ip_level_to_int(level)
738
- else
739
- unknown_level_to_int(level)
740
- end
151
+ raise SocketError, "unknown socket domain: #{family}"
741
152
  end
742
153
  when Integer
743
- level
154
+ family
155
+ when NilClass
156
+ ::Socket::AF_UNSPEC
744
157
  else
745
- raise SocketError, "unknown protocol level: #{level}"
746
- end
747
- rescue NameError
748
- raise SocketError, "unknown protocol level: #{level}"
749
- end
750
-
751
- def optname_arg(level, optname)
752
- case optname
753
- when Symbol, String
754
- if Socket::Constants.const_defined?(optname)
755
- Socket::Constants.const_get(optname)
158
+ if family.respond_to?(:to_str)
159
+ address_family(Rubinius::Type.coerce_to(family, String, :to_str))
756
160
  else
757
- case(level)
758
- when Socket::Constants::SOL_SOCKET
759
- constant("SO", optname)
760
- when Socket::Constants::IPPROTO_IP
761
- constant("IP", optname)
762
- when Socket::Constants::IPPROTO_TCP
763
- constant("TCP", optname)
764
- when Socket::Constants::IPPROTO_UDP
765
- constant("UDP", optname)
766
- else
767
- if Socket::Constants.const_defined?(Socket::Constants::IPPROTO_IPV6) &&
768
- level == Socket::Constants::IPPROTO_IPV6
769
- constant("IPV6", optname)
770
- else
771
- optname
772
- end
773
- end
161
+ raise SocketError, "unknown socket domain: #{family}"
774
162
  end
775
- else
776
- optname
777
163
  end
778
- rescue NameError
779
- raise SocketError, "unknown socket level option name: #{optname}"
780
- end
781
-
782
- def is_ip_family?(family)
783
- [Socket::AF_INET, Socket::AF_INET6].include? family
784
- end
785
-
786
- def ip_level_to_int(level)
787
- prefixes = ["IPPROTO", "SOL"]
788
- prefixes.each do |prefix|
789
- if Socket::Constants.const_defined?("#{prefix}_#{level}")
790
- return Socket::Constants.const_get("#{prefix}_#{level}")
791
- end
792
- end
793
- end
794
-
795
- def unknown_level_to_int(level)
796
- constant("SOL", level)
797
164
  end
798
165
 
799
- def constant(prefix, suffix)
800
- #if Socket::Constants.const_defined?("#{prefix}_#{suffix}")
801
- Socket::Constants.const_get("#{prefix}_#{suffix}")
802
- #end
803
- end
804
- end
805
-
806
- # If we have the details to support unix sockets, do so.
807
- if FFI.config("sockaddr_un.sun_family.offset") and Socket::Constants.const_defined?(:AF_UNIX)
808
- class SockAddr_Un < FFI::Struct
809
- config("rbx.platform.sockaddr_un", :sun_family, :sun_path)
810
-
811
- def initialize(filename = nil)
812
- maxfnsize = self.size - (FFI.config("sockaddr_un.sun_family.size") + 1)
813
-
814
- if filename and filename.length > maxfnsize
815
- raise ArgumentError, "too long unix socket path (max: #{maxfnsize}bytes)"
816
- end
817
- @p = FFI::MemoryPointer.new self.size
818
- if filename
819
- @p.write_string( [Socket::AF_UNIX].pack("s") + filename )
820
- end
821
- super @p
166
+ def self.address_family_name(family_int)
167
+ # Both AF_LOCAL and AF_UNIX use value 1. CRuby seems to prefer AF_UNIX
168
+ # over AF_LOCAL.
169
+ if family_int == ::Socket::AF_UNIX && family_int == ::Socket::AF_LOCAL
170
+ return 'AF_UNIX'
822
171
  end
823
172
 
824
- def to_s
825
- @p.read_string self.size
173
+ ::Socket.constants.grep(/^AF_/).each do |name|
174
+ return name.to_s if ::Socket.const_get(name) == family_int
826
175
  end
827
- end
828
- end
829
-
830
- def self.getaddrinfo(host, service, family = 0, socktype = 0,
831
- protocol = 0, flags = 0)
832
- if service
833
- if service.kind_of? Fixnum
834
- service = service.to_s
835
- else
836
- service = StringValue(service)
837
- end
838
- end
839
-
840
- addrinfos = Socket::Foreign.getaddrinfo(host, service, family, socktype,
841
- protocol, flags)
842
-
843
- addrinfos.map do |ai|
844
- addrinfo = []
845
- addrinfo << Socket::Constants::AF_TO_FAMILY[ai[1]]
846
176
 
847
- sockaddr = Foreign.unpack_sockaddr_in ai[4], !BasicSocket.do_not_reverse_lookup
848
-
849
- addrinfo << sockaddr.pop # port
850
- addrinfo.concat sockaddr # hosts
851
- addrinfo << ai[1]
852
- addrinfo << ai[2]
853
- addrinfo << ai[3]
854
- addrinfo
177
+ 'AF_UNSPEC'
855
178
  end
856
- end
857
179
 
858
- def self.getnameinfo(sockaddr, flags = 0)
859
- port = nil
860
- host = nil
861
- family = Socket::AF_UNSPEC
862
- if sockaddr.is_a?(Array)
863
- if sockaddr.size == 3
864
- af = sockaddr[0]
865
- port = sockaddr[1]
866
- host = sockaddr[2]
867
- elsif sockaddr.size == 4
868
- af = sockaddr[0]
869
- port = sockaddr[1]
870
- host = sockaddr[3] || sockaddr[2]
871
- else
872
- raise ArgumentError, "array size should be 3 or 4, #{sockaddr.size} given"
180
+ def self.protocol_family_name(family_int)
181
+ # Both PF_LOCAL and PF_UNIX use value 1. CRuby seems to prefer PF_UNIX
182
+ # over PF_LOCAL.
183
+ if family_int == ::Socket::PF_UNIX && family_int == ::Socket::PF_LOCAL
184
+ return 'PF_UNIX'
873
185
  end
874
186
 
875
- if family == "AF_INET"
876
- family = Socket::AF_INET
877
- elsif family == "AF_INET6"
878
- family = Socket::AF_INET6
187
+ ::Socket.constants.grep(/^PF_/).each do |name|
188
+ return name.to_s if ::Socket.const_get(name) == family_int
879
189
  end
880
- sockaddr = Socket::Foreign.pack_sockaddr_in(host, port, family, Socket::SOCK_DGRAM, 0)
881
- end
882
190
 
883
- family, port, host, ip = Socket::Foreign.getnameinfo(sockaddr, flags)
884
- [host, port]
885
- end
886
-
887
- def self.gethostname
888
- FFI::MemoryPointer.new :char, 1024 do |mp| #magic number 1024 comes from MRI
889
- Socket::Foreign.gethostname(mp, 1024) # same here
890
- return mp.read_string
191
+ 'PF_UNSPEC'
891
192
  end
892
- end
893
-
894
- def self.gethostbyname(hostname)
895
- addrinfos = Socket.getaddrinfo(hostname, nil)
896
193
 
897
- hostname = addrinfos.first[2]
898
- family = addrinfos.first[4]
899
- addresses = []
900
- alternatives = []
901
- addrinfos.each do |a|
902
- alternatives << a[2] unless a[2] == hostname
903
- # transform addresses to packed strings
904
- if a[4] == family
905
- sockaddr = Socket.sockaddr_in(1, a[3])
906
- if family == AF_INET
907
- # IPv4 address
908
- offset = FFI.config("sockaddr_in.sin_addr.offset")
909
- size = FFI.config("sockaddr_in.sin_addr.size")
910
- addresses << sockaddr.byteslice(offset, size)
911
- elsif family == AF_INET6
912
- # Ipv6 address
913
- offset = FFI.config("sockaddr_in6.sin6_addr.offset")
914
- size = FFI.config("sockaddr_in6.sin6_addr.size")
915
- addresses << sockaddr.byteslice(offset, size)
916
- else
917
- addresses << a[3]
918
- end
194
+ def self.protocol_name(family_int)
195
+ ::Socket.constants.grep(/^IPPROTO_/).each do |name|
196
+ return name.to_s if ::Socket.const_get(name) == family_int
919
197
  end
920
- end
921
-
922
- [hostname, alternatives.uniq, family] + addresses.uniq
923
- end
924
-
925
-
926
- class Servent < FFI::Struct
927
- config("rbx.platform.servent", :s_name, :s_aliases, :s_port, :s_proto)
928
198
 
929
- def initialize(data)
930
- @p = FFI::MemoryPointer.new data.bytesize
931
- @p.write_string(data, data.bytesize)
932
- super(@p)
199
+ 'IPPROTO_IP'
933
200
  end
934
201
 
935
- def to_s
936
- @p.read_string(size)
937
- end
938
-
939
- end
940
-
941
- def self.getservbyname(service, proto='tcp')
942
- FFI::MemoryPointer.new :char, service.length + 1 do |svc|
943
- FFI::MemoryPointer.new :char, proto.length + 1 do |prot|
944
- svc.write_string(service + "\0")
945
- prot.write_string(proto + "\0")
946
- fn = Socket::Foreign.getservbyname(svc, prot)
947
-
948
- raise SocketError, "no such service #{service}/#{proto}" if fn.nil?
949
-
950
- s = Servent.new(fn.read_string(Servent.size))
951
- return Socket::Foreign.ntohs(s[:s_port])
202
+ def self.socket_type_name(socktype)
203
+ ::Socket.constants.grep(/^SOCK_/).each do |name|
204
+ return name.to_s if ::Socket.const_get(name) == socktype
952
205
  end
953
- end
954
- end
955
206
 
956
- def self.pack_sockaddr_in(port, host, type = Socket::SOCK_DGRAM, flags = 0)
957
- Socket::Foreign.pack_sockaddr_in host, port, Socket::AF_UNSPEC, type, flags
958
- end
207
+ nil
208
+ end
959
209
 
960
- def self.unpack_sockaddr_in(sockaddr)
961
- host, address, port = Socket::Foreign.unpack_sockaddr_in sockaddr, false
210
+ def self.protocol_family(family)
211
+ case family
212
+ when Symbol, String
213
+ f = family.to_s
962
214
 
963
- return [port, address]
964
- rescue SocketError => e
965
- if e.message =~ /ai_family not supported/ then # HACK platform specific?
966
- raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr'
967
- else
968
- raise e
969
- end
970
- end
215
+ unless family_prefix?(f)
216
+ f = 'PF_' + f
217
+ end
971
218
 
972
- def self.socketpair(domain, type, protocol, klass=self)
973
- if domain.kind_of? String
974
- if domain.prefix? "AF_" or domain.prefix? "PF_"
975
- begin
976
- domain = Socket::Constants.const_get(domain)
977
- rescue NameError
978
- raise SocketError, "unknown socket domain #{domani}"
219
+ if ::Socket.const_defined?(f)
220
+ ::Socket.const_get(f)
221
+ else
222
+ raise SocketError, "unknown socket domain: #{family}"
979
223
  end
224
+ when Integer
225
+ family
226
+ when NilClass
227
+ ::Socket::PF_UNSPEC
980
228
  else
981
- raise SocketError, "unknown socket domain #{domani}"
982
- end
983
- end
984
-
985
- type = get_socket_type(type)
986
-
987
- FFI::MemoryPointer.new :int, 2 do |mp|
988
- Socket::Foreign.socketpair(domain, type, protocol, mp)
989
- fd0, fd1 = mp.read_array_of_int(2)
990
-
991
- [ klass.from_descriptor(fd0), klass.from_descriptor(fd1) ]
992
- end
993
- end
994
-
995
- class << self
996
- alias_method :sockaddr_in, :pack_sockaddr_in
997
- alias_method :pair, :socketpair
998
- end
999
-
1000
- # Only define these methods if we support unix sockets
1001
- if self.const_defined?(:SockAddr_Un)
1002
- def self.pack_sockaddr_un(file)
1003
- SockAddr_Un.new(file).to_s
1004
- end
1005
-
1006
- def self.unpack_sockaddr_un(addr)
1007
-
1008
- if addr.bytesize > FFI.config("sockaddr_un.sizeof")
1009
- raise TypeError, "too long sockaddr_un - #{addr.bytesize} longer than #{FFI.config("sockaddr_un.sizeof")}"
1010
- end
1011
-
1012
- struct = SockAddr_Un.new
1013
- struct.pointer.write_string(addr, addr.bytesize)
1014
-
1015
- struct[:sun_path]
1016
- end
1017
-
1018
- class << self
1019
- alias_method :sockaddr_un, :pack_sockaddr_un
1020
- end
1021
- end
1022
-
1023
- def initialize(family, socket_type, protocol=0)
1024
- @no_reverse_lookup = self.class.do_not_reverse_lookup
1025
- family = self.class.get_protocol_family(family)
1026
- socket_type = self.class.get_socket_type(socket_type)
1027
- descriptor = Socket::Foreign.socket family, socket_type, protocol
1028
-
1029
- Errno.handle 'socket(2)' if descriptor < 0
1030
-
1031
- IO.setup self, descriptor, nil, true
1032
- end
1033
-
1034
- def bind(server_sockaddr)
1035
- err = Socket::Foreign.bind(descriptor, server_sockaddr)
1036
- Errno.handle 'bind(2)' unless err == 0
1037
- err
1038
- end
1039
-
1040
- # @todo Should this be closing the descriptor? --rue
1041
- def connect(sockaddr, extra=nil)
1042
- if extra
1043
- sockaddr = Socket.pack_sockaddr_in sockaddr, extra
1044
- else
1045
- sockaddr = StringValue(sockaddr)
1046
- end
1047
-
1048
- status = Socket::Foreign.connect descriptor, sockaddr
1049
-
1050
- if status < 0
1051
- begin
1052
- Errno.handle "connect(2)"
1053
- rescue Errno::EISCONN
1054
- return 0
229
+ if family.respond_to?(:to_str)
230
+ protocol_family(Rubinius::Type.coerce_to(family, String, :to_str))
231
+ else
232
+ raise SocketError, "unknown socket domain: #{family}"
233
+ end
1055
234
  end
1056
235
  end
1057
236
 
1058
- return 0
1059
- end
1060
-
1061
- def connect_nonblock(sockaddr)
1062
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
1063
-
1064
- status = Socket::Foreign.connect descriptor, StringValue(sockaddr)
1065
- if status < 0
1066
- Errno.handle "connect(2)"
1067
- end
1068
-
1069
- return status
1070
- end
1071
-
1072
- def self.get_protocol_family(family)
1073
- case family
1074
- when Fixnum
1075
- return family
1076
- when String
1077
- # do nothing
1078
- when Symbol
1079
- family = family.to_s
1080
- else
1081
- family = StringValue(family)
1082
- end
237
+ def self.socket_type(type)
238
+ case type
239
+ when Symbol, String
240
+ t = type.to_s
1083
241
 
1084
- family = "PF_#{family}" unless family[0, 3] == "PF_"
1085
- Socket::Constants.const_get family
1086
- end
242
+ if t[0..4] != 'SOCK_'
243
+ t = "SOCK_#{t}"
244
+ end
1087
245
 
1088
- def self.get_socket_type(type)
1089
- if type.kind_of? String
1090
- if type.prefix? "SOCK_"
1091
- begin
1092
- type = Socket::Constants.const_get(type)
1093
- rescue NameError
1094
- raise SocketError, "unknown socket type #{type}"
246
+ if ::Socket.const_defined?(t)
247
+ ::Socket.const_get(t)
248
+ else
249
+ raise SocketError, "unknown socket type: #{type}"
1095
250
  end
251
+ when Integer
252
+ type
253
+ when NilClass
254
+ 0
1096
255
  else
1097
- raise SocketError, "unknown socket type #{type}"
1098
- end
1099
- end
1100
-
1101
- if type.kind_of? Symbol
1102
- begin
1103
- type = Socket::Constants.const_get("SOCK_#{type}")
1104
- rescue NameError
1105
- raise SocketError, "unknown socket type #{type}"
256
+ if type.respond_to?(:to_str)
257
+ socket_type(Rubinius::Type.coerce_to(type, String, :to_str))
258
+ else
259
+ raise SocketError, "unknown socket type: #{type}"
260
+ end
1106
261
  end
1107
262
  end
1108
263
 
1109
- type
1110
- end
1111
- end
1112
-
1113
- class UNIXSocket < BasicSocket
1114
- include IO::TransferIO
1115
-
1116
- # Coding to the lowest standard here.
1117
- def recvfrom(bytes_read, flags = 0)
1118
- # FIXME 2 is hardcoded knowledge from io.cpp
1119
- socket_recv(bytes_read, flags, 2)
1120
- end
1121
-
1122
- def initialize(path)
1123
- @no_reverse_lookup = self.class.do_not_reverse_lookup
1124
- @path = path
1125
- unix_setup
1126
- @path = "" # Client
1127
- end
1128
-
1129
- def path
1130
- unless @path
1131
- sockaddr = Socket::Foreign.getsockname descriptor
1132
- _, @path = sockaddr.unpack('SZ*')
1133
- end
1134
-
1135
- return @path
1136
- end
1137
-
1138
- def from_descriptor(fixnum)
1139
- super
1140
- @path = nil
1141
- end
1142
-
1143
- def unix_setup(server = false)
1144
- status = nil
1145
- phase = 'socket(2)'
1146
- sock = Socket::Foreign.socket Socket::Constants::AF_UNIX, Socket::Constants::SOCK_STREAM, 0
1147
-
1148
- Errno.handle phase if sock < 0
1149
-
1150
- IO.setup self, sock, 'r+', true
1151
-
1152
- sockaddr = Socket.pack_sockaddr_un(@path)
264
+ def self.convert_reverse_lookup(socket = nil, reverse_lookup = nil)
265
+ if reverse_lookup.nil?
266
+ if socket
267
+ reverse_lookup = !socket.do_not_reverse_lookup
268
+ else
269
+ reverse_lookup = !BasicSocket.do_not_reverse_lookup
270
+ end
1153
271
 
1154
- if server then
1155
- phase = 'bind(2)'
1156
- status = Socket::Foreign.bind descriptor, sockaddr
1157
- else
1158
- phase = 'connect(2)'
1159
- status = Socket::Foreign.connect descriptor, sockaddr
1160
- end
272
+ elsif reverse_lookup == :hostname
273
+ reverse_lookup = true
1161
274
 
1162
- if status < 0 then
1163
- close
1164
- Errno.handle phase
1165
- end
275
+ elsif reverse_lookup == :numeric
276
+ reverse_lookup = false
1166
277
 
1167
- if server then
1168
- phase = 'listen(2)'
1169
- status = Socket::Foreign.listen descriptor, 5
1170
- if status < 0
1171
- close
1172
- Errno.handle phase
278
+ elsif reverse_lookup != true and reverse_lookup != false
279
+ raise ArgumentError,
280
+ "invalid reverse_lookup flag: #{reverse_lookup.inspect}"
1173
281
  end
1174
- end
1175
-
1176
- return sock
1177
- end
1178
- private :unix_setup
1179
-
1180
- def addr
1181
- sockaddr = Socket::Foreign.getsockname descriptor
1182
- _, sock_path = sockaddr.unpack('SZ*')
1183
- ["AF_UNIX", sock_path]
1184
- end
1185
-
1186
- def peeraddr
1187
- sockaddr = Socket::Foreign.getpeername descriptor
1188
- _, sock_path = sockaddr.unpack('SZ*')
1189
- ["AF_UNIX", sock_path]
1190
- end
1191
-
1192
- def recv_io(klass=IO, mode=nil)
1193
- begin
1194
- fd = recv_fd
1195
- rescue PrimitiveFailure
1196
- raise SocketError, "file descriptor was not passed"
1197
- end
1198
-
1199
- return fd unless klass
1200
-
1201
- if klass < BasicSocket
1202
- klass.for_fd(fd)
1203
- else
1204
- klass.for_fd(fd, mode)
1205
- end
1206
- end
1207
-
1208
- class << self
1209
- def socketpair(type=Socket::SOCK_STREAM, protocol=0)
1210
- Socket.socketpair(Socket::PF_UNIX, type, protocol, self)
1211
- end
1212
-
1213
- alias_method :pair, :socketpair
1214
- end
1215
-
1216
- end
1217
-
1218
- class UNIXServer < UNIXSocket
1219
-
1220
- include Socket::ListenAndAccept
1221
-
1222
- def initialize(path)
1223
- @no_reverse_lookup = self.class.do_not_reverse_lookup
1224
- @path = path
1225
- unix_setup(true)
1226
- end
1227
- end
1228
-
1229
- class IPSocket < BasicSocket
1230
-
1231
- def self.getaddress(host)
1232
- Socket::Foreign.getaddress host
1233
- end
1234
-
1235
- def addr(reverse_lookup=nil)
1236
- sockaddr = Socket::Foreign.getsockname descriptor
1237
-
1238
- reverse_lookup = !do_not_reverse_lookup if reverse_lookup.nil?
1239
-
1240
- family, port, host, ip = Socket::Foreign.getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV, reverse_lookup
1241
- [family, port.to_i, host, ip]
1242
- end
1243
-
1244
- def peeraddr(reverse_lookup=nil)
1245
- sockaddr = Socket::Foreign.getpeername descriptor
1246
-
1247
- reverse_lookup = !do_not_reverse_lookup if reverse_lookup.nil?
1248
-
1249
- family, port, host, ip = Socket::Foreign.getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV, reverse_lookup
1250
- [family, port.to_i, host, ip]
1251
- end
1252
-
1253
- def recvfrom(maxlen, flags = 0)
1254
- # FIXME 1 is hardcoded knowledge from io.cpp
1255
- flags = 0 if flags.nil?
1256
- socket_recv maxlen, flags, 1
1257
- end
1258
-
1259
- def recvfrom_nonblock(maxlen, flags = 0)
1260
- # Set socket to non-blocking, if we can
1261
- # Todo: Ensure this works in Windows! If not, I claim that's Fcntl's fault.
1262
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
1263
- flags = 0 if flags.nil?
1264
- flags |= Socket::MSG_DONTWAIT
1265
-
1266
- # Wait until we have something to read
1267
- # @todo Why? ^^ --rue
1268
- IO.select([self])
1269
- return recvfrom(maxlen, flags)
1270
- end
1271
- end
1272
-
1273
- class UDPSocket < IPSocket
1274
- FFI = Rubinius::FFI
1275
-
1276
- def initialize(socktype = Socket::AF_INET)
1277
- @no_reverse_lookup = self.class.do_not_reverse_lookup
1278
- @socktype = socktype
1279
- status = Socket::Foreign.socket @socktype,
1280
- Socket::SOCK_DGRAM,
1281
- Socket::IPPROTO_UDP
1282
- Errno.handle 'socket(2)' if status < 0
1283
-
1284
- IO.setup self, status, nil, true
1285
- end
1286
-
1287
- def bind(host, port)
1288
- @host = host.to_s if host
1289
- @port = port.to_s if port
1290
-
1291
- addrinfos = Socket::Foreign.getaddrinfo(@host,
1292
- @port,
1293
- @socktype,
1294
- Socket::SOCK_DGRAM, 0,
1295
- Socket::AI_PASSIVE)
1296
-
1297
- status = -1
1298
-
1299
- addrinfos.each do |addrinfo|
1300
- flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
1301
-
1302
- status = Socket::Foreign.bind descriptor, sockaddr
1303
-
1304
- break if status >= 0
1305
- end
1306
-
1307
- if status < 0
1308
- Errno.handle 'bind(2)'
1309
- end
1310
-
1311
- status
1312
- end
1313
-
1314
- def connect(host, port)
1315
- sockaddr = Socket::Foreign.pack_sockaddr_in host, port, @socktype, Socket::SOCK_DGRAM, 0
1316
-
1317
- syscall = 'connect(2)'
1318
- status = Socket::Foreign.connect descriptor, sockaddr
1319
282
 
1320
- if status < 0
1321
- Errno.handle syscall
283
+ reverse_lookup
1322
284
  end
1323
285
 
1324
- 0
1325
- end
1326
-
1327
- def send(message, flags, *to)
1328
- connect *to unless to.empty?
1329
-
1330
- bytes = message.bytesize
1331
- bytes_sent = 0
1332
-
1333
- FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
1334
- buffer.write_string message, bytes
1335
- bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
1336
- Errno.handle 'send(2)' if bytes_sent < 0
1337
- end
1338
-
1339
- bytes_sent
1340
- end
1341
-
1342
- def inspect
1343
- "#<#{self.class}:0x#{object_id.to_s(16)} #{@host}:#{@port}>"
1344
- end
1345
-
1346
- end
1347
-
1348
- class TCPSocket < IPSocket
1349
- FFI = Rubinius::FFI
1350
-
1351
- def self.gethostbyname(hostname)
1352
- addrinfos = Socket.getaddrinfo(hostname, nil)
1353
-
1354
- hostname = addrinfos.first[2]
1355
- family = addrinfos.first[4]
1356
- addresses = []
1357
- alternatives = []
1358
- addrinfos.each do |a|
1359
- alternatives << a[2] unless a[2] == hostname
1360
- addresses << a[3] if a[4] == family
1361
- end
1362
-
1363
- [hostname, alternatives.uniq, family] + addresses.uniq
1364
- end
1365
-
1366
- #
1367
- # @todo Is it correct to ignore the to? If not, does
1368
- # the socket need to be reconnected? --rue
1369
- #
1370
- def send(bytes_to_read, flags, to = nil)
1371
- super(bytes_to_read, flags)
1372
- end
286
+ def self.address_info(method, socket, reverse_lookup = nil)
287
+ sockaddr = Foreign.__send__(method, socket.descriptor)
1373
288
 
289
+ reverse_lookup = convert_reverse_lookup(socket, reverse_lookup)
1374
290
 
1375
- def initialize(host, port, local_host=nil, local_service=nil)
1376
- @no_reverse_lookup = self.class.do_not_reverse_lookup
1377
- @host = host
1378
- @port = port
291
+ options = ::Socket::Constants::NI_NUMERICHOST |
292
+ ::Socket::Constants::NI_NUMERICSERV
1379
293
 
1380
- tcp_setup @host, @port, local_host, local_service
1381
- end
294
+ family, port, host, ip = Foreign
295
+ .getnameinfo(sockaddr, options, reverse_lookup)
1382
296
 
1383
- def tcp_setup(remote_host, remote_service, local_host = nil,
1384
- local_service = nil, server = false)
1385
- status = nil
1386
- syscall = nil
1387
- remote_host = StringValue(remote_host) if remote_host
1388
- if remote_service
1389
- if remote_service.kind_of? Fixnum
1390
- remote_service = remote_service.to_s
1391
- else
1392
- remote_service = StringValue(remote_service)
1393
- end
297
+ [family, port.to_i, host, ip]
1394
298
  end
1395
299
 
1396
- flags = server ? Socket::AI_PASSIVE : 0
1397
- @remote_addrinfo = Socket::Foreign.getaddrinfo(remote_host,
1398
- remote_service,
1399
- Socket::AF_UNSPEC,
1400
- Socket::SOCK_STREAM, 0,
1401
- flags)
1402
-
1403
- if server == false and (local_host or local_service)
1404
- local_host = local_host.to_s if local_host
1405
- local_service = local_service.to_s if local_service
1406
- @local_addrinfo = Socket::Foreign.getaddrinfo(local_host,
1407
- local_service,
1408
- Socket::AF_UNSPEC,
1409
- Socket::SOCK_STREAM, 0, 0)
1410
- end
1411
-
1412
- sock = nil
1413
-
1414
- @remote_addrinfo.each do |addrinfo|
1415
- flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
1416
-
1417
- sock = Socket::Foreign.socket family, socket_type, protocol
1418
- syscall = 'socket(2)'
1419
-
1420
- next if sock < 0
1421
-
1422
- if server
1423
- FFI::MemoryPointer.new :socklen_t do |val|
1424
- val.write_int 1
1425
- level = Socket::Constants::SOL_SOCKET
1426
- optname = Socket::Constants::SO_REUSEADDR
1427
- error = Socket::Foreign.setsockopt(sock, level,
1428
- optname, val,
1429
- val.total)
1430
- # Don't check error because if this fails, we just continue
1431
- # anyway.
300
+ def self.shutdown_option(how)
301
+ case how
302
+ when String, Symbol
303
+ prefixed_socket_constant(how.to_s, 'SHUT_') do
304
+ "unknown shutdown argument: #{how}"
1432
305
  end
1433
-
1434
- status = Socket::Foreign.bind sock, sockaddr
1435
- syscall = 'bind(2)'
1436
- else
1437
- if @local_addrinfo
1438
- # Pick a local_addrinfo for the family and type of
1439
- # the remote side
1440
- li = @local_addrinfo.find do |i|
1441
- i[1] == family && i[2] == socket_type
1442
- end
1443
-
1444
- if li
1445
- status = Socket::Foreign.bind sock, li[4]
1446
- syscall = 'bind(2)'
1447
- else
1448
- status = 1
1449
- end
306
+ when Fixnum
307
+ if how == ::Socket::SHUT_RD or
308
+ how == ::Socket::SHUT_WR or
309
+ how == ::Socket::SHUT_RDWR
310
+ how
1450
311
  else
1451
- status = 1
1452
- end
1453
-
1454
- if status >= 0
1455
- status = Socket::Foreign.connect sock, sockaddr
1456
- syscall = 'connect(2)'
312
+ raise ArgumentError,
313
+ 'argument should be :SHUT_RD, :SHUT_WR, or :SHUT_RDWR'
1457
314
  end
1458
- end
1459
-
1460
- if status < 0
1461
- Socket::Foreign.close sock
1462
315
  else
1463
- break
1464
- end
1465
- end
1466
-
1467
- if status < 0
1468
- Errno.handle syscall
1469
- end
1470
-
1471
- if server
1472
- err = Socket::Foreign.listen sock, 5
1473
- unless err == 0
1474
- Socket::Foreign.close sock
1475
- Errno.handle syscall
316
+ if how.respond_to?(:to_str)
317
+ shutdown_option(coerce_to_string(how))
318
+ else
319
+ raise TypeError,
320
+ "no implicit conversion of #{how.class} into Integer"
321
+ end
1476
322
  end
1477
323
  end
1478
-
1479
- # Only setup once we have found a socket we can use. Otherwise
1480
- # because we manually close a socket fd, we can create an IO fd
1481
- # alias condition which causes EBADF because when an IO is finalized
1482
- # and it's fd has been closed underneith it, we close someone elses
1483
- # fd!
1484
- IO.setup self, sock, nil, true
1485
- end
1486
- private :tcp_setup
1487
-
1488
- def from_descriptor(descriptor)
1489
- IO.setup self, descriptor, nil, true
1490
-
1491
- self
1492
- end
1493
- end
1494
-
1495
- class TCPServer < TCPSocket
1496
-
1497
- include Socket::ListenAndAccept
1498
-
1499
- def initialize(host, port = nil)
1500
- @no_reverse_lookup = self.class.do_not_reverse_lookup
1501
-
1502
- if Fixnum === host and port.nil? then
1503
- port = host
1504
- host = nil
1505
- end
1506
-
1507
- if String === host and port.nil? then
1508
- port = Integer(host)
1509
- host = nil
1510
- end
1511
-
1512
- port = StringValue port unless port.kind_of? Fixnum
1513
-
1514
- @host = host
1515
- @port = port
1516
-
1517
- tcp_setup @host, @port, nil, nil, true
1518
324
  end
1519
-
1520
325
  end