> On Jan 8, 2015, at 1:49 PM, James Peach <jpe...@apache.org> wrote:
> 
> Should this be cmd/traffic_wccp?

+1.


Also, a comment on printf() style: Instead of using e.g. “%lu” as you do, we 
generally prefer that you use an appropriate stdint definition, based on what 
the type of the argument is. So, quickly glancing at the code, some of the 
places where you use %lu the type is uint32_t. That means that the tag in the 
format string should be “%” PRIu32 “ …”. This will guarantee it works on all 
platforms properly, regardless of what the size of a “unsigned long” is.

I know we’re not particularly consistent on this, but since this is new code, I 
figure it’d be worthwhile to get it right from the get-go :).

Cheers,

— leif

> 
>> 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();
>> +    }
>> +  }
>> +}
>> 
> 

Reply via email to