[
https://issues.apache.org/jira/browse/TS-4723?focusedWorklogId=26919&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-26919
]
ASF GitHub Bot logged work on TS-4723:
--------------------------------------
Author: ASF GitHub Bot
Created on: 23/Aug/16 14:13
Start Date: 23/Aug/16 14:13
Worklog Time Spent: 10m
Work Description: Github user SolidWallOfCode commented on a diff in the
pull request:
https://github.com/apache/trafficserver/pull/843#discussion_r75874123
--- Diff: plugins/experimental/carp/Common.cc ---
@@ -0,0 +1,364 @@
+
+/** @file
+
+ Loads the CARP configuration
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+#include "Common.h"
+
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <memory.h>
+
+using namespace std;
+
+/************************************************************************/
+void stringExplode(string str, string separator, vector<string>* results)
+{
+ size_t found;
+ found = str.find_first_of(separator);
+ while (found != std::string::npos)
+ {
+ if (found > 0)
+ {
+ results->push_back(str.substr(0, found));
+ }
+ str = str.substr(found + 1);
+ found = str.find_first_of(separator);
+ }
+ if (str.length() > 0)
+ {
+ results->push_back(str);
+ }
+}
+
+/************************************************************************/
+/*
+ Parse /proc/{pid}/net/tcp
+ sl local_address rem_address st tx_queue rx_queue tr tm->when
retrnsmt uid timeout inode
+ 0: 00000000:036B 00000000:0000 0A 00000000:00000000 00:00000000
00000000 0 0 22272 1 ffff8801b7ecb700 299 0 0 2 -1
+ 1: 00000000:08AE 00000000:0000 0A 00000000:00000000 00:00000000
00000000 0 0 10621 1 ffff8801b7b9a080 299 0 0 2 -1
+ 2: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000
00000000 0 0 22046 1 ffff8801b7b9b400 299 0 0 2 -1
+ Parse /proc/{pid}/net/tcp6
+ * sl local_address remote_address
st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
+ 0: 00000000000000000000000000000000:08AE
00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000
0 0 10619 1 ffff8801b266d780 299 0 0 2 -1
+ 1: 00000000000000000000000000000000:006F
00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000
0 0 22051 1 ffff8801b3a51880 299 0 0 2 -1
+ 2: 00000000000000000000000000000000:0016
00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000
0 0 10656 1 ffff8801b266d040 299 0 0 2 -1
+ 3: 00000000000000000000000000000000:8E77
00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000
0 0 22300 1 ffff8801b2f5c780 299 0 0 2 -1
+
+ looking for local_address:PORT wher st = LISTEN (0x0A)
+ * ./include/net/tcp_states.h
+ * enum {
+ TCP_ESTABLISHED = 1,
+ TCP_SYN_SENT,
+ TCP_SYN_RECV,
+ TCP_FIN_WAIT1,
+ TCP_FIN_WAIT2,
+ TCP_TIME_WAIT,
+ TCP_CLOSE,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+ TCP_LISTEN,
+ TCP_CLOSING,
+
+ TCP_MAX_STATES
+ */
+
+/************************************************************************/
+
+/* used internally */
+bool
+scanProcFileForPort(string sFilename, string sPid, unsigned int iPort)
+{
+ bool bMatch = false;
+ TSFile file;
+ int iLine = 0;
+ bool bParseDone = false;
+
+ // attempt to open file
+ TSDebug(DEBUG_TAG_INIT, "Trying to open proc file @ %s to determine
listening ports", sFilename.c_str());
+ file = TSfopen(sFilename.c_str(), "r");
+ if (file == NULL) {
+ TSError("Failed to open proc tcp file of %s. Error=%s",
sFilename.c_str(), strerror(errno));
+ return false;
+ }
+
+ TSDebug(DEBUG_TAG_INIT, "Successfully opened %s file",
sFilename.c_str());
+
+ char buffer[1024];
+ memset(buffer, 0, sizeof (buffer));
+
+ while (TSfgets(file, buffer, sizeof (buffer) - 1) != NULL &&
!bParseDone) {
+ char *eol = strstr(buffer, "\r\n");
+ if (!eol)
+ eol = strchr(buffer, '\n');
+ if (eol)
+ *eol = 0; // remove ending LF or CRLF
+
+ // TSDebug(DEBUG_TAG_INIT, "Parsing line: %s", buffer);
+ ++iLine;
+ if (iLine == 1) { // ignore header line
+ continue;
+ }
+ vector<string> vParts;
+ stringExplode(string(buffer), string(" "), &vParts);
+ // part 3 is status
+ unsigned int iStatus = 0;
+ sscanf(vParts[3].c_str(), "%x", &iStatus);
+ if (iStatus == TCP_LISTEN) {
+ vector<string> vLocalParts;
+ stringExplode(vParts[1], string(":"), &vLocalParts); // part 1 is
localaddr
+ unsigned int iLPort = 0;
+ sscanf(vLocalParts[1].c_str(), "%x", &iLPort);
+ TSDebug(DEBUG_TAG_INIT, "Found listening port %d", iLPort);
+ if (iLPort == iPort) {
+ string sLabel = string("socket:[" + vParts[9] + "]");
+ // find inode in /proc/{pid}/fd/
+ string sDir = "/proc/" + string(sPid) + "/fd";
+
+ DIR *dp;
+ struct dirent *dirp;
+ if ((dp = opendir(sDir.c_str())) == NULL) {
+ TSDebug(DEBUG_TAG_INIT, "Failed to open directory %s, %s",
sDir.c_str(), strerror(errno));
+ continue;
+ }
+
+ while ((dirp = readdir(dp)) != NULL && !bParseDone) {
+ //TSDebug(DEBUG_TAG_INIT, "File in %s = %s inode=%d",
sDir.c_str(),dirp->d_name,dirp->d_ino);
+ string sPath = sDir + "/" + dirp->d_name;
+ char sBuf[256];
+ ssize_t iCount = readlink(sPath.c_str(), sBuf, sizeof (sBuf));
+ if (iCount > 0) {
+ string sLink(sBuf, iCount);
+ if (sLink.compare(sLabel) == 0) {
+ TSDebug(DEBUG_TAG_INIT, "Found that port %d is opened for
listening by pid %s", iLPort, sPid.c_str());
+ bParseDone = true;
+ bMatch = true;
+ }
+ }
+ }
+ closedir(dp);
+ }
+ }
+ /*
+ for(int i=0;i<vParts.size();i++)
+ {
+ TSDebug(DEBUG_TAG_INIT, "part[%d]='%s'", i, vParts[i].c_str());
+ }
+ */
+ }
+
+ TSfclose(file);
+
+ return bMatch;
+}
+
+/************************************************************************/
+bool
+isPortSelf(unsigned int iPort)
+{
+ pid_t pid = getpid();
+ char sPid[10];
+ bool bMatch = false;
+
+ string sFileName;
+ // open file @ /proc/{pid}/net/tcp
+
+
+ sprintf(sPid,"%d",pid);
+
+ // look for IPv4 listener first
+ sFileName = "/proc/" + string(sPid) + "/net/tcp";
+ bMatch = scanProcFileForPort(sFileName,sPid, iPort);
+ if(!bMatch) { // did not find IPv4 listener, check for IPv6
+ sFileName = "/proc/" + string(sPid) + "/net/tcp6";
+ bMatch = scanProcFileForPort(sFileName,sPid, iPort);
+ }
+ return bMatch;
+}
+
+/************************************************************************/
+struct hostent *
+getHostIp(string hName, struct hostent *h, char *buf, int buflen)
+{
+ int res, err;
+ struct hostent *hp = NULL;
+
+ res = gethostbyname_r(hName.c_str(), h, buf, buflen, &hp, &err);
+ if ((res == 0) && (hp != NULL)) {
+ return hp;
+ } else {
+ TSDebug(DEBUG_TAG_INIT, "gethostbyname_r failed for %s. Error=%s",
hName.c_str(), strerror(err));
+ }
+ return NULL;
+}
+
+
+/************************************************************************/
+/*
+ * *** WARNING *** You will need to run the carp plugin with
traffic_manager for it to detect
+ * itself and to forward directly to the origin. It will not work by
running traffic_server directly!
+ */
--- End diff --
Why? Because `traffic_manager` opens the ports and so only if it is running
will the port scan work? In that case, why not wait until
`TS_LIFECYCLE_PORTS_READY_HOOK`?
Issue Time Tracking
-------------------
Worklog Id: (was: 26919)
Time Spent: 6h 20m (was: 6h 10m)
> ATS CARP Plugin
> ---------------
>
> Key: TS-4723
> URL: https://issues.apache.org/jira/browse/TS-4723
> Project: Traffic Server
> Issue Type: New Feature
> Components: Plugins
> Reporter: Eric Schwartz
> Assignee: Eric Schwartz
> Fix For: 7.0.0
>
> Time Spent: 6h 20m
> Remaining Estimate: 0h
>
> Open sourcing this plugin we use internally within Yahoo in place of
> hierarchical caching.
> CARP is a plugin that allows you to group a bunch of ATS hosts into a cluster
> and share cache space across the entire group. This is done with consistent
> hashing on the object URL to generate an "owner" node in the cluster.
> Requests to any other node in the cluster will be forwarded on to the
> corresponding owner. More info in the README.
> Difference from internal version of note:
> I've ripped out some code we weren't entirely sure we could open source
> because of a hash function. If it turns out that we can open source this,
> I'll do so. The CarpHashAlgorithm class is meant to be extensible, so any
> consistent hash function can replace it. The function included here is pretty
> straightforward but not what we use in production, so just wanted to use that
> caveat.
> One last caveat:
> You'll see some code and documentation in here for object replication. This
> is something I added recently to CARP that allows you to specify an object be
> replicated a certain number of times in the cluster. This is useful if you
> have a network partition or if you're performing some sort of update. When an
> object's primary owner is unreachable, a node in the cluster can go to the
> secondary owner if it's available rather than having to fall all the way back
> to origin. While I've done some initial testing on this with my own cluster
> of hosts, it's not been tested in production so use at your own risk for now.
> I'll be sure to keep the open source community informed on the progress of
> our tests with this feature.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)