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