On Jan 8, 2015, at 12:00 PM, shinr...@apache.org wrote:
Repository: trafficserver
Updated Branches:
refs/heads/master aaf5d6bfa -> 5f2fc30d7
TS-3219: Separate WCCP client process
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/5f2fc30d
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/5f2fc30d
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/5f2fc30d
Branch: refs/heads/master
Commit: 5f2fc30d7d1b4f2107026ede93c05df8360e4d75
Parents: aaf5d6b
Author: shinrich <shinr...@network-geographics.com>
Authored: Thu Nov 20 15:14:55 2014 -0600
Committer: shinrich <shinr...@yahoo-inc.com>
Committed: Thu Jan 8 13:54:10 2015 -0600
----------------------------------------------------------------------
CHANGES | 2 +
lib/wccp/Makefile.am | 8 +-
lib/wccp/Wccp.h | 2 +-
lib/wccp/WccpConfig.cc | 11 +
lib/wccp/WccpEndPoint.cc | 139 +++++++----
lib/wccp/WccpLocal.h | 17 ++
lib/wccp/wccp-test-cache.cc | 196 ---------------
lib/wccp/wccp-test-router.cc | 14 +-
tools/Makefile.am | 17 +-
tools/wccp_client/Makefile.am | 33 +++
tools/wccp_client/readme.txt | 42 ++++
tools/wccp_client/service-nogre-example.config | 66 +++++
tools/wccp_client/wccp_client.cc | 256 ++++++++++++++++++++
13 files changed, 544 insertions(+), 259 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index eac1de9..3b06244 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
-*- coding: utf-8 -*-
Changes with Apache Traffic Server 5.3.0
+ *) [TS-3219] Create WCCP client process.
+
*) [TS-3272] Fix to ensure that SSL_SNI callback only called when state
changes.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/wccp/Makefile.am b/lib/wccp/Makefile.am
index f782c8b..abbf632 100644
--- a/lib/wccp/Makefile.am
+++ b/lib/wccp/Makefile.am
@@ -26,7 +26,7 @@ AM_CPPFLAGS = \
#DEFS += $(WCCP_DEFS)
noinst_LIBRARIES = libwccp.a
-#noinst_PROGRAMS = test-cache
+# noinst_PROGRAMS = test-cache
libwccp_a_SOURCES = \
Wccp.h \
@@ -38,5 +38,7 @@ libwccp_a_SOURCES = \
WccpStatic.cc \
WccpUtil.h
-#test_cache_SOURCES = \
-# wccp-test-cache.cc wccp-test-router.cc
+# test_cache_SOURCES = \
+# wccp-test-cache.cc
+
+# test_cache_LDADD = $(LDADD) -L$(top_builddir)/lib/tsconfig -ltsconfig
-L$(top_builddir)/lib/wccp -lwccp -L$(top_builddir)/lib/ts -ltsutil
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/Wccp.h
----------------------------------------------------------------------
diff --git a/lib/wccp/Wccp.h b/lib/wccp/Wccp.h
index 4e885e5..cfe99c7 100644
--- a/lib/wccp/Wccp.h
+++ b/lib/wccp/Wccp.h
@@ -27,6 +27,7 @@
# include <tsconfig/Errata.h>
# include <memory.h>
# include <ink_defs.h>
+# include <ink_memory.h>
// Nasty, defining this with no prefix. The value is still available
// in TS_VERSION_STRING.
# undef VERSION
@@ -421,7 +422,6 @@ inline ServiceGroup::Type
ServiceGroup::getSvcType() const {
return static_cast<ServiceGroup::Type>(m_svc_type);
}
-
inline uint8_t
ServiceGroup::getSvcId() const {
return m_svc_id;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/WccpConfig.cc
----------------------------------------------------------------------
diff --git a/lib/wccp/WccpConfig.cc b/lib/wccp/WccpConfig.cc
index 443fa8f..fca9966 100644
--- a/lib/wccp/WccpConfig.cc
+++ b/lib/wccp/WccpConfig.cc
@@ -67,6 +67,7 @@ static char const * const SVC_PROP_ROUTERS = "routers";
static char const * const SVC_PROP_FORWARD = "forward";
static char const * const SVC_PROP_RETURN = "return";
static char const * const SVC_PROP_ASSIGN = "assignment";
+static char const * const SVC_PROP_PROC = "proc-name";
static char const * const SECURITY_PROP_OPTION = "option";
static char const * const SECURITY_PROP_KEY = "key";
@@ -725,6 +726,16 @@ CacheImpl::loadServicesFromFile(char const* path) {
// Properties after this are optional so we can proceed if they fail.
GroupData& svc = this->defineServiceGroup(svc_info);
+
+ // Is there a process we should track?
+ if ((prop = svc_cfg[SVC_PROP_PROC]).hasValue()) {
+ if (ts::config::StringValue == prop.getType()) {
+ svc.setProcName(prop.getText());
+ } else {
+ zret.push(Prop_Invalid_Type(prop, ts::config::StringValue));
+ }
+ }
+
// Add seed routers.
std::vector<uint32_t>::iterator rspot, rlimit;
for ( rspot = routers.begin(), rlimit = routers.end() ; rspot != rlimit ;
++rspot )
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/WccpEndPoint.cc
----------------------------------------------------------------------
diff --git a/lib/wccp/WccpEndPoint.cc b/lib/wccp/WccpEndPoint.cc
index 0dcf7cb..2426bc1 100644
--- a/lib/wccp/WccpEndPoint.cc
+++ b/lib/wccp/WccpEndPoint.cc
@@ -255,7 +255,7 @@ Impl::handleRemovalQuery(IpHeader const&, ts::Buffer const&
/* data ATS_UNUSED *
}
// ------------------------------------------------------
CacheImpl::GroupData::GroupData()
- : m_assignment_pending(false) {
+ : m_proc_name(NULL), m_assignment_pending(false) {
}
CacheImpl::GroupData&
@@ -404,6 +404,37 @@ CacheImpl::GroupData::waitTime(time_t now) const {
}
bool
+CacheImpl::GroupData::processUp() {
+ bool zret = false;
+ const char *proc_pid_path = this->getProcName();
+ if (proc_pid_path == NULL || proc_pid_path[0] == '\0') {
+ zret = true; // No process to track, always chatter
+ } else {
+ // Look for the pid file
+ int fd = open(proc_pid_path, O_RDONLY);
+ if (fd > 0) {
+ char buffer[256];
+ ssize_t read_count = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+ if (read_count > 0) {
+ buffer[read_count] = '\0';
+ int pid = atoi(buffer);
+ if (pid > 0) {
+ // If the process is still running, it has an entry in the proc file
system, (Linux only)
+ sprintf(buffer, "/proc/%d/status", pid);
+ fd = open(buffer, O_RDONLY);
+ if (fd > 0) {
+ zret = true;
+ close(fd);
+ }
+ }
+ }
+ }
+ }
+ return zret;
+}
+
+bool
CacheImpl::GroupData::cullRouters(time_t now) {
bool zret = false;
size_t idx = 0, n = m_routers.size();
@@ -603,37 +634,40 @@ CacheImpl::housekeeping() {
group.cullRouters(now); // TBD UPDATE VIEW!
- // Check the active routers for scheduled packets.
- for ( RouterBag::iterator rspot = group.m_routers.begin(),
- rend = group.m_routers.end() ;
- rspot != rend ;
- ++rspot
- ) {
- dst_addr.sin_addr.s_addr = rspot->m_addr;
- if (0 == rspot->pingTime(now)) {
- HereIAmMsg here_i_am;
- here_i_am.setBuffer(msg_buffer);
- this->generateHereIAm(here_i_am, group, *rspot);
- zret = sendto(m_fd, msg_data, here_i_am.getCount(), 0, addr_ptr,
sizeof(dst_addr));
- if (0 <= zret) {
- rspot->m_xmit.set(now, group.m_generation);
- rspot->m_send_caps = false;
- logf(LVL_DEBUG, "Sent HERE_I_AM for service group %d to router
%s%s[#%d,%lu].",
- group.m_svc.getSvcId(),
- ip_addr_to_str(rspot->m_addr),
- rspot->m_rapid ? " [rapid] " : " ",
- group.m_generation, now
- );
- if (rspot->m_rapid) --(rspot->m_rapid);
- } else {
- logf_errno(LVL_WARN, "Failed to send to router " ATS_IP_PRINTF_CODE " -
", ATS_IP_OCTETS(rspot->m_addr));
+ // Check to see if the related service is up
+ if (group.processUp()) {
+ // Check the active routers for scheduled packets.
+ for ( RouterBag::iterator rspot = group.m_routers.begin(),
+ rend = group.m_routers.end() ;
+ rspot != rend ;
+ ++rspot
+ ) {
+ dst_addr.sin_addr.s_addr = rspot->m_addr;
+ if (0 == rspot->pingTime(now)) {
+ HereIAmMsg here_i_am;
+ here_i_am.setBuffer(msg_buffer);
+ this->generateHereIAm(here_i_am, group, *rspot);
+ zret = sendto(m_fd, msg_data, here_i_am.getCount(), 0, addr_ptr,
sizeof(dst_addr));
+ if (0 <= zret) {
+ rspot->m_xmit.set(now, group.m_generation);
+ rspot->m_send_caps = false;
+ logf(LVL_DEBUG, "Sent HERE_I_AM for service group %d to router
%s%s[#%d,%lu].",
+ group.m_svc.getSvcId(),
+ ip_addr_to_str(rspot->m_addr),
+ rspot->m_rapid ? " [rapid] " : " ",
+ group.m_generation, now
+ );
+ if (rspot->m_rapid) --(rspot->m_rapid);
+ } else {
+ logf_errno(LVL_WARN, "Failed to send to router " ATS_IP_PRINTF_CODE " -
", ATS_IP_OCTETS(rspot->m_addr));
+ }
+ } else if (rspot->m_assign) {
+ RedirectAssignMsg redirect_assign;
+ redirect_assign.setBuffer(msg_buffer);
+ this->generateRedirectAssign(redirect_assign, group);
+ zret = sendto(m_fd, msg_data, redirect_assign.getCount(), 0,
addr_ptr, sizeof(dst_addr));
+ if (0 <= zret) rspot->m_assign = false;
}
- } else if (rspot->m_assign) {
- RedirectAssignMsg redirect_assign;
- redirect_assign.setBuffer(msg_buffer);
- this->generateRedirectAssign(redirect_assign, group);
- zret = sendto(m_fd, msg_data, redirect_assign.getCount(), 0, addr_ptr,
sizeof(dst_addr));
- if (0 <= zret) rspot->m_assign = false;
}
}
@@ -644,32 +678,35 @@ CacheImpl::housekeeping() {
sspot != slimit ;
++sspot
) {
- HereIAmMsg here_i_am;
- here_i_am.setBuffer(msg_buffer);
- // Is the router due for a ping?
- if (sspot->m_xmit + TIME_UNIT > now) continue; // no
+ // Check to see if the related service is up
+ if (group.processUp()) {
+ HereIAmMsg here_i_am;
+ here_i_am.setBuffer(msg_buffer);
+ // Is the router due for a ping?
+ if (sspot->m_xmit + TIME_UNIT > now) continue; // no
- this->generateHereIAm(here_i_am, group);
+ this->generateHereIAm(here_i_am, group);
- dst_addr.sin_addr.s_addr = sspot->m_addr;
- zret = sendto(m_fd, msg_data, here_i_am.getCount(), 0,
- addr_ptr, sizeof(dst_addr));
- if (0 <= zret) {
- logf(LVL_DEBUG, "Sent HERE_I_AM for SG %d to seed router %s
[gen=#%d,t=%lu,n=%lu].",
+ dst_addr.sin_addr.s_addr = sspot->m_addr;
+ zret = sendto(m_fd, msg_data, here_i_am.getCount(), 0,
+ addr_ptr, sizeof(dst_addr));
+ if (0 <= zret) {
+ logf(LVL_DEBUG, "Sent HERE_I_AM for SG %d to seed router %s
[gen=#%d,t=%lu,n=%lu].",
+ group.m_svc.getSvcId(),
+ ip_addr_to_str(sspot->m_addr),
+ group.m_generation, now, here_i_am.getCount()
+ );
+ sspot->m_xmit = now;
+ sspot->m_count += 1;
+ }
+ else logf(LVL_DEBUG,
+ "Error [%d:%s] sending HERE_I_AM for SG %d to seed router %s
[#%d,%lu].",
+ zret, strerror(errno),
group.m_svc.getSvcId(),
ip_addr_to_str(sspot->m_addr),
- group.m_generation, now, here_i_am.getCount()
+ group.m_generation, now
);
- sspot->m_xmit = now;
- sspot->m_count += 1;
}
- else logf(LVL_DEBUG,
- "Error [%d:%s] sending HERE_I_AM for SG %d to seed router %s
[#%d,%lu].",
- zret, strerror(errno),
- group.m_svc.getSvcId(),
- ip_addr_to_str(sspot->m_addr),
- group.m_generation, now
- );
}
}
return zret;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/WccpLocal.h
----------------------------------------------------------------------
diff --git a/lib/wccp/WccpLocal.h b/lib/wccp/WccpLocal.h
index 9d73d17..89bab24 100644
--- a/lib/wccp/WccpLocal.h
+++ b/lib/wccp/WccpLocal.h
@@ -2463,10 +2463,12 @@ namespace detail {
/// Cache assignment methods supported.
ServiceGroup::CacheAssignmentStyle m_cache_assign;
+
/// Known caches.
CacheBag m_caches;
/// Known routers.
RouterBag m_routers;
+ char *m_proc_name;
/// Set if there an assignment should be computed and sent.
/// This is before checking for being a designated cache
@@ -2478,6 +2480,9 @@ namespace detail {
GroupData(); ///< Default constructor.
+ void setProcName(const ts::ConstBuffer &name);
+ const char *getProcName();
+
/// Find a router by IP @a addr.
/// @return A pointer to the router, or @c NULL if not found.
RouterBag::iterator findRouter(
@@ -2518,6 +2523,10 @@ namespace detail {
time_t now ///< Current time.
);
+ /** Check to see if the process associated with service is up
+ */
+ bool processUp();
+
/// Update state to reflect a view change.
self& viewChanged(time_t now);
@@ -2530,6 +2539,14 @@ namespace detail {
SecurityOption style ///< Security style to use.
);
};
+ inline const char *
+ GroupData::getProcName() {
+ return m_proc_name;
+ }
+ inline void
+ GroupData::setProcName(const ts::ConstBuffer &name) {
+ m_proc_name = ats_strndup(name.data(), name.size());
+ }
}
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/wccp-test-cache.cc
----------------------------------------------------------------------
diff --git a/lib/wccp/wccp-test-cache.cc b/lib/wccp/wccp-test-cache.cc
deleted file mode 100644
index f044dc8..0000000
--- a/lib/wccp/wccp-test-cache.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-/** @file
- WCCP cache simulation for testing.
-
- @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 <stdio.h>
-# include <unistd.h>
-# include <stdarg.h>
-# include <memory.h>
-# include <strings.h>
-# include <iostream>
-# include <iomanip>
-
-# include <getopt.h>
-
-# include "Wccp.h"
-
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-
-# include <poll.h>
-
-# include <libconfig.h++>
-
-static char const USAGE_TEXT[] =
- "%s\n"
- "--address IP address to bind.\n"
- "--router Booststrap IP address for routers.\n"
- "--service Path to service group definitions.\n"
- "--help Print usage and exit.\n"
- ;
-
-static bool Ready = true;
-
-inline void Error(char const* fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- Ready = false;
-}
-
-void Log(
- std::ostream& out,
- ats::Errata const& errata,
- int indent = 0
-) {
- for ( ats::Errata::const_iterator spot = errata.begin(), limit =
errata.end();
- spot != limit;
- ++spot
- ) {
- if (spot->m_id) {
- if (indent) out << std::setw(indent) << std::setfill(' ') << "> ";
- out << spot->m_id << " [" << spot->m_code << "]: " << spot->m_text
- << std::endl
- ;
- }
- if (spot->getErrata().size()) Log(out, spot->getErrata(), indent+2);
- }
-}
-
-void LogToStdErr(ats::Errata const& errata) {
- Log(std::cerr, errata);
-}
-
-int
-main(int argc, char** argv) {
- Wccp::Cache wcp;
-
- // Reading stdin support.
- size_t in_size = 200;
- char* in_buff = 0;
- ssize_t in_count;
-
- // Set up erratum support.
- ats::Errata::registerSink(&LogToStdErr);
-
- // getopt return values. Selected to avoid collisions with
- // short arguments.
- static int const OPT_ADDRESS = 257; ///< Bind to IP address option.
- static int const OPT_HELP = 258; ///< Print help message.
- static int const OPT_ROUTER = 259; ///< Seeded router IP address.
- static int const OPT_SERVICE = 260; ///< Service group definition.
-
- static option OPTIONS[] = {
- { "address", 1, 0, OPT_ADDRESS },
- { "router", 1, 0, OPT_ROUTER },
- { "service", 1, 0, OPT_SERVICE },
- { "help", 0, 0, OPT_HELP },
- { 0, 0, 0, 0 } // required terminator.
- };
-
- in_addr ip_addr = { INADDR_ANY };
- in_addr router_addr = { INADDR_ANY };
-
- int zret; // getopt return.
- int zidx; // option index.
- bool fail = false;
- char const* FAIL_MSG = "";
-
- while (-1 != (zret = getopt_long_only(argc, argv, "", OPTIONS, &zidx))) {
- switch (zret) {
- case OPT_HELP:
- FAIL_MSG = "Usage:";
- fail = true;
- break;
- case '?':
- FAIL_MSG = "Invalid option specified.";
- fail = true;
- break;
- case OPT_ADDRESS:
- if (0 == inet_aton(optarg, &ip_addr)) {
- FAIL_MSG = "Invalid IP address specified for client.";
- fail = true;
- }
- break;
- case OPT_ROUTER:
- if (0 == inet_aton(optarg, &router_addr)) {
- FAIL_MSG = "Invalid IP address specified for router.";
- fail = true;
- }
- break;
- case OPT_SERVICE:
- ats::Errata status = wcp.loadServicesFromFile(optarg);
- if (!status) fail = true;
- break;
- }
- }
-
- if (fail) {
- printf(USAGE_TEXT, FAIL_MSG);
- return 1;
- }
-
- if (0 > wcp.open(ip_addr.s_addr)) {
- fprintf(stderr, "Failed to open or bind socket.\n");
- return 2;
- }
-
- static int const POLL_FD_COUNT = 2;
- pollfd pfa[POLL_FD_COUNT];
-
- // Poll on STDIN and the socket.
- pfa[0].fd = STDIN_FILENO;
- pfa[0].events = POLLIN;
-
- pfa[1].fd = wcp.getSocket();
- pfa[1].events = POLLIN;
-
- wcp.housekeeping();
-
- while (true) {
- time_t dt = std::min(Wccp::TIME_UNIT, wcp.waitTime());
- printf("Waiting %lu milliseconds\n", dt * 1000);
- int n = poll(pfa, POLL_FD_COUNT, dt * 1000);
- if (n < 0) { // error
- perror("General polling failure");
- return 5;
- } else if (n > 0) { // things of interest happened
- if (pfa[1].revents) {
- if (pfa[1].revents & POLLIN) {
- wcp.handleMessage();
- } else {
- fprintf(stderr, "Socket failure.\n");
- return 6;
- }
- }
- if (pfa[0].revents) {
- if (pfa[0].revents & POLLIN) {
- in_count = getline(&in_buff, &in_size, stdin);
- fprintf(stderr, "Terminated from console.\n");
- return 0;
- }
- }
- } else { // timeout
- wcp.housekeeping();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/lib/wccp/wccp-test-router.cc
----------------------------------------------------------------------
diff --git a/lib/wccp/wccp-test-router.cc b/lib/wccp/wccp-test-router.cc
index 731cd41..362277b 100644
--- a/lib/wccp/wccp-test-router.cc
+++ b/lib/wccp/wccp-test-router.cc
@@ -28,7 +28,7 @@
# include <getopt.h>
-# include "ats-wccp-api.h"
+# include "Wccp.h"
# include <sys/socket.h>
# include <netinet/in.h>
@@ -36,7 +36,7 @@
# include <poll.h>
-# include <libconfig.h++>
+# include <tsconfig/TsValue.h>
static char const USAGE_TEXT[] =
"%s\n"
@@ -55,7 +55,7 @@ inline void Error(char const* fmt, ...) {
int
main(int argc, char** argv) {
- Wccp::Router wcp;
+ wccp::Router wcp;
// Reading stdin support.
size_t in_size = 200;
@@ -124,11 +124,11 @@ main(int argc, char** argv) {
pfa[0].fd = STDIN_FILENO;
pfa[0].events = POLLIN;
- pfa[1].fd = wcp.get_socket();
+ pfa[1].fd = wcp.getSocket();
pfa[1].events = POLLIN;
while (true) {
- int n = poll(pfa, POLL_FD_COUNT, Wccp::TIME_UNIT * 1000);
+ int n = poll(pfa, POLL_FD_COUNT, wccp::TIME_UNIT * 1000);
if (n < 0) { // error
perror("General polling failure");
return 5;
@@ -136,7 +136,7 @@ main(int argc, char** argv) {
if (pfa[1].revents) {
if (pfa[1].revents & POLLIN) {
wcp.handleMessage();
- wcp.sendPendingMessages();
+ //wcp.sendPendingMessages();
} else {
fprintf(stderr, "Socket failure.\n");
return 6;
@@ -150,7 +150,7 @@ main(int argc, char** argv) {
}
}
} else { // timeout
- wcp.sendPendingMessages();
+ //wcp.sendPendingMessages();
}
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/tools/Makefile.am
----------------------------------------------------------------------
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 56726b8..4b04473 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -22,7 +22,8 @@ bin_SCRIPTS = tsxs tspush
AM_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@
AM_CPPFLAGS = $(iocore_include_dirs) \
-I$(top_srcdir)/lib -I$(top_builddir)/lib \
- -I$(top_srcdir)/lib/ts -I$(top_builddir)/lib/ts
+ -I$(top_srcdir)/lib/ts -I$(top_builddir)/lib/ts \
+ -I$(top_srcdir)/lib/wccp
if BUILD_TEST_TOOLS
bin_PROGRAMS = jtest/jtest
@@ -49,3 +50,17 @@ http_load_http_load_SOURCES = \
http_load/timers.h
endif
+
+if BUILD_WCCP
+
+if BUILD_TEST_TOOLS
+bin_PROGRAMS += wccp_client/wccp_client
+else
+bin_PROGRAMS = wccp_client/wccp_client
+endif
+
+wccp_client_wccp_client_SOURCES = wccp_client/wccp_client.cc
+
+wccp_client_wccp_client_LDADD = -L$(top_builddir)/lib/tsconfig -ltsconfig
-L$(top_builddir)/lib/wccp -lwccp -L$(top_builddir)/lib/ts -ltsutil
+
+endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/tools/wccp_client/Makefile.am
----------------------------------------------------------------------
diff --git a/tools/wccp_client/Makefile.am b/tools/wccp_client/Makefile.am
new file mode 100644
index 0000000..969d67c
--- /dev/null
+++ b/tools/wccp_client/Makefile.am
@@ -0,0 +1,33 @@
+#
+# Makefile.am for WCCP client
+#
+# 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.
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/lib/ts \
+ -I$(top_srcdir)/proxy/api/ts
+
+#WCCP_DEFS = @WCCP_DEFS@
+#DEFS += $(WCCP_DEFS)
+
+noinst_PROGRAMS = test-cache
+
+test_cache_SOURCES = \
+ wccp-test-cache.cc
+
+test_cache_LDADD = $(LDADD) -L$(top_builddir)/lib/tsconfig -ltsconfig
-L$(top_builddir)/lib/wccp -lwccp -L$(top_builddir)/lib/ts -ltsutil
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/tools/wccp_client/readme.txt
----------------------------------------------------------------------
diff --git a/tools/wccp_client/readme.txt b/tools/wccp_client/readme.txt
new file mode 100644
index 0000000..d86e8c3
--- /dev/null
+++ b/tools/wccp_client/readme.txt
@@ -0,0 +1,42 @@
+Wccp_client is a front end to the wccp client library. It is a stand
+alone program that speaks the client side of the WCCP cache protocol.
+
+It can be used instead of the built in WCCP feature in Apache traffic server.
+This can be beneficial if you have multiple programs running on the same
+computer that are relying on WCCP to redirect traffic from the router to
+the computer.
+
+Since it relies on the wccp library, the wccp_client is only build if apache
+traffic server is configured with --enable-wccp.
+
+The overall Apache Traffic Server WCCP configuration documentation is
+at
https://docs.trafficserver.apache.org/en/latest/admin/transparent-proxy/wccp-configuration.en.html.
+
+The wccp-client takes the following arguments.
+--address IP address to bind.
+--router Booststrap IP address for routers.
+--service Path to service group definitions.
+--debug Print debugging information.
+--daemon Run as daemon.
+
+You need to run at least with the --address and the --service arguments. The
+address should be an address assigned to one of your computer's interfaces.
+An example service definition file, service-nogre-example.config, is included
+in this directory. In this file you define your MD5 security password
+(highly recommended), and you define your service groups. For each service
+group you define how the service should be recognized (protocol and port),
+the routers you are communicating with, whether you are using GRE or basic L2
+routing to redirect packets.
+
+In addition, you can specify a proc-name, a path
+to a process pid file. If the proc-name is present, the wccp client will
+only advertise the associated service group, if the process is currently
+up and running. So if your computer is hosting three services, and one of
+them goes down, the wccp client could stop advertising the service group
+associated with the down service thus stopping the router from redirecting
+that traffic, but continue to advertise and maintain the redireciton for the
+other two services.
+
+The current WCCP implementation associated with ATS only supports one cache
+client per service group per router. The cache assignment logic current
+assigns the current cache client to all buckets.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/tools/wccp_client/service-nogre-example.config
----------------------------------------------------------------------
diff --git a/tools/wccp_client/service-nogre-example.config
b/tools/wccp_client/service-nogre-example.config
new file mode 100644
index 0000000..56152b5
--- /dev/null
+++ b/tools/wccp_client/service-nogre-example.config
@@ -0,0 +1,66 @@
+security = {
+ key = "example-password";
+ option = "MD5";
+};
+
+services = (
+ {
+ name = "WCCP HTTP Client";
+ description = "Capture packets from client";
+ proc-name = "/opt/ats/var/trafficserver/cop.lock";
+ id = 51;
+ type = "DYNAMIC";
+ priority = 240;
+ protocol = 6;
+ primary-hash = ( "src_ip" );
+ ports = ( 80 );
+ assignment = ( "hash" );
+ forward = ( "l2" );
+ return = ( "l2" );
+ routers = ( "10.10.50.1" );
+ },
+ {
+ name = "WCCP HTTP Server";
+ description = "Capture packets from origin server";
+ proc-name = "/opt/ats/var/trafficserver/cop.lock";
+ id = 52;
+ type = "DYNAMIC";
+ priority = 240;
+ protocol = 6;
+ primary-hash = ( "dst_ip" );
+ ports = ( 80 );
+ port-type = "src";
+ assignment = ( "hash" );
+ forward = ( "l2" );
+ return = ( "l2" );
+ routers = ( "10.10.50.1" );
+ },
+ {
+ name = "WCCP RTMP Client";
+ description = "Capture packets from client";
+ id = 53;
+ type = "DYNAMIC";
+ priority = 240;
+ protocol = 6;
+ primary-hash = ( "src_ip" );
+ ports = ( 1935 );
+ assignment = ( "hash" );
+ forward = ( "l2" );
+ return = ( "l2" );
+ routers = ( "10.10.50.1" );
+ },
+ {
+ name = "WCCP RTSP Client";
+ description = "Capture packets from client";
+ id = 55;
+ type = "DYNAMIC";
+ priority = 240;
+ protocol = 6;
+ primary-hash = ( "src_ip" );
+ ports = ( 5544 );
+ assignment = ( "hash" );
+ forward = ( "l2" );
+ return = ( "l2" );
+ routers = ( "10.10.50.1" );
+ },
+);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5f2fc30d/tools/wccp_client/wccp_client.cc
----------------------------------------------------------------------
diff --git a/tools/wccp_client/wccp_client.cc b/tools/wccp_client/wccp_client.cc
new file mode 100644
index 0000000..f8215e9
--- /dev/null
+++ b/tools/wccp_client/wccp_client.cc
@@ -0,0 +1,256 @@
+/** @file
+ WCCP cache simulation for testing.
+
+ @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 <stdio.h>
+# include <unistd.h>
+# include <stdarg.h>
+# include <memory.h>
+# include <strings.h>
+# include <iostream>
+# include <iomanip>
+
+# include <getopt.h>
+
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+
+# include <poll.h>
+
+# include "ink_memory.h"
+# include "Wccp.h"
+# include "WccpUtil.h"
+# include "tsconfig/TsValue.h"
+# include "ink_lockfile.h"
+
+#define WCCP_LOCK "wccp.pid"
+
+bool do_debug = false;
+bool do_daemon = false;
+
+static char const USAGE_TEXT[] =
+ "%s\n"
+ "--address IP address to bind.\n"
+ "--router Booststrap IP address for routers.\n"
+ "--service Path to service group definitions.\n"
+ "--debug Print debugging information.\n"
+ "--daemon Run as daemon.\n"
+ "--help Print usage and exit.\n"
+ ;
+
+void Log(
+ std::ostream& out,
+ ts::Errata const& errata,
+ int indent = 0
+) {
+ for ( ts::Errata::const_iterator spot = errata.begin(), limit = errata.end();
+ spot != limit;
+ ++spot
+ ) {
+ if (spot->m_id) {
+ if (indent) out << std::setw(indent) << std::setfill(' ') << "> ";
+ out << spot->m_id << " [" << spot->m_code << "]: " << spot->m_text
+ << std::endl
+ ;
+ }
+ if (spot->getErrata().size()) Log(out, spot->getErrata(), indent+2);
+ }
+}
+
+void LogToStdErr(ts::Errata const& errata) {
+ Log(std::cerr, errata);
+}
+
+static void
+PrintErrata(ts::Errata const& err) {
+ size_t n;
+ static size_t const SIZE = 4096;
+ char buff[SIZE];
+ if (err.size()) {
+ ts::Errata::Code code = err.top().getCode();
+ if (do_debug || code >= wccp::LVL_WARN) {
+ n = err.write(buff, SIZE, 1, 0, 2, "> ");
+ // strip trailing newlines.
+ while (n && (buff[n-1] == '\n' || buff[n-1] == '\r'))
+ buff[--n] = 0;
+ printf("%s\n", buff);
+ }
+ }
+}
+
+static void
+Init_Errata_Logging() {
+ ts::Errata::registerSink(&PrintErrata);
+}
+
+static void
+check_lockfile()
+{
+ char lockfile[256];
+ pid_t holding_pid;
+ int err;
+
+ strcpy(lockfile, "/var/run/");
+ strcat(lockfile, WCCP_LOCK);
+
+ Lockfile server_lockfile(lockfile);
+ err = server_lockfile.Get(&holding_pid);
+
+ if (err != 1) {
+ char *reason = strerror(-err);
+ fprintf(stderr, "WARNING: Can't acquire lockfile '%s'", (const char
*)lockfile);
+
+ if ((err == 0) && (holding_pid != -1)) {
+ fprintf(stderr, " (Lock file held by process ID %ld)\n",
(long)holding_pid);
+ } else if ((err == 0) && (holding_pid == -1)) {
+ fprintf(stderr, " (Lock file exists, but can't read process ID)\n");
+ } else if (reason) {
+ fprintf(stderr, " (%s)\n", reason);
+ } else {
+ fprintf(stderr, "\n");
+ }
+ _exit(1);
+ }
+}
+
+int
+main(int argc, char** argv) {
+ wccp::Cache wcp;
+
+
+ // getopt return values. Selected to avoid collisions with
+ // short arguments.
+ static int const OPT_ADDRESS = 257; ///< Bind to IP address option.
+ static int const OPT_HELP = 258; ///< Print help message.
+ static int const OPT_ROUTER = 259; ///< Seeded router IP address.
+ static int const OPT_SERVICE = 260; ///< Service group definition.
+ static int const OPT_DEBUG = 261; ///< Enable debug printing
+ static int const OPT_DAEMON = 262; ///< Disconnect and run as daemon
+
+ static option OPTIONS[] = {
+ { "address", 1, 0, OPT_ADDRESS },
+ { "router", 1, 0, OPT_ROUTER },
+ { "service", 1, 0, OPT_SERVICE },
+ { "debug", 0, 0, OPT_DEBUG },
+ { "daemon", 0, 0, OPT_DAEMON },
+ { "help", 0, 0, OPT_HELP },
+ { 0, 0, 0, 0 } // required terminator.
+ };
+
+ in_addr ip_addr = { INADDR_ANY };
+ in_addr router_addr = { INADDR_ANY };
+
+ int zret; // getopt return.
+ int zidx; // option index.
+ bool fail = false;
+ char const* FAIL_MSG = "";
+
+ while (-1 != (zret = getopt_long_only(argc, argv, "", OPTIONS, &zidx))) {
+ switch (zret) {
+ case OPT_HELP:
+ FAIL_MSG = "Usage:";
+ fail = true;
+ break;
+ case '?':
+ FAIL_MSG = "Invalid option specified.";
+ fail = true;
+ break;
+ case OPT_ADDRESS:
+ if (0 == inet_aton(optarg, &ip_addr)) {
+ FAIL_MSG = "Invalid IP address specified for client.";
+ fail = true;
+ }
+ break;
+ case OPT_ROUTER:
+ if (0 == inet_aton(optarg, &router_addr)) {
+ FAIL_MSG = "Invalid IP address specified for router.";
+ fail = true;
+ }
+ break;
+ case OPT_SERVICE: {
+ ts::Errata status = wcp.loadServicesFromFile(optarg);
+ if (!status) fail = true;
+ break;
+ }
+ case OPT_DEBUG:
+ do_debug = true;
+ break;
+ case OPT_DAEMON:
+ do_daemon = true;
+ break;
+ }
+ }
+
+ if (fail) {
+ printf(USAGE_TEXT, FAIL_MSG);
+ return 1;
+ }
+
+ if (0 > wcp.open(ip_addr.s_addr)) {
+ fprintf(stderr, "Failed to open or bind socket.\n");
+ return 2;
+ }
+
+ if (do_daemon) {
+ pid_t pid = fork();
+ if (pid > 0) {
+ // Successful, the parent should go away
+ _exit(0);
+ }
+ }
+
+ check_lockfile();
+
+ // Set up erratum support.
+ //ts::Errata::registerSink(&LogToStdErr);
+ Init_Errata_Logging();
+
+ static int const POLL_FD_COUNT = 1;
+ pollfd pfa[POLL_FD_COUNT];
+
+ // Poll on the socket.
+ pfa[0].fd = wcp.getSocket();
+ pfa[0].events = POLLIN;
+
+ wcp.housekeeping();
+
+ while (true) {
+ //time_t dt = std::min(wccp::TIME_UNIT, wcp.waitTime());
+ //printf("Waiting %lu milliseconds\n", dt * 1000);
+ int n = poll(pfa, POLL_FD_COUNT, 1000);
+ if (n < 0) { // error
+ perror("General polling failure");
+ return 5;
+ } else if (n > 0) { // things of interest happened
+ if (pfa[0].revents) {
+ if (pfa[0].revents & POLLIN) {
+ wcp.handleMessage();
+ } else {
+ fprintf(stderr, "Socket failure.\n");
+ return 6;
+ }
+ }
+ } else { // timeout
+ wcp.housekeeping();
+ }
+ }
+}