mp_ws_query.c revision 171795
155714Skris/*- 255714Skris * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 355714Skris * All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 8280304Sjkim * 1. Redistributions of source code must retain the above copyright 955714Skris * notice, this list of conditions and the following disclaimer. 1055714Skris * 2. Redistributions in binary form must reproduce the above copyright 1155714Skris * notice, this list of conditions and the following disclaimer in the 1255714Skris * documentation and/or other materials provided with the distribution. 1355714Skris * 1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15280304Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1655714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1755714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1855714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1955714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2055714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2155714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22280304Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2355714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2455714Skris * SUCH DAMAGE. 2555714Skris * 2655714Skris */ 2755714Skris 2855714Skris#include <sys/cdefs.h> 2955714Skris__FBSDID("$FreeBSD: head/usr.sbin/nscd/mp_ws_query.c 171795 2007-08-09 13:06:12Z bushman $"); 3055714Skris 3155714Skris#include <sys/socket.h> 3255714Skris#include <sys/time.h> 3355714Skris#include <sys/types.h> 3455714Skris#include <sys/event.h> 3555714Skris#include <assert.h> 3655714Skris#include <errno.h> 37280304Sjkim#include <stdlib.h> 3855714Skris#include <string.h> 3955714Skris#include <stdio.h> 40280304Sjkim 4155714Skris#include "cachelib.h" 4255714Skris#include "config.h" 4355714Skris#include "debug.h" 4455714Skris#include "log.h" 4555714Skris#include "query.h" 4655714Skris#include "mp_ws_query.h" 4755714Skris#include "singletons.h" 4855714Skris 4955714Skrisstatic int on_mp_write_session_abandon_notification(struct query_state *); 5055714Skrisstatic int on_mp_write_session_close_notification(struct query_state *); 5155714Skrisstatic void on_mp_write_session_destroy(struct query_state *); 52280304Sjkimstatic int on_mp_write_session_mapper(struct query_state *); 5355714Skris/* int on_mp_write_session_request_read1(struct query_state *); */ 5455714Skrisstatic int on_mp_write_session_request_read2(struct query_state *); 5555714Skrisstatic int on_mp_write_session_request_process(struct query_state *); 5655714Skrisstatic int on_mp_write_session_response_write1(struct query_state *); 5755714Skrisstatic int on_mp_write_session_write_request_read1(struct query_state *); 5855714Skrisstatic int on_mp_write_session_write_request_read2(struct query_state *); 59280304Sjkimstatic int on_mp_write_session_write_request_process(struct query_state *); 60280304Sjkimstatic int on_mp_write_session_write_response_write1(struct query_state *); 61280304Sjkim 62280304Sjkim/* 63160814Ssimon * This function is used as the query_state's destroy_func to make the 64280304Sjkim * proper cleanup in case of errors. 65160814Ssimon */ 66160814Ssimonstatic void 6755714Skrison_mp_write_session_destroy(struct query_state *qstate) 6855714Skris{ 6955714Skris 70109998Smarkm TRACE_IN(on_mp_write_session_destroy); 71109998Smarkm finalize_comm_element(&qstate->request); 72109998Smarkm finalize_comm_element(&qstate->response); 7355714Skris 7455714Skris if (qstate->mdata != NULL) { 7555714Skris configuration_lock_entry(qstate->config_entry, CELT_MULTIPART); 7659191Skris abandon_cache_mp_write_session( 77100928Snectar (cache_mp_write_session)qstate->mdata); 7855714Skris configuration_unlock_entry(qstate->config_entry, 79109998Smarkm CELT_MULTIPART); 8055714Skris } 8155714Skris TRACE_OUT(on_mp_write_session_destroy); 8255714Skris} 83280304Sjkim 8455714Skris/* 8555714Skris * The functions below are used to process multipart write session initiation 86280304Sjkim * requests. 8755714Skris * - on_mp_write_session_request_read1 and on_mp_write_session_request_read2 88280304Sjkim * read the request itself 89280304Sjkim * - on_mp_write_session_request_process processes it 90280304Sjkim * - on_mp_write_session_response_write1 sends the response 91280304Sjkim */ 92280304Sjkimint 9355714Skrison_mp_write_session_request_read1(struct query_state *qstate) 94160814Ssimon{ 9555714Skris struct cache_mp_write_session_request *c_mp_ws_request; 96280304Sjkim ssize_t result; 97280304Sjkim 9855714Skris TRACE_IN(on_mp_write_session_request_read1); 9955714Skris if (qstate->kevent_watermark == 0) 100280304Sjkim qstate->kevent_watermark = sizeof(size_t); 101280304Sjkim else { 102280304Sjkim init_comm_element(&qstate->request, 103280304Sjkim CET_MP_WRITE_SESSION_REQUEST); 104280304Sjkim c_mp_ws_request = get_cache_mp_write_session_request( 105280304Sjkim &qstate->request); 106280304Sjkim 107280304Sjkim result = qstate->read_func(qstate, 10855714Skris &c_mp_ws_request->entry_length, sizeof(size_t)); 109280304Sjkim 110280304Sjkim if (result != sizeof(size_t)) { 111280304Sjkim LOG_ERR_3("on_mp_write_session_request_read1", 112109998Smarkm "read failed"); 113280304Sjkim TRACE_OUT(on_mp_write_session_request_read1); 114280304Sjkim return (-1); 115280304Sjkim } 11655714Skris 117280304Sjkim if (BUFSIZE_INVALID(c_mp_ws_request->entry_length)) { 11859191Skris LOG_ERR_3("on_mp_write_session_request_read1", 119280304Sjkim "invalid entry_length value"); 120280304Sjkim TRACE_OUT(on_mp_write_session_request_read1); 121280304Sjkim return (-1); 122280304Sjkim } 12355714Skris 124280304Sjkim c_mp_ws_request->entry = (char *)malloc( 125280304Sjkim c_mp_ws_request->entry_length + 1); 126280304Sjkim assert(c_mp_ws_request->entry != NULL); 127280304Sjkim memset(c_mp_ws_request->entry, 0, 128280304Sjkim c_mp_ws_request->entry_length + 1); 12955714Skris 130280304Sjkim qstate->kevent_watermark = c_mp_ws_request->entry_length; 131280304Sjkim qstate->process_func = on_mp_write_session_request_read2; 132280304Sjkim } 133280304Sjkim TRACE_OUT(on_mp_write_session_request_read1); 134280304Sjkim return (0); 135280304Sjkim} 136280304Sjkim 137280304Sjkimstatic int 138280304Sjkimon_mp_write_session_request_read2(struct query_state *qstate) 139280304Sjkim{ 140100928Snectar struct cache_mp_write_session_request *c_mp_ws_request; 141280304Sjkim ssize_t result; 142280304Sjkim 143280304Sjkim TRACE_IN(on_mp_write_session_request_read2); 144280304Sjkim c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request); 145280304Sjkim 14655714Skris result = qstate->read_func(qstate, c_mp_ws_request->entry, 147280304Sjkim c_mp_ws_request->entry_length); 148280304Sjkim 149280304Sjkim if (result != qstate->kevent_watermark) { 15055714Skris LOG_ERR_3("on_mp_write_session_request_read2", 151280304Sjkim "read failed"); 152280304Sjkim TRACE_OUT(on_mp_write_session_request_read2); 153280304Sjkim return (-1); 154280304Sjkim } 15555714Skris 156280304Sjkim qstate->kevent_watermark = 0; 157280304Sjkim qstate->process_func = on_mp_write_session_request_process; 158280304Sjkim 159160814Ssimon TRACE_OUT(on_mp_write_session_request_read2); 160280304Sjkim return (0); 161280304Sjkim} 162280304Sjkim 163280304Sjkimstatic int 164280304Sjkimon_mp_write_session_request_process(struct query_state *qstate) 165280304Sjkim{ 166280304Sjkim struct cache_mp_write_session_request *c_mp_ws_request; 16755714Skris struct cache_mp_write_session_response *c_mp_ws_response; 168280304Sjkim cache_mp_write_session ws; 169280304Sjkim cache_entry c_entry; 170280304Sjkim char *dec_cache_entry_name; 171280304Sjkim 172280304Sjkim TRACE_IN(on_mp_write_session_request_process); 173280304Sjkim init_comm_element(&qstate->response, CET_MP_WRITE_SESSION_RESPONSE); 174280304Sjkim c_mp_ws_response = get_cache_mp_write_session_response( 17555714Skris &qstate->response); 176280304Sjkim c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request); 177280304Sjkim 178280304Sjkim qstate->config_entry = configuration_find_entry( 17955714Skris s_configuration, c_mp_ws_request->entry); 180280304Sjkim if (qstate->config_entry == NULL) { 181280304Sjkim c_mp_ws_response->error_code = ENOENT; 182280304Sjkim 183280304Sjkim LOG_ERR_2("write_session_request", 184280304Sjkim "can't find configuration entry '%s'. " 185280304Sjkim "aborting request", c_mp_ws_request->entry); 18655714Skris goto fin; 187280304Sjkim } 188280304Sjkim 189280304Sjkim if (qstate->config_entry->enabled == 0) { 19055714Skris c_mp_ws_response->error_code = EACCES; 191280304Sjkim 192280304Sjkim LOG_ERR_2("write_session_request", 193280304Sjkim "configuration entry '%s' is disabled", 194280304Sjkim c_mp_ws_request->entry); 195280304Sjkim goto fin; 196280304Sjkim } 197280304Sjkim 198280304Sjkim if (qstate->config_entry->perform_actual_lookups != 0) { 199280304Sjkim c_mp_ws_response->error_code = EOPNOTSUPP; 200280304Sjkim 201280304Sjkim LOG_ERR_2("write_session_request", 202280304Sjkim "entry '%s' performs lookups by itself: " 203280304Sjkim "can't write to it", c_mp_ws_request->entry); 204100928Snectar goto fin; 205280304Sjkim } else { 206280304Sjkim#ifdef NS_NSCD_EID_CHECKING 207280304Sjkim if (check_query_eids(qstate) != 0) { 208280304Sjkim c_mp_ws_response->error_code = EPERM; 209280304Sjkim goto fin; 210280304Sjkim } 211280304Sjkim#endif 212280304Sjkim } 213280304Sjkim 214280304Sjkim /* 215280304Sjkim * All multipart entries are separated by their name decorations. 216280304Sjkim * For one configuration entry there will be a lot of multipart 217280304Sjkim * cache entries - each with its own decorated name. 218280304Sjkim */ 219280304Sjkim asprintf(&dec_cache_entry_name, "%s%s", qstate->eid_str, 220280304Sjkim qstate->config_entry->mp_cache_params.entry_name); 22155714Skris assert(dec_cache_entry_name != NULL); 222160814Ssimon 223280304Sjkim configuration_lock_rdlock(s_configuration); 224280304Sjkim c_entry = find_cache_entry(s_cache, 22555714Skris dec_cache_entry_name); 226280304Sjkim configuration_unlock(s_configuration); 227280304Sjkim 228280304Sjkim if (c_entry == INVALID_CACHE_ENTRY) 229280304Sjkim c_entry = register_new_mp_cache_entry(qstate, 230280304Sjkim dec_cache_entry_name); 231280304Sjkim 232280304Sjkim free(dec_cache_entry_name); 233280304Sjkim 234280304Sjkim assert(c_entry != NULL); 235280304Sjkim configuration_lock_entry(qstate->config_entry, CELT_MULTIPART); 236280304Sjkim ws = open_cache_mp_write_session(c_entry); 237280304Sjkim if (ws == INVALID_CACHE_MP_WRITE_SESSION) 238280304Sjkim c_mp_ws_response->error_code = -1; 239280304Sjkim else { 240280304Sjkim qstate->mdata = ws; 24155714Skris qstate->destroy_func = on_mp_write_session_destroy; 242 243 if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) || 244 (qstate->config_entry->mp_query_timeout.tv_usec != 0)) 245 memcpy(&qstate->timeout, 246 &qstate->config_entry->mp_query_timeout, 247 sizeof(struct timeval)); 248 } 249 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART); 250 251fin: 252 qstate->process_func = on_mp_write_session_response_write1; 253 qstate->kevent_watermark = sizeof(int); 254 qstate->kevent_filter = EVFILT_WRITE; 255 256 TRACE_OUT(on_mp_write_session_request_process); 257 return (0); 258} 259 260static int 261on_mp_write_session_response_write1(struct query_state *qstate) 262{ 263 struct cache_mp_write_session_response *c_mp_ws_response; 264 ssize_t result; 265 266 TRACE_IN(on_mp_write_session_response_write1); 267 c_mp_ws_response = get_cache_mp_write_session_response( 268 &qstate->response); 269 result = qstate->write_func(qstate, &c_mp_ws_response->error_code, 270 sizeof(int)); 271 if (result != sizeof(int)) { 272 LOG_ERR_3("on_mp_write_session_response_write1", 273 "write failed"); 274 TRACE_OUT(on_mp_write_session_response_write1); 275 return (-1); 276 } 277 278 if (c_mp_ws_response->error_code == 0) { 279 qstate->kevent_watermark = sizeof(int); 280 qstate->process_func = on_mp_write_session_mapper; 281 qstate->kevent_filter = EVFILT_READ; 282 } else { 283 qstate->kevent_watermark = 0; 284 qstate->process_func = NULL; 285 } 286 TRACE_OUT(on_mp_write_session_response_write1); 287 return (0); 288} 289 290/* 291 * Mapper function is used to avoid multiple connections for each session 292 * write or read requests. After processing the request, it does not close 293 * the connection, but waits for the next request. 294 */ 295static int 296on_mp_write_session_mapper(struct query_state *qstate) 297{ 298 ssize_t result; 299 int elem_type; 300 301 TRACE_IN(on_mp_write_session_mapper); 302 if (qstate->kevent_watermark == 0) { 303 qstate->kevent_watermark = sizeof(int); 304 } else { 305 result = qstate->read_func(qstate, &elem_type, sizeof(int)); 306 if (result != sizeof(int)) { 307 LOG_ERR_3("on_mp_write_session_mapper", 308 "read failed"); 309 TRACE_OUT(on_mp_write_session_mapper); 310 return (-1); 311 } 312 313 switch (elem_type) { 314 case CET_MP_WRITE_SESSION_WRITE_REQUEST: 315 qstate->kevent_watermark = sizeof(size_t); 316 qstate->process_func = 317 on_mp_write_session_write_request_read1; 318 break; 319 case CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION: 320 qstate->kevent_watermark = 0; 321 qstate->process_func = 322 on_mp_write_session_abandon_notification; 323 break; 324 case CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION: 325 qstate->kevent_watermark = 0; 326 qstate->process_func = 327 on_mp_write_session_close_notification; 328 break; 329 default: 330 qstate->kevent_watermark = 0; 331 qstate->process_func = NULL; 332 LOG_ERR_2("on_mp_write_session_mapper", 333 "unknown element type"); 334 TRACE_OUT(on_mp_write_session_mapper); 335 return (-1); 336 } 337 } 338 TRACE_OUT(on_mp_write_session_mapper); 339 return (0); 340} 341 342/* 343 * The functions below are used to process multipart write sessions write 344 * requests. 345 * - on_mp_write_session_write_request_read1 and 346 * on_mp_write_session_write_request_read2 read the request itself 347 * - on_mp_write_session_write_request_process processes it 348 * - on_mp_write_session_write_response_write1 sends the response 349 */ 350static int 351on_mp_write_session_write_request_read1(struct query_state *qstate) 352{ 353 struct cache_mp_write_session_write_request *write_request; 354 ssize_t result; 355 356 TRACE_IN(on_mp_write_session_write_request_read1); 357 init_comm_element(&qstate->request, 358 CET_MP_WRITE_SESSION_WRITE_REQUEST); 359 write_request = get_cache_mp_write_session_write_request( 360 &qstate->request); 361 362 result = qstate->read_func(qstate, &write_request->data_size, 363 sizeof(size_t)); 364 365 if (result != sizeof(size_t)) { 366 LOG_ERR_3("on_mp_write_session_write_request_read1", 367 "read failed"); 368 TRACE_OUT(on_mp_write_session_write_request_read1); 369 return (-1); 370 } 371 372 if (BUFSIZE_INVALID(write_request->data_size)) { 373 LOG_ERR_3("on_mp_write_session_write_request_read1", 374 "invalid data_size value"); 375 TRACE_OUT(on_mp_write_session_write_request_read1); 376 return (-1); 377 } 378 379 write_request->data = (char *)malloc(write_request->data_size); 380 assert(write_request->data != NULL); 381 memset(write_request->data, 0, write_request->data_size); 382 383 qstate->kevent_watermark = write_request->data_size; 384 qstate->process_func = on_mp_write_session_write_request_read2; 385 TRACE_OUT(on_mp_write_session_write_request_read1); 386 return (0); 387} 388 389static int 390on_mp_write_session_write_request_read2(struct query_state *qstate) 391{ 392 struct cache_mp_write_session_write_request *write_request; 393 ssize_t result; 394 395 TRACE_IN(on_mp_write_session_write_request_read2); 396 write_request = get_cache_mp_write_session_write_request( 397 &qstate->request); 398 399 result = qstate->read_func(qstate, write_request->data, 400 write_request->data_size); 401 402 if (result != qstate->kevent_watermark) { 403 LOG_ERR_3("on_mp_write_session_write_request_read2", 404 "read failed"); 405 TRACE_OUT(on_mp_write_session_write_request_read2); 406 return (-1); 407 } 408 409 qstate->kevent_watermark = 0; 410 qstate->process_func = on_mp_write_session_write_request_process; 411 TRACE_OUT(on_mp_write_session_write_request_read2); 412 return (0); 413} 414 415static int 416on_mp_write_session_write_request_process(struct query_state *qstate) 417{ 418 struct cache_mp_write_session_write_request *write_request; 419 struct cache_mp_write_session_write_response *write_response; 420 421 TRACE_IN(on_mp_write_session_write_request_process); 422 init_comm_element(&qstate->response, 423 CET_MP_WRITE_SESSION_WRITE_RESPONSE); 424 write_response = get_cache_mp_write_session_write_response( 425 &qstate->response); 426 write_request = get_cache_mp_write_session_write_request( 427 &qstate->request); 428 429 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART); 430 write_response->error_code = cache_mp_write( 431 (cache_mp_write_session)qstate->mdata, 432 write_request->data, 433 write_request->data_size); 434 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART); 435 436 qstate->kevent_watermark = sizeof(int); 437 qstate->process_func = on_mp_write_session_write_response_write1; 438 qstate->kevent_filter = EVFILT_WRITE; 439 440 TRACE_OUT(on_mp_write_session_write_request_process); 441 return (0); 442} 443 444static int 445on_mp_write_session_write_response_write1(struct query_state *qstate) 446{ 447 struct cache_mp_write_session_write_response *write_response; 448 ssize_t result; 449 450 TRACE_IN(on_mp_write_session_write_response_write1); 451 write_response = get_cache_mp_write_session_write_response( 452 &qstate->response); 453 result = qstate->write_func(qstate, &write_response->error_code, 454 sizeof(int)); 455 if (result != sizeof(int)) { 456 LOG_ERR_3("on_mp_write_session_write_response_write1", 457 "write failed"); 458 TRACE_OUT(on_mp_write_session_write_response_write1); 459 return (-1); 460 } 461 462 if (write_response->error_code == 0) { 463 finalize_comm_element(&qstate->request); 464 finalize_comm_element(&qstate->response); 465 466 qstate->kevent_watermark = sizeof(int); 467 qstate->process_func = on_mp_write_session_mapper; 468 qstate->kevent_filter = EVFILT_READ; 469 } else { 470 qstate->kevent_watermark = 0; 471 qstate->process_func = 0; 472 } 473 474 TRACE_OUT(on_mp_write_session_write_response_write1); 475 return (0); 476} 477 478/* 479 * Handles abandon notifications. Destroys the session by calling the 480 * abandon_cache_mp_write_session. 481 */ 482static int 483on_mp_write_session_abandon_notification(struct query_state *qstate) 484{ 485 TRACE_IN(on_mp_write_session_abandon_notification); 486 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART); 487 abandon_cache_mp_write_session((cache_mp_write_session)qstate->mdata); 488 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART); 489 qstate->mdata = INVALID_CACHE_MP_WRITE_SESSION; 490 491 qstate->kevent_watermark = 0; 492 qstate->process_func = NULL; 493 TRACE_OUT(on_mp_write_session_abandon_notification); 494 return (0); 495} 496 497/* 498 * Handles close notifications. Commits the session by calling 499 * the close_cache_mp_write_session. 500 */ 501static int 502on_mp_write_session_close_notification(struct query_state *qstate) 503{ 504 TRACE_IN(on_mp_write_session_close_notification); 505 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART); 506 close_cache_mp_write_session((cache_mp_write_session)qstate->mdata); 507 configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART); 508 qstate->mdata = INVALID_CACHE_MP_WRITE_SESSION; 509 510 qstate->kevent_watermark = 0; 511 qstate->process_func = NULL; 512 TRACE_OUT(on_mp_write_session_close_notification); 513 return (0); 514} 515 516cache_entry register_new_mp_cache_entry(struct query_state *qstate, 517 const char *dec_cache_entry_name) 518{ 519 cache_entry c_entry; 520 char *en_bkp; 521 522 TRACE_IN(register_new_mp_cache_entry); 523 c_entry = INVALID_CACHE_ENTRY; 524 configuration_lock_entry(qstate->config_entry, CELT_MULTIPART); 525 526 configuration_lock_wrlock(s_configuration); 527 en_bkp = qstate->config_entry->mp_cache_params.entry_name; 528 qstate->config_entry->mp_cache_params.entry_name = 529 (char *)dec_cache_entry_name; 530 register_cache_entry(s_cache, (struct cache_entry_params *) 531 &qstate->config_entry->mp_cache_params); 532 qstate->config_entry->mp_cache_params.entry_name = en_bkp; 533 configuration_unlock(s_configuration); 534 535 configuration_lock_rdlock(s_configuration); 536 c_entry = find_cache_entry(s_cache, 537 dec_cache_entry_name); 538 configuration_unlock(s_configuration); 539 540 configuration_entry_add_mp_cache_entry(qstate->config_entry, 541 c_entry); 542 543 configuration_unlock_entry(qstate->config_entry, 544 CELT_MULTIPART); 545 546 TRACE_OUT(register_new_mp_cache_entry); 547 return (c_entry); 548} 549