1 /*- 2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <assert.h> 32 #include <math.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include "config.h" 37 #include "debug.h" 38 #include "log.h" 39 40 /* 41 * Default entries, which always exist in the configuration 42 */ 43 const char *c_default_entries[6] = { 44 NSDB_PASSWD, 45 NSDB_GROUP, 46 NSDB_HOSTS, 47 NSDB_SERVICES, 48 NSDB_PROTOCOLS, 49 NSDB_RPC 50 }; 51 52 static int configuration_entry_cmp(const void *, const void *); 53 static int configuration_entry_sort_cmp(const void *, const void *); 54 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *); 55 static int configuration_entry_cache_mp_cmp(const void *, const void *); 56 static int configuration_entry_cache_mp_part_cmp(const void *, const void *); 57 static struct configuration_entry *create_configuration_entry(const char *, 58 struct timeval const *, struct timeval const *, 59 struct common_cache_entry_params const *, 60 struct common_cache_entry_params const *, 61 struct mp_cache_entry_params const *); 62 63 static int 64 configuration_entry_sort_cmp(const void *e1, const void *e2) 65 { 66 return (strcmp((*((struct configuration_entry **)e1))->name, 67 (*((struct configuration_entry **)e2))->name 68 )); 69 } 70 71 static int 72 configuration_entry_cmp(const void *e1, const void *e2) 73 { 74 return (strcmp((const char *)e1, 75 (*((struct configuration_entry **)e2))->name 76 )); 77 } 78 79 static int 80 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2) 81 { 82 return (strcmp((*((cache_entry *)e1))->params->entry_name, 83 (*((cache_entry *)e2))->params->entry_name 84 )); 85 } 86 87 static int 88 configuration_entry_cache_mp_cmp(const void *e1, const void *e2) 89 { 90 return (strcmp((const char *)e1, 91 (*((cache_entry *)e2))->params->entry_name 92 )); 93 } 94 95 static int 96 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2) 97 { 98 return (strncmp((const char *)e1, 99 (*((cache_entry *)e2))->params->entry_name, 100 strlen((const char *)e1) 101 )); 102 } 103 104 static struct configuration_entry * 105 create_configuration_entry(const char *name, 106 struct timeval const *common_timeout, 107 struct timeval const *mp_timeout, 108 struct common_cache_entry_params const *positive_params, 109 struct common_cache_entry_params const *negative_params, 110 struct mp_cache_entry_params const *mp_params) 111 { 112 struct configuration_entry *retval; 113 size_t size; 114 int res; 115 116 TRACE_IN(create_configuration_entry); 117 assert(name != NULL); 118 assert(positive_params != NULL); 119 assert(negative_params != NULL); 120 assert(mp_params != NULL); 121 122 retval = (struct configuration_entry *)calloc(1, 123 sizeof(struct configuration_entry)); 124 assert(retval != NULL); 125 126 res = pthread_mutex_init(&retval->positive_cache_lock, NULL); 127 if (res != 0) { 128 free(retval); 129 LOG_ERR_2("create_configuration_entry", 130 "can't create positive cache lock"); 131 TRACE_OUT(create_configuration_entry); 132 return (NULL); 133 } 134 135 res = pthread_mutex_init(&retval->negative_cache_lock, NULL); 136 if (res != 0) { 137 pthread_mutex_destroy(&retval->positive_cache_lock); 138 free(retval); 139 LOG_ERR_2("create_configuration_entry", 140 "can't create negative cache lock"); 141 TRACE_OUT(create_configuration_entry); 142 return (NULL); 143 } 144 145 res = pthread_mutex_init(&retval->mp_cache_lock, NULL); 146 if (res != 0) { 147 pthread_mutex_destroy(&retval->positive_cache_lock); 148 pthread_mutex_destroy(&retval->negative_cache_lock); 149 free(retval); 150 LOG_ERR_2("create_configuration_entry", 151 "can't create negative cache lock"); 152 TRACE_OUT(create_configuration_entry); 153 return (NULL); 154 } 155 156 memcpy(&retval->positive_cache_params, positive_params, 157 sizeof(struct common_cache_entry_params)); 158 memcpy(&retval->negative_cache_params, negative_params, 159 sizeof(struct common_cache_entry_params)); 160 memcpy(&retval->mp_cache_params, mp_params, 161 sizeof(struct mp_cache_entry_params)); 162 163 size = strlen(name); 164 retval->name = (char *)calloc(1, size + 1); 165 assert(retval->name != NULL); 166 memcpy(retval->name, name, size); 167 168 memcpy(&retval->common_query_timeout, common_timeout, 169 sizeof(struct timeval)); 170 memcpy(&retval->mp_query_timeout, mp_timeout, 171 sizeof(struct timeval)); 172 173 asprintf(&retval->positive_cache_params.entry_name, "%s+", name); 174 assert(retval->positive_cache_params.entry_name != NULL); 175 176 asprintf(&retval->negative_cache_params.entry_name, "%s-", name); 177 assert(retval->negative_cache_params.entry_name != NULL); 178 179 asprintf(&retval->mp_cache_params.entry_name, "%s*", name); 180 assert(retval->mp_cache_params.entry_name != NULL); 181 182 TRACE_OUT(create_configuration_entry); 183 return (retval); 184 } 185 186 /* 187 * Creates configuration entry and fills it with default values 188 */ 189 struct configuration_entry * 190 create_def_configuration_entry(const char *name) 191 { 192 struct common_cache_entry_params positive_params, negative_params; 193 struct mp_cache_entry_params mp_params; 194 struct timeval default_common_timeout, default_mp_timeout; 195 196 struct configuration_entry *res = NULL; 197 198 TRACE_IN(create_def_configuration_entry); 199 memset(&positive_params, 0, 200 sizeof(struct common_cache_entry_params)); 201 positive_params.entry_type = CET_COMMON; 202 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE; 203 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE; 204 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2; 205 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME; 206 positive_params.policy = CPT_LRU; 207 208 memcpy(&negative_params, &positive_params, 209 sizeof(struct common_cache_entry_params)); 210 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE; 211 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2; 212 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME; 213 negative_params.policy = CPT_FIFO; 214 215 memset(&default_common_timeout, 0, sizeof(struct timeval)); 216 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT; 217 218 memset(&default_mp_timeout, 0, sizeof(struct timeval)); 219 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT; 220 221 memset(&mp_params, 0, 222 sizeof(struct mp_cache_entry_params)); 223 mp_params.entry_type = CET_MULTIPART; 224 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE; 225 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE; 226 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME; 227 228 res = create_configuration_entry(name, &default_common_timeout, 229 &default_mp_timeout, &positive_params, &negative_params, 230 &mp_params); 231 232 TRACE_OUT(create_def_configuration_entry); 233 return (res); 234 } 235 236 void 237 destroy_configuration_entry(struct configuration_entry *entry) 238 { 239 TRACE_IN(destroy_configuration_entry); 240 assert(entry != NULL); 241 pthread_mutex_destroy(&entry->positive_cache_lock); 242 pthread_mutex_destroy(&entry->negative_cache_lock); 243 pthread_mutex_destroy(&entry->mp_cache_lock); 244 free(entry->name); 245 free(entry->positive_cache_params.entry_name); 246 free(entry->negative_cache_params.entry_name); 247 free(entry->mp_cache_params.entry_name); 248 free(entry->mp_cache_entries); 249 free(entry); 250 TRACE_OUT(destroy_configuration_entry); 251 } 252 253 int 254 add_configuration_entry(struct configuration *config, 255 struct configuration_entry *entry) 256 { 257 TRACE_IN(add_configuration_entry); 258 assert(entry != NULL); 259 assert(entry->name != NULL); 260 if (configuration_find_entry(config, entry->name) != NULL) { 261 TRACE_OUT(add_configuration_entry); 262 return (-1); 263 } 264 265 if (config->entries_size == config->entries_capacity) { 266 struct configuration_entry **new_entries; 267 268 config->entries_capacity *= 2; 269 new_entries = (struct configuration_entry **)calloc(1, 270 sizeof(struct configuration_entry *) * 271 config->entries_capacity); 272 assert(new_entries != NULL); 273 memcpy(new_entries, config->entries, 274 sizeof(struct configuration_entry *) * 275 config->entries_size); 276 277 free(config->entries); 278 config->entries = new_entries; 279 } 280 281 config->entries[config->entries_size++] = entry; 282 qsort(config->entries, config->entries_size, 283 sizeof(struct configuration_entry *), 284 configuration_entry_sort_cmp); 285 286 TRACE_OUT(add_configuration_entry); 287 return (0); 288 } 289 290 size_t 291 configuration_get_entries_size(struct configuration *config) 292 { 293 TRACE_IN(configuration_get_entries_size); 294 assert(config != NULL); 295 TRACE_OUT(configuration_get_entries_size); 296 return (config->entries_size); 297 } 298 299 struct configuration_entry * 300 configuration_get_entry(struct configuration *config, size_t index) 301 { 302 TRACE_IN(configuration_get_entry); 303 assert(config != NULL); 304 assert(index < config->entries_size); 305 TRACE_OUT(configuration_get_entry); 306 return (config->entries[index]); 307 } 308 309 struct configuration_entry * 310 configuration_find_entry(struct configuration *config, 311 const char *name) 312 { 313 struct configuration_entry **retval; 314 315 TRACE_IN(configuration_find_entry); 316 317 retval = bsearch(name, config->entries, config->entries_size, 318 sizeof(struct configuration_entry *), configuration_entry_cmp); 319 TRACE_OUT(configuration_find_entry); 320 321 return ((retval != NULL) ? *retval : NULL); 322 } 323 324 /* 325 * All multipart cache entries are stored in the configuration_entry in the 326 * sorted array (sorted by names). The 3 functions below manage this array. 327 */ 328 329 int 330 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry, 331 cache_entry c_entry) 332 { 333 cache_entry *new_mp_entries, *old_mp_entries; 334 335 TRACE_IN(configuration_entry_add_mp_cache_entry); 336 ++config_entry->mp_cache_entries_size; 337 new_mp_entries = (cache_entry *)malloc(sizeof(cache_entry) * 338 config_entry->mp_cache_entries_size); 339 assert(new_mp_entries != NULL); 340 new_mp_entries[0] = c_entry; 341 342 if (config_entry->mp_cache_entries_size - 1 > 0) { 343 memcpy(new_mp_entries + 1, 344 config_entry->mp_cache_entries, 345 (config_entry->mp_cache_entries_size - 1) * 346 sizeof(cache_entry)); 347 } 348 349 old_mp_entries = config_entry->mp_cache_entries; 350 config_entry->mp_cache_entries = new_mp_entries; 351 free(old_mp_entries); 352 353 qsort(config_entry->mp_cache_entries, 354 config_entry->mp_cache_entries_size, 355 sizeof(cache_entry), 356 configuration_entry_cache_mp_sort_cmp); 357 358 TRACE_OUT(configuration_entry_add_mp_cache_entry); 359 return (0); 360 } 361 362 cache_entry 363 configuration_entry_find_mp_cache_entry( 364 struct configuration_entry *config_entry, const char *mp_name) 365 { 366 cache_entry *result; 367 368 TRACE_IN(configuration_entry_find_mp_cache_entry); 369 result = bsearch(mp_name, config_entry->mp_cache_entries, 370 config_entry->mp_cache_entries_size, 371 sizeof(cache_entry), configuration_entry_cache_mp_cmp); 372 373 if (result == NULL) { 374 TRACE_OUT(configuration_entry_find_mp_cache_entry); 375 return (NULL); 376 } else { 377 TRACE_OUT(configuration_entry_find_mp_cache_entry); 378 return (*result); 379 } 380 } 381 382 /* 383 * Searches for all multipart entries with names starting with mp_name. 384 * Needed for cache flushing. 385 */ 386 int 387 configuration_entry_find_mp_cache_entries( 388 struct configuration_entry *config_entry, const char *mp_name, 389 cache_entry **start, cache_entry **finish) 390 { 391 cache_entry *result; 392 393 TRACE_IN(configuration_entry_find_mp_cache_entries); 394 result = bsearch(mp_name, config_entry->mp_cache_entries, 395 config_entry->mp_cache_entries_size, 396 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp); 397 398 if (result == NULL) { 399 TRACE_OUT(configuration_entry_find_mp_cache_entries); 400 return (-1); 401 } 402 403 *start = result; 404 *finish = result + 1; 405 406 while (*start != config_entry->mp_cache_entries) { 407 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0) 408 *start = *start - 1; 409 else 410 break; 411 } 412 413 while (*finish != config_entry->mp_cache_entries + 414 config_entry->mp_cache_entries_size) { 415 416 if (configuration_entry_cache_mp_part_cmp( 417 mp_name, *finish) == 0) 418 *finish = *finish + 1; 419 else 420 break; 421 } 422 423 TRACE_OUT(configuration_entry_find_mp_cache_entries); 424 return (0); 425 } 426 427 /* 428 * Configuration entry uses rwlock to handle access to its fields. 429 */ 430 void 431 configuration_lock_rdlock(struct configuration *config) 432 { 433 TRACE_IN(configuration_lock_rdlock); 434 pthread_rwlock_rdlock(&config->rwlock); 435 TRACE_OUT(configuration_lock_rdlock); 436 } 437 438 void 439 configuration_lock_wrlock(struct configuration *config) 440 { 441 TRACE_IN(configuration_lock_wrlock); 442 pthread_rwlock_wrlock(&config->rwlock); 443 TRACE_OUT(configuration_lock_wrlock); 444 } 445 446 void 447 configuration_unlock(struct configuration *config) 448 { 449 TRACE_IN(configuration_unlock); 450 pthread_rwlock_unlock(&config->rwlock); 451 TRACE_OUT(configuration_unlock); 452 } 453 454 /* 455 * Configuration entry uses 3 mutexes to handle cache operations. They are 456 * acquired by configuration_lock_entry and configuration_unlock_entry 457 * functions. 458 */ 459 void 460 configuration_lock_entry(struct configuration_entry *entry, 461 enum config_entry_lock_type lock_type) 462 { 463 TRACE_IN(configuration_lock_entry); 464 assert(entry != NULL); 465 466 switch (lock_type) { 467 case CELT_POSITIVE: 468 pthread_mutex_lock(&entry->positive_cache_lock); 469 break; 470 case CELT_NEGATIVE: 471 pthread_mutex_lock(&entry->negative_cache_lock); 472 break; 473 case CELT_MULTIPART: 474 pthread_mutex_lock(&entry->mp_cache_lock); 475 break; 476 default: 477 /* should be unreachable */ 478 break; 479 } 480 TRACE_OUT(configuration_lock_entry); 481 } 482 483 void 484 configuration_unlock_entry(struct configuration_entry *entry, 485 enum config_entry_lock_type lock_type) 486 { 487 TRACE_IN(configuration_unlock_entry); 488 assert(entry != NULL); 489 490 switch (lock_type) { 491 case CELT_POSITIVE: 492 pthread_mutex_unlock(&entry->positive_cache_lock); 493 break; 494 case CELT_NEGATIVE: 495 pthread_mutex_unlock(&entry->negative_cache_lock); 496 break; 497 case CELT_MULTIPART: 498 pthread_mutex_unlock(&entry->mp_cache_lock); 499 break; 500 default: 501 /* should be unreachable */ 502 break; 503 } 504 TRACE_OUT(configuration_unlock_entry); 505 } 506 507 struct configuration * 508 init_configuration(void) 509 { 510 struct configuration *retval; 511 512 TRACE_IN(init_configuration); 513 retval = (struct configuration *)calloc(1, sizeof(struct configuration)); 514 assert(retval != NULL); 515 516 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 517 retval->entries = (struct configuration_entry **)calloc(1, 518 sizeof(struct configuration_entry *) * 519 retval->entries_capacity); 520 assert(retval->entries != NULL); 521 522 pthread_rwlock_init(&retval->rwlock, NULL); 523 524 TRACE_OUT(init_configuration); 525 return (retval); 526 } 527 528 void 529 fill_configuration_defaults(struct configuration *config) 530 { 531 size_t len, i; 532 533 TRACE_IN(fill_configuration_defaults); 534 assert(config != NULL); 535 536 if (config->socket_path != NULL) 537 free(config->socket_path); 538 539 len = strlen(DEFAULT_SOCKET_PATH); 540 config->socket_path = (char *)calloc(1, len + 1); 541 assert(config->socket_path != NULL); 542 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len); 543 544 len = strlen(DEFAULT_PIDFILE_PATH); 545 config->pidfile_path = (char *)calloc(1, len + 1); 546 assert(config->pidfile_path != NULL); 547 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len); 548 549 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | 550 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 551 config->force_unlink = 1; 552 553 config->query_timeout = DEFAULT_QUERY_TIMEOUT; 554 config->threads_num = DEFAULT_THREADS_NUM; 555 556 for (i = 0; i < config->entries_size; ++i) 557 destroy_configuration_entry(config->entries[i]); 558 config->entries_size = 0; 559 560 TRACE_OUT(fill_configuration_defaults); 561 } 562 563 void 564 destroy_configuration(struct configuration *config) 565 { 566 int i; 567 TRACE_IN(destroy_configuration); 568 assert(config != NULL); 569 free(config->pidfile_path); 570 free(config->socket_path); 571 572 for (i = 0; i < config->entries_size; ++i) 573 destroy_configuration_entry(config->entries[i]); 574 free(config->entries); 575 576 pthread_rwlock_destroy(&config->rwlock); 577 free(config); 578 TRACE_OUT(destroy_configuration); 579 } 580