rubysl-socket 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -16
- data/lib/rubysl/socket.rb +201 -1396
- data/lib/rubysl/socket/ancillary_data.rb +56 -0
- data/lib/rubysl/socket/bsd.rb +28 -0
- data/lib/rubysl/socket/error.rb +67 -0
- data/lib/rubysl/socket/foreign.rb +324 -0
- data/lib/rubysl/socket/foreign/addrinfo.rb +10 -0
- data/lib/rubysl/socket/foreign/hostent.rb +36 -0
- data/lib/rubysl/socket/foreign/ifaddrs.rb +129 -0
- data/lib/rubysl/socket/foreign/iovec.rb +18 -0
- data/lib/rubysl/socket/foreign/linger.rb +41 -0
- data/lib/rubysl/socket/foreign/msghdr.rb +41 -0
- data/lib/rubysl/socket/foreign/servent.rb +17 -0
- data/lib/rubysl/socket/foreign/sockaddr.rb +21 -0
- data/lib/rubysl/socket/foreign/sockaddr_in.rb +25 -0
- data/lib/rubysl/socket/foreign/sockaddr_in6.rb +25 -0
- data/lib/rubysl/socket/foreign/sockaddr_un.rb +29 -0
- data/lib/rubysl/socket/ipv6.rb +38 -0
- data/lib/rubysl/socket/linux.rb +16 -0
- data/lib/rubysl/socket/socket_options.rb +84 -0
- data/lib/rubysl/socket/version.rb +1 -1
- data/lib/socket.rb +45 -1
- data/lib/socket/addrinfo.rb +453 -0
- data/lib/socket/ancillary_data.rb +114 -0
- data/lib/socket/basic_socket.rb +295 -0
- data/lib/socket/constants.rb +41 -0
- data/lib/socket/ifaddr.rb +29 -0
- data/lib/socket/ip_socket.rb +37 -0
- data/lib/socket/mri.rb +928 -0
- data/lib/socket/option.rb +96 -0
- data/lib/socket/socket.rb +353 -0
- data/lib/socket/socket_error.rb +2 -0
- data/lib/socket/tcp_server.rb +78 -0
- data/lib/socket/tcp_socket.rb +109 -0
- data/lib/socket/udp_socket.rb +73 -0
- data/lib/socket/unix_server.rb +35 -0
- data/lib/socket/unix_socket.rb +78 -0
- data/rubysl-socket.gemspec +15 -10
- metadata +78 -293
- data/.gitignore +0 -17
- data/.travis.yml +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/spec/addrinfo/afamily_spec.rb +0 -5
- data/spec/addrinfo/bind_spec.rb +0 -5
- data/spec/addrinfo/canonname_spec.rb +0 -5
- data/spec/addrinfo/connect_from_spec.rb +0 -5
- data/spec/addrinfo/connect_spec.rb +0 -5
- data/spec/addrinfo/connect_to_spec.rb +0 -5
- data/spec/addrinfo/family_addrinfo_spec.rb +0 -5
- data/spec/addrinfo/foreach_spec.rb +0 -5
- data/spec/addrinfo/getaddrinfo_spec.rb +0 -5
- data/spec/addrinfo/getnameinfo_spec.rb +0 -5
- data/spec/addrinfo/inspect_sockaddr_spec.rb +0 -5
- data/spec/addrinfo/inspect_spec.rb +0 -5
- data/spec/addrinfo/ip_address_spec.rb +0 -5
- data/spec/addrinfo/ip_port_spec.rb +0 -5
- data/spec/addrinfo/ip_spec.rb +0 -9
- data/spec/addrinfo/ip_unpack_spec.rb +0 -5
- data/spec/addrinfo/ipv4_loopback_spec.rb +0 -5
- data/spec/addrinfo/ipv4_multicast_spec.rb +0 -5
- data/spec/addrinfo/ipv4_private_spec.rb +0 -5
- data/spec/addrinfo/ipv4_spec.rb +0 -5
- data/spec/addrinfo/ipv6_linklocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_loopback_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_global_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_linklocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_nodelocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_orglocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_mc_sitelocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_multicast_spec.rb +0 -5
- data/spec/addrinfo/ipv6_sitelocal_spec.rb +0 -5
- data/spec/addrinfo/ipv6_spec.rb +0 -5
- data/spec/addrinfo/ipv6_to_ipv4_spec.rb +0 -5
- data/spec/addrinfo/ipv6_unspecified_spec.rb +0 -5
- data/spec/addrinfo/ipv6_v4compat_spec.rb +0 -5
- data/spec/addrinfo/ipv6_v4mapped_spec.rb +0 -5
- data/spec/addrinfo/listen_spec.rb +0 -5
- data/spec/addrinfo/marshal_dump_spec.rb +0 -5
- data/spec/addrinfo/marshal_load_spec.rb +0 -5
- data/spec/addrinfo/pfamily_spec.rb +0 -5
- data/spec/addrinfo/protocol_spec.rb +0 -5
- data/spec/addrinfo/socktype_spec.rb +0 -5
- data/spec/addrinfo/tcp_spec.rb +0 -5
- data/spec/addrinfo/to_s_spec.rb +0 -5
- data/spec/addrinfo/to_sockaddr_spec.rb +0 -5
- data/spec/addrinfo/udp_spec.rb +0 -5
- data/spec/addrinfo/unix_path_spec.rb +0 -5
- data/spec/addrinfo/unix_spec.rb +0 -9
- data/spec/basicsocket/close_read_spec.rb +0 -42
- data/spec/basicsocket/close_write_spec.rb +0 -42
- data/spec/basicsocket/do_not_reverse_lookup_spec.rb +0 -78
- data/spec/basicsocket/for_fd_spec.rb +0 -37
- data/spec/basicsocket/getpeername_spec.rb +0 -24
- data/spec/basicsocket/getsockname_spec.rb +0 -27
- data/spec/basicsocket/getsockopt_spec.rb +0 -54
- data/spec/basicsocket/ioctl_spec.rb +0 -22
- data/spec/basicsocket/recv_nonblock_spec.rb +0 -6
- data/spec/basicsocket/recv_spec.rb +0 -76
- data/spec/basicsocket/send_spec.rb +0 -81
- data/spec/basicsocket/setsockopt_spec.rb +0 -333
- data/spec/basicsocket/shutdown_spec.rb +0 -5
- data/spec/constants/constants_spec.rb +0 -63
- data/spec/fixtures/classes.rb +0 -174
- data/spec/fixtures/send_io.txt +0 -1
- data/spec/ipsocket/addr_spec.rb +0 -72
- data/spec/ipsocket/getaddress_spec.rb +0 -26
- data/spec/ipsocket/peeraddr_spec.rb +0 -79
- data/spec/ipsocket/recvfrom_spec.rb +0 -64
- data/spec/option/int_spec.rb +0 -27
- data/spec/option/linger_spec.rb +0 -52
- data/spec/option/new_spec.rb +0 -32
- data/spec/shared/pack_sockaddr.rb +0 -26
- data/spec/shared/partially_closable_sockets.rb +0 -13
- data/spec/shared/recv_nonblock.rb +0 -33
- data/spec/shared/socketpair.rb +0 -35
- data/spec/socket/accept_nonblock_spec.rb +0 -27
- data/spec/socket/accept_spec.rb +0 -1
- data/spec/socket/bind_spec.rb +0 -80
- data/spec/socket/connect_nonblock_spec.rb +0 -62
- data/spec/socket/connect_spec.rb +0 -1
- data/spec/socket/for_fd_spec.rb +0 -29
- data/spec/socket/getaddrinfo_spec.rb +0 -120
- data/spec/socket/gethostbyaddr_spec.rb +0 -1
- data/spec/socket/gethostbyname_spec.rb +0 -26
- data/spec/socket/gethostname_spec.rb +0 -9
- data/spec/socket/getnameinfo_spec.rb +0 -57
- data/spec/socket/getservbyname_spec.rb +0 -24
- data/spec/socket/listen_spec.rb +0 -21
- data/spec/socket/new_spec.rb +0 -109
- data/spec/socket/pack_sockaddr_in_spec.rb +0 -6
- data/spec/socket/pack_sockaddr_un_spec.rb +0 -6
- data/spec/socket/pair_spec.rb +0 -6
- data/spec/socket/recvfrom_nonblock_spec.rb +0 -1
- data/spec/socket/recvfrom_spec.rb +0 -1
- data/spec/socket/sockaddr_in_spec.rb +0 -6
- data/spec/socket/sockaddr_un_spec.rb +0 -6
- data/spec/socket/socket_spec.rb +0 -37
- data/spec/socket/socketpair_spec.rb +0 -6
- data/spec/socket/sysaccept_spec.rb +0 -1
- data/spec/socket/unpack_sockaddr_in_spec.rb +0 -16
- data/spec/socket/unpack_sockaddr_un_spec.rb +0 -2
- data/spec/tcpserver/accept_nonblock_spec.rb +0 -30
- data/spec/tcpserver/accept_spec.rb +0 -60
- data/spec/tcpserver/gets_spec.rb +0 -17
- data/spec/tcpserver/listen_spec.rb +0 -1
- data/spec/tcpserver/new_spec.rb +0 -88
- data/spec/tcpserver/output_spec.rb +0 -8
- data/spec/tcpserver/readpartial_spec.rb +0 -8
- data/spec/tcpserver/sysaccept_spec.rb +0 -1
- data/spec/tcpsocket/gethostbyname_spec.rb +0 -62
- data/spec/tcpsocket/new_spec.rb +0 -5
- data/spec/tcpsocket/open_spec.rb +0 -5
- data/spec/tcpsocket/partially_closable_spec.rb +0 -20
- data/spec/tcpsocket/recv_nonblock_spec.rb +0 -31
- data/spec/tcpsocket/setsockopt_spec.rb +0 -49
- data/spec/tcpsocket/shared/new.rb +0 -85
- data/spec/udpsocket/bind_spec.rb +0 -33
- data/spec/udpsocket/connect_spec.rb +0 -1
- data/spec/udpsocket/new_spec.rb +0 -1
- data/spec/udpsocket/open_spec.rb +0 -12
- data/spec/udpsocket/recvfrom_nonblock_spec.rb +0 -1
- data/spec/udpsocket/send_spec.rb +0 -57
- data/spec/unixserver/accept_nonblock_spec.rb +0 -33
- data/spec/unixserver/accept_spec.rb +0 -64
- data/spec/unixserver/for_fd_spec.rb +0 -32
- data/spec/unixserver/new_spec.rb +0 -5
- data/spec/unixserver/open_spec.rb +0 -25
- data/spec/unixserver/shared/new.rb +0 -23
- data/spec/unixsocket/addr_spec.rb +0 -37
- data/spec/unixsocket/new_spec.rb +0 -5
- data/spec/unixsocket/open_spec.rb +0 -26
- data/spec/unixsocket/pair_spec.rb +0 -38
- data/spec/unixsocket/partially_closable_spec.rb +0 -25
- data/spec/unixsocket/path_spec.rb +0 -29
- data/spec/unixsocket/peeraddr_spec.rb +0 -29
- data/spec/unixsocket/recv_io_spec.rb +0 -40
- data/spec/unixsocket/recvfrom_spec.rb +0 -48
- data/spec/unixsocket/send_io_spec.rb +0 -30
- data/spec/unixsocket/shared/new.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 562ed559cd440cd82723928244bf9c0cf26ce180
|
4
|
+
data.tar.gz: 38e38e4237bad622ab117187d81d8110be7d674a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90d29f351d1005511ba0c1127dd2e51f3a25e4b74084f7e77e8af847a26fefb24c62b5ec0cae6307cedea1e44196ff4911791534eb464742f4fb890c3731229a
|
7
|
+
data.tar.gz: 9d161931b8bf02aeffd1f6e5325e9eec9b26bb6889c186b4785b34ffd3d3f36b04c3903a5fa0a750e3aaac1719abc663f7506d61ecf408c9f06d9084079f6031
|
data/README.md
CHANGED
@@ -1,29 +1,83 @@
|
|
1
|
-
#
|
1
|
+
# rubysl-socket
|
2
2
|
|
3
|
-
|
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
|
-
|
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
|
-
|
17
|
+
## Target
|
8
18
|
|
9
|
-
|
19
|
+
The 2.0 branch of rubysl-socket targets Ruby 2.x, other Ruby versions are
|
20
|
+
currently not supported.
|
10
21
|
|
11
|
-
|
22
|
+
## Unsupported Features
|
12
23
|
|
13
|
-
|
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
|
-
|
31
|
+
## Requirements
|
16
32
|
|
17
|
-
|
33
|
+
* Rubinius 2.10 or newer
|
34
|
+
* A POSIX compliant operating system
|
18
35
|
|
19
|
-
|
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
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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.
|
data/lib/rubysl/socket.rb
CHANGED
@@ -1,1520 +1,325 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
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.
|
356
|
-
|
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.
|
367
|
-
|
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
|
-
|
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.
|
381
|
-
|
382
|
-
|
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
|
-
|
424
|
-
|
425
|
-
|
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
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
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.
|
497
|
-
|
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
|
-
|
45
|
+
sockaddr = sockaddr_class_for_socket(source).new
|
502
46
|
|
503
|
-
|
47
|
+
begin
|
48
|
+
fd = RubySL::Socket::Foreign.memory_pointer(:int) do |size_p|
|
49
|
+
size_p.write_int(sockaddr.size)
|
504
50
|
|
505
|
-
|
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
|
-
|
55
|
+
Error.read_error('accept(2)', source) if fd < 0
|
529
56
|
|
530
|
-
|
57
|
+
socket = new_class.allocate
|
531
58
|
|
532
|
-
|
533
|
-
|
59
|
+
IO.setup(socket, fd, nil, true)
|
60
|
+
socket.binmode
|
534
61
|
|
535
|
-
|
536
|
-
|
62
|
+
socktype = source.getsockopt(:SOCKET, :TYPE).int
|
63
|
+
addrinfo = Addrinfo.new(sockaddr.to_s, sockaddr.family, socktype)
|
537
64
|
|
538
|
-
|
539
|
-
|
540
|
-
|
65
|
+
return socket, addrinfo
|
66
|
+
ensure
|
67
|
+
sockaddr.free
|
541
68
|
end
|
542
69
|
end
|
543
70
|
|
544
|
-
def self.
|
545
|
-
|
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
|
-
|
74
|
+
accept(source, new_class)
|
564
75
|
end
|
565
76
|
|
566
|
-
def
|
567
|
-
|
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
|
-
|
81
|
+
Error.read_error('listen(2)', source) if err < 0
|
570
82
|
|
571
|
-
|
572
|
-
IO.setup socket, fd, nil, true
|
573
|
-
socket.binmode
|
574
|
-
socket
|
83
|
+
0
|
575
84
|
end
|
576
85
|
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
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
|
-
|
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.
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
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
|
-
|
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
|
661
|
-
|
113
|
+
def self.family_prefix?(family)
|
114
|
+
family.start_with?('AF_') || family.start_with?('PF_')
|
662
115
|
end
|
663
116
|
|
664
|
-
def
|
665
|
-
|
666
|
-
|
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
|
-
|
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
|
687
|
-
|
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
|
-
|
696
|
-
|
128
|
+
socket_constant(prefixed, &block)
|
129
|
+
end
|
697
130
|
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
731
|
-
|
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
|
-
|
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
|
-
|
154
|
+
family
|
155
|
+
when NilClass
|
156
|
+
::Socket::AF_UNSPEC
|
744
157
|
else
|
745
|
-
|
746
|
-
|
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
|
-
|
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
|
800
|
-
#
|
801
|
-
|
802
|
-
|
803
|
-
|
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
|
-
|
825
|
-
|
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
|
-
|
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
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
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
|
-
|
876
|
-
|
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
|
-
|
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
|
-
|
898
|
-
|
899
|
-
|
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
|
-
|
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
|
936
|
-
|
937
|
-
|
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
|
-
|
957
|
-
|
958
|
-
end
|
207
|
+
nil
|
208
|
+
end
|
959
209
|
|
960
|
-
|
961
|
-
|
210
|
+
def self.protocol_family(family)
|
211
|
+
case family
|
212
|
+
when Symbol, String
|
213
|
+
f = family.to_s
|
962
214
|
|
963
|
-
|
964
|
-
|
965
|
-
|
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
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
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
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
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
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
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
|
-
|
1085
|
-
|
1086
|
-
|
242
|
+
if t[0..4] != 'SOCK_'
|
243
|
+
t = "SOCK_#{t}"
|
244
|
+
end
|
1087
245
|
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
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
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
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
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
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
|
-
|
1155
|
-
|
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
|
-
|
1163
|
-
|
1164
|
-
Errno.handle phase
|
1165
|
-
end
|
275
|
+
elsif reverse_lookup == :numeric
|
276
|
+
reverse_lookup = false
|
1166
277
|
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
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
|
-
|
1321
|
-
Errno.handle syscall
|
283
|
+
reverse_lookup
|
1322
284
|
end
|
1323
285
|
|
1324
|
-
|
1325
|
-
|
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
|
-
|
1376
|
-
|
1377
|
-
@host = host
|
1378
|
-
@port = port
|
291
|
+
options = ::Socket::Constants::NI_NUMERICHOST |
|
292
|
+
::Socket::Constants::NI_NUMERICSERV
|
1379
293
|
|
1380
|
-
|
1381
|
-
|
294
|
+
family, port, host, ip = Foreign
|
295
|
+
.getnameinfo(sockaddr, options, reverse_lookup)
|
1382
296
|
|
1383
|
-
|
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
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
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
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
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
|
-
|
1452
|
-
|
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
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
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
|