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

Reply via email to