• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/build/buildd-opendnssec_1.3.2-1~bpo60+1-mipsel-iYafXM/opendnssec-1.3.2/signer/src/daemon/engine.c

Go to the documentation of this file.
00001 /*
00002  * $Id: engine.c 5432 2011-08-22 12:55:04Z matthijs $
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 "config.h"
00035 #include "daemon/cfg.h"
00036 #include "daemon/cmdhandler.h"
00037 #include "daemon/engine.h"
00038 #include "daemon/signal.h"
00039 #include "daemon/worker.h"
00040 #include "scheduler/schedule.h"
00041 #include "scheduler/task.h"
00042 #include "shared/allocator.h"
00043 #include "shared/file.h"
00044 #include "shared/locks.h"
00045 #include "shared/log.h"
00046 #include "shared/privdrop.h"
00047 #include "shared/status.h"
00048 #include "shared/util.h"
00049 #include "signer/zone.h"
00050 #include "signer/zonelist.h"
00051 #include "tools/zone_fetcher.h"
00052 
00053 #include <errno.h>
00054 #include <libhsm.h>
00055 #include <libxml/parser.h>
00056 #include <signal.h>
00057 #include <stdio.h>
00058 #include <stdlib.h>
00059 #include <string.h>
00060 #include <strings.h>
00061 #include <sys/socket.h>
00062 #include <sys/types.h>
00063 #include <sys/un.h>
00064 #include <time.h>
00065 #include <unistd.h>
00066 
00067 static const char* engine_str = "engine";
00068 
00069 
00074 static engine_type*
00075 engine_create(void)
00076 {
00077     engine_type* engine;
00078     allocator_type* allocator = allocator_create(malloc, free);
00079     if (!allocator) {
00080         return NULL;
00081     }
00082     engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type));
00083     if (!engine) {
00084         allocator_cleanup(allocator);
00085         return NULL;
00086     }
00087     engine->allocator = allocator;
00088     engine->config = NULL;
00089     engine->workers = NULL;
00090     engine->drudgers = NULL;
00091     engine->cmdhandler = NULL;
00092     engine->cmdhandler_done = 0;
00093     engine->pid = -1;
00094     engine->zfpid = -1;
00095     engine->uid = -1;
00096     engine->gid = -1;
00097     engine->daemonize = 0;
00098     engine->need_to_exit = 0;
00099     engine->need_to_reload = 0;
00100 
00101     lock_basic_init(&engine->signal_lock);
00102     lock_basic_set(&engine->signal_cond);
00103     lock_basic_lock(&engine->signal_lock);
00104     engine->signal = SIGNAL_INIT;
00105     lock_basic_unlock(&engine->signal_lock);
00106 
00107     engine->zonelist = zonelist_create(engine->allocator);
00108     if (!engine->zonelist) {
00109         engine_cleanup(engine);
00110         return NULL;
00111     }
00112     engine->taskq = schedule_create(engine->allocator);
00113     if (!engine->taskq) {
00114         engine_cleanup(engine);
00115         return NULL;
00116     }
00117     engine->signq = fifoq_create(engine->allocator);
00118     if (!engine->signq) {
00119         engine_cleanup(engine);
00120         return NULL;
00121     }
00122     return engine;
00123 }
00124 
00125 
00130 static void*
00131 cmdhandler_thread_start(void* arg)
00132 {
00133     cmdhandler_type* cmd = (cmdhandler_type*) arg;
00134     ods_thread_blocksigs();
00135     cmdhandler_start(cmd);
00136     return NULL;
00137 }
00138 static void
00139 engine_start_cmdhandler(engine_type* engine)
00140 {
00141     ods_log_assert(engine);
00142     ods_log_debug("[%s] start command handler", engine_str);
00143     engine->cmdhandler->engine = engine;
00144     ods_thread_create(&engine->cmdhandler->thread_id,
00145         cmdhandler_thread_start, engine->cmdhandler);
00146     return;
00147 }
00152 static int
00153 self_pipe_trick(engine_type* engine)
00154 {
00155     int sockfd, ret;
00156     struct sockaddr_un servaddr;
00157     const char* servsock_filename = ODS_SE_SOCKFILE;
00158 
00159     ods_log_assert(engine);
00160     ods_log_assert(engine->cmdhandler);
00161 
00162     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
00163     if (sockfd <= 0) {
00164         ods_log_error("[%s] cannot connect to command handler: "
00165             "socket() failed: %s\n", engine_str, strerror(errno));
00166         return 1;
00167     } else {
00168         bzero(&servaddr, sizeof(servaddr));
00169         servaddr.sun_family = AF_UNIX;
00170         strncpy(servaddr.sun_path, servsock_filename,
00171             sizeof(servaddr.sun_path) - 1);
00172 
00173         ret = connect(sockfd, (const struct sockaddr*) &servaddr,
00174             sizeof(servaddr));
00175         if (ret != 0) {
00176             ods_log_error("[%s] cannot connect to command handler: "
00177                 "connect() failed: %s\n", engine_str, strerror(errno));
00178             close(sockfd);
00179             return 1;
00180         } else {
00181             /* self-pipe trick */
00182             ods_writen(sockfd, "", 1);
00183             close(sockfd);
00184         }
00185     }
00186     return 0;
00187 }
00192 static void
00193 engine_stop_cmdhandler(engine_type* engine)
00194 {
00195     ods_log_assert(engine);
00196     if (!engine->cmdhandler) {
00197         return;
00198     }
00199     ods_log_debug("[%s] stop command handler", engine_str);
00200     engine->cmdhandler->need_to_exit = 1;
00201     if (self_pipe_trick(engine) == 0) {
00202         while (!engine->cmdhandler_done) {
00203             ods_log_debug("[%s] waiting for command handler to exit...",
00204                 engine_str);
00205             sleep(1);
00206         }
00207     } else {
00208         ods_log_error("[%s] command handler self pipe trick failed, "
00209             "unclean shutdown", engine_str);
00210     }
00211     return;
00212 }
00213 
00214 
00219 static ods_status
00220 engine_privdrop(engine_type* engine)
00221 {
00222     ods_status status = ODS_STATUS_OK;
00223     uid_t uid = -1;
00224     gid_t gid = -1;
00225 
00226     ods_log_assert(engine);
00227     ods_log_assert(engine->config);
00228     ods_log_debug("[%s] drop privileges", engine_str);
00229 
00230     if (engine->config->username && engine->config->group) {
00231         ods_log_verbose("[%s] drop privileges to user %s, group %s",
00232            engine_str, engine->config->username, engine->config->group);
00233     } else if (engine->config->username) {
00234         ods_log_verbose("[%s] drop privileges to user %s", engine_str,
00235            engine->config->username);
00236     } else if (engine->config->group) {
00237         ods_log_verbose("[%s] drop privileges to group %s", engine_str,
00238            engine->config->group);
00239     }
00240     if (engine->config->chroot) {
00241         ods_log_verbose("[%s] chroot to %s", engine_str,
00242             engine->config->chroot);
00243     }
00244     status = privdrop(engine->config->username, engine->config->group,
00245         engine->config->chroot, &uid, &gid);
00246     engine->uid = uid;
00247     engine->gid = gid;
00248     privclose(engine->config->username, engine->config->group);
00249     return status;
00250 }
00251 
00252 
00257 static void
00258 engine_create_workers(engine_type* engine)
00259 {
00260     size_t i = 0;
00261     ods_log_assert(engine);
00262     ods_log_assert(engine->config);
00263     ods_log_assert(engine->allocator);
00264     engine->workers = (worker_type**) allocator_alloc(engine->allocator,
00265         ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*));
00266     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00267         engine->workers[i] = worker_create(engine->allocator, i,
00268             WORKER_WORKER);
00269     }
00270     return;
00271 }
00272 static void
00273 engine_create_drudgers(engine_type* engine)
00274 {
00275     size_t i = 0;
00276     ods_log_assert(engine);
00277     ods_log_assert(engine->config);
00278     ods_log_assert(engine->allocator);
00279     engine->drudgers = (worker_type**) allocator_alloc(engine->allocator,
00280         ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*));
00281     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00282         engine->drudgers[i] = worker_create(engine->allocator, i,
00283             WORKER_DRUDGER);
00284     }
00285     return;
00286 }
00287 static void*
00288 worker_thread_start(void* arg)
00289 {
00290     worker_type* worker = (worker_type*) arg;
00291     ods_thread_blocksigs();
00292     worker_start(worker);
00293     return NULL;
00294 }
00295 static void
00296 engine_start_workers(engine_type* engine)
00297 {
00298     size_t i = 0;
00299 
00300     ods_log_assert(engine);
00301     ods_log_assert(engine->config);
00302     ods_log_debug("[%s] start workers", engine_str);
00303     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00304         engine->workers[i]->need_to_exit = 0;
00305         engine->workers[i]->engine = (struct engine_struct*) engine;
00306         ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
00307             engine->workers[i]);
00308     }
00309     return;
00310 }
00311 static void
00312 engine_start_drudgers(engine_type* engine)
00313 {
00314     size_t i = 0;
00315 
00316     ods_log_assert(engine);
00317     ods_log_assert(engine->config);
00318     ods_log_debug("[%s] start drudgers", engine_str);
00319     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00320         engine->drudgers[i]->need_to_exit = 0;
00321         engine->drudgers[i]->engine = (struct engine_struct*) engine;
00322         ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
00323             engine->drudgers[i]);
00324     }
00325     return;
00326 }
00327 static void
00328 engine_stop_workers(engine_type* engine)
00329 {
00330     size_t i = 0;
00331 
00332     ods_log_assert(engine);
00333     ods_log_assert(engine->config);
00334     ods_log_debug("[%s] stop workers", engine_str);
00335     /* tell them to exit and wake up sleepyheads */
00336     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00337         engine->workers[i]->need_to_exit = 1;
00338         worker_wakeup(engine->workers[i]);
00339     }
00340     /* head count */
00341     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00342         ods_log_debug("[%s] join worker %i", engine_str, i+1);
00343         ods_thread_join(engine->workers[i]->thread_id);
00344         engine->workers[i]->engine = NULL;
00345     }
00346     return;
00347 }
00348 static void
00349 engine_stop_drudgers(engine_type* engine)
00350 {
00351     size_t i = 0;
00352 
00353     ods_log_assert(engine);
00354     ods_log_assert(engine->config);
00355     ods_log_debug("[%s] stop drudgers", engine_str);
00356     /* tell them to exit and wake up sleepyheads */
00357     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00358         engine->drudgers[i]->need_to_exit = 1;
00359     }
00360     worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
00361 
00362     /* head count */
00363     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00364         ods_log_debug("[%s] join drudger %i", engine_str, i+1);
00365         ods_thread_join(engine->drudgers[i]->thread_id);
00366         engine->drudgers[i]->engine = NULL;
00367     }
00368     return;
00369 }
00370 
00371 
00376 void
00377 engine_wakeup_workers(engine_type* engine)
00378 {
00379     size_t i = 0;
00380 
00381     ods_log_assert(engine);
00382     ods_log_assert(engine->config);
00383     ods_log_debug("[%s] wake up workers", engine_str);
00384     /* wake up sleepyheads */
00385     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00386         worker_wakeup(engine->workers[i]);
00387     }
00388     return;
00389 }
00390 
00391 
00396 static int
00397 start_zonefetcher(engine_type* engine)
00398 {
00399     pid_t zfpid = 0;
00400     int result = 0;
00401     char* zf_filename = NULL;
00402     char* zl_filename = NULL;
00403     char* log_filename = NULL;
00404     char* grp = NULL;
00405     char* usr = NULL;
00406     char* chrt = NULL;
00407     int use_syslog = 0;
00408     int verbosity = 0;
00409 
00410     ods_log_assert(engine);
00411     ods_log_assert(engine->config);
00412 
00413     if (!engine->config->zonefetch_filename) {
00414         /* zone fetcher disabled */
00415         return 0;
00416     }
00417 
00418     switch ((zfpid = fork())) {
00419         case -1: /* error */
00420             ods_log_error("failed to fork zone fetcher: %s",
00421                 strerror(errno));
00422             return 1;
00423         case 0: /* child */
00424             break;
00425         default: /* parent */
00426             engine->zfpid = zfpid;
00427             return 0;
00428     }
00429 
00430     if (setsid() == -1) {
00431         ods_log_error("failed to setsid zone fetcher: %s",
00432             strerror(errno));
00433         return 1;
00434     }
00435 
00436     ods_log_verbose("zone fetcher running as pid %lu",
00437         (unsigned long) getpid());
00438 
00439     if (engine->config->zonefetch_filename) {
00440         zf_filename = strdup(engine->config->zonefetch_filename);
00441     }
00442     if (engine->config->zonelist_filename) {
00443         zl_filename = strdup(engine->config->zonelist_filename);
00444     }
00445     if (engine->config->group) {
00446         grp = strdup(engine->config->group);
00447     }
00448     if (engine->config->username) {
00449         usr = strdup(engine->config->username);
00450     }
00451     if (engine->config->chroot) {
00452         chrt = strdup(engine->config->chroot);
00453     }
00454     if (engine->config->log_filename) {
00455         log_filename = strdup(engine->config->log_filename);
00456     }
00457     use_syslog = engine->config->use_syslog;
00458     verbosity = engine->config->verbosity;
00459 
00460     result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr,
00461         chrt, log_filename, use_syslog, verbosity);
00462 
00463     ods_log_verbose("zone fetcher done", result);
00464     if (zf_filename)  { free((void*)zf_filename); }
00465     if (zl_filename)  { free((void*)zl_filename); }
00466     if (grp)          { free((void*)grp); }
00467     if (usr)          { free((void*)usr); }
00468     if (chrt)         { free((void*)chrt); }
00469     if (log_filename) { free((void*)log_filename); }
00470 
00471     engine_cleanup(engine);
00472     engine = NULL;
00473     ods_log_close();
00474     xmlCleanupParser();
00475     xmlCleanupGlobals();
00476     xmlCleanupThreads();
00477     exit(result);
00478 
00479     return 0;
00480 }
00481 
00482 
00487 static void
00488 reload_zonefetcher(engine_type* engine)
00489 {
00490     int result = 0;
00491 
00492     ods_log_assert(engine);
00493     ods_log_assert(engine->config);
00494 
00495     if (engine->config->zonefetch_filename) {
00496         if (engine->zfpid > 0) {
00497             result = kill(engine->zfpid, SIGHUP);
00498             if (result == -1) {
00499                 ods_log_error("cannot reload zone fetcher: %s",
00500                     strerror(errno));
00501             } else {
00502                 ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid);
00503             }
00504         } else {
00505             ods_log_error("cannot reload zone fetcher: process id unknown");
00506         }
00507     }
00508     return;
00509 }
00510 
00511 
00516 static void
00517 stop_zonefetcher(engine_type* engine)
00518 {
00519     int result = 0;
00520 
00521     ods_log_assert(engine);
00522     ods_log_assert(engine->config);
00523 
00524     if (engine->config->zonefetch_filename) {
00525         if (engine->zfpid > 0) {
00526             result = kill(engine->zfpid, SIGTERM);
00527             if (result == -1) {
00528                 ods_log_error("cannot stop zone fetcher: %s", strerror(errno));
00529             } else {
00530                 ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid);
00531             }
00532             engine->zfpid = -1;
00533         } else {
00534             ods_log_error("cannot stop zone fetcher: process id unknown");
00535         }
00536     }
00537     return;
00538 }
00539 
00540 
00545 static ods_status
00546 engine_init_adapters(engine_type* engine)
00547 {
00548     size_t i = 0;
00549     ods_status status = ODS_STATUS_OK;
00550 
00551     ods_log_assert(engine);
00552     ods_log_assert(engine->config);
00553     ods_log_debug("[%s] initialize adapters", engine_str);
00554     for (i=0; i < (size_t) engine->config->num_adapters; i++) {
00555         status = adapter_init(engine->config->adapters[i]);
00556         if (status != ODS_STATUS_OK) {
00557             return status;
00558         }
00559     }
00560     return status;
00561 }
00562 
00563 
00568 static ods_status
00569 engine_setup(engine_type* engine)
00570 {
00571     struct sigaction action;
00572     int result = 0;
00573     ods_status status = ODS_STATUS_OK;
00574 
00575     ods_log_debug("[%s] signer setup", engine_str);
00576     if (!engine || !engine->config) {
00577         return ODS_STATUS_ASSERT_ERR;
00578     }
00579 
00580     /* create command handler (before chowning socket file) */
00581     engine->cmdhandler = cmdhandler_create(engine->allocator,
00582         engine->config->clisock_filename);
00583     if (!engine->cmdhandler) {
00584         ods_log_error("[%s] create command handler to %s failed",
00585             engine_str, engine->config->clisock_filename);
00586         return ODS_STATUS_CMDHANDLER_ERR;
00587     }
00588 
00589     /* fork of fetcher */
00590     if (start_zonefetcher(engine) != 0) {
00591         ods_log_error("[%s] cannot start zonefetcher", engine_str);
00592         return ODS_STATUS_ERR;
00593     }
00594 
00595     /* initialize adapters */
00596     status = engine_init_adapters(engine);
00597     if (status != ODS_STATUS_OK) {
00598         ods_log_error("[%s] initializing adapters failed", engine_str);
00599         return status;
00600     }
00601 
00602     /* privdrop */
00603     engine->uid = privuid(engine->config->username);
00604     engine->gid = privgid(engine->config->group);
00605     /* TODO: does piddir exists? */
00606     /* remove the chown stuff: piddir? */
00607     ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
00608     ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
00609     ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
00610     if (engine->config->log_filename && !engine->config->use_syslog) {
00611         ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
00612     }
00613     if (engine->config->working_dir &&
00614         chdir(engine->config->working_dir) != 0) {
00615         ods_log_error("[%s] chdir to %s failed: %s", engine_str,
00616             engine->config->working_dir, strerror(errno));
00617         return ODS_STATUS_CHDIR_ERR;
00618     }
00619     if (engine_privdrop(engine) != ODS_STATUS_OK) {
00620         ods_log_error("[%s] unable to drop privileges", engine_str);
00621         return ODS_STATUS_PRIVDROP_ERR;
00622     }
00623 
00624     /* daemonize */
00625     if (engine->daemonize) {
00626         switch ((engine->pid = fork())) {
00627             case -1: /* error */
00628                 ods_log_error("[%s] unable to fork daemon: %s",
00629                     engine_str, strerror(errno));
00630                 return ODS_STATUS_FORK_ERR;
00631             case 0: /* child */
00632                 break;
00633             default: /* parent */
00634                 engine_cleanup(engine);
00635                 engine = NULL;
00636                 xmlCleanupParser();
00637                 xmlCleanupGlobals();
00638                 xmlCleanupThreads();
00639                 exit(0);
00640         }
00641         if (setsid() == -1) {
00642             ods_log_error("[%s] unable to setsid daemon (%s)",
00643                 engine_str, strerror(errno));
00644             return ODS_STATUS_SETSID_ERR;
00645         }
00646     }
00647     engine->pid = getpid();
00648     ods_log_verbose("[%s] running as pid %lu", engine_str,
00649         (unsigned long) engine->pid);
00650 
00651     /* catch signals */
00652     signal_set_engine(engine);
00653     action.sa_handler = signal_handler;
00654     sigfillset(&action.sa_mask);
00655     action.sa_flags = 0;
00656     sigaction(SIGHUP, &action, NULL);
00657     sigaction(SIGTERM, &action, NULL);
00658 
00659     /* set up hsm */ /* LEAK */
00660     result = hsm_open(engine->config->cfg_filename, hsm_prompt_pin, NULL);
00661     if (result != HSM_OK) {
00662         char *error =  hsm_get_error(NULL);
00663         if (error != NULL) {
00664             ods_log_error("[%s] %s", engine_str, error);
00665             free(error);
00666         }
00667         ods_log_error("[%s] error initializing libhsm (errno %i)",
00668             engine_str, result);
00669         return ODS_STATUS_HSM_ERR;
00670     }
00671 
00672     /* create workers */
00673     engine_create_workers(engine);
00674     engine_create_drudgers(engine);
00675 
00676     /* start command handler */
00677     engine_start_cmdhandler(engine);
00678 
00679     /* write pidfile */
00680     if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
00681         hsm_close();
00682         ods_log_error("[%s] unable to write pid file", engine_str);
00683         return ODS_STATUS_WRITE_PIDFILE_ERR;
00684     }
00685 
00686     return ODS_STATUS_OK;
00687 }
00688 
00689 
00694 static int
00695 engine_all_zones_processed(engine_type* engine)
00696 {
00697     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00698     zone_type* zone = NULL;
00699 
00700     ods_log_assert(engine);
00701     ods_log_assert(engine->zonelist);
00702     ods_log_assert(engine->zonelist->zones);
00703 
00704     node = ldns_rbtree_first(engine->zonelist->zones);
00705     while (node && node != LDNS_RBTREE_NULL) {
00706         zone = (zone_type*) node->key;
00707         if (!zone->processed) {
00708                 return 0;
00709         }
00710         node = ldns_rbtree_next(node);
00711     }
00712     return 1;
00713 }
00714 
00715 
00720 static void
00721 engine_run(engine_type* engine, int single_run)
00722 {
00723     if (!engine) {
00724         return;
00725     }
00726     ods_log_assert(engine);
00727 
00728     engine_start_workers(engine);
00729     engine_start_drudgers(engine);
00730 
00731     lock_basic_lock(&engine->signal_lock);
00732     /* [LOCK] signal */
00733     engine->signal = SIGNAL_RUN;
00734     /* [UNLOCK] signal */
00735     lock_basic_unlock(&engine->signal_lock);
00736 
00737     while (!engine->need_to_exit && !engine->need_to_reload) {
00738         lock_basic_lock(&engine->signal_lock);
00739         /* [LOCK] signal */
00740         engine->signal = signal_capture(engine->signal);
00741         switch (engine->signal) {
00742             case SIGNAL_RUN:
00743                 ods_log_assert(1);
00744                 break;
00745             case SIGNAL_RELOAD:
00746                 engine->need_to_reload = 1;
00747                 break;
00748             case SIGNAL_SHUTDOWN:
00749                 engine->need_to_exit = 1;
00750                 break;
00751             default:
00752                 ods_log_warning("[%s] invalid signal captured: %d, "
00753                     "keep running", engine_str, signal);
00754                 engine->signal = SIGNAL_RUN;
00755                 break;
00756         }
00757         /* [UNLOCK] signal */
00758         lock_basic_unlock(&engine->signal_lock);
00759 
00760         if (single_run) {
00761            engine->need_to_exit = engine_all_zones_processed(engine);
00762         }
00763 
00764         lock_basic_lock(&engine->signal_lock);
00765         /* [LOCK] signal */
00766         if (engine->signal == SIGNAL_RUN && !single_run) {
00767            ods_log_debug("[%s] taking a break", engine_str);
00768            lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
00769         }
00770         /* [UNLOCK] signal */
00771         lock_basic_unlock(&engine->signal_lock);
00772     }
00773     ods_log_debug("[%s] signer halted", engine_str);
00774     engine_stop_drudgers(engine);
00775     engine_stop_workers(engine);
00776     return;
00777 }
00778 
00779 
00784 static void
00785 set_notify_ns(zone_type* zone, const char* cmd)
00786 {
00787     const char* str = NULL;
00788     const char* str2 = NULL;
00789 
00790     ods_log_assert(cmd);
00791     ods_log_assert(zone);
00792     ods_log_assert(zone->name);
00793     ods_log_assert(zone->adoutbound);
00794 
00795     if (zone->adoutbound->type == ADAPTER_FILE) {
00796         str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
00797     } else {
00798         str = cmd;
00799     }
00800 
00801     str2 = ods_replace(str, "%zone", zone->name);
00802     free((void*)str);
00803     zone->notify_ns = (const char*) str2;
00804     ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
00805     return;
00806 }
00807 
00808 
00813 void
00814 engine_update_zones(engine_type* engine)
00815 {
00816     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00817     zone_type* zone = NULL;
00818     zone_type* delzone = NULL;
00819     task_type* task = NULL;
00820     ods_status status = ODS_STATUS_OK;
00821     int wake_up = 0;
00822     time_t now;
00823 
00824     if (!engine || !engine->zonelist || !engine->zonelist->zones) {
00825         ods_log_error("[%s] cannot update zones: no engine or zonelist",
00826             engine_str);
00827         return;
00828     }
00829     ods_log_assert(engine);
00830     ods_log_assert(engine->zonelist);
00831     ods_log_assert(engine->zonelist->zones);
00832 
00833     now = time_now();
00834     reload_zonefetcher(engine);
00835 
00836     lock_basic_lock(&engine->zonelist->zl_lock);
00837     /* [LOCK] zonelist */
00838     node = ldns_rbtree_first(engine->zonelist->zones);
00839     while (node && node != LDNS_RBTREE_NULL) {
00840         zone = (zone_type*) node->data;
00841         task = NULL; /* reset task */
00842 
00843         if (zone->tobe_removed) {
00844             node = ldns_rbtree_next(node);
00845 
00846             lock_basic_lock(&zone->zone_lock);
00847             /* [LOCK] zone */
00848             delzone = zonelist_del_zone(engine->zonelist, zone);
00849             if (delzone) {
00850                 lock_basic_lock(&engine->taskq->schedule_lock);
00851                 /* [LOCK] schedule */
00852                 task = unschedule_task(engine->taskq,
00853                     (task_type*) zone->task);
00854                 /* [UNLOCK] schedule */
00855                 lock_basic_unlock(&engine->taskq->schedule_lock);
00856             }
00857             task_cleanup(task);
00858             task = NULL;
00859             /* [UNLOCK] zone */
00860             lock_basic_unlock(&zone->zone_lock);
00861 
00862             zone_cleanup(zone);
00863             zone = NULL;
00864             continue;
00865         } else if (zone->just_added) {
00866 
00867             lock_basic_lock(&zone->zone_lock);
00868             ods_log_assert(!zone->task);
00869             zone->just_added = 0;
00870             /* notify nameserver */
00871             if (engine->config->notify_command && !zone->notify_ns) {
00872                 set_notify_ns(zone, engine->config->notify_command);
00873             }
00874             /* schedule task */
00875             task = task_create(TASK_SIGNCONF, now, zone->name, zone);
00876             if (!task) {
00877                 ods_log_crit("[%s] failed to create task for zone %s",
00878                     engine_str, zone->name);
00879             } else {
00880                 lock_basic_lock(&engine->taskq->schedule_lock);
00881                 /* [LOCK] schedule */
00882                 status = schedule_task(engine->taskq, task, 0);
00883                 /* [UNLOCK] schedule */
00884                 lock_basic_unlock(&engine->taskq->schedule_lock);
00885                 wake_up = 1;
00886             }
00887             /* zone fetcher enabled? */
00888             zone->fetch = (engine->config->zonefetch_filename != NULL);
00889             lock_basic_unlock(&zone->zone_lock);
00890         } else if (zone->just_updated) {
00891             lock_basic_lock(&zone->zone_lock);
00892             ods_log_assert(zone->task);
00893             zone->just_updated = 0;
00894             /* reschedule task */
00895             lock_basic_lock(&engine->taskq->schedule_lock);
00896             /* [LOCK] schedule */
00897             task = unschedule_task(engine->taskq, (task_type*) zone->task);
00898             if (task != NULL) {
00899                 ods_log_debug("[%s] reschedule task for zone %s", engine_str,
00900                     zone->name);
00901                 if (task->what != TASK_SIGNCONF) {
00902                     task->halted = task->what;
00903                     task->interrupt = TASK_SIGNCONF;
00904                 }
00905                 task->what = TASK_SIGNCONF;
00906                 task->when = now;
00907                 status = schedule_task(engine->taskq, task, 0);
00908             } else {
00909                 /* task not queued, being worked on? */
00910                 ods_log_debug("[%s] worker busy with zone %s, will update "
00911                     "signconf as soon as possible", engine_str, zone->name);
00912                 task = (task_type*) zone->task;
00913                 task->interrupt = TASK_SIGNCONF;
00914                 /* task->halted set by worker */
00915             }
00916             /* [UNLOCK] schedule */
00917             lock_basic_unlock(&engine->taskq->schedule_lock);
00918             lock_basic_unlock(&zone->zone_lock);
00919 
00920             wake_up = 1;
00921         }
00922 
00923         zone->task = task;
00924         if (status != ODS_STATUS_OK) {
00925             ods_log_crit("[%s] failed to schedule task for zone %s: %s",
00926                 engine_str, zone->name, ods_status2str(status));
00927             task_cleanup(task);
00928             zone->task = NULL;
00929         }
00930         node = ldns_rbtree_next(node);
00931     }
00932     /* [UNLOCK] zonelist */
00933     lock_basic_unlock(&engine->zonelist->zl_lock);
00934     if (wake_up) {
00935         engine_wakeup_workers(engine);
00936     }
00937     return;
00938 }
00939 
00940 
00945 static ods_status
00946 engine_recover(engine_type* engine)
00947 {
00948     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00949     zone_type* zone = NULL;
00950     ods_status status = ODS_STATUS_OK;
00951     ods_status result = ODS_STATUS_UNCHANGED;
00952 
00953     if (!engine || !engine->zonelist || !engine->zonelist->zones) {
00954         ods_log_error("[%s] cannot update zones: no engine or zonelist",
00955             engine_str);
00956         return ODS_STATUS_OK; /* will trigger update zones */
00957     }
00958     ods_log_assert(engine);
00959     ods_log_assert(engine->zonelist);
00960     ods_log_assert(engine->zonelist->zones);
00961 
00962     lock_basic_lock(&engine->zonelist->zl_lock);
00963     /* [LOCK] zonelist */
00964     node = ldns_rbtree_first(engine->zonelist->zones);
00965     while (node && node != LDNS_RBTREE_NULL) {
00966         zone = (zone_type*) node->data;
00967 
00968         ods_log_assert(zone->just_added);
00969         status = zone_recover(zone);
00970         if (status == ODS_STATUS_OK) {
00971             ods_log_assert(zone->task);
00972             ods_log_assert(zone->zonedata);
00973             ods_log_assert(zone->signconf);
00974             /* notify nameserver */
00975             if (engine->config->notify_command && !zone->notify_ns) {
00976                 set_notify_ns(zone, engine->config->notify_command);
00977             }
00978             /* zone fetcher enabled? */
00979             zone->fetch = (engine->config->zonefetch_filename != NULL);
00980             /* schedule task */
00981             lock_basic_lock(&engine->taskq->schedule_lock);
00982             /* [LOCK] schedule */
00983             status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
00984             /* [UNLOCK] schedule */
00985             lock_basic_unlock(&engine->taskq->schedule_lock);
00986 
00987             if (status != ODS_STATUS_OK) {
00988                 ods_log_crit("[%s] unable to schedule task for zone %s: %s",
00989                     engine_str, zone->name, ods_status2str(status));
00990                 task_cleanup((task_type*) zone->task);
00991                 zone->task = NULL;
00992                 result = ODS_STATUS_OK; /* will trigger update zones */
00993             } else {
00994                 ods_log_verbose("[%s] recovered zone %s", engine_str,
00995                     zone->name);
00996                 /* recovery done */
00997                 zone->just_added = 0;
00998             }
00999         } else {
01000             if (status != ODS_STATUS_UNCHANGED) {
01001                 ods_log_warning("[%s] unable to recover zone %s from backup,"
01002                 " performing full sign", engine_str, zone->name);
01003             }
01004             result = ODS_STATUS_OK; /* will trigger update zones */
01005         }
01006         node = ldns_rbtree_next(node);
01007     }
01008     /* [UNLOCK] zonelist */
01009     lock_basic_unlock(&engine->zonelist->zl_lock);
01010     return result;
01011 }
01012 
01013 
01018 void
01019 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
01020     int info, int single_run)
01021 {
01022     engine_type* engine = NULL;
01023     int use_syslog = 0;
01024     ods_status zl_changed = ODS_STATUS_UNCHANGED;
01025     ods_status status = ODS_STATUS_OK;
01026     int close_hsm = 0;
01027 
01028     ods_log_assert(cfgfile);
01029     ods_log_init(NULL, use_syslog, cmdline_verbosity);
01030     ods_log_verbose("[%s] starting signer", engine_str);
01031 
01032     /* initialize */
01033     xmlInitGlobals();
01034     xmlInitParser();
01035     xmlInitThreads();
01036     engine = engine_create();
01037     if (!engine) {
01038         ods_fatal_exit("[%s] create failed", engine_str);
01039         return;
01040     }
01041     engine->daemonize = daemonize;
01042 
01043     /* config */
01044     engine->config = engine_config(engine->allocator, cfgfile,
01045         cmdline_verbosity);
01046     status = engine_config_check(engine->config);
01047     if (status != ODS_STATUS_OK) {
01048         ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
01049         goto earlyexit;
01050     }
01051     if (info) {
01052         engine_config_print(stdout, engine->config); /* for debugging */
01053         goto earlyexit;
01054     }
01055 
01056     /* open log */
01057     ods_log_init(engine->config->log_filename, engine->config->use_syslog,
01058        engine->config->verbosity);
01059 
01060     /* setup */
01061     tzset(); /* for portability */
01062     status = engine_setup(engine);
01063     if (status != ODS_STATUS_OK) {
01064         ods_log_error("[%s] setup failed: %s", engine_str,
01065             ods_status2str(status));
01066         engine->need_to_exit = 1;
01067         if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
01068             /* command handler had not yet been started */
01069             engine->cmdhandler_done = 1;
01070         }
01071     } else {
01072         /* setup ok, mark hsm open */
01073         close_hsm = 1;
01074     }
01075 
01076     /* run */
01077     while (engine->need_to_exit == 0) {
01078         /* update zone list */
01079         lock_basic_lock(&engine->zonelist->zl_lock);
01080         /* [LOCK] zonelist */
01081         zl_changed = zonelist_update(engine->zonelist,
01082             engine->config->zonelist_filename);
01083         engine->zonelist->just_removed = 0;
01084         engine->zonelist->just_added = 0;
01085         engine->zonelist->just_updated = 0;
01086         /* [UNLOCK] zonelist */
01087         lock_basic_unlock(&engine->zonelist->zl_lock);
01088 
01089         if (engine->need_to_reload) {
01090             ods_log_info("[%s] signer reloading", engine_str);
01091             engine->need_to_reload = 0;
01092         } else {
01093             ods_log_info("[%s] signer started", engine_str);
01094             zl_changed = engine_recover(engine);
01095         }
01096 
01097         /* update zones */
01098         if (zl_changed == ODS_STATUS_OK) {
01099             ods_log_debug("[%s] commit zone list changes", engine_str);
01100             engine_update_zones(engine);
01101             ods_log_debug("[%s] signer configurations updated", engine_str);
01102             zl_changed = ODS_STATUS_UNCHANGED;
01103         }
01104 
01105         engine_run(engine, single_run);
01106     }
01107 
01108     /* shutdown */
01109     ods_log_info("[%s] signer shutdown", engine_str);
01110     stop_zonefetcher(engine);
01111     if (close_hsm) {
01112         hsm_close();
01113     }
01114     if (engine->cmdhandler != NULL) {
01115         engine_stop_cmdhandler(engine);
01116     }
01117 
01118 earlyexit:
01119     if (engine && engine->config) {
01120         if (engine->config->pid_filename) {
01121             (void)unlink(engine->config->pid_filename);
01122         }
01123         if (engine->config->clisock_filename) {
01124             (void)unlink(engine->config->clisock_filename);
01125         }
01126     }
01127     engine_cleanup(engine);
01128     engine = NULL;
01129     ods_log_close();
01130     xmlCleanupParser();
01131     xmlCleanupGlobals();
01132     xmlCleanupThreads();
01133     return;
01134 }
01135 
01136 
01141 void
01142 engine_cleanup(engine_type* engine)
01143 {
01144     size_t i = 0;
01145     allocator_type* allocator;
01146     cond_basic_type signal_cond;
01147     lock_basic_type signal_lock;
01148 
01149     if (!engine) {
01150         return;
01151     }
01152     allocator = engine->allocator;
01153     signal_cond = engine->signal_cond;
01154     signal_lock = engine->signal_lock;
01155 
01156     if (engine->workers && engine->config) {
01157         for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
01158             worker_cleanup(engine->workers[i]);
01159         }
01160         allocator_deallocate(allocator, (void*) engine->workers);
01161     }
01162     if (engine->drudgers && engine->config) {
01163        for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
01164            worker_cleanup(engine->drudgers[i]);
01165        }
01166         allocator_deallocate(allocator, (void*) engine->drudgers);
01167     }
01168     zonelist_cleanup(engine->zonelist);
01169     schedule_cleanup(engine->taskq);
01170     fifoq_cleanup(engine->signq);
01171     cmdhandler_cleanup(engine->cmdhandler);
01172     engine_config_cleanup(engine->config);
01173     allocator_deallocate(allocator, (void*) engine);
01174 
01175     lock_basic_destroy(&signal_lock);
01176     lock_basic_off(&signal_cond);
01177     allocator_cleanup(allocator);
01178     return;
01179 }

Generated on Sun Dec 18 2011 11:53:58 for OpenDNSSEC-signer by  doxygen 1.7.1