00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
00130
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
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
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
00173 lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00174 zl_changed = zonelist_update(cmdc->engine->zonelist,
00175 cmdc->engine->config->zonelist_filename);
00176
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
00206 lock_basic_lock(&cmdc->engine->zonelist->zl_lock);
00207
00208 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
00209 LDNS_RR_CLASS_IN);
00210
00211 if (zone && zone->just_added) {
00212 zone = NULL;
00213 }
00214
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
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
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
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
00248 }
00249
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
00292 schedule_flush(cmdc->engine->taskq, TASK_READ);
00293
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
00305 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
00306 LDNS_RR_CLASS_IN);
00307
00308 if (zone && zone->just_added) {
00309 zone = NULL;
00310 }
00311
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
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
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
00344 }
00345
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
00410 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
00411 LDNS_RR_CLASS_IN);
00412
00413 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock);
00414 if (zone) {
00415
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
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
00492
00493
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
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
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
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
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
00550 schedule_flush(cmdc->engine->taskq, TASK_NONE);
00551
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
00579 lock_basic_alarm(&cmdc->engine->signal_cond);
00580
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
00605 lock_basic_alarm(&cmdc->engine->signal_cond);
00606
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
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
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
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
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
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
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
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