• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Main.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /****************************************************************************
00025 
00026   Main.cc
00027 
00028   This is the primary source file for the proxy cache system.
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 //#include "ClusterTest.h"
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 // Global Data
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; // Enable core file dump?
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 //         = DEFAULT_CLUSTER_PORT_NUMBER;
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;  // default debug output level from ink_dprintf function
00158 static int poll_timeout = -1; // No value set.
00159 
00160 // 1: delay listen, wait for cache.
00161 // 0: Do not delay, start listen ASAP.
00162 // -1: cache is already initialized, don't delay.
00163 static volatile int delay_listen_for_cache_p = 0;
00164 
00165 AppVersionInfo appVersionInfo;  // Build info for this application
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", &regression_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 // Initialize operating system related information/services
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   // Delimit file Descriptors
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 // Startup process manager
00294 //
00295 static void
00296 initialize_process_manager()
00297 {
00298   mgmt_use_syslog();
00299 
00300   // Temporary Hack to Enable Communication with LocalManager
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   // Start up manager
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   // Define version info records
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 // Shutdown
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 * /* cmd ATS_UNUSED */)
00348 {
00349   printf("LIST\n\n");
00350 
00351   // show hostdb size
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   // show cache config information....
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 // Handler for things that need to wait until the cache is initialized.
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   // Check for cache BC after the cache is initialized and before listen, if possible.
00394   if (cacheProcessor.min_stripe_version.ink_major < CACHE_DB_MAJOR_VERSION) {
00395     // Versions before 23 need the MMH hash.
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   // Alert the plugins the cache is initialized.
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 * /* cmd ATS_UNUSED */, 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 //#ifndef INK_NO_ACC
00490 //  acc.clear_cache();
00491 //#endif
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   //bool c_adb = !strcmp(cmd, "clear_authdb");
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 //#ifndef INK_NO_ACC
00571 //  if (c_adb || c_all) {
00572  //   if (!acc.clear_cache()) {
00573   //    return CMD_FAILED;
00574   //  }
00575    // if (c_adb)
00576     //  return CMD_OK;
00577 //  }
00578 //#endif
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;                      // name
00599   const char *d;                      // description (part of a line)
00600   const char *h;                      // help string (multi-line)
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 // Command mode
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;        // in error
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 * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
00750               RecData data, void * /* opaque_token ATS_UNUSED */)
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   // TODO: I think we might be able to get rid of this?
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 // TODO: How come this is never used ??
00984 static int syslog_facility = LOG_DAEMON;
00985 
00986 // static void syslog_log_configure()
00987 //
00988 //   Reads the syslog configuration variable
00989 //     and sets the global integer for the
00990 //     facility and calls open log with the
00991 //     new facility
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   // TODO: Not really, what's up with this?
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   // Set number of ssl threads equal to num of processors if
01111   // SSL is enabled so it will scale properly. If SSL is not
01112   // enabled, leave num of ssl threads one, incase a remap rule
01113   // requires traffic server to act as an ssl client.
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; // This will disable ET_SSL threads entirely
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       // Last resort
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 {                      /* autoconfig is enabled */
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)) {      /* impossible case -just for protection */
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  * Change the uid and gid to what is in the passwd entry for supplied user name.
01185  * @param user User name in the passwd file to change the uid and gid to.
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; // or 4096?
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)); // revert euid if possible.
01205   if (0 != geteuid()) {
01206     // Not root so can't change user ID. Logging isn't operational yet so
01207     // we have to write directly to stderr. Perhaps this should be fatal?
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       // numeric user notation
01215       uid_t uid = (uid_t)atoi(&user[1]);
01216       getpwuid_r(uid, &pwbuf, buf, buflen, &pwbufp);
01217     }
01218     else {
01219       // read the entry from the passwd file
01220       getpwnam_r(user, &pwbuf, buf, buflen, &pwbufp);
01221     }
01222     // check to see if we found an entry
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     // change the gid to passwd entry if we are not already running as that gid
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     // change the uid to passwd entry if we are not already running as that uid
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   // Ugly but this gets reset when the process user ID is changed so
01257   // it must be udpated here.
01258   EnableCoreFile(enable_core_file_p);
01259 }
01260 
01261 //
01262 // Main
01263 //
01264 
01265 int
01266 main(int /* argc ATS_UNUSED */, 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   // Verify system dependent 'constants'
01281   check_system_constants();
01282 
01283   // Define the version info
01284   appVersionInfo.setup(PACKAGE_NAME,"traffic_server", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
01285 
01286   // Before accessing file system initialize Layout engine
01287   Layout::create();
01288   chdir_root(); // change directory to the install root of traffic server.
01289 
01290   process_args(argument_descriptions, countof(argument_descriptions), argv);
01291 
01292   // Check for version number request
01293   if (version_flag) {
01294     fprintf(stderr, "%s\n", appVersionInfo.FullVersionInfoStr);
01295     _exit(0);
01296   }
01297 
01298   // Set stdout/stdin to be unbuffered
01299   setbuf(stdout, NULL);
01300   setbuf(stdin, NULL);
01301 
01302   // Set new debug output level (from command line arg)
01303   // Only for debug purposes. We should do it as early as possible.
01304   ink_set_dprintf_level(cmd_line_dprintf_level);
01305 
01306   // Bootstrap syslog.  Since we haven't read records.config
01307   //   yet we do not know where
01308   openlog("traffic_server", LOG_PID | LOG_NDELAY | LOG_NOWAIT, LOG_DAEMON);
01309 
01310   // Setup Diags temporary to allow librecords to be initialized.
01311   // We will re-configure Diags again with proper configurations after
01312   // librecords initialized. This is needed because:
01313   //   - librecords needs diags to initialize
01314   //   - diags needs to read some configuration records to initial
01315   // We cannot mimic whatever TM did (start Diag, init. librecords, and
01316   // re-start Diag completely) because at initialize, TM only has 1 thread.
01317   // In TS, some threads have already created, so if we delete Diag and
01318   // re-start it again, TS will crash.
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   // Local process manager
01326   initialize_process_manager();
01327 
01328   // Ensure only one copy of traffic server is running
01329   check_lockfile();
01330 
01331   // Set the core limit for the process
01332   init_core_size();
01333   init_system();
01334 
01335   // Adjust system and process settings
01336   adjust_sys_settings();
01337 
01338   // Restart syslog now that we have configuration info
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   // Change the user of the process.
01355   // Do this before we start threads so we control the user id of the
01356   // threads (rather than have it change asynchronously during thread
01357   // execution). We also need to do this before we fiddle with capabilities
01358   // as those are thread local and if we change the user id it will
01359   // modify the capabilities in other threads, breaking things.
01360   if (admin_user_p) {
01361     PreserveCapabilities();
01362     change_uid_gid(user);
01363     RestrictCapabilities();
01364   }
01365 # endif
01366 
01367   // Can't generate a log message yet, do that right after Diags is
01368   // setup.
01369 
01370   // This call is required for win_9xMe
01371   //without this this_ethread() is failing when
01372   //start_HttpProxyServer is called from main thread
01373   Thread *main_thread = new EThread;
01374   main_thread->set_specific();
01375 
01376   // Re-initialize diagsConfig based on records.config configuration
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"); // Can do this now, logging is up.
01390 # endif
01391 
01392   // Check if we should do mlockall()
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   // Check for core file
01406   if (core_file[0] != '\0') {
01407     process_core(core_file);
01408     _exit(0);
01409   }
01410 
01411   // We need to do this early so we can initialize the Machine
01412   // singleton, which depends on configuration values loaded in this.
01413   // We want to initialize Machine as early as possible because it
01414   // has other dependencies. Hopefully not in init_HttpProxyServer().
01415   HttpConfig::startup();
01416   /* Set up the machine with the outbound address if that's set,
01417      or the inbound address if set, otherwise let it default.
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   // pmgmt->start() must occur after initialization of Diags but
01432   // before calling RecProcessInit()
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   // Sanity checks
01440   check_fd_limit();
01441   command_flag = command_flag || *command_string;
01442 
01443   // Set up store
01444   if (!command_flag && initialize_store())
01445     ProcessFatal("unable to initialize storage, (Re)Configuration required\n");
01446 
01447   // Alter the frequecies at which the update threads will trigger
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   // Initialize the stat pages manager
01461   statPagesManager.init();
01462 
01463   //////////////////////////////////////////////////////////////////////
01464   // Determine if Cache Clustering is enabled, since the transaction
01465   // on a thread changes require special consideration to allow
01466   // minimial Cache Clustering functionality.
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   // Initialize New Stat system
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   // This has some special semantics, in that providing this configuration on
01486   // command line has higher priority than what is set in records.config.
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   // This shouldn't happen, but lets make sure we run somewhat reasonable.
01494   if (net_config_poll_timeout < 0) {
01495     net_config_poll_timeout = 10; // Default value for all platform.
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   // log initialization moved down
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);               // everything is OK
01526       else
01527         _exit(1);               // in error
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(); // must be before HttpProxyPort init.
01543 # endif
01544     // Load HTTP port data. getNumSSLThreads depends on this.
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     // initialize logging (after event and net processor)
01562     Log::init(remote_management_flag ? 0 : Log::NO_REMOTE_MANAGEMENT);
01563 
01564     // Init plugins as soon as logging is ready.
01565     plugin_init();        // plugin.config
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     // UDP net-threads are turned off by default.
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     //acc.init();
01581     //if (auto_clear_authdb_flag)
01582      // acc.clear_cache();
01583     //acc.start();
01584     // pmgmt initialization moved up, needed by RecProcessInit
01585     //pmgmt->start();
01586     start_stats_snap();
01587 
01588     // Initialize Response Body Factory
01589     body_factory = new HttpBodyFactory;
01590 
01591     // Start IP to userName cache processor used
01592     // by RADIUS and FW1 plug-ins.
01593     //ipToUserNameCacheProcessor.start();
01594 
01595     // Initialize the system for SIMPLE support
01596     //  Simple::init();
01597 
01598     // Initialize the system for RAFT support
01599     // All this is handled by plugin support code
01600     //   Raft::init();
01601 
01602     // Continuation Statistics Dump
01603     if (show_statistics)
01604       eventProcessor.schedule_every(new ShowStats(), HRTIME_SECONDS(show_statistics), ET_CALL);
01605 
01606 
01607     //////////////////////////////////////
01608     // main server logic initiated here //
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       // call the ready hooks before we start accepting connections.
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       // Delay only if config value set and flag value is zero
01633       // (-1 => cache already initialized)
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(); // PORTS_READY_HOOK called from in here
01638       }
01639       if (icp_enabled)
01640         icpProcessor.start();
01641     }
01642 
01643     // "Task" processor, possibly with its own set of task threads
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); // One accept thread is enough
01650 
01651     if (netProcessor.socks_conf_stuff->accept_enabled) {
01652       start_SocksProxy(netProcessor.socks_conf_stuff->accept_port);
01653     }
01654 
01655     ///////////////////////////////////////////
01656     // Initialize Scheduled Update subsystem
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     // Callback for various storage commands. These all go to the same function so we
01664     // pass the event code along so it can do the right thing. We cast that to <int> first
01665     // just to be safe because the value is a #define, not a typed value.
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     // The main thread also becomes a net thread.
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     //  run_SimpleHttp();
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 // Unit Regresion Test Hook //
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 /* data_len ATS_UNUSED */)
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   // data is the device name to control
01719   CacheDisk* d = cacheProcessor.find_by_path(arg, len);
01720   // Actual command is in @a data.
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 }

Generated by  doxygen 1.7.1