OpenDNSSEC-signer 1.2.1
|
00001 /* 00002 * $Id: cmdhandler.c 4294 2011-01-13 19:58:29Z jakob $ 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/locks.h" 00037 #include "util/file.h" 00038 #include "util/log.h" 00039 #include "util/se_malloc.h" 00040 00041 #include <errno.h> 00042 #include <fcntl.h> /* fcntl() */ 00043 #include <ldns/ldns.h> /* ldns_rbtree_*() */ 00044 #include <stdio.h> /* snprintf() */ 00045 #include <stdlib.h> /* atoi() */ 00046 #include <string.h> /* strncpy(), strerror(), strlen(), strncmp() */ 00047 #include <strings.h> /* bzero() */ 00048 #include <sys/select.h> /* select(), FD_ZERO(), FD_SET(), FD_ISSET() */ 00049 #include <sys/socket.h> /* socket(), listen(), bind(), accept() */ 00050 #ifdef HAVE_SYS_TYPES_H 00051 # include <sys/types.h> 00052 #endif 00053 #include <unistd.h> /* fcntl(), close(), unlink(), read() */ 00054 00055 /* According to earlier standards: select() sys/time.h sys/types.h unistd.h */ 00056 #include <sys/time.h> 00057 #include <sys/types.h> 00058 00059 #define SE_CMDH_CMDLEN 7 00060 00061 #ifndef SUN_LEN 00062 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 00063 #endif 00064 00065 static int count = 0; 00066 00067 00072 static void 00073 cmdhandler_handle_cmd_help(int sockfd) 00074 { 00075 char buf[ODS_SE_MAXLINE]; 00076 00077 (void) snprintf(buf, ODS_SE_MAXLINE, 00078 "Commands:\n" 00079 "zones show the currently known zones.\n" 00080 "sign <zone> read zone and schedule for immediate (re-)sign.\n" 00081 "sign --all read all zones and schedule all for immediate (re-)sign.\n" 00082 "clear <zone> delete the internal storage of this zone.\n" 00083 " All signatures will be regenerated on the next re-sign.\n" 00084 "queue show the current task queue.\n" 00085 ); 00086 se_writen(sockfd, buf, strlen(buf)); 00087 00088 (void) snprintf(buf, ODS_SE_MAXLINE, 00089 "flush execute all scheduled tasks immediately.\n" 00090 "update <zone> update this zone signer configurations.\n" 00091 "update [--all] update zone list and all signer configurations.\n" 00092 "start start the engine.\n" 00093 "reload reload the engine.\n" 00094 "stop stop the engine.\n" 00095 "verbosity <nr> set verbosity.\n" 00096 ); 00097 se_writen(sockfd, buf, strlen(buf)); 00098 return; 00099 } 00100 00101 00106 static void 00107 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc) 00108 { 00109 char buf[ODS_SE_MAXLINE]; 00110 size_t i; 00111 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00112 zone_type* zone = NULL; 00113 00114 se_log_assert(cmdc); 00115 se_log_assert(cmdc->engine); 00116 se_log_assert(cmdc->engine->zonelist); 00117 00118 /* lock zonelist */ 00119 zonelist_lock(cmdc->engine->zonelist); 00120 00121 /* how many zones */ 00122 (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n", 00123 (int) cmdc->engine->zonelist->zones->count); 00124 se_writen(sockfd, buf, strlen(buf)); 00125 00126 /* list zones */ 00127 node = ldns_rbtree_first(cmdc->engine->zonelist->zones); 00128 while (node && node != LDNS_RBTREE_NULL) { 00129 zone = (zone_type*) node->key; 00130 for (i=0; i < ODS_SE_MAXLINE; i++) { 00131 buf[i] = 0; 00132 } 00133 (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", 00134 zone->name?zone->name:"(null)"); 00135 se_writen(sockfd, buf, strlen(buf)); 00136 node = ldns_rbtree_next(node); 00137 } 00138 00139 /* unlock zonelist */ 00140 zonelist_unlock(cmdc->engine->zonelist); 00141 return; 00142 } 00143 00144 00149 static void 00150 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc, const char* tbd) 00151 { 00152 char buf[ODS_SE_MAXLINE]; 00153 size_t i = 0; 00154 int ret = 0; 00155 00156 se_log_assert(tbd); 00157 se_log_assert(cmdc); 00158 se_log_assert(cmdc->engine); 00159 se_log_assert(cmdc->engine->config); 00160 se_log_assert(cmdc->engine->tasklist); 00161 00162 if (se_strcmp(tbd, "--all") == 0) { 00163 se_log_info("cmdhandler: updating zone list"); 00164 ret = engine_update_zonelist(cmdc->engine, buf); 00165 se_writen(sockfd, buf, strlen(buf)); 00166 tbd = NULL; 00167 } 00168 se_log_info("cmdhandler: updating signer configuration (%s)", 00169 tbd?tbd:"--all"); 00170 ret = engine_update_zones(cmdc->engine, tbd, buf, 1); 00171 se_writen(sockfd, buf, strlen(buf)); 00172 00173 if (tbd && ret != 0) { 00174 /* zone was not found */ 00175 ret = engine_update_zonelist(cmdc->engine, buf); 00176 se_writen(sockfd, buf, strlen(buf)); 00177 00178 /* try again */ 00179 ret = engine_update_zones(cmdc->engine, tbd, buf, 0); 00180 se_writen(sockfd, buf, strlen(buf)); 00181 } 00182 00183 /* wake up sleeping workers */ 00184 for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) { 00185 worker_wakeup(cmdc->engine->workers[i]); 00186 } 00187 return; 00188 } 00189 00190 00195 static void 00196 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd) 00197 { 00198 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00199 task_type* task = NULL; 00200 time_t now = time_now(); 00201 int found = 0, scheduled = 0; 00202 char buf[ODS_SE_MAXLINE]; 00203 size_t i = 0; 00204 00205 se_log_assert(tbd); 00206 se_log_assert(cmdc); 00207 se_log_assert(cmdc->engine); 00208 se_log_assert(cmdc->engine->config); 00209 se_log_assert(cmdc->engine->tasklist); 00210 00211 /* lock tasklist */ 00212 lock_basic_lock(&cmdc->engine->tasklist->tasklist_lock); 00213 00214 if (se_strcmp(tbd, "--all") == 0) { 00215 tasklist_flush(cmdc->engine->tasklist, TASK_READ); 00216 } else { 00217 node = ldns_rbtree_first(cmdc->engine->tasklist->tasks); 00218 while (node && node != LDNS_RBTREE_NULL) { 00219 task = (task_type*) node->key; 00220 if (se_strcmp(tbd, task->who) == 0) { 00221 found = 1; 00222 task = tasklist_delete_task(cmdc->engine->tasklist, task); 00223 if (!task) { 00224 se_log_error("cannot immediate sign zone %s: delete old " 00225 "task failed", tbd); 00226 (void)snprintf(buf, ODS_SE_MAXLINE, "Sign zone %s " 00227 "failed.\n", tbd); 00228 se_writen(sockfd, buf, strlen(buf)); 00229 lock_basic_unlock(&cmdc->engine->tasklist->tasklist_lock); 00230 return; 00231 } else { 00232 task->when = now; 00233 task->what = TASK_READ; 00234 task = tasklist_schedule_task(cmdc->engine->tasklist, 00235 task, 0); 00236 if (task) { 00237 scheduled = 1; 00238 } 00239 } 00240 break; 00241 } 00242 node = ldns_rbtree_next(node); 00243 } 00244 } 00245 00246 /* unlock tasklist */ 00247 lock_basic_unlock(&cmdc->engine->tasklist->tasklist_lock); 00248 00249 if (se_strcmp(tbd, "--all") == 0) { 00250 (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for " 00251 "immediate re-sign.\n"); 00252 se_writen(sockfd, buf, strlen(buf)); 00253 se_log_info("cmdhandler: all zones scheduled for immediate re-sign"); 00254 00255 /* wake up sleeping workers */ 00256 for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) { 00257 worker_wakeup(cmdc->engine->workers[i]); 00258 } 00259 } else if (found && scheduled) { 00260 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for " 00261 "immediate re-sign.\n", tbd?tbd:"(null)"); 00262 se_writen(sockfd, buf, strlen(buf)); 00263 se_log_info("cmdhandler: zone %s scheduled for immediate re-sign", 00264 tbd?tbd:"(null)"); 00265 00266 /* wake up sleeping workers */ 00267 for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) { 00268 worker_wakeup(cmdc->engine->workers[i]); 00269 } 00270 } else if (found && !scheduled) { 00271 (void)snprintf(buf, ODS_SE_MAXLINE, "Failed to schedule signing for " 00272 "zone %s\n", tbd?tbd:"(null)"); 00273 se_writen(sockfd, buf, strlen(buf)); 00274 se_log_error("cmdhandler: zone %s was found in task queue but " 00275 "rescheduling failed", tbd?tbd:"(null)"); 00276 } else if (engine_search_workers(cmdc->engine, tbd)) { 00277 se_log_warning("cmdhandler: not working on zone %s, updating " 00278 "zone list", tbd?tbd:"(null"); 00279 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s not not being signed " 00280 "yet, updating sign configuration\n", tbd?tbd:"(null)"); 00281 se_writen(sockfd, buf, strlen(buf)); 00282 cmdhandler_handle_cmd_update(sockfd, cmdc, tbd); 00283 } else { 00284 se_log_warning("cmdhandler: already performing task for zone %s", 00285 tbd?tbd:"(null"); 00286 (void)snprintf(buf, ODS_SE_MAXLINE, "Signer is already working on " 00287 "zone %s, sign command ignored\n", tbd?tbd:"(null)"); 00288 se_writen(sockfd, buf, strlen(buf)); 00289 } 00290 return; 00291 } 00292 00293 00298 static void 00299 unlink_backup_file(const char* filename, const char* extension) 00300 { 00301 char* tmpname = se_build_path(filename, extension, 0); 00302 se_log_debug("unlink file %s", tmpname); 00303 unlink(tmpname); 00304 se_free((void*)tmpname); 00305 return; 00306 } 00307 00312 static void 00313 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd) 00314 { 00315 char buf[ODS_SE_MAXLINE]; 00316 zone_type* zone = NULL; 00317 uint32_t inbound_serial = 0; 00318 uint32_t internal_serial = 0; 00319 uint32_t outbound_serial = 0; 00320 00321 se_log_assert(tbd); 00322 se_log_assert(cmdc); 00323 se_log_assert(cmdc->engine); 00324 00325 /* unlink_backup_file(tbd,, ".sc"); */ 00326 /* unlink_backup_file(tbd,, ".state"); */ 00327 /* unlink_backup_file(tbd,, ".task"); */ 00328 unlink_backup_file(tbd, ".inbound"); 00329 unlink_backup_file(tbd, ".unsorted"); 00330 unlink_backup_file(tbd, ".dnskeys"); 00331 unlink_backup_file(tbd, ".denial"); 00332 unlink_backup_file(tbd, ".rrsigs"); 00333 unlink_backup_file(tbd, ".finalized"); 00334 00335 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd); 00336 if (zone) { 00337 inbound_serial = zone->zonedata->inbound_serial; 00338 internal_serial = zone->zonedata->internal_serial; 00339 outbound_serial = zone->zonedata->outbound_serial; 00340 zonedata_cleanup(zone->zonedata); 00341 zone->zonedata = NULL; 00342 zone->zonedata = zonedata_create(); 00343 zone->zonedata->initialized = 1; 00344 zone->zonedata->inbound_serial = inbound_serial; 00345 zone->zonedata->internal_serial = internal_serial; 00346 zone->zonedata->outbound_serial = outbound_serial; 00347 zone->task->what = TASK_READ; 00348 00349 (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about " 00350 "%s cleared", tbd?tbd:"(null)"); 00351 se_log_info("cmdhandler: internal zone information about %s cleared", 00352 tbd?tbd:"(null)"); 00353 } else { 00354 (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not " 00355 "found", tbd?tbd:"(null)"); 00356 se_log_warning("cmdhandler: cannot clear zone %s, zone not found", 00357 tbd?tbd:"(null)"); 00358 } 00359 00360 se_writen(sockfd, buf, strlen(buf)); 00361 return; 00362 } 00363 00364 00369 static void 00370 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc) 00371 { 00372 char* strtime = NULL; 00373 char buf[ODS_SE_MAXLINE]; 00374 size_t i = 0; 00375 time_t now = 0; 00376 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00377 task_type* task = NULL; 00378 00379 se_log_assert(cmdc); 00380 se_log_assert(cmdc->engine); 00381 se_log_assert(cmdc->engine->tasklist); 00382 00383 /* lock tasklist */ 00384 lock_basic_lock(&cmdc->engine->tasklist->tasklist_lock); 00385 00386 /* how many tasks scheduled */ 00387 now = time_now(); 00388 strtime = ctime(&now); 00389 (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i tasks scheduled\nIt is " 00390 "now %s", (int) cmdc->engine->tasklist->tasks->count, 00391 strtime?strtime:"(null)"); 00392 se_writen(sockfd, buf, strlen(buf)); 00393 00394 /* list tasks */ 00395 node = ldns_rbtree_first(cmdc->engine->tasklist->tasks); 00396 while (node && node != LDNS_RBTREE_NULL) { 00397 task = (task_type*) node->key; 00398 for (i=0; i < ODS_SE_MAXLINE; i++) { 00399 buf[i] = 0; 00400 } 00401 (void)task2str(task, (char*) &buf[0]); 00402 se_writen(sockfd, buf, strlen(buf)); 00403 node = ldns_rbtree_next(node); 00404 } 00405 00406 /* unlock tasklist */ 00407 lock_basic_unlock(&cmdc->engine->tasklist->tasklist_lock); 00408 return; 00409 } 00410 00411 00416 static void 00417 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc) 00418 { 00419 char buf[ODS_SE_MAXLINE]; 00420 size_t i = 0; 00421 00422 se_log_assert(cmdc); 00423 se_log_assert(cmdc->engine); 00424 se_log_assert(cmdc->engine->config); 00425 se_log_assert(cmdc->engine->tasklist); 00426 00427 lock_basic_lock(&cmdc->engine->tasklist->tasklist_lock); 00428 tasklist_flush(cmdc->engine->tasklist, TASK_NONE); 00429 lock_basic_unlock(&cmdc->engine->tasklist->tasklist_lock); 00430 00431 /* wake up sleeping workers */ 00432 for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) { 00433 worker_wakeup(cmdc->engine->workers[i]); 00434 } 00435 00436 (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n"); 00437 se_writen(sockfd, buf, strlen(buf)); 00438 se_log_info("cmdhandler: all tasks being flushed"); 00439 return; 00440 } 00441 00442 00447 static void 00448 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc) 00449 { 00450 char buf[ODS_SE_MAXLINE]; 00451 00452 se_log_assert(cmdc); 00453 se_log_assert(cmdc->engine); 00454 00455 cmdc->engine->need_to_reload = 1; 00456 00457 lock_basic_lock(&cmdc->engine->signal_lock); 00458 lock_basic_alarm(&cmdc->engine->signal_cond); 00459 lock_basic_unlock(&cmdc->engine->signal_lock); 00460 00461 (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n"); 00462 se_writen(sockfd, buf, strlen(buf)); 00463 return; 00464 } 00465 00466 00471 static void 00472 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc) 00473 { 00474 char buf[ODS_SE_MAXLINE]; 00475 00476 se_log_assert(cmdc); 00477 se_log_assert(cmdc->engine); 00478 00479 cmdc->engine->need_to_exit = 1; 00480 00481 lock_basic_lock(&cmdc->engine->signal_lock); 00482 lock_basic_alarm(&cmdc->engine->signal_cond); 00483 lock_basic_unlock(&cmdc->engine->signal_lock); 00484 00485 (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE); 00486 se_writen(sockfd, buf, strlen(buf)); 00487 return; 00488 } 00489 00490 00495 static void 00496 cmdhandler_handle_cmd_start(int sockfd) 00497 { 00498 char buf[ODS_SE_MAXLINE]; 00499 00500 (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n"); 00501 se_writen(sockfd, buf, strlen(buf)); 00502 return; 00503 } 00504 00505 00510 static void 00511 cmdhandler_handle_cmd_running(int sockfd) 00512 { 00513 char buf[ODS_SE_MAXLINE]; 00514 00515 (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n"); 00516 se_writen(sockfd, buf, strlen(buf)); 00517 return; 00518 } 00519 00520 00525 static void 00526 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val) 00527 { 00528 char buf[ODS_SE_MAXLINE]; 00529 00530 se_log_assert(cmdc); 00531 se_log_assert(cmdc->engine); 00532 se_log_assert(cmdc->engine->config); 00533 00534 se_log_init(cmdc->engine->config->log_filename, 00535 cmdc->engine->config->use_syslog, val); 00536 00537 (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val); 00538 se_writen(sockfd, buf, strlen(buf)); 00539 } 00540 00541 00546 static void 00547 cmdhandler_handle_cmd_error(int sockfd, const char* str) 00548 { 00549 char buf[ODS_SE_MAXLINE]; 00550 (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)"); 00551 se_writen(sockfd, buf, strlen(buf)); 00552 return; 00553 } 00554 00555 00560 static void 00561 cmdhandler_handle_cmd_unknown(int sockfd, const char* str) 00562 { 00563 char buf[ODS_SE_MAXLINE]; 00564 (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n", 00565 str?str:"(null)"); 00566 se_writen(sockfd, buf, strlen(buf)); 00567 return; 00568 } 00569 00570 00589 static void 00590 cmdhandler_handle_cmd(cmdhandler_type* cmdc) 00591 { 00592 ssize_t n = 0; 00593 int sockfd = 0; 00594 char buf[ODS_SE_MAXLINE]; 00595 00596 se_log_assert(cmdc); 00597 00598 sockfd = cmdc->client_fd; 00599 00600 again: 00601 while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) { 00602 buf[n-1] = '\0'; 00603 n--; 00604 if (n <= 0) { 00605 return; 00606 } 00607 se_log_verbose("received command %s[%i]", buf, n); 00608 00609 if (n == 4 && strncmp(buf, "help", n) == 0) { 00610 se_log_debug("help command"); 00611 cmdhandler_handle_cmd_help(sockfd); 00612 } else if (n == 5 && strncmp(buf, "zones", n) == 0) { 00613 se_log_debug("list zones command"); 00614 cmdhandler_handle_cmd_zones(sockfd, cmdc); 00615 } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) { 00616 se_log_debug("sign zone command"); 00617 if (buf[4] == '\0') { 00618 /* NOTE: wouldn't it be nice that we default to --all? */ 00619 cmdhandler_handle_cmd_error(sockfd, "sign command needs " 00620 "an argument (either '--all' or a zone name)"); 00621 } else if (buf[4] != ' ') { 00622 cmdhandler_handle_cmd_unknown(sockfd, buf); 00623 } else { 00624 cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]); 00625 } 00626 } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) { 00627 se_log_debug("clear zone command"); 00628 if (buf[5] == '\0') { 00629 cmdhandler_handle_cmd_error(sockfd, "clear command needs " 00630 "a zone name"); 00631 } else if (buf[5] != ' ') { 00632 cmdhandler_handle_cmd_unknown(sockfd, buf); 00633 } else { 00634 cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]); 00635 } 00636 } else if (n == 5 && strncmp(buf, "queue", n) == 0) { 00637 se_log_debug("list tasks command"); 00638 cmdhandler_handle_cmd_queue(sockfd, cmdc); 00639 } else if (n == 5 && strncmp(buf, "flush", n) == 0) { 00640 se_log_debug("flush tasks command"); 00641 cmdhandler_handle_cmd_flush(sockfd, cmdc); 00642 } else if (n >= 6 && strncmp(buf, "update", 6) == 0) { 00643 se_log_debug("update command"); 00644 if (buf[6] == '\0') { 00645 cmdhandler_handle_cmd_update(sockfd, cmdc, "--all"); 00646 } else if (buf[6] != ' ') { 00647 cmdhandler_handle_cmd_unknown(sockfd, buf); 00648 } else { 00649 cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]); 00650 } 00651 } else if (n == 4 && strncmp(buf, "stop", n) == 0) { 00652 se_log_debug("shutdown command"); 00653 cmdhandler_handle_cmd_stop(sockfd, cmdc); 00654 return; 00655 } else if (n == 5 && strncmp(buf, "start", n) == 0) { 00656 se_log_debug("start command"); 00657 cmdhandler_handle_cmd_start(sockfd); 00658 } else if (n == 6 && strncmp(buf, "reload", n) == 0) { 00659 se_log_debug("reload command"); 00660 cmdhandler_handle_cmd_reload(sockfd, cmdc); 00661 } else if (n == 7 && strncmp(buf, "running", n) == 0) { 00662 se_log_debug("running command"); 00663 cmdhandler_handle_cmd_running(sockfd); 00664 } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) { 00665 se_log_debug("verbosity command"); 00666 if (buf[9] == '\0') { 00667 cmdhandler_handle_cmd_error(sockfd, "verbosity command " 00668 "an argument (verbosity level)"); 00669 } else if (buf[9] != ' ') { 00670 cmdhandler_handle_cmd_unknown(sockfd, buf); 00671 } else { 00672 cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10])); 00673 } 00674 } else { 00675 se_log_debug("unknown command"); 00676 cmdhandler_handle_cmd_unknown(sockfd, buf); 00677 } 00678 00679 se_log_debug("done handling command %s[%i]", buf, n); 00680 (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> "); 00681 se_writen(sockfd, buf, strlen(buf)); 00682 } 00683 00684 if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) { 00685 goto again; 00686 } else if (n < 0 && errno == ECONNRESET) { 00687 se_log_debug("done handling client: %s", strerror(errno)); 00688 } else if (n < 0 ) { 00689 se_log_error("command handler read error[%i]: %s", errno, strerror(errno)); 00690 } 00691 return; 00692 } 00693 00694 00699 static void* 00700 cmdhandler_accept_client(void* arg) 00701 { 00702 cmdhandler_type* cmdc = (cmdhandler_type*) arg; 00703 00704 se_thread_blocksigs(); 00705 se_thread_detach(cmdc->thread_id); 00706 00707 se_log_debug("command handler accept client %i", cmdc->client_fd); 00708 cmdhandler_handle_cmd(cmdc); 00709 if (cmdc->client_fd) { 00710 close(cmdc->client_fd); 00711 } 00712 cmdhandler_cleanup(cmdc); 00713 count--; 00714 return NULL; 00715 } 00716 00717 00722 cmdhandler_type* 00723 cmdhandler_create(const char* filename) 00724 { 00725 cmdhandler_type* cmdh = NULL; 00726 struct sockaddr_un servaddr; 00727 int listenfd = 0; 00728 int flags = 0; 00729 int ret = 0; 00730 00731 if (!filename) { 00732 se_log_error("unable to create command handler, no filename"); 00733 return NULL; 00734 } 00735 se_log_debug("create command handler to socket %s", filename); 00736 00737 /* new socket */ 00738 listenfd = socket(AF_UNIX, SOCK_STREAM, 0); 00739 if (listenfd <= 0) { 00740 se_log_error("unable to create command handler, socket() failed: %s", 00741 strerror(errno)); 00742 return NULL; 00743 } 00744 /* set it to non-blocking */ 00745 flags = fcntl(listenfd, F_GETFL, 0); 00746 if (flags < 0) { 00747 se_log_error("unable to create command handler, fcntl(F_GETFL) " 00748 "failed: %s", strerror(errno)); 00749 close(listenfd); 00750 return NULL; 00751 } 00752 flags |= O_NONBLOCK; 00753 if (fcntl(listenfd, F_SETFL, flags) < 0) { 00754 se_log_error("unable to create command handler, fcntl(F_SETFL) " 00755 "failed: %s", strerror(errno)); 00756 close(listenfd); 00757 return NULL; 00758 } 00759 00760 /* no suprises */ 00761 unlink(filename); 00762 bzero(&servaddr, sizeof(servaddr)); 00763 servaddr.sun_family = AF_UNIX; 00764 strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1); 00765 00766 /* bind and listen... */ 00767 ret = bind(listenfd, (const struct sockaddr*) &servaddr, 00768 SUN_LEN(&servaddr)); 00769 if (ret != 0) { 00770 se_log_error("unable to create command handler, bind() failed: %s", 00771 strerror(errno)); 00772 close(listenfd); 00773 return NULL; 00774 } 00775 ret = listen(listenfd, ODS_SE_MAX_HANDLERS); 00776 if (ret != 0) { 00777 se_log_error("unable to create command handler, listen() failed: %s", 00778 strerror(errno)); 00779 close(listenfd); 00780 return NULL; 00781 } 00782 00783 /* all ok */ 00784 cmdh = (cmdhandler_type*) se_malloc(sizeof(cmdhandler_type)); 00785 cmdh->listen_fd = listenfd; 00786 cmdh->listen_addr = servaddr; 00787 cmdh->need_to_exit = 0; 00788 return cmdh; 00789 } 00790 00791 00796 void 00797 cmdhandler_start(cmdhandler_type* cmdhandler) 00798 { 00799 struct sockaddr_un cliaddr; 00800 socklen_t clilen; 00801 cmdhandler_type* cmdc = NULL; 00802 engine_type* engine = NULL; 00803 fd_set rset; 00804 int connfd = 0; 00805 int ret = 0; 00806 00807 se_log_assert(cmdhandler); 00808 se_log_assert(cmdhandler->engine); 00809 se_log_debug("command handler start"); 00810 00811 engine = cmdhandler->engine; 00812 se_thread_detach(cmdhandler->thread_id); 00813 FD_ZERO(&rset); 00814 while (cmdhandler->need_to_exit == 0) { 00815 clilen = sizeof(cliaddr); 00816 FD_SET(cmdhandler->listen_fd, &rset); 00817 ret = select(ODS_SE_MAX_HANDLERS+1, &rset, NULL, NULL, NULL); 00818 if (ret < 0) { 00819 if (errno != EINTR && errno != EWOULDBLOCK) { 00820 se_log_warning("cmdhandler select() error: %s", 00821 strerror(errno)); 00822 } 00823 continue; 00824 } 00825 if (FD_ISSET(cmdhandler->listen_fd, &rset)) { 00826 connfd = accept(cmdhandler->listen_fd, 00827 (struct sockaddr *) &cliaddr, &clilen); 00828 if (connfd < 0) { 00829 if (errno != EINTR && errno != EWOULDBLOCK) { 00830 se_log_warning("command handler accept error: %s", 00831 strerror(errno)); 00832 } 00833 continue; 00834 } 00835 /* client accepted, create new thread */ 00836 cmdc = (cmdhandler_type*) se_malloc(sizeof(cmdhandler_type)); 00837 cmdc->listen_fd = cmdhandler->listen_fd; 00838 cmdc->client_fd = connfd; 00839 cmdc->listen_addr = cmdhandler->listen_addr; 00840 cmdc->engine = cmdhandler->engine; 00841 cmdc->need_to_exit = cmdhandler->need_to_exit; 00842 se_thread_create(&cmdc->thread_id, &cmdhandler_accept_client, 00843 (void*) cmdc); 00844 count++; 00845 se_log_debug("command handler %i clients in progress...", count); 00846 } 00847 } 00848 00849 se_log_debug("command handler done"); 00850 engine = cmdhandler->engine; 00851 cmdhandler_cleanup(cmdhandler); 00852 engine->cmdhandler_done = 1; 00853 return; 00854 } 00855 00856 00861 void 00862 cmdhandler_cleanup(cmdhandler_type* cmdhandler) 00863 { 00864 if (cmdhandler) { 00865 se_free((void*)cmdhandler); 00866 } else { 00867 se_log_warning("clean up empty command handler"); 00868 } 00869 return; 00870 }