Class: Libuv::TCP

Inherits:
Handle show all
Includes:
Net, Stream
Defined in:
lib/libuv/tcp.rb

Defined Under Namespace

Classes: Socket4, Socket6, SocketBase

Constant Summary collapse

TLS_ERROR =
"TLS write failed".freeze

Constants included from Stream

Stream::BACKLOG_ERROR, Stream::CLOSED_HANDLE_ERROR, Stream::STREAM_CLOSED_ERROR, Stream::WRITE_ERROR

Constants included from Net

Net::INET6_ADDRSTRLEN, Net::INET_ADDRSTRLEN, Net::IP_ARGUMENT_ERROR, Net::PORT_ARGUMENT_ERROR

Constants included from Assertions

Assertions::MSG_NO_PROC

Constants inherited from Q::Promise

Q::Promise::MAKE_PROMISE

Instance Attribute Summary collapse

Attributes inherited from Handle

#closed, #loop, #storage

Instance Method Summary collapse

Methods included from Stream

#listen, #progress, #readable?, #start_read, #stop_read, #try_write, #writable?

Methods inherited from Handle

#active?, #closing?, #ref, #unref

Methods included from Assertions

#assert_block, #assert_boolean, #assert_type

Methods included from Resource

#check_result, #check_result!, #resolve, #to_ptr

Methods inherited from Q::DeferredPromise

#resolved?, #then

Methods inherited from Q::Promise

#catch, #finally, #progress

Constructor Details

#initialize(loop, acceptor = nil) ⇒ TCP

Returns a new instance of TCP.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/libuv/tcp.rb', line 18

def initialize(loop, acceptor = nil)
    @loop = loop

    tcp_ptr = ::Libuv::Ext.create_handle(:uv_tcp)
    error = check_result(::Libuv::Ext.tcp_init(loop.handle, tcp_ptr))

    if acceptor && error.nil?
        error = check_result(::Libuv::Ext.accept(acceptor, tcp_ptr))
        @connected = true
    else
        @connected = false
    end
    
    super(tcp_ptr, error)
end

Instance Attribute Details

#connectedObject (readonly)

Returns the value of attribute connected.



13
14
15
# File 'lib/libuv/tcp.rb', line 13

def connected
  @connected
end

Instance Method Details

#accept(callback = nil, &blk) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/libuv/tcp.rb', line 170

def accept(callback = nil, &blk)
    begin
        raise RuntimeError, CLOSED_HANDLE_ERROR if @closed
        tcp = TCP.new(loop, handle)
        begin
            (callback || blk).call(tcp)
        rescue Exception => e
            @loop.log :error, :tcp_accept_cb, e
        end
    rescue Exception => e
        @loop.log :info, :tcp_accept_failed, e
    end
    nil
end

#bind(ip, port, callback = nil, &blk) ⇒ Object

END TLS Abstraction ——————




145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/libuv/tcp.rb', line 145

def bind(ip, port, callback = nil, &blk)
    return if @closed
    @on_listen = callback || blk
    assert_type(String, ip, IP_ARGUMENT_ERROR)
    assert_type(Integer, port, PORT_ARGUMENT_ERROR)

    begin
        @tcp_socket = create_socket(IPAddr.new(ip), port)
        @tcp_socket.bind
    rescue Exception => e
        reject(e)
    end
end

#closeObject

overwrite the default close to ensure pending writes are rejected



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/libuv/tcp.rb', line 93

def close
    return if @closed

    @tls.cleanup if @tls  # Free tls memory
    @connected = false

    if not @pending_writes.nil?
        @pending_writes.each do |deferred, data|
            deferred.reject(TLS_ERROR)
        end
        @pending_writes = nil
    end

    super
end

#close_cbObject

Close can be called multiple times



81
82
83
84
85
86
87
88
89
# File 'lib/libuv/tcp.rb', line 81

def close_cb
    if not @pending_write.nil?
        @pending_write.reject(TLS_ERROR)
        @pending_write = nil
    end

    # Shutdown the stream
    close
end

#connect(ip, port, callback = nil, &blk) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/libuv/tcp.rb', line 185

def connect(ip, port, callback = nil, &blk)
    return if @closed
    @callback = callback || blk
    assert_type(String, ip, IP_ARGUMENT_ERROR)
    assert_type(Integer, port, PORT_ARGUMENT_ERROR)
    
    begin
        @tcp_socket = create_socket(IPAddr.new(ip), port)
        @tcp_socket.connect(callback(:on_connect))
    rescue Exception => e
        reject(e)
    end
end

#direct_writeObject



114
# File 'lib/libuv/tcp.rb', line 114

alias_method :direct_write, :write

#disable_keepaliveObject



228
229
230
231
# File 'lib/libuv/tcp.rb', line 228

def disable_keepalive
    return if @closed
    check_result ::Libuv::Ext.tcp_keepalive(handle, 0, 0)
end

#disable_nodelayObject



218
219
220
221
# File 'lib/libuv/tcp.rb', line 218

def disable_nodelay
    return if @closed
    check_result ::Libuv::Ext.tcp_nodelay(handle, 0)
end

#disable_simultaneous_acceptsObject



238
239
240
241
# File 'lib/libuv/tcp.rb', line 238

def disable_simultaneous_accepts
    return if @closed
    check_result ::Libuv::Ext.tcp_simultaneous_accepts(handle, 0)
end

#dispatch_cb(data) ⇒ Object

This is clear text data that has been decrypted Same as stream.rb on_read for clear text



61
62
63
64
65
66
67
# File 'lib/libuv/tcp.rb', line 61

def dispatch_cb(data)
    begin
        @progress.call data, self
    rescue Exception => e
        @loop.log :error, :stream_progress_cb, e
    end
end

#do_shutdownObject



132
# File 'lib/libuv/tcp.rb', line 132

alias_method :do_shutdown, :shutdown

#enable_keepalive(delay) ⇒ Object



223
224
225
226
# File 'lib/libuv/tcp.rb', line 223

def enable_keepalive(delay)
    return if @closed                   # The to_i asserts integer
    check_result ::Libuv::Ext.tcp_keepalive(handle, 1, delay.to_i)
end

#enable_nodelayObject



213
214
215
216
# File 'lib/libuv/tcp.rb', line 213

def enable_nodelay
    return if @closed
    check_result ::Libuv::Ext.tcp_nodelay(handle, 1)
end

#enable_simultaneous_acceptsObject



233
234
235
236
# File 'lib/libuv/tcp.rb', line 233

def enable_simultaneous_accepts
    return if @closed
    check_result ::Libuv::Ext.tcp_simultaneous_accepts(handle, 1)
end

#handshake_cbObject

Push through any pending writes when handshake has completed



49
50
51
52
53
54
55
56
57
# File 'lib/libuv/tcp.rb', line 49

def handshake_cb
    @handshake = true
    writes = @pending_writes
    @pending_writes = nil
    writes.each do |deferred, data|
        @pending_write = deferred
        @tls.encrypt(data)
    end
end

#open(fd, binding = true, callback = nil, &blk) ⇒ Object



159
160
161
162
163
164
165
166
167
168
# File 'lib/libuv/tcp.rb', line 159

def open(fd, binding = true, callback = nil, &blk)
    return if @closed
    if binding
        @on_listen = callback || blk
    else
        @callback = callback || blk
    end
    error = check_result UV.tcp_open(handle, fd)
    reject(error) if error
end

#peernameObject



206
207
208
209
210
211
# File 'lib/libuv/tcp.rb', line 206

def peername
    return [] if @closed
    sockaddr, len = get_sockaddr_and_len
    check_result! ::Libuv::Ext.tcp_getpeername(handle, sockaddr, len)
    get_ip_and_port(::Libuv::Ext::Sockaddr.new(sockaddr), len.get_int(0))
end

#shutdownObject



133
134
135
136
137
138
139
# File 'lib/libuv/tcp.rb', line 133

def shutdown
    if @pending_writes && @pending_writes.length > 0
        @pending_writes[-1][0].finally method(:do_shutdown)
    else
        do_shutdown
    end
end

#socknameObject



199
200
201
202
203
204
# File 'lib/libuv/tcp.rb', line 199

def sockname
    return [] if @closed
    sockaddr, len = get_sockaddr_and_len
    check_result! ::Libuv::Ext.tcp_getsockname(handle, sockaddr, len)
    get_ip_and_port(::Libuv::Ext::Sockaddr.new(sockaddr), len.get_int(0))
end

#start_tls(args = {}) ⇒ Object

TLS Abstraction ———————-




39
40
41
42
43
44
45
46
# File 'lib/libuv/tcp.rb', line 39

def start_tls(args = {})
    return unless @connected && @tls.nil?

    @handshake = false
    @pending_writes = []
    @tls = ::RubyTls::Connection.new(self)
    @tls.start(args)
end

#tls?Boolean

Check if tls active on the socket

Returns:

  • (Boolean)


15
# File 'lib/libuv/tcp.rb', line 15

def tls?; !@tls.nil?; end

#transmit_cb(data) ⇒ Object

We resolve the existing tls write promise with a the

real writes promise (a close may have occurred)


71
72
73
74
75
76
77
78
# File 'lib/libuv/tcp.rb', line 71

def transmit_cb(data)
    if not @pending_write.nil?
        @pending_write.resolve(direct_write(data))
        @pending_write = nil
    else
        direct_write(data)
    end
end

#verify_peer(&block) ⇒ Object

Verify peers will be called for each cert in the chain



110
111
112
# File 'lib/libuv/tcp.rb', line 110

def verify_peer(&block)
    @tls.verify_cb &block
end

#write(data) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/libuv/tcp.rb', line 115

def write(data)
    if @tls.nil?
        direct_write(data)
    else
        deferred = @loop.defer
        
        if @handshake == true
            @pending_write = deferred
            @tls.encrypt(data)
        else
            @pending_writes << [deferred, data]
        end

        deferred.promise
    end
end