OpenDNSSEC-signer 1.2.1
|
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 }