rubysl-socket 1.0.1 → 2.0.0

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