Class: TCPSocket

Inherits:
IPSocket show all
Defined in:
lib/socket/tcp_socket.rb

Direct Known Subclasses

TCPServer

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from IPSocket

#addr, getaddress, #peeraddr, #recvfrom

Methods inherited from BasicSocket

#close_read, #close_write, #connect_address, do_not_reverse_lookup, #do_not_reverse_lookup, do_not_reverse_lookup=, #do_not_reverse_lookup=, for_fd, #getpeereid, #getpeername, #getsockname, #getsockopt, #recv, #recv_nonblock, #recvmsg, #recvmsg_nonblock, #send, #sendmsg, #sendmsg_nonblock, #setsockopt, #shutdown

Constructor Details

#initialize(host, service, local_host = nil, local_service = nil) ⇒ TCPSocket

Returns a new instance of TCPSocket.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/socket/tcp_socket.rb', line 18

def initialize(host, service, local_host = nil, local_service = nil)
  @no_reverse_lookup = self.class.do_not_reverse_lookup

  if host
    host = RubySL::Socket.coerce_to_string(host)
  end

  if service.is_a?(Fixnum)
    service = service.to_s
  else
    service = RubySL::Socket.coerce_to_string(service)
  end

  local_addrinfo = nil

  # When a local address and/or service/port are given we should bind the
  # socket to said address (besides also connecting to the remote address).
  if local_host or local_service
    if local_host
      local_host = RubySL::Socket.coerce_to_string(local_host)
    end

    if local_service.is_a?(Fixnum)
      local_service = local_service.to_s
    elsif local_service
      local_service = RubySL::Socket.coerce_to_string(local_service)
    end

    local_addrinfo = Socket
      .getaddrinfo(local_host, local_service, :UNSPEC, :STREAM)
  end

  descriptor     = nil
  connect_status = 0

  # Because we don't know exactly what address family to bind to we'll just
  # grab all the available ones and try every one of them, bailing out on the
  # first address that we can connect to.
  #
  # This code is loosely based on the behaviour of CRuby's
  # "init_inetsock_internal()" function as of Ruby 2.2.
  Socket.getaddrinfo(host, service, :UNSPEC, :STREAM).each do |addrinfo|
    _, port, address, _, family, socktype, protocol = addrinfo

    descriptor = RubySL::Socket::Foreign.socket(family, socktype, protocol)

    next if descriptor < 0

    # If any local address details were given we should bind to one that
    # matches the remote address connected to above.
    if local_addrinfo
      local_info = local_addrinfo.find do |addr|
        addr[4] == family && addr[5] == socktype
      end

      if local_info
        status = RubySL::Socket::Foreign
          .bind(descriptor, Socket.sockaddr_in(local_info[1], local_info[2]))

        Errno.handle('bind(2)') if status < 0
      end
    end

    connect_status = RubySL::Socket::Foreign
      .connect(descriptor, Socket.sockaddr_in(port, address))

    break if connect_status >= 0
  end

  if connect_status < 0
    RubySL::Socket::Foreign.close(descriptor)

    Errno.handle('connect(2)')
  else
    IO.setup(self, descriptor, nil, true)
    binmode
  end
end

Class Method Details

.gethostbyname(hostname) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/socket/tcp_socket.rb', line 2

def self.gethostbyname(hostname)
  addrinfos = Socket
    .getaddrinfo(hostname, nil, nil, :STREAM, nil, Socket::AI_CANONNAME)

  hostname     = addrinfos[0][2]
  family       = addrinfos[0][4]
  addresses    = addrinfos.map { |a| a[3] }
  alternatives = []

  RubySL::Socket.aliases_for_hostname(hostname).each do |name|
    alternatives << name unless name == hostname
  end

  [hostname, alternatives, family, *addresses]
end

Instance Method Details

#local_addressObject



97
98
99
100
101
102
# File 'lib/socket/tcp_socket.rb', line 97

def local_address
  address  = addr
  sockaddr = Socket.pack_sockaddr_in(address[1], address[3])

  Addrinfo.new(sockaddr, address[0], :STREAM)
end

#remote_addressObject



104
105
106
107
108
109
# File 'lib/socket/tcp_socket.rb', line 104

def remote_address
  address  = peeraddr
  sockaddr = Socket.pack_sockaddr_in(address[1], address[3])

  Addrinfo.new(sockaddr, address[0], :STREAM)
end