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

/build/buildd-opendnssec_1.3.2-1~bpo60+1-ia64-Ga1C3m/opendnssec-1.3.2/signer/src/daemon/cmdhandler.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cmdhandler.c 5408 2011-08-16 08:15:16Z 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 "daemon/cmdhandler.h"
00035 #include "daemon/engine.h"
00036 #include "scheduler/schedule.h"
00037 #include "scheduler/task.h"
00038 #include "shared/allocator.h"
00039 #include "shared/file.h"
00040 #include "shared/locks.h"
00041 #include "shared/log.h"
00042 #include "shared/status.h"
00043 
00044 #include <errno.h>
00045 #include <fcntl.h>
00046 #include <ldns/ldns.h>
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include <string.h>
00050 #include <strings.h>
00051 #include <sys/select.h>
00052 #include <sys/socket.h>
00053 #ifdef HAVE_SYS_TYPES_H
00054 # include <sys/types.h>
00055 #endif
00056 #include <unistd.h>
00057 /* According to earlier standards: select() sys/time.h sys/types.h unistd.h */
00058 #include <sys/time.h>
00059 #include <sys/types.h>
00060 
00061 #define SE_CMDH_CMDLEN 7
00062 
00063 #ifndef SUN_LEN
00064 #define SUN_LEN(su)  (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
00065 #endif
00066 
00067 static int count = 0;
00068 static char* cmdh_str = "cmdhandler";
00069 
00070 
00075 static void
00076 cmdhandler_handle_cmd_help(int sockfd)
00077 {
00078     char buf[ODS_SE_MAXLINE];
00079 
00080     (void) snprintf(buf, ODS_SE_MAXLINE,
00081         "Commands:\n"
00082         "zones           show the currently known zones.\n"
00083         "sign <zone>     read zone and schedule for immediate (re-)sign.\n"
00084         "sign --all      read all zones and schedule all for immediate "
00085                          "(re-)sign.\n"
00086         "clear <zone>    delete the internal storage of this zone.\n"
00087         "                All signatures will be regenerated on the next "
00088                          "re-sign.\n"
00089         "queue           show the current task queue.\n"
00090     );
00091     ods_writen(sockfd, buf, strlen(buf));
00092 
00093     (void) snprintf(buf, ODS_SE_MAXLINE,
00094         "flush           execute all scheduled tasks immediately.\n"
00095         "update <zone>   update this zone signer configurations.\n"
00096         "update [--all]  update zone list and all signer configurations.\n"
00097         "start           start the engine.\n"
00098         "running         check if the engine is running.\n"
00099         "reload          reload the engine.\n"
00100         "stop            stop the engine.\n"
00101         "verbosity <nr>  set verbosity.\n"
00102     );
00103     ods_writen(sockfd, buf, strlen(buf));
00104     return;
00105 }
00106 
00107 
00112 static void
00113 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc)
00114 {
00115     char buf[ODS_SE_MAXLINE];
00116     size_t i;
00117     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00118     zone_type* zone = NULL;
00119 
00120     ods_log_assert(cmdc);
00121     ods_log_assert(cmdc->engine);
00122     if (!cmdc->engine->zonelist || !cmdc->engine->zonelist->zones) {
00123         (void)snprintf(buf, ODS_SE_MAXLINE, "I have no zones configured\n");
00124         ods_writen(sockfd, buf, strlen(buf));
00125         return;
00126     }
00127 
00128     lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00129     /* how many zones */
00130     /* [LOCK] zonelist */
00131     (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n",
00132         (int) cmdc->engine->zonelist->zones->count);
00133     ods_writen(sockfd, buf, strlen(buf));
00134 
00135     /* list zones */
00136     node = ldns_rbtree_first(cmdc->engine->zonelist->zones);
00137     while (node && node != LDNS_RBTREE_NULL) {
00138         zone = (zone_type*) node->data;
00139         for (i=0; i < ODS_SE_MAXLINE; i++) {
00140             buf[i] = 0;
00141         }
00142         (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name);
00143         ods_writen(sockfd, buf, strlen(buf));
00144         node = ldns_rbtree_next(node);
00145     }
00146     /* [UNLOCK] zonelist */
00147     lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00148     return;
00149 }
00150 
00151 
00156 static void
00157 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc,
00158     const char* tbd)
00159 {
00160     char buf[ODS_SE_MAXLINE];
00161     ods_status status = ODS_STATUS_OK;
00162     zone_type* zone = NULL;
00163     task_type* task = NULL;
00164     int zl_changed = 0;
00165 
00166     ods_log_assert(tbd);
00167     ods_log_assert(cmdc);
00168     ods_log_assert(cmdc->engine);
00169     ods_log_assert(cmdc->engine->taskq);
00170 
00171     if (ods_strcmp(tbd, "--all") == 0) {
00172         /* [LOCK] zonelist */
00173         lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00174         zl_changed = zonelist_update(cmdc->engine->zonelist,
00175             cmdc->engine->config->zonelist_filename);
00176         /* [UNLOCK] zonelist */
00177         if (zl_changed == ODS_STATUS_UNCHANGED) {
00178             lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00179             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed."
00180                 "\n");
00181             ods_writen(sockfd, buf, strlen(buf));
00182         } else if (zl_changed == ODS_STATUS_OK) {
00183             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i "
00184             "removed, %i added, %i updated.\n",
00185                 cmdc->engine->zonelist->just_removed,
00186                 cmdc->engine->zonelist->just_added,
00187                 cmdc->engine->zonelist->just_updated);
00188             ods_writen(sockfd, buf, strlen(buf));
00189 
00190             cmdc->engine->zonelist->just_removed = 0;
00191             cmdc->engine->zonelist->just_added = 0;
00192             cmdc->engine->zonelist->just_updated = 0;
00193             lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00194 
00195             ods_log_debug("[%s] commit zone list changes", cmdh_str);
00196             engine_update_zones(cmdc->engine);
00197             ods_log_debug("[%s] signer configurations updated", cmdh_str);
00198         } else {
00199             lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00200             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n");
00201             ods_writen(sockfd, buf, strlen(buf));
00202         }
00203         return;
00204     } else {
00205         /* look up zone */
00206         lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00207         /* [LOCK] zonelist */
00208         zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
00209             LDNS_RR_CLASS_IN);
00210         /* If this zone is just added, don't update (it might not have a task yet) */
00211         if (zone && zone->just_added) {
00212             zone = NULL;
00213         }
00214         /* [UNLOCK] zonelist */
00215         lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00216         if (!zone) {
00217             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s not found.\n",
00218                 tbd);
00219             ods_writen(sockfd, buf, strlen(buf));
00220             /* update all */
00221             cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
00222             return;
00223         }
00224 
00225         lock_basic_lock(&zone->zone_lock);
00226         ods_log_assert(zone->task);
00227 
00228         lock_basic_lock(&cmdc->engine->taskq->schedule_lock);
00229         /* [LOCK] schedule */
00230         task = unschedule_task(cmdc->engine->taskq, (task_type*) zone->task);
00231         if (task != NULL) {
00232             ods_log_debug("[%s] reschedule task for zone %s", cmdh_str,
00233                 zone->name);
00234             if (task->what != TASK_SIGNCONF) {
00235                 task->halted = task->what;
00236                 task->interrupt = TASK_SIGNCONF;
00237             }
00238             task->what = TASK_SIGNCONF;
00239             task->when = time_now();
00240             status = schedule_task(cmdc->engine->taskq, task, 0);
00241         } else {
00242             /* task not queued, being worked on? */
00243             ods_log_verbose("[%s] worker busy with zone %s, will update "
00244                 "signconf as soon as possible", cmdh_str, zone->name);
00245             task = (task_type*) zone->task;
00246             task->interrupt = TASK_SIGNCONF;
00247             /* task->halted set by worker */
00248         }
00249         /* [UNLOCK] schedule */
00250         lock_basic_unlock(&cmdc->engine->taskq->schedule_lock);
00251 
00252         zone->task = task;
00253         lock_basic_unlock(&zone->zone_lock);
00254 
00255         if (status != ODS_STATUS_OK) {
00256             ods_log_crit("[%s] cannot schedule task for zone %s: %s",
00257                 cmdh_str, zone->name, ods_status2str(status));
00258             task_cleanup(task);
00259             zone->task = NULL;
00260         } else {
00261             engine_wakeup_workers(cmdc->engine);
00262         }
00263 
00264         (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n",
00265             tbd);
00266         ods_writen(sockfd, buf, strlen(buf));
00267     }
00268     return;
00269 }
00270 
00271 
00276 static void
00277 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
00278 {
00279     zone_type* zone = NULL;
00280     task_type* task = NULL;
00281     ods_status status = ODS_STATUS_OK;
00282     char buf[ODS_SE_MAXLINE];
00283 
00284     ods_log_assert(tbd);
00285     ods_log_assert(cmdc);
00286     ods_log_assert(cmdc->engine);
00287     ods_log_assert(cmdc->engine->taskq);
00288 
00289     if (ods_strcmp(tbd, "--all") == 0) {
00290         lock_basic_lock(&cmdc->engine->taskq->schedule_lock);
00291         /* [LOCK] schedule */
00292         schedule_flush(cmdc->engine->taskq, TASK_READ);
00293         /* [UNLOCK] schedule */
00294         lock_basic_unlock(&cmdc->engine->taskq->schedule_lock);
00295         engine_wakeup_workers(cmdc->engine);
00296         (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
00297             "immediate re-sign.\n");
00298         ods_writen(sockfd, buf, strlen(buf));
00299         ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
00300             cmdh_str);
00301         return;
00302     } else {
00303         lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00304         /* [LOCK] zonelist */
00305         zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
00306             LDNS_RR_CLASS_IN);
00307         /* If this zone is just added, don't update (it might not have a task yet) */
00308         if (zone && zone->just_added) {
00309             zone = NULL;
00310         }
00311         /* [UNLOCK] zonelist */
00312         lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00313 
00314         if (!zone) {
00315             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s not found.\n",
00316                 tbd);
00317             ods_writen(sockfd, buf, strlen(buf));
00318             return;
00319         }
00320 
00321         lock_basic_lock(&zone->zone_lock);
00322         ods_log_assert(zone->task);
00323 
00324         lock_basic_lock(&cmdc->engine->taskq->schedule_lock);
00325         /* [LOCK] schedule */
00326         task = unschedule_task(cmdc->engine->taskq, (task_type*) zone->task);
00327         if (task != NULL) {
00328             ods_log_debug("[%s] reschedule task for zone %s", cmdh_str,
00329                 zone->name);
00330             if (task->what != TASK_READ) {
00331                 task->halted = task->what;
00332                 task->interrupt = TASK_READ;
00333             }
00334             task->what = TASK_READ;
00335             task->when = time_now();
00336             status = schedule_task(cmdc->engine->taskq, task, 0);
00337         } else {
00338             /* task now queued, being worked on? */
00339             ods_log_verbose("[%s] worker busy with zone %s, will read "
00340                 "zone input as soon as possible", cmdh_str, zone->name);
00341             task = (task_type*) zone->task;
00342             task->interrupt = TASK_READ;
00343             /* task->halted set by worker */
00344         }
00345         /* [UNLOCK] schedule */
00346         lock_basic_unlock(&cmdc->engine->taskq->schedule_lock);
00347 
00348         zone->task = task;
00349         lock_basic_unlock(&zone->zone_lock);
00350 
00351         if (status != ODS_STATUS_OK) {
00352             (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Cannot schedule task for "
00353                 "zone %s.\n", tbd);
00354             ods_writen(sockfd, buf, strlen(buf));
00355             ods_log_crit("[%s] cannot schedule task for zone %s: %s",
00356                 cmdh_str, zone->name, ods_status2str(status));
00357             task_cleanup(task);
00358             zone->task = NULL;
00359         } else {
00360             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for immediate "
00361                 "re-sign.\n", tbd);
00362             ods_writen(sockfd, buf, strlen(buf));
00363             ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
00364                 cmdh_str, tbd);
00365             engine_wakeup_workers(cmdc->engine);
00366         }
00367     }
00368     return;
00369 }
00370 
00371 
00376 static void
00377 unlink_backup_file(const char* filename, const char* extension)
00378 {
00379     char* tmpname = ods_build_path(filename, extension, 0);
00380     ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
00381     unlink(tmpname);
00382     free((void*)tmpname);
00383     return;
00384 }
00385 
00390 static void
00391 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
00392 {
00393     char buf[ODS_SE_MAXLINE];
00394     zone_type* zone = NULL;
00395     task_type* task = NULL;
00396     uint32_t inbound_serial = 0;
00397     uint32_t internal_serial = 0;
00398     uint32_t outbound_serial = 0;
00399     ods_status status = ODS_STATUS_OK;
00400 
00401     ods_log_assert(tbd);
00402     ods_log_assert(cmdc);
00403     ods_log_assert(cmdc->engine);
00404 
00405     unlink_backup_file(tbd, ".inbound");
00406     unlink_backup_file(tbd, ".backup");
00407 
00408     lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00409     /* [LOCK] zonelist */
00410     zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
00411         LDNS_RR_CLASS_IN);
00412     /* [UNLOCK] zonelist */
00413     lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00414     if (zone) {
00415         /* [LOCK] zone */
00416         lock_basic_lock(&zone->zone_lock);
00417         inbound_serial = zone->zonedata->inbound_serial;
00418         internal_serial = zone->zonedata->internal_serial;
00419         outbound_serial = zone->zonedata->outbound_serial;
00420         zonedata_cleanup(zone->zonedata);
00421         zone->zonedata = NULL;
00422         zone->zonedata = zonedata_create(zone->allocator);
00423         zone->zonedata->initialized = 1;
00424         zone->zonedata->inbound_serial = inbound_serial;
00425         zone->zonedata->internal_serial = internal_serial;
00426         zone->zonedata->outbound_serial = outbound_serial;
00427 
00428         status = zone_publish_dnskeys(zone, 1);
00429         if (status == ODS_STATUS_OK) {
00430             status = zone_prepare_nsec3(zone, 1);
00431         } else {
00432             ods_log_warning("[%s] unable to restore DNSKEY RRset for zone %s,"
00433                 " reloading signconf", cmdh_str, zone->name);
00434         }
00435         if (status == ODS_STATUS_OK) {
00436             status = zonedata_commit(zone->zonedata);
00437         } else {
00438             ods_log_warning("[%s] unable to restore NSEC3PARAM RRset for "
00439                 " zone %s d1reloading signconf", cmdh_str, zone->name);
00440         }
00441 
00442         task = (task_type*) zone->task;
00443         task->what = TASK_READ;
00444         if (status != ODS_STATUS_OK) {
00445             ods_log_warning("[%s] unable to restore DNSKEY/NSEC3PARAM RRset "
00446                 " for zone %s d1reloading signconf", cmdh_str, zone->name);
00447             task->what = TASK_SIGNCONF;
00448         }
00449         /* [UNLOCK] zone */
00450         lock_basic_unlock(&zone->zone_lock);
00451 
00452         (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
00453             "%s cleared", tbd?tbd:"(null)");
00454         ods_log_info("[%s] internal zone information about %s cleared",
00455             cmdh_str, tbd?tbd:"(null)");
00456     } else {
00457         (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
00458             "found", tbd?tbd:"(null)");
00459         ods_log_warning("[%s] cannot clear zone %s, zone not found",
00460             cmdh_str, tbd?tbd:"(null)");
00461     }
00462 
00463     ods_writen(sockfd, buf, strlen(buf));
00464     return;
00465 }
00466 
00467 
00472 static void
00473 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
00474 {
00475     char* strtime = NULL;
00476     char buf[ODS_SE_MAXLINE];
00477     size_t i = 0;
00478     time_t now = 0;
00479     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00480     task_type* task = NULL;
00481 
00482     ods_log_assert(cmdc);
00483     ods_log_assert(cmdc->engine);
00484     if (!cmdc->engine->taskq || !cmdc->engine->taskq->tasks) {
00485         (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n");
00486         ods_writen(sockfd, buf, strlen(buf));
00487         return;
00488     }
00489 
00490     lock_basic_lock(&cmdc->engine->taskq->schedule_lock);
00491     /* [LOCK] schedule */
00492 
00493     /* time */
00494     now = time_now();
00495     strtime = ctime(&now);
00496     (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
00497         strtime?strtime:"(null)");
00498     ods_writen(sockfd, buf, strlen(buf));
00499 
00500     /* current work */
00501     for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) {
00502         task = cmdc->engine->workers[i]->task;
00503         if (task) {
00504             (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
00505                 "zone %s\n",
00506                 task_what2str(cmdc->engine->workers[i]->working_with),
00507                 task_who2str(task->who));
00508             ods_writen(sockfd, buf, strlen(buf));
00509         }
00510     }
00511 
00512     /* how many tasks */
00513     (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n",
00514         (int) cmdc->engine->taskq->tasks->count);
00515     ods_writen(sockfd, buf, strlen(buf));
00516 
00517     /* list tasks */
00518     node = ldns_rbtree_first(cmdc->engine->taskq->tasks);
00519     while (node && node != LDNS_RBTREE_NULL) {
00520         task = (task_type*) node->data;
00521         for (i=0; i < ODS_SE_MAXLINE; i++) {
00522             buf[i] = 0;
00523         }
00524         (void)task2str(task, (char*) &buf[0]);
00525         ods_writen(sockfd, buf, strlen(buf));
00526         node = ldns_rbtree_next(node);
00527     }
00528 
00529     /* [UNLOCK] schedule */
00530     lock_basic_unlock(&cmdc->engine->taskq->schedule_lock);
00531     return;
00532 }
00533 
00534 
00539 static void
00540 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
00541 {
00542     char buf[ODS_SE_MAXLINE];
00543 
00544     ods_log_assert(cmdc);
00545     ods_log_assert(cmdc->engine);
00546     ods_log_assert(cmdc->engine->taskq);
00547 
00548     lock_basic_lock(&cmdc->engine->taskq->schedule_lock);
00549     /* [LOCK] schedule */
00550     schedule_flush(cmdc->engine->taskq, TASK_NONE);
00551     /* [UNLOCK] schedule */
00552     lock_basic_unlock(&cmdc->engine->taskq->schedule_lock);
00553 
00554     engine_wakeup_workers(cmdc->engine);
00555 
00556     (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
00557     ods_writen(sockfd, buf, strlen(buf));
00558     ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
00559     return;
00560 }
00561 
00562 
00567 static void
00568 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
00569 {
00570     char buf[ODS_SE_MAXLINE];
00571 
00572     ods_log_assert(cmdc);
00573     ods_log_assert(cmdc->engine);
00574 
00575     cmdc->engine->need_to_reload = 1;
00576 
00577     lock_basic_lock(&cmdc->engine->signal_lock);
00578     /* [LOCK] signal */
00579     lock_basic_alarm(&cmdc->engine->signal_cond);
00580     /* [UNLOCK] signal */
00581     lock_basic_unlock(&cmdc->engine->signal_lock);
00582 
00583     (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
00584     ods_writen(sockfd, buf, strlen(buf));
00585     return;
00586 }
00587 
00588 
00593 static void
00594 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
00595 {
00596     char buf[ODS_SE_MAXLINE];
00597 
00598     ods_log_assert(cmdc);
00599     ods_log_assert(cmdc->engine);
00600 
00601     cmdc->engine->need_to_exit = 1;
00602 
00603     lock_basic_lock(&cmdc->engine->signal_lock);
00604     /* [LOCK] signal */
00605     lock_basic_alarm(&cmdc->engine->signal_cond);
00606     /* [UNLOCK] signal */
00607     lock_basic_unlock(&cmdc->engine->signal_lock);
00608 
00609     (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
00610     ods_writen(sockfd, buf, strlen(buf));
00611     return;
00612 }
00613 
00614 
00619 static void
00620 cmdhandler_handle_cmd_start(int sockfd)
00621 {
00622     char buf[ODS_SE_MAXLINE];
00623 
00624     (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
00625     ods_writen(sockfd, buf, strlen(buf));
00626     return;
00627 }
00628 
00629 
00634 static void
00635 cmdhandler_handle_cmd_running(int sockfd)
00636 {
00637     char buf[ODS_SE_MAXLINE];
00638 
00639     (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
00640     ods_writen(sockfd, buf, strlen(buf));
00641     return;
00642 }
00643 
00644 
00649 static void
00650 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
00651 {
00652     char buf[ODS_SE_MAXLINE];
00653 
00654     ods_log_assert(cmdc);
00655     ods_log_assert(cmdc->engine);
00656     ods_log_assert(cmdc->engine->config);
00657 
00658     ods_log_init(cmdc->engine->config->log_filename,
00659         cmdc->engine->config->use_syslog, val);
00660 
00661     (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
00662     ods_writen(sockfd, buf, strlen(buf));
00663 }
00664 
00665 
00670 static void
00671 cmdhandler_handle_cmd_error(int sockfd, const char* str)
00672 {
00673     char buf[ODS_SE_MAXLINE];
00674     (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
00675     ods_writen(sockfd, buf, strlen(buf));
00676     return;
00677 }
00678 
00679 
00684 static void
00685 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
00686 {
00687     char buf[ODS_SE_MAXLINE];
00688     (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
00689         str?str:"(null)");
00690     ods_writen(sockfd, buf, strlen(buf));
00691     return;
00692 }
00693 
00694 
00713 static void
00714 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
00715 {
00716     ssize_t n = 0;
00717     int sockfd = 0;
00718     char buf[ODS_SE_MAXLINE];
00719 
00720     ods_log_assert(cmdc);
00721     sockfd = cmdc->client_fd;
00722 
00723 again:
00724     while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
00725         buf[n-1] = '\0';
00726         n--;
00727         if (n <= 0) {
00728             return;
00729         }
00730         ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
00731 
00732         if (n == 4 && strncmp(buf, "help", n) == 0) {
00733             ods_log_debug("[%s] help command", cmdh_str);
00734             cmdhandler_handle_cmd_help(sockfd);
00735         } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
00736             ods_log_debug("[%s] list zones command", cmdh_str);
00737             cmdhandler_handle_cmd_zones(sockfd, cmdc);
00738         } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
00739             ods_log_debug("[%s] sign zone command", cmdh_str);
00740             if (buf[4] == '\0') {
00741                 /* NOTE: wouldn't it be nice that we default to --all? */
00742                 cmdhandler_handle_cmd_error(sockfd, "sign command needs "
00743                     "an argument (either '--all' or a zone name)");
00744             } else if (buf[4] != ' ') {
00745                 cmdhandler_handle_cmd_unknown(sockfd, buf);
00746             } else {
00747                 cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
00748             }
00749         } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
00750             ods_log_debug("[%s] clear zone command", cmdh_str);
00751             if (buf[5] == '\0') {
00752                 cmdhandler_handle_cmd_error(sockfd, "clear command needs "
00753                     "a zone name");
00754             } else if (buf[5] != ' ') {
00755                 cmdhandler_handle_cmd_unknown(sockfd, buf);
00756             } else {
00757                 cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
00758             }
00759         } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
00760             ods_log_debug("[%s] list tasks command", cmdh_str);
00761             cmdhandler_handle_cmd_queue(sockfd, cmdc);
00762         } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
00763             ods_log_debug("[%s] flush tasks command", cmdh_str);
00764             cmdhandler_handle_cmd_flush(sockfd, cmdc);
00765         } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
00766             ods_log_debug("[%s] update command", cmdh_str);
00767             if (buf[6] == '\0') {
00768                 cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
00769             } else if (buf[6] != ' ') {
00770                 cmdhandler_handle_cmd_unknown(sockfd, buf);
00771             } else {
00772                 cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
00773             }
00774         } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
00775             ods_log_debug("[%s] shutdown command", cmdh_str);
00776             cmdhandler_handle_cmd_stop(sockfd, cmdc);
00777             return;
00778         } else if (n == 5 && strncmp(buf, "start", n) == 0) {
00779             ods_log_debug("[%s] start command", cmdh_str);
00780             cmdhandler_handle_cmd_start(sockfd);
00781         } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
00782             ods_log_debug("[%s] reload command", cmdh_str);
00783             cmdhandler_handle_cmd_reload(sockfd, cmdc);
00784         } else if (n == 7 && strncmp(buf, "running", n) == 0) {
00785             ods_log_debug("[%s] running command", cmdh_str);
00786             cmdhandler_handle_cmd_running(sockfd);
00787         } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
00788             ods_log_debug("[%s] verbosity command", cmdh_str);
00789             if (buf[9] == '\0') {
00790                 cmdhandler_handle_cmd_error(sockfd, "verbosity command "
00791                     "an argument (verbosity level)");
00792             } else if (buf[9] != ' ') {
00793                 cmdhandler_handle_cmd_unknown(sockfd, buf);
00794             } else {
00795                 cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
00796             }
00797         } else {
00798             ods_log_debug("[%s] unknown command", cmdh_str);
00799             cmdhandler_handle_cmd_unknown(sockfd, buf);
00800         }
00801 
00802         ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
00803         (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
00804         ods_writen(sockfd, buf, strlen(buf));
00805     }
00806 
00807     if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
00808         goto again;
00809     } else if (n < 0 && errno == ECONNRESET) {
00810         ods_log_debug("[%s] done handling client: %s", cmdh_str,
00811             strerror(errno));
00812     } else if (n < 0 ) {
00813         ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
00814     }
00815     return;
00816 }
00817 
00818 
00823 static void*
00824 cmdhandler_accept_client(void* arg)
00825 {
00826     cmdhandler_type* cmdc = (cmdhandler_type*) arg;
00827 
00828     ods_thread_blocksigs();
00829     ods_thread_detach(cmdc->thread_id);
00830 
00831     ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
00832     cmdhandler_handle_cmd(cmdc);
00833     if (cmdc->client_fd) {
00834         close(cmdc->client_fd);
00835     }
00836     free(cmdc);
00837     count--;
00838     return NULL;
00839 }
00840 
00841 
00846 cmdhandler_type*
00847 cmdhandler_create(allocator_type* allocator, const char* filename)
00848 {
00849     cmdhandler_type* cmdh = NULL;
00850     struct sockaddr_un servaddr;
00851     int listenfd = 0;
00852     int flags = 0;
00853     int ret = 0;
00854 
00855     if (!allocator) {
00856         ods_log_error("[%s] unable to create: no allocator", cmdh_str);
00857         return NULL;
00858     }
00859     ods_log_assert(allocator);
00860 
00861     if (!filename) {
00862         ods_log_error("[%s] unable to create: no socket filename", cmdh_str);
00863         return NULL;
00864     }
00865     ods_log_assert(filename);
00866     ods_log_debug("[%s] create socket %s", cmdh_str, filename);
00867 
00868     /* new socket */
00869     listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
00870     if (listenfd <= 0) {
00871         ods_log_error("[%s] unable to create, socket() failed: %s", cmdh_str,
00872             strerror(errno));
00873         return NULL;
00874     }
00875     /* set it to non-blocking */
00876     flags = fcntl(listenfd, F_GETFL, 0);
00877     if (flags < 0) {
00878         ods_log_error("[%s] unable to create, fcntl(F_GETFL) failed: %s",
00879             cmdh_str, strerror(errno));
00880         close(listenfd);
00881         return NULL;
00882     }
00883     flags |= O_NONBLOCK;
00884     if (fcntl(listenfd, F_SETFL, flags) < 0) {
00885         ods_log_error("[%s] unable to create, fcntl(F_SETFL) failed: %s",
00886             cmdh_str, strerror(errno));
00887         close(listenfd);
00888         return NULL;
00889     }
00890 
00891     /* no surprises */
00892     if (filename) {
00893         unlink(filename);
00894     }
00895     bzero(&servaddr, sizeof(servaddr));
00896     servaddr.sun_family = AF_UNIX;
00897     strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
00898 
00899     /* bind and listen... */
00900     ret = bind(listenfd, (const struct sockaddr*) &servaddr,
00901         SUN_LEN(&servaddr));
00902     if (ret != 0) {
00903         ods_log_error("[%s] unable to create, bind() failed: %s", cmdh_str,
00904             strerror(errno));
00905         close(listenfd);
00906         return NULL;
00907     }
00908     ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
00909     if (ret != 0) {
00910         ods_log_error("[%s] unable to create, listen() failed: %s", cmdh_str,
00911             strerror(errno));
00912         close(listenfd);
00913         return NULL;
00914     }
00915 
00916     /* all ok */
00917     cmdh = (cmdhandler_type*) allocator_alloc(allocator,
00918         sizeof(cmdhandler_type));
00919     if (!cmdh) {
00920         close(listenfd);
00921         return NULL;
00922     }
00923     cmdh->allocator = allocator;
00924     cmdh->listen_fd = listenfd;
00925     cmdh->listen_addr = servaddr;
00926     cmdh->need_to_exit = 0;
00927     return cmdh;
00928 }
00929 
00930 
00935 void
00936 cmdhandler_start(cmdhandler_type* cmdhandler)
00937 {
00938     struct sockaddr_un cliaddr;
00939     socklen_t clilen;
00940     cmdhandler_type* cmdc = NULL;
00941     engine_type* engine = NULL;
00942     fd_set rset;
00943     int connfd = 0;
00944     int ret = 0;
00945 
00946     ods_log_assert(cmdhandler);
00947     ods_log_assert(cmdhandler->engine);
00948     ods_log_debug("[%s] start", cmdh_str);
00949 
00950     engine = cmdhandler->engine;
00951     ods_thread_detach(cmdhandler->thread_id);
00952     FD_ZERO(&rset);
00953     while (cmdhandler->need_to_exit == 0) {
00954         clilen = sizeof(cliaddr);
00955         FD_SET(cmdhandler->listen_fd, &rset);
00956         ret = select(ODS_SE_MAX_HANDLERS+1, &rset, NULL, NULL, NULL);
00957         if (ret < 0) {
00958             if (errno != EINTR && errno != EWOULDBLOCK) {
00959                 ods_log_warning("[%s] select() error: %s", cmdh_str,
00960                    strerror(errno));
00961             }
00962             continue;
00963         }
00964         if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
00965             connfd = accept(cmdhandler->listen_fd,
00966                 (struct sockaddr *) &cliaddr, &clilen);
00967             if (connfd < 0) {
00968                 if (errno != EINTR && errno != EWOULDBLOCK) {
00969                     ods_log_warning("[%s] accept error: %s", cmdh_str,
00970                         strerror(errno));
00971                 }
00972                 continue;
00973             }
00974             /* client accepted, create new thread */
00975             cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
00976             if (!cmdc) {
00977                 ods_log_crit("[%s] unable to create thread for client: "
00978                     "malloc failed", cmdh_str);
00979                 cmdhandler->need_to_exit = 1;
00980                 break;
00981             }
00982             cmdc->listen_fd = cmdhandler->listen_fd;
00983             cmdc->client_fd = connfd;
00984             cmdc->listen_addr = cmdhandler->listen_addr;
00985             cmdc->engine = cmdhandler->engine;
00986             cmdc->need_to_exit = cmdhandler->need_to_exit;
00987             ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
00988                 (void*) cmdc);
00989             count++;
00990             ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
00991         }
00992     }
00993 
00994     ods_log_debug("[%s] done", cmdh_str);
00995     engine = cmdhandler->engine;
00996     engine->cmdhandler_done = 1;
00997     return;
00998 }
00999 
01000 
01005 void
01006 cmdhandler_cleanup(cmdhandler_type* cmdhandler)
01007 {
01008     allocator_type* allocator;
01009     if (!cmdhandler) {
01010         return;
01011     }
01012     allocator = cmdhandler->allocator;
01013     allocator_deallocate(allocator, (void*) cmdhandler);
01014     return;
01015 }
01016 

Generated on Sat Dec 17 2011 10:02:42 for OpenDNSSEC-signer by  doxygen 1.7.1