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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a687efad1b7199d53b21fe71763459fec39b3283
4
- data.tar.gz: f854d3362dae260928e72a7c4f4a556c55883e97
3
+ metadata.gz: 3001f70f2e5573956833527ffbe91569468d1db7
4
+ data.tar.gz: 8b6cbda543492cb5ba85b95950ec3442ff589020
5
5
  SHA512:
6
- metadata.gz: d185e6ab0ba0c801a1c6279ff7e3091b42476f0fb9438f7b30040acda156b26092deb4a10954746c5db64d5ed414a1acedf8f9c12c5735f2f01008a7c0abd0c3
7
- data.tar.gz: 265d200b3494d2551b0fa96ca4039cb861ed0f6ac022cc03f3dcf4bf0aafbb61d551a5799c4e5016768f1b53dca6f042244a10a225f086a5e572535d3ada7eac
6
+ metadata.gz: c5ffc798a438d07cb7d87c63cec69bab0e8a05ff5e21b7d4c97401a6dec668e1948bb780aec783a0f0302643448130549923d04ea35d4cabb0d5d2c338c81295
7
+ data.tar.gz: d94be2dc455e26657f2e73b3490cfa36e9984757bfcdd1b51241afcf5b154fe295d5c1e024d4a95a05db2226e444297381c20e3a783510ad9832281b8eb5e755
data/.travis.yml CHANGED
@@ -1,14 +1,7 @@
1
1
  language: ruby
2
2
  env:
3
3
  - RUBYLIB=lib
4
- - RUBYLIB=
5
- script: mspec spec
4
+ script: bundle exec mspec
6
5
  rvm:
7
- - 1.8.7
8
- - rbx-1
9
- matrix:
10
- exclude:
11
- - rvm: 1.8.7
12
- env: RUBYLIB=lib
13
- - rvm: rbx-1
14
- env: RUBYLIB=
6
+ - 1.9.3
7
+ - rbx-nightly-19mode
data/lib/rubysl/socket.rb CHANGED
@@ -1,2 +1,1520 @@
1
- require "rubysl/socket/socket"
2
1
  require "rubysl/socket/version"
2
+ require "rubysl/fcntl"
3
+
4
+ class SocketError < StandardError
5
+ end
6
+
7
+ # @todo Socket#accept[_nonblock]
8
+ # @todo UNIXServer#accept[_nonblock]
9
+ # @todo UDPSocket#recvfrom
10
+
11
+ class BasicSocket < IO
12
+ FFI = Rubinius::FFI
13
+
14
+ class << self
15
+ def from_descriptor(fixnum)
16
+ sock = allocate()
17
+ sock.from_descriptor(fixnum)
18
+ return sock
19
+ end
20
+
21
+ alias :for_fd :from_descriptor
22
+ end
23
+
24
+ def from_descriptor(fixnum)
25
+ IO.setup self, fixnum, nil, true
26
+ return self
27
+ end
28
+
29
+ def self.do_not_reverse_lookup=(setting)
30
+ @no_reverse_lookup = setting
31
+ end
32
+
33
+ def self.do_not_reverse_lookup
34
+ @no_reverse_lookup = true unless defined? @no_reverse_lookup
35
+ @no_reverse_lookup
36
+ end
37
+
38
+ def do_not_reverse_lookup=(setting)
39
+ @no_reverse_lookup = setting
40
+ end
41
+
42
+ def do_not_reverse_lookup
43
+ @no_reverse_lookup
44
+ end
45
+
46
+ def getsockopt(level, optname)
47
+ data = Socket::Foreign.getsockopt(descriptor, level, optname)
48
+
49
+ sockaddr = Socket::Foreign.getsockname(descriptor)
50
+ family, = Socket::Foreign.getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV
51
+ Socket::Option.new(family, level, optname, data)
52
+ end
53
+
54
+ def setsockopt(level_or_option, optname=nil, optval=nil)
55
+ level = nil
56
+
57
+ case level_or_option
58
+ when Socket::Option
59
+ if !optname.nil?
60
+ raise ArgumentError, "given 2, expected 3"
61
+ end
62
+ level = level_or_option.level
63
+ optname = level_or_option.optname
64
+ optval = level_or_option.data
65
+ else
66
+ if level_or_option.nil? or optname.nil?
67
+ nb_arg = 3 - [level_or_option, optname, optval].count(nil)
68
+ raise ArgumentError, "given #{nb_arg}, expected 3"
69
+ end
70
+ level = level_or_option
71
+ end
72
+
73
+ optval = 1 if optval == true
74
+ optval = 0 if optval == false
75
+
76
+ error = 0
77
+
78
+ sockname = Socket::Foreign.getsockname descriptor
79
+ family = Socket::Foreign.getnameinfo(sockname).first
80
+
81
+ level = level_arg(family, level)
82
+ optname = optname_arg(level, optname)
83
+
84
+ case optval
85
+ when Fixnum then
86
+ FFI::MemoryPointer.new :socklen_t do |val|
87
+ val.write_int optval
88
+ error = Socket::Foreign.setsockopt(descriptor, level,
89
+ optname, val,
90
+ val.total)
91
+ end
92
+ when String then
93
+ FFI::MemoryPointer.new optval.bytesize do |val|
94
+ val.write_string optval, optval.bytesize
95
+ error = Socket::Foreign.setsockopt(descriptor, level,
96
+ optname, val,
97
+ optval.size)
98
+ end
99
+ else
100
+ raise TypeError, "socket option should be a String, a Fixnum, true, or false"
101
+ end
102
+
103
+ Errno.handle "Unable to set socket option" unless error == 0
104
+
105
+ return 0
106
+ end
107
+
108
+ def getsockname()
109
+ return Socket::Foreign.getsockname(descriptor)
110
+ end
111
+
112
+ #
113
+ # Obtain peername information for this socket.
114
+ #
115
+ # @see Socket.getpeername
116
+ #
117
+ def getpeername()
118
+ Socket::Foreign.getpeername @descriptor
119
+ end
120
+
121
+ #
122
+ #
123
+ #
124
+ def send(message, flags, to = nil)
125
+ connect to if to
126
+
127
+ bytes = message.bytesize
128
+ bytes_sent = 0
129
+
130
+ FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
131
+ buffer.write_string message, bytes
132
+ bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
133
+ Errno.handle 'send(2)' if bytes_sent < 0
134
+ end
135
+
136
+ bytes_sent
137
+ end
138
+
139
+ def recvfrom(bytes_to_read, flags = 0)
140
+ # FIXME 0 is knowledge from io.cpp
141
+ return socket_recv(bytes_to_read, flags, 0)
142
+ end
143
+
144
+ def recv(bytes_to_read, flags = 0)
145
+ # FIXME 0 is knowledge from io.cpp
146
+ return socket_recv(bytes_to_read, flags, 0)
147
+ end
148
+
149
+ def close_read
150
+ ensure_open
151
+
152
+ # If we were only in readonly mode, close it all together
153
+ if @mode & ACCMODE == RDONLY
154
+ return close
155
+ end
156
+
157
+ # MRI doesn't check if shutdown worked, so we don't.
158
+ Socket::Foreign.shutdown @descriptor, 0
159
+
160
+ @mode = WRONLY
161
+
162
+ nil
163
+ end
164
+
165
+ def close_write
166
+ ensure_open
167
+
168
+ # If we were only in writeonly mode, close it all together
169
+ if @mode & ACCMODE == WRONLY
170
+ return close
171
+ end
172
+
173
+ Socket::Foreign.shutdown @descriptor, 1
174
+
175
+ # Mark it as read only
176
+ @mode = RDONLY
177
+
178
+ nil
179
+ end
180
+
181
+ #
182
+ # Sets socket nonblocking and reads up to given number of bytes.
183
+ #
184
+ # @todo Should EWOULDBLOCK be passed unchanged? --rue
185
+ #
186
+ def recv_nonblock(bytes_to_read, flags = 0)
187
+ fcntl Fcntl::F_SETFL, Fcntl::O_NONBLOCK
188
+ socket_recv bytes_to_read, flags, 0
189
+ rescue Errno::EWOULDBLOCK
190
+ raise Errno::EAGAIN
191
+ end
192
+
193
+ def shutdown(how = 2)
194
+ err = Socket::Foreign.shutdown @descriptor, how
195
+ Errno.handle "shutdown" unless err == 0
196
+ end
197
+
198
+ private
199
+
200
+ def level_arg(family, level)
201
+ case level
202
+ when Symbol, String
203
+ if Socket::Constants.const_defined?(level)
204
+ Socket::Constants.const_get(level)
205
+ else
206
+ if is_ip_family?(family)
207
+ ip_level_to_int(level)
208
+ else
209
+ unknown_level_to_int(level)
210
+ end
211
+ end
212
+ else
213
+ level
214
+ end
215
+ end
216
+
217
+ def optname_arg(level, optname)
218
+ case optname
219
+ when Symbol, String
220
+ if Socket::Constants.const_defined?(optname)
221
+ Socket::Constants.const_get(optname)
222
+ else
223
+ case(level)
224
+ when Socket::Constants::SOL_SOCKET
225
+ constant("SO", optname)
226
+ when Socket::Constants::IPPROTO_IP
227
+ constant("IP", optname)
228
+ when Socket::Constants::IPPROTO_TCP
229
+ constant("TCP", optname)
230
+ when Socket::Constants::IPPROTO_UDP
231
+ constant("UDP", optname)
232
+ else
233
+ if Socket::Constants.const_defined?(Socket::Constants::IPPROTO_IPV6) &&
234
+ level == Socket::Constants::IPPROTO_IPV6
235
+ constant("IPV6", optname)
236
+ else
237
+ optname
238
+ end
239
+ end
240
+ end
241
+ else
242
+ optname
243
+ end
244
+ end
245
+
246
+ def is_ip_family?(family)
247
+ family == "AF_INET" || family == "AF_INET6"
248
+ end
249
+
250
+ def ip_level_to_int(level)
251
+ prefixes = ["IPPROTO", "SOL"]
252
+ prefixes.each do |prefix|
253
+ if Socket::Constants.const_defined?("#{prefix}_#{level}")
254
+ return Socket::Constants.const_get("#{prefix}_#{level}")
255
+ end
256
+ end
257
+ end
258
+
259
+ def unknown_level_to_int(level)
260
+ constant("SOL", level)
261
+ end
262
+
263
+ def constant(prefix, suffix)
264
+ if Socket::Constants.const_defined?("#{prefix}_#{suffix}")
265
+ Socket::Constants.const_get("#{prefix}_#{suffix}")
266
+ end
267
+ end
268
+
269
+ end
270
+
271
+ class Socket < BasicSocket
272
+ FFI = Rubinius::FFI
273
+
274
+ # @todo Is omitting empty-value constants reasonable? --rue
275
+ module Constants
276
+ all_valid = FFI.config_hash("socket").reject {|name, value| value.empty? }
277
+
278
+ all_valid.each {|name, value| const_set name, Integer(value) }
279
+
280
+ # MRI compat. socket is a pretty screwed up API. All the constants in Constants
281
+ # must also be directly accessible on Socket itself. This means it's not enough
282
+ # to include Constants into Socket, because Socket#const_defined? must be able
283
+ # to see constants like AF_INET6 directly on Socket, but #const_defined? doesn't
284
+ # check inherited constants. O_o
285
+ #
286
+ all_valid.each {|name, value| Socket.const_set name, Integer(value) }
287
+
288
+
289
+ afamilies = all_valid.to_a.select { |name,| name =~ /^AF_/ }
290
+ afamilies.map! {|name, value| [value.to_i, name] }
291
+
292
+ pfamilies = all_valid.to_a.select { |name,| name =~ /^PF_/ }
293
+ pfamilies.map! {|name, value| [value.to_i, name] }
294
+
295
+ AF_TO_FAMILY = Hash[*afamilies.flatten]
296
+ PF_TO_FAMILY = Hash[*pfamilies.flatten]
297
+ end
298
+
299
+ module Foreign
300
+ extend FFI::Library
301
+
302
+ class Addrinfo < FFI::Struct
303
+ config("rbx.platform.addrinfo", :ai_flags, :ai_family, :ai_socktype,
304
+ :ai_protocol, :ai_addrlen, :ai_addr, :ai_canonname, :ai_next)
305
+ end
306
+
307
+ class Linger < FFI::Struct
308
+ config("rbx.platform.linger", :l_onoff, :l_linger)
309
+ end
310
+
311
+ attach_function :_bind, "bind", [:int, :pointer, :socklen_t], :int
312
+ attach_function :_connect, "connect", [:int, :pointer, :socklen_t], :int
313
+
314
+ attach_function :accept, [:int, :pointer, :pointer], :int
315
+ attach_function :close, [:int], :int
316
+ attach_function :shutdown, [:int, :int], :int
317
+ attach_function :listen, [:int, :int], :int
318
+ attach_function :socket, [:int, :int, :int], :int
319
+ attach_function :send, [:int, :pointer, :size_t, :int], :ssize_t
320
+ attach_function :recv, [:int, :pointer, :size_t, :int], :ssize_t
321
+ attach_function :recvfrom, [:int, :pointer, :size_t, :int,
322
+ :pointer, :pointer], :int
323
+
324
+ attach_function :_getsockopt,
325
+ "getsockopt", [:int, :int, :int, :pointer, :pointer], :int
326
+ attach_function :_getaddrinfo,
327
+ "getaddrinfo", [:string, :string, :pointer, :pointer], :int
328
+
329
+ attach_function :gai_strerror, [:int], :string
330
+ attach_function :setsockopt, [:int, :int, :int, :pointer, :socklen_t], :int
331
+ attach_function :freeaddrinfo, [:pointer], :void
332
+ attach_function :_getpeername, "getpeername", [:int, :pointer, :pointer], :int
333
+ attach_function :_getsockname, "getsockname", [:int, :pointer, :pointer], :int
334
+
335
+ attach_function :socketpair, [:int, :int, :int, :pointer], :int
336
+
337
+ attach_function :gethostname, [:pointer, :size_t], :int
338
+ attach_function :getservbyname, [:pointer, :pointer], :pointer
339
+
340
+ attach_function :htons, [:uint16_t], :uint16_t
341
+ attach_function :ntohs, [:uint16_t], :uint16_t
342
+
343
+ attach_function :_getnameinfo,
344
+ "getnameinfo", [:pointer, :socklen_t, :pointer, :socklen_t,
345
+ :pointer, :socklen_t, :int], :int
346
+
347
+ def self.bind(descriptor, sockaddr)
348
+ FFI::MemoryPointer.new :char, sockaddr.bytesize do |sockaddr_p|
349
+ sockaddr_p.write_string sockaddr, sockaddr.bytesize
350
+
351
+ _bind descriptor, sockaddr_p, sockaddr.bytesize
352
+ end
353
+ end
354
+
355
+ def self.connect(descriptor, sockaddr)
356
+ err = 0
357
+ FFI::MemoryPointer.new :char, sockaddr.bytesize do |sockaddr_p|
358
+ sockaddr_p.write_string sockaddr, sockaddr.bytesize
359
+
360
+ err = _connect descriptor, sockaddr_p, sockaddr.bytesize
361
+ end
362
+
363
+ err
364
+ end
365
+
366
+ def self.getsockopt(descriptor, level, optname)
367
+ FFI::MemoryPointer.new 256 do |val| # HACK magic number
368
+ FFI::MemoryPointer.new :socklen_t do |length|
369
+ length.write_int 256 # HACK magic number
370
+
371
+ err = _getsockopt descriptor, level, optname, val, length
372
+
373
+ Errno.handle "Unable to get socket option" unless err == 0
374
+
375
+ return val.read_string(length.read_int)
376
+ end
377
+ end
378
+ end
379
+
380
+ def self.getaddrinfo(host, service = nil, family = nil, socktype = nil, protocol = nil, flags = nil)
381
+ hints = Addrinfo.new
382
+ hints[:ai_family] = family || 0
383
+ hints[:ai_socktype] = socktype || 0
384
+ hints[:ai_protocol] = protocol || 0
385
+ hints[:ai_flags] = flags || 0
386
+
387
+ if host && (host.empty? || host == '<any>')
388
+ host = "0.0.0.0"
389
+ elsif host == '<broadcast>'
390
+ host = '255.255.255.255'
391
+ end
392
+
393
+ res_p = FFI::MemoryPointer.new :pointer
394
+
395
+ err = _getaddrinfo host, service, hints.pointer, res_p
396
+
397
+ raise SocketError, gai_strerror(err) unless err == 0
398
+
399
+ ptr = res_p.read_pointer
400
+
401
+ return [] unless ptr
402
+
403
+ res = Addrinfo.new ptr
404
+
405
+ addrinfos = []
406
+
407
+ while true
408
+ addrinfo = []
409
+ addrinfo << res[:ai_flags]
410
+ addrinfo << res[:ai_family]
411
+ addrinfo << res[:ai_socktype]
412
+ addrinfo << res[:ai_protocol]
413
+ addrinfo << res[:ai_addr].read_string(res[:ai_addrlen])
414
+ addrinfo << res[:ai_canonname]
415
+
416
+ addrinfos << addrinfo
417
+
418
+ break unless res[:ai_next]
419
+
420
+ res = Addrinfo.new res[:ai_next]
421
+ end
422
+
423
+ return addrinfos
424
+ ensure
425
+ hints.free if hints
426
+
427
+ if res_p
428
+ ptr = res_p.read_pointer
429
+
430
+ # Be sure to feed a legit pointer to freeaddrinfo
431
+ if ptr and !ptr.null?
432
+ freeaddrinfo ptr
433
+ end
434
+ res_p.free
435
+ end
436
+ end
437
+
438
+ def self.getaddress(host)
439
+ addrinfos = getaddrinfo(host)
440
+ unpack_sockaddr_in(addrinfos.first[4], false).first
441
+ end
442
+
443
+ def self.getnameinfo(sockaddr, flags = Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV,
444
+ reverse_lookup = !BasicSocket.do_not_reverse_lookup)
445
+ name_info = []
446
+ value = nil
447
+
448
+ FFI::MemoryPointer.new :char, sockaddr.bytesize do |sockaddr_p|
449
+ FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXHOST do |node|
450
+ FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXSERV do |service|
451
+ sockaddr_p.write_string sockaddr, sockaddr.bytesize
452
+
453
+ if reverse_lookup then
454
+ err = _getnameinfo(sockaddr_p, sockaddr.bytesize,
455
+ node, Socket::Constants::NI_MAXHOST, nil, 0, 0)
456
+
457
+ name_info[2] = node.read_string if err == 0
458
+ end
459
+
460
+ err = _getnameinfo(sockaddr_p, sockaddr.bytesize,
461
+ node, Socket::Constants::NI_MAXHOST,
462
+ service, Socket::Constants::NI_MAXSERV,
463
+ flags)
464
+
465
+ unless err == 0 then
466
+ raise SocketError, gai_strerror(err)
467
+ end
468
+
469
+ sa_family = SockAddr_In.new(sockaddr)[:sin_family]
470
+
471
+ name_info[0] = Socket::Constants::AF_TO_FAMILY[sa_family]
472
+ name_info[1] = service.read_string
473
+ name_info[3] = node.read_string
474
+ end
475
+ end
476
+ end
477
+
478
+ name_info[2] = name_info[3] if name_info[2].nil?
479
+ name_info
480
+ end
481
+
482
+ def self.getpeername(descriptor)
483
+ FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
484
+ FFI::MemoryPointer.new :socklen_t do |len_p|
485
+ len_p.write_int 128
486
+
487
+ err = _getpeername descriptor, sockaddr_storage_p, len_p
488
+
489
+ Errno.handle 'getpeername(2)' unless err == 0
490
+
491
+ sockaddr_storage_p.read_string len_p.read_int
492
+ end
493
+ end
494
+ end
495
+
496
+ def self.getsockname(descriptor)
497
+ FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
498
+ FFI::MemoryPointer.new :socklen_t do |len_p|
499
+ len_p.write_int 128
500
+
501
+ err = _getsockname descriptor, sockaddr_storage_p, len_p
502
+
503
+ Errno.handle 'getsockname(2)' unless err == 0
504
+
505
+ sockaddr_storage_p.read_string len_p.read_int
506
+ 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
+
528
+ res = Addrinfo.new res_p.read_pointer
529
+
530
+ return res[:ai_addr].read_string(res[:ai_addrlen])
531
+
532
+ ensure
533
+ hints.free if hints
534
+
535
+ if res_p then
536
+ ptr = res_p.read_pointer
537
+
538
+ freeaddrinfo ptr if ptr and not ptr.null?
539
+
540
+ res_p.free
541
+ end
542
+ end
543
+
544
+ def self.unpack_sockaddr_in(sockaddr, reverse_lookup)
545
+ family, port, host, ip = getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV, reverse_lookup
546
+ # On some systems this doesn't fail for families other than AF_INET(6)
547
+ # so we raise manually here.
548
+ raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr' unless family =~ /AF_INET/
549
+ return host, ip, port.to_i
550
+ end
551
+ end
552
+
553
+ module ListenAndAccept
554
+ include IO::Socketable
555
+
556
+ def listen(backlog)
557
+ backlog = Rubinius::Type.coerce_to backlog, Fixnum, :to_int
558
+
559
+ err = Socket::Foreign.listen descriptor, backlog
560
+
561
+ Errno.handle 'listen(2)' unless err == 0
562
+
563
+ err
564
+ end
565
+
566
+ def accept
567
+ return if closed?
568
+
569
+ fd = super
570
+
571
+ socket = self.class.superclass.allocate
572
+ IO.setup socket, fd, nil, true
573
+ socket.binmode
574
+ socket
575
+ end
576
+
577
+ #
578
+ # Set nonblocking and accept.
579
+ #
580
+ def accept_nonblock
581
+ return if closed?
582
+
583
+ fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
584
+
585
+ fd = nil
586
+ sockaddr = nil
587
+
588
+ FFI::MemoryPointer.new 1024 do |sockaddr_p| # HACK from MRI
589
+ FFI::MemoryPointer.new :int do |size_p|
590
+ fd = Socket::Foreign.accept descriptor, sockaddr_p, size_p
591
+ end
592
+ 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
+ end
618
+
619
+ end
620
+
621
+ class Option
622
+ attr_reader :family, :level, :optname, :data
623
+
624
+ def self.bool(family, level, optname, bool)
625
+ data = [(bool ? 1 : 0)].pack('i')
626
+ new family, level, optname, data
627
+ end
628
+
629
+ def self.int(family, level, optname, integer)
630
+ new family, level, optname, [integer].pack('i')
631
+ end
632
+
633
+ def self.linger(onoff, secs)
634
+ linger = Socket::Foreign::Linger.new
635
+
636
+ case onoff
637
+ when Integer
638
+ linger[:l_onoff] = onoff
639
+ else
640
+ linger[:l_onoff] = onoff ? 1 : 0
641
+ 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
+ end
659
+
660
+ def unpack(template)
661
+ @data.unpack template
662
+ end
663
+
664
+ def inspect
665
+ "#<#{self.class}: #@family_name #@level_name #@opt_name #{@data.inspect}>"
666
+ end
667
+
668
+ def bool
669
+ unless @data.length == Rubinius::FFI.type_size(:int)
670
+ raise TypeError, "size differ. expected as sizeof(int)=" +
671
+ "#{Rubinius::FFI.type_size(:int)} but #{@data.length}"
672
+ end
673
+
674
+ i = @data.unpack('i').first
675
+ i == 0 ? false : true
676
+ end
677
+
678
+ def int
679
+ unless @data.length == Rubinius::FFI.type_size(:int)
680
+ raise TypeError, "size differ. expected as sizeof(int)=" +
681
+ "#{Rubinius::FFI.type_size(:int)} but #{@data.length}"
682
+ end
683
+ @data.unpack('i').first
684
+ end
685
+
686
+ def linger
687
+ if @level != Socket::SOL_SOCKET || @optname != Socket::SO_LINGER
688
+ raise TypeError, "linger socket option expected"
689
+ end
690
+ if @data.bytesize != FFI.config("linger.sizeof")
691
+ raise TypeError, "size differ. expected as sizeof(struct linger)=" +
692
+ "#{FFI.config("linger.sizeof")} but #{@data.length}"
693
+ end
694
+
695
+ linger = Socket::Foreign::Linger.new
696
+ linger.to_ptr.write_string @data, @data.bytesize
697
+
698
+ onoff = nil
699
+ case linger[:l_onoff]
700
+ when 0 then onoff = false
701
+ when 1 then onoff = true
702
+ else onoff = linger[:l_onoff].to_i
703
+ end
704
+
705
+ [onoff, linger[:l_linger].to_i]
706
+ end
707
+
708
+ alias :to_s :data
709
+
710
+
711
+ private
712
+
713
+ def family_arg(family)
714
+ case family
715
+ when Symbol, String
716
+ f = family.to_s
717
+ if f[0..2] != 'AF_'
718
+ f = 'AF_' + f
719
+ 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
+
730
+ def level_arg(family, level)
731
+ case level
732
+ when Symbol, String
733
+ if Socket::Constants.const_defined?(level)
734
+ Socket::Constants.const_get(level)
735
+ else
736
+ if is_ip_family?(family)
737
+ ip_level_to_int(level)
738
+ else
739
+ unknown_level_to_int(level)
740
+ end
741
+ end
742
+ when Integer
743
+ level
744
+ else
745
+ raise SocketError, "unknown protocol level: #{level}"
746
+ end
747
+ rescue NameError
748
+ raise SocketError, "unknown protocol level: #{level}"
749
+ end
750
+
751
+ def optname_arg(level, optname)
752
+ case optname
753
+ when Symbol, String
754
+ if Socket::Constants.const_defined?(optname)
755
+ Socket::Constants.const_get(optname)
756
+ else
757
+ case(level)
758
+ when Socket::Constants::SOL_SOCKET
759
+ constant("SO", optname)
760
+ when Socket::Constants::IPPROTO_IP
761
+ constant("IP", optname)
762
+ when Socket::Constants::IPPROTO_TCP
763
+ constant("TCP", optname)
764
+ when Socket::Constants::IPPROTO_UDP
765
+ constant("UDP", optname)
766
+ else
767
+ if Socket::Constants.const_defined?(Socket::Constants::IPPROTO_IPV6) &&
768
+ level == Socket::Constants::IPPROTO_IPV6
769
+ constant("IPV6", optname)
770
+ else
771
+ optname
772
+ end
773
+ end
774
+ end
775
+ else
776
+ optname
777
+ 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
+ end
798
+
799
+ def constant(prefix, suffix)
800
+ #if Socket::Constants.const_defined?("#{prefix}_#{suffix}")
801
+ Socket::Constants.const_get("#{prefix}_#{suffix}")
802
+ #end
803
+ end
804
+ end
805
+
806
+ # If we have the details to support unix sockets, do so.
807
+ if FFI.config("sockaddr_un.sun_family.offset") and Socket::Constants.const_defined?(:AF_UNIX)
808
+ class SockAddr_Un < FFI::Struct
809
+ config("rbx.platform.sockaddr_un", :sun_family, :sun_path)
810
+
811
+ def initialize(filename = nil)
812
+ maxfnsize = self.size - (FFI.config("sockaddr_un.sun_family.size") + 1)
813
+
814
+ if filename and filename.length > maxfnsize
815
+ raise ArgumentError, "too long unix socket path (max: #{maxfnsize}bytes)"
816
+ end
817
+ @p = FFI::MemoryPointer.new self.size
818
+ if filename
819
+ @p.write_string( [Socket::AF_UNIX].pack("s") + filename )
820
+ end
821
+ super @p
822
+ end
823
+
824
+ def to_s
825
+ @p.read_string self.size
826
+ 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
+
847
+ sockaddr = Foreign.unpack_sockaddr_in ai[4], !BasicSocket.do_not_reverse_lookup
848
+
849
+ addrinfo << sockaddr.pop # port
850
+ addrinfo.concat sockaddr # hosts
851
+ addrinfo << ai[1]
852
+ addrinfo << ai[2]
853
+ addrinfo << ai[3]
854
+ addrinfo
855
+ end
856
+ end
857
+
858
+ def self.getnameinfo(sockaddr, flags = 0)
859
+ port = nil
860
+ host = nil
861
+ family = Socket::AF_UNSPEC
862
+ if sockaddr.is_a?(Array)
863
+ if sockaddr.size == 3
864
+ af = sockaddr[0]
865
+ port = sockaddr[1]
866
+ host = sockaddr[2]
867
+ elsif sockaddr.size == 4
868
+ af = sockaddr[0]
869
+ port = sockaddr[1]
870
+ host = sockaddr[3] || sockaddr[2]
871
+ else
872
+ raise ArgumentError, "array size should be 3 or 4, #{sockaddr.size} given"
873
+ end
874
+
875
+ if family == "AF_INET"
876
+ family = Socket::AF_INET
877
+ elsif family == "AF_INET6"
878
+ family = Socket::AF_INET6
879
+ end
880
+ sockaddr = Socket::Foreign.pack_sockaddr_in(host, port, family, Socket::SOCK_DGRAM, 0)
881
+ end
882
+
883
+ family, port, host, ip = Socket::Foreign.getnameinfo(sockaddr, flags)
884
+ [host, port]
885
+ end
886
+
887
+ def self.gethostname
888
+ FFI::MemoryPointer.new :char, 1024 do |mp| #magic number 1024 comes from MRI
889
+ Socket::Foreign.gethostname(mp, 1024) # same here
890
+ return mp.read_string
891
+ end
892
+ end
893
+
894
+ def self.gethostbyname(hostname)
895
+ addrinfos = Socket.getaddrinfo(hostname, nil)
896
+
897
+ hostname = addrinfos.first[2]
898
+ family = addrinfos.first[4]
899
+ addresses = []
900
+ alternatives = []
901
+ addrinfos.each do |a|
902
+ alternatives << a[2] unless a[2] == hostname
903
+ # transform addresses to packed strings
904
+ if a[4] == family
905
+ sockaddr = Socket.sockaddr_in(1, a[3])
906
+ if family == AF_INET
907
+ # IPv4 address
908
+ offset = FFI.config("sockaddr_in.sin_addr.offset")
909
+ size = FFI.config("sockaddr_in.sin_addr.size")
910
+ addresses << sockaddr.byteslice(offset, size)
911
+ elsif family == AF_INET6
912
+ # Ipv6 address
913
+ offset = FFI.config("sockaddr_in6.sin6_addr.offset")
914
+ size = FFI.config("sockaddr_in6.sin6_addr.size")
915
+ addresses << sockaddr.byteslice(offset, size)
916
+ else
917
+ addresses << a[3]
918
+ end
919
+ 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
+
929
+ def initialize(data)
930
+ @p = FFI::MemoryPointer.new data.bytesize
931
+ @p.write_string(data, data.bytesize)
932
+ super(@p)
933
+ end
934
+
935
+ def to_s
936
+ @p.read_string(size)
937
+ end
938
+
939
+ end
940
+
941
+ def self.getservbyname(service, proto='tcp')
942
+ FFI::MemoryPointer.new :char, service.length + 1 do |svc|
943
+ FFI::MemoryPointer.new :char, proto.length + 1 do |prot|
944
+ svc.write_string(service + "\0")
945
+ prot.write_string(proto + "\0")
946
+ fn = Socket::Foreign.getservbyname(svc, prot)
947
+
948
+ raise SocketError, "no such service #{service}/#{proto}" if fn.nil?
949
+
950
+ s = Servent.new(fn.read_string(Servent.size))
951
+ return Socket::Foreign.ntohs(s[:s_port])
952
+ end
953
+ end
954
+ end
955
+
956
+ def self.pack_sockaddr_in(port, host, type = Socket::SOCK_DGRAM, flags = 0)
957
+ Socket::Foreign.pack_sockaddr_in host, port, Socket::AF_UNSPEC, type, flags
958
+ end
959
+
960
+ def self.unpack_sockaddr_in(sockaddr)
961
+ host, address, port = Socket::Foreign.unpack_sockaddr_in sockaddr, false
962
+
963
+ return [port, address]
964
+ rescue SocketError => e
965
+ if e.message =~ /ai_family not supported/ then # HACK platform specific?
966
+ raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr'
967
+ else
968
+ raise e
969
+ end
970
+ end
971
+
972
+ def self.socketpair(domain, type, protocol, klass=self)
973
+ if domain.kind_of? String
974
+ if domain.prefix? "AF_" or domain.prefix? "PF_"
975
+ begin
976
+ domain = Socket::Constants.const_get(domain)
977
+ rescue NameError
978
+ raise SocketError, "unknown socket domain #{domani}"
979
+ end
980
+ else
981
+ raise SocketError, "unknown socket domain #{domani}"
982
+ end
983
+ end
984
+
985
+ type = get_socket_type(type)
986
+
987
+ FFI::MemoryPointer.new :int, 2 do |mp|
988
+ Socket::Foreign.socketpair(domain, type, protocol, mp)
989
+ fd0, fd1 = mp.read_array_of_int(2)
990
+
991
+ [ klass.from_descriptor(fd0), klass.from_descriptor(fd1) ]
992
+ end
993
+ end
994
+
995
+ class << self
996
+ alias_method :sockaddr_in, :pack_sockaddr_in
997
+ alias_method :pair, :socketpair
998
+ end
999
+
1000
+ # Only define these methods if we support unix sockets
1001
+ if self.const_defined?(:SockAddr_Un)
1002
+ def self.pack_sockaddr_un(file)
1003
+ SockAddr_Un.new(file).to_s
1004
+ end
1005
+
1006
+ def self.unpack_sockaddr_un(addr)
1007
+
1008
+ if addr.bytesize > FFI.config("sockaddr_un.sizeof")
1009
+ raise TypeError, "too long sockaddr_un - #{addr.bytesize} longer than #{FFI.config("sockaddr_un.sizeof")}"
1010
+ end
1011
+
1012
+ struct = SockAddr_Un.new
1013
+ struct.pointer.write_string(addr, addr.bytesize)
1014
+
1015
+ struct[:sun_path]
1016
+ end
1017
+
1018
+ class << self
1019
+ alias_method :sockaddr_un, :pack_sockaddr_un
1020
+ end
1021
+ end
1022
+
1023
+ def initialize(family, socket_type, protocol=0)
1024
+ @no_reverse_lookup = self.class.do_not_reverse_lookup
1025
+ family = self.class.get_protocol_family(family)
1026
+ socket_type = self.class.get_socket_type(socket_type)
1027
+ descriptor = Socket::Foreign.socket family, socket_type, protocol
1028
+
1029
+ Errno.handle 'socket(2)' if descriptor < 0
1030
+
1031
+ IO.setup self, descriptor, nil, true
1032
+ end
1033
+
1034
+ def bind(server_sockaddr)
1035
+ err = Socket::Foreign.bind(descriptor, server_sockaddr)
1036
+ Errno.handle 'bind(2)' unless err == 0
1037
+ err
1038
+ end
1039
+
1040
+ # @todo Should this be closing the descriptor? --rue
1041
+ def connect(sockaddr, extra=nil)
1042
+ if extra
1043
+ sockaddr = Socket.pack_sockaddr_in sockaddr, extra
1044
+ else
1045
+ sockaddr = StringValue(sockaddr)
1046
+ end
1047
+
1048
+ status = Socket::Foreign.connect descriptor, sockaddr
1049
+
1050
+ if status < 0
1051
+ begin
1052
+ Errno.handle "connect(2)"
1053
+ rescue Errno::EISCONN
1054
+ return 0
1055
+ end
1056
+ end
1057
+
1058
+ return 0
1059
+ end
1060
+
1061
+ def connect_nonblock(sockaddr)
1062
+ fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
1063
+
1064
+ status = Socket::Foreign.connect descriptor, StringValue(sockaddr)
1065
+ if status < 0
1066
+ Errno.handle "connect(2)"
1067
+ end
1068
+
1069
+ return status
1070
+ end
1071
+
1072
+ def self.get_protocol_family(family)
1073
+ case family
1074
+ when Fixnum
1075
+ return family
1076
+ when String
1077
+ # do nothing
1078
+ when Symbol
1079
+ family = family.to_s
1080
+ else
1081
+ family = StringValue(family)
1082
+ end
1083
+
1084
+ family = "PF_#{family}" unless family[0, 3] == "PF_"
1085
+ Socket::Constants.const_get family
1086
+ end
1087
+
1088
+ def self.get_socket_type(type)
1089
+ if type.kind_of? String
1090
+ if type.prefix? "SOCK_"
1091
+ begin
1092
+ type = Socket::Constants.const_get(type)
1093
+ rescue NameError
1094
+ raise SocketError, "unknown socket type #{type}"
1095
+ end
1096
+ else
1097
+ raise SocketError, "unknown socket type #{type}"
1098
+ end
1099
+ end
1100
+
1101
+ if type.kind_of? Symbol
1102
+ begin
1103
+ type = Socket::Constants.const_get("SOCK_#{type}")
1104
+ rescue NameError
1105
+ raise SocketError, "unknown socket type #{type}"
1106
+ end
1107
+ end
1108
+
1109
+ type
1110
+ end
1111
+ end
1112
+
1113
+ class UNIXSocket < BasicSocket
1114
+ include IO::TransferIO
1115
+
1116
+ # Coding to the lowest standard here.
1117
+ def recvfrom(bytes_read, flags = 0)
1118
+ # FIXME 2 is hardcoded knowledge from io.cpp
1119
+ socket_recv(bytes_read, flags, 2)
1120
+ end
1121
+
1122
+ def initialize(path)
1123
+ @no_reverse_lookup = self.class.do_not_reverse_lookup
1124
+ @path = path
1125
+ unix_setup
1126
+ @path = "" # Client
1127
+ end
1128
+
1129
+ def path
1130
+ unless @path
1131
+ sockaddr = Socket::Foreign.getsockname descriptor
1132
+ _, @path = sockaddr.unpack('SZ*')
1133
+ end
1134
+
1135
+ return @path
1136
+ end
1137
+
1138
+ def from_descriptor(fixnum)
1139
+ super
1140
+ @path = nil
1141
+ end
1142
+
1143
+ def unix_setup(server = false)
1144
+ status = nil
1145
+ phase = 'socket(2)'
1146
+ sock = Socket::Foreign.socket Socket::Constants::AF_UNIX, Socket::Constants::SOCK_STREAM, 0
1147
+
1148
+ Errno.handle phase if sock < 0
1149
+
1150
+ IO.setup self, sock, 'r+', true
1151
+
1152
+ sockaddr = Socket.pack_sockaddr_un(@path)
1153
+
1154
+ if server then
1155
+ phase = 'bind(2)'
1156
+ status = Socket::Foreign.bind descriptor, sockaddr
1157
+ else
1158
+ phase = 'connect(2)'
1159
+ status = Socket::Foreign.connect descriptor, sockaddr
1160
+ end
1161
+
1162
+ if status < 0 then
1163
+ close
1164
+ Errno.handle phase
1165
+ end
1166
+
1167
+ if server then
1168
+ phase = 'listen(2)'
1169
+ status = Socket::Foreign.listen descriptor, 5
1170
+ if status < 0
1171
+ close
1172
+ Errno.handle phase
1173
+ 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
+
1320
+ if status < 0
1321
+ Errno.handle syscall
1322
+ end
1323
+
1324
+ 0
1325
+ end
1326
+
1327
+ def send(message, flags, *to)
1328
+ connect *to unless to.empty?
1329
+
1330
+ bytes = message.bytesize
1331
+ bytes_sent = 0
1332
+
1333
+ FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
1334
+ buffer.write_string message, bytes
1335
+ bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
1336
+ Errno.handle 'send(2)' if bytes_sent < 0
1337
+ end
1338
+
1339
+ bytes_sent
1340
+ end
1341
+
1342
+ def inspect
1343
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{@host}:#{@port}>"
1344
+ end
1345
+
1346
+ end
1347
+
1348
+ class TCPSocket < IPSocket
1349
+ FFI = Rubinius::FFI
1350
+
1351
+ def self.gethostbyname(hostname)
1352
+ addrinfos = Socket.getaddrinfo(hostname, nil)
1353
+
1354
+ hostname = addrinfos.first[2]
1355
+ family = addrinfos.first[4]
1356
+ addresses = []
1357
+ alternatives = []
1358
+ addrinfos.each do |a|
1359
+ alternatives << a[2] unless a[2] == hostname
1360
+ addresses << a[3] if a[4] == family
1361
+ end
1362
+
1363
+ [hostname, alternatives.uniq, family] + addresses.uniq
1364
+ end
1365
+
1366
+ #
1367
+ # @todo Is it correct to ignore the to? If not, does
1368
+ # the socket need to be reconnected? --rue
1369
+ #
1370
+ def send(bytes_to_read, flags, to = nil)
1371
+ super(bytes_to_read, flags)
1372
+ end
1373
+
1374
+
1375
+ def initialize(host, port, local_host=nil, local_service=nil)
1376
+ @no_reverse_lookup = self.class.do_not_reverse_lookup
1377
+ @host = host
1378
+ @port = port
1379
+
1380
+ tcp_setup @host, @port, local_host, local_service
1381
+ end
1382
+
1383
+ def tcp_setup(remote_host, remote_service, local_host = nil,
1384
+ local_service = nil, server = false)
1385
+ status = nil
1386
+ syscall = nil
1387
+ remote_host = StringValue(remote_host) if remote_host
1388
+ if remote_service
1389
+ if remote_service.kind_of? Fixnum
1390
+ remote_service = remote_service.to_s
1391
+ else
1392
+ remote_service = StringValue(remote_service)
1393
+ end
1394
+ end
1395
+
1396
+ flags = server ? Socket::AI_PASSIVE : 0
1397
+ @remote_addrinfo = Socket::Foreign.getaddrinfo(remote_host,
1398
+ remote_service,
1399
+ Socket::AF_UNSPEC,
1400
+ Socket::SOCK_STREAM, 0,
1401
+ flags)
1402
+
1403
+ if server == false and (local_host or local_service)
1404
+ local_host = local_host.to_s if local_host
1405
+ local_service = local_service.to_s if local_service
1406
+ @local_addrinfo = Socket::Foreign.getaddrinfo(local_host,
1407
+ local_service,
1408
+ Socket::AF_UNSPEC,
1409
+ Socket::SOCK_STREAM, 0, 0)
1410
+ end
1411
+
1412
+ sock = nil
1413
+
1414
+ @remote_addrinfo.each do |addrinfo|
1415
+ flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
1416
+
1417
+ sock = Socket::Foreign.socket family, socket_type, protocol
1418
+ syscall = 'socket(2)'
1419
+
1420
+ next if sock < 0
1421
+
1422
+ if server
1423
+ FFI::MemoryPointer.new :socklen_t do |val|
1424
+ val.write_int 1
1425
+ level = Socket::Constants::SOL_SOCKET
1426
+ optname = Socket::Constants::SO_REUSEADDR
1427
+ error = Socket::Foreign.setsockopt(sock, level,
1428
+ optname, val,
1429
+ val.total)
1430
+ # Don't check error because if this fails, we just continue
1431
+ # anyway.
1432
+ end
1433
+
1434
+ status = Socket::Foreign.bind sock, sockaddr
1435
+ syscall = 'bind(2)'
1436
+ else
1437
+ if @local_addrinfo
1438
+ # Pick a local_addrinfo for the family and type of
1439
+ # the remote side
1440
+ li = @local_addrinfo.find do |i|
1441
+ i[1] == family && i[2] == socket_type
1442
+ end
1443
+
1444
+ if li
1445
+ status = Socket::Foreign.bind sock, li[4]
1446
+ syscall = 'bind(2)'
1447
+ else
1448
+ status = 1
1449
+ end
1450
+ else
1451
+ status = 1
1452
+ end
1453
+
1454
+ if status >= 0
1455
+ status = Socket::Foreign.connect sock, sockaddr
1456
+ syscall = 'connect(2)'
1457
+ end
1458
+ end
1459
+
1460
+ if status < 0
1461
+ Socket::Foreign.close sock
1462
+ else
1463
+ break
1464
+ end
1465
+ end
1466
+
1467
+ if status < 0
1468
+ Errno.handle syscall
1469
+ end
1470
+
1471
+ if server
1472
+ err = Socket::Foreign.listen sock, 5
1473
+ unless err == 0
1474
+ Socket::Foreign.close sock
1475
+ Errno.handle syscall
1476
+ end
1477
+ 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
+ end
1519
+
1520
+ end