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

KEEPALIVE_ARGUMENT_ERROR =
"delay must be an Integer".freeze
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?, #shutdown, #start_read, #stop_read, #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.



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

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.



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

def connected
  @connected
end

Instance Method Details

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



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

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 ——————




134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/libuv/tcp.rb', line 134

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



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

def close
    @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



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

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



174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/libuv/tcp.rb', line 174

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



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

alias_method :direct_write, :write

#disable_keepaliveObject



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

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

#disable_nodelayObject



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

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

#disable_simultaneous_acceptsObject



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

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



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

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

#enable_keepalive(delay) ⇒ Object



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

def enable_keepalive(delay)
    return if @closed
    assert_type(Integer, delay, KEEPALIVE_ARGUMENT_ERROR)
    check_result ::Libuv::Ext.tcp_keepalive(handle, 1, delay)
end

#enable_nodelayObject



202
203
204
205
# File 'lib/libuv/tcp.rb', line 202

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

#enable_simultaneous_acceptsObject



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

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



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

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



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

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



195
196
197
198
199
200
# File 'lib/libuv/tcp.rb', line 195

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

#socknameObject



188
189
190
191
192
193
# File 'lib/libuv/tcp.rb', line 188

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 ———————-




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

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)


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

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)


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

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



108
109
110
# File 'lib/libuv/tcp.rb', line 108

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

#write(data) ⇒ Object



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

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