]>
Commit | Line | Data |
---|---|---|
5f623035 | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 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 | |
22 | namespace Ping | |
23 | { | |
24 | Ping::TheConfig Config; | |
25 | ||
26 | /// measurements collected by the squidclient ping mode logics | |
27 | class pingStats_ | |
28 | { | |
29 | public: | |
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 | */ | |
45 | static void | |
46 | catchSignal(int sig) | |
47 | { | |
48 | Ping::DisplayStats(); | |
49 | Ping::Config.enable = false; | |
50 | std::cerr << "SIGNAL " << sig << " Interrupted." << std::endl; | |
51 | } | |
52 | ||
53 | uint32_t | |
54 | Ping::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 | ||
76 | static struct timeval tv1, tv2; | |
77 | ||
78 | void | |
79 | Ping::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 | ||
91 | void | |
92 | Ping::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 | ||
140 | void | |
141 | Ping::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 | ||
154 | void | |
155 | Ping::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 | ||
166 | bool | |
167 | Ping::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 |