rubysl-socket 1.0.1 → 2.0.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.
@@ -1,5 +1,5 @@
1
1
  module RubySL
2
2
  module Socket
3
- VERSION = "1.0.1"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -16,10 +16,9 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.required_ruby_version = "~> 1.8.7"
19
+ spec.required_ruby_version = "~> 2.0"
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
23
  spec.add_development_dependency "mspec", "~> 1.5"
24
- spec.add_development_dependency "rubysl-prettyprint", "~> 1.0"
25
24
  end
@@ -1 +1,2 @@
1
+ require File.expand_path('../../../../spec_helper', __FILE__)
1
2
  require File.expand_path('../../fixtures/classes', __FILE__)
metadata CHANGED
@@ -1,71 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubysl-socket
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-17 00:00:00.000000000 Z
11
+ date: 2013-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
- - !ruby/object:Gem::Dependency
56
- name: rubysl-prettyprint
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.0'
69
55
  description: Ruby standard library socket.
70
56
  email:
71
57
  - brixen@gmail.com
@@ -73,14 +59,13 @@ executables: []
73
59
  extensions: []
74
60
  extra_rdoc_files: []
75
61
  files:
76
- - ".gitignore"
77
- - ".travis.yml"
62
+ - .gitignore
63
+ - .travis.yml
78
64
  - Gemfile
79
65
  - LICENSE
80
66
  - README.md
81
67
  - Rakefile
82
68
  - lib/rubysl/socket.rb
83
- - lib/rubysl/socket/socket.rb
84
69
  - lib/rubysl/socket/version.rb
85
70
  - lib/socket.rb
86
71
  - rubysl-socket.gemspec
@@ -231,17 +216,17 @@ require_paths:
231
216
  - lib
232
217
  required_ruby_version: !ruby/object:Gem::Requirement
233
218
  requirements:
234
- - - "~>"
219
+ - - ~>
235
220
  - !ruby/object:Gem::Version
236
- version: 1.8.7
221
+ version: '2.0'
237
222
  required_rubygems_version: !ruby/object:Gem::Requirement
238
223
  requirements:
239
- - - ">="
224
+ - - '>='
240
225
  - !ruby/object:Gem::Version
241
226
  version: '0'
242
227
  requirements: []
243
228
  rubyforge_project:
244
- rubygems_version: 2.2.2
229
+ rubygems_version: 2.0.7
245
230
  signing_key:
246
231
  specification_version: 4
247
232
  summary: Ruby standard library socket.
@@ -1,1210 +0,0 @@
1
- require 'fcntl'
2
-
3
- class SocketError < StandardError
4
- end
5
-
6
- # @todo Socket#accept[_nonblock]
7
- # @todo UNIXServer#accept[_nonblock]
8
- # @todo UDPSocket#recvfrom
9
-
10
- class BasicSocket < IO
11
- FFI = Rubinius::FFI
12
-
13
- class << self
14
- def from_descriptor(fixnum)
15
- sock = allocate()
16
- sock.from_descriptor(fixnum)
17
- return sock
18
- end
19
-
20
- alias :for_fd :from_descriptor
21
- end
22
-
23
- def from_descriptor(fixnum)
24
- IO.setup self, fixnum, nil, true
25
- return self
26
- end
27
-
28
- def self.do_not_reverse_lookup=(setting)
29
- @no_reverse_lookup = setting
30
- end
31
-
32
- def self.do_not_reverse_lookup
33
- @no_reverse_lookup ? true : false
34
- end
35
-
36
- def getsockopt(level, optname)
37
- Socket::Foreign.getsockopt descriptor, level, optname
38
- end
39
-
40
- def setsockopt(level, optname, optval)
41
- optval = 1 if optval == true
42
- optval = 0 if optval == false
43
-
44
- error = 0
45
-
46
- case optval
47
- when Fixnum then
48
- FFI::MemoryPointer.new :socklen_t do |val|
49
- val.write_int optval
50
- error = Socket::Foreign.setsockopt(descriptor, level,
51
- optname, val,
52
- val.total)
53
- end
54
- when String then
55
- FFI::MemoryPointer.new optval.size do |val|
56
- val.write_string optval
57
- error = Socket::Foreign.setsockopt(descriptor, level,
58
- optname, val,
59
- optval.size)
60
- end
61
- else
62
- raise TypeError, "socket option should be a String, a Fixnum, true, or false"
63
- end
64
-
65
- Errno.handle "Unable to set socket option" unless error == 0
66
-
67
- return 0
68
- end
69
-
70
- def getsockname()
71
- return Socket::Foreign.getsockname(descriptor)
72
- end
73
-
74
- #
75
- # Obtain peername information for this socket.
76
- #
77
- # @see Socket.getpeername
78
- #
79
- def getpeername()
80
- Socket::Foreign.getpeername @descriptor
81
- end
82
-
83
- #
84
- #
85
- #
86
- def send(message, flags, to = nil)
87
- connect to if to
88
-
89
- bytes = message.length
90
- bytes_sent = 0
91
-
92
- FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
93
- buffer.write_string message
94
- bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
95
- Errno.handle 'send(2)' if bytes_sent < 0
96
- end
97
-
98
- bytes_sent
99
- end
100
-
101
- def recvfrom(bytes_to_read, flags = 0)
102
- # FIXME 0 is knowledge from io.cpp
103
- return socket_recv(bytes_to_read, flags, 0)
104
- end
105
-
106
- def recv(bytes_to_read, flags = 0)
107
- # FIXME 0 is knowledge from io.cpp
108
- return socket_recv(bytes_to_read, flags, 0)
109
- end
110
-
111
- def close_read
112
- ensure_open
113
-
114
- # If we were only in readonly mode, close it all together
115
- if @mode & ACCMODE == RDONLY
116
- return close
117
- end
118
-
119
- # MRI doesn't check if shutdown worked, so we don't.
120
- Socket::Foreign.shutdown @descriptor, 0
121
-
122
- @mode = WRONLY
123
-
124
- nil
125
- end
126
-
127
- def close_write
128
- ensure_open
129
-
130
- # If we were only in writeonly mode, close it all together
131
- if @mode & ACCMODE == WRONLY
132
- return close
133
- end
134
-
135
- Socket::Foreign.shutdown @descriptor, 1
136
-
137
- # Mark it as read only
138
- @mode = RDONLY
139
-
140
- nil
141
- end
142
-
143
- #
144
- # Sets socket nonblocking and reads up to given number of bytes.
145
- #
146
- # @todo Should EWOULDBLOCK be passed unchanged? --rue
147
- #
148
- def recv_nonblock(bytes_to_read, flags = 0)
149
- fcntl Fcntl::F_SETFL, Fcntl::O_NONBLOCK
150
- socket_recv bytes_to_read, flags, 0
151
- rescue Errno::EWOULDBLOCK
152
- raise Errno::EAGAIN
153
- end
154
-
155
- def shutdown(how = 2)
156
- err = Socket::Foreign.shutdown @descriptor, how
157
- Errno.handle "shutdown" unless err == 0
158
- end
159
-
160
- end
161
-
162
- class Socket < BasicSocket
163
- FFI = Rubinius::FFI
164
-
165
- # @todo Is omitting empty-value constants reasonable? --rue
166
- module Constants
167
- all_valid = FFI.config_hash("socket").reject {|name, value| value.empty? }
168
-
169
- all_valid.each {|name, value| const_set name, Integer(value) }
170
-
171
- # MRI compat. socket is a pretty screwed up API. All the constants in Constants
172
- # must also be directly accessible on Socket itself. This means it's not enough
173
- # to include Constants into Socket, because Socket#const_defined? must be able
174
- # to see constants like AF_INET6 directly on Socket, but #const_defined? doesn't
175
- # check inherited constants. O_o
176
- #
177
- all_valid.each {|name, value| Socket.const_set name, Integer(value) }
178
-
179
-
180
- afamilies = all_valid.to_a.select { |name,| name =~ /^AF_/ }
181
- afamilies.map! {|name, value| [value.to_i, name] }
182
-
183
- pfamilies = all_valid.to_a.select { |name,| name =~ /^PF_/ }
184
- pfamilies.map! {|name, value| [value.to_i, name] }
185
-
186
- AF_TO_FAMILY = Hash[*afamilies.flatten]
187
- PF_TO_FAMILY = Hash[*pfamilies.flatten]
188
- end
189
-
190
- module Foreign
191
- extend FFI::Library
192
-
193
- class Addrinfo < FFI::Struct
194
- config("rbx.platform.addrinfo", :ai_flags, :ai_family, :ai_socktype,
195
- :ai_protocol, :ai_addrlen, :ai_addr, :ai_canonname, :ai_next)
196
- end
197
-
198
- attach_function :_bind, "bind", [:int, :pointer, :socklen_t], :int
199
- attach_function :_connect, "connect", [:int, :pointer, :socklen_t], :int
200
-
201
- attach_function :accept, [:int, :pointer, :pointer], :int
202
- attach_function :close, [:int], :int
203
- attach_function :shutdown, [:int, :int], :int
204
- attach_function :listen, [:int, :int], :int
205
- attach_function :socket, [:int, :int, :int], :int
206
- attach_function :send, [:int, :pointer, :size_t, :int], :int
207
- attach_function :recv, [:int, :pointer, :size_t, :int], :int
208
- attach_function :recvfrom, [:int, :pointer, :size_t, :int,
209
- :pointer, :pointer], :int
210
-
211
- attach_function :_getsockopt,
212
- "getsockopt", [:int, :int, :int, :pointer, :pointer], :int
213
- attach_function :_getaddrinfo,
214
- "getaddrinfo", [:string, :string, :pointer, :pointer], :int
215
-
216
- attach_function :gai_strerror, [:int], :string
217
- attach_function :setsockopt, [:int, :int, :int, :pointer, :socklen_t], :int
218
- attach_function :freeaddrinfo, [:pointer], :void
219
- attach_function :_getpeername, "getpeername", [:int, :pointer, :pointer], :int
220
- attach_function :_getsockname, "getsockname", [:int, :pointer, :pointer], :int
221
-
222
- attach_function :socketpair, [:int, :int, :int, :pointer], :int
223
-
224
- attach_function :gethostname, [:pointer, :size_t], :int
225
- attach_function :getservbyname, [:pointer, :pointer], :pointer
226
-
227
- attach_function :htons, [:uint16_t], :uint16_t
228
- attach_function :ntohs, [:uint16_t], :uint16_t
229
-
230
- attach_function :_getnameinfo,
231
- "getnameinfo", [:pointer, :socklen_t, :pointer, :socklen_t,
232
- :pointer, :socklen_t, :int], :int
233
-
234
- def self.bind(descriptor, sockaddr)
235
- FFI::MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
236
- sockaddr_p.write_string sockaddr, sockaddr.length
237
-
238
- _bind descriptor, sockaddr_p, sockaddr.length
239
- end
240
- end
241
-
242
- def self.connect(descriptor, sockaddr)
243
- err = 0
244
- FFI::MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
245
- sockaddr_p.write_string sockaddr, sockaddr.length
246
-
247
- err = _connect descriptor, sockaddr_p, sockaddr.length
248
- end
249
-
250
- err
251
- end
252
-
253
- def self.getsockopt(descriptor, level, optname)
254
- FFI::MemoryPointer.new 256 do |val| # HACK magic number
255
- FFI::MemoryPointer.new :socklen_t do |length|
256
- length.write_int 256 # HACK magic number
257
-
258
- err = _getsockopt descriptor, level, optname, val, length
259
-
260
- Errno.handle "Unable to get socket option" unless err == 0
261
-
262
- return val.read_string(length.read_int)
263
- end
264
- end
265
- end
266
-
267
- def self.getaddrinfo(host, service = nil, family = nil, socktype = nil, protocol = nil, flags = nil)
268
- hints = Addrinfo.new
269
- hints[:ai_family] = family || 0
270
- hints[:ai_socktype] = socktype || 0
271
- hints[:ai_protocol] = protocol || 0
272
- hints[:ai_flags] = flags || 0
273
-
274
- if host && (host.empty? || host == '<any>')
275
- host = "0.0.0.0"
276
- elsif host == '<broadcast>'
277
- host = '255.255.255.255'
278
- end
279
-
280
- res_p = FFI::MemoryPointer.new :pointer
281
-
282
- err = _getaddrinfo host, service, hints.pointer, res_p
283
-
284
- raise SocketError, gai_strerror(err) unless err == 0
285
-
286
- ptr = res_p.read_pointer
287
-
288
- return [] unless ptr
289
-
290
- res = Addrinfo.new ptr
291
-
292
- addrinfos = []
293
-
294
- while true
295
- addrinfo = []
296
- addrinfo << res[:ai_flags]
297
- addrinfo << res[:ai_family]
298
- addrinfo << res[:ai_socktype]
299
- addrinfo << res[:ai_protocol]
300
- addrinfo << res[:ai_addr].read_string(res[:ai_addrlen])
301
- addrinfo << res[:ai_canonname]
302
-
303
- addrinfos << addrinfo
304
-
305
- break unless res[:ai_next]
306
-
307
- res = Addrinfo.new res[:ai_next]
308
- end
309
-
310
- return addrinfos
311
- ensure
312
- hints.free if hints
313
-
314
- if res_p
315
- ptr = res_p.read_pointer
316
-
317
- # Be sure to feed a legit pointer to freeaddrinfo
318
- if ptr and !ptr.null?
319
- freeaddrinfo ptr
320
- end
321
- res_p.free
322
- end
323
- end
324
-
325
- def self.getaddress(host)
326
- addrinfos = getaddrinfo(host)
327
- unpack_sockaddr_in(addrinfos.first[4], false).first
328
- end
329
-
330
- def self.getnameinfo(sockaddr, flags = Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV,
331
- reverse_lookup = !BasicSocket.do_not_reverse_lookup)
332
- name_info = []
333
- value = nil
334
-
335
- FFI::MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
336
- FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXHOST do |node|
337
- FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXSERV do |service|
338
- sockaddr_p.write_string sockaddr, sockaddr.length
339
-
340
- if reverse_lookup then
341
- err = _getnameinfo(sockaddr_p, sockaddr.length,
342
- node, Socket::Constants::NI_MAXHOST, nil, 0, 0)
343
-
344
- name_info[2] = node.read_string if err == 0
345
- end
346
-
347
- err = _getnameinfo(sockaddr_p, sockaddr.length,
348
- node, Socket::Constants::NI_MAXHOST,
349
- service, Socket::Constants::NI_MAXSERV,
350
- flags)
351
-
352
- unless err == 0 then
353
- raise SocketError, gai_strerror(err)
354
- end
355
-
356
- sa_family = SockAddr_In.new(sockaddr)[:sin_family]
357
-
358
- name_info[0] = Socket::Constants::AF_TO_FAMILY[sa_family]
359
- name_info[1] = service.read_string
360
- name_info[3] = node.read_string
361
- end
362
- end
363
- end
364
-
365
- name_info[2] = name_info[3] if name_info[2].nil?
366
- name_info
367
- end
368
-
369
- def self.getpeername(descriptor)
370
- FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
371
- FFI::MemoryPointer.new :socklen_t do |len_p|
372
- len_p.write_int 128
373
-
374
- err = _getpeername descriptor, sockaddr_storage_p, len_p
375
-
376
- Errno.handle 'getpeername(2)' unless err == 0
377
-
378
- sockaddr_storage_p.read_string len_p.read_int
379
- end
380
- end
381
- end
382
-
383
- def self.getsockname(descriptor)
384
- FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
385
- FFI::MemoryPointer.new :socklen_t do |len_p|
386
- len_p.write_int 128
387
-
388
- err = _getsockname descriptor, sockaddr_storage_p, len_p
389
-
390
- Errno.handle 'getsockname(2)' unless err == 0
391
-
392
- sockaddr_storage_p.read_string len_p.read_int
393
- end
394
- end
395
- end
396
-
397
- def self.pack_sockaddr_in(host, port, family, type, flags)
398
- hints = Addrinfo.new
399
- hints[:ai_family] = family
400
- hints[:ai_socktype] = type
401
- hints[:ai_flags] = flags
402
-
403
- if host && host.empty?
404
- host = "0.0.0.0"
405
- end
406
-
407
- res_p = FFI::MemoryPointer.new :pointer
408
-
409
- err = _getaddrinfo host, port.to_s, hints.pointer, res_p
410
-
411
- raise SocketError, gai_strerror(err) unless err == 0
412
-
413
- return [] if res_p.read_pointer.null?
414
-
415
- res = Addrinfo.new res_p.read_pointer
416
-
417
- return res[:ai_addr].read_string(res[:ai_addrlen])
418
-
419
- ensure
420
- hints.free if hints
421
-
422
- if res_p then
423
- ptr = res_p.read_pointer
424
-
425
- freeaddrinfo ptr if ptr and not ptr.null?
426
-
427
- res_p.free
428
- end
429
- end
430
-
431
- def self.unpack_sockaddr_in(sockaddr, reverse_lookup)
432
- family, port, host, ip = getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV, reverse_lookup
433
- # On some systems this doesn't fail for families other than AF_INET(6)
434
- # so we raise manually here.
435
- raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr' unless family =~ /AF_INET/
436
- return host, ip, port.to_i
437
- end
438
- end
439
-
440
- module ListenAndAccept
441
- include IO::Socketable
442
-
443
- def listen(backlog)
444
- backlog = Rubinius::Type.coerce_to backlog, Fixnum, :to_int
445
-
446
- err = Socket::Foreign.listen descriptor, backlog
447
-
448
- Errno.handle 'listen(2)' unless err == 0
449
-
450
- err
451
- end
452
-
453
- def accept
454
- return if closed?
455
-
456
- fd = super
457
-
458
- socket = self.class.superclass.allocate
459
- IO.setup socket, fd, nil, true
460
- socket
461
- end
462
-
463
- #
464
- # Set nonblocking and accept.
465
- #
466
- def accept_nonblock
467
- return if closed?
468
-
469
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
470
-
471
- fd = Socket::Foreign.accept descriptor, nil, nil
472
-
473
- Errno.handle 'accept(2)' if fd < 0
474
-
475
- # TCPServer -> TCPSocket etc. *sigh*
476
- socket = self.class.superclass.allocate
477
- IO.setup socket, fd, nil, true
478
- socket
479
- end
480
-
481
- def accept_nonblock2
482
- return if closed?
483
-
484
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
485
-
486
- fd = Socket::Foreign.accept descriptor, nil, nil
487
- if fd < 0
488
- return nil if FFI::Platform::POSIX.errno == Errno::EAGAIN::Errno
489
- Errno.handle 'accept(2)'
490
- end
491
-
492
- # TCPServer -> TCPSocket etc. *sigh*
493
- socket = self.class.superclass.allocate
494
- IO.setup socket, fd, nil, true
495
- socket
496
- end
497
- end
498
-
499
- include Socket::ListenAndAccept
500
-
501
- class SockAddr_In < FFI::Struct
502
- config("rbx.platform.sockaddr_in", :sin_family, :sin_port, :sin_addr, :sin_zero)
503
-
504
- def initialize(sockaddrin)
505
- @p = FFI::MemoryPointer.new sockaddrin.size
506
- @p.write_string(sockaddrin)
507
- super(@p)
508
- end
509
-
510
- def to_s
511
- @p.read_string(@p.total)
512
- end
513
-
514
- end
515
-
516
- # If we have the details to support unix sockets, do so.
517
- if FFI.config("sockaddr_un.sun_family.offset") and Socket::Constants.const_defined?(:AF_UNIX)
518
- class SockAddr_Un < FFI::Struct
519
- config("rbx.platform.sockaddr_un", :sun_family, :sun_path)
520
-
521
- def initialize(filename = nil)
522
- maxfnsize = self.size - (FFI.config("sockaddr_un.sun_family.size") + 1)
523
-
524
- if filename and filename.length > maxfnsize
525
- raise ArgumentError, "too long unix socket path (max: #{maxfnsize}bytes)"
526
- end
527
- @p = FFI::MemoryPointer.new self.size
528
- if filename
529
- @p.write_string( [Socket::AF_UNIX].pack("s") + filename )
530
- end
531
- super @p
532
- end
533
-
534
- def to_s
535
- @p.read_string self.size
536
- end
537
- end
538
- end
539
-
540
- def self.getaddrinfo(host, service, family = 0, socktype = 0,
541
- protocol = 0, flags = 0)
542
- if service
543
- if service.kind_of? Fixnum
544
- service = service.to_s
545
- else
546
- service = StringValue(service)
547
- end
548
- end
549
-
550
- addrinfos = Socket::Foreign.getaddrinfo(host, service, family, socktype,
551
- protocol, flags)
552
-
553
- addrinfos.map do |ai|
554
- addrinfo = []
555
- addrinfo << Socket::Constants::AF_TO_FAMILY[ai[1]]
556
-
557
- sockaddr = Foreign.unpack_sockaddr_in ai[4], !BasicSocket.do_not_reverse_lookup
558
-
559
- addrinfo << sockaddr.pop # port
560
- addrinfo.concat sockaddr # hosts
561
- addrinfo << ai[1]
562
- addrinfo << ai[2]
563
- addrinfo << ai[3]
564
- addrinfo
565
- end
566
- end
567
-
568
- def self.getnameinfo(sockaddr, flags = 0)
569
- port = nil
570
- host = nil
571
- family = Socket::AF_UNSPEC
572
- if sockaddr.is_a?(Array)
573
- if sockaddr.size == 3
574
- af = sockaddr[0]
575
- port = sockaddr[1]
576
- host = sockaddr[2]
577
- elsif sockaddr.size == 4
578
- af = sockaddr[0]
579
- port = sockaddr[1]
580
- host = sockaddr[3] || sockaddr[2]
581
- else
582
- raise ArgumentError, "array size should be 3 or 4, #{sockaddr.size} given"
583
- end
584
-
585
- if family == "AF_INET"
586
- family = Socket::AF_INET
587
- elsif family == "AF_INET6"
588
- family = Socket::AF_INET6
589
- end
590
- sockaddr = Socket::Foreign.pack_sockaddr_in(host, port, family, Socket::SOCK_DGRAM, 0)
591
- end
592
-
593
- family, port, host, ip = Socket::Foreign.getnameinfo(sockaddr, flags)
594
- [host, port]
595
- end
596
-
597
- def self.gethostname
598
- FFI::MemoryPointer.new :char, 1024 do |mp| #magic number 1024 comes from MRI
599
- Socket::Foreign.gethostname(mp, 1024) # same here
600
- return mp.read_string
601
- end
602
- end
603
-
604
- def self.gethostbyname(hostname)
605
- addrinfos = Socket.getaddrinfo(hostname, nil)
606
-
607
- hostname = addrinfos.first[2]
608
- family = addrinfos.first[4]
609
- addresses = []
610
- alternatives = []
611
- addrinfos.each do |a|
612
- alternatives << a[2] unless a[2] == hostname
613
- # transform addresses to packed strings
614
- if a[4] == family
615
- sockaddr = Socket.sockaddr_in(1, a[3])
616
- if family == AF_INET
617
- # IPv4 address
618
- offset = FFI.config("sockaddr_in.sin_addr.offset")
619
- size = FFI.config("sockaddr_in.sin_addr.size")
620
- addresses << sockaddr.slice(offset, size)
621
- elsif family == AF_INET6
622
- # Ipv6 address
623
- offset = FFI.config("sockaddr_in6.sin6_addr.offset")
624
- size = FFI.config("sockaddr_in6.sin6_addr.size")
625
- addresses << sockaddr.slice(offset, size)
626
- else
627
- addresses << a[3]
628
- end
629
- end
630
- end
631
-
632
- [hostname, alternatives.uniq, family] + addresses.uniq
633
- end
634
-
635
-
636
- class Servent < FFI::Struct
637
- config("rbx.platform.servent", :s_name, :s_aliases, :s_port, :s_proto)
638
-
639
- def initialize(data)
640
- @p = FFI::MemoryPointer.new data.size
641
- @p.write_string(data)
642
- super(@p)
643
- end
644
-
645
- def to_s
646
- @p.read_string(size)
647
- end
648
-
649
- end
650
-
651
- def self.getservbyname(service, proto='tcp')
652
- FFI::MemoryPointer.new :char, service.length + 1 do |svc|
653
- FFI::MemoryPointer.new :char, proto.length + 1 do |prot|
654
- svc.write_string(service + "\0")
655
- prot.write_string(proto + "\0")
656
- fn = Socket::Foreign.getservbyname(svc, prot)
657
-
658
- raise SocketError, "no such service #{service}/#{proto}" if fn.nil?
659
-
660
- s = Servent.new(fn.read_string(Servent.size))
661
- return Socket::Foreign.ntohs(s[:s_port])
662
- end
663
- end
664
- end
665
-
666
- def self.pack_sockaddr_in(port, host, type = Socket::SOCK_DGRAM, flags = 0)
667
- Socket::Foreign.pack_sockaddr_in host, port, Socket::AF_UNSPEC, type, flags
668
- end
669
-
670
- def self.unpack_sockaddr_in(sockaddr)
671
- host, address, port = Socket::Foreign.unpack_sockaddr_in sockaddr, false
672
-
673
- return [port, address]
674
- rescue SocketError => e
675
- if e.message =~ /ai_family not supported/ then # HACK platform specific?
676
- raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr'
677
- else
678
- raise e
679
- end
680
- end
681
-
682
- def self.socketpair(domain, type, protocol, klass=self)
683
- if domain.kind_of? String
684
- if domain.prefix? "AF_" or domain.prefix? "PF_"
685
- begin
686
- domain = Socket::Constants.const_get(domain)
687
- rescue NameError
688
- raise SocketError, "unknown socket domain #{domani}"
689
- end
690
- else
691
- raise SocketError, "unknown socket domain #{domani}"
692
- end
693
- end
694
-
695
- type = get_socket_type(type)
696
-
697
- FFI::MemoryPointer.new :int, 2 do |mp|
698
- Socket::Foreign.socketpair(domain, type, protocol, mp)
699
- fd0, fd1 = mp.read_array_of_int(2)
700
-
701
- [ klass.from_descriptor(fd0), klass.from_descriptor(fd1) ]
702
- end
703
- end
704
-
705
- class << self
706
- alias_method :sockaddr_in, :pack_sockaddr_in
707
- alias_method :pair, :socketpair
708
- end
709
-
710
- # Only define these methods if we support unix sockets
711
- if self.const_defined?(:SockAddr_Un)
712
- def self.pack_sockaddr_un(file)
713
- SockAddr_Un.new(file).to_s
714
- end
715
-
716
- def self.unpack_sockaddr_un(addr)
717
-
718
- if addr.length > FFI.config("sockaddr_un.sizeof")
719
- raise TypeError, "too long sockaddr_un - #{addr.length} longer than #{FFI.config("sockaddr_un.sizeof")}"
720
- end
721
-
722
- struct = SockAddr_Un.new
723
- struct.pointer.write_string(addr)
724
-
725
- struct[:sun_path]
726
- end
727
-
728
- class << self
729
- alias_method :sockaddr_un, :pack_sockaddr_un
730
- end
731
- end
732
-
733
- def initialize(family, socket_type, protocol)
734
- family = self.class.get_protocol_family family
735
- socket_type = self.class.get_socket_type socket_type
736
- descriptor = Socket::Foreign.socket family, socket_type, protocol
737
-
738
- Errno.handle 'socket(2)' if descriptor < 0
739
-
740
- IO.setup self, descriptor, nil, true
741
- end
742
-
743
- def bind(server_sockaddr)
744
- err = Socket::Foreign.bind(descriptor, server_sockaddr)
745
- Errno.handle 'bind(2)' unless err == 0
746
- err
747
- end
748
-
749
- # @todo Should this be closing the descriptor? --rue
750
- def connect(sockaddr, extra=nil)
751
- if extra
752
- sockaddr = Socket.pack_sockaddr_in sockaddr, extra
753
- else
754
- sockaddr = StringValue(sockaddr)
755
- end
756
-
757
- status = Socket::Foreign.connect descriptor, sockaddr
758
-
759
- if status < 0
760
- begin
761
- Errno.handle "connect(2)"
762
- rescue Errno::EISCONN
763
- return 0
764
- end
765
- end
766
-
767
- return 0
768
- end
769
-
770
- def connect_nonblock(sockaddr)
771
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
772
-
773
- status = Socket::Foreign.connect descriptor, StringValue(sockaddr)
774
- if status < 0
775
- Errno.handle "connect(2)"
776
- end
777
-
778
- return status
779
- end
780
-
781
- def self.get_protocol_family(family)
782
- case family
783
- when Fixnum
784
- return family
785
- when String
786
- # do nothing
787
- else
788
- family = StringValue(family)
789
- end
790
-
791
- return Socket::Constants.const_get family
792
- end
793
-
794
- def self.get_socket_type(type)
795
- if type.kind_of? String
796
- if type.prefix? "SOCK_"
797
- begin
798
- type = Socket::Constants.const_get(type)
799
- rescue NameError
800
- raise SocketError, "unknown socket type #{type}"
801
- end
802
- else
803
- raise SocketError, "unknown socket type #{type}"
804
- end
805
- elsif !type.kind_of? Integer
806
- raise Errno::EPROTONOSUPPORT, type.inspect
807
- end
808
-
809
- type
810
- end
811
- end
812
-
813
- class UNIXSocket < BasicSocket
814
- include IO::TransferIO
815
-
816
- # Coding to the lowest standard here.
817
- def recvfrom(bytes_read, flags = 0)
818
- # FIXME 2 is hardcoded knowledge from io.cpp
819
- socket_recv(bytes_read, flags, 2)
820
- end
821
-
822
- def initialize(path)
823
- @path = path
824
- unix_setup
825
- @path = "" # Client
826
- end
827
-
828
- def path
829
- unless @path
830
- sockaddr = Socket::Foreign.getsockname descriptor
831
- _, @path = sockaddr.unpack('SZ*')
832
- end
833
-
834
- return @path
835
- end
836
-
837
- def from_descriptor(fixnum)
838
- super
839
- @path = nil
840
- end
841
-
842
- def unix_setup(server = false)
843
- status = nil
844
- phase = 'socket(2)'
845
- sock = Socket::Foreign.socket Socket::Constants::AF_UNIX, Socket::Constants::SOCK_STREAM, 0
846
-
847
- Errno.handle phase if sock < 0
848
-
849
- IO.setup self, sock, 'r+', true
850
-
851
- sockaddr = Socket.pack_sockaddr_un(@path)
852
-
853
- if server then
854
- phase = 'bind(2)'
855
- status = Socket::Foreign.bind descriptor, sockaddr
856
- else
857
- phase = 'connect(2)'
858
- status = Socket::Foreign.connect descriptor, sockaddr
859
- end
860
-
861
- if status < 0 then
862
- close
863
- Errno.handle phase
864
- end
865
-
866
- if server then
867
- phase = 'listen(2)'
868
- status = Socket::Foreign.listen descriptor, 5
869
- if status < 0
870
- close
871
- Errno.handle phase
872
- end
873
- end
874
-
875
- return sock
876
- end
877
- private :unix_setup
878
-
879
- def addr
880
- sockaddr = Socket::Foreign.getsockname descriptor
881
- _, sock_path = sockaddr.unpack('SZ*')
882
- ["AF_UNIX", sock_path]
883
- end
884
-
885
- def peeraddr
886
- sockaddr = Socket::Foreign.getpeername descriptor
887
- _, sock_path = sockaddr.unpack('SZ*')
888
- ["AF_UNIX", sock_path]
889
- end
890
-
891
- def recv_io(klass=IO, mode=nil)
892
- begin
893
- fd = recv_fd
894
- rescue PrimitiveFailure
895
- raise SocketError, "file descriptor was not passed"
896
- end
897
-
898
- return fd unless klass
899
-
900
- if klass < BasicSocket
901
- klass.for_fd(fd)
902
- else
903
- klass.for_fd(fd, mode)
904
- end
905
- end
906
-
907
- class << self
908
- def socketpair(type=Socket::SOCK_STREAM, protocol=0)
909
- Socket.socketpair(Socket::PF_UNIX, type, protocol, self)
910
- end
911
-
912
- alias_method :pair, :socketpair
913
- end
914
-
915
- end
916
-
917
- class UNIXServer < UNIXSocket
918
-
919
- include Socket::ListenAndAccept
920
-
921
- def initialize(path)
922
- @path = path
923
- unix_setup(true)
924
- end
925
- end
926
-
927
- class IPSocket < BasicSocket
928
-
929
- def self.getaddress(host)
930
- Socket::Foreign.getaddress host
931
- end
932
-
933
- def addr
934
- sockaddr = Socket::Foreign.getsockname descriptor
935
-
936
- family, port, host, ip = Socket::Foreign.getnameinfo sockaddr
937
- [family, port.to_i, host, ip]
938
- end
939
-
940
- def peeraddr
941
- sockaddr = Socket::Foreign.getpeername descriptor
942
-
943
- family, port, host, ip = Socket::Foreign.getnameinfo sockaddr
944
- [family, port.to_i, host, ip]
945
- end
946
-
947
- def recvfrom(maxlen, flags = 0)
948
- # FIXME 1 is hardcoded knowledge from io.cpp
949
- flags = 0 if flags.nil?
950
- socket_recv maxlen, flags, 1
951
- end
952
-
953
- def recvfrom_nonblock(maxlen, flags = 0)
954
- # Set socket to non-blocking, if we can
955
- # Todo: Ensure this works in Windows! If not, I claim that's Fcntl's fault.
956
- fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
957
- flags = 0 if flags.nil?
958
- flags |= Socket::MSG_DONTWAIT
959
-
960
- # Wait until we have something to read
961
- # @todo Why? ^^ --rue
962
- IO.select([self])
963
- return recvfrom(maxlen, flags)
964
- end
965
- end
966
-
967
- class UDPSocket < IPSocket
968
- FFI = Rubinius::FFI
969
-
970
- def initialize(socktype = Socket::AF_INET)
971
- @socktype = socktype
972
- status = Socket::Foreign.socket @socktype,
973
- Socket::SOCK_DGRAM,
974
- Socket::IPPROTO_UDP
975
- Errno.handle 'socket(2)' if status < 0
976
-
977
- IO.setup self, status, nil, true
978
- end
979
-
980
- def bind(host, port)
981
- @host = host.to_s if host
982
- @port = port.to_s if port
983
-
984
- addrinfos = Socket::Foreign.getaddrinfo(@host,
985
- @port,
986
- @socktype,
987
- Socket::SOCK_DGRAM, 0,
988
- Socket::AI_PASSIVE)
989
-
990
- status = -1
991
-
992
- addrinfos.each do |addrinfo|
993
- flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
994
-
995
- status = Socket::Foreign.bind descriptor, sockaddr
996
-
997
- break if status >= 0
998
- end
999
-
1000
- if status < 0
1001
- Errno.handle 'bind(2)'
1002
- end
1003
-
1004
- status
1005
- end
1006
-
1007
- def connect(host, port)
1008
- sockaddr = Socket::Foreign.pack_sockaddr_in host, port, @socktype, Socket::SOCK_DGRAM, 0
1009
-
1010
- syscall = 'connect(2)'
1011
- status = Socket::Foreign.connect descriptor, sockaddr
1012
-
1013
- if status < 0
1014
- Errno.handle syscall
1015
- end
1016
-
1017
- 0
1018
- end
1019
-
1020
- def send(message, flags, *to)
1021
- connect *to unless to.empty?
1022
-
1023
- bytes = message.length
1024
- bytes_sent = 0
1025
-
1026
- FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
1027
- buffer.write_string message
1028
- bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
1029
- Errno.handle 'send(2)' if bytes_sent < 0
1030
- end
1031
-
1032
- bytes_sent
1033
- end
1034
-
1035
- def inspect
1036
- "#<#{self.class}:0x#{object_id.to_s(16)} #{@host}:#{@port}>"
1037
- end
1038
-
1039
- end
1040
-
1041
- class TCPSocket < IPSocket
1042
- FFI = Rubinius::FFI
1043
-
1044
- def self.gethostbyname(hostname)
1045
- addrinfos = Socket.getaddrinfo(hostname, nil)
1046
-
1047
- hostname = addrinfos.first[2]
1048
- family = addrinfos.first[4]
1049
- addresses = []
1050
- alternatives = []
1051
- addrinfos.each do |a|
1052
- alternatives << a[2] unless a[2] == hostname
1053
- addresses << a[3] if a[4] == family
1054
- end
1055
-
1056
- [hostname, alternatives.uniq, family] + addresses.uniq
1057
- end
1058
-
1059
- #
1060
- # @todo Is it correct to ignore the to? If not, does
1061
- # the socket need to be reconnected? --rue
1062
- #
1063
- def send(bytes_to_read, flags, to = nil)
1064
- super(bytes_to_read, flags)
1065
- end
1066
-
1067
-
1068
- def initialize(host, port, local_host=nil, local_service=nil)
1069
- @host = host
1070
- @port = port
1071
-
1072
- tcp_setup @host, @port, local_host, local_service
1073
- end
1074
-
1075
- def tcp_setup(remote_host, remote_service, local_host = nil,
1076
- local_service = nil, server = false)
1077
- status = nil
1078
- syscall = nil
1079
- remote_host = StringValue(remote_host) if remote_host
1080
- if remote_service
1081
- if remote_service.kind_of? Fixnum
1082
- remote_service = remote_service.to_s
1083
- else
1084
- remote_service = StringValue(remote_service)
1085
- end
1086
- end
1087
-
1088
- flags = server ? Socket::AI_PASSIVE : 0
1089
- @remote_addrinfo = Socket::Foreign.getaddrinfo(remote_host,
1090
- remote_service,
1091
- Socket::AF_UNSPEC,
1092
- Socket::SOCK_STREAM, 0,
1093
- flags)
1094
-
1095
- if server == false and (local_host or local_service)
1096
- local_host = local_host.to_s if local_host
1097
- local_service = local_service.to_s if local_service
1098
- @local_addrinfo = Socket::Foreign.getaddrinfo(local_host,
1099
- local_service,
1100
- Socket::AF_UNSPEC,
1101
- Socket::SOCK_STREAM, 0, 0)
1102
- end
1103
-
1104
- sock = nil
1105
-
1106
- @remote_addrinfo.each do |addrinfo|
1107
- flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
1108
-
1109
- sock = Socket::Foreign.socket family, socket_type, protocol
1110
- syscall = 'socket(2)'
1111
-
1112
- next if sock < 0
1113
-
1114
- if server
1115
- FFI::MemoryPointer.new :socklen_t do |val|
1116
- val.write_int 1
1117
- level = Socket::Constants::SOL_SOCKET
1118
- optname = Socket::Constants::SO_REUSEADDR
1119
- error = Socket::Foreign.setsockopt(sock, level,
1120
- optname, val,
1121
- val.total)
1122
- # Don't check error because if this fails, we just continue
1123
- # anyway.
1124
- end
1125
-
1126
- status = Socket::Foreign.bind sock, sockaddr
1127
- syscall = 'bind(2)'
1128
- else
1129
- if @local_addrinfo
1130
- # Pick a local_addrinfo for the family and type of
1131
- # the remote side
1132
- li = @local_addrinfo.find do |i|
1133
- i[1] == family && i[2] == socket_type
1134
- end
1135
-
1136
- if li
1137
- status = Socket::Foreign.bind sock, li[4]
1138
- syscall = 'bind(2)'
1139
- else
1140
- status = 1
1141
- end
1142
- else
1143
- status = 1
1144
- end
1145
-
1146
- if status >= 0
1147
- status = Socket::Foreign.connect sock, sockaddr
1148
- syscall = 'connect(2)'
1149
- end
1150
- end
1151
-
1152
- if status < 0
1153
- Socket::Foreign.close sock
1154
- else
1155
- break
1156
- end
1157
- end
1158
-
1159
- if status < 0
1160
- Errno.handle syscall
1161
- end
1162
-
1163
- if server
1164
- err = Socket::Foreign.listen sock, 5
1165
- unless err == 0
1166
- Socket::Foreign.close sock
1167
- Errno.handle syscall
1168
- end
1169
- end
1170
-
1171
- # Only setup once we have found a socket we can use. Otherwise
1172
- # because we manually close a socket fd, we can create an IO fd
1173
- # alias condition which causes EBADF because when an IO is finalized
1174
- # and it's fd has been closed underneith it, we close someone elses
1175
- # fd!
1176
- IO.setup self, sock, nil, true
1177
- end
1178
- private :tcp_setup
1179
-
1180
- def from_descriptor(descriptor)
1181
- IO.setup self, descriptor, nil, true
1182
-
1183
- self
1184
- end
1185
- end
1186
-
1187
- class TCPServer < TCPSocket
1188
-
1189
- include Socket::ListenAndAccept
1190
-
1191
- def initialize(host, port = nil)
1192
- if Fixnum === host and port.nil? then
1193
- port = host
1194
- host = nil
1195
- end
1196
-
1197
- if String === host and port.nil? then
1198
- port = Integer(host)
1199
- host = nil
1200
- end
1201
-
1202
- port = StringValue port unless port.kind_of? Fixnum
1203
-
1204
- @host = host
1205
- @port = port
1206
-
1207
- tcp_setup @host, @port, nil, nil, true
1208
- end
1209
-
1210
- end