rom-ldap 0.2.2

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