tcp-client 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe13751730310529097b79992b58a5ed212ecc4119c576c04bcf7b0c4a0373c7
4
- data.tar.gz: 558f73ee8e06309c8d6ca52cdc4309ceac853a9587b6891959b67f5d49c89413
3
+ metadata.gz: e88146d7f1f966d6c9e7dce6a876c17dca7383ee88eb76a8e5caf36076a03720
4
+ data.tar.gz: 493d8cbf748789df4efd0301679082023c140f23dbc2a3d52ccfcf8d71a4a1b4
5
5
  SHA512:
6
- metadata.gz: a2a9d54d6de01896b83180e7e94afde9a1e2b8f62ca24c9e91d63a7c809a06286357fdecb5a3ad6fce1dceaaa50067a6f64263c83f4069d07b3ad837db138b9d
7
- data.tar.gz: ac6168903ebb5c953e850fb97d80281c63b70b208335d34611f57829199e623fac3fbea85959d09d8c9ddec1edbe23ffef23cd9e5e94e788b74b0ded665dd5c2
6
+ metadata.gz: 070ba42a0a185a67ae1ac4d1912220ab0aa297a6cdc4147d3afaf8593129f3b25da2ecad7a8569651c6d54dd1ba11c7705ebf8bcc1def2d525388025b45d12b3
7
+ data.tar.gz: 4c34127d89744a537d5b64c578ac4c1e2121c27e9412208f7c0abcf74999bb1e85c1c246bebfea83401c8caaf4c472daee7ff5e599989632076784881131b3ea
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --readme README.md
2
+ --title 'tcp-client Documentation'
3
+ --charset utf-8
4
+ --markup markdown
5
+ 'lib/**/*.rb' - 'LICENSE'
data/README.md CHANGED
@@ -2,16 +2,14 @@
2
2
 
3
3
  A TCP client implementation with working timeout support.
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/tcp-client.svg)](https://badge.fury.io/rb/tcp-client)
5
+ - Gem: [rubygems.org](https://rubygems.org/gems/tcp-client)
6
+ - Source: [github.com](https://github.com/mblumtritt/tcp-client)
7
+ - Help: [rubydoc.info](https://rubydoc.info/github/mblumtritt/tcp-client/main/index)
6
8
 
7
9
  ## Description
8
10
 
9
11
  This Gem implements a TCP client with (optional) SSL support. It is an easy to use, versatile configurable client that can correctly handle time limits. Unlike other implementations, this client respects predefined/configurable time limits for each method (`connect`, `read`, `write`). Deadlines for a sequence of read/write actions can also be monitored.
10
12
 
11
- ## Help
12
-
13
- The latest help can be found at [rubydoc.info](https://rubydoc.info/github/mblumtritt/tcp-client/main/index)
14
-
15
13
  ## Sample
16
14
 
17
15
  ```ruby
@@ -29,11 +27,14 @@ cfg = TCPClient::Configuration.create(
29
27
  # - limit all network interactions to 1.5 seconds
30
28
  # - use the Configuration cfg
31
29
  # - send a simple HTTP get request
32
- # - read 12 byte: "HTTP/1.1 " + 3 byte HTTP status code
33
- TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
34
- client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") # >= 40
35
- client.read(12) # => "HTTP/1.1 200"
36
- end
30
+ # - read the returned message and headers
31
+ response =
32
+ TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
33
+ client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") #=> 40
34
+ client.readline("\r\n\r\n") #=> see response
35
+ end
36
+
37
+ puts(response)
37
38
  ```
38
39
 
39
40
  For more samples see [the samples dir](https://github.com/mblumtritt/tcp-client/tree/main/sample)
data/gems.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source('https://rubygems.org') { gemspec }
3
+ source 'https://rubygems.org'
4
+ gemspec
@@ -21,23 +21,30 @@ class TCPClient
21
21
  # Initializes an address
22
22
  # @overload initialize(addr)
23
23
  # The addr can be specified as
24
- # - a valid named address containing the port like "my.host.test:80"
25
- # - a valid TCPv4 address like "142.250.181.206:80"
26
- # - a valid TCPv6 address like "[2001:16b8:5093:3500:ad77:abe6:eb88:47b6]:80"
27
24
  #
28
- # @param addr [String] address string
25
+ # - a valid named address containing the port like "my.host.test:80"
26
+ # - a valid TCPv4 address like "142.250.181.206:80"
27
+ # - a valid TCPv6 address like
28
+ # "[2001:16b8:5093:3500:ad77:abe6:eb88:47b6]:80"
29
29
  #
30
- # @overload initialize(address)
31
- # Used to create a copy
30
+ # @example create an Address instance with a host name and port
31
+ # Address.new('www.google.com:80')
32
+ #
33
+ # @param addr [String] address containing host and port name
32
34
  #
33
- # @param address [Address]
34
35
  #
35
36
  # @overload initialize(addrinfo)
36
37
  #
38
+ # @example create an Address with an Addrinfo
39
+ # Address.new(Addrinfo.tcp('www.google.com', 'http'))
40
+ #
37
41
  # @param addrinfo [Addrinfo] containing the addressed host and port
38
42
  #
39
43
  # @overload initialize(port)
40
- # Adresses the port on the local machine.
44
+ # Addresses the port on the local machine.
45
+ #
46
+ # @example create an Address for localhost on port 80
47
+ # Address.new(80)
41
48
  #
42
49
  # @param port [Integer] the addressed port
43
50
  #
@@ -56,18 +63,27 @@ class TCPClient
56
63
  end
57
64
 
58
65
  #
59
- # @return [String] text representation of self as "<host>:<port>"
66
+ # @attribute [r] port
67
+ # @return [Integer] the port number
68
+ #
69
+ def port
70
+ @addrinfo.ip_port
71
+ end
72
+
73
+ #
74
+ # @return [String] text representation of self as "host:port"
60
75
  #
61
76
  def to_s
62
- return "[#{@hostname}]:#{@addrinfo.ip_port}" if @hostname.index(':') # IP6
63
- "#{@hostname}:#{@addrinfo.ip_port}"
77
+ hostname.index(':') ? "[#{hostname}]:#{port}" : "#{hostname}:#{port}"
64
78
  end
65
79
 
66
80
  #
67
- # @return [Hash] containing the host and port
81
+ # Convert `self` to a Hash containing host and port attribute.
82
+ #
83
+ # @return [Hash] host and port
68
84
  #
69
85
  def to_h
70
- { host: @hostname, port: @addrinfo.ip_port }
86
+ { host: hostname, port: port }
71
87
  end
72
88
 
73
89
  # @!visibility private
@@ -89,7 +105,7 @@ class TCPClient
89
105
  end
90
106
 
91
107
  def init_from_addrinfo(addrinfo)
92
- @hostname, _port = addrinfo.getnameinfo(Socket::NI_NUMERICSERV)
108
+ @hostname = addrinfo.getnameinfo(Socket::NI_NUMERICSERV).first
93
109
  @addrinfo = addrinfo
94
110
  end
95
111
 
@@ -102,7 +118,7 @@ class TCPClient
102
118
  def from_string(str)
103
119
  idx = str.rindex(':') or return nil, str.to_i
104
120
  name = str[0, idx].delete_prefix('[').delete_suffix(']')
105
- [name, str[idx + 1, str.size - idx].to_i]
121
+ [name.empty? ? nil : name, str[idx + 1, str.size - idx].to_i]
106
122
  end
107
123
  end
108
124
  end
@@ -6,55 +6,55 @@ class TCPClient
6
6
  #
7
7
  # A Configuration is used to configure the behavior of a {TCPClient} instance.
8
8
  #
9
- # It allows to specify to monitor timeout, how to handle exceptions, if SSL
9
+ # It allows to specify the monitor timeout, how to handle exceptions, if SSL
10
10
  # should be used and to setup the underlying Socket.
11
11
  #
12
12
  class Configuration
13
13
  #
14
- # @overload create(options)
15
- # Shorthand to create a new configuration with given options.
16
- #
17
- # @example
18
- # config = TCPClient::Configuration.create(buffered: false)
19
- #
20
- # @param options [Hash] see {#initialize} for details
21
- #
22
- # @return [Configuration] the initialized configuration
23
- #
24
- # @overload create(&block)
25
- # Shorthand to initialize a new configuration.
14
+ # Shorthand to create a new configuration.
26
15
  #
16
+ # @overload create()
27
17
  # @example
28
18
  # config = TCPClient::Configuration.create do |cfg|
29
19
  # cfg.buffered = false
30
20
  # cfg.ssl_params = { min_version: :TLS1_2, max_version: :TLS1_3 }
31
21
  # end
32
22
  #
33
- # @yieldparam cfg {Configuration}
23
+ # @yieldparam configuration {Configuration}
34
24
  #
35
- # @return [Configuration] the initialized configuration
25
+ # @overload create(options)
26
+ # @example
27
+ # config = TCPClient::Configuration.create(buffered: false)
28
+ #
29
+ # @param options [{Symbol => Object}] see {#initialize} for details
30
+ #
31
+ # @return [Configuration] the initialized configuration
36
32
  #
37
33
  def self.create(options = {})
38
- cfg = new(options)
39
- yield(cfg) if block_given?
40
- cfg
34
+ configuration = new(options)
35
+ yield(configuration) if block_given?
36
+ configuration
41
37
  end
42
38
 
43
39
  #
44
- # Intializes the instance with given options.
40
+ # Initializes the instance with given options.
45
41
  #
46
- # @param options [Hash]
42
+ # @param options [{Symbol => Object}]
47
43
  # @option options [Boolean] :buffered, see {#buffered}
48
44
  # @option options [Boolean] :keep_alive, see {#keep_alive}
49
45
  # @option options [Boolean] :reverse_lookup, see {#reverse_lookup}
50
- # @option options [Boolean] :normalize_network_errors, see {#normalize_network_errors}
46
+ # @option options [{Symbol => Object}] :ssl_params, see {#ssl_params}
51
47
  # @option options [Numeric] :connect_timeout, see {#connect_timeout}
52
- # @option options [Exception] :connect_timeout_error, see {#connect_timeout_error}
48
+ # @option options [Class<Exception>] :connect_timeout_error, see
49
+ # {#connect_timeout_error}
53
50
  # @option options [Numeric] :read_timeout, see {#read_timeout}
54
- # @option options [Exception] :read_timeout_error, see {#read_timeout_error}
51
+ # @option options [Class<Exception>] :read_timeout_error, see
52
+ # {#read_timeout_error}
55
53
  # @option options [Numeric] :write_timeout, see {#write_timeout}
56
- # @option options [Exception] :write_timeout_error, see {#write_timeout_error}
57
- # @option options [Hash<Symbol, Object>] :ssl_params, see {#ssl_params}
54
+ # @option options [Class<Exception>] :write_timeout_error, see
55
+ # {#write_timeout_error}
56
+ # @option options [Boolean] :normalize_network_errors, see
57
+ # {#normalize_network_errors}
58
58
  #
59
59
  def initialize(options = {})
60
60
  @buffered = @keep_alive = @reverse_lookup = true
@@ -66,11 +66,13 @@ class TCPClient
66
66
  options.each_pair { |attribute, value| set(attribute, value) }
67
67
  end
68
68
 
69
+ # @!group Instance Attributes Socket Level
70
+
69
71
  #
70
- # Enables/disables use of Socket-level buffers.
72
+ # Enables/disables use of Socket-level buffering
71
73
  #
72
- # @return [true] if the connection is allowed to use internal buffers (default)
73
- # @return [false] if buffering is not allowed
74
+ # @return [Boolean] whether the connection is allowed to use internal
75
+ # buffers (default) or not
74
76
  #
75
77
  attr_reader :buffered
76
78
 
@@ -81,8 +83,8 @@ class TCPClient
81
83
  #
82
84
  # Enables/disables use of Socket-level keep alive handling.
83
85
  #
84
- # @return [true] if the connection is allowed to use keep alive signals (default)
85
- # @return [false] if the connection should not check keep alive
86
+ # @return [Boolean] whether the connection is allowed to use keep alive
87
+ # signals (default) or not
86
88
  #
87
89
  attr_reader :keep_alive
88
90
 
@@ -93,8 +95,8 @@ class TCPClient
93
95
  #
94
96
  # Enables/disables address lookup.
95
97
  #
96
- # @return [true] if the connection is allowed to lookup the address (default)
97
- # @return [false] if the address lookup is not required
98
+ # @return [Boolean] whether the connection is allowed to lookup the address
99
+ # (default) or not
98
100
  #
99
101
  attr_reader :reverse_lookup
100
102
 
@@ -103,55 +105,45 @@ class TCPClient
103
105
  end
104
106
 
105
107
  #
106
- # Enables/disables if network exceptions should be raised as {NetworkError}.
107
- #
108
- # @return [true] if all network exceptions should be raised as {NetworkError}
109
- # @return [false] if socket/system errors should not be normalzed (default)
108
+ # @!parse attr_reader :ssl?
109
+ # @return [Boolean] whether SSL is configured, see {#ssl_params}
110
110
  #
111
- attr_reader :normalize_network_errors
112
-
113
- def normalize_network_errors=(value)
114
- @normalize_network_errors = value ? true : false
111
+ def ssl?
112
+ @ssl_params ? true : false
115
113
  end
116
114
 
117
115
  #
118
- # @attribute [w] timeout
119
- # Shorthand to set timeout value for connect, read and write at once or to disable any timeout monitoring
120
- #
121
- # @return [Numeric] maximum time in seconds for any action
122
- # @return [nil] if all timeout monitoring should be disabled (default)
116
+ # Parameters used to initialize a SSL context. SSL/TLS will only be used if
117
+ # this attribute is not `nil`.
123
118
  #
124
- # @see #connect_timeout
125
- # @see #read_timeout
126
- # @see #write_timeout
119
+ # @return [{Symbol => Object}] SSL parameters for the SSL context
120
+ # @return [nil] if no SSL should be used (default)
127
121
  #
128
- def timeout=(value)
129
- @connect_timeout = @write_timeout = @read_timeout = seconds(value)
130
- end
122
+ attr_reader :ssl_params
131
123
 
132
- #
133
- # @attribute [w] timeout_error
134
- # Shorthand to configure exception class raised when connect, read or write exceeded the configured timeout
135
- #
136
- # @return [Class] exception class raised
137
- #
138
- # @raise [NotAnExceptionError] if given argument is not an Exception class
139
- #
140
- # @see #connect_timeout_error
141
- # @see #read_timeout_error
142
- # @see #write_timeout_error
143
- #
144
- def timeout_error=(value)
145
- raise(NotAnExceptionError, value) unless exception_class?(value)
146
- @connect_timeout_error =
147
- @read_timeout_error = @write_timeout_error = value
124
+ def ssl_params=(value)
125
+ @ssl_params =
126
+ if value.respond_to?(:to_hash)
127
+ Hash[value.to_hash]
128
+ elsif value.respond_to?(:to_h)
129
+ value.nil? ? nil : Hash[value.to_h]
130
+ else
131
+ value ? {} : nil
132
+ end
148
133
  end
134
+ alias ssl= ssl_params=
135
+
136
+ # @!endgroup
149
137
 
138
+ # @!group Instance Attributes Timeout Monitoring
139
+
140
+ #
141
+ # The maximum time in seconds to establish a connection.
150
142
  #
151
- # Configures maximum time in seconds to establish a connection.
143
+ # @return [Numeric] maximum time in seconds
144
+ # @return [nil] if the connect time should not be monitored (default)
152
145
  #
153
- # @return [Numeric] maximum time in seconds to establish a connection
154
- # @return [nil] if the connect time should not be checked (default)
146
+ # @see TCPClient#connect
155
147
  #
156
148
  attr_reader :connect_timeout
157
149
 
@@ -160,7 +152,10 @@ class TCPClient
160
152
  end
161
153
 
162
154
  #
163
- # @return [Class] exception class raised if a {TCPClient#connect} timed out
155
+ # The exception class which will be raised if {TCPClient#connect} can not
156
+ # be finished in time.
157
+ #
158
+ # @return [Class<Exception>] exception class raised
164
159
  # @raise [NotAnExceptionError] if given argument is not an Exception class
165
160
  #
166
161
  attr_reader :connect_timeout_error
@@ -171,10 +166,12 @@ class TCPClient
171
166
  end
172
167
 
173
168
  #
174
- # Configures maximum time in seconds to finish a {TCPClient#read}.
169
+ # The maximum time in seconds to read from a connection.
170
+ #
171
+ # @return [Numeric] maximum time in seconds
172
+ # @return [nil] if the read time should not be monitored (default)
175
173
  #
176
- # @return [Numeric] maximum time in seconds to finish a {TCPClient#read} request
177
- # @return [nil] if the read time should not be checked (default)
174
+ # @see TCPClient#read
178
175
  #
179
176
  attr_reader :read_timeout
180
177
 
@@ -183,7 +180,10 @@ class TCPClient
183
180
  end
184
181
 
185
182
  #
186
- # @return [Class] exception class raised if a {TCPClient#read} timed out
183
+ # The exception class which will be raised if {TCPClient#read} can not be
184
+ # finished in time.
185
+ #
186
+ # @return [Class<Exception>] exception class raised
187
187
  # @raise [NotAnExceptionError] if given argument is not an Exception class
188
188
  #
189
189
  attr_reader :read_timeout_error
@@ -194,10 +194,12 @@ class TCPClient
194
194
  end
195
195
 
196
196
  #
197
- # Configures maximum time in seconds to finish a {TCPClient#write}.
197
+ # The maximum time in seconds to write to a connection.
198
198
  #
199
- # @return [Numeric] maximum time in seconds to finish a {TCPClient#write} request
200
- # @return [nil] if the write time should not be checked (default)
199
+ # @return [Numeric] maximum time in seconds
200
+ # @return [nil] if the write time should not be monitored (default)
201
+ #
202
+ # @see TCPClient#write
201
203
  #
202
204
  attr_reader :write_timeout
203
205
 
@@ -206,7 +208,10 @@ class TCPClient
206
208
  end
207
209
 
208
210
  #
209
- # @return [Class] exception class raised if a {TCPClient#write} timed out
211
+ # The exception class which will be raised if {TCPClient#write} can not be
212
+ # finished in time.
213
+ #
214
+ # @return [Class<Exception>] exception class raised
210
215
  # @raise [NotAnExceptionError] if given argument is not an Exception class
211
216
  #
212
217
  attr_reader :write_timeout_error
@@ -217,48 +222,76 @@ class TCPClient
217
222
  end
218
223
 
219
224
  #
220
- # @attribute ssl?
221
- # @return [Boolean] wheter SSL is configured, see {#ssl_params}
225
+ # @attribute [w] timeout
226
+ # Shorthand to set maximum time in seconds for all timeout monitoring.
222
227
  #
223
- def ssl?
224
- @ssl_params ? true : false
228
+ # @return [Numeric] maximum time in seconds for any action
229
+ # @return [nil] if all timeout monitoring should be disabled (default)
230
+ #
231
+ # @see #connect_timeout
232
+ # @see #read_timeout
233
+ # @see #write_timeout
234
+ #
235
+ def timeout=(value)
236
+ @connect_timeout = @write_timeout = @read_timeout = seconds(value)
225
237
  end
226
238
 
227
239
  #
228
- # Configures the SSL parameters used to initialize a SSL context.
240
+ # @attribute [w] timeout_error
241
+ # Shorthand to set the exception class which will by raised by any reached
242
+ # timeout.
229
243
  #
230
- # @return [Hash<Symbol, Object>] SSL parameters for the SSL context
231
- # @return [nil] if no SSL should be used (default)
244
+ # @return [Class<Exception>] exception class raised
232
245
  #
233
- attr_reader :ssl_params
246
+ # @raise [NotAnExceptionError] if given argument is not an Exception class
247
+ #
248
+ # @see #connect_timeout_error
249
+ # @see #read_timeout_error
250
+ # @see #write_timeout_error
251
+ #
252
+ def timeout_error=(value)
253
+ raise(NotAnExceptionError, value) unless exception_class?(value)
254
+ @connect_timeout_error =
255
+ @read_timeout_error = @write_timeout_error = value
256
+ end
234
257
 
235
- def ssl_params=(value)
236
- @ssl_params =
237
- if value.respond_to?(:to_hash)
238
- Hash[value.to_hash]
239
- elsif value.respond_to?(:to_h)
240
- Hash[value.to_h]
241
- else
242
- value ? {} : nil
243
- end
258
+ # @!endgroup
259
+
260
+ #
261
+ # Enables/disables if network exceptions should be raised as {NetworkError}.
262
+ #
263
+ # This allows to handle all network/socket related exceptions like
264
+ # `SocketError`, `OpenSSL::SSL::SSLError`, `IOError`, etc. in a uniform
265
+ # manner. If this option is set to true all these error cases are raised as
266
+ # {NetworkError} and can be easily captured.
267
+ #
268
+ # @return [Boolean] whether all network exceptions should be raised as
269
+ # {NetworkError}, or not (default)
270
+ #
271
+ attr_reader :normalize_network_errors
272
+
273
+ def normalize_network_errors=(value)
274
+ @normalize_network_errors = value ? true : false
244
275
  end
245
- alias ssl= ssl_params=
246
276
 
247
277
  #
248
- # @return [Hash] configuration as a Hash
278
+ # @return [{Symbol => Object}] Hash containing all attributes
279
+ #
280
+ # @see #initialize
249
281
  #
250
282
  def to_h
251
283
  {
252
284
  buffered: @buffered,
253
285
  keep_alive: @keep_alive,
254
286
  reverse_lookup: @reverse_lookup,
287
+ ssl_params: @ssl_params,
255
288
  connect_timeout: @connect_timeout,
256
289
  connect_timeout_error: @connect_timeout_error,
257
290
  read_timeout: @read_timeout,
258
291
  read_timeout_error: @read_timeout_error,
259
292
  write_timeout: @write_timeout,
260
293
  write_timeout_error: @write_timeout_error,
261
- ssl_params: @ssl_params
294
+ normalize_network_errors: @normalize_network_errors
262
295
  }
263
296
  end
264
297
 
@@ -2,8 +2,6 @@
2
2
 
3
3
  class TCPClient
4
4
  class Deadline
5
- MONOTONIC = defined?(Process::CLOCK_MONOTONIC) ? true : false
6
-
7
5
  def initialize(timeout)
8
6
  timeout = timeout&.to_f
9
7
  @deadline = timeout&.positive? ? now + timeout : 0
@@ -19,7 +17,7 @@ class TCPClient
19
17
 
20
18
  private
21
19
 
22
- if MONOTONIC
20
+ if defined?(Process::CLOCK_MONOTONIC)
23
21
  def now
24
22
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
25
23
  end
@@ -7,13 +7,17 @@ class TCPClient
7
7
 
8
8
  class << self
9
9
  #
10
- # @return [Configuration] used by default if no dedicated configuration was specified
10
+ # The default configuration.
11
+ # This is used by default if no dedicated configuration was specified to
12
+ # {.open} or {#connect}.
13
+ #
14
+ # @return [Configuration]
11
15
  #
12
16
  attr_reader :default_configuration
13
17
 
14
18
  #
15
- # Configure the default configuration which is used if no dedicated
16
- # configuration was specified.
19
+ # Configure the {.default_configuration} which is used if no dedicated
20
+ # configuration was specified to {.open} or {#connect}.
17
21
  #
18
22
  # @example
19
23
  # TCPClient.configure do |cfg|
@@ -33,11 +37,19 @@ class TCPClient
33
37
  end
34
38
 
35
39
  class Configuration
36
- #
37
- # @return [Configuration] used by default if no dedicated configuration was specified
38
- #
39
- def self.default
40
- TCPClient.default_configuration
40
+ class << self
41
+ #
42
+ # @!parse attr_reader :default
43
+ # @return [Configuration] used by default if no dedicated configuration
44
+ # was specified
45
+ #
46
+ # @see TCPClient.open
47
+ # @see TCPClient.with_deadline
48
+ # @see TCPClient#connect
49
+ #
50
+ def default
51
+ TCPClient.default_configuration
52
+ end
41
53
  end
42
54
  end
43
55
  end