OpenDNSSEC-signer 1.2.1

/build/buildd-opendnssec_1.2.1.dfsg-1-mips-p9AT07/opendnssec-1.2.1.dfsg/signer/src/daemon/worker.c

Go to the documentation of this file.
00001 /*
00002  * $Id: worker.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 "daemon/engine.h"
00035 #include "daemon/worker.h"
00036 #include "scheduler/locks.h"
00037 #include "scheduler/task.h"
00038 #include "signer/tools.h"
00039 #include "signer/zone.h"
00040 #include "util/log.h"
00041 #include "util/se_malloc.h"
00042 
00043 #include <time.h> /* time() */
00044 
00045 
00050 worker_type*
00051 worker_create(int num, int type)
00052 {
00053     worker_type* worker = (worker_type*) se_malloc(sizeof(worker_type));
00054     se_log_debug("create worker[%i]", num +1);
00055     worker->thread_num = num +1;
00056     worker->engineptr = NULL;
00057     worker->tasklist = NULL;
00058     worker->task = NULL;
00059     worker->need_to_exit = 0;
00060     worker->type = type;
00061     lock_basic_init(&worker->worker_lock);
00062     lock_basic_set(&worker->worker_alarm);
00063 
00064     lock_basic_lock(&worker->worker_lock);
00065     worker->sleeping = 0;
00066     worker->waiting = 0;
00067     lock_basic_unlock(&worker->worker_lock);
00068     return worker;
00069 }
00070 
00071 
00076 void
00077 worker_start(worker_type* worker)
00078 {
00079     task_type* task;
00080     time_t now, timeout = 1;
00081     zone_type* zone = NULL;
00082 
00083     se_log_assert(worker);
00084     se_log_assert(worker->type == WORKER_WORKER);
00085     se_log_debug("start worker[%i]", worker->thread_num);
00086 
00087     while (worker->need_to_exit == 0) {
00088         se_log_debug("worker[%i]: report for duty", worker->thread_num);
00089         se_log_debug("worker[%i]: lock tasklist", worker->thread_num);
00090         lock_basic_lock(&worker->tasklist->tasklist_lock);
00091         se_log_debug("worker[%i]: locked tasklist", worker->thread_num);
00092         task = tasklist_pop_task(worker->tasklist);
00093         if (task) {
00094             se_log_debug("worker[%i] perform task for zone %s",
00095                 worker->thread_num, task->who?task->who:"(null)");
00096             zone = task->zone;
00097             zone->in_progress = 1;
00098 
00099             se_log_debug("worker[%i]: unlock tasklist", worker->thread_num);
00100             lock_basic_unlock(&worker->tasklist->tasklist_lock);
00101             se_log_debug("worker[%i]: unlocked tasklist", worker->thread_num);
00102 
00103             worker->task = task;
00104             se_log_debug("worker[%i]: lock zone %s", worker->thread_num,
00105                 task->who);
00106             lock_basic_lock(&zone->zone_lock);
00107             se_log_debug("worker[%i]: locked zone %s", worker->thread_num,
00108                 task->who);
00109             worker_perform_task(worker, task);
00110             zone->processed = 1;
00111             se_log_debug("worker[%i]: unlock zone %s", worker->thread_num,
00112                 task->who);
00113             lock_basic_unlock(&zone->zone_lock);
00114             se_log_debug("worker[%i]: unlocked zone %s", worker->thread_num,
00115                 task->who);
00116             worker->task = NULL;
00117 
00118             if (task->what == TASK_NONE) {
00119                 zone->in_progress = 0;
00120                 se_log_debug("worker[%i]: cleanup task none for zone %s",
00121                     worker->thread_num, task->who);
00122                 task_cleanup(task);
00123             } else {
00124                 se_log_debug("worker[%i]: lock tasklist", worker->thread_num);
00125                 lock_basic_lock(&worker->tasklist->tasklist_lock);
00126                 se_log_debug("worker[%i]: locked tasklist", worker->thread_num);
00127                 zone->in_progress = 0;
00128                 task = tasklist_schedule_task(worker->tasklist, task, 1);
00129                 if (!task) {
00130                     se_log_error("failed to schedule task");
00131                 } else {
00132                     task_backup(task);
00133                 }
00134                 se_log_debug("worker[%i]: unlock tasklist", worker->thread_num);
00135                 lock_basic_unlock(&worker->tasklist->tasklist_lock);
00136                 se_log_debug("worker[%i]: unlocked tasklist", worker->thread_num);
00137             }
00138 
00139             timeout = 1;
00140         } else {
00141             se_log_debug("worker[%i] no task ready", worker->thread_num);
00142             task = tasklist_first_task(worker->tasklist);
00143             now = time_now();
00144             if (task && !worker->tasklist->loading) {
00145                 timeout = (task->when - now);
00146             } else {
00147                 timeout *= 2;
00148                 if (timeout > ODS_SE_MAX_BACKOFF) {
00149                     timeout = ODS_SE_MAX_BACKOFF;
00150                 }
00151             }
00152             se_log_debug("worker[%i]: unlock tasklist", worker->thread_num);
00153             lock_basic_unlock(&worker->tasklist->tasklist_lock);
00154             se_log_debug("worker[%i]: unlocked tasklist", worker->thread_num);
00155 
00156             worker_sleep(worker, timeout);
00157         }
00158     }
00159     return;
00160 }
00161 
00162 
00167 void
00168 worker_perform_task(worker_type* worker, task_type* task)
00169 {
00170     zone_type* zone = NULL;
00171     engine_type* engine = (engine_type*) worker->engineptr;
00172     char* working_dir = NULL;
00173     char* cfg_filename = NULL;
00174     int error = 0;
00175 
00176     se_log_assert(worker);
00177     se_log_assert(task);
00178 
00179     if (!task->zone) {
00180         se_log_error("worker[%i] cannot perform task: no corresponding zone",
00181             worker->thread_num);
00182         return;
00183     }
00184     zone = task->zone;
00185 
00186     switch (task->what) {
00187         case TASK_NONE:
00188             se_log_warning("no task for zone %s", task->who?task->who:"(null)");
00189             break;
00190         case TASK_READ:
00191             if (tools_read_input(zone) != 0) {
00192                 se_log_error("task [read zone %s] failed",
00193                     task->who?task->who:"(null)");
00194                 task->what = TASK_SIGN;
00195                 task->when = time_now() +
00196                     duration2time(zone->signconf->sig_resign_interval);
00197                 goto task_perform_continue;
00198                 break;
00199             }
00200             task->what = TASK_ADDKEYS;
00201         case TASK_ADDKEYS:
00202             if (tools_add_dnskeys(zone) != 0) {
00203                 se_log_error("task [add dnskeys to zone %s] failed",
00204                     task->who?task->who:"(null)");
00205                 task->what = TASK_SIGN;
00206                 task->when = time_now() +
00207                     duration2time(zone->signconf->sig_resign_interval);
00208                 goto task_perform_continue;
00209                 break;
00210             }
00211             task->what = TASK_UPDATE;
00212         case TASK_UPDATE:
00213             if (tools_update(zone) != 0) {
00214                 se_log_error("task [update zone %s] failed",
00215                     task->who?task->who:"(null)");
00216                 task->what = TASK_SIGN;
00217                 task->when = time_now() +
00218                     duration2time(zone->signconf->sig_resign_interval);
00219                 goto task_perform_continue;
00220                 break;
00221             }
00222             task->what = TASK_NSECIFY;
00223         case TASK_NSECIFY:
00224             if (tools_nsecify(zone) != 0) {
00225                 se_log_error("task [nsecify zone %s] failed",
00226                     task->who?task->who:"(null)");
00227                 goto task_perform_fail;
00228                 break;
00229             }
00230             task->what = TASK_SIGN;
00231         case TASK_SIGN:
00232             if (tools_sign(zone) != 0) {
00233                 se_log_error("task [sign zone %s] failed",
00234                     task->who?task->who:"(null)");
00235                 goto task_perform_fail;
00236                 break;
00237             }
00238             task->what = TASK_AUDIT;
00239         case TASK_AUDIT:
00240             working_dir = se_strdup(engine->config->working_dir);
00241             cfg_filename = se_strdup(engine->config->cfg_filename);
00242             error = tools_audit(zone, working_dir, cfg_filename);
00243             if (working_dir)  { se_free((void*)working_dir); }
00244             if (cfg_filename) { se_free((void*)cfg_filename); }
00245             working_dir = NULL;
00246             cfg_filename = NULL;
00247             if (error) {
00248                 se_log_error("task [audit zone %s] failed",
00249                     task->who?task->who:"(null)");
00250                 task->what = TASK_SIGN;
00251                 goto task_perform_fail;
00252                 break;
00253             }
00254             task->what = TASK_WRITE;
00255         case TASK_WRITE:
00256             if (tools_write_output(zone) != 0) {
00257                 se_log_error("task [write zone %s] failed",
00258                     task->who?task->who:"(null)");
00259                 task->what = TASK_SIGN;
00260                 goto task_perform_fail;
00261                 break;
00262             }
00263             task->what = TASK_SIGN;
00264             task->when = time_now() +
00265                 duration2time(zone->signconf->sig_resign_interval);
00266             break;
00267         default:
00268             se_log_warning("unknown task[id %i zone %s], "
00269                 "trying full sign", task->what, task->who?task->who:"(null)");
00270             task->what = TASK_READ;
00271             task->when = time_now();
00272             break;
00273     }
00274     return;
00275 
00276 task_perform_fail:
00277     if (zone->backoff) {
00278         zone->backoff *= 2;
00279         if (zone->backoff > ODS_SE_MAX_BACKOFF) {
00280             zone->backoff = ODS_SE_MAX_BACKOFF;
00281         }
00282     } else {
00283         zone->backoff = 60;
00284     }
00285     task->when += zone->backoff;
00286 
00287 task_perform_continue:
00288     return;
00289 }
00290 
00291 
00296 void
00297 worker_cleanup(worker_type* worker)
00298 {
00299     int num = 0;
00300 
00301     if (worker) {
00302          num = worker->thread_num;
00303          lock_basic_destroy(&worker->worker_lock);
00304          lock_basic_off(&worker->worker_alarm);
00305          se_free((void*)worker);
00306     } else {
00307          se_log_warning("cleanup empty worker");
00308     }
00309     return;
00310 }
00311 
00312 
00317 void
00318 worker_sleep(worker_type* worker, time_t timeout)
00319 {
00320     se_log_assert(worker);
00321     lock_basic_lock(&worker->worker_lock);
00322     worker->sleeping = 1;
00323     lock_basic_sleep(&worker->worker_alarm, &worker->worker_lock,
00324         timeout);
00325     lock_basic_unlock(&worker->worker_lock);
00326     return;
00327 }
00328 
00329 
00334 void
00335 worker_wait(worker_type* worker)
00336 {
00337     se_log_assert(worker);
00338     lock_basic_lock(&worker->worker_lock);
00339     worker->waiting = 1;
00340     lock_basic_sleep(&worker->worker_alarm, &worker->worker_lock, 0);
00341     lock_basic_unlock(&worker->worker_lock);
00342     return;
00343 }
00344 
00345 
00350 void
00351 worker_wakeup(worker_type* worker)
00352 {
00353     se_log_assert(worker);
00354     se_log_assert(!worker->waiting);
00355     if (worker && worker->sleeping && !worker->waiting) {
00356         se_log_debug("wake up worker[%i]", worker->thread_num);
00357         lock_basic_lock(&worker->worker_lock);
00358         lock_basic_alarm(&worker->worker_alarm);
00359         worker->sleeping = 0;
00360         lock_basic_unlock(&worker->worker_lock);
00361     }
00362     return;
00363 }
00364 
00365 
00370 void
00371 worker_notify(worker_type* worker)
00372 {
00373     se_log_assert(worker);
00374     se_log_assert(!worker->sleeping);
00375     if (worker && worker->waiting && !worker->sleeping) {
00376         se_log_debug("notify worker[%i]", worker->thread_num);
00377         lock_basic_lock(&worker->worker_lock);
00378         lock_basic_alarm(&worker->worker_alarm);
00379         worker->waiting = 0;
00380         lock_basic_unlock(&worker->worker_lock);
00381     }
00382     return;
00383 }