2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.sbin/nscd/mp_rs_query.c,v 1.4 2008/10/12 00:44:27 delphij Exp $
29 #include <sys/socket.h>
31 #include <sys/types.h>
32 #include <sys/event.h>
44 #include "mp_rs_query.h"
45 #include "mp_ws_query.h"
46 #include "singletons.h"
48 static int on_mp_read_session_close_notification(struct query_state
*);
49 static void on_mp_read_session_destroy(struct query_state
*);
50 static int on_mp_read_session_mapper(struct query_state
*);
51 /* int on_mp_read_session_request_read1(struct query_state *); */
52 static int on_mp_read_session_request_read2(struct query_state
*);
53 static int on_mp_read_session_request_process(struct query_state
*);
54 static int on_mp_read_session_response_write1(struct query_state
*);
55 static int on_mp_read_session_read_request_process(struct query_state
*);
56 static int on_mp_read_session_read_response_write1(struct query_state
*);
57 static int on_mp_read_session_read_response_write2(struct query_state
*);
60 * This function is used as the query_state's destroy_func to make the
61 * proper cleanup in case of errors.
64 on_mp_read_session_destroy(struct query_state
*qstate
)
66 TRACE_IN(on_mp_read_session_destroy
);
67 finalize_comm_element(&qstate
->request
);
68 finalize_comm_element(&qstate
->response
);
70 if (qstate
->mdata
!= NULL
) {
71 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
72 close_cache_mp_read_session(
73 (cache_mp_read_session
)qstate
->mdata
);
74 configuration_unlock_entry(qstate
->config_entry
,
77 TRACE_OUT(on_mp_read_session_destroy
);
81 * The functions below are used to process multipart read session initiation
83 * - on_mp_read_session_request_read1 and on_mp_read_session_request_read2 read
85 * - on_mp_read_session_request_process processes it
86 * - on_mp_read_session_response_write1 sends the response
89 on_mp_read_session_request_read1(struct query_state
*qstate
)
91 struct cache_mp_read_session_request
*c_mp_rs_request
;
94 TRACE_IN(on_mp_read_session_request_read1
);
95 if (qstate
->kevent_watermark
== 0)
96 qstate
->kevent_watermark
= sizeof(size_t);
98 init_comm_element(&qstate
->request
,
99 CET_MP_READ_SESSION_REQUEST
);
100 c_mp_rs_request
= get_cache_mp_read_session_request(
103 result
= qstate
->read_func(qstate
,
104 &c_mp_rs_request
->entry_length
, sizeof(size_t));
106 if (result
!= sizeof(size_t)) {
107 TRACE_OUT(on_mp_read_session_request_read1
);
111 if (BUFSIZE_INVALID(c_mp_rs_request
->entry_length
)) {
112 TRACE_OUT(on_mp_read_session_request_read1
);
116 c_mp_rs_request
->entry
= (char *)calloc(1,
117 c_mp_rs_request
->entry_length
+ 1);
118 assert(c_mp_rs_request
->entry
!= NULL
);
120 qstate
->kevent_watermark
= c_mp_rs_request
->entry_length
;
121 qstate
->process_func
= on_mp_read_session_request_read2
;
123 TRACE_OUT(on_mp_read_session_request_read1
);
128 on_mp_read_session_request_read2(struct query_state
*qstate
)
130 struct cache_mp_read_session_request
*c_mp_rs_request
;
133 TRACE_IN(on_mp_read_session_request_read2
);
134 c_mp_rs_request
= get_cache_mp_read_session_request(&qstate
->request
);
136 result
= qstate
->read_func(qstate
, c_mp_rs_request
->entry
,
137 c_mp_rs_request
->entry_length
);
139 if (result
!= qstate
->kevent_watermark
) {
140 LOG_ERR_3("on_mp_read_session_request_read2",
142 TRACE_OUT(on_mp_read_session_request_read2
);
146 qstate
->kevent_watermark
= 0;
147 qstate
->process_func
= on_mp_read_session_request_process
;
148 TRACE_OUT(on_mp_read_session_request_read2
);
153 on_mp_read_session_request_process(struct query_state
*qstate
)
155 struct cache_mp_read_session_request
*c_mp_rs_request
;
156 struct cache_mp_read_session_response
*c_mp_rs_response
;
157 cache_mp_read_session rs
;
159 char *dec_cache_entry_name
;
163 cache_mp_write_session ws
;
164 struct agent
*lookup_agent
;
165 struct multipart_agent
*mp_agent
;
169 TRACE_IN(on_mp_read_session_request_process
);
170 init_comm_element(&qstate
->response
, CET_MP_READ_SESSION_RESPONSE
);
171 c_mp_rs_response
= get_cache_mp_read_session_response(
173 c_mp_rs_request
= get_cache_mp_read_session_request(&qstate
->request
);
175 qstate
->config_entry
= configuration_find_entry(
176 s_configuration
, c_mp_rs_request
->entry
);
177 if (qstate
->config_entry
== NULL
) {
178 c_mp_rs_response
->error_code
= ENOENT
;
180 LOG_ERR_2("read_session_request",
181 "can't find configuration entry '%s'."
182 " aborting request", c_mp_rs_request
->entry
);
186 if (qstate
->config_entry
->enabled
== 0) {
187 c_mp_rs_response
->error_code
= EACCES
;
189 LOG_ERR_2("read_session_request",
190 "configuration entry '%s' is disabled",
191 c_mp_rs_request
->entry
);
195 if (qstate
->config_entry
->perform_actual_lookups
!= 0)
196 dec_cache_entry_name
= strdup(
197 qstate
->config_entry
->mp_cache_params
.entry_name
);
199 #ifdef NS_NSCD_EID_CHECKING
200 if (check_query_eids(qstate
) != 0) {
201 c_mp_rs_response
->error_code
= EPERM
;
206 asprintf(&dec_cache_entry_name
, "%s%s", qstate
->eid_str
,
207 qstate
->config_entry
->mp_cache_params
.entry_name
);
210 assert(dec_cache_entry_name
!= NULL
);
212 configuration_lock_rdlock(s_configuration
);
213 c_entry
= find_cache_entry(s_cache
, dec_cache_entry_name
);
214 configuration_unlock(s_configuration
);
216 if ((c_entry
== INVALID_CACHE
) &&
217 (qstate
->config_entry
->perform_actual_lookups
!= 0))
218 c_entry
= register_new_mp_cache_entry(qstate
,
219 dec_cache_entry_name
);
221 free(dec_cache_entry_name
);
223 if (c_entry
!= INVALID_CACHE_ENTRY
) {
224 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
225 rs
= open_cache_mp_read_session(c_entry
);
226 configuration_unlock_entry(qstate
->config_entry
,
229 if ((rs
== INVALID_CACHE_MP_READ_SESSION
) &&
230 (qstate
->config_entry
->perform_actual_lookups
!= 0)) {
231 lookup_agent
= find_agent(s_agent_table
,
232 c_mp_rs_request
->entry
, MULTIPART_AGENT
);
234 if ((lookup_agent
!= NULL
) &&
235 (lookup_agent
->type
== MULTIPART_AGENT
)) {
236 mp_agent
= (struct multipart_agent
*)
238 mdata
= mp_agent
->mp_init_func();
241 * Multipart agents read the whole snapshot
242 * of the data at one time.
244 configuration_lock_entry(qstate
->config_entry
,
246 ws
= open_cache_mp_write_session(c_entry
);
247 configuration_unlock_entry(qstate
->config_entry
,
252 res
= mp_agent
->mp_lookup_func(&buffer
,
256 if ((res
& NS_TERMINATE
) &&
258 configuration_lock_entry(
259 qstate
->config_entry
,
261 if (cache_mp_write(ws
, buffer
,
263 abandon_cache_mp_write_session(ws
);
266 configuration_unlock_entry(
267 qstate
->config_entry
,
273 configuration_lock_entry(
274 qstate
->config_entry
,
276 close_cache_mp_write_session(ws
);
277 configuration_unlock_entry(
278 qstate
->config_entry
,
284 } while ((res
& NS_TERMINATE
) &&
288 configuration_lock_entry(qstate
->config_entry
,
290 rs
= open_cache_mp_read_session(c_entry
);
291 configuration_unlock_entry(qstate
->config_entry
,
296 if (rs
== INVALID_CACHE_MP_READ_SESSION
)
297 c_mp_rs_response
->error_code
= -1;
300 qstate
->destroy_func
= on_mp_read_session_destroy
;
302 configuration_lock_entry(qstate
->config_entry
,
304 if ((qstate
->config_entry
->mp_query_timeout
.tv_sec
!= 0) ||
305 (qstate
->config_entry
->mp_query_timeout
.tv_usec
!= 0))
306 memcpy(&qstate
->timeout
,
307 &qstate
->config_entry
->mp_query_timeout
,
308 sizeof(struct timeval
));
309 configuration_unlock_entry(qstate
->config_entry
,
313 c_mp_rs_response
->error_code
= -1;
316 qstate
->process_func
= on_mp_read_session_response_write1
;
317 qstate
->kevent_watermark
= sizeof(int);
318 qstate
->kevent_filter
= EVFILT_WRITE
;
320 TRACE_OUT(on_mp_read_session_request_process
);
325 on_mp_read_session_response_write1(struct query_state
*qstate
)
327 struct cache_mp_read_session_response
*c_mp_rs_response
;
330 TRACE_IN(on_mp_read_session_response_write1
);
331 c_mp_rs_response
= get_cache_mp_read_session_response(
333 result
= qstate
->write_func(qstate
, &c_mp_rs_response
->error_code
,
336 if (result
!= sizeof(int)) {
337 LOG_ERR_3("on_mp_read_session_response_write1",
339 TRACE_OUT(on_mp_read_session_response_write1
);
343 if (c_mp_rs_response
->error_code
== 0) {
344 qstate
->kevent_watermark
= sizeof(int);
345 qstate
->process_func
= on_mp_read_session_mapper
;
346 qstate
->kevent_filter
= EVFILT_READ
;
348 qstate
->kevent_watermark
= 0;
349 qstate
->process_func
= NULL
;
351 TRACE_OUT(on_mp_read_session_response_write1
);
356 * Mapper function is used to avoid multiple connections for each session
357 * write or read requests. After processing the request, it does not close
358 * the connection, but waits for the next request.
361 on_mp_read_session_mapper(struct query_state
*qstate
)
366 TRACE_IN(on_mp_read_session_mapper
);
367 if (qstate
->kevent_watermark
== 0) {
368 qstate
->kevent_watermark
= sizeof(int);
370 result
= qstate
->read_func(qstate
, &elem_type
, sizeof(int));
371 if (result
!= sizeof(int)) {
372 LOG_ERR_3("on_mp_read_session_mapper",
374 TRACE_OUT(on_mp_read_session_mapper
);
379 case CET_MP_READ_SESSION_READ_REQUEST
:
380 qstate
->kevent_watermark
= 0;
381 qstate
->process_func
=
382 on_mp_read_session_read_request_process
;
384 case CET_MP_READ_SESSION_CLOSE_NOTIFICATION
:
385 qstate
->kevent_watermark
= 0;
386 qstate
->process_func
=
387 on_mp_read_session_close_notification
;
390 qstate
->kevent_watermark
= 0;
391 qstate
->process_func
= NULL
;
392 LOG_ERR_3("on_mp_read_session_mapper",
393 "unknown element type");
394 TRACE_OUT(on_mp_read_session_mapper
);
398 TRACE_OUT(on_mp_read_session_mapper
);
403 * The functions below are used to process multipart read sessions read
404 * requests. User doesn't have to pass any kind of data, besides the
405 * request identificator itself. So we don't need any XXX_read functions and
406 * start with the XXX_process function.
407 * - on_mp_read_session_read_request_process processes it
408 * - on_mp_read_session_read_response_write1 and
409 * on_mp_read_session_read_response_write2 sends the response
412 on_mp_read_session_read_request_process(struct query_state
*qstate
)
414 struct cache_mp_read_session_read_response
*read_response
;
416 TRACE_IN(on_mp_read_session_response_process
);
417 init_comm_element(&qstate
->response
, CET_MP_READ_SESSION_READ_RESPONSE
);
418 read_response
= get_cache_mp_read_session_read_response(
421 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
422 read_response
->error_code
= cache_mp_read(
423 (cache_mp_read_session
)qstate
->mdata
, NULL
,
424 &read_response
->data_size
);
426 if (read_response
->error_code
== 0) {
427 read_response
->data
= (char *)malloc(read_response
->data_size
);
428 assert(read_response
!= NULL
);
429 read_response
->error_code
= cache_mp_read(
430 (cache_mp_read_session
)qstate
->mdata
,
432 &read_response
->data_size
);
434 configuration_unlock_entry(qstate
->config_entry
, CELT_MULTIPART
);
436 if (read_response
->error_code
== 0)
437 qstate
->kevent_watermark
= sizeof(size_t) + sizeof(int);
439 qstate
->kevent_watermark
= sizeof(int);
440 qstate
->process_func
= on_mp_read_session_read_response_write1
;
441 qstate
->kevent_filter
= EVFILT_WRITE
;
443 TRACE_OUT(on_mp_read_session_response_process
);
448 on_mp_read_session_read_response_write1(struct query_state
*qstate
)
450 struct cache_mp_read_session_read_response
*read_response
;
453 TRACE_IN(on_mp_read_session_read_response_write1
);
454 read_response
= get_cache_mp_read_session_read_response(
457 result
= qstate
->write_func(qstate
, &read_response
->error_code
,
459 if (read_response
->error_code
== 0) {
460 result
+= qstate
->write_func(qstate
, &read_response
->data_size
,
462 if (result
!= qstate
->kevent_watermark
) {
463 TRACE_OUT(on_mp_read_session_read_response_write1
);
464 LOG_ERR_3("on_mp_read_session_read_response_write1",
469 qstate
->kevent_watermark
= read_response
->data_size
;
470 qstate
->process_func
= on_mp_read_session_read_response_write2
;
472 if (result
!= qstate
->kevent_watermark
) {
473 LOG_ERR_3("on_mp_read_session_read_response_write1",
475 TRACE_OUT(on_mp_read_session_read_response_write1
);
479 qstate
->kevent_watermark
= 0;
480 qstate
->process_func
= NULL
;
483 TRACE_OUT(on_mp_read_session_read_response_write1
);
488 on_mp_read_session_read_response_write2(struct query_state
*qstate
)
490 struct cache_mp_read_session_read_response
*read_response
;
493 TRACE_IN(on_mp_read_session_read_response_write2
);
494 read_response
= get_cache_mp_read_session_read_response(
496 result
= qstate
->write_func(qstate
, read_response
->data
,
497 read_response
->data_size
);
498 if (result
!= qstate
->kevent_watermark
) {
499 LOG_ERR_3("on_mp_read_session_read_response_write2",
501 TRACE_OUT(on_mp_read_session_read_response_write2
);
505 finalize_comm_element(&qstate
->request
);
506 finalize_comm_element(&qstate
->response
);
508 qstate
->kevent_watermark
= sizeof(int);
509 qstate
->process_func
= on_mp_read_session_mapper
;
510 qstate
->kevent_filter
= EVFILT_READ
;
512 TRACE_OUT(on_mp_read_session_read_response_write2
);
517 * Handles session close notification by calling close_cache_mp_read_session
521 on_mp_read_session_close_notification(struct query_state
*qstate
)
524 TRACE_IN(on_mp_read_session_close_notification
);
525 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
526 close_cache_mp_read_session((cache_mp_read_session
)qstate
->mdata
);
527 configuration_unlock_entry(qstate
->config_entry
, CELT_MULTIPART
);
528 qstate
->mdata
= NULL
;
529 qstate
->kevent_watermark
= 0;
530 qstate
->process_func
= NULL
;
531 TRACE_OUT(on_mp_read_session_close_notification
);