]>
Commit | Line | Data |
---|---|---|
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 | ||
15 | namespace Ping | |
16 | { | |
17 | Ping::TheConfig Config; | |
18 | ||
19 | /// measurements collected by the squidclient ping mode logics | |
20 | class pingStats_ | |
21 | { | |
22 | public: | |
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 | */ | |
38 | static void | |
39 | catchSignal(int sig) | |
40 | { | |
41 | Ping::DisplayStats(); | |
42 | Ping::Config.enable = false; | |
43 | std::cerr << "SIGNAL " << sig << " Interrupted." << std::endl; | |
44 | } | |
45 | ||
46 | uint32_t | |
47 | Ping::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 | ||
69 | static struct timeval tv1, tv2; | |
70 | ||
71 | void | |
72 | Ping::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 | ||
84 | void | |
85 | Ping::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 | ||
133 | void | |
134 | Ping::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 | ||
146 | void | |
147 | Ping::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 | ||
158 | bool | |
159 | Ping::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 | } |