@@ -111,6 +111,45 @@ def close
111
111
@conn = nil
112
112
end
113
113
114
+ # Internal: Reads messages by ID from a queue, falling back to reading from
115
+ # the connected socket until a message matching the ID is read. Any messages
116
+ # with mismatched IDs gets queued for subsequent reads by the origin of that
117
+ # message ID.
118
+ #
119
+ # Returns a Net::LDAP::PDU object or nil.
120
+ def queued_read ( message_id )
121
+ if pdu = message_queue [ message_id ] . shift
122
+ return pdu
123
+ end
124
+
125
+ # read messages until we have a match for the given message_id
126
+ while pdu = read
127
+ if pdu . message_id == message_id
128
+ return pdu
129
+ else
130
+ message_queue [ pdu . message_id ] . push pdu
131
+ next
132
+ end
133
+ end
134
+
135
+ pdu
136
+ end
137
+
138
+ # Internal: The internal queue of messages, read from the socket, grouped by
139
+ # message ID.
140
+ #
141
+ # Used by `queued_read` to return messages sent by the server with the given
142
+ # ID. If no messages are queued for that ID, `queued_read` will `read` from
143
+ # the socket and queue messages that don't match the given ID for other
144
+ # readers.
145
+ #
146
+ # Returns the message queue Hash.
147
+ def message_queue
148
+ @message_queue ||= Hash . new do |hash , key |
149
+ hash [ key ] = [ ]
150
+ end
151
+ end
152
+
114
153
# Internal: Reads and parses data from the configured connection.
115
154
#
116
155
# - syntax: the BER syntax to use to parse the read data with
@@ -146,9 +185,9 @@ def read(syntax = Net::LDAP::AsnSyntax)
146
185
#
147
186
# Returns the return value from writing to the connection, which in some
148
187
# cases is the Integer number of bytes written to the socket.
149
- def write ( request , controls = nil )
188
+ def write ( request , controls = nil , message_id = next_msgid )
150
189
instrument "write.net_ldap_connection" do |payload |
151
- packet = [ next_msgid . to_ber , request , controls ] . compact . to_ber_sequence
190
+ packet = [ message_id . to_ber , request , controls ] . compact . to_ber_sequence
152
191
payload [ :content_length ] = @conn . write ( packet )
153
192
end
154
193
end
@@ -356,7 +395,10 @@ def search(args = {})
356
395
result_pdu = nil
357
396
n_results = 0
358
397
398
+ message_id = next_msgid
399
+
359
400
instrument "search.net_ldap_connection" ,
401
+ :message_id => message_id ,
360
402
:filter => search_filter ,
361
403
:base => search_base ,
362
404
:scope => scope ,
@@ -403,12 +445,12 @@ def search(args = {})
403
445
controls << sort_control if sort_control
404
446
controls = controls . empty? ? nil : controls . to_ber_contextspecific ( 0 )
405
447
406
- write ( request , controls )
448
+ write ( request , controls , message_id )
407
449
408
450
result_pdu = nil
409
451
controls = [ ]
410
452
411
- while pdu = read
453
+ while pdu = queued_read ( message_id )
412
454
case pdu . app_tag
413
455
when Net ::LDAP ::PDU ::SearchReturnedData
414
456
n_results += 1
@@ -476,6 +518,14 @@ def search(args = {})
476
518
477
519
result_pdu || OpenStruct . new ( :status => :failure , :result_code => 1 , :message => "Invalid search" )
478
520
end # instrument
521
+ ensure
522
+ # clean up message queue for this search
523
+ messages = message_queue . delete ( message_id )
524
+
525
+ unless messages . empty?
526
+ instrument "search_messages_unread.net_ldap_connection" ,
527
+ message_id : message_id , messages : messages
528
+ end
479
529
end
480
530
481
531
MODIFY_OPERATIONS = { #:nodoc:
0 commit comments