PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/socket.rb

https://github.com/ethansr/rubinius
Ruby | 1147 lines | 821 code | 267 blank | 59 comment | 100 complexity | 8486bade17713f16d535db7c4d4ff853 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. require 'fcntl'
  2. class SocketError < StandardError
  3. end
  4. # @todo Socket#accept[_nonblock]
  5. # @todo UNIXServer#accept[_nonblock]
  6. # @todo UDPSocket#recvfrom
  7. class BasicSocket < IO
  8. class << self
  9. def from_descriptor(fixnum)
  10. sock = allocate()
  11. sock.from_descriptor(fixnum)
  12. return sock
  13. end
  14. alias :for_fd :from_descriptor
  15. end
  16. def from_descriptor(fixnum)
  17. IO.setup self, fixnum, nil, true
  18. return self
  19. end
  20. def self.do_not_reverse_lookup=(setting)
  21. @no_reverse_lookup = setting
  22. end
  23. def self.do_not_reverse_lookup
  24. @no_reverse_lookup ? true : false
  25. end
  26. def getsockopt(level, optname)
  27. Socket::Foreign.getsockopt descriptor, level, optname
  28. end
  29. def setsockopt(level, optname, optval)
  30. optval = 1 if optval == true
  31. optval = 0 if optval == false
  32. error = 0
  33. case optval
  34. when Fixnum then
  35. FFI::MemoryPointer.new :socklen_t do |val|
  36. val.write_int optval
  37. error = Socket::Foreign.setsockopt(descriptor, level,
  38. optname, val,
  39. val.total)
  40. end
  41. when String then
  42. FFI::MemoryPointer.new optval.size do |val|
  43. val.write_string optval
  44. error = Socket::Foreign.setsockopt(descriptor, level,
  45. optname, val,
  46. optval.size)
  47. end
  48. else
  49. raise TypeError, "socket option should be a String, a Fixnum, true, or false"
  50. end
  51. Errno.handle "Unable to set socket option" unless error == 0
  52. return 0
  53. end
  54. def getsockname()
  55. return Socket::Foreign.getsockname(descriptor)
  56. end
  57. #
  58. # Obtain peername information for this socket.
  59. #
  60. # @see Socket.getpeername
  61. #
  62. def getpeername()
  63. Socket::Foreign.getpeername @descriptor
  64. end
  65. #
  66. #
  67. #
  68. def send(message, flags, to = nil)
  69. connect to if to
  70. bytes = message.length
  71. bytes_sent = 0
  72. FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
  73. buffer.write_string message
  74. bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
  75. Errno.handle 'send(2)' if bytes_sent < 0
  76. end
  77. bytes_sent
  78. end
  79. def recvfrom(bytes_to_read, flags = 0)
  80. # FIXME 0 is knowledge from io.cpp
  81. return socket_recv(bytes_to_read, flags, 0)
  82. end
  83. def recv(bytes_to_read, flags = 0)
  84. # FIXME 0 is knowledge from io.cpp
  85. return socket_recv(bytes_to_read, flags, 0)
  86. end
  87. def close_read
  88. ensure_open
  89. # If we were only in readonly mode, close it all together
  90. if @mode & ACCMODE == RDONLY
  91. return close
  92. end
  93. # MRI doesn't check if shutdown worked, so we don't.
  94. Socket::Foreign.shutdown @descriptor, 0
  95. @mode = WRONLY
  96. nil
  97. end
  98. def close_write
  99. ensure_open
  100. # If we were only in writeonly mode, close it all together
  101. if @mode & ACCMODE == WRONLY
  102. return close
  103. end
  104. Socket::Foreign.shutdown @descriptor, 1
  105. # Mark it as read only
  106. @mode = RDONLY
  107. nil
  108. end
  109. #
  110. # Sets socket nonblocking and reads up to given number of bytes.
  111. #
  112. # @todo Should EWOULDBLOCK be passed unchanged? --rue
  113. #
  114. def recv_nonblock(bytes_to_read, flags = 0)
  115. fcntl Fcntl::F_SETFL, Fcntl::O_NONBLOCK
  116. socket_recv bytes_to_read, flags, 0
  117. rescue Errno::EWOULDBLOCK
  118. raise Errno::EAGAIN
  119. end
  120. def shutdown(how = 2)
  121. err = Socket::Foreign.shutdown @descriptor, how
  122. Errno.handle "shutdown" unless err == 0
  123. end
  124. end
  125. class Socket < BasicSocket
  126. # @todo Is omitting empty-value constants reasonable? --rue
  127. module Constants
  128. all_valid = FFI.config_hash("socket").reject {|name, value| value.empty? }
  129. all_valid.each {|name, value| const_set name, Integer(value) }
  130. # MRI compat. socket is a pretty screwed up API. All the constants in Constants
  131. # must also be directly accessible on Socket itself. This means it's not enough
  132. # to include Constants into Socket, because Socket#const_defined? must be able
  133. # to see constants like AF_INET6 directly on Socket, but #const_defined? doesn't
  134. # check inherited constants. O_o
  135. #
  136. all_valid.each {|name, value| Socket.const_set name, Integer(value) }
  137. afamilies = all_valid.to_a.select { |name,| name =~ /^AF_/ }
  138. afamilies.map! {|name, value| [value.to_i, name] }
  139. pfamilies = all_valid.to_a.select { |name,| name =~ /^PF_/ }
  140. pfamilies.map! {|name, value| [value.to_i, name] }
  141. AF_TO_FAMILY = Hash[*afamilies.flatten]
  142. PF_TO_FAMILY = Hash[*pfamilies.flatten]
  143. end
  144. module Foreign
  145. extend FFI::Library
  146. class AddrInfo < FFI::Struct
  147. config("rbx.platform.addrinfo", :ai_flags, :ai_family, :ai_socktype,
  148. :ai_protocol, :ai_addrlen, :ai_addr, :ai_canonname, :ai_next)
  149. end
  150. attach_function :_bind, "bind", [:int, :pointer, :socklen_t], :int
  151. attach_function :_connect, "connect", [:int, :pointer, :socklen_t], :int
  152. attach_function :accept, [:int, :pointer, :pointer], :int
  153. attach_function :close, [:int], :int
  154. attach_function :shutdown, [:int, :int], :int
  155. attach_function :listen, [:int, :int], :int
  156. attach_function :socket, [:int, :int, :int], :int
  157. attach_function :send, [:int, :pointer, :size_t, :int], :int
  158. attach_function :recv, [:int, :pointer, :size_t, :int], :int
  159. attach_function :recvfrom, [:int, :pointer, :size_t, :int,
  160. :pointer, :pointer], :int
  161. attach_function :_getsockopt,
  162. "getsockopt", [:int, :int, :int, :pointer, :pointer], :int
  163. attach_function :_getaddrinfo,
  164. "getaddrinfo", [:string, :string, :pointer, :pointer], :int
  165. attach_function :gai_strerror, [:int], :string
  166. attach_function :setsockopt, [:int, :int, :int, :pointer, :socklen_t], :int
  167. attach_function :freeaddrinfo, [:pointer], :void
  168. attach_function :_getpeername, "getpeername", [:int, :pointer, :pointer], :int
  169. attach_function :_getsockname, "getsockname", [:int, :pointer, :pointer], :int
  170. attach_function :socketpair, [:int, :int, :int, :pointer], :int
  171. attach_function :gethostname, [:pointer, :size_t], :int
  172. attach_function :getservbyname, [:pointer, :pointer], :pointer
  173. attach_function :htons, [:uint16_t], :uint16_t
  174. attach_function :ntohs, [:uint16_t], :uint16_t
  175. attach_function :_getnameinfo,
  176. "getnameinfo", [:pointer, :socklen_t, :pointer, :socklen_t,
  177. :pointer, :socklen_t, :int], :int
  178. def self.bind(descriptor, sockaddr)
  179. FFI::MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
  180. sockaddr_p.write_string sockaddr, sockaddr.length
  181. _bind descriptor, sockaddr_p, sockaddr.length
  182. end
  183. end
  184. def self.connect(descriptor, sockaddr)
  185. err = 0
  186. FFI::MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
  187. sockaddr_p.write_string sockaddr, sockaddr.length
  188. err = _connect descriptor, sockaddr_p, sockaddr.length
  189. end
  190. err
  191. end
  192. def self.getsockopt(descriptor, level, optname)
  193. FFI::MemoryPointer.new 256 do |val| # HACK magic number
  194. FFI::MemoryPointer.new :socklen_t do |length|
  195. length.write_int 256 # HACK magic number
  196. err = _getsockopt descriptor, level, optname, val, length
  197. Errno.handle "Unable to get socket option" unless err == 0
  198. return val.read_string(length.read_int)
  199. end
  200. end
  201. end
  202. def self.getaddrinfo(host, service = nil, family = 0, socktype = 0, protocol = 0, flags = 0)
  203. hints = AddrInfo.new
  204. hints[:ai_family] = family
  205. hints[:ai_socktype] = socktype
  206. hints[:ai_protocol] = protocol
  207. hints[:ai_flags] = flags
  208. if host && host.empty?
  209. host = "0.0.0.0"
  210. end
  211. res_p = FFI::MemoryPointer.new :pointer
  212. err = _getaddrinfo host, service, hints.pointer, res_p
  213. raise SocketError, gai_strerror(err) unless err == 0
  214. ptr = res_p.read_pointer
  215. return [] unless ptr
  216. res = AddrInfo.new ptr
  217. addrinfos = []
  218. while true
  219. addrinfo = []
  220. addrinfo << res[:ai_flags]
  221. addrinfo << res[:ai_family]
  222. addrinfo << res[:ai_socktype]
  223. addrinfo << res[:ai_protocol]
  224. addrinfo << res[:ai_addr].read_string(res[:ai_addrlen])
  225. addrinfo << res[:ai_canonname]
  226. addrinfos << addrinfo
  227. break unless res[:ai_next]
  228. res = AddrInfo.new res[:ai_next]
  229. end
  230. return addrinfos
  231. ensure
  232. hints.free if hints
  233. if res_p
  234. ptr = res_p.read_pointer
  235. # Be sure to feed a legit pointer to freeaddrinfo
  236. if ptr and !ptr.null?
  237. freeaddrinfo ptr
  238. end
  239. res_p.free
  240. end
  241. end
  242. def self.getaddress(host)
  243. addrinfos = getaddrinfo(host)
  244. unpack_sockaddr_in(addrinfos.first[4], false).first
  245. end
  246. def self.getnameinfo(sockaddr, flags = Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV,
  247. reverse_lookup = !BasicSocket.do_not_reverse_lookup)
  248. name_info = []
  249. value = nil
  250. FFI::MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
  251. FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXHOST do |node|
  252. FFI::MemoryPointer.new :char, Socket::Constants::NI_MAXSERV do |service|
  253. sockaddr_p.write_string sockaddr, sockaddr.length
  254. if reverse_lookup then
  255. err = _getnameinfo(sockaddr_p, sockaddr.length,
  256. node, Socket::Constants::NI_MAXHOST, nil, 0, 0)
  257. unless err == 0 then
  258. raise SocketError, gai_strerror(err)
  259. end
  260. name_info[2] = node.read_string
  261. end
  262. err = _getnameinfo(sockaddr_p, sockaddr.length,
  263. node, Socket::Constants::NI_MAXHOST,
  264. service, Socket::Constants::NI_MAXSERV,
  265. flags)
  266. unless err == 0 then
  267. raise SocketError, gai_strerror(err)
  268. end
  269. sa_family = SockAddr_In.new(sockaddr)[:sin_family]
  270. name_info[0] = Socket::Constants::AF_TO_FAMILY[sa_family]
  271. name_info[1] = service.read_string
  272. name_info[3] = node.read_string
  273. end
  274. end
  275. end
  276. name_info[2] = name_info[3] if name_info[2].nil?
  277. name_info
  278. end
  279. def self.getpeername(descriptor)
  280. FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
  281. FFI::MemoryPointer.new :socklen_t do |len_p|
  282. len_p.write_int 128
  283. err = _getpeername descriptor, sockaddr_storage_p, len_p
  284. Errno.handle 'getpeername(2)' unless err == 0
  285. sockaddr_storage_p.read_string len_p.read_int
  286. end
  287. end
  288. end
  289. def self.getsockname(descriptor)
  290. FFI::MemoryPointer.new :char, 128 do |sockaddr_storage_p|
  291. FFI::MemoryPointer.new :socklen_t do |len_p|
  292. len_p.write_int 128
  293. err = _getsockname descriptor, sockaddr_storage_p, len_p
  294. Errno.handle 'getsockname(2)' unless err == 0
  295. sockaddr_storage_p.read_string len_p.read_int
  296. end
  297. end
  298. end
  299. def self.pack_sockaddr_in(host, port, family, type, flags)
  300. hints = AddrInfo.new
  301. hints[:ai_family] = family
  302. hints[:ai_socktype] = type
  303. hints[:ai_flags] = flags
  304. if host && host.empty?
  305. host = "0.0.0.0"
  306. end
  307. res_p = FFI::MemoryPointer.new :pointer
  308. err = _getaddrinfo host, port.to_s, hints.pointer, res_p
  309. raise SocketError, gai_strerror(err) unless err == 0
  310. return [] if res_p.read_pointer.null?
  311. res = AddrInfo.new res_p.read_pointer
  312. return res[:ai_addr].read_string(res[:ai_addrlen])
  313. ensure
  314. hints.free if hints
  315. if res_p then
  316. ptr = res_p.read_pointer
  317. freeaddrinfo ptr if ptr and not ptr.null?
  318. res_p.free
  319. end
  320. end
  321. def self.unpack_sockaddr_in(sockaddr, reverse_lookup)
  322. family, port, host, ip = getnameinfo sockaddr, Socket::Constants::NI_NUMERICHOST | Socket::Constants::NI_NUMERICSERV, reverse_lookup
  323. # On some systems this doesn't fail for families other than AF_INET(6)
  324. # so we raise manually here.
  325. raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr' unless family =~ /AF_INET/
  326. return host, ip, port.to_i
  327. end
  328. end
  329. module ListenAndAccept
  330. include IO::Socketable
  331. def listen(backlog)
  332. backlog = Type.coerce_to backlog, Fixnum, :to_int
  333. err = Socket::Foreign.listen descriptor, backlog
  334. Errno.handle 'listen(2)' unless err == 0
  335. err
  336. end
  337. def accept
  338. return if closed?
  339. fd = super
  340. socket = self.class.superclass.allocate
  341. IO.setup socket, fd, nil, true
  342. socket
  343. end
  344. #
  345. # Set nonblocking and accept.
  346. #
  347. def accept_nonblock
  348. return if closed?
  349. fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
  350. fd = nil
  351. sockaddr = nil
  352. FFI::MemoryPointer.new 1024 do |sockaddr_p| # HACK from MRI
  353. FFI::MemoryPointer.new :int do |size_p|
  354. fd = Socket::Foreign.accept descriptor, sockaddr_p, size_p
  355. end
  356. end
  357. Errno.handle 'accept(2)' if fd < 0
  358. # TCPServer -> TCPSocket etc. *sigh*
  359. socket = self.class.superclass.allocate
  360. IO.setup socket, fd, nil, true
  361. socket
  362. end
  363. end
  364. include Socket::ListenAndAccept
  365. class SockAddr_In < FFI::Struct
  366. config("rbx.platform.sockaddr_in", :sin_family, :sin_port, :sin_addr, :sin_zero)
  367. def initialize(sockaddrin)
  368. @p = FFI::MemoryPointer.new sockaddrin.size
  369. @p.write_string(sockaddrin)
  370. super(@p)
  371. end
  372. def to_s
  373. @p.read_string(@p.total)
  374. end
  375. end
  376. # If we have the details to support unix sockets, do so.
  377. if FFI.config("sockaddr_un.sun_family.offset") and Socket::Constants.const_defined?(:AF_UNIX)
  378. class SockAddr_Un < FFI::Struct
  379. config("rbx.platform.sockaddr_un", :sun_family, :sun_path)
  380. def initialize(filename = nil)
  381. maxfnsize = self.size - (FFI.config("sockaddr_un.sun_family.size") + 1)
  382. if filename and filename.length > maxfnsize
  383. raise ArgumentError, "too long unix socket path (max: #{maxfnsize}bytes)"
  384. end
  385. @p = FFI::MemoryPointer.new self.size
  386. if filename
  387. @p.write_string( [Socket::AF_UNIX].pack("s") + filename )
  388. end
  389. super @p
  390. end
  391. def to_s
  392. @p.read_string self.size
  393. end
  394. end
  395. end
  396. def self.getaddrinfo(host, service, family = 0, socktype = 0,
  397. protocol = 0, flags = 0)
  398. if service
  399. if service.kind_of? Fixnum
  400. service = service.to_s
  401. else
  402. service = StringValue(service)
  403. end
  404. end
  405. addrinfos = Socket::Foreign.getaddrinfo(host, service, family, socktype,
  406. protocol, flags)
  407. addrinfos.map do |ai|
  408. addrinfo = []
  409. addrinfo << Socket::Constants::AF_TO_FAMILY[ai[1]]
  410. sockaddr = Foreign.unpack_sockaddr_in ai[4], !BasicSocket.do_not_reverse_lookup
  411. addrinfo << sockaddr.pop # port
  412. addrinfo.concat sockaddr # hosts
  413. addrinfo << ai[1]
  414. addrinfo << ai[2]
  415. addrinfo << ai[3]
  416. addrinfo
  417. end
  418. end
  419. def self.getnameinfo(sockaddr, flags = 0)
  420. port = nil
  421. host = nil
  422. family = Socket::AF_UNSPEC
  423. if sockaddr.is_a?(Array)
  424. if sockaddr.size == 3
  425. af = sockaddr[0]
  426. port = sockaddr[1]
  427. host = sockaddr[2]
  428. elsif sockaddr.size == 4
  429. af = sockaddr[0]
  430. port = sockaddr[1]
  431. host = sockaddr[3] || sockaddr[2]
  432. else
  433. raise ArgumentError, "array size should be 3 or 4, #{sockaddr.size} given"
  434. end
  435. if family == "AF_INET"
  436. family = Socket::AF_INET
  437. elsif family == "AF_INET6"
  438. family = Socket::AF_INET6
  439. end
  440. sockaddr = Socket::Foreign.pack_sockaddr_in(host, port, family, Socket::SOCK_DGRAM, 0)
  441. end
  442. family, port, host, ip = Socket::Foreign.getnameinfo(sockaddr, flags)
  443. [host, port]
  444. end
  445. def self.gethostname
  446. FFI::MemoryPointer.new :char, 1024 do |mp| #magic number 1024 comes from MRI
  447. Socket::Foreign.gethostname(mp, 1024) # same here
  448. return mp.read_string
  449. end
  450. end
  451. def self.gethostbyname(hostname)
  452. addrinfos = Socket.getaddrinfo(hostname, nil)
  453. hostname = addrinfos.first[2]
  454. family = addrinfos.first[4]
  455. addresses = []
  456. alternatives = []
  457. addrinfos.each do |a|
  458. alternatives << a[2] unless a[2] == hostname
  459. addresses << a[3] if a[4] == family
  460. end
  461. [hostname, alternatives.uniq, family] + addresses.uniq
  462. end
  463. class Servent < FFI::Struct
  464. config("rbx.platform.servent", :s_name, :s_aliases, :s_port, :s_proto)
  465. def initialize(data)
  466. @p = FFI::MemoryPointer.new data.size
  467. @p.write_string(data)
  468. super(@p)
  469. end
  470. def to_s
  471. @p.read_string(size)
  472. end
  473. end
  474. def self.getservbyname(service, proto='tcp')
  475. FFI::MemoryPointer.new :char, service.length + 1 do |svc|
  476. FFI::MemoryPointer.new :char, proto.length + 1 do |prot|
  477. svc.write_string(service + "\0")
  478. prot.write_string(proto + "\0")
  479. fn = Socket::Foreign.getservbyname(svc, prot)
  480. raise SocketError, "no such service #{service}/#{proto}" if fn.nil?
  481. s = Servent.new(fn.read_string(Servent.size))
  482. return Socket::Foreign.ntohs(s[:s_port])
  483. end
  484. end
  485. end
  486. def self.pack_sockaddr_in(port, host, type = Socket::SOCK_DGRAM, flags = 0)
  487. Socket::Foreign.pack_sockaddr_in host, port, Socket::AF_UNSPEC, type, flags
  488. end
  489. def self.unpack_sockaddr_in(sockaddr)
  490. host, address, port = Socket::Foreign.unpack_sockaddr_in sockaddr, false
  491. return [port, address]
  492. rescue SocketError => e
  493. if e.message =~ /ai_family not supported/ then # HACK platform specific?
  494. raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr'
  495. else
  496. raise e
  497. end
  498. end
  499. def self.socketpair(domain, type, protocol, klass=self)
  500. if domain.kind_of? String
  501. if domain.prefix? "AF_" or domain.prefix? "PF_"
  502. begin
  503. domain = Socket::Constants.const_get(domain)
  504. rescue NameError
  505. raise SocketError, "unknown socket domain #{domani}"
  506. end
  507. else
  508. raise SocketError, "unknown socket domain #{domani}"
  509. end
  510. end
  511. if type.kind_of? String
  512. if type.prefix? "SOCK_"
  513. begin
  514. type = Socket::Constants.const_get(type)
  515. rescue NameError
  516. raise SocketError, "unknown socket type #{type}"
  517. end
  518. else
  519. raise SocketError, "unknown socket type #{type}"
  520. end
  521. end
  522. FFI::MemoryPointer.new :int, 2 do |mp|
  523. Socket::Foreign.socketpair(domain, type, protocol, mp)
  524. fd0, fd1 = mp.read_array_of_int(2)
  525. [ klass.from_descriptor(fd0), klass.from_descriptor(fd1) ]
  526. end
  527. end
  528. class << self
  529. alias_method :sockaddr_in, :pack_sockaddr_in
  530. alias_method :pair, :socketpair
  531. end
  532. # Only define these methods if we support unix sockets
  533. if self.const_defined?(:SockAddr_Un)
  534. def self.pack_sockaddr_un(file)
  535. SockAddr_Un.new(file).to_s
  536. end
  537. def self.unpack_sockaddr_un(addr)
  538. if addr.length > FFI.config("sockaddr_un.sizeof")
  539. raise TypeError, "too long sockaddr_un - #{addr.length} longer than #{FFI.config("sockaddr_un.sizeof")}"
  540. end
  541. struct = SockAddr_Un.new
  542. struct.pointer.write_string(addr)
  543. struct[:sun_path]
  544. end
  545. class << self
  546. alias_method :sockaddr_un, :pack_sockaddr_un
  547. end
  548. end
  549. def initialize(family, socket_type, protocol)
  550. descriptor = Socket::Foreign.socket family, socket_type, protocol
  551. Errno.handle 'socket(2)' if descriptor < 0
  552. IO.setup self, descriptor, nil, true
  553. end
  554. def bind(server_sockaddr)
  555. err = Socket::Foreign.bind(descriptor, server_sockaddr)
  556. Errno.handle 'bind(2)' unless err == 0
  557. err
  558. end
  559. # @todo Should this be closing the descriptor? --rue
  560. def connect(sockaddr, extra=nil)
  561. if extra
  562. sockaddr = Socket.pack_sockaddr_in sockaddr, extra
  563. else
  564. sockaddr = StringValue(sockaddr)
  565. end
  566. status = Socket::Foreign.connect descriptor, sockaddr
  567. if status < 0
  568. begin
  569. Errno.handle "connect(2)"
  570. rescue Errno::EISCONN
  571. return 0
  572. end
  573. end
  574. return 0
  575. end
  576. def connect_nonblock(sockaddr)
  577. fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
  578. status = Socket::Foreign.connect descriptor, StringValue(sockaddr)
  579. if status < 0
  580. Errno.handle "connect(2)"
  581. end
  582. return status
  583. end
  584. end
  585. class UNIXSocket < BasicSocket
  586. include IO::TransferIO
  587. # Coding to the lowest standard here.
  588. def recvfrom(bytes_read, flags = 0)
  589. # FIXME 2 is hardcoded knowledge from io.cpp
  590. socket_recv(bytes_read, flags, 2)
  591. end
  592. def initialize(path)
  593. @path = path
  594. unix_setup
  595. @path = "" # Client
  596. end
  597. def path
  598. unless @path
  599. sockaddr = Socket::Foreign.getsockname descriptor
  600. _, @path = sockaddr.unpack('SZ*')
  601. end
  602. return @path
  603. end
  604. def from_descriptor(fixnum)
  605. super
  606. @path = nil
  607. end
  608. def unix_setup(server = false)
  609. status = nil
  610. phase = 'socket(2)'
  611. sock = Socket::Foreign.socket Socket::Constants::AF_UNIX, Socket::Constants::SOCK_STREAM, 0
  612. Errno.handle phase if sock < 0
  613. IO.setup self, sock, 'r+', true
  614. sockaddr = Socket.pack_sockaddr_un(@path)
  615. if server then
  616. phase = 'bind(2)'
  617. status = Socket::Foreign.bind descriptor, sockaddr
  618. else
  619. phase = 'connect(2)'
  620. status = Socket::Foreign.connect descriptor, sockaddr
  621. end
  622. if status < 0 then
  623. close
  624. Errno.handle phase
  625. end
  626. if server then
  627. phase = 'listen(2)'
  628. status = Socket::Foreign.listen descriptor, 5
  629. if status < 0
  630. close
  631. Errno.handle phase
  632. end
  633. end
  634. return sock
  635. end
  636. private :unix_setup
  637. def addr
  638. sockaddr = Socket::Foreign.getsockname descriptor
  639. _, sock_path = sockaddr.unpack('SZ*')
  640. ["AF_UNIX", sock_path]
  641. end
  642. def peeraddr
  643. sockaddr = Socket::Foreign.getpeername descriptor
  644. _, sock_path = sockaddr.unpack('SZ*')
  645. ["AF_UNIX", sock_path]
  646. end
  647. def recv_io(klass=IO, mode=nil)
  648. begin
  649. fd = recv_fd
  650. rescue PrimitiveFailure
  651. raise SocketError, "file descriptor was not passed"
  652. end
  653. return fd unless klass
  654. klass.for_fd(fd, mode)
  655. end
  656. class << self
  657. def socketpair(type=Socket::SOCK_STREAM, protocol=0)
  658. Socket.socketpair(Socket::PF_UNIX, type, protocol, self)
  659. end
  660. alias_method :pair, :socketpair
  661. end
  662. end
  663. class UNIXServer < UNIXSocket
  664. include Socket::ListenAndAccept
  665. def initialize(path)
  666. @path = path
  667. unix_setup(true)
  668. end
  669. end
  670. class IPSocket < BasicSocket
  671. def self.getaddress(host)
  672. Socket::Foreign.getaddress host
  673. end
  674. def addr
  675. sockaddr = Socket::Foreign.getsockname descriptor
  676. family, port, host, ip = Socket::Foreign.getnameinfo sockaddr
  677. [family, port.to_i, host, ip]
  678. end
  679. def peeraddr
  680. sockaddr = Socket::Foreign.getpeername descriptor
  681. family, port, host, ip = Socket::Foreign.getnameinfo sockaddr
  682. [family, port.to_i, host, ip]
  683. end
  684. def recvfrom(maxlen, flags = 0)
  685. # FIXME 1 is hardcoded knowledge from io.cpp
  686. socket_recv maxlen, flags, 1
  687. end
  688. def recvfrom_nonblock(maxlen, flags = 0)
  689. # Set socket to non-blocking, if we can
  690. # Todo: Ensure this works in Windows! If not, I claim that's Fcntl's fault.
  691. fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
  692. # Wait until we have something to read
  693. # @todo Why? ^^ --rue
  694. IO.select([self])
  695. return recvfrom(maxlen, flags)
  696. end
  697. end
  698. class UDPSocket < IPSocket
  699. def initialize(socktype = Socket::AF_INET)
  700. @socktype = socktype
  701. status = Socket::Foreign.socket @socktype,
  702. Socket::SOCK_DGRAM,
  703. Socket::IPPROTO_UDP
  704. Errno.handle 'socket(2)' if status < 0
  705. IO.setup self, status, nil, true
  706. end
  707. def bind(host, port)
  708. @host = host.to_s if host
  709. @port = port.to_s if port
  710. addrinfos = Socket::Foreign.getaddrinfo(@host,
  711. @port,
  712. @socktype,
  713. Socket::SOCK_DGRAM, 0,
  714. Socket::AI_PASSIVE)
  715. status = -1
  716. addrinfos.each do |addrinfo|
  717. flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
  718. status = Socket::Foreign.bind descriptor, sockaddr
  719. break if status >= 0
  720. end
  721. if status < 0
  722. Errno.handle 'bind(2)'
  723. end
  724. status
  725. end
  726. def connect(host, port)
  727. sockaddr = Socket::Foreign.pack_sockaddr_in host, port, @socktype, Socket::SOCK_DGRAM, 0
  728. syscall = 'connect(2)'
  729. status = Socket::Foreign.connect descriptor, sockaddr
  730. if status < 0
  731. Errno.handle syscall
  732. end
  733. 0
  734. end
  735. def send(message, flags, *to)
  736. connect *to unless to.empty?
  737. bytes = message.length
  738. bytes_sent = 0
  739. FFI::MemoryPointer.new :char, bytes + 1 do |buffer|
  740. buffer.write_string message
  741. bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
  742. Errno.handle 'send(2)' if bytes_sent < 0
  743. end
  744. bytes_sent
  745. end
  746. def inspect
  747. "#<#{self.class}:0x#{object_id.to_s(16)} #{@host}:#{@port}>"
  748. end
  749. end
  750. class TCPSocket < IPSocket
  751. def self.gethostbyname(hostname)
  752. addrinfos = Socket.getaddrinfo(hostname, nil)
  753. hostname = addrinfos.first[2]
  754. family = addrinfos.first[4]
  755. addresses = []
  756. alternatives = []
  757. addrinfos.each do |a|
  758. alternatives << a[2] unless a[2] == hostname
  759. addresses << a[3] if a[4] == family
  760. end
  761. [hostname, alternatives.uniq, family] + addresses.uniq
  762. end
  763. #
  764. # @todo Is it correct to ignore the to? If not, does
  765. # the socket need to be reconnected? --rue
  766. #
  767. def send(bytes_to_read, flags, to = nil)
  768. super(bytes_to_read, flags)
  769. end
  770. def initialize(host, port, local_host=nil, local_service=nil)
  771. @host = host
  772. @port = port
  773. tcp_setup @host, @port, local_host, local_service
  774. end
  775. def tcp_setup(remote_host, remote_service, local_host = nil,
  776. local_service = nil, server = false)
  777. status = nil
  778. syscall = nil
  779. remote_host = remote_host.to_s if remote_host
  780. remote_service = remote_service.to_s if remote_service
  781. flags = server ? Socket::AI_PASSIVE : 0
  782. @remote_addrinfo = Socket::Foreign.getaddrinfo(remote_host,
  783. remote_service,
  784. Socket::AF_UNSPEC,
  785. Socket::SOCK_STREAM, 0,
  786. flags)
  787. if server == false and (local_host or local_service)
  788. local_host = local_host.to_s if local_host
  789. local_service = local_service.to_s if local_service
  790. @local_addrinfo = Socket::Foreign.getaddrinfo(local_host,
  791. local_service,
  792. Socket::AF_UNSPEC,
  793. Socket::SOCK_STREAM, 0, 0)
  794. end
  795. sock = nil
  796. @remote_addrinfo.each do |addrinfo|
  797. flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
  798. sock = Socket::Foreign.socket family, socket_type, protocol
  799. syscall = 'socket(2)'
  800. next if sock < 0
  801. if server
  802. FFI::MemoryPointer.new :socklen_t do |val|
  803. val.write_int 1
  804. level = Socket::Constants::SOL_SOCKET
  805. optname = Socket::Constants::SO_REUSEADDR
  806. error = Socket::Foreign.setsockopt(sock, level,
  807. optname, val,
  808. val.total)
  809. # Don't check error because if this fails, we just continue
  810. # anyway.
  811. end
  812. status = Socket::Foreign.bind sock, sockaddr
  813. syscall = 'bind(2)'
  814. else
  815. if @local_addrinfo
  816. # Pick a local_addrinfo for the family and type of
  817. # the remote side
  818. li = @local_addrinfo.find do |i|
  819. i[1] == family && i[2] == socket_type
  820. end
  821. if li
  822. status = Socket::Foreign.bind sock, li[4]
  823. syscall = 'bind(2)'
  824. else
  825. status = 1
  826. end
  827. else
  828. status = 1
  829. end
  830. if status >= 0
  831. status = Socket::Foreign.connect sock, sockaddr
  832. syscall = 'connect(2)'
  833. end
  834. end
  835. if status < 0
  836. Socket::Foreign.close sock
  837. else
  838. break
  839. end
  840. end
  841. if status < 0
  842. Errno.handle syscall
  843. end
  844. if server
  845. err = Socket::Foreign.listen sock, 5
  846. unless err == 0
  847. Socket::Foreign.close sock
  848. Errno.handle syscall
  849. end
  850. end
  851. # Only setup once we have found a socket we can use. Otherwise
  852. # because we manually close a socket fd, we can create an IO fd
  853. # alias condition which causes EBADF because when an IO is finalized
  854. # and it's fd has been closed underneith it, we close someone elses
  855. # fd!
  856. IO.setup self, sock, nil, true
  857. end
  858. private :tcp_setup
  859. def from_descriptor(descriptor)
  860. IO.setup self, descriptor, nil, true
  861. self
  862. end
  863. end
  864. class TCPServer < TCPSocket
  865. include Socket::ListenAndAccept
  866. def initialize(host, port = nil)
  867. if Fixnum === host and port.nil? then
  868. port = host
  869. host = nil
  870. end
  871. if String === host and port.nil? then
  872. port = Integer(host)
  873. host = nil
  874. end
  875. port = StringValue port unless port.kind_of? Fixnum
  876. @host = host
  877. @port = port
  878. tcp_setup @host, @port, nil, nil, true
  879. end
  880. end