OpenDNSSEC-signer
1.3.4
|
00001 /* 00002 * $Id: cmdhandler.c 5657 2011-09-30 06:47:41Z 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 zone->task = task; 00242 } else { 00243 /* task not queued, being worked on? */ 00244 ods_log_verbose("[%s] worker busy with zone %s, will update " 00245 "signconf as soon as possible", cmdh_str, zone->name); 00246 task = (task_type*) zone->task; 00247 task->interrupt = TASK_SIGNCONF; 00248 /* task->halted set by worker */ 00249 } 00250 /* [UNLOCK] schedule */ 00251 lock_basic_unlock(&cmdc->engine->taskq->schedule_lock); 00252 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