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_ws_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_ws_query.h"
45 #include "singletons.h"
47 static int on_mp_write_session_abandon_notification(struct query_state
*);
48 static int on_mp_write_session_close_notification(struct query_state
*);
49 static void on_mp_write_session_destroy(struct query_state
*);
50 static int on_mp_write_session_mapper(struct query_state
*);
51 /* int on_mp_write_session_request_read1(struct query_state *); */
52 static int on_mp_write_session_request_read2(struct query_state
*);
53 static int on_mp_write_session_request_process(struct query_state
*);
54 static int on_mp_write_session_response_write1(struct query_state
*);
55 static int on_mp_write_session_write_request_read1(struct query_state
*);
56 static int on_mp_write_session_write_request_read2(struct query_state
*);
57 static int on_mp_write_session_write_request_process(struct query_state
*);
58 static int on_mp_write_session_write_response_write1(struct query_state
*);
61 * This function is used as the query_state's destroy_func to make the
62 * proper cleanup in case of errors.
65 on_mp_write_session_destroy(struct query_state
*qstate
)
68 TRACE_IN(on_mp_write_session_destroy
);
69 finalize_comm_element(&qstate
->request
);
70 finalize_comm_element(&qstate
->response
);
72 if (qstate
->mdata
!= NULL
) {
73 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
74 abandon_cache_mp_write_session(
75 (cache_mp_write_session
)qstate
->mdata
);
76 configuration_unlock_entry(qstate
->config_entry
,
79 TRACE_OUT(on_mp_write_session_destroy
);
83 * The functions below are used to process multipart write session initiation
85 * - on_mp_write_session_request_read1 and on_mp_write_session_request_read2
86 * read the request itself
87 * - on_mp_write_session_request_process processes it
88 * - on_mp_write_session_response_write1 sends the response
91 on_mp_write_session_request_read1(struct query_state
*qstate
)
93 struct cache_mp_write_session_request
*c_mp_ws_request
;
96 TRACE_IN(on_mp_write_session_request_read1
);
97 if (qstate
->kevent_watermark
== 0)
98 qstate
->kevent_watermark
= sizeof(size_t);
100 init_comm_element(&qstate
->request
,
101 CET_MP_WRITE_SESSION_REQUEST
);
102 c_mp_ws_request
= get_cache_mp_write_session_request(
105 result
= qstate
->read_func(qstate
,
106 &c_mp_ws_request
->entry_length
, sizeof(size_t));
108 if (result
!= sizeof(size_t)) {
109 LOG_ERR_3("on_mp_write_session_request_read1",
111 TRACE_OUT(on_mp_write_session_request_read1
);
115 if (BUFSIZE_INVALID(c_mp_ws_request
->entry_length
)) {
116 LOG_ERR_3("on_mp_write_session_request_read1",
117 "invalid entry_length value");
118 TRACE_OUT(on_mp_write_session_request_read1
);
122 c_mp_ws_request
->entry
= (char *)calloc(1,
123 c_mp_ws_request
->entry_length
+ 1);
124 assert(c_mp_ws_request
->entry
!= NULL
);
126 qstate
->kevent_watermark
= c_mp_ws_request
->entry_length
;
127 qstate
->process_func
= on_mp_write_session_request_read2
;
129 TRACE_OUT(on_mp_write_session_request_read1
);
134 on_mp_write_session_request_read2(struct query_state
*qstate
)
136 struct cache_mp_write_session_request
*c_mp_ws_request
;
139 TRACE_IN(on_mp_write_session_request_read2
);
140 c_mp_ws_request
= get_cache_mp_write_session_request(&qstate
->request
);
142 result
= qstate
->read_func(qstate
, c_mp_ws_request
->entry
,
143 c_mp_ws_request
->entry_length
);
145 if (result
!= qstate
->kevent_watermark
) {
146 LOG_ERR_3("on_mp_write_session_request_read2",
148 TRACE_OUT(on_mp_write_session_request_read2
);
152 qstate
->kevent_watermark
= 0;
153 qstate
->process_func
= on_mp_write_session_request_process
;
155 TRACE_OUT(on_mp_write_session_request_read2
);
160 on_mp_write_session_request_process(struct query_state
*qstate
)
162 struct cache_mp_write_session_request
*c_mp_ws_request
;
163 struct cache_mp_write_session_response
*c_mp_ws_response
;
164 cache_mp_write_session ws
;
166 char *dec_cache_entry_name
;
168 TRACE_IN(on_mp_write_session_request_process
);
169 init_comm_element(&qstate
->response
, CET_MP_WRITE_SESSION_RESPONSE
);
170 c_mp_ws_response
= get_cache_mp_write_session_response(
172 c_mp_ws_request
= get_cache_mp_write_session_request(&qstate
->request
);
174 qstate
->config_entry
= configuration_find_entry(
175 s_configuration
, c_mp_ws_request
->entry
);
176 if (qstate
->config_entry
== NULL
) {
177 c_mp_ws_response
->error_code
= ENOENT
;
179 LOG_ERR_2("write_session_request",
180 "can't find configuration entry '%s'. "
181 "aborting request", c_mp_ws_request
->entry
);
185 if (qstate
->config_entry
->enabled
== 0) {
186 c_mp_ws_response
->error_code
= EACCES
;
188 LOG_ERR_2("write_session_request",
189 "configuration entry '%s' is disabled",
190 c_mp_ws_request
->entry
);
194 if (qstate
->config_entry
->perform_actual_lookups
!= 0) {
195 c_mp_ws_response
->error_code
= EOPNOTSUPP
;
197 LOG_ERR_2("write_session_request",
198 "entry '%s' performs lookups by itself: "
199 "can't write to it", c_mp_ws_request
->entry
);
202 #ifdef NS_NSCD_EID_CHECKING
203 if (check_query_eids(qstate
) != 0) {
204 c_mp_ws_response
->error_code
= EPERM
;
211 * All multipart entries are separated by their name decorations.
212 * For one configuration entry there will be a lot of multipart
213 * cache entries - each with its own decorated name.
215 asprintf(&dec_cache_entry_name
, "%s%s", qstate
->eid_str
,
216 qstate
->config_entry
->mp_cache_params
.entry_name
);
217 assert(dec_cache_entry_name
!= NULL
);
219 configuration_lock_rdlock(s_configuration
);
220 c_entry
= find_cache_entry(s_cache
,
221 dec_cache_entry_name
);
222 configuration_unlock(s_configuration
);
224 if (c_entry
== INVALID_CACHE_ENTRY
)
225 c_entry
= register_new_mp_cache_entry(qstate
,
226 dec_cache_entry_name
);
228 free(dec_cache_entry_name
);
230 assert(c_entry
!= NULL
);
231 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
232 ws
= open_cache_mp_write_session(c_entry
);
233 if (ws
== INVALID_CACHE_MP_WRITE_SESSION
)
234 c_mp_ws_response
->error_code
= -1;
237 qstate
->destroy_func
= on_mp_write_session_destroy
;
239 if ((qstate
->config_entry
->mp_query_timeout
.tv_sec
!= 0) ||
240 (qstate
->config_entry
->mp_query_timeout
.tv_usec
!= 0))
241 memcpy(&qstate
->timeout
,
242 &qstate
->config_entry
->mp_query_timeout
,
243 sizeof(struct timeval
));
245 configuration_unlock_entry(qstate
->config_entry
, CELT_MULTIPART
);
248 qstate
->process_func
= on_mp_write_session_response_write1
;
249 qstate
->kevent_watermark
= sizeof(int);
250 qstate
->kevent_filter
= EVFILT_WRITE
;
252 TRACE_OUT(on_mp_write_session_request_process
);
257 on_mp_write_session_response_write1(struct query_state
*qstate
)
259 struct cache_mp_write_session_response
*c_mp_ws_response
;
262 TRACE_IN(on_mp_write_session_response_write1
);
263 c_mp_ws_response
= get_cache_mp_write_session_response(
265 result
= qstate
->write_func(qstate
, &c_mp_ws_response
->error_code
,
267 if (result
!= sizeof(int)) {
268 LOG_ERR_3("on_mp_write_session_response_write1",
270 TRACE_OUT(on_mp_write_session_response_write1
);
274 if (c_mp_ws_response
->error_code
== 0) {
275 qstate
->kevent_watermark
= sizeof(int);
276 qstate
->process_func
= on_mp_write_session_mapper
;
277 qstate
->kevent_filter
= EVFILT_READ
;
279 qstate
->kevent_watermark
= 0;
280 qstate
->process_func
= NULL
;
282 TRACE_OUT(on_mp_write_session_response_write1
);
287 * Mapper function is used to avoid multiple connections for each session
288 * write or read requests. After processing the request, it does not close
289 * the connection, but waits for the next request.
292 on_mp_write_session_mapper(struct query_state
*qstate
)
297 TRACE_IN(on_mp_write_session_mapper
);
298 if (qstate
->kevent_watermark
== 0) {
299 qstate
->kevent_watermark
= sizeof(int);
301 result
= qstate
->read_func(qstate
, &elem_type
, sizeof(int));
302 if (result
!= sizeof(int)) {
303 LOG_ERR_3("on_mp_write_session_mapper",
305 TRACE_OUT(on_mp_write_session_mapper
);
310 case CET_MP_WRITE_SESSION_WRITE_REQUEST
:
311 qstate
->kevent_watermark
= sizeof(size_t);
312 qstate
->process_func
=
313 on_mp_write_session_write_request_read1
;
315 case CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION
:
316 qstate
->kevent_watermark
= 0;
317 qstate
->process_func
=
318 on_mp_write_session_abandon_notification
;
320 case CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION
:
321 qstate
->kevent_watermark
= 0;
322 qstate
->process_func
=
323 on_mp_write_session_close_notification
;
326 qstate
->kevent_watermark
= 0;
327 qstate
->process_func
= NULL
;
328 LOG_ERR_2("on_mp_write_session_mapper",
329 "unknown element type");
330 TRACE_OUT(on_mp_write_session_mapper
);
334 TRACE_OUT(on_mp_write_session_mapper
);
339 * The functions below are used to process multipart write sessions write
341 * - on_mp_write_session_write_request_read1 and
342 * on_mp_write_session_write_request_read2 read the request itself
343 * - on_mp_write_session_write_request_process processes it
344 * - on_mp_write_session_write_response_write1 sends the response
347 on_mp_write_session_write_request_read1(struct query_state
*qstate
)
349 struct cache_mp_write_session_write_request
*write_request
;
352 TRACE_IN(on_mp_write_session_write_request_read1
);
353 init_comm_element(&qstate
->request
,
354 CET_MP_WRITE_SESSION_WRITE_REQUEST
);
355 write_request
= get_cache_mp_write_session_write_request(
358 result
= qstate
->read_func(qstate
, &write_request
->data_size
,
361 if (result
!= sizeof(size_t)) {
362 LOG_ERR_3("on_mp_write_session_write_request_read1",
364 TRACE_OUT(on_mp_write_session_write_request_read1
);
368 if (BUFSIZE_INVALID(write_request
->data_size
)) {
369 LOG_ERR_3("on_mp_write_session_write_request_read1",
370 "invalid data_size value");
371 TRACE_OUT(on_mp_write_session_write_request_read1
);
375 write_request
->data
= (char *)calloc(1, write_request
->data_size
);
376 assert(write_request
->data
!= NULL
);
378 qstate
->kevent_watermark
= write_request
->data_size
;
379 qstate
->process_func
= on_mp_write_session_write_request_read2
;
380 TRACE_OUT(on_mp_write_session_write_request_read1
);
385 on_mp_write_session_write_request_read2(struct query_state
*qstate
)
387 struct cache_mp_write_session_write_request
*write_request
;
390 TRACE_IN(on_mp_write_session_write_request_read2
);
391 write_request
= get_cache_mp_write_session_write_request(
394 result
= qstate
->read_func(qstate
, write_request
->data
,
395 write_request
->data_size
);
397 if (result
!= qstate
->kevent_watermark
) {
398 LOG_ERR_3("on_mp_write_session_write_request_read2",
400 TRACE_OUT(on_mp_write_session_write_request_read2
);
404 qstate
->kevent_watermark
= 0;
405 qstate
->process_func
= on_mp_write_session_write_request_process
;
406 TRACE_OUT(on_mp_write_session_write_request_read2
);
411 on_mp_write_session_write_request_process(struct query_state
*qstate
)
413 struct cache_mp_write_session_write_request
*write_request
;
414 struct cache_mp_write_session_write_response
*write_response
;
416 TRACE_IN(on_mp_write_session_write_request_process
);
417 init_comm_element(&qstate
->response
,
418 CET_MP_WRITE_SESSION_WRITE_RESPONSE
);
419 write_response
= get_cache_mp_write_session_write_response(
421 write_request
= get_cache_mp_write_session_write_request(
424 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
425 write_response
->error_code
= cache_mp_write(
426 (cache_mp_write_session
)qstate
->mdata
,
428 write_request
->data_size
);
429 configuration_unlock_entry(qstate
->config_entry
, CELT_MULTIPART
);
431 qstate
->kevent_watermark
= sizeof(int);
432 qstate
->process_func
= on_mp_write_session_write_response_write1
;
433 qstate
->kevent_filter
= EVFILT_WRITE
;
435 TRACE_OUT(on_mp_write_session_write_request_process
);
440 on_mp_write_session_write_response_write1(struct query_state
*qstate
)
442 struct cache_mp_write_session_write_response
*write_response
;
445 TRACE_IN(on_mp_write_session_write_response_write1
);
446 write_response
= get_cache_mp_write_session_write_response(
448 result
= qstate
->write_func(qstate
, &write_response
->error_code
,
450 if (result
!= sizeof(int)) {
451 LOG_ERR_3("on_mp_write_session_write_response_write1",
453 TRACE_OUT(on_mp_write_session_write_response_write1
);
457 if (write_response
->error_code
== 0) {
458 finalize_comm_element(&qstate
->request
);
459 finalize_comm_element(&qstate
->response
);
461 qstate
->kevent_watermark
= sizeof(int);
462 qstate
->process_func
= on_mp_write_session_mapper
;
463 qstate
->kevent_filter
= EVFILT_READ
;
465 qstate
->kevent_watermark
= 0;
466 qstate
->process_func
= 0;
469 TRACE_OUT(on_mp_write_session_write_response_write1
);
474 * Handles abandon notifications. Destroys the session by calling the
475 * abandon_cache_mp_write_session.
478 on_mp_write_session_abandon_notification(struct query_state
*qstate
)
480 TRACE_IN(on_mp_write_session_abandon_notification
);
481 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
482 abandon_cache_mp_write_session((cache_mp_write_session
)qstate
->mdata
);
483 configuration_unlock_entry(qstate
->config_entry
, CELT_MULTIPART
);
484 qstate
->mdata
= INVALID_CACHE_MP_WRITE_SESSION
;
486 qstate
->kevent_watermark
= 0;
487 qstate
->process_func
= NULL
;
488 TRACE_OUT(on_mp_write_session_abandon_notification
);
493 * Handles close notifications. Commits the session by calling
494 * the close_cache_mp_write_session.
497 on_mp_write_session_close_notification(struct query_state
*qstate
)
499 TRACE_IN(on_mp_write_session_close_notification
);
500 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
501 close_cache_mp_write_session((cache_mp_write_session
)qstate
->mdata
);
502 configuration_unlock_entry(qstate
->config_entry
, CELT_MULTIPART
);
503 qstate
->mdata
= INVALID_CACHE_MP_WRITE_SESSION
;
505 qstate
->kevent_watermark
= 0;
506 qstate
->process_func
= NULL
;
507 TRACE_OUT(on_mp_write_session_close_notification
);
511 cache_entry
register_new_mp_cache_entry(struct query_state
*qstate
,
512 const char *dec_cache_entry_name
)
517 TRACE_IN(register_new_mp_cache_entry
);
518 c_entry
= INVALID_CACHE_ENTRY
;
519 configuration_lock_entry(qstate
->config_entry
, CELT_MULTIPART
);
521 configuration_lock_wrlock(s_configuration
);
522 en_bkp
= qstate
->config_entry
->mp_cache_params
.entry_name
;
523 qstate
->config_entry
->mp_cache_params
.entry_name
=
524 (char *)dec_cache_entry_name
;
525 register_cache_entry(s_cache
, (struct cache_entry_params
*)
526 &qstate
->config_entry
->mp_cache_params
);
527 qstate
->config_entry
->mp_cache_params
.entry_name
= en_bkp
;
528 configuration_unlock(s_configuration
);
530 configuration_lock_rdlock(s_configuration
);
531 c_entry
= find_cache_entry(s_cache
,
532 dec_cache_entry_name
);
533 configuration_unlock(s_configuration
);
535 configuration_entry_add_mp_cache_entry(qstate
->config_entry
,
538 configuration_unlock_entry(qstate
->config_entry
,
541 TRACE_OUT(register_new_mp_cache_entry
);