/*
* $Id$
*
- * DEBUG: section 3 Configuration File Parsing
+ * DEBUG: section 03 Configuration File Parsing
* AUTHOR: Harvest Derived
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
#endif
#include "auth/Config.h"
#include "auth/Scheme.h"
-#include "CacheManager.h"
#include "ConfigParser.h"
+#include "CpuAffinityMap.h"
#include "eui/Config.h"
#if USE_SQUID_ESI
#include "esi/Parser.h"
#endif
#include "HttpRequestMethod.h"
#include "ident/Config.h"
-#include "ip/IpIntercept.h"
+#include "ip/Intercept.h"
#include "ip/QosConfig.h"
+#include "ip/tools.h"
#include "log/Config.h"
#include "MemBuf.h"
+#include "mgr/Registration.h"
#include "Parsing.h"
#include "ProtoPort.h"
#include "rfc1738.h"
#include "StoreFileSystem.h"
#include "SwapDir.h"
#include "wordlist.h"
+#include "ipc/Kids.h"
#if HAVE_GLOB_H
#include <glob.h>
#endif
+#if HAVE_LIMITS_H
+#include <limits>
+#endif
+
#if USE_ADAPTATION
static void parse_adaptation_service_set_type();
static void parse_adaptation_service_chain_type();
static void default_all(void);
static void defaults_if_none(void);
static int parse_line(char *);
+static void parse_obsolete(const char *);
static void parseBytesLine(size_t * bptr, const char *units);
+#if !USE_DNSSERVERS
+static void parseBytesLineSigned(ssize_t * bptr, const char *units);
+#endif
static size_t parseBytesUnits(const char *unit);
static void free_all(void);
void requirePathnameExists(const char *name, const char *path);
static OBJH dump_config;
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
static void parse_http_header_access(header_mangler header[]);
static void free_http_header_access(header_mangler header[]);
static void parse_b_size_t(size_t * var);
static void parse_b_int64_t(int64_t * var);
+static bool parseNamedIntList(const char *data, const String &name, Vector<int> &list);
+
+static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
+static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
+static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
+
static int parseOneConfigFile(const char *file_name, unsigned int depth);
/*
return error_count;
}
+static void
+ReplaceSubstr(char*& str, int& len, unsigned substrIdx, unsigned substrLen, const char* newSubstr)
+{
+ assert(str != NULL);
+ assert(newSubstr != NULL);
+
+ unsigned newSubstrLen = strlen(newSubstr);
+ if (newSubstrLen > substrLen)
+ str = (char*)realloc(str, len - substrLen + newSubstrLen + 1);
+
+ // move tail part including zero
+ memmove(str + substrIdx + newSubstrLen, str + substrIdx + substrLen, len - substrIdx - substrLen + 1);
+ // copy new substring in place
+ memcpy(str + substrIdx, newSubstr, newSubstrLen);
+
+ len = strlen(str);
+}
+
+static void
+SubstituteMacro(char*& line, int& len, const char* macroName, const char* substStr)
+{
+ assert(line != NULL);
+ assert(macroName != NULL);
+ assert(substStr != NULL);
+ unsigned macroNameLen = strlen(macroName);
+ while (const char* macroPos = strstr(line, macroName)) // we would replace all occurrences
+ ReplaceSubstr(line, len, macroPos - line, macroNameLen, substStr);
+}
+
+static void
+ProcessMacros(char*& line, int& len)
+{
+ SubstituteMacro(line, len, "${process_name}", TheKidName);
+ SubstituteMacro(line, len, "${process_number}", xitoa(KidIdentifier));
+}
+
+static void
+trim_trailing_ws(char* str)
+{
+ assert(str != NULL);
+ unsigned i = strlen(str);
+ while ((i > 0) && xisspace(str[i - 1]))
+ --i;
+ str[i] = '\0';
+}
+
+static const char*
+FindStatement(const char* line, const char* statement)
+{
+ assert(line != NULL);
+ assert(statement != NULL);
+
+ const char* str = skip_ws(line);
+ unsigned len = strlen(statement);
+ if (strncmp(str, statement, len) == 0) {
+ str += len;
+ if (*str == '\0')
+ return str;
+ else if (xisspace(*str))
+ return skip_ws(str);
+ }
+
+ return NULL;
+}
+
+static bool
+StrToInt(const char* str, long& number)
+{
+ assert(str != NULL);
+
+ char* end;
+ number = strtol(str, &end, 0);
+
+ return (end != str) && (*end == '\0'); // returns true if string contains nothing except number
+}
+
+static bool
+EvalBoolExpr(const char* expr)
+{
+ assert(expr != NULL);
+ if (strcmp(expr, "true") == 0) {
+ return true;
+ } else if (strcmp(expr, "false") == 0) {
+ return false;
+ } else if (const char* equation = strchr(expr, '=')) {
+ const char* rvalue = skip_ws(equation + 1);
+ char* lvalue = (char*)xmalloc(equation - expr + 1);
+ xstrncpy(lvalue, expr, equation - expr + 1);
+ trim_trailing_ws(lvalue);
+
+ long number1;
+ if (!StrToInt(lvalue, number1))
+ fatalf("String is not a integer number: '%s'\n", lvalue);
+ long number2;
+ if (!StrToInt(rvalue, number2))
+ fatalf("String is not a integer number: '%s'\n", rvalue);
+
+ xfree(lvalue);
+ return number1 == number2;
+ }
+ fatalf("Unable to evaluate expression '%s'\n", expr);
+ return false; // this place cannot be reached
+}
+
static int
parseOneConfigFile(const char *file_name, unsigned int depth)
{
config_lineno = 0;
+ Vector<bool> if_states;
while (fgets(config_input_line, BUFSIZ, fp)) {
config_lineno++;
continue;
}
+ trim_trailing_ws(tmp_line);
+ ProcessMacros(tmp_line, tmp_line_len);
debugs(3, 5, "Processing: '" << tmp_line << "'");
- /* Handle includes here */
- if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
- err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
- } else if (!parse_line(tmp_line)) {
- debugs(3, 0, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
- err_count++;
+ if (const char* expr = FindStatement(tmp_line, "if")) {
+ if_states.push_back(EvalBoolExpr(expr)); // store last if-statement meaning
+ } else if (FindStatement(tmp_line, "endif")) {
+ if (!if_states.empty())
+ if_states.pop_back(); // remove last if-statement meaning
+ else
+ fatalf("'endif' without 'if'\n");
+ } else if (FindStatement(tmp_line, "else")) {
+ if (!if_states.empty())
+ if_states.back() = !if_states.back();
+ else
+ fatalf("'else' without 'if'\n");
+ } else if (if_states.empty() || if_states.back()) { // test last if-statement meaning if present
+ /* Handle includes here */
+ if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
+ err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
+ } else if (!parse_line(tmp_line)) {
+ debugs(3, 0, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
+ err_count++;
+ }
}
safe_free(tmp_line);
tmp_line_len = 0;
}
+ if (!if_states.empty())
+ fatalf("if-statement without 'endif'\n");
if (is_pipe) {
int ret = pclose(fp);
parseConfigFile(const char *file_name)
{
int err_count = 0;
- CacheManager *manager=CacheManager::GetInstance();
debugs(5, 4, HERE);
}
if (opt_send_signal == -1) {
- manager->registerAction("config",
- "Current Squid Configuration",
- dump_config,
- 1, 1);
+ Mgr::RegisterAction("config",
+ "Current Squid Configuration",
+ dump_config,
+ 1, 1);
}
return err_count;
else
Config.appendDomainLen = 0;
- if (Config.retry.maxtries > 10)
- fatal("maximum_single_addr_tries cannot be larger than 10");
-
- if (Config.retry.maxtries < 1) {
- debugs(3, 0, "WARNING: resetting 'maximum_single_addr_tries to 1");
- Config.retry.maxtries = 1;
+ if (Config.connect_retries > 10) {
+ debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10.");
+ Config.connect_retries = 10;
}
requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
if (Config.errorDirectory)
requirePathnameExists("Error Directory", Config.errorDirectory);
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
{
const refresh_t *R;
}
#endif
-#if !HTTP_VIOLATIONS
+#if !USE_HTTP_VIOLATIONS
Config.onoff.via = 1;
#else
#endif
}
+/** Parse a line containing an obsolete directive.
+ * To upgrade it where possible instead of just "Bungled config" for
+ * directives which cannot be marked as simply aliases of the some name.
+ * For example if the parameter order and content has changed.
+ * Or if the directive has been completely removed.
+ */
+void
+parse_obsolete(const char *name)
+{
+ // Directives which have been radically changed rather than removed
+ if (!strcmp(name, "url_rewrite_concurrency")) {
+ int cval;
+ parse_int(&cval);
+ debugs(3, DBG_CRITICAL, "WARNING: url_rewrite_concurrency upgrade overriding url_rewrite_children settings.");
+ Config.redirectChildren.concurrency = cval;
+ }
+}
+
/* Parse a time specification from the config file. Store the
* result in 'tptr', after converting it to 'units' */
static void
self_destruct();
}
+#if !USE_DNSSERVERS
+static void
+parseBytesLineSigned(ssize_t * bptr, const char *units)
+{
+ char *token;
+ double d;
+ int m;
+ int u;
+
+ if ((u = parseBytesUnits(units)) == 0) {
+ self_destruct();
+ return;
+ }
+
+ if ((token = strtok(NULL, w_space)) == NULL) {
+ self_destruct();
+ return;
+ }
+
+ if (strcmp(token, "none") == 0 || token[0] == '-' /* -N */) {
+ *bptr = -1;
+ return;
+ }
+
+ d = xatof(token);
+
+ m = u; /* default to 'units' if none specified */
+
+ if (0.0 == d)
+ (void) 0;
+ else if ((token = strtok(NULL, w_space)) == NULL)
+ debugs(3, 0, "WARNING: No units on '" <<
+ config_input_line << "', assuming " <<
+ d << " " << units );
+ else if ((m = parseBytesUnits(token)) == 0) {
+ self_destruct();
+ return;
+ }
+
+ *bptr = static_cast<size_t>(m * d / u);
+
+ if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+ self_destruct();
+}
+#endif
+
static size_t
parseBytesUnits(const char *unit)
{
aclDestroyAcls(ae);
}
-static void
+void
dump_acl_list(StoreEntry * entry, ACLList * head)
{
ACLList *l;
{
acl_tos *l;
acl_tos **tail = head; /* sane name below */
- int tos;
- char junk;
+ unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */
char *token = strtok(NULL, w_space);
if (!token) {
return;
}
- if (sscanf(token, "0x%x%c", &tos, &junk) != 1) {
- self_destruct();
- return;
- }
-
- if (tos < 0 || tos > 255) {
+ if (!xstrtoui(token, NULL, &tos, 0, std::numeric_limits<tos_t>::max())) {
self_destruct();
return;
}
l = cbdataAlloc(acl_tos);
- l->tos = tos;
+ l->tos = (tos_t)tos;
aclParseAclList(LegacyParser, &l->aclList);
}
}
+#if defined(SO_MARK)
+
+CBDATA_TYPE(acl_nfmark);
+
+static void
+dump_acl_nfmark(StoreEntry * entry, const char *name, acl_nfmark * head)
+{
+ acl_nfmark *l;
+
+ for (l = head; l; l = l->next) {
+ if (l->nfmark > 0)
+ storeAppendPrintf(entry, "%s 0x%02X", name, l->nfmark);
+ else
+ storeAppendPrintf(entry, "%s none", name);
+
+ dump_acl_list(entry, l->aclList);
+
+ storeAppendPrintf(entry, "\n");
+ }
+}
+
+static void
+freed_acl_nfmark(void *data)
+{
+ acl_nfmark *l = static_cast<acl_nfmark *>(data);
+ aclDestroyAclList(&l->aclList);
+}
+
+static void
+parse_acl_nfmark(acl_nfmark ** head)
+{
+ acl_nfmark *l;
+ acl_nfmark **tail = head; /* sane name below */
+ nfmark_t mark;
+ char *token = strtok(NULL, w_space);
+
+ if (!token) {
+ self_destruct();
+ return;
+ }
+
+ if (!xstrtoui(token, NULL, &mark, 0, std::numeric_limits<nfmark_t>::max())) {
+ self_destruct();
+ return;
+ }
+
+ CBDATA_INIT_TYPE_FREECB(acl_nfmark, freed_acl_nfmark);
+
+ l = cbdataAlloc(acl_nfmark);
+
+ l->nfmark = mark;
+
+ aclParseAclList(LegacyParser, &l->aclList);
+
+ while (*tail)
+ tail = &(*tail)->next;
+
+ *tail = l;
+}
+
+static void
+free_acl_nfmark(acl_nfmark ** head)
+{
+ while (*head) {
+ acl_nfmark *l = *head;
+ *head = l->next;
+ l->next = NULL;
+ cbdataFree(l);
+ }
+}
+#endif /* SO_MARK */
+
CBDATA_TYPE(acl_size_t);
static void
#endif
-#if HTTP_VIOLATIONS
+#if DELAY_POOLS
+#include "ClientDelayConfig.h"
+/* do nothing - free_client_delay_pool_count is the magic free function.
+ * this is why client_delay_pool_count isn't just marked TYPE: ushort
+ */
+
+#define free_client_delay_pool_access(X)
+#define free_client_delay_pool_rates(X)
+#define dump_client_delay_pool_access(X, Y, Z)
+#define dump_client_delay_pool_rates(X, Y, Z)
+
+static void
+free_client_delay_pool_count(ClientDelayConfig * cfg)
+{
+ cfg->freePoolCount();
+}
+
+static void
+dump_client_delay_pool_count(StoreEntry * entry, const char *name, ClientDelayConfig &cfg)
+{
+ cfg.dumpPoolCount (entry, name);
+}
+
+static void
+parse_client_delay_pool_count(ClientDelayConfig * cfg)
+{
+ cfg->parsePoolCount();
+}
+
+static void
+parse_client_delay_pool_rates(ClientDelayConfig * cfg)
+{
+ cfg->parsePoolRates();
+}
+
+static void
+parse_client_delay_pool_access(ClientDelayConfig * cfg)
+{
+ cfg->parsePoolAccess(LegacyParser);
+}
+#endif
+
+#if USE_HTTP_VIOLATIONS
static void
dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
{
}
/* on reconfigure initialize new auth schemes for the new config. */
- if(reconfiguring) {
+ if (reconfiguring) {
InitAuthSchemes();
}
}
static void
parse_cachedir(SquidConfig::_cacheSwap * swap)
{
+ // The workers option must preceed cache_dir for the IamWorkerProcess check
+ // below to work. TODO: Redo IamWorkerProcess to work w/o Config and remove
+ if (KidIdentifier > 1 && Config.workers == 1) {
+ debugs(3, DBG_CRITICAL,
+ "FATAL: cache_dir found before the workers option. Reorder.");
+ self_destruct();
+ }
+
+ // Among all processes, only workers may need and can handle cache_dir.
+ if (!IamWorkerProcess())
+ return;
+
char *type_str;
char *path_str;
RefCount<SwapDir> sd;
} else if (!strcasecmp(token, "weighted-round-robin")) {
p->options.weighted_roundrobin = 1;
#if USE_HTCP
-
} else if (!strcasecmp(token, "htcp")) {
p->options.htcp = 1;
- } else if (!strcasecmp(token, "htcp-oldsquid")) {
+ } else if (!strncasecmp(token, "htcp=", 5) || !strncasecmp(token, "htcp-", 5)) {
+ /* Note: The htcp- form is deprecated, replaced by htcp= */
p->options.htcp = 1;
- p->options.htcp_oldsquid = 1;
- } else if (!strcasecmp(token, "htcp-no-clr")) {
- if (p->options.htcp_only_clr)
- fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
- p->options.htcp = 1;
- p->options.htcp_no_clr = 1;
- } else if (!strcasecmp(token, "htcp-no-purge-clr")) {
- p->options.htcp = 1;
- p->options.htcp_no_purge_clr = 1;
- } else if (!strcasecmp(token, "htcp-only-clr")) {
- if (p->options.htcp_no_clr)
- fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
- p->options.htcp = 1;
- p->options.htcp_only_clr = 1;
- } else if (!strcasecmp(token, "htcp-forward-clr")) {
- p->options.htcp = 1;
- p->options.htcp_forward_clr = 1;
+ char *tmp = xstrdup(token+5);
+ char *mode, *nextmode;
+ for (mode = nextmode = tmp; mode; mode = nextmode) {
+ nextmode = strchr(mode, ',');
+ if (nextmode)
+ *nextmode++ = '\0';
+ if (!strcasecmp(mode, "no-clr")) {
+ if (p->options.htcp_only_clr)
+ fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
+ p->options.htcp_no_clr = 1;
+ } else if (!strcasecmp(mode, "no-purge-clr")) {
+ p->options.htcp_no_purge_clr = 1;
+ } else if (!strcasecmp(mode, "only-clr")) {
+ if (p->options.htcp_no_clr)
+ fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
+ p->options.htcp_only_clr = 1;
+ } else if (!strcasecmp(mode, "forward-clr")) {
+ p->options.htcp_forward_clr = 1;
+ } else if (!strcasecmp(mode, "oldsquid")) {
+ p->options.htcp_oldsquid = 1;
+ } else {
+ fatalf("invalid HTCP mode '%s'", mode);
+ }
+ }
+ safe_free(tmp);
#endif
-
} else if (!strcasecmp(token, "no-netdb-exchange")) {
p->options.no_netdb_exchange = 1;
p->icp.version = ICP_VERSION_CURRENT;
- p->test_fd = -1;
+ p->testing_now = false;
#if USE_CACHE_DIGESTS
dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
{
while (head != NULL) {
- storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
+ storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
name,
head->flags.icase ? " -i" : null_string,
head->pattern,
if (head->flags.refresh_ims)
storeAppendPrintf(entry, " refresh-ims");
-#if HTTP_VIOLATIONS
+ if (head->flags.store_stale)
+ storeAppendPrintf(entry, " store-stale");
+
+#if USE_HTTP_VIOLATIONS
if (head->flags.override_expire)
storeAppendPrintf(entry, " override-expire");
double pct = 0.0;
time_t max = 0;
int refresh_ims = 0;
-#if HTTP_VIOLATIONS
+ int store_stale = 0;
+
+#if USE_HTTP_VIOLATIONS
int override_expire = 0;
int override_lastmod = 0;
i = GetInteger(); /* token: min */
+ /* catch negative and insanely huge values close to 32-bit wrap */
+ if (i < 0) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
+ i = 0;
+ }
+ if (i > 60*24*365) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age too high. Cropped back to 1 year.");
+ i = 60*24*365;
+ }
+
min = (time_t) (i * 60); /* convert minutes to seconds */
i = GetInteger(); /* token: pct */
i = GetInteger(); /* token: max */
+ /* catch negative and insanely huge values close to 32-bit wrap */
+ if (i < 0) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age negative. Cropped back to zero.");
+ i = 0;
+ }
+ if (i > 60*24*365) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age too high. Cropped back to 1 year.");
+ i = 60*24*365;
+ }
+
max = (time_t) (i * 60); /* convert minutes to seconds */
/* Options */
while ((token = strtok(NULL, w_space)) != NULL) {
if (!strcmp(token, "refresh-ims")) {
refresh_ims = 1;
-#if HTTP_VIOLATIONS
+ } else if (!strcmp(token, "store-stale")) {
+ store_stale = 1;
+#if USE_HTTP_VIOLATIONS
} else if (!strcmp(token, "override-expire"))
override_expire = 1;
if (refresh_ims)
t->flags.refresh_ims = 1;
-#if HTTP_VIOLATIONS
+ if (store_stale)
+ t->flags.store_stale = 1;
+
+#if USE_HTTP_VIOLATIONS
if (override_expire)
t->flags.override_expire = 1;
safe_free(t);
}
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
refresh_nocache_hack = 0;
#endif
storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
}
+#if !USE_DNSSERVERS
+static void
+dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
+{
+ storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
+}
+#endif
+
#if UNUSED_CODE
static void
dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
parseBytesLine(var, B_BYTES_STR);
}
+#if !USE_DNSSERVERS
+static void
+parse_b_ssize_t(ssize_t * var)
+{
+ parseBytesLineSigned(var, B_BYTES_STR);
+}
+#endif
+
#if UNUSED_CODE
static void
parse_kb_size_t(size_t * var)
*var = 0;
}
+#if !USE_DNSSERVERS
+static void
+free_ssize_t(ssize_t * var)
+{
+ *var = 0;
+}
+#endif
+
static void
free_b_int64_t(int64_t * var)
{
}
#define free_b_size_t free_size_t
+#define free_b_ssize_t free_ssize_t
#define free_kb_size_t free_size_t
#define free_mb_size_t free_size_t
#define free_gb_size_t free_size_t
storeAppendPrintf(entry, "\n");
}
-#include "cf_parser.h"
+#include "cf_parser.cci"
peer_t
parseNeighborType(const char *s)
s->name = xstrdup(token);
s->connection_auth_disabled = false;
-#if USE_IPV6
if (*token == '[') {
/* [ipv6]:port */
host = token + 1;
debugs(3, 0, "http(s)_port: missing Port in: " << token);
self_destruct();
}
- port = xatos(t + 1);
- } else
-#endif
- if ((t = strchr(token, ':'))) {
- /* host:port */
- /* ipv4:port */
- host = token;
- *t = '\0';
- port = xatos(t + 1);
-
- } else if ((port = strtol(token, &junk, 10)), !*junk) {
- /* port */
- debugs(3, 3, "http(s)_port: found Listen on Port: " << port);
- } else {
- debugs(3, 0, "http(s)_port: missing Port: " << token);
+ if (!Ip::EnableIpv6) {
+ debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 is not available.");
self_destruct();
}
+ port = xatos(t + 1);
+ } else if ((t = strchr(token, ':'))) {
+ /* host:port */
+ /* ipv4:port */
+ host = token;
+ *t = '\0';
+ port = xatos(t + 1);
+
+ } else if ((port = strtol(token, &junk, 10)), !*junk) {
+ /* port */
+ debugs(3, 3, "http(s)_port: found Listen on Port: " << port);
+ } else {
+ debugs(3, 0, "http(s)_port: missing Port: " << token);
+ self_destruct();
+ }
if (port == 0) {
debugs(3, 0, "http(s)_port: Port cannot be 0: " << token);
if (NULL == host) {
s->s.SetAnyAddr();
s->s.SetPort(port);
+ if (!Ip::EnableIpv6)
+ s->s.SetIPv4();
debugs(3, 3, "http(s)_port: found Listen on wildcard address: *:" << s->s.GetPort() );
} else if ( s->s = host ) { /* check/parse numeric IPA */
s->s.SetPort(port);
+ if (!Ip::EnableIpv6)
+ s->s.SetIPv4();
debugs(3, 3, "http(s)_port: Listen on Host/IP: " << host << " --> " << s->s);
} else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */
/* dont use ipcache */
s->defaultsite = xstrdup(host);
s->s.SetPort(port);
+ if (!Ip::EnableIpv6)
+ s->s.SetIPv4();
debugs(3, 3, "http(s)_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
} else {
debugs(3, 0, "http(s)_port: failed to resolve Host/IP: " << host);
debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s);
debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)");
-#if USE_IPV6
/* INET6: until transparent REDIRECT works on IPv6 SOCKET, force wildcard to IPv4 */
- debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
+ if (Ip::EnableIpv6)
+ debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
if ( !s->s.SetIPv4() ) {
debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be transparent (protocol does not provide NAT)" << s->s );
self_destruct();
}
-#endif
} else if (strcmp(token, "tproxy") == 0) {
if (s->intercepted || s->accel) {
debugs(3,DBG_CRITICAL, "FATAL: http(s)_port: TPROXY option requires its own interception port. It cannot be shared with other modes.");
}
s->allow_direct = 1;
} else if (strcmp(token, "ignore-cc") == 0) {
-#if !HTTP_VIOLATIONS
+#if !USE_HTTP_VIOLATIONS
if (!s->accel) {
debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: ignore-cc option requires Scceleration mode flag.");
self_destruct();
else
self_destruct();
} else if (strcmp(token, "ipv4") == 0) {
-#if USE_IPV6
if ( !s->s.SetIPv4() ) {
- debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be used a IPv4-Only." << s->s );
+ debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be used as IPv4-Only. " << s->s );
self_destruct();
}
-#endif
} else if (strcmp(token, "tcpkeepalive") == 0) {
s->tcp_keepalive.enabled = 1;
} else if (strncmp(token, "tcpkeepalive=", 13) == 0) {
t = strchr(t, ',');
}
#if USE_SSL
- } else if (strcmp(token, "sslBump") == 0) {
+ } else if (strcasecmp(token, "sslBump") == 0) {
+ debugs(3, DBG_CRITICAL, "WARNING: '" << token << "' is deprecated " <<
+ "in http_port. Use 'ssl-bump' instead.");
+ s->sslBump = 1; // accelerated when bumped, otherwise not
+ } else if (strcmp(token, "ssl-bump") == 0) {
s->sslBump = 1; // accelerated when bumped, otherwise not
} else if (strncmp(token, "cert=", 5) == 0) {
safe_free(s->cert);
Config.Sockaddr.http = s;
}
-#if IPV6_SPECIAL_SPLITSTACK
http_port_list *
clone_http_port_list(http_port_list *a)
{
return b;
}
-#endif
static void
parse_http_port_list(http_port_list ** head)
parse_http_port_option(s, token);
}
-#if IPV6_SPECIAL_SPLITSTACK
- if (s->s.IsAnyAddr()) {
+ if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.IsAnyAddr()) {
// clone the port options from *s to *(s->next)
s->next = clone_http_port_list(s);
s->next->s.SetIPv4();
debugs(3, 3, "http(s)_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
}
-#endif
while (*head)
head = &(*head)->next;
}
}
+/// parses list of integers form name=N1,N2,N3,...
+static bool
+parseNamedIntList(const char *data, const String &name, Vector<int> &list)
+{
+ if (data && (strncmp(data, name.rawBuf(), name.size()) == 0)) {
+ data += name.size();
+ if (*data == '=') {
+ while (true) {
+ ++data;
+ int value = 0;
+ if (!StringToInt(data, value, &data, 10))
+ break;
+ list.push_back(value);
+ if (*data == '\0' || *data != ',')
+ break;
+ }
+ }
+ }
+ return data && *data == '\0';
+}
+
+static void
+parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
+{
+#if !HAVE_CPU_AFFINITY
+ debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
+ "support, do not set 'cpu_affinity_map'");
+ self_destruct();
+#endif /* HAVE_CPU_AFFINITY */
+
+ if (!*cpuAffinityMap)
+ *cpuAffinityMap = new CpuAffinityMap;
+
+ const char *const pToken = strtok(NULL, w_space);
+ const char *const cToken = strtok(NULL, w_space);
+ Vector<int> processes, cores;
+ if (!parseNamedIntList(pToken, "process_numbers", processes)) {
+ debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
+ "in 'cpu_affinity_map'");
+ self_destruct();
+ } else if (!parseNamedIntList(cToken, "cores", cores)) {
+ debugs(3, DBG_CRITICAL, "FATAL: bad 'cores' parameter in " <<
+ "'cpu_affinity_map'");
+ self_destruct();
+ } else if (!(*cpuAffinityMap)->add(processes, cores)) {
+ debugs(3, DBG_CRITICAL, "FATAL: bad 'cpu_affinity_map'; " <<
+ "process_numbers and cores lists differ in length or " <<
+ "contain numbers <= 0");
+ self_destruct();
+ }
+}
+
+static void
+dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap)
+{
+ if (cpuAffinityMap) {
+ storeAppendPrintf(entry, "%s process_numbers=", name);
+ for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
+ storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
+ cpuAffinityMap->processes()[i]);
+ }
+ storeAppendPrintf(entry, " cores=");
+ for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
+ storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
+ cpuAffinityMap->cores()[i]);
+ }
+ storeAppendPrintf(entry, "\n");
+ }
+}
+
+static void
+free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
+{
+ delete *cpuAffinityMap;
+ *cpuAffinityMap = NULL;
+}
+
#if USE_ADAPTATION
static void