OpenDNSSEC-signer 1.2.1

/build/buildd-opendnssec_1.2.1.dfsg-1-ia64-j6OroR/opendnssec-1.2.1.dfsg/signer/src/scheduler/task.c

Go to the documentation of this file.
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 }