4 Copyright (C) Simo Sorce 2005-2008
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb paged results control module
29 * Description: this module caches a complete search and sends back
30 * results in chunks as asked by the client
35 #include "ldb_includes.h"
36 #include "ldb_module.h"
38 struct message_store
{
39 /* keep the whole ldb_reply as an optimization
40 * instead of freeing and talloc-ing the container
43 struct message_store
*next
;
48 struct results_store
{
50 struct private_data
*priv
;
55 struct results_store
*next
;
57 struct message_store
*first
;
58 struct message_store
*last
;
61 struct message_store
*first_ref
;
62 struct message_store
*last_ref
;
64 struct ldb_control
**controls
;
68 unsigned int next_free_id
;
69 struct results_store
*store
;
73 static int store_destructor(struct results_store
*del
)
75 struct private_data
*priv
= del
->priv
;
76 struct results_store
*loop
;
78 if (priv
->store
== del
) {
79 priv
->store
= del
->next
;
83 for (loop
= priv
->store
; loop
; loop
= loop
->next
) {
84 if (loop
->next
== del
) {
85 loop
->next
= del
->next
;
90 /* is not in list ? */
94 static struct results_store
*new_store(struct private_data
*priv
)
96 struct results_store
*newr
;
97 unsigned int new_id
= priv
->next_free_id
++;
99 /* TODO: we should have a limit on the number of
100 * outstanding paged searches
103 newr
= talloc(priv
, struct results_store
);
104 if (!newr
) return NULL
;
108 newr
->cookie
= talloc_asprintf(newr
, "%d", new_id
);
114 newr
->timestamp
= time(NULL
);
117 newr
->num_entries
= 0;
118 newr
->first_ref
= NULL
;
119 newr
->controls
= NULL
;
121 newr
->next
= priv
->store
;
124 talloc_set_destructor(newr
, store_destructor
);
129 struct paged_context
{
130 struct ldb_module
*module
;
131 struct ldb_request
*req
;
133 struct results_store
*store
;
135 struct ldb_control
**controls
;
138 static int paged_results(struct paged_context
*ac
)
140 struct ldb_paged_control
*paged
;
141 struct message_store
*msg
;
142 unsigned int i
, num_ctrls
;
145 if (ac
->store
== NULL
) {
146 return LDB_ERR_OPERATIONS_ERROR
;
149 while (ac
->store
->num_entries
> 0 && ac
->size
> 0) {
150 msg
= ac
->store
->first
;
151 ret
= ldb_module_send_entry(ac
->req
, msg
->r
->message
, msg
->r
->controls
);
152 if (ret
!= LDB_SUCCESS
) {
156 ac
->store
->first
= msg
->next
;
158 ac
->store
->num_entries
--;
162 while (ac
->store
->first_ref
!= NULL
) {
163 msg
= ac
->store
->first_ref
;
164 ret
= ldb_module_send_referral(ac
->req
, msg
->r
->referral
);
165 if (ret
!= LDB_SUCCESS
) {
169 ac
->store
->first_ref
= msg
->next
;
173 /* return result done */
177 if (ac
->store
->controls
!= NULL
) {
178 while (ac
->store
->controls
[i
]) i
++; /* counting */
183 ac
->controls
= talloc_array(ac
, struct ldb_control
*, num_ctrls
+1);
184 if (ac
->controls
== NULL
) {
185 return LDB_ERR_OPERATIONS_ERROR
;
187 ac
->controls
[num_ctrls
] = NULL
;
189 for (i
= 0; i
< (num_ctrls
-1); i
++) {
190 ac
->controls
[i
] = talloc_reference(ac
->controls
, ac
->store
->controls
[i
]);
193 ac
->controls
[i
] = talloc(ac
->controls
, struct ldb_control
);
194 if (ac
->controls
[i
] == NULL
) {
195 return LDB_ERR_OPERATIONS_ERROR
;
198 ac
->controls
[i
]->oid
= talloc_strdup(ac
->controls
[i
],
199 LDB_CONTROL_PAGED_RESULTS_OID
);
200 if (ac
->controls
[i
]->oid
== NULL
) {
201 return LDB_ERR_OPERATIONS_ERROR
;
204 ac
->controls
[i
]->critical
= 0;
206 paged
= talloc(ac
->controls
[i
], struct ldb_paged_control
);
208 return LDB_ERR_OPERATIONS_ERROR
;
211 ac
->controls
[i
]->data
= paged
;
215 paged
->cookie
= NULL
;
216 paged
->cookie_len
= 0;
218 paged
->size
= ac
->store
->num_entries
;
219 paged
->cookie
= talloc_strdup(paged
, ac
->store
->cookie
);
220 paged
->cookie_len
= strlen(paged
->cookie
) + 1;
226 static int paged_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
228 struct paged_context
*ac
;
229 struct message_store
*msg_store
;
232 ac
= talloc_get_type(req
->context
, struct paged_context
);
235 return ldb_module_done(ac
->req
, NULL
, NULL
,
236 LDB_ERR_OPERATIONS_ERROR
);
238 if (ares
->error
!= LDB_SUCCESS
) {
239 return ldb_module_done(ac
->req
, ares
->controls
,
240 ares
->response
, ares
->error
);
243 switch (ares
->type
) {
244 case LDB_REPLY_ENTRY
:
245 msg_store
= talloc(ac
->store
, struct message_store
);
246 if (msg_store
== NULL
) {
247 return ldb_module_done(ac
->req
, NULL
, NULL
,
248 LDB_ERR_OPERATIONS_ERROR
);
250 msg_store
->next
= NULL
;
251 msg_store
->r
= talloc_steal(msg_store
, ares
);
253 if (ac
->store
->first
== NULL
) {
254 ac
->store
->first
= msg_store
;
256 ac
->store
->last
->next
= msg_store
;
258 ac
->store
->last
= msg_store
;
260 ac
->store
->num_entries
++;
264 case LDB_REPLY_REFERRAL
:
265 msg_store
= talloc(ac
->store
, struct message_store
);
266 if (msg_store
== NULL
) {
267 return ldb_module_done(ac
->req
, NULL
, NULL
,
268 LDB_ERR_OPERATIONS_ERROR
);
270 msg_store
->next
= NULL
;
271 msg_store
->r
= talloc_steal(msg_store
, ares
);
273 if (ac
->store
->first_ref
== NULL
) {
274 ac
->store
->first_ref
= msg_store
;
276 ac
->store
->last_ref
->next
= msg_store
;
278 ac
->store
->last_ref
= msg_store
;
283 ac
->store
->controls
= talloc_move(ac
->store
, &ares
->controls
);
284 ret
= paged_results(ac
);
285 return ldb_module_done(ac
->req
, ac
->controls
,
286 ares
->response
, ret
);
292 static int paged_search(struct ldb_module
*module
, struct ldb_request
*req
)
294 struct ldb_context
*ldb
;
295 struct ldb_control
*control
;
296 struct private_data
*private_data
;
297 struct ldb_paged_control
*paged_ctrl
;
298 struct ldb_control
**saved_controls
;
299 struct ldb_request
*search_req
;
300 struct paged_context
*ac
;
303 ldb
= ldb_module_get_ctx(module
);
305 /* check if there's a paged request control */
306 control
= ldb_request_get_control(req
, LDB_CONTROL_PAGED_RESULTS_OID
);
307 if (control
== NULL
) {
308 /* not found go on */
309 return ldb_next_request(module
, req
);
312 paged_ctrl
= talloc_get_type(control
->data
, struct ldb_paged_control
);
314 return LDB_ERR_PROTOCOL_ERROR
;
317 private_data
= talloc_get_type(ldb_module_get_private(module
),
318 struct private_data
);
320 ac
= talloc_zero(req
, struct paged_context
);
322 ldb_set_errstring(ldb
, "Out of Memory");
323 return LDB_ERR_OPERATIONS_ERROR
;
328 ac
->size
= paged_ctrl
->size
;
330 /* apparently some clients send more than 2^31. This
331 violates the ldap standard, but we need to cope */
332 ac
->size
= 0x7FFFFFFF;
335 /* check if it is a continuation search the store */
336 if (paged_ctrl
->cookie_len
== 0) {
337 if (paged_ctrl
->size
== 0) {
338 return LDB_ERR_OPERATIONS_ERROR
;
341 ac
->store
= new_store(private_data
);
342 if (ac
->store
== NULL
) {
343 return LDB_ERR_OPERATIONS_ERROR
;
346 ret
= ldb_build_search_req_ex(&search_req
, ldb
, ac
,
348 req
->op
.search
.scope
,
350 req
->op
.search
.attrs
,
353 paged_search_callback
,
355 if (ret
!= LDB_SUCCESS
) {
359 /* save it locally and remove it from the list */
360 /* we do not need to replace them later as we
361 * are keeping the original req intact */
362 if (!save_controls(control
, search_req
, &saved_controls
)) {
363 return LDB_ERR_OPERATIONS_ERROR
;
366 return ldb_next_request(module
, search_req
);
369 struct results_store
*current
= NULL
;
371 /* TODO: age out old outstanding requests */
372 for (current
= private_data
->store
; current
; current
= current
->next
) {
373 if (strcmp(current
->cookie
, paged_ctrl
->cookie
) == 0) {
374 current
->timestamp
= time(NULL
);
378 if (current
== NULL
) {
379 return LDB_ERR_UNWILLING_TO_PERFORM
;
384 /* check if it is an abandon */
386 return ldb_module_done(req
, NULL
, NULL
,
390 ret
= paged_results(ac
);
391 if (ret
!= LDB_SUCCESS
) {
392 return ldb_module_done(req
, NULL
, NULL
, ret
);
394 return ldb_module_done(req
, ac
->controls
, NULL
,
399 static int paged_request_init(struct ldb_module
*module
)
401 struct ldb_context
*ldb
;
402 struct private_data
*data
;
405 ldb
= ldb_module_get_ctx(module
);
407 data
= talloc(module
, struct private_data
);
409 return LDB_ERR_OTHER
;
412 data
->next_free_id
= 1;
414 ldb_module_set_private(module
, data
);
416 ret
= ldb_mod_register_control(module
, LDB_CONTROL_PAGED_RESULTS_OID
);
417 if (ret
!= LDB_SUCCESS
) {
418 ldb_debug(ldb
, LDB_DEBUG_WARNING
,
420 "Unable to register control with rootdse!");
423 return ldb_next_init(module
);
426 const struct ldb_module_ops ldb_paged_results_module_ops
= {
427 .name
= "paged_results",
428 .search
= paged_search
,
429 .init_context
= paged_request_init