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