rom-ldap 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +251 -0
  3. data/CONTRIBUTING.md +18 -0
  4. data/README.md +172 -0
  5. data/TODO.md +33 -0
  6. data/config/responses.yml +328 -0
  7. data/lib/dry/monitor/ldap/colorizers/default.rb +17 -0
  8. data/lib/dry/monitor/ldap/colorizers/rouge.rb +31 -0
  9. data/lib/dry/monitor/ldap/logger.rb +58 -0
  10. data/lib/rom-ldap.rb +1 -0
  11. data/lib/rom/ldap.rb +22 -0
  12. data/lib/rom/ldap/alias.rb +30 -0
  13. data/lib/rom/ldap/associations.rb +6 -0
  14. data/lib/rom/ldap/associations/core.rb +23 -0
  15. data/lib/rom/ldap/associations/many_to_many.rb +18 -0
  16. data/lib/rom/ldap/associations/many_to_one.rb +22 -0
  17. data/lib/rom/ldap/associations/one_to_many.rb +32 -0
  18. data/lib/rom/ldap/associations/one_to_one.rb +19 -0
  19. data/lib/rom/ldap/associations/self_ref.rb +35 -0
  20. data/lib/rom/ldap/attribute.rb +327 -0
  21. data/lib/rom/ldap/client.rb +185 -0
  22. data/lib/rom/ldap/client/authentication.rb +118 -0
  23. data/lib/rom/ldap/client/operations.rb +233 -0
  24. data/lib/rom/ldap/commands.rb +6 -0
  25. data/lib/rom/ldap/commands/create.rb +41 -0
  26. data/lib/rom/ldap/commands/delete.rb +17 -0
  27. data/lib/rom/ldap/commands/update.rb +35 -0
  28. data/lib/rom/ldap/constants.rb +193 -0
  29. data/lib/rom/ldap/dataset.rb +286 -0
  30. data/lib/rom/ldap/dataset/conversion.rb +62 -0
  31. data/lib/rom/ldap/dataset/dsl.rb +299 -0
  32. data/lib/rom/ldap/dataset/persistence.rb +44 -0
  33. data/lib/rom/ldap/directory.rb +126 -0
  34. data/lib/rom/ldap/directory/capabilities.rb +71 -0
  35. data/lib/rom/ldap/directory/entry.rb +200 -0
  36. data/lib/rom/ldap/directory/env.rb +155 -0
  37. data/lib/rom/ldap/directory/operations.rb +282 -0
  38. data/lib/rom/ldap/directory/password.rb +122 -0
  39. data/lib/rom/ldap/directory/root.rb +187 -0
  40. data/lib/rom/ldap/directory/tokenization.rb +66 -0
  41. data/lib/rom/ldap/directory/transactions.rb +31 -0
  42. data/lib/rom/ldap/directory/vendors/active_directory.rb +129 -0
  43. data/lib/rom/ldap/directory/vendors/apache_ds.rb +27 -0
  44. data/lib/rom/ldap/directory/vendors/e_directory.rb +16 -0
  45. data/lib/rom/ldap/directory/vendors/open_directory.rb +12 -0
  46. data/lib/rom/ldap/directory/vendors/open_dj.rb +25 -0
  47. data/lib/rom/ldap/directory/vendors/open_ldap.rb +35 -0
  48. data/lib/rom/ldap/directory/vendors/three_eight_nine.rb +16 -0
  49. data/lib/rom/ldap/directory/vendors/unknown.rb +22 -0
  50. data/lib/rom/ldap/dsl.rb +76 -0
  51. data/lib/rom/ldap/errors.rb +47 -0
  52. data/lib/rom/ldap/expression.rb +77 -0
  53. data/lib/rom/ldap/expression_encoder.rb +174 -0
  54. data/lib/rom/ldap/extensions.rb +50 -0
  55. data/lib/rom/ldap/extensions/active_support_notifications.rb +26 -0
  56. data/lib/rom/ldap/extensions/compatibility.rb +11 -0
  57. data/lib/rom/ldap/extensions/dsml.rb +165 -0
  58. data/lib/rom/ldap/extensions/msgpack.rb +23 -0
  59. data/lib/rom/ldap/extensions/optimised_json.rb +25 -0
  60. data/lib/rom/ldap/extensions/rails_log_subscriber.rb +38 -0
  61. data/lib/rom/ldap/formatter.rb +26 -0
  62. data/lib/rom/ldap/functions.rb +207 -0
  63. data/lib/rom/ldap/gateway.rb +145 -0
  64. data/lib/rom/ldap/ldif.rb +74 -0
  65. data/lib/rom/ldap/ldif/exporter.rb +77 -0
  66. data/lib/rom/ldap/ldif/importer.rb +95 -0
  67. data/lib/rom/ldap/mapper_compiler.rb +19 -0
  68. data/lib/rom/ldap/matchers.rb +69 -0
  69. data/lib/rom/ldap/message_queue.rb +7 -0
  70. data/lib/rom/ldap/oid.rb +101 -0
  71. data/lib/rom/ldap/parsers/abstract_syntax.rb +91 -0
  72. data/lib/rom/ldap/parsers/attribute.rb +290 -0
  73. data/lib/rom/ldap/parsers/filter_syntax.rb +133 -0
  74. data/lib/rom/ldap/pdu.rb +285 -0
  75. data/lib/rom/ldap/plugin/pagination.rb +145 -0
  76. data/lib/rom/ldap/plugins.rb +7 -0
  77. data/lib/rom/ldap/projection_dsl.rb +38 -0
  78. data/lib/rom/ldap/relation.rb +135 -0
  79. data/lib/rom/ldap/relation/exporting.rb +72 -0
  80. data/lib/rom/ldap/relation/reading.rb +461 -0
  81. data/lib/rom/ldap/relation/writing.rb +64 -0
  82. data/lib/rom/ldap/responses.rb +17 -0
  83. data/lib/rom/ldap/restriction_dsl.rb +45 -0
  84. data/lib/rom/ldap/schema.rb +123 -0
  85. data/lib/rom/ldap/schema/attributes_inferrer.rb +59 -0
  86. data/lib/rom/ldap/schema/dsl.rb +13 -0
  87. data/lib/rom/ldap/schema/inferrer.rb +50 -0
  88. data/lib/rom/ldap/schema/type_builder.rb +133 -0
  89. data/lib/rom/ldap/scope.rb +19 -0
  90. data/lib/rom/ldap/search_request.rb +249 -0
  91. data/lib/rom/ldap/socket.rb +210 -0
  92. data/lib/rom/ldap/tasks/ldap.rake +103 -0
  93. data/lib/rom/ldap/tasks/ldif.rake +80 -0
  94. data/lib/rom/ldap/transaction.rb +29 -0
  95. data/lib/rom/ldap/type_map.rb +88 -0
  96. data/lib/rom/ldap/types.rb +158 -0
  97. data/lib/rom/ldap/version.rb +17 -0
  98. data/lib/rom/plugins/relation/ldap/active_directory.rb +182 -0
  99. data/lib/rom/plugins/relation/ldap/auto_restrictions.rb +69 -0
  100. data/lib/rom/plugins/relation/ldap/e_directory.rb +27 -0
  101. data/lib/rom/plugins/relation/ldap/instrumentation.rb +35 -0
  102. data/lib/rouge/lexers/ldap.rb +72 -0
  103. data/lib/rouge/themes/ldap.rb +49 -0
  104. metadata +231 -0
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module LDAP
5
+ #
6
+ # Search Scope
7
+ #
8
+ # @see https://ldapwiki.com/wiki/LDAP%20Search%20Scopes
9
+ #
10
+ # Constrained to the entry named by baseObject.
11
+ SCOPE_BASE = 0 # "base"
12
+ # Constrained to the immediate subordinates of the entry named by baseObject.
13
+ SCOPE_ONE = 1 # "one"
14
+ # Constrained to the entry named by baseObject and to all its subordinates.
15
+ SCOPE_SUB = 2 # "sub"
16
+
17
+ SCOPES = [SCOPE_BASE, SCOPE_ONE, SCOPE_SUB].freeze
18
+ end
19
+ end
@@ -0,0 +1,249 @@
1
+ # frozen_string_literal: true
2
+
3
+ using ::BER
4
+
5
+ require 'rom/ldap/types'
6
+ require 'rom/ldap/expression'
7
+
8
+ module ROM
9
+ module LDAP
10
+ # The Search request is defined as follows:
11
+ #
12
+ # SearchRequest ::= [APPLICATION 3] SEQUENCE {
13
+ # baseObject LDAPDN,
14
+ # scope ENUMERATED {
15
+ # baseObject (0),
16
+ # singleLevel (1),
17
+ # wholeSubtree (2),
18
+ # ... },
19
+ # derefAliases ENUMERATED {
20
+ # neverDerefAliases (0),
21
+ # derefInSearching (1),
22
+ # derefFindingBaseObj (2),
23
+ # derefAlways (3) },
24
+ # sizeLimit INTEGER (0 .. maxInt),
25
+ # timeLimit INTEGER (0 .. maxInt),
26
+ # typesOnly BOOLEAN,
27
+ # filter Filter,
28
+ # attributes AttributeSelection }
29
+ #
30
+ # AttributeSelection ::= SEQUENCE OF selector LDAPString
31
+ # -- The LDAPString is constrained to
32
+ # -- <attributeSelector> in Section 4.5.1.8
33
+ #
34
+ # Filter ::= CHOICE {
35
+ # and [0] SET SIZE (1..MAX) OF filter Filter,
36
+ # or [1] SET SIZE (1..MAX) OF filter Filter,
37
+ # not [2] Filter,
38
+ # equalityMatch [3] AttributeValueAssertion,
39
+ # substrings [4] SubstringFilter,
40
+ # greaterOrEqual [5] AttributeValueAssertion,
41
+ # lessOrEqual [6] AttributeValueAssertion,
42
+ # present [7] AttributeDescription,
43
+ # approxMatch [8] AttributeValueAssertion,
44
+ # extensibleMatch [9] MatchingRuleAssertion,
45
+ # ... }
46
+ #
47
+ # SubstringFilter ::= SEQUENCE {
48
+ # type AttributeDescription,
49
+ # substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
50
+ # initial [0] AssertionValue, -- can occur at most once
51
+ # any [1] AssertionValue,
52
+ # final [2] AssertionValue } -- can occur at most once
53
+ # }
54
+ #
55
+ # MatchingRuleAssertion ::= SEQUENCE {
56
+ # matchingRule [1] MatchingRuleId OPTIONAL,
57
+ # type [2] AttributeDescription OPTIONAL,
58
+ # matchValue [3] AssertionValue,
59
+ # dnAttributes [4] BOOLEAN DEFAULT FALSE }
60
+ #
61
+ #
62
+ #
63
+ #
64
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1
65
+ #
66
+ # @api private
67
+ class SearchRequest
68
+
69
+ extend Initializer
70
+
71
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.7
72
+ #
73
+ # @!attribute [r] expression
74
+ # @return [Expression] Required.
75
+ option :expression, type: Types.Instance(Expression)
76
+
77
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.1
78
+ #
79
+ # @!attribute [r] base
80
+ # @return [String] Set to Relation default_base:
81
+ option :base, proc(&:to_s), type: Types::DN, default: -> { EMPTY_STRING }
82
+
83
+ # Defaults to only searching entries under base object.
84
+ #
85
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.2
86
+ #
87
+ # @!attribute [r] scope
88
+ # @return [Integer]
89
+ option :scope, type: Types::Scope, default: -> { SCOPE_SUB }
90
+
91
+ # Defaults to dereferencing both when searching and when locating the search base.
92
+ #
93
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.3
94
+ #
95
+ # @!attribute [r] deref
96
+ # @return [Integer]
97
+ option :deref, type: Types::Deref, default: -> { DEREF_ALWAYS }
98
+
99
+ # Defaults to all attributes '*' but not operational.
100
+ #
101
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.8
102
+ #
103
+ # @!attribute [r] attributes
104
+ # @return [Array<String>] Restrict attributes returned.
105
+ option :attributes, type: Types::Strings, default: -> { [WILDCARD] }
106
+
107
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.6
108
+ #
109
+ # @!attribute [r] attributes_only
110
+ # @return [Boolean] Do not include values.
111
+ option :attributes_only, type: Types::Strict::Bool, default: -> { false }
112
+
113
+ # @!attribute [r] reverse
114
+ # @return [Boolean]
115
+ option :reverse, type: Types::Strict::Bool, default: -> { false }
116
+
117
+ # Defaults to not paging results
118
+ #
119
+ # Adds :paged_result control to the request.
120
+ #
121
+ # @!attribute [r] paged
122
+ # @return [Boolean]
123
+ option :paged, type: Types::Strict::Bool, default: -> { false }
124
+
125
+ # ads-maxTimeLimit: 15000
126
+ # Defaults to zero, no timeout.
127
+ #
128
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.5
129
+ #
130
+ # @!attribute [r] timeout
131
+ # @return [Integer]
132
+ option :timeout, type: Types::Strict::Integer, default: -> { 0 }
133
+
134
+ # ads-maxSizeLimit: 200
135
+ #
136
+ # @see https://tools.ietf.org/html/rfc4511#section-4.5.1.4
137
+ #
138
+ # @!attribute [r] max
139
+ # @return [Integer]
140
+ option :max, type: Types::Strict::Integer, optional: true
141
+
142
+ # @!attribute [r] sort
143
+ # @return [Array<String>]
144
+ option :sorted, type: Types::Strict::Array, optional: true
145
+
146
+ # Search request components.
147
+ #
148
+ # @return [Array]
149
+ def parts
150
+ [
151
+ base.to_ber, # 4.5.1.1. SearchRequest.baseObject
152
+ scope.to_ber_enumerated, # 4.5.1.2. SearchRequest.scope
153
+ deref.to_ber_enumerated, # 4.5.1.3. SearchRequest.derefAliases
154
+ limit.to_ber, # 4.5.1.4. SearchRequest.sizeLimit
155
+ timeout.to_ber, # 4.5.1.5. SearchRequest.timeLimit
156
+ attributes_only.to_ber, # 4.5.1.6. SearchRequest.typesOnly
157
+ expression.to_ber, # 4.5.1.7. SearchRequest.filter
158
+ ber_attrs.to_ber_sequence # 4.5.1.8. SearchRequest.attributes
159
+ ]
160
+ end
161
+
162
+ #
163
+ # Controls sent by clients are termed 'request controls', and those
164
+ # sent by servers are termed 'response controls'.
165
+ #
166
+ # Controls ::= SEQUENCE OF control Control
167
+ #
168
+ # Control ::= SEQUENCE {
169
+ # controlType LDAPOID,
170
+ # criticality BOOLEAN DEFAULT FALSE,
171
+ # controlValue OCTET STRING OPTIONAL }
172
+ #
173
+ #
174
+ # @see https://tools.ietf.org/html/rfc4511#section-4.1.11
175
+ #
176
+ # @return [Array]
177
+ def controls
178
+ ctrls = []
179
+ ctrls << build_controls(:paged_results, cookie) if paged
180
+ ctrls << build_controls(:sort_request, sort_rules) if sorted
181
+ ctrls.empty? ? nil : ctrls.to_ber_contextspecific(0)
182
+ end
183
+
184
+ private
185
+
186
+ # Set test server to only serve 200 at a time to check paging
187
+ #
188
+ # Limit to no more than 126 entries.
189
+ #
190
+ # @return [Integer]
191
+ #
192
+ # @api private
193
+ def limit
194
+ (0..126).cover?(max) ? max : 0
195
+ end
196
+
197
+ # @return [Array]
198
+ #
199
+ # @api private
200
+ def ber_attrs
201
+ Array(attributes).map { |attr| attr.to_s.to_ber }
202
+ end
203
+
204
+ # @see https://tools.ietf.org/html/rfc2696
205
+ #
206
+ # @return [Array]
207
+ #
208
+ # @api private
209
+ def cookie
210
+ [126.to_ber, EMPTY_STRING.to_ber]
211
+ # [99.to_ber, EMPTY_STRING.to_ber]
212
+ end
213
+
214
+ # Control ::= SEQUENCE {
215
+ # controlType LDAPOID,
216
+ # criticality BOOLEAN DEFAULT FALSE,
217
+ # controlValue OCTET STRING OPTIONAL }
218
+ #
219
+ # @return [String] LDAP 'control'
220
+ #
221
+ # @see PDU#result_controls
222
+ #
223
+ def build_controls(type, payload)
224
+ [
225
+ OID[type].to_ber,
226
+ false.to_ber,
227
+ payload.to_ber_sequence.to_s.to_ber
228
+ ].to_ber_sequence
229
+ end
230
+
231
+ # Only uses attribute names because not all vendors have fully implemented SSS.
232
+ #
233
+ # SortKeyList ::= SEQUENCE OF SEQUENCE {
234
+ # attributeType AttributeDescription,
235
+ # orderingRule [0] MatchingRuleId OPTIONAL,
236
+ # reverseOrder [1] BOOLEAN DEFAULT FALSE }
237
+ #
238
+ #
239
+ # @see https://tools.ietf.org/html/rfc2891
240
+ # @see https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/controls/ServerSideSortRequestControl.html
241
+ #
242
+ # @api private
243
+ def sort_rules
244
+ sorted.map { |attr| [attr.to_ber].to_ber_sequence }
245
+ end
246
+
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+ require 'rom/initializer'
5
+
6
+ module GetbyteForSSLSocket
7
+ def getbyte
8
+ byte = getc
9
+ return nil if byte.nil?
10
+
11
+ byte.ord
12
+ end
13
+ end
14
+
15
+ module FixSSLSocketSyncClose
16
+ def close
17
+ super
18
+ io.close
19
+ end
20
+ end
21
+
22
+ module ROM
23
+ module LDAP
24
+ #
25
+ # Builds either TCP or UNIX.
26
+ #
27
+ # @api private
28
+ class Socket
29
+
30
+ extend Initializer
31
+
32
+ # Unix socket absolute file path
33
+ #
34
+ # @!attribute [r] path
35
+ # @return [String]
36
+ option :path, type: Types::Strict::String, reader: :private, optional: true
37
+
38
+ # Domain name or IP for TCP connection
39
+ #
40
+ # @!attribute [r] host
41
+ # @return [String]
42
+ option :host, type: Types::Strict::String, reader: :private, optional: true
43
+
44
+ # TCP port
45
+ #
46
+ # @!attribute [r] host
47
+ # @return [Integer]
48
+ option :port, type: Types::Strict::Integer, reader: :private, optional: true
49
+
50
+ # OpenSSL
51
+ # OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
52
+ option :ssl, type: Types::Strict::Hash, reader: :private, optional: true
53
+
54
+ # Config
55
+ # option :timeout, type: Types::Strict::Integer, reader: :private, default: -> { 10 }
56
+
57
+ option :read_timeout, type: Types::Strict::Integer, reader: :private, default: -> { 20 }
58
+
59
+ # Timeout limit in seconds when writing to the socket
60
+ #
61
+ # @!attribute [r] write_timeout
62
+ # @return [Integer] default: 10
63
+ option :write_timeout, type: Types::Strict::Integer, reader: :private, default: -> { 10 }
64
+
65
+ # Retry limit when establishing connection
66
+ #
67
+ # @!attribute [r] retry_count
68
+ # @return [Integer] default: 3
69
+ option :retry_count, type: Types::Strict::Integer, reader: :private, default: -> { 3 }
70
+
71
+ #
72
+ #
73
+ # @!attribute [r] retry_count
74
+ # @return [Boolean] default: true
75
+ option :keep_alive, type: Types::Strict::Bool, reader: :private, default: -> { true }
76
+
77
+ #
78
+ #
79
+ # @!attribute [r] buffered
80
+ # @return [Boolean] default: true
81
+ option :buffered, type: Types::Strict::Bool, reader: :private, default: -> { true }
82
+
83
+ # @return [::Socket, ::OpenSSL::SSL::SSLSocket]
84
+ #
85
+ def call
86
+ socket.do_not_reverse_lookup = true
87
+ socket.sync = buffered
88
+ socket.setsockopt(:SOCKET, :KEEPALIVE, keep_alive)
89
+ socket.setsockopt(:TCP, :NODELAY, buffered) unless path
90
+
91
+ connect!
92
+ end
93
+
94
+ private
95
+
96
+ # @return [::Socket]
97
+ #
98
+ # @raise [ConnectionError]
99
+ #
100
+ def connect!
101
+ @counter ||= 1
102
+
103
+ if ssl
104
+ require 'openssl'
105
+
106
+ ctx = OpenSSL::SSL::SSLContext.new
107
+ ctx.set_params(ssl)
108
+ @socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
109
+ # socket.extend(GetbyteForSSLSocket) unless socket.respond_to?(:getbyte)
110
+ # socket.extend(FixSSLSocketSyncClose)
111
+ socket.connect_nonblock
112
+ else
113
+ socket.connect_nonblock(sockaddr)
114
+ end
115
+
116
+ socket
117
+ rescue Errno::EISCONN
118
+ socket
119
+ rescue IO::WaitWritable
120
+ # OpenSSL::SSL::SSLErrorWaitWritable
121
+ if writable?
122
+ connect!
123
+ else
124
+ disconnect!
125
+ raise ConnectionError, "Connection write timeout - #{host}:#{port}"
126
+ end
127
+ rescue IO::WaitReadable
128
+ if readable?
129
+ @counter += 1
130
+ retry unless @counter > retry_count
131
+ else
132
+ raise ConnectionError, "Connection read timeout - #{host}:#{port}"
133
+ end
134
+ rescue Errno::EADDRNOTAVAIL
135
+ raise ConnectionError, "Host or port is invalid - #{host}:#{port}"
136
+ rescue SocketError
137
+ raise ConnectionError, "Host could not be resolved - #{host}:#{port}"
138
+ rescue Errno::ENOENT
139
+ raise ConnectionError, "Path to unix socket is invalid - #{path}"
140
+ rescue Errno::EHOSTDOWN
141
+ raise ConnectionError, "Server is down - #{host}:#{port}"
142
+ rescue Errno::ECONNREFUSED
143
+ raise ConnectionError, "Connection refused - #{host}:#{port}"
144
+ rescue Errno::EAFNOSUPPORT
145
+ raise ConnectionError, "Connection is not supported - #{host}:#{port}"
146
+ rescue
147
+ disconnect!
148
+ raise ConnectionError, "Connection failed - #{host}:#{port}"
149
+ end
150
+
151
+ #
152
+ #
153
+ # @return [::Socket]
154
+ #
155
+ def socket
156
+ @socket ||= ::Socket.new((path ? :UNIX : :INET), :STREAM)
157
+ end
158
+
159
+ # @return [NilClass]
160
+ #
161
+ def disconnect!
162
+ socket.close
163
+ @socket = nil
164
+ end
165
+
166
+ # IPV4 or UNIX socket address
167
+ #
168
+ # @return [String] ASCII-8BIT
169
+ #
170
+ # @api private
171
+ def sockaddr
172
+ if addrinfo.unix?
173
+ ::Socket.pack_sockaddr_un(addrinfo.unix_path)
174
+
175
+ elsif addrinfo.ipv4?
176
+ ::Socket.pack_sockaddr_in(addrinfo.ip_port, addrinfo.ip_address)
177
+
178
+ elsif addrinfo.ipv6_loopback?
179
+ ::Socket.pack_sockaddr_in(addrinfo.ip_port, '127.0.0.1')
180
+ end
181
+ end
182
+
183
+ # Performs DNS lookup
184
+ #
185
+ # @return [Addrinfo]
186
+ #
187
+ # @api private
188
+ def addrinfo
189
+ return Addrinfo.unix(path) if path
190
+
191
+ Addrinfo.tcp(host, port)
192
+ end
193
+
194
+ # @return [TrueClass,FalseClass]
195
+ #
196
+ # @api private
197
+ def writable?
198
+ !IO.select(nil, [socket], nil, write_timeout).nil?
199
+ end
200
+
201
+ # @return [TrueClass,FalseClass]
202
+ #
203
+ # @api private
204
+ def readable?
205
+ !IO.select([socket], nil, nil, read_timeout).nil?
206
+ end
207
+
208
+ end
209
+ end
210
+ end