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
00029
00030
00031
00032
00033 #include "ink_config.h"
00034
00035 #include "libts.h"
00036 #include "ink_sys_control.h"
00037 #include <syslog.h>
00038
00039 #if !defined(linux)
00040 #include <sys/lock.h>
00041 #endif
00042
00043 #if defined(linux)
00044 extern "C" int plock(int);
00045 #else
00046 #include <sys/filio.h>
00047 #endif
00048
00049 #if HAVE_MCHECK_H
00050 #include <mcheck.h>
00051 #endif
00052
00053 #include "Main.h"
00054 #include "signals.h"
00055 #include "Error.h"
00056 #include "StatSystem.h"
00057 #include "P_EventSystem.h"
00058 #include "P_Net.h"
00059 #include "P_UDPNet.h"
00060 #include "P_DNS.h"
00061 #include "P_SplitDNS.h"
00062 #include "P_Cluster.h"
00063 #include "P_HostDB.h"
00064 #include "P_Cache.h"
00065 #include "I_Layout.h"
00066 #include "I_Machine.h"
00067 #include "RecordsConfig.h"
00068 #include "I_RecProcess.h"
00069 #include "Transform.h"
00070 #include "ProcessManager.h"
00071 #include "ProxyConfig.h"
00072 #include "HttpProxyServerMain.h"
00073 #include "HttpBodyFactory.h"
00074 #include "logging/Log.h"
00075 #include "ICPProcessor.h"
00076
00077 #include "CacheControl.h"
00078 #include "IPAllow.h"
00079 #include "ParentSelection.h"
00080 #include "MgmtUtils.h"
00081 #include "StatPages.h"
00082 #include "HTTP.h"
00083 #include "Plugin.h"
00084 #include "DiagsConfig.h"
00085 #include "CoreUtils.h"
00086 #include "Update.h"
00087 #include "congest/Congestion.h"
00088 #include "RemapProcessor.h"
00089 #include "I_Tasks.h"
00090 #include "InkAPIInternal.h"
00091
00092 #include <ts/ink_cap.h>
00093
00094 #if TS_HAS_PROFILER
00095 #include <google/profiler.h>
00096 #endif
00097
00098
00099
00100
00101 #define DEFAULT_HTTP_ACCEPT_PORT_NUMBER 0
00102 #define DEFAULT_COMMAND_FLAG 0
00103
00104 #define DEFAULT_VERBOSE_FLAG 0
00105 #define DEFAULT_VERSION_FLAG 0
00106 #define DEFAULT_STACK_TRACE_FLAG 0
00107
00108 #if DEFAULT_COMMAND_FLAG
00109 # define DEFAULT_COMMAND_FLAG_TYPE "f"
00110 #else
00111 # define DEFAULT_COMMAND_FLAG_TYPE "F"
00112 #endif
00113
00114 #define DEFAULT_REMOTE_MANAGEMENT_FLAG 0
00115 #define DIAGS_LOG_FILENAME "diags.log"
00116
00117 static const long MAX_LOGIN = sysconf(_SC_LOGIN_NAME_MAX) <= 0 ? _POSIX_LOGIN_NAME_MAX : sysconf(_SC_LOGIN_NAME_MAX);
00118
00119 static void * mgmt_restart_shutdown_callback(void *, char *, int data_len);
00120 static void* mgmt_storage_device_cmd_callback(void* x, char* data, int len);
00121 static void init_ssl_ctx_callback(void *ctx, bool server);
00122
00123 static int version_flag = DEFAULT_VERSION_FLAG;
00124
00125 static int num_of_net_threads = ink_number_of_processors();
00126 static int num_of_udp_threads = 0;
00127 static int num_accept_threads = 0;
00128 static int num_task_threads = 0;
00129
00130 extern int num_of_cluster_threads;
00131
00132 static char * http_accept_port_descriptor;
00133 int http_accept_file_descriptor = NO_FD;
00134 static char core_file[255] = "";
00135 static bool enable_core_file_p = false;
00136 int command_flag = DEFAULT_COMMAND_FLAG;
00137 #if TS_HAS_TESTS
00138 static char regression_test[1024] = "";
00139 #endif
00140 int auto_clear_hostdb_flag = 0;
00141 extern int fds_limit;
00142 extern int cluster_port_number;
00143 extern int cache_clustering_enabled;
00144 char cluster_host[MAXDNAME + 1] = DEFAULT_CLUSTER_HOST;
00145
00146
00147 static char command_string[512] = "";
00148 int remote_management_flag = DEFAULT_REMOTE_MANAGEMENT_FLAG;
00149
00150 static char error_tags[1024] = "";
00151 static char action_tags[1024] = "";
00152 static int show_statistics = 0;
00153 static inkcoreapi DiagsConfig *diagsConfig = NULL;
00154 HttpBodyFactory *body_factory = NULL;
00155
00156 static int accept_mss = 0;
00157 static int cmd_line_dprintf_level = 0;
00158 static int poll_timeout = -1;
00159
00160
00161
00162
00163 static volatile int delay_listen_for_cache_p = 0;
00164
00165 AppVersionInfo appVersionInfo;
00166
00167 static const ArgumentDescription argument_descriptions[] = {
00168 {"net_threads", 'n', "Number of Net Threads", "I", &num_of_net_threads, "PROXY_NET_THREADS", NULL},
00169 {"cluster_threads", 'Z', "Number of Cluster Threads", "I", &num_of_cluster_threads, "PROXY_CLUSTER_THREADS", NULL},
00170 {"udp_threads", 'U', "Number of UDP Threads", "I", &num_of_udp_threads, "PROXY_UDP_THREADS", NULL},
00171 {"accept_thread", 'a', "Use an Accept Thread", "T", &num_accept_threads, "PROXY_ACCEPT_THREAD", NULL},
00172 {"accept_till_done", 'b', "Accept Till Done", "T", &accept_till_done, "PROXY_ACCEPT_TILL_DONE", NULL},
00173 {"httpport", 'p', "Port descriptor for HTTP Accept", "S*", &http_accept_port_descriptor,
00174 "PROXY_HTTP_ACCEPT_PORT", NULL},
00175 {"cluster_port", 'P', "Cluster Port Number", "I", &cluster_port_number, "PROXY_CLUSTER_PORT", NULL},
00176 {"dprintf_level", 'o', "Debug output level", "I", &cmd_line_dprintf_level, "PROXY_DPRINTF_LEVEL", NULL},
00177 {"version", 'V', "Print Version String", "T", &version_flag, NULL, NULL},
00178
00179 #if TS_HAS_TESTS
00180 {"regression", 'R',
00181 #ifdef DEBUG
00182 "Regression Level (quick:1..long:3)",
00183 #else
00184 0,
00185 #endif
00186 "I", ®ression_level, "PROXY_REGRESSION", NULL},
00187 {"regression_test", 'r',
00188
00189 #ifdef DEBUG
00190 "Run Specific Regression Test",
00191 #else
00192 0,
00193 #endif
00194 "S512", regression_test, "PROXY_REGRESSION_TEST", NULL},
00195 #endif //TS_HAS_TESTS
00196
00197 #if TS_USE_DIAGS
00198 {"debug_tags", 'T', "Vertical-bar-separated Debug Tags", "S1023", error_tags, "PROXY_DEBUG_TAGS", NULL},
00199 {"action_tags", 'B', "Vertical-bar-separated Behavior Tags", "S1023", action_tags, "PROXY_BEHAVIOR_TAGS", NULL},
00200 #endif
00201
00202 {"interval", 'i', "Statistics Interval", "I", &show_statistics, "PROXY_STATS_INTERVAL", NULL},
00203 {"remote_management", 'M', "Remote Management", "T", &remote_management_flag, "PROXY_REMOTE_MANAGEMENT", NULL},
00204 {"command", 'C', "Maintenance Command to Execute", "S511", &command_string, "PROXY_COMMAND_STRING", NULL},
00205 {"clear_hostdb", 'k', "Clear HostDB on Startup", "F", &auto_clear_hostdb_flag, "PROXY_CLEAR_HOSTDB", NULL},
00206 {"clear_cache", 'K', "Clear Cache on Startup", "F", &cacheProcessor.auto_clear_flag, "PROXY_CLEAR_CACHE", NULL},
00207 #if defined(linux)
00208 {"read_core", 'c', "Read Core file", "S255", &core_file, NULL, NULL},
00209 #endif
00210
00211 {"accept_mss", ' ', "MSS for client connections", "I", &accept_mss, NULL, NULL},
00212 {"poll_timeout", 't', "poll timeout in milliseconds", "I", &poll_timeout, NULL, NULL},
00213 {"help", 'h', "HELP!", NULL, NULL, NULL, usage},
00214 };
00215
00216
00217
00218
00219 static void
00220 init_system()
00221 {
00222 RecInt stackDump;
00223 bool found = (RecGetRecordInt("proxy.config.stack_dump_enabled", &stackDump) == REC_ERR_OKAY);
00224
00225 if (found == false) {
00226 Warning("Unable to determine stack_dump_enabled , assuming enabled");
00227 stackDump = 1;
00228 }
00229
00230 init_signals(stackDump == 1);
00231
00232 syslog(LOG_NOTICE, "NOTE: --- %s Starting ---", appVersionInfo.AppStr);
00233 syslog(LOG_NOTICE, "NOTE: %s Version: %s", appVersionInfo.AppStr, appVersionInfo.FullVersionInfoStr);
00234
00235
00236
00237
00238 fds_limit = ink_max_out_rlimit(RLIMIT_NOFILE, true, false);
00239 }
00240
00241 static void
00242 check_lockfile()
00243 {
00244 ats_scoped_str rundir(RecConfigReadRuntimeDir());
00245 ats_scoped_str lockfile;
00246 pid_t holding_pid;
00247 int err;
00248
00249 lockfile = Layout::relative_to(rundir, SERVER_LOCK);
00250
00251 Lockfile server_lockfile(lockfile);
00252 err = server_lockfile.Get(&holding_pid);
00253
00254 if (err != 1) {
00255 char *reason = strerror(-err);
00256 fprintf(stderr, "WARNING: Can't acquire lockfile '%s'", (const char *)lockfile);
00257
00258 if ((err == 0) && (holding_pid != -1)) {
00259 fprintf(stderr, " (Lock file held by process ID %ld)\n", (long)holding_pid);
00260 } else if ((err == 0) && (holding_pid == -1)) {
00261 fprintf(stderr, " (Lock file exists, but can't read process ID)\n");
00262 } else if (reason) {
00263 fprintf(stderr, " (%s)\n", reason);
00264 } else {
00265 fprintf(stderr, "\n");
00266 }
00267 _exit(1);
00268 }
00269 }
00270
00271 static void
00272 check_config_directories(void)
00273 {
00274 ats_scoped_str rundir(RecConfigReadRuntimeDir());
00275
00276 if (access(Layout::get()->sysconfdir, R_OK) == -1) {
00277 fprintf(stderr,"unable to access() config dir '%s': %d, %s\n",
00278 Layout::get()->sysconfdir, errno, strerror(errno));
00279 fprintf(stderr, "please set the 'TS_ROOT' environment variable\n");
00280 _exit(1);
00281 }
00282
00283 if (access(rundir, R_OK | W_OK) == -1) {
00284 fprintf(stderr,"unable to access() local state dir '%s': %d, %s\n",
00285 (const char *)rundir, errno, strerror(errno));
00286 fprintf(stderr,"please set 'proxy.config.local_state_dir'\n");
00287 _exit(1);
00288 }
00289
00290 }
00291
00292
00293
00294
00295 static void
00296 initialize_process_manager()
00297 {
00298 mgmt_use_syslog();
00299
00300
00301 if (getenv("PROXY_REMOTE_MGMT")) {
00302 remote_management_flag = true;
00303 }
00304
00305 RecProcessInit(remote_management_flag ? RECM_CLIENT : RECM_STAND_ALONE, diags);
00306
00307 if (!remote_management_flag) {
00308 LibRecordsConfigInit();
00309 RecordsConfigOverrideFromEnvironment();
00310 }
00311
00312
00313 pmgmt = new ProcessManager(remote_management_flag);
00314
00315 pmgmt->start();
00316 RecProcessInitMessage(remote_management_flag ? RECM_CLIENT : RECM_STAND_ALONE);
00317 pmgmt->reconfigure();
00318 check_config_directories();
00319
00320
00321
00322
00323 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.short", appVersionInfo.VersionStr, RECP_NON_PERSISTENT);
00324 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.long", appVersionInfo.FullVersionInfoStr, RECP_NON_PERSISTENT);
00325 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.build_number", appVersionInfo.BldNumStr, RECP_NON_PERSISTENT);
00326 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.build_time", appVersionInfo.BldTimeStr, RECP_NON_PERSISTENT);
00327 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.build_date", appVersionInfo.BldDateStr, RECP_NON_PERSISTENT);
00328 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.build_machine", appVersionInfo.BldMachineStr, RECP_NON_PERSISTENT);
00329 RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.build_person", appVersionInfo.BldPersonStr, RECP_NON_PERSISTENT);
00330 }
00331
00332
00333
00334
00335 void
00336 shutdown_system()
00337 {
00338 }
00339
00340 #define CMD_ERROR -2 // serious error, exit maintaince mode
00341 #define CMD_FAILED -1 // error, but recoverable
00342 #define CMD_OK 0 // ok, or minor (user) error
00343 #define CMD_HELP 1 // ok, print help
00344 #define CMD_IN_PROGRESS 2 // task not completed. don't exit
00345
00346 static int
00347 cmd_list(char * )
00348 {
00349 printf("LIST\n\n");
00350
00351
00352
00353 int h_size = 120000;
00354 REC_ReadConfigInteger(h_size, "proxy.config.hostdb.size");
00355 printf("Host Database size:\t%d\n", h_size);
00356
00357
00358
00359 Note("Cache Storage:");
00360 Store tStore;
00361 if (tStore.read_config() < 0) {
00362 Note("config read failure");
00363 return CMD_FAILED;
00364 } else {
00365 tStore.write_config_data(fileno(stdout));
00366 return CMD_OK;
00367 }
00368 }
00369
00370 static char *
00371 skip(char *cmd, int null_ok = 0)
00372 {
00373 cmd += strspn(cmd, " \t");
00374 cmd = strpbrk(cmd, " \t");
00375 if (!cmd) {
00376 if (!null_ok)
00377 printf("Error: argument missing\n");
00378 return cmd;
00379 }
00380 cmd += strspn(cmd, " \t");
00381 return cmd;
00382 }
00383
00384
00385 static void
00386 CB_After_Cache_Init()
00387 {
00388 APIHook* hook;
00389 int start;
00390
00391 start = ink_atomic_swap(&delay_listen_for_cache_p, -1);
00392
00393
00394 if (cacheProcessor.min_stripe_version.ink_major < CACHE_DB_MAJOR_VERSION) {
00395
00396 if (cacheProcessor.min_stripe_version.ink_major < 23) {
00397 Debug("cache_bc", "Pre 4.0 stripe (cache version %d.%d) found, forcing MMH hash for cache URLs"
00398 , cacheProcessor.min_stripe_version.ink_major, cacheProcessor.min_stripe_version.ink_minor
00399 );
00400 URLHashContext::Setting = URLHashContext::MMH;
00401 }
00402 }
00403
00404 if (1 == start) {
00405 Debug("http_listen", "Delayed listen enable, cache initialization finished");
00406 start_HttpProxyServer();
00407 }
00408
00409 time_t cache_ready_at = time(NULL);
00410 RecSetRecordInt("proxy.node.restarts.proxy.cache_ready_time", cache_ready_at);
00411
00412
00413 hook = lifecycle_hooks->get(TS_LIFECYCLE_CACHE_READY_HOOK);
00414 while (hook) {
00415 hook->invoke(TS_EVENT_LIFECYCLE_CACHE_READY, NULL);
00416 hook = hook->next();
00417 }
00418 }
00419
00420 struct CmdCacheCont: public Continuation
00421 {
00422
00423 int cache_fix;
00424
00425 int ClearEvent(int event, Event * e)
00426 {
00427 (void) event;
00428 (void) e;
00429 if (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED) {
00430 Note("CLEAR, succeeded");
00431 _exit(0);
00432 } else if (cacheProcessor.IsCacheEnabled() == CACHE_INIT_FAILED) {
00433 Note("unable to open Cache, CLEAR failed");
00434 _exit(1);
00435 }
00436 return EVENT_CONT;
00437 }
00438
00439 int CheckEvent(int event, Event * e)
00440 {
00441 (void) event;
00442 (void) e;
00443 int res = 0;
00444 Note("Cache Directory");
00445 if (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED) {
00446
00447 res = cacheProcessor.dir_check(cache_fix) < 0 || res;
00448
00449 Note("Cache");
00450 res = cacheProcessor.db_check(cache_fix) < 0 || res;
00451
00452 cacheProcessor.stop();
00453
00454 const char *n = cache_fix ? "REPAIR" : "CHECK";
00455
00456 if (res) {
00457 printf("\n%s failed", n);
00458 _exit(1);
00459 } else {
00460 printf("\n%s succeeded\n", n);
00461 _exit(0);
00462 }
00463 } else if (cacheProcessor.IsCacheEnabled() == CACHE_INIT_FAILED) {
00464 Note("unable to open Cache, Check failed");
00465 _exit(1);
00466 }
00467 return EVENT_CONT;
00468 }
00469
00470 CmdCacheCont(bool check, bool fix = false):Continuation(new_ProxyMutex()) {
00471 cache_fix = fix;
00472 if (check)
00473 SET_HANDLER(&CmdCacheCont::CheckEvent);
00474 else
00475 SET_HANDLER(&CmdCacheCont::ClearEvent);
00476 }
00477
00478 };
00479
00480 static int
00481 cmd_check_internal(char * , bool fix = false)
00482 {
00483 const char *n = fix ? "REPAIR" : "CHECK";
00484
00485 printf("%s\n\n", n);
00486
00487 hostdb_current_interval = (ink_get_based_hrtime() / HRTIME_MINUTE);
00488
00489
00490
00491
00492
00493 const char *err = NULL;
00494 theStore.delete_all();
00495 if ((err = theStore.read_config())) {
00496 printf("%s, %s failed\n", err, n);
00497 return CMD_FAILED;
00498 }
00499 printf("Host Database\n");
00500 HostDBCache hd;
00501 if (hd.start(fix) < 0) {
00502 printf("\tunable to open Host Database, %s failed\n", n);
00503 return CMD_OK;
00504 }
00505 hd.check("hostdb.config", fix);
00506 hd.reset();
00507
00508 if (cacheProcessor.start() < 0) {
00509 printf("\nbad cache configuration, %s failed\n", n);
00510 return CMD_FAILED;
00511 }
00512 eventProcessor.schedule_every(new CmdCacheCont(true, fix), HRTIME_SECONDS(1));
00513
00514 return CMD_IN_PROGRESS;
00515 }
00516
00517 static int
00518 cmd_check(char *cmd)
00519 {
00520 return cmd_check_internal(cmd, false);
00521 }
00522
00523 #ifdef UNUSED_FUNCTION
00524 static int
00525 cmd_repair(char *cmd)
00526 {
00527 return cmd_check_internal(cmd, true);
00528 }
00529 #endif
00530
00531 static int
00532 cmd_clear(char *cmd)
00533 {
00534 Note("CLEAR");
00535
00536 bool c_all = !strcmp(cmd, "clear");
00537 bool c_hdb = !strcmp(cmd, "clear_hostdb");
00538
00539 bool c_cache = !strcmp(cmd, "clear_cache");
00540
00541 if (c_all || c_hdb) {
00542 ats_scoped_str rundir(RecConfigReadRuntimeDir());
00543 ats_scoped_str config(Layout::relative_to(rundir, "hostdb.config"));
00544
00545 Note("Clearing HostDB Configuration");
00546 if (unlink(config) < 0)
00547 Note("unable to unlink %s", (const char *)config);
00548 }
00549
00550 if (c_all || c_cache) {
00551 const char *err = NULL;
00552 theStore.delete_all();
00553 if ((err = theStore.read_config())) {
00554 printf("%s, CLEAR failed\n", err);
00555 return CMD_FAILED;
00556 }
00557 }
00558
00559 if (c_hdb || c_all) {
00560 Note("Clearing Host Database");
00561 if (hostDBProcessor.cache()->start(PROCESSOR_RECONFIGURE) < 0) {
00562 Note("unable to open Host Database, CLEAR failed");
00563 return CMD_FAILED;
00564 }
00565 hostDBProcessor.cache()->reset();
00566 if (c_hdb)
00567 return CMD_OK;
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 if (c_all || c_cache) {
00581 Note("Clearing Cache");
00582
00583 if (cacheProcessor.start_internal(PROCESSOR_RECONFIGURE) < 0) {
00584 Note("unable to open Cache, CLEAR failed");
00585 return CMD_FAILED;
00586 }
00587 eventProcessor.schedule_every(new CmdCacheCont(false), HRTIME_SECONDS(1));
00588 return CMD_IN_PROGRESS;
00589 }
00590
00591 return CMD_OK;
00592 }
00593
00594 static int cmd_help(char *cmd);
00595
00596 static const struct CMD
00597 {
00598 const char *n;
00599 const char *d;
00600 const char *h;
00601 int (*f) (char *);
00602 }
00603 commands[] = {
00604 {
00605 "list",
00606 "List cache configuration",
00607 "LIST\n"
00608 "\n"
00609 "FORMAT: list\n"
00610 "\n"
00611 "List the sizes of the Host Database and Cache Index,\n" "and the storage available to the cache.\n", cmd_list}, {
00612 "check",
00613 "Check the cache (do not make any changes)",
00614 "CHECK\n"
00615 "\n"
00616 "FORMAT: check\n"
00617 "\n"
00618 "Check the cache for inconsistencies or corruption.\n"
00619 "CHECK does not make any changes to the data stored in\n"
00620 "the cache. CHECK requires a scan of the contents of the\n"
00621 "cache and may take a long time for large caches.\n", cmd_check}, {
00622 "clear",
00623 "Clear the entire cache",
00624 "CLEAR\n"
00625 "\n"
00626 "FORMAT: clear\n"
00627 "\n"
00628 "Clear the entire cache. All data in the cache is\n"
00629 "lost and the cache is reconfigured based on the current\n"
00630 "description of database sizes and available storage.\n", cmd_clear}, {
00631 "clear_cache",
00632 "Clear the document cache",
00633 "CLEAR_CACHE\n"
00634 "\n"
00635 "FORMAT: clear_cache\n"
00636 "\n"
00637 "Clear the document cache. All documents in the cache are\n"
00638 "lost and the cache is reconfigured based on the current\n"
00639 "description of database sizes and available storage.\n", cmd_clear}, {
00640 "clear_hostdb",
00641 "Clear the hostdb cache",
00642 "CLEAR_HOSTDB\n"
00643 "\n"
00644 "FORMAT: clear_hostdb\n"
00645 "\n" "Clear the entire hostdb cache. All host name resolution\n" "information is lost.\n", cmd_clear}, {
00646 "help",
00647 "Obtain a short description of a command (e.g. 'help clear')",
00648 "HELP\n"
00649 "\n"
00650 "FORMAT: help [command_name]\n"
00651 "\n"
00652 "EXAMPLES: help help\n"
00653 " help commit\n" "\n" "Provide a short description of a command (like this).\n", cmd_help},};
00654
00655 static int
00656 cmd_index(char *p)
00657 {
00658 p += strspn(p, " \t");
00659 for (unsigned c = 0; c < countof(commands); c++) {
00660 const char *l = commands[c].n;
00661 while (l) {
00662 const char *s = strchr(l, '/');
00663 char *e = strpbrk(p, " \t\n");
00664 int len = s ? s - l : strlen(l);
00665 int lenp = e ? e - p : strlen(p);
00666 if ((len == lenp) && !strncasecmp(p, l, len))
00667 return c;
00668 l = s ? s + 1 : 0;
00669 }
00670 }
00671 return -1;
00672 }
00673
00674 static int
00675 cmd_help(char *cmd)
00676 {
00677 (void) cmd;
00678 printf("HELP\n\n");
00679 cmd = skip(cmd, true);
00680 if (!cmd) {
00681 for (unsigned i = 0; i < countof(commands); i++) {
00682 printf("%15s %s\n", commands[i].n, commands[i].d);
00683 }
00684 } else {
00685 int i;
00686 if ((i = cmd_index(cmd)) < 0) {
00687 printf("\nno help found for: %s\n", cmd);
00688 return CMD_FAILED;
00689 }
00690 printf("Help for: %s\n\n", commands[i].n);
00691 printf("%s", commands[i].h);
00692 }
00693 return CMD_OK;
00694 }
00695
00696 static void
00697 check_fd_limit()
00698 {
00699 int fds_throttle = -1;
00700 REC_ReadConfigInteger(fds_throttle, "proxy.config.net.connections_throttle");
00701 if (fds_throttle > fds_limit + THROTTLE_FD_HEADROOM) {
00702 int new_fds_throttle = fds_limit - THROTTLE_FD_HEADROOM;
00703 if (new_fds_throttle < 1)
00704 MachineFatal("too few file descritors (%d) available", fds_limit);
00705 char msg[256];
00706 snprintf(msg, sizeof(msg), "connection throttle too high, "
00707 "%d (throttle) + %d (internal use) > %d (file descriptor limit), "
00708 "using throttle of %d", fds_throttle, THROTTLE_FD_HEADROOM, fds_limit, new_fds_throttle);
00709 SignalWarning(MGMT_SIGNAL_SYSTEM_ERROR, msg);
00710 }
00711 }
00712
00713
00714
00715
00716 static int
00717 cmd_mode()
00718 {
00719 if (*command_string) {
00720 int c = cmd_index(command_string);
00721 if (c >= 0) {
00722 return commands[c].f(command_string);
00723 } else {
00724 Warning("unrecognized command: '%s'", command_string);
00725 return CMD_FAILED;
00726 }
00727 } else {
00728 printf("\n");
00729 printf("WARNING\n");
00730 printf("\n");
00731 printf("The interactive command mode no longer exists.\n");
00732 printf("Use '-C <command>' to execute a command from the shell prompt.\n");
00733 printf("For example: 'traffic_server -C clear' will clear the cache.\n");
00734 return 1;
00735 }
00736 }
00737
00738 #ifdef UNUSED_FUNCTION
00739 static void
00740 check_for_root_uid()
00741 {
00742 if ((getuid() == 0) || (geteuid() == 0)) {
00743 ProcessFatal("Traffic Server must not be run as root");
00744 }
00745 }
00746 #endif
00747
00748 static int
00749 set_core_size(const char * , RecDataT ,
00750 RecData data, void * )
00751 {
00752 RecInt size = data.rec_int;
00753 struct rlimit lim;
00754 bool failed = false;
00755
00756 if (getrlimit(RLIMIT_CORE, &lim) < 0) {
00757 failed = true;
00758 } else {
00759 if (size < 0) {
00760 lim.rlim_cur = lim.rlim_max;
00761 } else {
00762 lim.rlim_cur = (rlim_t) size;
00763 }
00764 if (setrlimit(RLIMIT_CORE, &lim) < 0) {
00765 failed = true;
00766 }
00767 enable_core_file_p = size != 0;
00768 EnableCoreFile(enable_core_file_p);
00769 }
00770
00771 if (failed == true) {
00772 Warning("Failed to set Core Limit : %s", strerror(errno));
00773 }
00774 return 0;
00775 }
00776
00777 static void
00778 init_core_size()
00779 {
00780 bool found;
00781 RecInt coreSize;
00782 found = (RecGetRecordInt("proxy.config.core_limit", &coreSize) == REC_ERR_OKAY);
00783
00784 if (found == false) {
00785 Warning("Unable to determine core limit");
00786 } else {
00787 RecData rec_temp;
00788 rec_temp.rec_int = coreSize;
00789 set_core_size(NULL, RECD_INT, rec_temp, NULL);
00790 found = (REC_RegisterConfigUpdateFunc("proxy.config.core_limit", set_core_size, NULL) == REC_ERR_OKAY);
00791
00792 ink_assert(found);
00793 }
00794 }
00795
00796 static void
00797 adjust_sys_settings(void)
00798 {
00799 #if defined(linux)
00800 struct rlimit lim;
00801 int mmap_max = -1;
00802 int fds_throttle = -1;
00803 float file_max_pct = 0.9;
00804 FILE *fd;
00805
00806
00807 REC_ReadConfigInteger(mmap_max, "proxy.config.system.mmap_max");
00808 if (mmap_max >= 0)
00809 ats_mallopt(ATS_MMAP_MAX, mmap_max);
00810
00811 if ((fd = fopen("/proc/sys/fs/file-max","r"))) {
00812 ATS_UNUSED_RETURN(fscanf(fd, "%" PRIu64 "", &lim.rlim_max));
00813 fclose(fd);
00814 REC_ReadConfigFloat(file_max_pct, "proxy.config.system.file_max_pct");
00815 lim.rlim_cur = lim.rlim_max = static_cast<rlim_t>(lim.rlim_max * file_max_pct);
00816 if (!setrlimit(RLIMIT_NOFILE, &lim) && !getrlimit(RLIMIT_NOFILE, &lim)) {
00817 fds_limit = (int) lim.rlim_cur;
00818 syslog(LOG_NOTICE, "NOTE: RLIMIT_NOFILE(%d):cur(%d),max(%d)",RLIMIT_NOFILE, (int)lim.rlim_cur, (int)lim.rlim_max);
00819 } else {
00820 syslog(LOG_NOTICE, "NOTE: Unable to set RLIMIT_NOFILE(%d):cur(%d),max(%d)", RLIMIT_NOFILE, (int)lim.rlim_cur, (int)lim.rlim_max);
00821 }
00822 } else {
00823 syslog(LOG_NOTICE, "NOTE: Unable to open /proc/sys/fs/file-max");
00824 }
00825
00826 REC_ReadConfigInteger(fds_throttle, "proxy.config.net.connections_throttle");
00827
00828 if (!getrlimit(RLIMIT_NOFILE, &lim)) {
00829 if (fds_throttle > (int) (lim.rlim_cur + THROTTLE_FD_HEADROOM)) {
00830 lim.rlim_cur = (lim.rlim_max = (rlim_t) fds_throttle);
00831 if (!setrlimit(RLIMIT_NOFILE, &lim) && !getrlimit(RLIMIT_NOFILE, &lim)) {
00832 fds_limit = (int) lim.rlim_cur;
00833 syslog(LOG_NOTICE, "NOTE: RLIMIT_NOFILE(%d):cur(%d),max(%d)",RLIMIT_NOFILE, (int)lim.rlim_cur, (int)lim.rlim_max);
00834 }
00835 }
00836 }
00837
00838 ink_max_out_rlimit(RLIMIT_STACK,true,true);
00839 ink_max_out_rlimit(RLIMIT_DATA,true,true);
00840 ink_max_out_rlimit(RLIMIT_FSIZE, true, false);
00841 #ifdef RLIMIT_RSS
00842 ink_max_out_rlimit(RLIMIT_RSS,true,true);
00843 #endif
00844
00845 #endif // linux check
00846 }
00847
00848 struct ShowStats: public Continuation
00849 {
00850 #ifdef ENABLE_TIME_TRACE
00851 FILE *fp;
00852 #endif
00853 int cycle;
00854 int64_t last_cc;
00855 int64_t last_rb;
00856 int64_t last_w;
00857 int64_t last_r;
00858 int64_t last_wb;
00859 int64_t last_nrb;
00860 int64_t last_nw;
00861 int64_t last_nr;
00862 int64_t last_nwb;
00863 int64_t last_p;
00864 int64_t last_o;
00865 int mainEvent(int event, Event * e)
00866 {
00867 (void) event;
00868 (void) e;
00869 if (!(cycle++ % 24))
00870 printf("r:rr w:ww r:rbs w:wbs open polls\n");
00871 ink_statval_t sval, cval;
00872
00873 NET_READ_DYN_SUM(net_calls_to_readfromnet_stat, sval);
00874 int64_t d_rb = sval - last_rb;
00875 last_rb += d_rb;
00876 NET_READ_DYN_SUM(net_calls_to_readfromnet_afterpoll_stat, sval);
00877 int64_t d_r = sval - last_r;
00878 last_r += d_r;
00879
00880 NET_READ_DYN_SUM(net_calls_to_writetonet_stat, sval);
00881 int64_t d_wb = sval - last_wb;
00882 last_wb += d_wb;
00883 NET_READ_DYN_SUM(net_calls_to_writetonet_afterpoll_stat, sval);
00884 int64_t d_w = sval - last_w;
00885 last_w += d_w;
00886
00887 NET_READ_DYN_STAT(net_read_bytes_stat, sval, cval);
00888 int64_t d_nrb = sval - last_nrb;
00889 last_nrb += d_nrb;
00890 int64_t d_nr = cval - last_nr;
00891 last_nr += d_nr;
00892
00893 NET_READ_DYN_STAT(net_write_bytes_stat, sval, cval);
00894 int64_t d_nwb = sval - last_nwb;
00895 last_nwb += d_nwb;
00896 int64_t d_nw = cval - last_nw;
00897 last_nw += d_nw;
00898
00899 NET_READ_GLOBAL_DYN_SUM(net_connections_currently_open_stat, sval);
00900 int64_t d_o = sval;
00901
00902 NET_READ_DYN_STAT(net_handler_run_stat, sval, cval);
00903 int64_t d_p = cval - last_p;
00904 last_p += d_p;
00905 printf("%" PRId64 ":%" PRId64 " %" PRId64 ":%" PRId64 " %" PRId64 ":%" PRId64 " %" PRId64 ":%" PRId64 " %" PRId64 " %" PRId64 "\n",
00906 d_rb, d_r, d_wb, d_w, d_nrb, d_nr, d_nwb, d_nw, d_o, d_p);
00907 #ifdef ENABLE_TIME_TRACE
00908 int i;
00909 fprintf(fp, "immediate_events_time_dist\n");
00910 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++)
00911 {
00912 if ((i % 10) == 0)
00913 fprintf(fp, "\n");
00914 fprintf(fp, "%5d ", immediate_events_time_dist[i]);
00915 }
00916 fprintf(fp, "\ncnt_immediate_events=%d\n", cnt_immediate_events);
00917
00918 fprintf(fp, "cdb_callback_time_dist\n");
00919 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++) {
00920 if ((i % 10) == 0)
00921 fprintf(fp, "\n");
00922 fprintf(fp, "%5d ", cdb_callback_time_dist[i]);
00923 }
00924 fprintf(fp, "\ncdb_cache_callbacks=%d\n", cdb_cache_callbacks);
00925
00926 fprintf(fp, "callback_time_dist\n");
00927 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++) {
00928 if ((i % 10) == 0)
00929 printf("\n");
00930 fprintf(fp, "%5d ", callback_time_dist[i]);
00931 }
00932 fprintf(fp, "\ncache_callbacks=%d\n", cache_callbacks);
00933
00934 fprintf(fp, "rmt_callback_time_dist\n");
00935 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++) {
00936 if ((i % 10) == 0)
00937 fprintf(fp, "\n");
00938 fprintf(fp, "%5d ", rmt_callback_time_dist[i]);
00939 }
00940 fprintf(fp, "\nrmt_cache_callbacks=%d\n", rmt_cache_callbacks);
00941
00942 fprintf(fp, "inmsg_time_dist\n");
00943 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++) {
00944 if ((i % 10) == 0)
00945 fprintf(fp, "\n");
00946 fprintf(fp, "%5d ", inmsg_time_dist[i]);
00947 }
00948 fprintf(fp, "\ninmsg_events=%d\n", inmsg_events);
00949
00950 fprintf(fp, "open_delay_time_dist\n");
00951 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++) {
00952 if ((i % 10) == 0)
00953 fprintf(fp, "\n");
00954 fprintf(fp, "%5d ", open_delay_time_dist[i]);
00955 }
00956 fprintf(fp, "\nopen_delay_events=%d\n", open_delay_events);
00957
00958 fprintf(fp, "cluster_send_time_dist\n");
00959 for (i = 0; i < TIME_DIST_BUCKETS_SIZE; i++) {
00960 if ((i % 10) == 0)
00961 fprintf(fp, "\n");
00962 fprintf(fp, "%5d ", cluster_send_time_dist[i]);
00963 }
00964 fprintf(fp, "\ncluster_send_events=%d\n", cluster_send_events);
00965 fflush(fp);
00966 #endif
00967 return EVENT_CONT;
00968 }
00969 ShowStats():Continuation(NULL),
00970 cycle(0),
00971 last_cc(0),
00972 last_rb(0),
00973 last_w(0), last_r(0), last_wb(0), last_nrb(0), last_nw(0), last_nr(0), last_nwb(0), last_p(0), last_o(0) {
00974 SET_HANDLER(&ShowStats::mainEvent);
00975 #ifdef ENABLE_TIME_TRACE
00976 fp = fopen("./time_trace.out", "a");
00977 #endif
00978
00979 }
00980 };
00981
00982
00983
00984 static int syslog_facility = LOG_DAEMON;
00985
00986
00987
00988
00989
00990
00991
00992
00993 static void
00994 syslog_log_configure()
00995 {
00996 char *facility_str = NULL;
00997 int facility;
00998
00999 REC_ReadConfigStringAlloc(facility_str, "proxy.config.syslog_facility");
01000
01001 if (facility_str == NULL || (facility = facility_string_to_int(facility_str)) < 0) {
01002 syslog(LOG_WARNING, "Bad or missing syslog facility. " "Defaulting to LOG_DAEMON");
01003 } else {
01004 syslog_facility = facility;
01005 closelog();
01006 openlog("traffic_server", LOG_PID | LOG_NDELAY | LOG_NOWAIT, facility);
01007 }
01008
01009 Debug("server", "Setting syslog facility to %d\n", syslog_facility);
01010 ats_free(facility_str);
01011 }
01012
01013 static void
01014 check_system_constants()
01015 {
01016 }
01017
01018 static void
01019 init_http_header()
01020 {
01021 url_init();
01022 mime_init();
01023 http_init();
01024 }
01025
01026 struct AutoStopCont: public Continuation
01027 {
01028 int mainEvent(int event, Event * e)
01029 {
01030 (void) event;
01031 (void) e;
01032 _exit(0);
01033 return 0;
01034 }
01035 AutoStopCont():Continuation(new_ProxyMutex())
01036 {
01037 SET_HANDLER(&AutoStopCont::mainEvent);
01038 }
01039 };
01040
01041 static void
01042 run_AutoStop()
01043 {
01044 if (getenv("PROXY_AUTO_EXIT"))
01045 eventProcessor.schedule_in(new AutoStopCont(), HRTIME_SECONDS(atoi(getenv("PROXY_AUTO_EXIT"))));
01046 }
01047
01048 #if TS_HAS_TESTS
01049 struct RegressionCont: public Continuation
01050 {
01051 int initialized;
01052 int waits;
01053 int started;
01054 int mainEvent(int event, Event * e)
01055 {
01056 (void) event;
01057 (void) e;
01058 int res = 0;
01059 if (!initialized && (cacheProcessor.IsCacheEnabled() != CACHE_INITIALIZED))
01060 {
01061 printf("Regression waiting for the cache to be ready... %d\n", ++waits);
01062 return EVENT_CONT;
01063 }
01064 char *rt = (char *) (regression_test[0] == 0 ? "" : regression_test);
01065 if (!initialized && RegressionTest::run(rt) == REGRESSION_TEST_INPROGRESS) {
01066 initialized = 1;
01067 return EVENT_CONT;
01068 }
01069 if ((res = RegressionTest::check_status()) == REGRESSION_TEST_INPROGRESS)
01070 return EVENT_CONT;
01071 fprintf(stderr, "REGRESSION_TEST DONE: %s\n", regression_status_string(res));
01072 _exit(res == REGRESSION_TEST_PASSED ? 0 : 1);
01073 return EVENT_CONT;
01074 }
01075 RegressionCont():Continuation(new_ProxyMutex()), initialized(0), waits(0), started(0) {
01076 SET_HANDLER(&RegressionCont::mainEvent);
01077 }
01078 };
01079
01080 static void
01081 run_RegressionTest()
01082 {
01083 if (regression_level)
01084 eventProcessor.schedule_every(new RegressionCont(), HRTIME_SECONDS(1));
01085 }
01086 #endif //TS_HAS_TESTS
01087
01088
01089 static void
01090 chdir_root()
01091 {
01092 const char * prefix = Layout::get()->prefix;
01093
01094 if (chdir(prefix) < 0) {
01095 fprintf(stderr,"unable to change to root directory \"%s\" [%d '%s']\n",
01096 prefix, errno, strerror(errno));
01097 fprintf(stderr," please set correct path in env variable TS_ROOT \n");
01098 _exit(1);
01099 } else {
01100 printf("[TrafficServer] using root directory '%s'\n", prefix);
01101 }
01102 }
01103
01104
01105 static int
01106 getNumSSLThreads(void)
01107 {
01108 int num_of_ssl_threads = -1;
01109
01110
01111
01112
01113
01114 if (HttpProxyPort::hasSSL()) {
01115 int config_num_ssl_threads = 0;
01116
01117 REC_ReadConfigInteger(config_num_ssl_threads, "proxy.config.ssl.number.threads");
01118
01119 if (config_num_ssl_threads > 0) {
01120 num_of_ssl_threads = config_num_ssl_threads;
01121 } else if (config_num_ssl_threads == -1) {
01122 return -1;
01123 } else {
01124 float autoconfig_scale = 1.5;
01125
01126 REC_ReadConfigFloat(autoconfig_scale, "proxy.config.exec_thread.autoconfig.scale");
01127 num_of_ssl_threads = (int)((float)ink_number_of_processors() * autoconfig_scale);
01128
01129
01130 if (num_of_ssl_threads <= 0)
01131 num_of_ssl_threads = config_num_ssl_threads * 2;
01132 }
01133 }
01134
01135 return num_of_ssl_threads;
01136 }
01137
01138 static int
01139 adjust_num_of_net_threads(int nthreads)
01140 {
01141 float autoconfig_scale = 1.0;
01142 int nth_auto_config = 1;
01143 int num_of_threads_tmp = 1;
01144
01145 REC_ReadConfigInteger(nth_auto_config, "proxy.config.exec_thread.autoconfig");
01146
01147 Debug("threads", "initial number of net threads is %d", nthreads);
01148 Debug("threads", "net threads auto-configuration %s", nth_auto_config ? "enabled" : "disabled");
01149
01150 if (!nth_auto_config) {
01151 REC_ReadConfigInteger(num_of_threads_tmp, "proxy.config.exec_thread.limit");
01152
01153 if (num_of_threads_tmp <= 0) {
01154 num_of_threads_tmp = 1;
01155 } else if (num_of_threads_tmp > MAX_EVENT_THREADS) {
01156 num_of_threads_tmp = MAX_EVENT_THREADS;
01157 }
01158
01159 nthreads = num_of_threads_tmp;
01160 } else {
01161 num_of_threads_tmp = nthreads;
01162 REC_ReadConfigFloat(autoconfig_scale, "proxy.config.exec_thread.autoconfig.scale");
01163 num_of_threads_tmp = (int) ((float) num_of_threads_tmp * autoconfig_scale);
01164
01165 if (unlikely(num_of_threads_tmp > MAX_EVENT_THREADS)) {
01166 num_of_threads_tmp = MAX_EVENT_THREADS;
01167 }
01168
01169 if (num_of_threads_tmp) {
01170 nthreads = num_of_threads_tmp;
01171 }
01172 }
01173
01174 if (unlikely(nthreads <= 0)) {
01175 Warning("number of net threads must be greater than 0, resetting to 1");
01176 nthreads = 1;
01177 }
01178
01179 Debug("threads", "adjusted number of net threads is %d", nthreads);
01180 return nthreads;
01181 }
01182
01183
01184
01185
01186
01187 static void
01188 change_uid_gid(const char *user)
01189 {
01190 struct passwd pwbuf;
01191 struct passwd *pwbufp = NULL;
01192 #if defined(freebsd) // TODO: investigate sysconf(_SC_GETPW_R_SIZE_MAX)) failure
01193 long buflen = 1024;
01194 #else
01195 long buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
01196 #endif
01197 if (buflen < 0) {
01198 ink_fatal_die("sysconf() failed for _SC_GETPW_R_SIZE_MAX");
01199 }
01200
01201 char *buf = (char *)ats_malloc(buflen);
01202
01203 if (0 != geteuid() && 0 == getuid())
01204 ATS_UNUSED_RETURN(seteuid(0));
01205 if (0 != geteuid()) {
01206
01207
01208 fprintf(stderr,
01209 "Can't change user to '%s' because running with effective uid=%d\n",
01210 user, geteuid());
01211 }
01212 else {
01213 if (user[0] == '#') {
01214
01215 uid_t uid = (uid_t)atoi(&user[1]);
01216 getpwuid_r(uid, &pwbuf, buf, buflen, &pwbufp);
01217 }
01218 else {
01219
01220 getpwnam_r(user, &pwbuf, buf, buflen, &pwbufp);
01221 }
01222
01223 if (pwbufp == NULL) {
01224 ink_fatal_die("Can't find entry in password file for user: %s", user);
01225 }
01226 #if !defined (BIG_SECURITY_HOLE)
01227 if (pwbuf.pw_uid == 0) {
01228 ink_fatal_die("Trafficserver has not been designed to serve pages while\n"
01229 "\trunning as root. There are known race conditions that\n"
01230 "\twill allow any local user to read any file on the system.\n"
01231 "\tIf you still desire to serve pages as root then\n"
01232 "\tadd -DBIG_SECURITY_HOLE to the CFLAGS env variable\n"
01233 "\tand then rebuild the server.\n"
01234 "\tIt is strongly suggested that you instead modify the\n"
01235 "\tproxy.config.admin.user_id directive in your\n"
01236 "\trecords.config file to list a non-root user.\n");
01237 }
01238 #endif
01239
01240 if (getgid() != pwbuf.pw_gid) {
01241 if (setgid(pwbuf.pw_gid) != 0) {
01242 ink_fatal_die("Can't change group to user: %s, gid: %d",
01243 user, pwbuf.pw_gid);
01244 }
01245 }
01246
01247 if (getuid() != pwbuf.pw_uid) {
01248 if (setuid(pwbuf.pw_uid) != 0) {
01249 ink_fatal_die("Can't change uid to user: %s, uid: %d",
01250 user, pwbuf.pw_uid);
01251 }
01252 }
01253 }
01254 ats_free(buf);
01255
01256
01257
01258 EnableCoreFile(enable_core_file_p);
01259 }
01260
01261
01262
01263
01264
01265 int
01266 main(int , char **argv)
01267 {
01268 #if TS_HAS_PROFILER
01269 ProfilerStart("/tmp/ts.prof");
01270 #endif
01271 bool admin_user_p = false;
01272
01273 #if defined(DEBUG) && defined(HAVE_MCHECK_PEDANTIC)
01274 mcheck_pedantic(NULL);
01275 #endif
01276
01277 pcre_malloc = ats_malloc;
01278 pcre_free = ats_free;
01279
01280
01281 check_system_constants();
01282
01283
01284 appVersionInfo.setup(PACKAGE_NAME,"traffic_server", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
01285
01286
01287 Layout::create();
01288 chdir_root();
01289
01290 process_args(argument_descriptions, countof(argument_descriptions), argv);
01291
01292
01293 if (version_flag) {
01294 fprintf(stderr, "%s\n", appVersionInfo.FullVersionInfoStr);
01295 _exit(0);
01296 }
01297
01298
01299 setbuf(stdout, NULL);
01300 setbuf(stdin, NULL);
01301
01302
01303
01304 ink_set_dprintf_level(cmd_line_dprintf_level);
01305
01306
01307
01308 openlog("traffic_server", LOG_PID | LOG_NDELAY | LOG_NOWAIT, LOG_DAEMON);
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319 diagsConfig = new DiagsConfig(DIAGS_LOG_FILENAME, error_tags, action_tags, false);
01320 diags = diagsConfig->diags;
01321 diags->prefix_str = "Server ";
01322 if (is_debug_tag_set("diags"))
01323 diags->dump();
01324
01325
01326 initialize_process_manager();
01327
01328
01329 check_lockfile();
01330
01331
01332 init_core_size();
01333 init_system();
01334
01335
01336 adjust_sys_settings();
01337
01338
01339 syslog_log_configure();
01340
01341 if (!num_accept_threads)
01342 REC_ReadConfigInteger(num_accept_threads, "proxy.config.accept_threads");
01343
01344 if (!num_task_threads)
01345 REC_ReadConfigInteger(num_task_threads, "proxy.config.task_threads");
01346
01347 ats_scoped_str user(MAX_LOGIN + 1);
01348
01349 *user = '\0';
01350 admin_user_p = ((REC_ERR_OKAY == REC_ReadConfigString(user, "proxy.config.admin.user_id", MAX_LOGIN)) &&
01351 (*user != '\0') && (0 != strcmp(user, "#-1")));
01352
01353 # if TS_USE_POSIX_CAP
01354
01355
01356
01357
01358
01359
01360 if (admin_user_p) {
01361 PreserveCapabilities();
01362 change_uid_gid(user);
01363 RestrictCapabilities();
01364 }
01365 # endif
01366
01367
01368
01369
01370
01371
01372
01373 Thread *main_thread = new EThread;
01374 main_thread->set_specific();
01375
01376
01377 if (diagsConfig) {
01378 RecDebugOff();
01379 delete(diagsConfig);
01380 }
01381 diagsConfig = new DiagsConfig(DIAGS_LOG_FILENAME, error_tags, action_tags, true);
01382 diags = diagsConfig->diags;
01383 RecSetDiags(diags);
01384 diags->prefix_str = "Server ";
01385 if (is_debug_tag_set("diags"))
01386 diags->dump();
01387 # if TS_USE_POSIX_CAP
01388 if (is_debug_tag_set("server"))
01389 DebugCapabilities("server");
01390 # endif
01391
01392
01393 #if defined(MCL_FUTURE)
01394 int mlock_flags = 0;
01395 REC_ReadConfigInteger(mlock_flags, "proxy.config.mlock_enabled");
01396
01397 if (mlock_flags == 2) {
01398 if (0 != mlockall(MCL_CURRENT | MCL_FUTURE))
01399 Warning("Unable to mlockall() on startup");
01400 else
01401 Debug("server", "Successfully called mlockall()");
01402 }
01403 #endif
01404
01405
01406 if (core_file[0] != '\0') {
01407 process_core(core_file);
01408 _exit(0);
01409 }
01410
01411
01412
01413
01414
01415 HttpConfig::startup();
01416
01417
01418
01419 IpEndpoint machine_addr;
01420 ink_zero(machine_addr);
01421 if (HttpConfig::m_master.outbound_ip4.isValid())
01422 machine_addr.assign(HttpConfig::m_master.outbound_ip4);
01423 else if (HttpConfig::m_master.outbound_ip6.isValid())
01424 machine_addr.assign(HttpConfig::m_master.outbound_ip6);
01425 else if (HttpConfig::m_master.inbound_ip4.isValid())
01426 machine_addr.assign(HttpConfig::m_master.inbound_ip4);
01427 else if (HttpConfig::m_master.inbound_ip6.isValid())
01428 machine_addr.assign(HttpConfig::m_master.inbound_ip6);
01429 Machine::init(0, &machine_addr.sa);
01430
01431
01432
01433
01434 REC_ReadConfigInteger(res_track_memory, "proxy.config.res_track_memory");
01435
01436 init_http_header();
01437 ts_session_protocol_well_known_name_indices_init();
01438
01439
01440 check_fd_limit();
01441 command_flag = command_flag || *command_string;
01442
01443
01444 if (!command_flag && initialize_store())
01445 ProcessFatal("unable to initialize storage, (Re)Configuration required\n");
01446
01447
01448 #define SET_INTERVAL(scope, name, var) do { \
01449 RecInt tmpint; \
01450 Debug("statsproc", "Looking for %s\n", name); \
01451 if (RecGetRecordInt(name, &tmpint) == REC_ERR_OKAY) { \
01452 Debug("statsproc", "Found %s\n", name); \
01453 scope##_set_##var(tmpint); \
01454 } \
01455 } while(0)
01456 SET_INTERVAL(RecProcess, "proxy.config.config_update_interval_ms", config_update_interval_ms);
01457 SET_INTERVAL(RecProcess, "proxy.config.raw_stat_sync_interval_ms", raw_stat_sync_interval_ms);
01458 SET_INTERVAL(RecProcess, "proxy.config.remote_sync_interval_ms", remote_sync_interval_ms);
01459
01460
01461 statPagesManager.init();
01462
01463
01464
01465
01466
01467
01468 RecInt cluster_type;
01469 cache_clustering_enabled = 0;
01470
01471 if (RecGetRecordInt("proxy.local.cluster.type", &cluster_type) == REC_ERR_OKAY) {
01472 if (cluster_type == 1)
01473 cache_clustering_enabled = 1;
01474 }
01475 Note("cache clustering %s", cache_clustering_enabled ? "enabled" : "disabled");
01476
01477
01478 initialize_all_global_stats();
01479
01480 num_of_net_threads = adjust_num_of_net_threads(num_of_net_threads);
01481
01482 size_t stacksize;
01483 REC_ReadConfigInteger(stacksize, "proxy.config.thread.default.stacksize");
01484
01485
01486
01487 if (-1 != poll_timeout) {
01488 net_config_poll_timeout = poll_timeout;
01489 } else {
01490 REC_ReadConfigInteger(net_config_poll_timeout, "proxy.config.net.poll_timeout");
01491 }
01492
01493
01494 if (net_config_poll_timeout < 0) {
01495 net_config_poll_timeout = 10;
01496 }
01497
01498 ink_event_system_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER));
01499 ink_net_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER));
01500 ink_aio_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER));
01501 ink_cache_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER));
01502 ink_hostdb_init(makeModuleVersion(HOSTDB_MODULE_MAJOR_VERSION, HOSTDB_MODULE_MINOR_VERSION , PRIVATE_MODULE_HEADER));
01503 ink_dns_init(makeModuleVersion(HOSTDB_MODULE_MAJOR_VERSION, HOSTDB_MODULE_MINOR_VERSION , PRIVATE_MODULE_HEADER));
01504 ink_split_dns_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER));
01505 eventProcessor.start(num_of_net_threads, stacksize);
01506
01507 int num_remap_threads = 0;
01508 REC_ReadConfigInteger(num_remap_threads, "proxy.config.remap.num_remap_threads");
01509 if (num_remap_threads < 1)
01510 num_remap_threads = 0;
01511
01512 if (num_remap_threads > 0) {
01513 Note("using the new remap processor system with %d threads", num_remap_threads);
01514 remapProcessor.setUseSeparateThread();
01515 }
01516
01517 init_signals2();
01518
01519
01520 if (command_flag) {
01521 int cmd_ret = cmd_mode();
01522
01523 if (cmd_ret != CMD_IN_PROGRESS) {
01524 if (cmd_ret >= 0)
01525 _exit(0);
01526 else
01527 _exit(1);
01528 }
01529 } else {
01530 remapProcessor.start(num_remap_threads, stacksize);
01531 RecProcessStart();
01532 initCacheControl();
01533 initCongestionControl();
01534 IpAllow::startup();
01535 ParentConfig::startup();
01536 #ifdef SPLIT_DNS
01537 SplitDNSConfig::startup();
01538 #endif
01539
01540 # if TS_HAS_SPDY
01541 extern int spdy_config_load ();
01542 spdy_config_load();
01543 # endif
01544
01545 if (!HttpProxyPort::loadValue(http_accept_port_descriptor))
01546 HttpProxyPort::loadConfig();
01547 HttpProxyPort::loadDefaultIfEmpty();
01548
01549 if (!accept_mss)
01550 REC_ReadConfigInteger(accept_mss, "proxy.config.net.sock_mss_in");
01551
01552 NetProcessor::accept_mss = accept_mss;
01553 netProcessor.start(0, stacksize);
01554
01555
01556 dnsProcessor.start(0, stacksize);
01557 if (hostDBProcessor.start() < 0)
01558 SignalWarning(MGMT_SIGNAL_SYSTEM_ERROR, "bad hostdb or storage configuration, hostdb disabled");
01559 clusterProcessor.init();
01560
01561
01562 Log::init(remote_management_flag ? 0 : Log::NO_REMOTE_MANAGEMENT);
01563
01564
01565 plugin_init();
01566
01567 SSLConfigParams::init_ssl_ctx_cb = init_ssl_ctx_callback;
01568 sslNetProcessor.start(getNumSSLThreads(), stacksize);
01569 pmgmt->registerPluginCallbacks(global_config_cbs);
01570
01571 cacheProcessor.set_after_init_callback(&CB_After_Cache_Init);
01572 cacheProcessor.start();
01573
01574
01575 if (!num_of_udp_threads)
01576 REC_ReadConfigInteger(num_of_udp_threads, "proxy.config.udp.threads");
01577 if (num_of_udp_threads)
01578 udpNet.start(num_of_udp_threads, stacksize);
01579
01580
01581
01582
01583
01584
01585
01586 start_stats_snap();
01587
01588
01589 body_factory = new HttpBodyFactory;
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603 if (show_statistics)
01604 eventProcessor.schedule_every(new ShowStats(), HRTIME_SECONDS(show_statistics), ET_CALL);
01605
01606
01607
01608
01609
01610
01611 transformProcessor.start();
01612
01613 init_HttpProxyServer(num_accept_threads);
01614
01615 int http_enabled = 1;
01616 REC_ReadConfigInteger(http_enabled, "proxy.config.http.enabled");
01617
01618 if (http_enabled) {
01619 int icp_enabled = 0;
01620 REC_ReadConfigInteger(icp_enabled, "proxy.config.icp.enabled");
01621
01622
01623 APIHook* hook = lifecycle_hooks->get(TS_LIFECYCLE_PORTS_INITIALIZED_HOOK);
01624 while (hook) {
01625 hook->invoke(TS_EVENT_LIFECYCLE_PORTS_INITIALIZED, NULL);
01626 hook = hook->next();
01627 }
01628
01629 int delay_p = 0;
01630 REC_ReadConfigInteger(delay_p, "proxy.config.http.wait_for_cache");
01631
01632
01633
01634 if (delay_p && ink_atomic_cas(&delay_listen_for_cache_p, 0, 1)) {
01635 Debug("http_listen", "Delaying listen, waiting for cache initialization");
01636 } else {
01637 start_HttpProxyServer();
01638 }
01639 if (icp_enabled)
01640 icpProcessor.start();
01641 }
01642
01643
01644 tasksProcessor.start(num_task_threads, stacksize);
01645
01646 int back_door_port = NO_FD;
01647 REC_ReadConfigInteger(back_door_port, "proxy.config.process_manager.mgmt_port");
01648 if (back_door_port != NO_FD)
01649 start_HttpProxyServerBackDoor(back_door_port, num_accept_threads > 0 ? 1 : 0);
01650
01651 if (netProcessor.socks_conf_stuff->accept_enabled) {
01652 start_SocksProxy(netProcessor.socks_conf_stuff->accept_port);
01653 }
01654
01655
01656
01657
01658 updateManager.start();
01659
01660 pmgmt->registerMgmtCallback(MGMT_EVENT_SHUTDOWN, mgmt_restart_shutdown_callback, NULL);
01661 pmgmt->registerMgmtCallback(MGMT_EVENT_RESTART, mgmt_restart_shutdown_callback, NULL);
01662
01663
01664
01665
01666 pmgmt->registerMgmtCallback(MGMT_EVENT_STORAGE_DEVICE_CMD_OFFLINE, mgmt_storage_device_cmd_callback, reinterpret_cast<void*>(static_cast<int>(MGMT_EVENT_STORAGE_DEVICE_CMD_OFFLINE)));
01667
01668
01669 ink_set_thread_name("[ET_NET 0]");
01670
01671 Note("traffic server running");
01672
01673 #if TS_HAS_TESTS
01674 TransformTest::run();
01675 run_HostDBTest();
01676
01677 run_RegressionTest();
01678 #endif
01679
01680 run_AutoStop();
01681 }
01682
01683 # if ! TS_USE_POSIX_CAP
01684 if (admin_user_p) {
01685 change_uid_gid(user);
01686 DebugCapabilities("server");
01687 }
01688 # endif
01689
01690 this_thread()->execute();
01691 }
01692
01693
01694 #if TS_HAS_TESTS
01695
01696
01697
01698
01699 #include "HdrTest.h"
01700
01701 REGRESSION_TEST(Hdrs) (RegressionTest * t, int atype, int *pstatus) {
01702 HdrTest ht;
01703 *pstatus = ht.go(t, atype);
01704 return;
01705 }
01706 #endif
01707
01708 static void *
01709 mgmt_restart_shutdown_callback(void *, char *, int )
01710 {
01711 sync_cache_dir_on_shutdown();
01712 return NULL;
01713 }
01714
01715 static void*
01716 mgmt_storage_device_cmd_callback(void* data, char* arg, int len)
01717 {
01718
01719 CacheDisk* d = cacheProcessor.find_by_path(arg, len);
01720
01721 intptr_t cmd = reinterpret_cast<intptr_t>(data);
01722
01723 if (d) {
01724 switch (cmd) {
01725 case MGMT_EVENT_STORAGE_DEVICE_CMD_OFFLINE:
01726 Debug("server", "Marking %.*s offline", len, arg);
01727 cacheProcessor.mark_storage_offline(d);
01728 break;
01729 }
01730 }
01731 return NULL;
01732 }
01733
01734 static void
01735 init_ssl_ctx_callback(void *ctx, bool server)
01736 {
01737 TSEvent event = server ? TS_EVENT_LIFECYCLE_SERVER_SSL_CTX_INITIALIZED : TS_EVENT_LIFECYCLE_CLIENT_SSL_CTX_INITIALIZED;
01738 APIHook *hook = lifecycle_hooks->get(server ? TS_LIFECYCLE_SERVER_SSL_CTX_INITIALIZED_HOOK : TS_LIFECYCLE_CLIENT_SSL_CTX_INITIALIZED_HOOK);
01739
01740 while (hook) {
01741 hook->invoke(event, ctx);
01742 hook = hook->next();
01743 }
01744 }