--- /dev/null
+#include "squid.h"
+#include "SquidTime.h"
+#include "tools/squidclient/Parameters.h"
+#include "tools/squidclient/Ping.h"
+
+#include <iostream>
+
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+namespace Ping
+{
+Ping::TheConfig Config;
+
+/// measurements collected by the squidclient ping mode logics
+class pingStats_
+{
+public:
+ pingStats_() {memset(this, 0, sizeof(pingStats_));}
+
+ long counted; ///< number of transactions which have so far been measured
+ long pMin; ///< shortest transaction time seen
+ long pMax; ///< longest transaction time seen
+ long sum; ///< total time so far spent waiting on transactions
+
+} stats;
+
+} // namespace Ping
+
+/**
+ * Signal interrupt handler for squidclient ping.
+ * Displays final statistics and disables further pings.
+ */
+static void
+catchSignal(int sig)
+{
+ Ping::DisplayStats();
+ Ping::Config.enable = false;
+ std::cerr << "SIGNAL " << sig << " Interrupted." << std::endl;
+}
+
+uint32_t
+Ping::Init()
+{
+ if (Ping::Config.enable) {
+#if HAVE_SIGACTION
+ struct sigaction sa, osa;
+ if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) {
+ sa.sa_handler = catchSignal;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ (void) sigaction(SIGINT, &sa, NULL);
+ }
+#else
+ void (*osig) (int);
+ if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL)
+ (void) signal(SIGINT, osig);
+#endif
+ return Ping::Config.count;
+ }
+
+ return 1;
+}
+
+static struct timeval tv1, tv2;
+
+void
+Ping::TimerStart()
+{
+ if (!Ping::Config.enable)
+ return;
+
+#if GETTIMEOFDAY_NO_TZP
+ (void)gettimeofday(&tv1);
+#else
+ (void)gettimeofday(&tv1, NULL);
+#endif
+}
+
+void
+Ping::TimerStop(size_t fsize)
+{
+ if (!Ping::Config.enable)
+ return;
+
+ struct tm *tmp;
+ time_t t2s;
+ long elapsed_msec;
+
+#if GETTIMEOFDAY_NO_TZP
+ (void)gettimeofday(&tv2);
+#else
+ (void)gettimeofday(&tv2, NULL);
+#endif
+
+ elapsed_msec = tvSubMsec(tv1, tv2);
+ t2s = tv2.tv_sec;
+ tmp = localtime(&t2s);
+ char tbuf[4096];
+ snprintf(tbuf, sizeof(tbuf)-1, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s",
+ tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec, stats.counted + 1,
+ elapsed_msec / 1000, elapsed_msec % 1000,
+ elapsed_msec ? (double) fsize / elapsed_msec : -1.0);
+ std::cerr << tbuf << std::endl;
+
+ if (!stats.counted || elapsed_msec < stats.pMin)
+ stats.pMin = elapsed_msec;
+
+ if (!stats.counted || elapsed_msec > stats.pMax)
+ stats.pMax = elapsed_msec;
+
+ stats.sum += elapsed_msec;
+
+ ++stats.counted;
+
+ /* Delay until next "ping.interval" boundary */
+ if (!LoopDone(stats.counted) && elapsed_msec < Ping::Config.interval) {
+
+ struct timeval tvs;
+ long msec_left = Ping::Config.interval - elapsed_msec;
+
+ tvs.tv_sec = msec_left / 1000;
+ tvs.tv_usec = (msec_left % 1000) * 1000;
+ select(0, NULL, NULL, NULL, &tvs);
+ }
+}
+
+void
+Ping::DisplayStats()
+{
+ if (Ping::Config.enable && stats.counted) {
+ long mean = stats.sum / stats.counted;
+ std::cerr << stats.counted << " requests, round-trip (secs) min/avg/max = "
+ << (stats.pMin/1000) << "." << (stats.pMin%1000)
+ << "/" << (mean/1000) << "." << (mean%1000)
+ << "/" << (stats.pMax/1000) << "." << (stats.pMax%1000)
+ << std::endl;
+ }
+}
+
+void
+Ping::TheConfig::usage()
+{
+ std::cerr << "Ping Mode" << std::endl
+ << " --ping [options] Enable ping mode." << std::endl
+ << std::endl
+ << " options:" << std::endl
+ << " -g count Ping iteration count (default, loop until interrupted)." << std::endl
+ << " -I interval Ping interval in seconds (default 1 second)." << std::endl
+ << std::endl;
+}
+
+bool
+Ping::TheConfig::parseCommandOpts(int argc, char *argv[], int c, int &optIndex)
+{
+ // to get here --ping was seen
+ enable = true;
+ count = 0; // default is infinite loop
+ interval = 1 * 1000; // default is 1s intervals
+
+ const char *shortOpStr = "g:I:?";
+
+ // options for controlling squidclient ping mode
+ static struct option pingOptions[] = {
+ {"count", no_argument, 0, 'g'},
+ {"interval", no_argument, 0, 'I'},
+ {0, 0, 0, 0}
+ };
+
+ int saved_opterr = opterr;
+ opterr = 0; // suppress errors from getopt
+ while ((c = getopt_long(argc, argv, shortOpStr, pingOptions, &optIndex)) != -1) {
+ switch (c) {
+ case 'g':
+ if (optarg)
+ count = atoi(optarg);
+ else {
+ std::cerr << "ERROR: -g ping count missing parameter." << std::endl;
+ usage();
+ }
+ break;
+
+ case 'I':
+ if ((interval = atoi(optarg) * 1000) <= 0) {
+ std::cerr << "ERROR: -I ping interval out of range (0-" << (INT_MAX/1000) << ")." << std::endl;
+ usage();
+ }
+ break;
+
+ default:
+ // rewind and let the caller handle unknown options
+ --optind;
+ opterr = saved_opterr;
+ return true;
+ }
+ }
+
+ opterr = saved_opterr;
+ return false;
+}
#include "ip/Address.h"
#include "ip/tools.h"
#include "rfc1123.h"
-#include "SquidTime.h"
+#include "tools/squidclient/Parameters.h"
+#include "tools/squidclient/Ping.h"
#if _SQUID_WINDOWS_
/** \cond AUTODOCS-IGNORE */
#define HEADERLEN 65536
#endif
-typedef void SIGHDLR(int sig);
-
/// display debug messages at varying verbosity levels
#define debugVerbose(LEVEL, MESSAGE) \
- while ((LEVEL) <= verbosityLevel) {std::cerr << MESSAGE << std::endl; break;}
-
-/**
- * What verbosity level to display.
- *
- * 0 : display no debug traces
- * 1 : display outgoing request message
- * 2+ : display all actions taken
- */
-int verbosityLevel = 0;
+ while ((LEVEL) <= scParams.verbosityLevel) {std::cerr << MESSAGE << std::endl; break;}
/* Local functions */
static int client_comm_bind(int, const Ip::Address &);
-static int client_comm_connect(int, const Ip::Address &, struct timeval *);
+static int client_comm_connect(int, const Ip::Address &);
static void usage(const char *progname);
-static int Now(struct timeval *);
-SIGHDLR catchSignal;
+typedef void SIGHDLR(int sig);
SIGHDLR pipe_handler;
static void set_our_signal(void);
static ssize_t myread(int fd, void *buf, size_t len);
static char *GSSAPI_token(const char *server);
#endif
+Parameters scParams;
+
static int put_fd;
static char *put_file = NULL;
usage(const char *progname)
{
std::cerr << "Version: " << VERSION << std::endl
- << "Usage: " << progname << " [Basic Options] [HTTP Options]" << std::endl
- << std::endl
- << "Basic Options:" << std::endl
- << " -g count Ping mode, perform \"count\" iterations (0 to loop until interrupted)." << std::endl
- << " -h host Send message to server on 'host'. Default is localhost." << std::endl
- << " -I interval Ping interval in seconds (default 1 second)." << std::endl
- << " -l host Specify a local IP address to bind to. Default is none." << std::endl
- << " -p port Port number on server to contact. Default is " << CACHE_HTTP_PORT << "." << std::endl
- << " -s | --quiet Silent. Do not print response message to stdout." << std::endl
- << " -T timeout Timeout value (seconds) for read/write operations" << std::endl
- << " -v | --verbose Verbose debugging. Repeat (-vv) to increase output level." << std::endl
- << " Levels:" << std::endl
- << " 1 - Print outgoing request message to stderr." << std::endl
- << " 2 - Print action trace to stderr." << std::endl
- << " --help Display this help text." << std::endl
- << std::endl
- << "HTTP Options:" << std::endl
- << " -a Do NOT include Accept: header." << std::endl
- << " -A User-Agent: header. Use \"\" to omit." << std::endl
- << " -H 'string' Extra headers to send. Use '\\n' for new lines." << std::endl
- << " -i IMS If-Modified-Since time (in Epoch seconds)." << std::endl
- << " -j hosthdr Host header content" << std::endl
- << " -k Keep the connection active. Default is to do only one request then close." << std::endl
- << " -m method Request method, default is GET." << std::endl
+ << "Usage: " << progname << " [Basic Options] [HTTP Options]" << std::endl
+ << std::endl
+ << "Basic Options:" << std::endl
+ << " -h host Send message to server on 'host'. Default is localhost." << std::endl
+ << " -l host Specify a local IP address to bind to. Default is none." << std::endl
+ << " -p port Port number on server to contact. Default is " << CACHE_HTTP_PORT << "." << std::endl
+ << " -s | --quiet Silent. Do not print response message to stdout." << std::endl
+ << " -T timeout Timeout value (seconds) for read/write operations" << std::endl
+ << " -v | --verbose Verbose debugging. Repeat (-vv) to increase output level." << std::endl
+ << " Levels:" << std::endl
+ << " 1 - Print outgoing request message to stderr." << std::endl
+ << " 2 - Print action trace to stderr." << std::endl
+ << " --help Display this help text." << std::endl
+ << std::endl;
+ Ping::Config.usage();
+ std::cerr
+ << "HTTP Options:" << std::endl
+ << " -a Do NOT include Accept: header." << std::endl
+ << " -A User-Agent: header. Use \"\" to omit." << std::endl
+ << " -H 'string' Extra headers to send. Use '\\n' for new lines." << std::endl
+ << " -i IMS If-Modified-Since time (in Epoch seconds)." << std::endl
+ << " -j hosthdr Host header content" << std::endl
+ << " -k Keep the connection active. Default is to do only one request then close." << std::endl
+ << " -m method Request method, default is GET." << std::endl
#if HAVE_GSSAPI
- << " -n Proxy Negotiate(Kerberos) authentication" << std::endl
- << " -N WWW Negotiate(Kerberos) authentication" << std::endl
-#endif
- << " -P file Send content from the named file as request payload" << std::endl
- << " -r Force cache to reload URL" << std::endl
- << " -t count Trace count cache-hops" << std::endl
- << " -u user Proxy authentication username" << std::endl
- << " -U user WWW authentication username" << std::endl
- << " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case" << std::endl
- << " -w password Proxy authentication password" << std::endl
- << " -W password WWW authentication password" << std::endl
- ;
+ << " -n Proxy Negotiate(Kerberos) authentication" << std::endl
+ << " -N WWW Negotiate(Kerberos) authentication" << std::endl
+#endif
+ << " -P file Send content from the named file as request payload" << std::endl
+ << " -r Force cache to reload URL" << std::endl
+ << " -t count Trace count cache-hops" << std::endl
+ << " -u user Proxy authentication username" << std::endl
+ << " -U user WWW authentication username" << std::endl
+ << " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case" << std::endl
+ << " -w password Proxy authentication password" << std::endl
+ << " -W password WWW authentication password" << std::endl
+ ;
exit(1);
}
-static int interrupted = 0;
int
main(int argc, char *argv[])
{
int conn, len, bytesWritten;
uint16_t port;
bool to_stdout, reload;
- int ping, pcount;
int keep_alive = 0;
int opt_noaccept = 0;
#if HAVE_GSSAPI
time_t ims = 0;
int max_forwards = -1;
- struct timeval tv1, tv2;
- int i = 0, loops;
- long ping_int;
- long ping_min = 0, ping_max = 0, ping_sum = 0, ping_mean = 0;
+ int i = 0;
const char *proxy_user = NULL;
const char *proxy_password = NULL;
const char *www_user = NULL;
port = CACHE_HTTP_PORT;
to_stdout = true;
reload = false;
- ping = 0;
- pcount = 0;
- ping_int = 1 * 1000;
Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
if (argc < 2 || argv[argc-1][0] == '-') {
url[BUFSIZ - 1] = '\0';
int optIndex = 0;
- const char *shortOpStr = "aA:h:j:V:l:P:i:kmnN:p:rsvt:g:p:I:H:T:u:U:w:W:?";
+ const char *shortOpStr = "aA:h:j:V:l:P:i:kmnN:p:rsvt:p:H:T:u:U:w:W:?";
// options for controlling squidclient
- static struct option basicOptions[] =
- {
- /* These are the generic options for squidclient itself */
- {"help", no_argument, 0, '?'},
- {"verbose", no_argument, 0, 'v'},
- {"quiet", no_argument, 0, 's'},
- {0, 0, 0, 0}
+ static struct option basicOptions[] = {
+ /* These are the generic options for squidclient itself */
+ {"help", no_argument, 0, '?'},
+ {"verbose", no_argument, 0, 'v'},
+ {"quiet", no_argument, 0, 's'},
+ {"ping", no_argument, 0, '\1'},
+ {0, 0, 0, 0}
};
int c;
while ((c = getopt_long(argc, argv, shortOpStr, basicOptions, &optIndex)) != -1) {
+
+ // modules parse their own specific options
switch (c) {
+ case '\1':
+ to_stdout = 0;
+ if (Ping::Config.parseCommandOpts(argc, argv, c, optIndex))
+ continue;
+ break;
+
+ default: // fall through to next switch
+ break;
+ }
+
+ switch (c) {
+
+ case '\0': // dummy value for end-of-options
+ break;
case 'a':
opt_noaccept = 1;
max_forwards = atoi(optarg);
break;
- case 'g':
- ping = 1;
- pcount = atoi(optarg);
- to_stdout = 0;
- break;
-
- case 'I':
- if ((ping_int = atoi(optarg) * 1000) <= 0)
- usage(argv[0]);
- break;
-
case 'H':
if (strlen(optarg)) {
char *t;
case 'v':
/* undocumented: may increase verb-level by giving more -v's */
- ++verbosityLevel;
- debugVerbose(2, "verbosity level set to " << verbosityLevel);
+ ++scParams.verbosityLevel;
+ debugVerbose(2, "verbosity level set to " << scParams.verbosityLevel);
break;
case '?': /* usage */
debugVerbose(1, "Request:" << std::endl << msg << std::endl << ".");
- if (ping) {
-#if HAVE_SIGACTION
-
- struct sigaction sa, osa;
-
- if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) {
- sa.sa_handler = catchSignal;
- sa.sa_flags = 0;
- sigemptyset(&sa.sa_mask);
- (void) sigaction(SIGINT, &sa, NULL);
- }
-#else
- void (*osig) (int);
-
- if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL)
- (void) signal(SIGINT, osig);
-
-#endif
-
- }
- loops = ping ? pcount : 1;
+ uint32_t loops = Ping::Init();
for (i = 0; loops == 0 || i < loops; ++i) {
- int fsize = 0;
+ size_t fsize = 0;
struct addrinfo *AI = NULL;
debugVerbose(2, "Resolving... " << hostname);
debugVerbose(2, "Connecting... " << hostname << " (" << iaddr << ")");
- if (client_comm_connect(conn, iaddr, ping ? &tv1 : NULL) < 0) {
+ if (client_comm_connect(conn, iaddr) < 0) {
char hostnameBuf[MAX_IPSTRLEN];
iaddr.toUrl(hostnameBuf, MAX_IPSTRLEN);
std::cerr << "ERROR: Cannot connect to " << hostnameBuf
(void) close(conn); /* done with socket */
- if (interrupted)
+ if (Ping::LoopDone(i))
break;
- if (ping) {
-
- struct tm *tmp;
- time_t t2s;
- long elapsed_msec;
-
- (void) Now(&tv2);
- elapsed_msec = tvSubMsec(tv1, tv2);
- t2s = tv2.tv_sec;
- tmp = localtime(&t2s);
- char tbuf[4096];
- snprintf(tbuf, sizeof(tbuf)-1, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s",
- tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec, i + 1,
- elapsed_msec / 1000, elapsed_msec % 1000,
- elapsed_msec ? (double) fsize / elapsed_msec : -1.0);
- std::cerr << tbuf << std::endl;
-
- if (i == 0 || elapsed_msec < ping_min)
- ping_min = elapsed_msec;
-
- if (i == 0 || elapsed_msec > ping_max)
- ping_max = elapsed_msec;
-
- ping_sum += elapsed_msec;
-
- /* Delay until next "ping_int" boundary */
- if ((loops == 0 || i + 1 < loops) && elapsed_msec < ping_int) {
-
- struct timeval tvs;
- long msec_left = ping_int - elapsed_msec;
-
- tvs.tv_sec = msec_left / 1000;
- tvs.tv_usec = (msec_left % 1000) * 1000;
- select(0, NULL, NULL, NULL, &tvs);
- }
- }
+ Ping::TimerStop(fsize);
}
- if (ping && i) {
- ping_mean = ping_sum / i;
- std::cerr << i << " requests, round-trip (secs) min/avg/max = "
- << (ping_min/1000) << "." << (ping_min%1000)
- << "/" << (ping_mean/1000) << "." << (ping_mean%1000)
- << "/" << (ping_max/1000) << "." << (ping_max%1000)
- << std::endl;
- }
+ Ping::DisplayStats();
return 0;
}
/// Set up the destination socket address for message to send to.
static int
-client_comm_connect(int sock, const Ip::Address &addr, struct timeval *tvp)
+client_comm_connect(int sock, const Ip::Address &addr)
{
static struct addrinfo *AI = NULL;
addr.getAddrInfo(AI);
int res = connect(sock, AI->ai_addr, AI->ai_addrlen);
Ip::Address::FreeAddrInfo(AI);
- if (tvp)
- (void) Now(tvp);
+ Ping::TimerStart();
return res;
}
-static int
-Now(struct timeval *tp)
-{
-#if GETTIMEOFDAY_NO_TZP
- return gettimeofday(tp);
-#else
- return gettimeofday(tp, NULL);
-#endif
-}
-
-void
-catchSignal(int sig)
-{
- interrupted = 1;
- std::cerr << "SIGNAL " << sig << " Interrupted." << std::endl;
-}
-
void
pipe_handler(int sig)
{