Should this be cmd/traffic_wccp?
> 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();
> + }
> + }
> +}
>