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
36 #include "system/filesys.h"
37 #include "system/time.h"
38 #include "ldb_module.h"
40 struct message_store
{
41 /* keep the whole ldb_reply as an optimization
42 * instead of freeing and talloc-ing the container
45 struct message_store
*next
;
50 struct results_store
{
52 struct private_data
*priv
;
57 struct results_store
*next
;
59 struct message_store
*first
;
60 struct message_store
*last
;
63 struct message_store
*first_ref
;
64 struct message_store
*last_ref
;
66 struct ldb_control
**controls
;
70 unsigned int next_free_id
;
71 struct results_store
*store
;
75 static int store_destructor(struct results_store
*del
)
77 struct private_data
*priv
= del
->priv
;
78 struct results_store
*loop
;
80 if (priv
->store
== del
) {
81 priv
->store
= del
->next
;
85 for (loop
= priv
->store
; loop
; loop
= loop
->next
) {
86 if (loop
->next
== del
) {
87 loop
->next
= del
->next
;
92 /* is not in list ? */
96 static struct results_store
*new_store(struct private_data
*priv
)
98 struct results_store
*newr
;
99 unsigned int new_id
= priv
->next_free_id
++;
101 /* TODO: we should have a limit on the number of
102 * outstanding paged searches
105 newr
= talloc(priv
, struct results_store
);
106 if (!newr
) return NULL
;
110 newr
->cookie
= talloc_asprintf(newr
, "%d", new_id
);
116 newr
->timestamp
= time(NULL
);
119 newr
->num_entries
= 0;
120 newr
->first_ref
= NULL
;
121 newr
->controls
= NULL
;
123 newr
->next
= priv
->store
;
126 talloc_set_destructor(newr
, store_destructor
);
131 struct paged_context
{
132 struct ldb_module
*module
;
133 struct ldb_request
*req
;
135 struct results_store
*store
;
137 struct ldb_control
**controls
;
140 static int paged_results(struct paged_context
*ac
)
142 struct ldb_paged_control
*paged
;
143 struct message_store
*msg
;
144 unsigned int i
, num_ctrls
;
147 if (ac
->store
== NULL
) {
148 return LDB_ERR_OPERATIONS_ERROR
;
151 while (ac
->store
->num_entries
> 0 && ac
->size
> 0) {
152 msg
= ac
->store
->first
;
153 ret
= ldb_module_send_entry(ac
->req
, msg
->r
->message
, msg
->r
->controls
);
154 if (ret
!= LDB_SUCCESS
) {
158 ac
->store
->first
= msg
->next
;
160 ac
->store
->num_entries
--;
164 while (ac
->store
->first_ref
!= NULL
) {
165 msg
= ac
->store
->first_ref
;
166 ret
= ldb_module_send_referral(ac
->req
, msg
->r
->referral
);
167 if (ret
!= LDB_SUCCESS
) {
171 ac
->store
->first_ref
= msg
->next
;
175 /* return result done */
179 if (ac
->store
->controls
!= NULL
) {
180 while (ac
->store
->controls
[i
]) i
++; /* counting */
185 ac
->controls
= talloc_array(ac
, struct ldb_control
*, num_ctrls
+1);
186 if (ac
->controls
== NULL
) {
187 return LDB_ERR_OPERATIONS_ERROR
;
189 ac
->controls
[num_ctrls
] = NULL
;
191 for (i
= 0; i
< (num_ctrls
-1); i
++) {
192 ac
->controls
[i
] = talloc_reference(ac
->controls
, ac
->store
->controls
[i
]);
195 ac
->controls
[i
] = talloc(ac
->controls
, struct ldb_control
);
196 if (ac
->controls
[i
] == NULL
) {
197 return LDB_ERR_OPERATIONS_ERROR
;
200 ac
->controls
[i
]->oid
= talloc_strdup(ac
->controls
[i
],
201 LDB_CONTROL_PAGED_RESULTS_OID
);
202 if (ac
->controls
[i
]->oid
== NULL
) {
203 return LDB_ERR_OPERATIONS_ERROR
;
206 ac
->controls
[i
]->critical
= 0;
208 paged
= talloc(ac
->controls
[i
], struct ldb_paged_control
);
210 return LDB_ERR_OPERATIONS_ERROR
;
213 ac
->controls
[i
]->data
= paged
;
217 paged
->cookie
= NULL
;
218 paged
->cookie_len
= 0;
220 paged
->size
= ac
->store
->num_entries
;
221 paged
->cookie
= talloc_strdup(paged
, ac
->store
->cookie
);
222 paged
->cookie_len
= strlen(paged
->cookie
) + 1;
228 static int paged_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
230 struct paged_context
*ac
;
231 struct message_store
*msg_store
;
234 ac
= talloc_get_type(req
->context
, struct paged_context
);
237 return ldb_module_done(ac
->req
, NULL
, NULL
,
238 LDB_ERR_OPERATIONS_ERROR
);
240 if (ares
->error
!= LDB_SUCCESS
) {
241 return ldb_module_done(ac
->req
, ares
->controls
,
242 ares
->response
, ares
->error
);
245 switch (ares
->type
) {
246 case LDB_REPLY_ENTRY
:
247 msg_store
= talloc(ac
->store
, struct message_store
);
248 if (msg_store
== NULL
) {
249 return ldb_module_done(ac
->req
, NULL
, NULL
,
250 LDB_ERR_OPERATIONS_ERROR
);
252 msg_store
->next
= NULL
;
253 msg_store
->r
= talloc_steal(msg_store
, ares
);
255 if (ac
->store
->first
== NULL
) {
256 ac
->store
->first
= msg_store
;
258 ac
->store
->last
->next
= msg_store
;
260 ac
->store
->last
= msg_store
;
262 ac
->store
->num_entries
++;
266 case LDB_REPLY_REFERRAL
:
267 msg_store
= talloc(ac
->store
, struct message_store
);
268 if (msg_store
== NULL
) {
269 return ldb_module_done(ac
->req
, NULL
, NULL
,
270 LDB_ERR_OPERATIONS_ERROR
);
272 msg_store
->next
= NULL
;
273 msg_store
->r
= talloc_steal(msg_store
, ares
);
275 if (ac
->store
->first_ref
== NULL
) {
276 ac
->store
->first_ref
= msg_store
;
278 ac
->store
->last_ref
->next
= msg_store
;
280 ac
->store
->last_ref
= msg_store
;
285 ac
->store
->controls
= talloc_move(ac
->store
, &ares
->controls
);
286 ret
= paged_results(ac
);
287 return ldb_module_done(ac
->req
, ac
->controls
,
288 ares
->response
, ret
);
294 static int paged_search(struct ldb_module
*module
, struct ldb_request
*req
)
296 struct ldb_context
*ldb
;
297 struct ldb_control
*control
;
298 struct private_data
*private_data
;
299 struct ldb_paged_control
*paged_ctrl
;
300 struct ldb_control
**saved_controls
;
301 struct ldb_request
*search_req
;
302 struct paged_context
*ac
;
305 ldb
= ldb_module_get_ctx(module
);
307 /* check if there's a paged request control */
308 control
= ldb_request_get_control(req
, LDB_CONTROL_PAGED_RESULTS_OID
);
309 if (control
== NULL
) {
310 /* not found go on */
311 return ldb_next_request(module
, req
);
314 paged_ctrl
= talloc_get_type(control
->data
, struct ldb_paged_control
);
316 return LDB_ERR_PROTOCOL_ERROR
;
319 private_data
= talloc_get_type(ldb_module_get_private(module
),
320 struct private_data
);
322 ac
= talloc_zero(req
, struct paged_context
);
324 ldb_set_errstring(ldb
, "Out of Memory");
325 return LDB_ERR_OPERATIONS_ERROR
;
330 ac
->size
= paged_ctrl
->size
;
332 /* apparently some clients send more than 2^31. This
333 violates the ldap standard, but we need to cope */
334 ac
->size
= 0x7FFFFFFF;
337 /* check if it is a continuation search the store */
338 if (paged_ctrl
->cookie_len
== 0) {
339 if (paged_ctrl
->size
== 0) {
340 return LDB_ERR_OPERATIONS_ERROR
;
343 ac
->store
= new_store(private_data
);
344 if (ac
->store
== NULL
) {
345 return LDB_ERR_OPERATIONS_ERROR
;
348 ret
= ldb_build_search_req_ex(&search_req
, ldb
, ac
,
350 req
->op
.search
.scope
,
352 req
->op
.search
.attrs
,
355 paged_search_callback
,
357 if (ret
!= LDB_SUCCESS
) {
361 /* save it locally and remove it from the list */
362 /* we do not need to replace them later as we
363 * are keeping the original req intact */
364 if (!ldb_save_controls(control
, search_req
, &saved_controls
)) {
365 return LDB_ERR_OPERATIONS_ERROR
;
368 return ldb_next_request(module
, search_req
);
371 struct results_store
*current
= NULL
;
373 /* TODO: age out old outstanding requests */
374 for (current
= private_data
->store
; current
; current
= current
->next
) {
375 if (strcmp(current
->cookie
, paged_ctrl
->cookie
) == 0) {
376 current
->timestamp
= time(NULL
);
380 if (current
== NULL
) {
381 return LDB_ERR_UNWILLING_TO_PERFORM
;
386 /* check if it is an abandon */
388 return ldb_module_done(req
, NULL
, NULL
,
392 ret
= paged_results(ac
);
393 if (ret
!= LDB_SUCCESS
) {
394 return ldb_module_done(req
, NULL
, NULL
, ret
);
396 return ldb_module_done(req
, ac
->controls
, NULL
,
401 static int paged_request_init(struct ldb_module
*module
)
403 struct ldb_context
*ldb
;
404 struct private_data
*data
;
407 ldb
= ldb_module_get_ctx(module
);
409 data
= talloc(module
, struct private_data
);
411 return LDB_ERR_OTHER
;
414 data
->next_free_id
= 1;
416 ldb_module_set_private(module
, data
);
418 ret
= ldb_mod_register_control(module
, LDB_CONTROL_PAGED_RESULTS_OID
);
419 if (ret
!= LDB_SUCCESS
) {
420 ldb_debug(ldb
, LDB_DEBUG_WARNING
,
422 "Unable to register control with rootdse!");
425 return ldb_next_init(module
);
428 static const struct ldb_module_ops ldb_paged_results_module_ops
= {
429 .name
= "paged_results",
430 .search
= paged_search
,
431 .init_context
= paged_request_init
434 int ldb_paged_results_init(const char *version
)
436 LDB_MODULE_CHECK_VERSION(version
);
437 return ldb_register_module(&ldb_paged_results_module_ops
);