]> git.ipfire.org Git - thirdparty/squid.git/blame - src/wccp.cc
Updates for running on squid-cache.org
[thirdparty/squid.git] / src / wccp.cc
CommitLineData
320e9f36 1
2/*
cc192b50 3 * $Id: wccp.cc,v 1.45 2007/12/14 23:11:48 amosjeffries Exp $
320e9f36 4 *
7e3ce7b9 5 * DEBUG: section 80 WCCP Support
320e9f36 6 * AUTHOR: Glenn Chisholm
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
320e9f36 9 * ----------------------------------------------------------
10 *
2b6662ba 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.
320e9f36 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.
2b6662ba 24 *
320e9f36 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.
2b6662ba 29 *
320e9f36 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"
063dc1eb 36#include "comm.h"
a553a5a3 37#include "event.h"
320e9f36 38
eb824054 39#if USE_WCCP
40
320e9f36 41#define WCCP_PORT 2048
320e9f36 42#define WCCP_REVISION 0
320e9f36 43#define WCCP_ACTIVE_CACHES 32
44#define WCCP_HASH_SIZE 32
45#define WCCP_BUCKETS 256
7e3ce7b9 46#define WCCP_CACHE_LEN 4
320e9f36 47
48#define WCCP_HERE_I_AM 7
49#define WCCP_I_SEE_YOU 8
50#define WCCP_ASSIGN_BUCKET 9
51
62e76326 52struct wccp_here_i_am_t
53{
320e9f36 54 int type;
55 int version;
56 int revision;
57 char hash[WCCP_HASH_SIZE];
58 int reserved;
59 int id;
60};
61
62e76326 62struct wccp_cache_entry_t
63{
cc192b50 64 IPAddress ip_addr;
320e9f36 65 int revision;
ede4c165 66 char hash[WCCP_HASH_SIZE];
320e9f36 67 int reserved;
68};
69
62e76326 70struct wccp_i_see_you_t
71{
320e9f36 72 int type;
73 int version;
74 int change;
75 int id;
76 int number;
62e76326 77
320e9f36 78 struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES];
79};
80
62e76326 81struct wccp_assign_bucket_t
82{
f6308664 83 int type;
84 int id;
85 int number;
320e9f36 86};
87
0b0cfcf2 88static int theWccpConnection = -1;
62e76326 89
320e9f36 90static struct wccp_here_i_am_t wccp_here_i_am;
62e76326 91
b5b86e2c 92static struct wccp_i_see_you_t wccp_i_see_you;
eccaff9c 93static int last_change;
94static int last_id;
1addf64a 95static int last_assign_buckets_change;
908b22c4 96static unsigned int number_caches;
62e76326 97
cc192b50 98static IPAddress local_ip;
b5b86e2c 99
1f38f50a 100static PF wccpHandleUdp;
101static int wccpLowestIP(void);
102static EVH wccpHereIam;
7e3ce7b9 103static void wccpAssignBuckets(void);
320e9f36 104
320e9f36 105/*
106 * The functions used during startup:
107 * wccpInit
108 * wccpConnectionOpen
109 * wccpConnectionShutdown
110 * wccpConnectionClose
111 */
112
113void
114wccpInit(void)
115{
bf8fe701 116 debugs(80, 5, "wccpInit: Called");
320e9f36 117 memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
118 wccp_here_i_am.type = htonl(WCCP_HERE_I_AM);
d20b1cd0 119 wccp_here_i_am.version = htonl(Config.Wccp.version);
f6308664 120 wccp_here_i_am.revision = htonl(WCCP_REVISION);
eccaff9c 121 last_change = 0;
122 last_id = 0;
1addf64a 123 last_assign_buckets_change = 0;
eccaff9c 124 number_caches = 0;
62e76326 125
cc192b50 126 if (!Config.Wccp.router.IsAnyAddr())
62e76326 127 if (!eventFind(wccpHereIam, NULL))
128 eventAdd("wccpHereIam", wccpHereIam, NULL, 5.0, 1);
320e9f36 129}
130
131void
132wccpConnectionOpen(void)
133{
cc192b50 134 struct addrinfo *router = NULL, *local = NULL;
bf8fe701 135 debugs(80, 5, "wccpConnectionOpen: Called");
62e76326 136
cc192b50 137 if (Config.Wccp.router.IsAnyAddr()) {
76dc4ca3 138 debugs(80, 2, "WCCPv1 disabled.");
62e76326 139 return;
1f38f50a 140 }
62e76326 141
cc192b50 142 if ( !Config.Wccp.router.SetIPv4() ) {
143 debugs(1, 1, "WCCPv1 Disabled. Router " << Config.Wccp.router << " is not IPv4.");
144 return;
145 }
146
147 if ( !Config.Wccp.address.SetIPv4() ) {
148 debugs(1, 1, "WCCPv1 Disabled. Local address " << Config.Wccp.address << " is not IPv4.");
149 return;
150 }
151
152 Config.Wccp.address.SetPort(WCCP_PORT);
153
0b0cfcf2 154 theWccpConnection = comm_open(SOCK_DGRAM,
155 IPPROTO_UDP,
156 Config.Wccp.address,
0b0cfcf2 157 COMM_NONBLOCKING,
158 "WCCP Socket");
62e76326 159
0b0cfcf2 160 if (theWccpConnection < 0)
62e76326 161 fatal("Cannot open WCCP Port");
162
0b0cfcf2 163 commSetSelect(theWccpConnection,
62e76326 164 COMM_SELECT_READ,
165 wccpHandleUdp,
166 NULL,
167 0);
168
cc192b50 169 debugs(80, 1, "Accepting WCCPv1 messages on " << Config.Wccp.address << ", FD " << theWccpConnection << ".");
0b0cfcf2 170
cc192b50 171 Config.Wccp.router.GetAddrInfo(router,AF_INET);
0b0cfcf2 172
cc192b50 173 if (connect(theWccpConnection, router->ai_addr, router->ai_addrlen))
62e76326 174 fatal("Unable to connect WCCP out socket");
175
cc192b50 176 Config.Wccp.router.FreeAddrInfo(router);
62e76326 177
cc192b50 178 Config.Wccp.address.InitAddrInfo(local);
62e76326 179
cc192b50 180 if (getsockname(theWccpConnection, local->ai_addr, &local->ai_addrlen))
62e76326 181 fatal("Unable to getsockname on WCCP out socket");
182
cc192b50 183 local_ip = *local;
184
185 Config.Wccp.address.FreeAddrInfo(local);
320e9f36 186}
187
320e9f36 188
189void
190wccpConnectionClose(void)
191{
0b0cfcf2 192 if (theWccpConnection > -1) {
76dc4ca3 193 debugs(80, 1, "FD " << theWccpConnection << " Closing WCCPv1 socket");
0b0cfcf2 194 comm_close(theWccpConnection);
195 theWccpConnection = -1;
320e9f36 196 }
197}
198
62e76326 199/*
320e9f36 200 * Functions for handling the requests.
201 */
202
62e76326 203/*
320e9f36 204 * Accept the UDP packet
f6308664 205 */
1f38f50a 206static void
320e9f36 207wccpHandleUdp(int sock, void *not_used)
f6308664 208{
62e76326 209
cc192b50 210 IPAddress from;
47ac1af3 211 int len;
320e9f36 212
bf8fe701 213 debugs(80, 6, "wccpHandleUdp: Called.");
f6308664 214
320e9f36 215 commSetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
62e76326 216
b5b86e2c 217 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
f6308664 218
7d21986b 219 len = comm_udp_recvfrom(sock,
62e76326 220 (void *) &wccp_i_see_you,
1205909e 221 sizeof(wccp_i_see_you),
62e76326 222 0,
cc192b50 223 from);
224 debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " << from <<
225 ": type=" <<
bf8fe701 226 (unsigned) ntohl(wccp_i_see_you.type) << ", version=" <<
227 (unsigned) ntohl(wccp_i_see_you.version) << ", change=" <<
228 (unsigned) ntohl(wccp_i_see_you.change) << ", id=" <<
229 (unsigned) ntohl(wccp_i_see_you.id) << ", number=" <<
230 (unsigned) ntohl(wccp_i_see_you.number));
62e76326 231
b5b86e2c 232 if (len < 0)
62e76326 233 return;
234
cc192b50 235 if (from != Config.Wccp.router)
62e76326 236 return;
237
e4049756 238 if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
62e76326 239 return;
240
b5b86e2c 241 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
62e76326 242 return;
243
0b0cfcf2 244 if (ntohl(wccp_i_see_you.number) > WCCP_ACTIVE_CACHES) {
bf8fe701 245 debugs(80, 1, "Ignoring WCCP_I_SEE_YOU from " <<
cc192b50 246 from << " with number of caches set to " <<
bf8fe701 247 (int) ntohl(wccp_i_see_you.number));
248
eedab643 249 return;
250 }
251
eccaff9c 252 last_id = wccp_i_see_you.id;
eedab643 253
eccaff9c 254 if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
62e76326 255 if (last_assign_buckets_change == wccp_i_see_you.change) {
256 /*
257 * After a WCCP_ASSIGN_BUCKET message, the router should
258 * update the change value. If not, maybe the route didn't
259 * receive our WCCP_ASSIGN_BUCKET message, so send it again.
260 *
261 * Don't update change here. Instead, fall through to
262 * the next block to call wccpAssignBuckets() again.
263 */
264 (void) 0;
265 } else {
eccaff9c 266 last_change = wccp_i_see_you.change;
62e76326 267 return;
268 }
b5b86e2c 269 }
62e76326 270
eccaff9c 271 if (last_change != wccp_i_see_you.change) {
272 last_change = wccp_i_see_you.change;
62e76326 273
274 if (wccpLowestIP() && wccp_i_see_you.number) {
eccaff9c 275 last_assign_buckets_change = last_change;
62e76326 276 wccpAssignBuckets();
277 }
b5b86e2c 278 }
279}
f6308664 280
1f38f50a 281static int
282wccpLowestIP(void)
b5b86e2c 283{
908b22c4 284 unsigned int loop;
eccaff9c 285 int found = 0;
62e76326 286
eedab643 287 /*
288 * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
289 */
290
e4049756 291 for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); loop++) {
eedab643 292 assert(loop < WCCP_ACTIVE_CACHES);
293
cc192b50 294 if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr < local_ip)
62e76326 295 return 0;
eccaff9c 296
cc192b50 297 if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr == local_ip)
eccaff9c 298 found = 1;
f6308664 299 }
62e76326 300
eccaff9c 301 return found;
f6308664 302}
320e9f36 303
1f38f50a 304static void
320e9f36 305wccpHereIam(void *voidnotused)
306{
bf8fe701 307 debugs(80, 6, "wccpHereIam: Called");
320e9f36 308
eccaff9c 309 wccp_here_i_am.id = last_id;
0b0cfcf2 310 comm_udp_send(theWccpConnection,
62e76326 311 &wccp_here_i_am,
312 sizeof(wccp_here_i_am),
313 0);
320e9f36 314
1f38f50a 315 if (!eventFind(wccpHereIam, NULL))
62e76326 316 eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
320e9f36 317}
318
1f38f50a 319static void
7e3ce7b9 320wccpAssignBuckets(void)
320e9f36 321{
62e76326 322
7e3ce7b9 323 struct wccp_assign_bucket_t *wccp_assign_bucket;
324 int wab_len;
325 char *buckets;
9bc73deb 326 int buckets_per_cache;
908b22c4 327 unsigned int loop;
1f38f50a 328 int bucket = 0;
329 int *caches;
7e3ce7b9 330 int cache_len;
1f38f50a 331 char *buf;
320e9f36 332
bf8fe701 333 debugs(80, 6, "wccpAssignBuckets: Called");
b5b86e2c 334 number_caches = ntohl(wccp_i_see_you.number);
62e76326 335
eedab643 336 assert(number_caches > 0);
337 assert(number_caches <= WCCP_ACTIVE_CACHES);
62e76326 338
7e3ce7b9 339 wab_len = sizeof(struct wccp_assign_bucket_t);
62e76326 340
7e3ce7b9 341 cache_len = WCCP_CACHE_LEN * number_caches;
342
908b22c4 343 buf = (char *)xmalloc(wab_len +
62e76326 344 WCCP_BUCKETS +
345 cache_len);
346
7e3ce7b9 347 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
62e76326 348
7e3ce7b9 349 caches = (int *) (buf + wab_len);
62e76326 350
7e3ce7b9 351 buckets = buf + wab_len + cache_len;
352
353 memset(wccp_assign_bucket, '\0', sizeof(wccp_assign_bucket));
62e76326 354
7e3ce7b9 355 memset(buckets, 0xFF, WCCP_BUCKETS);
320e9f36 356
9bc73deb 357 buckets_per_cache = WCCP_BUCKETS / number_caches;
62e76326 358
f6308664 359 for (loop = 0; loop < number_caches; loop++) {
62e76326 360 int i;
361 xmemcpy(&caches[loop],
cc192b50 362 &wccp_i_see_you.wccp_cache_entry[loop].ip_addr,
62e76326 363 sizeof(*caches));
364
365 for (i = 0; i < buckets_per_cache; i++) {
366 assert(bucket < WCCP_BUCKETS);
367 buckets[bucket++] = loop;
368 }
320e9f36 369 }
62e76326 370
994f613f 371 while (bucket < WCCP_BUCKETS) {
62e76326 372 buckets[bucket++] = number_caches - 1;
994f613f 373 }
62e76326 374
7e3ce7b9 375 wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
376 wccp_assign_bucket->id = wccp_i_see_you.id;
377 wccp_assign_bucket->number = wccp_i_see_you.number;
378
0b0cfcf2 379 comm_udp_send(theWccpConnection,
62e76326 380 buf,
381 wab_len + WCCP_BUCKETS + cache_len,
382 0);
eccaff9c 383 last_change = 0;
1f38f50a 384 xfree(buf);
320e9f36 385}
eb824054 386
387#endif /* USE_WCCP */