]> git.ipfire.org Git - thirdparty/squid.git/blame - tools/squidclient/Ping.cc
squidclient: --ping mode module support
[thirdparty/squid.git] / tools / squidclient / Ping.cc
CommitLineData
842cd45a
AJ
1#include "squid.h"
2#include "SquidTime.h"
3#include "tools/squidclient/Parameters.h"
4#include "tools/squidclient/Ping.h"
5
6#include <iostream>
7
8#if HAVE_GETOPT_H
9#include <getopt.h>
10#endif
11#if HAVE_SIGNAL_H
12#include <signal.h>
13#endif
14
15namespace Ping
16{
17Ping::TheConfig Config;
18
19/// measurements collected by the squidclient ping mode logics
20class pingStats_
21{
22public:
23 pingStats_() {memset(this, 0, sizeof(pingStats_));}
24
25 long counted; ///< number of transactions which have so far been measured
26 long pMin; ///< shortest transaction time seen
27 long pMax; ///< longest transaction time seen
28 long sum; ///< total time so far spent waiting on transactions
29
30} stats;
31
32} // namespace Ping
33
34/**
35 * Signal interrupt handler for squidclient ping.
36 * Displays final statistics and disables further pings.
37 */
38static void
39catchSignal(int sig)
40{
41 Ping::DisplayStats();
42 Ping::Config.enable = false;
43 std::cerr << "SIGNAL " << sig << " Interrupted." << std::endl;
44}
45
46uint32_t
47Ping::Init()
48{
49 if (Ping::Config.enable) {
50#if HAVE_SIGACTION
51 struct sigaction sa, osa;
52 if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) {
53 sa.sa_handler = catchSignal;
54 sa.sa_flags = 0;
55 sigemptyset(&sa.sa_mask);
56 (void) sigaction(SIGINT, &sa, NULL);
57 }
58#else
59 void (*osig) (int);
60 if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL)
61 (void) signal(SIGINT, osig);
62#endif
63 return Ping::Config.count;
64 }
65
66 return 1;
67}
68
69static struct timeval tv1, tv2;
70
71void
72Ping::TimerStart()
73{
74 if (!Ping::Config.enable)
75 return;
76
77#if GETTIMEOFDAY_NO_TZP
78 (void)gettimeofday(&tv1);
79#else
80 (void)gettimeofday(&tv1, NULL);
81#endif
82}
83
84void
85Ping::TimerStop(size_t fsize)
86{
87 if (!Ping::Config.enable)
88 return;
89
90 struct tm *tmp;
91 time_t t2s;
92 long elapsed_msec;
93
94#if GETTIMEOFDAY_NO_TZP
95 (void)gettimeofday(&tv2);
96#else
97 (void)gettimeofday(&tv2, NULL);
98#endif
99
100 elapsed_msec = tvSubMsec(tv1, tv2);
101 t2s = tv2.tv_sec;
102 tmp = localtime(&t2s);
103 char tbuf[4096];
104 snprintf(tbuf, sizeof(tbuf)-1, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s",
105 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
106 tmp->tm_hour, tmp->tm_min, tmp->tm_sec, stats.counted + 1,
107 elapsed_msec / 1000, elapsed_msec % 1000,
108 elapsed_msec ? (double) fsize / elapsed_msec : -1.0);
109 std::cerr << tbuf << std::endl;
110
111 if (!stats.counted || elapsed_msec < stats.pMin)
112 stats.pMin = elapsed_msec;
113
114 if (!stats.counted || elapsed_msec > stats.pMax)
115 stats.pMax = elapsed_msec;
116
117 stats.sum += elapsed_msec;
118
119 ++stats.counted;
120
121 /* Delay until next "ping.interval" boundary */
122 if (!LoopDone(stats.counted) && elapsed_msec < Ping::Config.interval) {
123
124 struct timeval tvs;
125 long msec_left = Ping::Config.interval - elapsed_msec;
126
127 tvs.tv_sec = msec_left / 1000;
128 tvs.tv_usec = (msec_left % 1000) * 1000;
129 select(0, NULL, NULL, NULL, &tvs);
130 }
131}
132
133void
134Ping::DisplayStats()
135{
136 if (Ping::Config.enable && stats.counted) {
137 long mean = stats.sum / stats.counted;
138 std::cerr << stats.counted << " requests, round-trip (secs) min/avg/max = "
139 << (stats.pMin/1000) << "." << (stats.pMin%1000)
140 << "/" << (mean/1000) << "." << (mean%1000)
141 << "/" << (stats.pMax/1000) << "." << (stats.pMax%1000)
142 << std::endl;
143 }
144}
145
146void
147Ping::TheConfig::usage()
148{
149 std::cerr << "Ping Mode" << std::endl
150 << " --ping [options] Enable ping mode." << std::endl
151 << std::endl
152 << " options:" << std::endl
153 << " -g count Ping iteration count (default, loop until interrupted)." << std::endl
154 << " -I interval Ping interval in seconds (default 1 second)." << std::endl
155 << std::endl;
156}
157
158bool
159Ping::TheConfig::parseCommandOpts(int argc, char *argv[], int c, int &optIndex)
160{
161 // to get here --ping was seen
162 enable = true;
163 count = 0; // default is infinite loop
164 interval = 1 * 1000; // default is 1s intervals
165
166 const char *shortOpStr = "g:I:?";
167
168 // options for controlling squidclient ping mode
169 static struct option pingOptions[] = {
170 {"count", no_argument, 0, 'g'},
171 {"interval", no_argument, 0, 'I'},
172 {0, 0, 0, 0}
173 };
174
175 int saved_opterr = opterr;
176 opterr = 0; // suppress errors from getopt
177 while ((c = getopt_long(argc, argv, shortOpStr, pingOptions, &optIndex)) != -1) {
178 switch (c) {
179 case 'g':
180 if (optarg)
181 count = atoi(optarg);
182 else {
183 std::cerr << "ERROR: -g ping count missing parameter." << std::endl;
184 usage();
185 }
186 break;
187
188 case 'I':
189 if ((interval = atoi(optarg) * 1000) <= 0) {
190 std::cerr << "ERROR: -I ping interval out of range (0-" << (INT_MAX/1000) << ")." << std::endl;
191 usage();
192 }
193 break;
194
195 default:
196 // rewind and let the caller handle unknown options
197 --optind;
198 opterr = saved_opterr;
199 return true;
200 }
201 }
202
203 opterr = saved_opterr;
204 return false;
205}