]> git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/pinger.cc
Merged from trunk
[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
74 #if _SQUID_MSWIN_
75
76 #if HAVE_WINSOCK2_H
77 #include <winsock2.h>
78 #elif HAVE_WINSOCK_H
79 #include <winsock.h>
80 #endif
81 #include <process.h>
82 #include "fde.h"
83
84 #define PINGER_TIMEOUT 5
85
86 /* windows uses the control socket for feedback to squid */
87 #define LINK_TO_SQUID squid_link
88
89 // windows still requires WSAFD but there are too many dependancy problems
90 // to just link to win32.cc where it is normally defined.
91
92 int
93 Win32__WSAFDIsSet(int fd, fd_set FAR * set)
94 {
95 fde *F = &fd_table[fd];
96 SOCKET s = F->win32.handle;
97
98 return __WSAFDIsSet(s, set);
99 }
100
101 #else
102
103 #define PINGER_TIMEOUT 10
104
105 /* non-windows use STDOUT for feedback to squid */
106 #define LINK_TO_SQUID 1
107
108 #endif /* _SQUID_MSWIN_ */
109
110 // ICMP Engines are declared global here so they can call each other easily.
111 IcmpPinger control;
112 Icmp4 icmp4;
113 Icmp6 icmp6;
114
115 int icmp_pkts_sent = 0;
116
117 /**
118 \ingroup pinger
119 \par This is the pinger external process.
120 *
121 \param argc Ignored.
122 \param argv Ignored.
123 */
124 int
125 main(int argc, char *argv[])
126 {
127 fd_set R;
128 int x;
129 int max_fd = 0;
130
131 struct timeval tv;
132 const char *debug_args = "ALL,10";
133 char *t;
134 time_t last_check_time = 0;
135
136 /*
137 * cevans - do this first. It grabs a raw socket. After this we can
138 * drop privs
139 */
140 int icmp4_worker = -1;
141 int icmp6_worker = -1;
142 int squid_link = -1;
143
144 /** start by initializing the pinger debug cache.log-pinger. */
145 if ((t = getenv("SQUID_DEBUG")))
146 debug_args = xstrdup(t);
147
148 getCurrentTime();
149
150 _db_init(NULL, debug_args);
151
152 debugs(42, DBG_CRITICAL, "pinger: Initialising ICMP pinger ...");
153
154 icmp4_worker = icmp4.Open();
155 if (icmp4_worker < 0) {
156 debugs(42, DBG_CRITICAL, "pinger: Unable to start ICMP pinger.");
157 }
158 max_fd = max(max_fd, icmp4_worker);
159
160 #if USE_IPV6
161 icmp6_worker = icmp6.Open();
162 if (icmp6_worker <0 ) {
163 debugs(42, DBG_CRITICAL, "pinger: Unable to start ICMPv6 pinger.");
164 }
165 max_fd = max(max_fd, icmp6_worker);
166 #endif
167
168 /** abort if neither worker could open a socket. */
169 if (icmp4_worker < 0 && icmp6_worker < 0) {
170 debugs(42, DBG_CRITICAL, "FATAL: pinger: Unable to open any ICMP sockets.");
171 exit(1);
172 }
173
174 if ( (squid_link = control.Open()) < 0) {
175 debugs(42, DBG_CRITICAL, "FATAL: pinger: Unable to setup Pinger control sockets.");
176 icmp4.Close();
177 icmp6.Close();
178 exit(1); // fatal error if the control channel fails.
179 }
180 max_fd = max(max_fd, squid_link);
181
182 setgid(getgid());
183 setuid(getuid());
184
185 last_check_time = squid_curtime;
186
187 for (;;) {
188 tv.tv_sec = PINGER_TIMEOUT;
189 tv.tv_usec = 0;
190 FD_ZERO(&R);
191 if (icmp4_worker >= 0) {
192 FD_SET(icmp4_worker, &R);
193 }
194 if (icmp6_worker >= 0) {
195 FD_SET(icmp6_worker, &R);
196 }
197
198 FD_SET(squid_link, &R);
199 x = select(10, &R, NULL, NULL, &tv);
200 getCurrentTime();
201
202 if (x < 0) {
203 debugs(42, DBG_CRITICAL, HERE << " FATAL Shutdown. select()==" << x << ", ERR: " << xstrerror());
204 control.Close();
205 exit(1);
206 }
207
208 if (FD_ISSET(squid_link, &R)) {
209 control.Recv();
210 }
211
212 if (icmp6_worker >= 0 && FD_ISSET(icmp6_worker, &R)) {
213 icmp6.Recv();
214 }
215 if (icmp4_worker >= 0 && FD_ISSET(icmp4_worker, &R)) {
216 icmp4.Recv();
217 }
218
219 if (PINGER_TIMEOUT + last_check_time < squid_curtime) {
220 if (send(LINK_TO_SQUID, &tv, 0, 0) < 0) {
221 debugs(42, DBG_CRITICAL, "pinger: Closing. No requests in last " << PINGER_TIMEOUT << " seconds.");
222 control.Close();
223 exit(1);
224 }
225
226 last_check_time = squid_curtime;
227 }
228 }
229
230 /* NOTREACHED */
231 return 0;
232 }
233
234 #else
235 #include <stdio.h>
236 int
237 main(int argc, char *argv[])
238 {
239 fprintf(stderr, "%s: ICMP support not compiled in.\n", argv[0]);
240 return 1;
241 }
242
243 #endif /* USE_ICMP */