]> git.ipfire.org Git - thirdparty/squid.git/blob - src/wccp.cc
Renamed squid.h to squid-old.h and config.h to squid.h.
[thirdparty/squid.git] / src / wccp.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 80 WCCP Support
6 * AUTHOR: Glenn Chisholm
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35 #include "squid.h"
36
37 #if USE_WCCP
38
39 #include "squid-old.h"
40 #include "comm.h"
41 #include "comm/Connection.h"
42 #include "comm/Loops.h"
43 #include "event.h"
44
45 #define WCCP_PORT 2048
46 #define WCCP_REVISION 0
47 #define WCCP_ACTIVE_CACHES 32
48 #define WCCP_HASH_SIZE 32
49 #define WCCP_BUCKETS 256
50 #define WCCP_CACHE_LEN 4
51
52 #define WCCP_HERE_I_AM 7
53 #define WCCP_I_SEE_YOU 8
54 #define WCCP_ASSIGN_BUCKET 9
55
56 struct wccp_here_i_am_t {
57 int type;
58 int version;
59 int revision;
60 char hash[WCCP_HASH_SIZE];
61 int reserved;
62 int id;
63 };
64
65 struct wccp_cache_entry_t {
66 struct in_addr ip_addr; // WCCP on-the-wire in 32-bit IPv4-only.
67 int revision;
68 char hash[WCCP_HASH_SIZE];
69 int reserved;
70 };
71
72 struct wccp_i_see_you_t {
73 int32_t type;
74 int32_t version;
75 int32_t change;
76 int32_t id;
77 int32_t number;
78
79 struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES];
80 };
81
82 struct wccp_assign_bucket_t {
83 int type;
84 int id;
85 int number;
86 };
87
88 static int theWccpConnection = -1;
89
90 static struct wccp_here_i_am_t wccp_here_i_am;
91
92 static struct wccp_i_see_you_t wccp_i_see_you;
93 static int last_change;
94 static int last_id;
95 static int last_assign_buckets_change;
96 static unsigned int number_caches;
97
98 static Ip::Address local_ip;
99
100 static PF wccpHandleUdp;
101 static int wccpLowestIP(void);
102 static EVH wccpHereIam;
103 static void wccpAssignBuckets(void);
104
105 /*
106 * The functions used during startup:
107 * wccpInit
108 * wccpConnectionOpen
109 * wccpConnectionShutdown
110 * wccpConnectionClose
111 */
112
113 void
114 wccpInit(void)
115 {
116 debugs(80, 5, "wccpInit: Called");
117 memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
118 wccp_here_i_am.type = htonl(WCCP_HERE_I_AM);
119 wccp_here_i_am.version = htonl(Config.Wccp.version);
120 wccp_here_i_am.revision = htonl(WCCP_REVISION);
121 last_change = 0;
122 last_id = 0;
123 last_assign_buckets_change = 0;
124 number_caches = 0;
125
126 if (!Config.Wccp.router.IsAnyAddr())
127 if (!eventFind(wccpHereIam, NULL))
128 eventAdd("wccpHereIam", wccpHereIam, NULL, 5.0, 1);
129 }
130
131 void
132 wccpConnectionOpen(void)
133 {
134 debugs(80, 5, "wccpConnectionOpen: Called");
135
136 if (Config.Wccp.router.IsAnyAddr()) {
137 debugs(80, 2, "WCCPv1 disabled.");
138 return;
139 }
140
141 if ( !Config.Wccp.router.SetIPv4() ) {
142 debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Router " << Config.Wccp.router << " is not an IPv4 address.");
143 return;
144 }
145
146 if ( !Config.Wccp.address.SetIPv4() ) {
147 debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Local address " << Config.Wccp.address << " is not an IPv4 address.");
148 return;
149 }
150
151 Config.Wccp.address.SetPort(WCCP_PORT);
152 Config.Wccp.router.SetPort(WCCP_PORT);
153
154 theWccpConnection = comm_open_listener(SOCK_DGRAM,
155 IPPROTO_UDP,
156 Config.Wccp.address,
157 COMM_NONBLOCKING,
158 "WCCP Socket");
159
160 if (theWccpConnection < 0)
161 fatal("Cannot open WCCP Port");
162
163 Comm::SetSelect(theWccpConnection, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
164
165 debugs(80, 1, "Accepting WCCPv1 messages on " << Config.Wccp.address << ", FD " << theWccpConnection << ".");
166
167
168 // Sadly WCCP only does IPv4
169
170 struct sockaddr_in router;
171 Config.Wccp.router.GetSockAddr(router);
172 if (connect(theWccpConnection, (struct sockaddr*)&router, sizeof(router)))
173 fatal("Unable to connect WCCP out socket");
174
175 struct sockaddr_in local;
176 memset(&local, '\0', sizeof(local));
177 socklen_t slen = sizeof(local);
178 if (getsockname(theWccpConnection, (struct sockaddr*)&local, &slen))
179 fatal("Unable to getsockname on WCCP out socket");
180
181 local_ip = local;
182 }
183
184
185 void
186 wccpConnectionClose(void)
187 {
188 if (theWccpConnection > -1) {
189 debugs(80, 1, "FD " << theWccpConnection << " Closing WCCPv1 socket");
190 comm_close(theWccpConnection);
191 theWccpConnection = -1;
192 }
193 }
194
195 /*
196 * Functions for handling the requests.
197 */
198
199 /*
200 * Accept the UDP packet
201 */
202 static void
203 wccpHandleUdp(int sock, void *not_used)
204 {
205 Ip::Address from;
206 int len;
207
208 debugs(80, 6, "wccpHandleUdp: Called.");
209
210 Comm::SetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
211
212 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
213
214 len = comm_udp_recvfrom(sock,
215 (void *) &wccp_i_see_you,
216 sizeof(wccp_i_see_you),
217 0,
218 from);
219 debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " << from <<
220 ": type=" <<
221 (unsigned) ntohl(wccp_i_see_you.type) << ", version=" <<
222 (unsigned) ntohl(wccp_i_see_you.version) << ", change=" <<
223 (unsigned) ntohl(wccp_i_see_you.change) << ", id=" <<
224 (unsigned) ntohl(wccp_i_see_you.id) << ", number=" <<
225 (unsigned) ntohl(wccp_i_see_you.number));
226
227 if (len < 0)
228 return;
229
230 if (from != Config.Wccp.router)
231 return;
232
233 if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
234 return;
235
236 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
237 return;
238
239 if (ntohl(wccp_i_see_you.number) > WCCP_ACTIVE_CACHES) {
240 debugs(80, 1, "Ignoring WCCP_I_SEE_YOU from " <<
241 from << " with number of caches set to " <<
242 (int) ntohl(wccp_i_see_you.number));
243
244 return;
245 }
246
247 last_id = wccp_i_see_you.id;
248
249 if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
250 if (last_assign_buckets_change == wccp_i_see_you.change) {
251 /*
252 * After a WCCP_ASSIGN_BUCKET message, the router should
253 * update the change value. If not, maybe the route didn't
254 * receive our WCCP_ASSIGN_BUCKET message, so send it again.
255 *
256 * Don't update change here. Instead, fall through to
257 * the next block to call wccpAssignBuckets() again.
258 */
259 (void) 0;
260 } else {
261 last_change = wccp_i_see_you.change;
262 return;
263 }
264 }
265
266 if (last_change != wccp_i_see_you.change) {
267 last_change = wccp_i_see_you.change;
268
269 if (wccpLowestIP() && wccp_i_see_you.number) {
270 last_assign_buckets_change = last_change;
271 wccpAssignBuckets();
272 }
273 }
274 }
275
276 static int
277 wccpLowestIP(void)
278 {
279 unsigned int loop;
280 int found = 0;
281
282 /*
283 * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
284 */
285
286 for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); loop++) {
287 assert(loop < WCCP_ACTIVE_CACHES);
288
289 if (local_ip > wccp_i_see_you.wccp_cache_entry[loop].ip_addr)
290 return 0;
291
292 if (local_ip == wccp_i_see_you.wccp_cache_entry[loop].ip_addr)
293 found = 1;
294 }
295
296 return found;
297 }
298
299 static void
300 wccpHereIam(void *voidnotused)
301 {
302 debugs(80, 6, "wccpHereIam: Called");
303
304 wccp_here_i_am.id = last_id;
305 comm_udp_send(theWccpConnection,
306 &wccp_here_i_am,
307 sizeof(wccp_here_i_am),
308 0);
309
310 if (!eventFind(wccpHereIam, NULL))
311 eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
312 }
313
314 static void
315 wccpAssignBuckets(void)
316 {
317
318 struct wccp_assign_bucket_t *wccp_assign_bucket;
319 int wab_len;
320 char *buckets;
321 int buckets_per_cache;
322 unsigned int loop;
323 int bucket = 0;
324 int *caches;
325 int cache_len;
326 char *buf;
327
328 debugs(80, 6, "wccpAssignBuckets: Called");
329 number_caches = ntohl(wccp_i_see_you.number);
330
331 assert(number_caches > 0);
332 assert(number_caches <= WCCP_ACTIVE_CACHES);
333
334 wab_len = sizeof(struct wccp_assign_bucket_t);
335
336 cache_len = WCCP_CACHE_LEN * number_caches;
337
338 buf = (char *)xmalloc(wab_len +
339 WCCP_BUCKETS +
340 cache_len);
341
342 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
343
344 caches = (int *) (buf + wab_len);
345
346 buckets = buf + wab_len + cache_len;
347
348 memset(wccp_assign_bucket, '\0', sizeof(*wccp_assign_bucket));
349
350 memset(buckets, 0xFF, WCCP_BUCKETS);
351
352 buckets_per_cache = WCCP_BUCKETS / number_caches;
353
354 for (loop = 0; loop < number_caches; loop++) {
355 int i;
356 memcpy(&caches[loop],
357 &wccp_i_see_you.wccp_cache_entry[loop].ip_addr,
358 sizeof(*caches));
359
360 for (i = 0; i < buckets_per_cache; i++) {
361 assert(bucket < WCCP_BUCKETS);
362 buckets[bucket++] = loop;
363 }
364 }
365
366 while (bucket < WCCP_BUCKETS) {
367 buckets[bucket++] = number_caches - 1;
368 }
369
370 wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
371 wccp_assign_bucket->id = wccp_i_see_you.id;
372 wccp_assign_bucket->number = wccp_i_see_you.number;
373
374 comm_udp_send(theWccpConnection,
375 buf,
376 wab_len + WCCP_BUCKETS + cache_len,
377 0);
378 last_change = 0;
379 xfree(buf);
380 }
381
382 #endif /* USE_WCCP */