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 }