You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by da...@apache.org on 2017/01/17 04:16:36 UTC
[3/4] incubator-trafficcontrol git commit: Removed ATS patch.
Removed ATS patch.
Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/fdf9f7d2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/fdf9f7d2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/fdf9f7d2
Branch: refs/heads/master
Commit: fdf9f7d2b969153f17ba81b273b04655e1727e6d
Parents: ff5712e
Author: Chris Lemmons <Ch...@comcast.com>
Authored: Fri Jan 13 13:56:41 2017 -0700
Committer: Dan Kirkwood <da...@gmail.com>
Committed: Tue Jan 17 04:13:26 2017 +0000
----------------------------------------------------------------------
.../patches/trafficserver-5.3.2-ee14bbe.diff | 673 -------------------
1 file changed, 673 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/fdf9f7d2/traffic_server/patches/trafficserver-5.3.2-ee14bbe.diff
----------------------------------------------------------------------
diff --git a/traffic_server/patches/trafficserver-5.3.2-ee14bbe.diff b/traffic_server/patches/trafficserver-5.3.2-ee14bbe.diff
deleted file mode 100644
index e28e787..0000000
--- a/traffic_server/patches/trafficserver-5.3.2-ee14bbe.diff
+++ /dev/null
@@ -1,673 +0,0 @@
-diff --git a/configure.ac b/configure.ac
-index 2c79ca4..a46a43e 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1960,6 +1960,7 @@ AS_IF([test "x$enable_experimental_plugins" = xyes], [
- plugins/experimental/hipes/Makefile
- plugins/experimental/metalink/Makefile
- plugins/experimental/mysql_remap/Makefile
-+ plugins/experimental/money_trace/Makefile
- plugins/experimental/regex_revalidate/Makefile
- plugins/experimental/remap_stats/Makefile
- plugins/experimental/s3_auth/Makefile
-diff --git a/iocore/aio/AIO.cc b/iocore/aio/AIO.cc
-index 4dd1842..5c4b217 100644
---- a/iocore/aio/AIO.cc
-+++ b/iocore/aio/AIO.cc
-@@ -187,6 +187,10 @@ struct AIOThreadInfo : public Continuation {
- {
- (void)event;
- (void)e;
-+#if TS_USE_HWLOC
-+ hwloc_set_membind_nodeset(ink_get_topology(), hwloc_topology_get_topology_nodeset(ink_get_topology()), HWLOC_MEMBIND_INTERLEAVE,
-+ HWLOC_MEMBIND_THREAD);
-+#endif
- aio_thread_main(this);
- return EVENT_DONE;
- }
-diff --git a/iocore/hostdb/HostDB.cc b/iocore/hostdb/HostDB.cc
-index a7f5c55..8a21a70 100644
---- a/iocore/hostdb/HostDB.cc
-+++ b/iocore/hostdb/HostDB.cc
-@@ -1470,6 +1470,12 @@ HostDBContinuation::dnsEvent(int event, HostEnt *e)
- // @c lookup_done should always return a valid value so @a r should be null @c NULL.
- ink_assert(r && r->app.allotment.application1 == 0 && r->app.allotment.application2 == 0);
-
-+ // lookup_done() returned null due to full hostdb database.
-+ if (!r) {
-+ Debug("hostdb", "HostDBInfo pointer 'r' is NULL");
-+ failed = true;
-+ }
-+
- if (rr) {
- const int rrsize = HostDBRoundRobin::size(n, e->srv_hosts.srv_hosts_length);
- HostDBRoundRobin *rr_data = (HostDBRoundRobin *)hostDB.alloc(&r->app.rr.offset, rrsize);
-diff --git a/mgmt/api/TSControlMain.cc b/mgmt/api/TSControlMain.cc
-index a771ca3..a3e64a4 100644
---- a/mgmt/api/TSControlMain.cc
-+++ b/mgmt/api/TSControlMain.cc
-@@ -967,7 +967,7 @@ handle_stats_reset(int fd, void *req, size_t reqlen)
- MgmtMarshallInt err;
-
- err = recv_mgmt_request(req, reqlen, STATS_RESET_NODE, &optype, &name);
-- if (err != TS_ERR_OKAY) {
-+ if (err == TS_ERR_OKAY) {
- err = StatsReset(optype == STATS_RESET_CLUSTER, name);
- }
-
-diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am
-index adb6da8..8f5d48e 100644
---- a/plugins/experimental/Makefile.am
-+++ b/plugins/experimental/Makefile.am
-@@ -33,6 +33,7 @@ SUBDIRS = \
- healthchecks \
- hipes \
- metalink \
-+ money_trace \
- regex_revalidate \
- remap_stats \
- s3_auth \
-diff --git a/plugins/experimental/money_trace/money_trace.cc b/plugins/experimental/money_trace/money_trace.cc
-index adb8980..09f8cd4 100644
---- a/plugins/experimental/money_trace/money_trace.cc
-+++ b/plugins/experimental/money_trace/money_trace.cc
-@@ -71,7 +71,7 @@ freeTransactionData(struct txndata *txn_data)
-
- /**
- * The TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE event callback.
-- *
-+ *
- * If there is a cache hit only schedule a TS_HTTP_SEND_RESPONSE_HDR_HOOK
- * continuation to send back the money trace header in the response to the
- * client.
-@@ -79,7 +79,7 @@ freeTransactionData(struct txndata *txn_data)
- * If there is a cache miss, a new money trace header is created and a
- * TS_HTTP_SEND_REQUES_HDR_HOOK continuation is scheduled to add the
- * new money trace header to the parent request.
-- */
-+ */
- static void
- mt_cache_lookup_check(TSCont contp, TSHttpTxn txnp, struct txndata *txn_data)
- {
-@@ -157,10 +157,10 @@ mt_check_request_header(TSHttpTxn txnp)
-
- /**
- * The TS_EVENT_HTTP_SEND_RESPONSE_HDR callback.
-- *
-+ *
- * Adds the money trace header received in the client request to the
- * client response headers.
-- */
-+ */
- static void
- mt_send_client_response(TSHttpTxn txnp, struct txndata *txn_data)
- {
-diff --git a/plugins/experimental/url_sig/README b/plugins/experimental/url_sig/README
-index 81fdd33..e4c4ca2 100644
---- a/plugins/experimental/url_sig/README
-+++ b/plugins/experimental/url_sig/README
-@@ -84,15 +84,19 @@ Signing a URL using path parameters instead of using a query string.
- in the request url. Any origin application query parameters then follow
- the file part of the request and are never part of the sign string.
-
-- Path parameters are separated by a ';' in the path. The following is an
-- example signed request using the path parameter method and with an origin
-- application query string:
-+ Path parameters are separated by a ';' in the path. The complete signature
-+ string is base64 encoded as a single path parameter that is assinged to the
-+ 'siganchor', and will appear in that path as siganchor=base64string. The
-+ following is an example signed request using the path parameter method and
-+ with an origin application query string:
-
-- http://ds-01.comcast.net/vod/t;E=1454013671;A=1;K=3;P=1;S=686945c15e8c4e02146af86a9fd8ee29ff432b0a/Frag10Num10.ts?appid=2&t=1
-+ http://ds-01.comcast.net/vod/t;urlsig=O0U9MTQ2MzkyOTYxODtBPTE7Sz0zO1A9MTtTPTEyZDlmN2RiNjUyZWI0YmI4MWYyNmVlMjE3MzczZGE5Y2VkYTRmZGY/Frag10Num10.ts?appid=2&t=1
-
-- Note that the signing parameters are embedded in the path between the last directory part and before the file part of
-- the request. Using 'parts' in sign.pl, the signature may be signed accordingly up to S= in the above request. To
-- generate a signed url using this method, use the --pathparams option in sign.pl
-+ Note that the signing string is embedded in the path between the last
-+ directory part and before the file part of the request. Using 'parts' in
-+ sign.pl, the signature may be signed accordingly up to S= in the above
-+ request. To generate a signed url using this method, use the --pathparams
-+ option in sign.pl
-
-
-
-@@ -163,7 +167,8 @@ Example
- Authorization Denied$
- $
-
-- Sign the URL and try it again. Run the script with appropriate params, and it will output the curl line to run:
-+ Sign the URL and try it again. Run the script with appropriate params, and
-+ it will output the curl line to run:
-
- $ ./sign.pl --url http://test-remap.domain.com/ --useparts 1 --algorithm 1 --duration 60 --keyindex 3 --key DTV4Tcn046eM9BzJMeYrYpm3kbqOtBs7
- curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/?E=1397603088&A=1&K=3&P=1&S=28d822f68ac7265db61a8441e0877a98fe1007cc'
-@@ -205,7 +210,12 @@ Example
-
- Generating a signed URL with path parameters:
-
-- $ ./sign.pl --url "http://test-remap.domain.com/vod/t/prog_index.m3u8?appid=2&t=1" --useparts 1 --algorithm 1 --duration 86400 --keyindex 3 --key kSCE1_uBREdGI3TPnr_dXKc9f_J4ZV2f --pathparams
-+ $ ./sign.pl --url "http://test-remap.domain.com/vod/t/prog_index.m3u8?appid=2&t=1" --useparts 1 --algorithm 1 --duration 86400 --keyindex 3 --key kSCE1_uBREdGI3TPnr_dXKc9f_J4ZV2f --pathparams --siganchor urlsig
-
-- curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/vod/t;E=1454015105;A=1;K=3;P=1;S=/173f2ff3667371e666fa17be6c37bfdfe6e89eccprog_index.m3u8?appid=2&t=1'
-+ curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/vod/t;urlsig=O0U9MTQ2MzkyOTM4NTtBPTE7Sz0zO1A9MTtTPTIxYzk2YWRiZWZkOGJkMDFhYmM3MmZkMTEzMWVkMGM5ZmU1ZmFiMjE/prog_index.m3u8?appid=2&t=1'
-
-+
-+Client IP in the Signing Script
-+ Below is an example of how to include client ip in the signing script
-+ Works for both IPv4 and IPv6
-+ --client 10.10.10.10
-diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
-index baf381f..b2b522c 100644
---- a/plugins/experimental/url_sig/url_sig.c
-+++ b/plugins/experimental/url_sig/url_sig.c
-@@ -176,9 +176,9 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
- cfg->err_url = TSstrndup(value, strlen(value));
- else
- cfg->err_url = NULL;
-- } else if (strncmp(line, "sig_anchor", 10) == 0) {
-- cfg->sig_anchor = TSstrndup(value, strlen(value));
-- TSDebug(PLUGIN_NAME, "sig_anchor: %s", cfg->sig_anchor);
-+ } else if (strncmp(line, "sig_anchor", 10) == 0) {
-+ cfg->sig_anchor = TSstrndup(value, strlen(value));
-+ TSDebug(PLUGIN_NAME, "sig_anchor: %s", cfg->sig_anchor);
- } else if (strncmp(line, "excl_regex", 10) == 0) {
- // compile and study regex
- const char *errptr;
-@@ -317,7 +317,7 @@ urlParse(bool *https, char *anchor, char *url, char *new_path_seg, int new_path_
- segment[numtoks] = p;
- if (anchor != NULL && sig_anchor_seg == 0) {
- // look for the signed anchor string.
-- if ((sig_anchor = strcasestr(segment[numtoks],anchor)) != NULL) {
-+ if ((sig_anchor = strcasestr(segment[numtoks], anchor)) != NULL) {
- // null terminate this segment just before he signing anchor, this should be a ';'.
- *(sig_anchor - 1) = '\0';
- if ((sig_anchor = strstr(sig_anchor, "=")) != NULL) {
-@@ -343,7 +343,7 @@ urlParse(bool *https, char *anchor, char *url, char *new_path_seg, int new_path_
- for (i = 2; i < numtoks; i++) {
- // if no signing anchor is found, skip the signed parameters segment.
- if (sig_anchor == NULL && i == numtoks - 2) {
-- // the signing parameters when no signature anchor is found, should be in the
-+ // the signing parameters when no signature anchor is found, should be in the
- // last path segment so skip them.
- continue;
- }
-@@ -382,12 +382,12 @@ urlParse(bool *https, char *anchor, char *url, char *new_path_seg, int new_path_
- // to be in the last path segment.
- if (sig_anchor == NULL) {
- if (TSBase64Decode(segment[numtoks - 2], strlen(segment[numtoks - 2]), decoded_string, sizeof(decoded_string),
-- (size_t *)&decoded_len) != TS_SUCCESS) {
-+ (size_t *)&decoded_len) != TS_SUCCESS) {
- TSDebug(PLUGIN_NAME, "Unable to decode the path parameter string.");
- }
- } else {
-- if (TSBase64Decode(sig_anchor, strlen(sig_anchor), decoded_string, sizeof(decoded_string),
-- (size_t *)&decoded_len) != TS_SUCCESS) {
-+ if (TSBase64Decode(sig_anchor, strlen(sig_anchor), decoded_string, sizeof(decoded_string), (size_t *)&decoded_len) !=
-+ TS_SUCCESS) {
- TSDebug(PLUGIN_NAME, "Unable to decode the path parameter string.");
- }
- }
-@@ -412,7 +412,7 @@ urlParse(bool *https, char *anchor, char *url, char *new_path_seg, int new_path_
- continue;
- }
- strncat(new_url, segment[i], strlen(segment[i]));
-- if (i < numtoks - 1) {
-+ if (i < numtoks - 1) {
- strncat(new_url, "/", 1);
- }
- }
-@@ -518,52 +518,52 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
- p = strstr(query, CIP_QSTRING "=");
- if (p != NULL) {
- p += (strlen(CIP_QSTRING) + 1);
-- struct sockaddr const *ip = TSHttpTxnClientAddrGet(txnp);
-+ struct sockaddr const *ip = TSHttpTxnClientAddrGet(txnp);
- if (ip == NULL) {
- TSError("Can't get client ip address.");
- goto deny;
- } else {
- switch (ip->sa_family) {
-- case AF_INET:
-- TSDebug(PLUGIN_NAME, "ip->sa_family: AF_INET");
-- isClient_ipv6 = false;
-- has_path_params == false ? (pp = strstr(p, "&")) : (pp = strstr(p, ";"));
-- if ((pp - p) > INET_ADDRSTRLEN - 1 || (pp - p) < 4) {
-- err_log(url, "IP address string too long or short.");
-- goto deny;
-- }
-- strncpy(client_ipv4, p, (pp - p));
-- client_ipv4[pp - p] = '\0';
-- TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ipv4);
-- inet_ntop(AF_INET, &(((struct sockaddr_in *)ip)->sin_addr), ipstr_v4, sizeof ipstr_v4);
-- TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr_v4);
-- if (strcmp(ipstr_v4, client_ipv4) != 0) {
-- err_log(url, "Client IP doesn't match signature.");
-- goto deny;
-- }
-- break;
-- case AF_INET6:
-- TSDebug(PLUGIN_NAME, "ip->sa_family: AF_INET6");
-- isClient_ipv6 = true;
-- has_path_params == false ? (pp = strstr(p, "&")) : (pp = strstr(p, ";"));
-- if ((pp - p) > INET6_ADDRSTRLEN - 1 || (pp - p) < 4) {
-- err_log(url, "IP address string too long or short.");
-- goto deny;
-- }
-- strncpy(client_ipv6, p, (pp - p));
-- client_ipv6[pp - p] = '\0';
-- TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ipv6);
-- inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)ip)->sin6_addr), ipstr_v6, sizeof ipstr_v6);
-- TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr_v6);
-- if (strcmp(ipstr_v6, client_ipv6) != 0) {
-- err_log(url, "Client IP doesn't match signature.");
-- goto deny;
-- }
-- break;
-- default:
-- TSError("%s: Unknown address family %d", PLUGIN_NAME, ip->sa_family);
-+ case AF_INET:
-+ TSDebug(PLUGIN_NAME, "ip->sa_family: AF_INET");
-+ isClient_ipv6 = false;
-+ has_path_params == false ? (pp = strstr(p, "&")) : (pp = strstr(p, ";"));
-+ if ((pp - p) > INET_ADDRSTRLEN - 1 || (pp - p) < 4) {
-+ err_log(url, "IP address string too long or short.");
-+ goto deny;
-+ }
-+ strncpy(client_ipv4, p, (pp - p));
-+ client_ipv4[pp - p] = '\0';
-+ TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ipv4);
-+ inet_ntop(AF_INET, &(((struct sockaddr_in *)ip)->sin_addr), ipstr_v4, sizeof ipstr_v4);
-+ TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr_v4);
-+ if (strcmp(ipstr_v4, client_ipv4) != 0) {
-+ err_log(url, "Client IP doesn't match signature.");
- goto deny;
-- break;
-+ }
-+ break;
-+ case AF_INET6:
-+ TSDebug(PLUGIN_NAME, "ip->sa_family: AF_INET6");
-+ isClient_ipv6 = true;
-+ has_path_params == false ? (pp = strstr(p, "&")) : (pp = strstr(p, ";"));
-+ if ((pp - p) > INET6_ADDRSTRLEN - 1 || (pp - p) < 4) {
-+ err_log(url, "IP address string too long or short.");
-+ goto deny;
-+ }
-+ strncpy(client_ipv6, p, (pp - p));
-+ client_ipv6[pp - p] = '\0';
-+ TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ipv6);
-+ inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)ip)->sin6_addr), ipstr_v6, sizeof ipstr_v6);
-+ TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr_v6);
-+ if (strcmp(ipstr_v6, client_ipv6) != 0) {
-+ err_log(url, "Client IP doesn't match signature.");
-+ goto deny;
-+ }
-+ break;
-+ default:
-+ TSError("%s: Unknown address family %d", PLUGIN_NAME, ip->sa_family);
-+ goto deny;
-+ break;
- }
- }
- }
-@@ -639,7 +639,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
- keyindex, parts, signature);
- } else {
- TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%d A=%d K=%d P=%s S=%s", client_ipv4, (int)expiration, algorithm,
-- keyindex, parts, signature);
-+ keyindex, parts, signature);
- }
- /* find the string that was signed - cycle through the parts letters, adding the part of the fqdn/path if it is 1 */
- has_path_params == false ? (p = strstr(url, "?")) : (p = strstr(url, ";"));
-diff --git a/proxy/ParentConsistentHash.cc b/proxy/ParentConsistentHash.cc
-index 1171ab9..5775e52 100644
---- a/proxy/ParentConsistentHash.cc
-+++ b/proxy/ParentConsistentHash.cc
-@@ -153,7 +153,7 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
- // check to see if it is retryable.
- if (pRec && !pRec->available) {
- Debug("parent_select", "Parent.failedAt = %u, retry = %u, xact_start = %u", (unsigned int)pRec->failedAt,
-- (unsigned int)policy->ParentRetryTime, (unsigned int)request_info->xact_start);
-+ (unsigned int)policy->ParentRetryTime, (unsigned int)request_info->xact_start);
- if ((pRec->failedAt + policy->ParentRetryTime) < request_info->xact_start) {
- // make sure that the proper state is recorded in the result structure
- result->last_parent = pRec->idx;
-@@ -164,7 +164,8 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
- } else {
- result->r = PARENT_SPECIFIED;
- }
-- Debug("parent_select", "Down parent %s is now retryable, pRec: %p, result->retry: %d.", pRec->hostname, pRec, result->retry);
-+ Debug("parent_select", "Down parent %s is now retryable, pRec: %p, result->retry: %d.", pRec->hostname, pRec,
-+ result->retry);
- } else { // if not retryable find an available host on the primary ring.
- last_lookup = PRIMARY;
- fhash = chash[PRIMARY];
-@@ -206,10 +207,10 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
- if (now > last_unavailable) {
- int len = 0;
- char *request_str = url->string_get_ref(&len);
-- if(request_str) {
-- Note("No available parents for request: %*s.", len, request_str);
-+ if (request_str) {
-+ Note("No available parents for request: %*s.", len, request_str);
- }
-- ink_atomic_swap(&last_unavailable, now);
-+ ink_atomic_swap(&last_unavailable, now);
- }
- result->r = PARENT_FAIL;
- }
-diff --git a/proxy/ParentRoundRobin.cc b/proxy/ParentRoundRobin.cc
-index c387e8c..0295324 100644
---- a/proxy/ParentRoundRobin.cc
-+++ b/proxy/ParentRoundRobin.cc
-@@ -25,6 +25,7 @@
- ParentRoundRobin::ParentRoundRobin(ParentRecord *parent_record, ParentRR_t _round_robin_type)
- {
- round_robin_type = _round_robin_type;
-+ latched_parent = 0;
-
- if (is_debug_tag_set("parent_select")) {
- switch (round_robin_type) {
-@@ -37,6 +38,9 @@ ParentRoundRobin::ParentRoundRobin(ParentRecord *parent_record, ParentRR_t _roun
- case P_HASH_ROUND_ROBIN:
- Debug("parent_select", "Using a round robin parent selection strategy of type P_HASH_ROUND_ROBIN.");
- break;
-+ case P_LATCHED_ROUND_ROBIN:
-+ Debug("parent_select", "Using a round robin parent selection strategy of type P_LATCHED_ROUND_ROBIN.");
-+ break;
- default:
- // should never see this, there is a problem if you do.
- Debug("parent_select", "Using a round robin parent selection strategy of type UNKNOWN TYPE.");
-@@ -100,13 +104,16 @@ ParentRoundRobin::selectParent(const ParentSelectionPolicy *policy, bool first_c
- case P_NO_ROUND_ROBIN:
- cur_index = result->start_parent = 0;
- break;
-+ case P_LATCHED_ROUND_ROBIN:
-+ cur_index = latched_parent;
-+ break;
- default:
- ink_release_assert(0);
- }
- }
- } else {
- // Move to next parent due to failure
-- cur_index = (result->last_parent + 1) % result->rec->num_parents;
-+ latched_parent = cur_index = (result->last_parent + 1) % result->rec->num_parents;
-
- // Check to see if we have wrapped around
- if ((unsigned int)cur_index == result->start_parent) {
-@@ -169,7 +176,7 @@ ParentRoundRobin::selectParent(const ParentSelectionPolicy *policy, bool first_c
- Debug("parent_select", "Chosen parent = %s.%d", result->hostname, result->port);
- return;
- }
-- cur_index = (cur_index + 1) % result->rec->num_parents;
-+ latched_parent = cur_index = (cur_index + 1) % result->rec->num_parents;
- } while ((unsigned int)cur_index != result->start_parent);
-
- if (result->rec->go_direct == true && result->rec->parent_is_proxy) {
-diff --git a/proxy/ParentRoundRobin.h b/proxy/ParentRoundRobin.h
-index 57b6832..818e26c 100644
---- a/proxy/ParentRoundRobin.h
-+++ b/proxy/ParentRoundRobin.h
-@@ -35,6 +35,7 @@
- class ParentRoundRobin : public ParentSelectionStrategy
- {
- ParentRR_t round_robin_type;
-+ int latched_parent;
-
- public:
- ParentRoundRobin(ParentRecord *_parent_record, ParentRR_t _round_robin_type);
-diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc
-index 81431a8..aa3c4b6 100644
---- a/proxy/ParentSelection.cc
-+++ b/proxy/ParentSelection.cc
-@@ -436,6 +436,7 @@ ParentRecord::ProcessParents(char *val, bool isPrimary)
- this->parents[i].hostname[tmp - current] = '\0';
- this->parents[i].port = port;
- this->parents[i].failedAt = 0;
-+ this->parents[i].failCount = 0;
- this->parents[i].scheme = scheme;
- this->parents[i].idx = i;
- this->parents[i].name = this->parents[i].hostname;
-@@ -446,6 +447,7 @@ ParentRecord::ProcessParents(char *val, bool isPrimary)
- this->secondary_parents[i].hostname[tmp - current] = '\0';
- this->secondary_parents[i].port = port;
- this->secondary_parents[i].failedAt = 0;
-+ this->parents[i].failCount = 0;
- this->secondary_parents[i].scheme = scheme;
- this->secondary_parents[i].idx = i;
- this->secondary_parents[i].name = this->secondary_parents[i].hostname;
-@@ -543,6 +545,8 @@ ParentRecord::Init(matcher_line *line_info)
- round_robin = P_NO_ROUND_ROBIN;
- } else if (strcasecmp(val, "consistent_hash") == 0) {
- round_robin = P_CONSISTENT_HASH;
-+ } else if (strcasecmp(val, "latched") == 0) {
-+ round_robin = P_LATCHED_ROUND_ROBIN;
- } else {
- round_robin = P_NO_ROUND_ROBIN;
- errPtr = "invalid argument to round_robin directive";
-@@ -621,6 +625,7 @@ ParentRecord::Init(matcher_line *line_info)
- case P_NO_ROUND_ROBIN:
- case P_STRICT_ROUND_ROBIN:
- case P_HASH_ROUND_ROBIN:
-+ case P_LATCHED_ROUND_ROBIN:
- TSDebug("parent_select", "allocating ParentRoundRobin() lookup strategy.");
- selection_strategy = new ParentRoundRobin(this, round_robin);
- break;
-@@ -654,6 +659,7 @@ ParentRecord::UpdateMatch(ParentResult *result, RequestData *rdata)
- ParentRecord::~ParentRecord()
- {
- ats_free(parents);
-+ ats_free(secondary_parents);
- delete selection_strategy;
- }
-
-diff --git a/proxy/ParentSelection.h b/proxy/ParentSelection.h
-index ab970c0..264dd0c 100644
---- a/proxy/ParentSelection.h
-+++ b/proxy/ParentSelection.h
-@@ -60,6 +60,7 @@ enum ParentRR_t {
- P_STRICT_ROUND_ROBIN,
- P_HASH_ROUND_ROBIN,
- P_CONSISTENT_HASH,
-+ P_LATCHED_ROUND_ROBIN
- };
-
- // struct pRecord
-diff --git a/tools/rc_admin.pl b/tools/rc_admin.pl
-new file mode 100755
-index 0000000..554e0b6
---- /dev/null
-+++ b/tools/rc_admin.pl
-@@ -0,0 +1,120 @@
-+#!/usr/bin/env perl
-+#
-+#
-+use strict;
-+use warnings;
-+
-+use File::Copy;
-+
-+my %el_versions = ( "6" => 1, "7" => 1);
-+my %modes = ("install" => 1, "upgrade" => 1, "uninstall" => 1);
-+my %phases = ("pre-uninstall" => 1, "post-install" => 1);
-+my $installdir;
-+my $mode;
-+my $phase;
-+
-+# returns the enterprise linux version.
-+sub el_version {
-+ my $el_version = 0;
-+
-+ if (`uname -r` =~ m/.+el(\d)\.x86_64/) {
-+ $el_version = $1;
-+ }
-+ exists $el_versions{$el_version} ? return $el_version
-+ : die("unsupported el_version: $el_version");
-+}
-+
-+sub usage {
-+ print STDERR "\nUsage: rc_admin.pl phase mode install_directory\n\n";
-+ print "\tvalid phase arguments:\n";
-+ print "\t\t'pre-uninstall' - pre uninstall phase\n";
-+ print "\t\t'post-install' - post install phase\n";
-+
-+ print "\tvalid mode arguments:\n";
-+ print "\t\t'install' or 'uninstall'\n\n";
-+ exit 1;
-+}
-+
-+if ( $#ARGV < 2 || !(exists $phases{$ARGV[0]}) || !(exists $modes{$ARGV[1]})) {
-+ &usage();
-+} else {
-+ $phase = $ARGV[0];
-+ $mode = $ARGV[1];
-+ $installdir = $ARGV[2];
-+}
-+
-+my $EL_VERSION = el_version();
-+
-+if (-d "$installdir/rc") {
-+ chdir("$installdir/rc");
-+} else {
-+ die("no such directory $installdir/rc");
-+}
-+
-+if ($phase eq "post-install") {
-+ if ($EL_VERSION eq "6" && $mode eq "install") {
-+ print "installing /etc/init.d/trafficserver.\n";
-+ `/bin/cp trafficserver /etc/init.d/`;
-+ if ($? != 0) {
-+ print "Failed to copy trafficsever to /etc/init.d/ : $!";
-+ } else {
-+ chmod(0755, "/etc/init.d/trafficserver");
-+ }
-+ `/sbin/chkconfig --add trafficserver`;
-+ if ($? != 0) {
-+ print "Failed running /sbin/chkconfig --add trafficsever";
-+ }
-+
-+ } elsif ("$EL_VERSION" eq "7" && $mode eq "install") {
-+ print "installing /usr/lib/systemd/system/trafficserver.service.\n";
-+ `/bin/cp trafficserver.service /usr/lib/systemd/system/`;
-+ if ($? != 0) {
-+ print "Failed to copy trafficsever.service to /usr/lib/systemd/system: $!";
-+ } else {
-+ chmod(0644, "/usr/lib/systemd/system/trafficserver.service");
-+ }
-+ `/bin/systemctl daemon-reload`;
-+ if ($? != 0) {
-+ print "Failed running /bin/systemctl daemon-reload";
-+ }
-+ `/bin/systemctl enable trafficserver`;
-+ if ($? != 0) {
-+ print "Failed running /bin/systemctl enable trafficsever";
-+ }
-+ }
-+} elsif ($phase eq "pre-uninstall") {
-+ print "Shutting down trafficserver.\n";
-+ `/sbin/service trafficserver stop`;
-+ if ($? != 0) {
-+ print "Failed running /sbin/service trafficsever stop\n";
-+ } else {
-+ print "trafficserver has stopped.\n";
-+ }
-+
-+ if ($mode eq "uninstall") {
-+ print "disabling trafficserver.\n";
-+ if ($EL_VERSION eq "6") {
-+ `/sbin/chkconfig --del trafficserver`;
-+ if ($? != 0) {
-+ print "Failed running /sbin/chkconfig --del trafficsever";
-+ } else {
-+ print "trafficserver has been disabled.\n";
-+ }
-+ unlink("/etc/init.d/trafficserver");
-+ } elsif ($EL_VERSION eq "7") {
-+ `/bin/systemctl disable trafficserver`;
-+ if ($? != 0) {
-+ print "Failed running /sbin/systemctl disable trafficsever";
-+ } else {
-+ print "trafficserver has been disabled.\n";
-+ }
-+ unlink ("/usr/lib/systemd/system/trafficserver.service");
-+ `/bin/systemctl daemon-reload`;
-+ if ($? != 0) {
-+ print "Failed running /bin/systemctl daemon-reload";
-+ }
-+ }
-+ }
-+}
-+
-+exit 0;
-diff --git a/trafficserver.spec b/trafficserver.spec
-index 9e74377..3ddb4dd 100644
---- a/trafficserver.spec
-+++ b/trafficserver.spec
-@@ -29,7 +29,6 @@ git clone git@github.comcast.com:cdneng/trafficserver.git %{name}
- git checkout build-master
- git checkout %{commit} .
- autoreconf -vfi
--#id ats &>/dev/null || /usr/sbin/useradd -u 176 -r ats -s /sbin/nologin -d /
-
- %build
- ./configure --prefix=%{install_prefix}/%{name} --with-user=ats --with-group=ats --with-build-number=%{release} --enable-experimental-plugins --with-max-api-stats=%{api_stats}
-@@ -42,8 +41,10 @@ make DESTDIR=$RPM_BUILD_ROOT install
- # ..so why haven't we fixed them? VSSCDNENG-767
-
- mkdir -p $RPM_BUILD_ROOT/opt/trafficserver/etc/trafficserver/snapshots
--mkdir -p $RPM_BUILD_ROOT/etc/init.d
--cp $RPM_BUILD_DIR/%{name}/rc/trafficserver $RPM_BUILD_ROOT/etc/init.d/
-+mkdir -p $RPM_BUILD_ROOT/opt/trafficserver/rc
-+cp $RPM_BUILD_DIR/%{name}/rc/trafficserver $RPM_BUILD_ROOT/opt/trafficserver/rc/
-+cp $RPM_BUILD_DIR/%{name}/rc/trafficserver.service $RPM_BUILD_ROOT/opt/trafficserver/rc/
-+cp $RPM_BUILD_DIR/%{name}/tools/rc_admin.pl $RPM_BUILD_ROOT/opt/trafficserver/rc/
-
- %clean
- rm -rf $RPM_BUILD_ROOT
-@@ -52,14 +53,14 @@ rm -rf $RPM_BUILD_ROOT
- id ats &>/dev/null || /usr/sbin/useradd -u 176 -r ats -s /sbin/nologin -d /
-
- %post
--chkconfig --add %{name}
-+/opt/trafficserver/rc/rc_admin.pl post-install install /opt/trafficserver
-
- %preun
--/etc/init.d/%{name} stop
--
- # if 0 uninstall, if 1 upgrade
- if [ "$1" = "0" ]; then
-- chkconfig --del %{name}
-+ /opt/trafficserver/rc/rc_admin.pl pre-uninstall uninstall /opt/trafficserver
-+elif [ "$1" = "1" ]; then
-+ /opt/trafficserver/rc/rc_admin.pl pre-uninstall upgrade /opt/trafficserver
- fi
-
- %postun
-@@ -72,7 +73,6 @@ fi
-
- %files
- %defattr(-,root,root)
--%attr(755,-,-) /etc/init.d/trafficserver
- %dir /opt/trafficserver
- /opt/trafficserver/bin
- /opt/trafficserver/include
-@@ -80,6 +80,7 @@ fi
- /opt/trafficserver/lib64
- /opt/trafficserver/libexec
- /opt/trafficserver/share
-+/opt/trafficserver/rc
- %dir /opt/trafficserver/var
- %attr(-,ats,ats) /opt/trafficserver/var/trafficserver
- %dir /opt/trafficserver/var/log
-@@ -112,6 +113,9 @@ fi
- %config(noreplace) %attr(644,ats,ats) /opt/trafficserver/etc/trafficserver/stats.config.xml
-
- %changelog
-+* Wed Jun 8 2016 John Rushford <john_rushford(at)cable.comcast.com>
-+- Added tools/rc_admin.pl to complete rpm tasks under both Enterprise Linux 6 or 7 using either chkconfig or systemd commands.
-+- Modified this spec file to use rc_admin.pl
- * Wed Aug 7 2013 Jeff Elsloo <jeffrey_elsloo(at)cable.comcast.com>
- - Modified to support building 3.3.x
- - Modified to support upgrades