OpenDNSSEC-signer 1.2.1
|
00001 /* 00002 * $Id: task.c 4294 2011-01-13 19:58:29Z jakob $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "scheduler/task.h" 00035 #include "signer/backup.h" 00036 #include "signer/zone.h" 00037 #include "util/duration.h" 00038 #include "util/file.h" 00039 #include "util/log.h" 00040 #include "util/se_malloc.h" 00041 00042 #include <ldns/ldns.h> /* ldns_dname_*(), ldns_rdf_*(), ldns_rbtree_*() */ 00043 #include <time.h> /* ctime() */ 00044 #include <stdio.h> /* fprintf(), snprintf() */ 00045 #include <stdlib.h> 00046 #include <string.h> /* strlen() */ 00047 00048 static void log_task(task_type* task); 00049 00050 00055 task_type* 00056 task_create(int what, time_t when, const char* who, struct zone_struct* zone) 00057 { 00058 task_type* task = (task_type*) se_malloc(sizeof(task_type)); 00059 00060 se_log_assert(who); 00061 se_log_assert(zone); 00062 00063 task->what = what; 00064 task->when = when; 00065 task->backoff = 0; 00066 task->who = se_strdup(who); 00067 task->dname = ldns_dname_new_frm_str(who); 00068 task->flush = 0; 00069 task->zone = zone; 00070 task->zone->task = task; 00071 return task; 00072 } 00073 00074 00079 task_type* 00080 task_recover_from_backup(const char* filename, struct zone_struct* zone) 00081 { 00082 task_type* task = NULL; 00083 FILE* fd = NULL; 00084 const char* who = NULL; 00085 int what = 0; 00086 time_t when = 0; 00087 int flush = 0; 00088 time_t backoff = 0; 00089 00090 se_log_assert(zone); 00091 fd = se_fopen(filename, NULL, "r"); 00092 if (fd) { 00093 if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC) || 00094 !backup_read_check_str(fd, ";who:") || 00095 !backup_read_str(fd, &who) || 00096 !backup_read_check_str(fd, ";what:") || 00097 !backup_read_int(fd, &what) || 00098 !backup_read_check_str(fd, ";when:") || 00099 !backup_read_time_t(fd, &when) || 00100 !backup_read_check_str(fd, ";flush:") || 00101 !backup_read_int(fd, &flush) || 00102 !backup_read_check_str(fd, ";backoff:") || 00103 !backup_read_time_t(fd, &backoff) || 00104 !backup_read_check_str(fd, ODS_SE_FILE_MAGIC)) 00105 { 00106 se_log_error("unable to recover task from file %s: file corrupted", 00107 filename?filename:"(null)"); 00108 task = NULL; 00109 } else { 00110 task = task_create((task_id) what, when, who, zone); 00111 task->flush = flush; 00112 task->backoff = backoff; 00113 } 00114 se_free((void*)who); 00115 se_fclose(fd); 00116 return task; 00117 } 00118 00119 se_log_debug("unable to recover task from file %s: no such file or directory", 00120 filename?filename:"(null)"); 00121 return NULL; 00122 } 00123 00124 00129 void 00130 task_backup(task_type* task) 00131 { 00132 char* filename = NULL; 00133 FILE* fd = NULL; 00134 00135 if (!task) { 00136 return; 00137 } 00138 00139 if (task->who) { 00140 filename = se_build_path(task->who, ".task", 0); 00141 fd = se_fopen(filename, NULL, "w"); 00142 se_free((void*)filename); 00143 } else { 00144 return; 00145 } 00146 00147 if (fd) { 00148 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00149 fprintf(fd, ";who: %s\n", task->who); 00150 fprintf(fd, ";what: %i\n", (int) task->what); 00151 fprintf(fd, ";when: %u\n", (uint32_t) task->when); 00152 fprintf(fd, ";flush: %i\n", task->flush); 00153 fprintf(fd, ";backoff: %u\n", (uint32_t) task->backoff); 00154 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00155 se_fclose(fd); 00156 } else { 00157 se_log_warning("cannot backup task for zone %s: cannot open file " 00158 "%s.task for writing", task->who, task->who); 00159 } 00160 return; 00161 } 00162 00163 00168 void 00169 task_cleanup(task_type* task) 00170 { 00171 if (task) { 00172 if (task->dname) { 00173 ldns_rdf_deep_free(task->dname); 00174 task->dname = NULL; 00175 } 00176 if (task->who) { 00177 se_free((void*)task->who); 00178 task->who = NULL; 00179 } 00180 se_free((void*)task); 00181 } else { 00182 se_log_warning("cleanup empty task"); 00183 } 00184 return; 00185 } 00186 00187 00192 int task_compare(const void* a, const void* b) 00193 { 00194 task_type* x = (task_type*)a; 00195 task_type* y = (task_type*)b; 00196 00197 se_log_assert(x); 00198 se_log_assert(y); 00199 00200 if (x->when != y->when) { 00201 return (int) x->when - y->when; 00202 } 00203 return ldns_dname_compare((const void*) x->dname, (const void*) y->dname); 00204 } 00205 00206 00211 static const char* 00212 taskid2str(int taskid) 00213 { 00214 switch (taskid) { 00215 case TASK_NONE: 00216 return "do nothing with"; 00217 break; 00218 case TASK_READ: 00219 return "read and sign"; 00220 break; 00221 case TASK_ADDKEYS: 00222 return "add keys and sign"; 00223 break; 00224 case TASK_UPDATE: 00225 return "prepare and sign"; 00226 break; 00227 case TASK_NSECIFY: 00228 return "nsecify and sign"; 00229 break; 00230 case TASK_SIGN: 00231 return "sign"; 00232 break; 00233 case TASK_AUDIT: 00234 return "audit"; 00235 break; 00236 case TASK_WRITE: 00237 return "output signed"; 00238 break; 00239 default: 00240 return "???"; 00241 break; 00242 } 00243 00244 return "???"; 00245 } 00246 00247 00252 char* 00253 task2str(task_type* task, char* buftask) 00254 { 00255 time_t now = time_now(); 00256 char* strtime = NULL; 00257 char* strtask = NULL; 00258 00259 se_log_assert(task); 00260 00261 if (task) { 00262 if (task->flush) { 00263 strtime = ctime(&now); 00264 } else { 00265 strtime = ctime(&task->when); 00266 } 00267 if (strtime) { 00268 strtime[strlen(strtime)-1] = '\0'; 00269 } 00270 if (buftask) { 00271 (void)snprintf(buftask, ODS_SE_MAXLINE, "On %s I will %s zone %s\n", 00272 strtime?strtime:"(null)", taskid2str(task->what), 00273 task->who?task->who:"(null)"); 00274 return buftask; 00275 } else { 00276 strtask = (char*) se_calloc(ODS_SE_MAXLINE, sizeof(char)); 00277 snprintf(strtask, ODS_SE_MAXLINE, "On %s I will %s zone %s\n", 00278 strtime?strtime:"(null)", taskid2str(task->what), 00279 task->who?task->who:"(null)"); 00280 return strtask; 00281 } 00282 } 00283 return NULL; 00284 } 00285 00286 00291 void 00292 task_print(FILE* out, task_type* task) 00293 { 00294 time_t now = time_now(); 00295 char* strtime = NULL; 00296 00297 se_log_assert(out); 00298 se_log_assert(task); 00299 00300 if (task) { 00301 if (task->flush) { 00302 strtime = ctime(&now); 00303 } else { 00304 strtime = ctime(&task->when); 00305 } 00306 if (strtime) { 00307 strtime[strlen(strtime)-1] = '\0'; 00308 } 00309 fprintf(out, "On %s I will %s zone %s\n", strtime?strtime:"(null)", 00310 taskid2str(task->what), task->who?task->who:"(null)"); 00311 } 00312 return; 00313 } 00314 00315 00320 static void 00321 log_task(task_type* task) 00322 { 00323 time_t now = time_now(); 00324 char* strtime = NULL; 00325 00326 se_log_assert(task); 00327 if (task) { 00328 if (task->flush) { 00329 strtime = ctime(&now); 00330 } else { 00331 strtime = ctime(&task->when); 00332 } 00333 if (strtime) { 00334 strtime[strlen(strtime)-1] = '\0'; 00335 } 00336 se_log_debug("On %s I will %s zone %s", strtime?strtime:"(null)", 00337 taskid2str(task->what), task->who?task->who:"(null)"); 00338 } 00339 return; 00340 } 00341 00342 00347 tasklist_type* 00348 tasklist_create(void) 00349 { 00350 tasklist_type* tl = (tasklist_type*) se_malloc(sizeof(tasklist_type)); 00351 00352 se_log_debug("create task list"); 00353 tl->tasks = ldns_rbtree_create(task_compare); 00354 lock_basic_init(&tl->tasklist_lock); 00355 00356 lock_basic_lock(&tl->tasklist_lock); 00357 tl->loading = 0; 00358 lock_basic_unlock(&tl->tasklist_lock); 00359 return tl; 00360 } 00361 00362 00367 void 00368 tasklist_cleanup(tasklist_type* list) 00369 { 00370 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00371 task_type* task = NULL; 00372 00373 if (list) { 00374 se_log_debug("clean up task list"); 00375 if (list->tasks) { 00376 node = ldns_rbtree_first(list->tasks); 00377 while (node != LDNS_RBTREE_NULL) { 00378 task = (task_type*) node->data; 00379 task_cleanup(task); 00380 node = ldns_rbtree_next(node); 00381 } 00382 se_rbnode_free(list->tasks->root); 00383 ldns_rbtree_free(list->tasks); 00384 list->tasks = NULL; 00385 } 00386 lock_basic_destroy(&list->tasklist_lock); 00387 se_free((void*) list); 00388 } else { 00389 se_log_warning("cleanup empty task list"); 00390 } 00391 return; 00392 } 00393 00394 00399 static ldns_rbnode_t* 00400 task2node(task_type* task) 00401 { 00402 ldns_rbnode_t* node = (ldns_rbnode_t*) se_malloc(sizeof(ldns_rbnode_t)); 00403 node->key = task; 00404 node->data = task; 00405 return node; 00406 } 00407 00408 00413 static task_type* 00414 tasklist_lookup(tasklist_type* list, task_type* task) 00415 { 00416 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00417 00418 se_log_assert(task); 00419 se_log_assert(list); 00420 se_log_assert(list->tasks); 00421 00422 node = ldns_rbtree_search(list->tasks, task); 00423 if (node && node != LDNS_RBTREE_NULL) { 00424 return (task_type*) node->data; 00425 } 00426 return NULL; 00427 } 00428 00429 00434 task_type* 00435 tasklist_schedule_task(tasklist_type* list, task_type* task, int log) 00436 { 00437 ldns_rbnode_t* new_node = NULL; 00438 zone_type* zone = NULL; 00439 00440 se_log_assert(list); 00441 se_log_assert(list->tasks); 00442 se_log_assert(task); 00443 se_log_debug("schedule task"); 00444 00445 zone = task->zone; 00446 if (zone->in_progress) { 00447 se_log_error("unable to schedule task %s for zone %s: " 00448 " zone in progress", taskid2str(task->what), 00449 task->who?task->who:"(null)"); 00450 task_cleanup(task); 00451 return NULL; 00452 } 00453 00454 if (tasklist_lookup(list, task) != NULL) { 00455 se_log_error("unable to schedule task %s for zone %s: " 00456 " already present", taskid2str(task->what), 00457 task->who?task->who:"(null)"); 00458 task_cleanup(task); 00459 return NULL; 00460 } 00461 00462 new_node = task2node(task); 00463 if (ldns_rbtree_insert(list->tasks, new_node) == NULL) { 00464 se_log_error("unable to schedule task %s for zone %s: " 00465 " insert failed", taskid2str(task->what), 00466 task->who?task->who:"(null)"); 00467 task_cleanup(task); 00468 se_free((void*) new_node); 00469 return NULL; 00470 } 00471 00472 if (log) { 00473 log_task(task); 00474 } 00475 return task; 00476 } 00477 00478 00483 void 00484 tasklist_flush(tasklist_type* list, task_id what) 00485 { 00486 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00487 task_type* task = NULL; 00488 00489 se_log_assert(list); 00490 se_log_assert(list->tasks); 00491 se_log_debug("flush task list"); 00492 00493 node = ldns_rbtree_first(list->tasks); 00494 while (node && node != LDNS_RBTREE_NULL) { 00495 task = (task_type*) node->data; 00496 task->flush = 1; 00497 if (what != TASK_NONE) { 00498 task->what = what; 00499 } 00500 node = ldns_rbtree_next(node); 00501 } 00502 return; 00503 } 00504 00505 00510 task_type* 00511 tasklist_delete_task(tasklist_type* list, task_type* task) 00512 { 00513 ldns_rbnode_t* del_node = LDNS_RBTREE_NULL; 00514 task_type* del_task = NULL; 00515 00516 se_log_assert(list); 00517 se_log_assert(list->tasks); 00518 00519 if (task) { 00520 se_log_debug("delete task from list"); 00521 del_node = ldns_rbtree_delete(list->tasks, (const void*) task); 00522 if (del_node) { 00523 del_task = (task_type*) del_node->data; 00524 se_free((void*)del_node); 00525 return del_task; 00526 } else { 00527 se_log_error("delete task failed"); 00528 log_task(task); 00529 } 00530 } else { 00531 se_log_warning("delete empty task from list"); 00532 } 00533 return NULL; 00534 } 00535 00536 00541 task_type* 00542 tasklist_pop_task(tasklist_type* list) 00543 { 00544 ldns_rbnode_t* first_node = LDNS_RBTREE_NULL; 00545 task_type* pop = NULL; 00546 time_t now; 00547 00548 se_log_assert(list); 00549 se_log_assert(list->tasks); 00550 00551 first_node = ldns_rbtree_first(list->tasks); 00552 if (!first_node) { 00553 return NULL; 00554 } 00555 00556 now = time_now(); 00557 pop = (task_type*) first_node->key; 00558 if (pop && (pop->flush || pop->when <= now)) { 00559 if (pop->flush) { 00560 se_log_debug("flush task for zone %s", pop->who?pop->who:"(null)"); 00561 } else { 00562 se_log_debug("pop task for zone %s", pop->who?pop->who:"(null)"); 00563 } 00564 pop->flush = 0; 00565 return tasklist_delete_task(list, pop); 00566 } 00567 return NULL; 00568 } 00569 00570 00575 task_type* 00576 tasklist_first_task(tasklist_type* list) 00577 { 00578 ldns_rbnode_t* first_node = LDNS_RBTREE_NULL; 00579 task_type* pop = NULL; 00580 00581 se_log_assert(list); 00582 se_log_assert(list->tasks); 00583 00584 first_node = ldns_rbtree_first(list->tasks); 00585 if (!first_node) { 00586 return NULL; 00587 } 00588 00589 pop = (task_type*) first_node->data; 00590 return pop; 00591 } 00592 00593 00598 void 00599 tasklist_print(FILE* out, tasklist_type* list) 00600 { 00601 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00602 task_type* task = NULL; 00603 00604 se_log_assert(out); 00605 se_log_assert(list); 00606 00607 node = ldns_rbtree_first(list->tasks); 00608 while (node && node != LDNS_RBTREE_NULL) { 00609 task = (task_type*) node->data; 00610 task_print(out, task); 00611 node = ldns_rbtree_next(node); 00612 } 00613 fprintf(out, "\n"); 00614 return; 00615 }