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