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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/socket.h>
33 #include <sys/types.h>
34 #include <sys/event.h>
46 #include "mp_ws_query.h"
47 #include "singletons.h"
49 static int on_mp_write_session_abandon_notification(struct query_state *);
50 static int on_mp_write_session_close_notification(struct query_state *);
51 static void on_mp_write_session_destroy(struct query_state *);
52 static int on_mp_write_session_mapper(struct query_state *);
53 /* int on_mp_write_session_request_read1(struct query_state *); */
54 static int on_mp_write_session_request_read2(struct query_state *);
55 static int on_mp_write_session_request_process(struct query_state *);
56 static int on_mp_write_session_response_write1(struct query_state *);
57 static int on_mp_write_session_write_request_read1(struct query_state *);
58 static int on_mp_write_session_write_request_read2(struct query_state *);
59 static int on_mp_write_session_write_request_process(struct query_state *);
60 static int on_mp_write_session_write_response_write1(struct query_state *);
63 * This function is used as the query_state's destroy_func to make the
64 * proper cleanup in case of errors.
67 on_mp_write_session_destroy(struct query_state *qstate)
70 TRACE_IN(on_mp_write_session_destroy);
71 finalize_comm_element(&qstate->request);
72 finalize_comm_element(&qstate->response);
74 if (qstate->mdata != NULL) {
75 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
76 abandon_cache_mp_write_session(
77 (cache_mp_write_session)qstate->mdata);
78 configuration_unlock_entry(qstate->config_entry,
81 TRACE_OUT(on_mp_write_session_destroy);
85 * The functions below are used to process multipart write session initiation
87 * - on_mp_write_session_request_read1 and on_mp_write_session_request_read2
88 * read the request itself
89 * - on_mp_write_session_request_process processes it
90 * - on_mp_write_session_response_write1 sends the response
93 on_mp_write_session_request_read1(struct query_state *qstate)
95 struct cache_mp_write_session_request *c_mp_ws_request;
98 TRACE_IN(on_mp_write_session_request_read1);
99 if (qstate->kevent_watermark == 0)
100 qstate->kevent_watermark = sizeof(size_t);
102 init_comm_element(&qstate->request,
103 CET_MP_WRITE_SESSION_REQUEST);
104 c_mp_ws_request = get_cache_mp_write_session_request(
107 result = qstate->read_func(qstate,
108 &c_mp_ws_request->entry_length, sizeof(size_t));
110 if (result != sizeof(size_t)) {
111 LOG_ERR_3("on_mp_write_session_request_read1",
113 TRACE_OUT(on_mp_write_session_request_read1);
117 if (BUFSIZE_INVALID(c_mp_ws_request->entry_length)) {
118 LOG_ERR_3("on_mp_write_session_request_read1",
119 "invalid entry_length value");
120 TRACE_OUT(on_mp_write_session_request_read1);
124 c_mp_ws_request->entry = (char *)calloc(1,
125 c_mp_ws_request->entry_length + 1);
126 assert(c_mp_ws_request->entry != NULL);
128 qstate->kevent_watermark = c_mp_ws_request->entry_length;
129 qstate->process_func = on_mp_write_session_request_read2;
131 TRACE_OUT(on_mp_write_session_request_read1);
136 on_mp_write_session_request_read2(struct query_state *qstate)
138 struct cache_mp_write_session_request *c_mp_ws_request;
141 TRACE_IN(on_mp_write_session_request_read2);
142 c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request);
144 result = qstate->read_func(qstate, c_mp_ws_request->entry,
145 c_mp_ws_request->entry_length);
147 if (result != qstate->kevent_watermark) {
148 LOG_ERR_3("on_mp_write_session_request_read2",
150 TRACE_OUT(on_mp_write_session_request_read2);
154 qstate->kevent_watermark = 0;
155 qstate->process_func = on_mp_write_session_request_process;
157 TRACE_OUT(on_mp_write_session_request_read2);
162 on_mp_write_session_request_process(struct query_state *qstate)
164 struct cache_mp_write_session_request *c_mp_ws_request;
165 struct cache_mp_write_session_response *c_mp_ws_response;
166 cache_mp_write_session ws;
168 char *dec_cache_entry_name;
170 TRACE_IN(on_mp_write_session_request_process);
171 init_comm_element(&qstate->response, CET_MP_WRITE_SESSION_RESPONSE);
172 c_mp_ws_response = get_cache_mp_write_session_response(
174 c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request);
176 qstate->config_entry = configuration_find_entry(
177 s_configuration, c_mp_ws_request->entry);
178 if (qstate->config_entry == NULL) {
179 c_mp_ws_response->error_code = ENOENT;
181 LOG_ERR_2("write_session_request",
182 "can't find configuration entry '%s'. "
183 "aborting request", c_mp_ws_request->entry);
187 if (qstate->config_entry->enabled == 0) {
188 c_mp_ws_response->error_code = EACCES;
190 LOG_ERR_2("write_session_request",
191 "configuration entry '%s' is disabled",
192 c_mp_ws_request->entry);
196 if (qstate->config_entry->perform_actual_lookups != 0) {
197 c_mp_ws_response->error_code = EOPNOTSUPP;
199 LOG_ERR_2("write_session_request",
200 "entry '%s' performs lookups by itself: "
201 "can't write to it", c_mp_ws_request->entry);
204 #ifdef NS_NSCD_EID_CHECKING
205 if (check_query_eids(qstate) != 0) {
206 c_mp_ws_response->error_code = EPERM;
213 * All multipart entries are separated by their name decorations.
214 * For one configuration entry there will be a lot of multipart
215 * cache entries - each with its own decorated name.
217 asprintf(&dec_cache_entry_name, "%s%s", qstate->eid_str,
218 qstate->config_entry->mp_cache_params.entry_name);
219 assert(dec_cache_entry_name != NULL);
221 configuration_lock_rdlock(s_configuration);
222 c_entry = find_cache_entry(s_cache,
223 dec_cache_entry_name);
224 configuration_unlock(s_configuration);
226 if (c_entry == INVALID_CACHE_ENTRY)
227 c_entry = register_new_mp_cache_entry(qstate,
228 dec_cache_entry_name);
230 free(dec_cache_entry_name);
232 assert(c_entry != NULL);
233 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
234 ws = open_cache_mp_write_session(c_entry);
235 if (ws == INVALID_CACHE_MP_WRITE_SESSION)
236 c_mp_ws_response->error_code = -1;
239 qstate->destroy_func = on_mp_write_session_destroy;
241 if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) ||
242 (qstate->config_entry->mp_query_timeout.tv_usec != 0))
243 memcpy(&qstate->timeout,
244 &qstate->config_entry->mp_query_timeout,
245 sizeof(struct timeval));
247 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
250 qstate->process_func = on_mp_write_session_response_write1;
251 qstate->kevent_watermark = sizeof(int);
252 qstate->kevent_filter = EVFILT_WRITE;
254 TRACE_OUT(on_mp_write_session_request_process);
259 on_mp_write_session_response_write1(struct query_state *qstate)
261 struct cache_mp_write_session_response *c_mp_ws_response;
264 TRACE_IN(on_mp_write_session_response_write1);
265 c_mp_ws_response = get_cache_mp_write_session_response(
267 result = qstate->write_func(qstate, &c_mp_ws_response->error_code,
269 if (result != sizeof(int)) {
270 LOG_ERR_3("on_mp_write_session_response_write1",
272 TRACE_OUT(on_mp_write_session_response_write1);
276 if (c_mp_ws_response->error_code == 0) {
277 qstate->kevent_watermark = sizeof(int);
278 qstate->process_func = on_mp_write_session_mapper;
279 qstate->kevent_filter = EVFILT_READ;
281 qstate->kevent_watermark = 0;
282 qstate->process_func = NULL;
284 TRACE_OUT(on_mp_write_session_response_write1);
289 * Mapper function is used to avoid multiple connections for each session
290 * write or read requests. After processing the request, it does not close
291 * the connection, but waits for the next request.
294 on_mp_write_session_mapper(struct query_state *qstate)
299 TRACE_IN(on_mp_write_session_mapper);
300 if (qstate->kevent_watermark == 0) {
301 qstate->kevent_watermark = sizeof(int);
303 result = qstate->read_func(qstate, &elem_type, sizeof(int));
304 if (result != sizeof(int)) {
305 LOG_ERR_3("on_mp_write_session_mapper",
307 TRACE_OUT(on_mp_write_session_mapper);
312 case CET_MP_WRITE_SESSION_WRITE_REQUEST:
313 qstate->kevent_watermark = sizeof(size_t);
314 qstate->process_func =
315 on_mp_write_session_write_request_read1;
317 case CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION:
318 qstate->kevent_watermark = 0;
319 qstate->process_func =
320 on_mp_write_session_abandon_notification;
322 case CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION:
323 qstate->kevent_watermark = 0;
324 qstate->process_func =
325 on_mp_write_session_close_notification;
328 qstate->kevent_watermark = 0;
329 qstate->process_func = NULL;
330 LOG_ERR_2("on_mp_write_session_mapper",
331 "unknown element type");
332 TRACE_OUT(on_mp_write_session_mapper);
336 TRACE_OUT(on_mp_write_session_mapper);
341 * The functions below are used to process multipart write sessions write
343 * - on_mp_write_session_write_request_read1 and
344 * on_mp_write_session_write_request_read2 read the request itself
345 * - on_mp_write_session_write_request_process processes it
346 * - on_mp_write_session_write_response_write1 sends the response
349 on_mp_write_session_write_request_read1(struct query_state *qstate)
351 struct cache_mp_write_session_write_request *write_request;
354 TRACE_IN(on_mp_write_session_write_request_read1);
355 init_comm_element(&qstate->request,
356 CET_MP_WRITE_SESSION_WRITE_REQUEST);
357 write_request = get_cache_mp_write_session_write_request(
360 result = qstate->read_func(qstate, &write_request->data_size,
363 if (result != sizeof(size_t)) {
364 LOG_ERR_3("on_mp_write_session_write_request_read1",
366 TRACE_OUT(on_mp_write_session_write_request_read1);
370 if (BUFSIZE_INVALID(write_request->data_size)) {
371 LOG_ERR_3("on_mp_write_session_write_request_read1",
372 "invalid data_size value");
373 TRACE_OUT(on_mp_write_session_write_request_read1);
377 write_request->data = (char *)calloc(1, write_request->data_size);
378 assert(write_request->data != NULL);
380 qstate->kevent_watermark = write_request->data_size;
381 qstate->process_func = on_mp_write_session_write_request_read2;
382 TRACE_OUT(on_mp_write_session_write_request_read1);
387 on_mp_write_session_write_request_read2(struct query_state *qstate)
389 struct cache_mp_write_session_write_request *write_request;
392 TRACE_IN(on_mp_write_session_write_request_read2);
393 write_request = get_cache_mp_write_session_write_request(
396 result = qstate->read_func(qstate, write_request->data,
397 write_request->data_size);
399 if (result != qstate->kevent_watermark) {
400 LOG_ERR_3("on_mp_write_session_write_request_read2",
402 TRACE_OUT(on_mp_write_session_write_request_read2);
406 qstate->kevent_watermark = 0;
407 qstate->process_func = on_mp_write_session_write_request_process;
408 TRACE_OUT(on_mp_write_session_write_request_read2);
413 on_mp_write_session_write_request_process(struct query_state *qstate)
415 struct cache_mp_write_session_write_request *write_request;
416 struct cache_mp_write_session_write_response *write_response;
418 TRACE_IN(on_mp_write_session_write_request_process);
419 init_comm_element(&qstate->response,
420 CET_MP_WRITE_SESSION_WRITE_RESPONSE);
421 write_response = get_cache_mp_write_session_write_response(
423 write_request = get_cache_mp_write_session_write_request(
426 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
427 write_response->error_code = cache_mp_write(
428 (cache_mp_write_session)qstate->mdata,
430 write_request->data_size);
431 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
433 qstate->kevent_watermark = sizeof(int);
434 qstate->process_func = on_mp_write_session_write_response_write1;
435 qstate->kevent_filter = EVFILT_WRITE;
437 TRACE_OUT(on_mp_write_session_write_request_process);
442 on_mp_write_session_write_response_write1(struct query_state *qstate)
444 struct cache_mp_write_session_write_response *write_response;
447 TRACE_IN(on_mp_write_session_write_response_write1);
448 write_response = get_cache_mp_write_session_write_response(
450 result = qstate->write_func(qstate, &write_response->error_code,
452 if (result != sizeof(int)) {
453 LOG_ERR_3("on_mp_write_session_write_response_write1",
455 TRACE_OUT(on_mp_write_session_write_response_write1);
459 if (write_response->error_code == 0) {
460 finalize_comm_element(&qstate->request);
461 finalize_comm_element(&qstate->response);
463 qstate->kevent_watermark = sizeof(int);
464 qstate->process_func = on_mp_write_session_mapper;
465 qstate->kevent_filter = EVFILT_READ;
467 qstate->kevent_watermark = 0;
468 qstate->process_func = 0;
471 TRACE_OUT(on_mp_write_session_write_response_write1);
476 * Handles abandon notifications. Destroys the session by calling the
477 * abandon_cache_mp_write_session.
480 on_mp_write_session_abandon_notification(struct query_state *qstate)
482 TRACE_IN(on_mp_write_session_abandon_notification);
483 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
484 abandon_cache_mp_write_session((cache_mp_write_session)qstate->mdata);
485 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
486 qstate->mdata = INVALID_CACHE_MP_WRITE_SESSION;
488 qstate->kevent_watermark = 0;
489 qstate->process_func = NULL;
490 TRACE_OUT(on_mp_write_session_abandon_notification);
495 * Handles close notifications. Commits the session by calling
496 * the close_cache_mp_write_session.
499 on_mp_write_session_close_notification(struct query_state *qstate)
501 TRACE_IN(on_mp_write_session_close_notification);
502 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
503 close_cache_mp_write_session((cache_mp_write_session)qstate->mdata);
504 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
505 qstate->mdata = INVALID_CACHE_MP_WRITE_SESSION;
507 qstate->kevent_watermark = 0;
508 qstate->process_func = NULL;
509 TRACE_OUT(on_mp_write_session_close_notification);
513 cache_entry register_new_mp_cache_entry(struct query_state *qstate,
514 const char *dec_cache_entry_name)
519 TRACE_IN(register_new_mp_cache_entry);
520 c_entry = INVALID_CACHE_ENTRY;
521 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
523 configuration_lock_wrlock(s_configuration);
524 en_bkp = qstate->config_entry->mp_cache_params.entry_name;
525 qstate->config_entry->mp_cache_params.entry_name =
526 (char *)dec_cache_entry_name;
527 register_cache_entry(s_cache, (struct cache_entry_params *)
528 &qstate->config_entry->mp_cache_params);
529 qstate->config_entry->mp_cache_params.entry_name = en_bkp;
530 configuration_unlock(s_configuration);
532 configuration_lock_rdlock(s_configuration);
533 c_entry = find_cache_entry(s_cache,
534 dec_cache_entry_name);
535 configuration_unlock(s_configuration);
537 configuration_entry_add_mp_cache_entry(qstate->config_entry,
540 configuration_unlock_entry(qstate->config_entry,
543 TRACE_OUT(register_new_mp_cache_entry);