]> git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/pinger.cc
Merge from trunk
[thirdparty/squid.git] / src / icmp / pinger.cc
1 /*
2 * $Id$
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 #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_MSWIN_ */
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 _db_init(NULL, debug_args);
152
153 debugs(42, 0, "pinger: Initialising ICMP pinger ...");
154
155 icmp4_worker = icmp4.Open();
156 if (icmp4_worker < 0) {
157 debugs(42, 0, "pinger: Unable to start ICMP pinger.");
158 }
159 max_fd = max(max_fd, icmp4_worker);
160
161 #if USE_IPV6
162 icmp6_worker = icmp6.Open();
163 if (icmp6_worker <0 ) {
164 debugs(42, 0, "pinger: Unable to start ICMPv6 pinger.");
165 }
166 max_fd = max(max_fd, icmp6_worker);
167 #endif
168
169 /** abort if neither worker could open a socket. */
170 if (icmp4_worker < 0 && icmp6_worker < 0) {
171 debugs(42, 0, "FATAL: pinger: Unable to open any ICMP sockets.");
172 exit(1);
173 }
174
175 if ( (squid_link = control.Open()) < 0) {
176 debugs(42, 0, "FATAL: pinger: Unable to setup Pinger control sockets.");
177 icmp4.Close();
178 icmp6.Close();
179 exit(1); // fatal error if the control channel fails.
180 }
181 max_fd = max(max_fd, squid_link);
182
183 setgid(getgid());
184 setuid(getuid());
185
186 last_check_time = squid_curtime;
187
188 for (;;) {
189 tv.tv_sec = PINGER_TIMEOUT;
190 tv.tv_usec = 0;
191 FD_ZERO(&R);
192 if (icmp4_worker >= 0) {
193 FD_SET(icmp4_worker, &R);
194 }
195 if (icmp6_worker >= 0) {
196 FD_SET(icmp6_worker, &R);
197 }
198
199 FD_SET(squid_link, &R);
200 x = select(10, &R, NULL, NULL, &tv);
201 getCurrentTime();
202
203 if (x < 0) {
204 debugs(42, 0, HERE << " FATAL Shutdown. select()==" << x << ", ERR: " << xstrerror());
205 control.Close();
206 exit(1);
207 }
208
209 if (FD_ISSET(squid_link, &R)) {
210 control.Recv();
211 }
212
213 if (icmp6_worker >= 0 && FD_ISSET(icmp6_worker, &R)) {
214 icmp6.Recv();
215 }
216 if (icmp4_worker >= 0 && FD_ISSET(icmp4_worker, &R)) {
217 icmp4.Recv();
218 }
219
220 if (PINGER_TIMEOUT + last_check_time < squid_curtime) {
221 if (send(LINK_TO_SQUID, &tv, 0, 0) < 0) {
222 debugs(42, 0, "pinger: Closing. No requests in last " << PINGER_TIMEOUT << " seconds.");
223 control.Close();
224 exit(1);
225 }
226
227 last_check_time = squid_curtime;
228 }
229 }
230
231 /* NOTREACHED */
232 return 0;
233 }
234
235 #else
236 #include <stdio.h>
237 int
238 main(int argc, char *argv[])
239 {
240 fprintf(stderr, "%s: ICMP support not compiled in.\n", argv[0]);
241 return 1;
242 }
243
244 #endif /* USE_ICMP */