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