rubysl-socket 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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