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