]> git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/pinger.cc
Merged from trunk
[thirdparty/squid.git] / src / icmp / pinger.cc
1 /*
2 * $Id: pinger.cc,v 1.62 2008/02/26 21:49:35 amosjeffries Exp $
3 *
4 * DEBUG: section 42 ICMP Pinger program
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 #define SQUID_HELPER 1
36
37 /**
38 \defgroup pinger pinger
39 \ingroup ExternalPrograms
40 \par
41 * Although it would be possible for Squid to send and receive
42 * ICMP messages directly, we use an external process for
43 * two important reasons:
44 *
45 \li Because squid handles many filedescriptors simultaneously,
46 * we get much more accurate RTT measurements when ICMP is
47 * handled by a separate process.
48 *
49 \li Superuser privileges are required to send and receive ICMP.
50 * Rather than require Squid to be started as root, we prefer
51 * to have the smaller and simpler pinger program installed
52 * with setuid permissions.
53 *
54 \par
55 * If you want to use Squid's ICMP features (highly recommended!)
56 * When USE_ICMP is defined, Squid will send ICMP pings
57 * to origin server sites.
58 * This information is used in numerous ways:
59 \li - Sent in ICP replies so neighbor caches know how close
60 * you are to the source.
61 \li - For finding the closest instance of a URN.
62 \li - With the 'test_reachability' option. Squid will return
63 * ICP_OP_MISS_NOFETCH for sites which it cannot ping.
64 */
65
66 #include "squid.h"
67 #include "SquidTime.h"
68
69 #if USE_ICMP
70
71 #include "Icmp4.h"
72 #include "Icmp6.h"
73 #include "IcmpPinger.h"
74
75 #ifdef _SQUID_MSWIN_
76
77 #if HAVE_WINSOCK2_H
78 #include <winsock2.h>
79 #endif
80 #include <process.h>
81 #include "fde.h"
82
83 #define PINGER_TIMEOUT 5
84
85 /* windows uses the control socket for feedback to squid */
86 #define LINK_TO_SQUID squid_link
87
88 // windows still requires WSAFD but there are too many dependancy problems
89 // to just link to win32.cc where it is normally defined.
90
91 int
92 Win32__WSAFDIsSet(int fd, fd_set FAR * set)
93 {
94 fde *F = &fd_table[fd];
95 SOCKET s = F->win32.handle;
96
97 return __WSAFDIsSet(s, set);
98 }
99
100 #else
101
102 #define PINGER_TIMEOUT 10
103
104 /* non-windows use STDOUT for feedback to squid */
105 #define LINK_TO_SQUID 1
106
107 #endif /* _SQUID_MSWIN_ */
108
109 // ICMP Engines are declared global here so they can call each other easily.
110 IcmpPinger control;
111 Icmp4 icmp4;
112 #if USE_IPV6
113 Icmp6 icmp6;
114 #endif
115
116 int icmp_pkts_sent = 0;
117
118 /**
119 \ingroup pinger
120 \par This is the pinger external process.
121 *
122 \param argc Ignored.
123 \param argv Ignored.
124 */
125 int
126 main(int argc, char *argv[])
127 {
128 fd_set R;
129 int x;
130 int max_fd = 0;
131
132 struct timeval tv;
133 const char *debug_args = "ALL,10";
134 char *t;
135 time_t last_check_time = 0;
136
137 /*
138 * cevans - do this first. It grabs a raw socket. After this we can
139 * drop privs
140 */
141 int icmp4_worker = -1;
142 #if USE_IPV6
143 int icmp6_worker = -1;
144 #endif
145 int squid_link = -1;
146
147 /** start by initializing the pinger debug cache.log-pinger. */
148 if ((t = getenv("SQUID_DEBUG")))
149 debug_args = xstrdup(t);
150
151 getCurrentTime();
152
153 _db_init(NULL, debug_args);
154
155 debugs(42, 0, "pinger: Initialising ICMP pinger ...");
156
157 icmp4_worker = icmp4.Open();
158 if (icmp4_worker < 0) {
159 debugs(42, 0, "pinger: Unable to start ICMP pinger.");
160 }
161 max_fd = max(max_fd, icmp4_worker);
162
163 #if USE_IPV6
164 icmp6_worker = icmp6.Open();
165 if (icmp6_worker <0 ) {
166 debugs(42, 0, "pinger: Unable to start ICMPv6 pinger.");
167 }
168 max_fd = max(max_fd, icmp6_worker);
169 #endif
170
171 /** abort if neither worker could open a socket. */
172 if (icmp4_worker == -1) {
173 #if USE_IPV6
174 if (icmp6_worker == -1)
175 #endif
176 {
177 debugs(42, 0, "FATAL: pinger: Unable to open any ICMP sockets.");
178 exit(1);
179 }
180 }
181
182 if ( (squid_link = control.Open()) < 0) {
183 debugs(42, 0, "FATAL: pinger: Unable to setup Pinger control sockets.");
184 icmp4.Close();
185 #if USE_IPV6
186 icmp6.Close();
187 #endif
188 exit(1); // fatal error if the control channel fails.
189 }
190 max_fd = max(max_fd, squid_link);
191
192 setgid(getgid());
193 setuid(getuid());
194
195 for (;;) {
196 tv.tv_sec = PINGER_TIMEOUT;
197 tv.tv_usec = 0;
198 FD_ZERO(&R);
199 if (icmp4_worker >= 0) {
200 FD_SET(icmp4_worker, &R);
201 }
202 #if USE_IPV6
203
204 if (icmp6_worker >= 0) {
205 FD_SET(icmp6_worker, &R);
206 }
207 #endif
208 FD_SET(squid_link, &R);
209 x = select(10, &R, NULL, NULL, &tv);
210 getCurrentTime();
211
212 if (x < 0) {
213 debugs(42, 0, HERE << " FATAL Shutdown. select()==" << x << ", ERR: " << xstrerror());
214 control.Close();
215 exit(1);
216 }
217
218 if (FD_ISSET(squid_link, &R)) {
219 control.Recv();
220 }
221
222 #if USE_IPV6
223 if (icmp6_worker >= 0 && FD_ISSET(icmp6_worker, &R)) {
224 icmp6.Recv();
225 }
226 #endif
227
228 if (icmp4_worker >= 0 && FD_ISSET(icmp4_worker, &R)) {
229 icmp4.Recv();
230 }
231
232 if (PINGER_TIMEOUT + last_check_time < squid_curtime) {
233 if (send(LINK_TO_SQUID, &tv, 0, 0) < 0) {
234 debugs(42, 0, "pinger: Closing. No requests in last " << PINGER_TIMEOUT << " seconds.");
235 control.Close();
236 exit(1);
237 }
238
239 last_check_time = squid_curtime;
240 }
241 }
242
243 /* NOTREACHED */
244 return 0;
245 }
246
247 #else
248 #include <stdio.h>
249 int
250 main(int argc, char *argv[])
251 {
252 fprintf(stderr, "%s: ICMP support not compiled in.\n", argv[0]);
253 return 1;
254 }
255
256 #endif /* USE_ICMP */