]> git.ipfire.org Git - thirdparty/squid.git/blame - src/wccp.cc
Remove unnecessary stub_tools dependency on String
[thirdparty/squid.git] / src / wccp.cc
CommitLineData
320e9f36 1
2/*
262a0e14 3 * $Id$
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.
26ac0430 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.
26ac0430 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 */
d841c88d 35#include "config.h"
320e9f36 36
eb824054 37#if USE_WCCP
38
320e9f36 39#include "squid.h"
f9b72e0c
AJ
40#include "comm.h"
41#include "comm/Connection.h"
d841c88d 42#include "comm/Loops.h"
f9b72e0c
AJ
43#include "event.h"
44
320e9f36 45#define WCCP_PORT 2048
320e9f36 46#define WCCP_REVISION 0
320e9f36 47#define WCCP_ACTIVE_CACHES 32
48#define WCCP_HASH_SIZE 32
49#define WCCP_BUCKETS 256
7e3ce7b9 50#define WCCP_CACHE_LEN 4
320e9f36 51
52#define WCCP_HERE_I_AM 7
53#define WCCP_I_SEE_YOU 8
54#define WCCP_ASSIGN_BUCKET 9
55
26ac0430 56struct wccp_here_i_am_t {
320e9f36 57 int type;
58 int version;
59 int revision;
60 char hash[WCCP_HASH_SIZE];
61 int reserved;
62 int id;
63};
64
26ac0430 65struct wccp_cache_entry_t {
b7ac5457 66 struct in_addr ip_addr; // WCCP on-the-wire in 32-bit IPv4-only.
320e9f36 67 int revision;
ede4c165 68 char hash[WCCP_HASH_SIZE];
320e9f36 69 int reserved;
70};
71
26ac0430 72struct wccp_i_see_you_t {
b7ac5457
AJ
73 int32_t type;
74 int32_t version;
75 int32_t change;
76 int32_t id;
77 int32_t number;
62e76326 78
320e9f36 79 struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES];
80};
81
26ac0430 82struct wccp_assign_bucket_t {
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
b7ac5457 98static Ip::Address 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{
bf8fe701 134 debugs(80, 5, "wccpConnectionOpen: Called");
62e76326 135
cc192b50 136 if (Config.Wccp.router.IsAnyAddr()) {
76dc4ca3 137 debugs(80, 2, "WCCPv1 disabled.");
62e76326 138 return;
1f38f50a 139 }
62e76326 140
cc192b50 141 if ( !Config.Wccp.router.SetIPv4() ) {
30c48b1a 142 debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Router " << Config.Wccp.router << " is not an IPv4 address.");
cc192b50 143 return;
144 }
145
146 if ( !Config.Wccp.address.SetIPv4() ) {
30c48b1a 147 debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Local address " << Config.Wccp.address << " is not an IPv4 address.");
cc192b50 148 return;
149 }
150
151 Config.Wccp.address.SetPort(WCCP_PORT);
83fa0221 152 Config.Wccp.router.SetPort(WCCP_PORT);
cc192b50 153
31be869c 154 theWccpConnection = comm_open_listener(SOCK_DGRAM,
04f7fd38
AJ
155 IPPROTO_UDP,
156 Config.Wccp.address,
157 COMM_NONBLOCKING,
158 "WCCP Socket");
62e76326 159
0b0cfcf2 160 if (theWccpConnection < 0)
62e76326 161 fatal("Cannot open WCCP Port");
162
d841c88d 163 Comm::SetSelect(theWccpConnection, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
62e76326 164
cc192b50 165 debugs(80, 1, "Accepting WCCPv1 messages on " << Config.Wccp.address << ", FD " << theWccpConnection << ".");
0b0cfcf2 166
0b0cfcf2 167
306bfbb2 168 // Sadly WCCP only does IPv4
62e76326 169
306bfbb2
AJ
170 struct sockaddr_in router;
171 Config.Wccp.router.GetSockAddr(router);
9055f14b 172 if (connect(theWccpConnection, (struct sockaddr*)&router, sizeof(router)))
306bfbb2 173 fatal("Unable to connect WCCP out socket");
62e76326 174
306bfbb2
AJ
175 struct sockaddr_in local;
176 memset(&local, '\0', sizeof(local));
177 socklen_t slen = sizeof(local);
9055f14b 178 if (getsockname(theWccpConnection, (struct sockaddr*)&local, &slen))
62e76326 179 fatal("Unable to getsockname on WCCP out socket");
180
306bfbb2 181 local_ip = local;
320e9f36 182}
183
320e9f36 184
185void
186wccpConnectionClose(void)
187{
0b0cfcf2 188 if (theWccpConnection > -1) {
76dc4ca3 189 debugs(80, 1, "FD " << theWccpConnection << " Closing WCCPv1 socket");
0b0cfcf2 190 comm_close(theWccpConnection);
191 theWccpConnection = -1;
320e9f36 192 }
193}
194
62e76326 195/*
320e9f36 196 * Functions for handling the requests.
197 */
198
62e76326 199/*
320e9f36 200 * Accept the UDP packet
f6308664 201 */
1f38f50a 202static void
320e9f36 203wccpHandleUdp(int sock, void *not_used)
f6308664 204{
b7ac5457 205 Ip::Address from;
47ac1af3 206 int len;
320e9f36 207
bf8fe701 208 debugs(80, 6, "wccpHandleUdp: Called.");
f6308664 209
d841c88d 210 Comm::SetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
62e76326 211
b5b86e2c 212 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
f6308664 213
7d21986b 214 len = comm_udp_recvfrom(sock,
62e76326 215 (void *) &wccp_i_see_you,
1205909e 216 sizeof(wccp_i_see_you),
62e76326 217 0,
cc192b50 218 from);
219 debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " << from <<
26ac0430 220 ": type=" <<
bf8fe701 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));
62e76326 226
b5b86e2c 227 if (len < 0)
62e76326 228 return;
229
cc192b50 230 if (from != Config.Wccp.router)
62e76326 231 return;
232
e4049756 233 if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
62e76326 234 return;
235
b5b86e2c 236 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
62e76326 237 return;
238
0b0cfcf2 239 if (ntohl(wccp_i_see_you.number) > WCCP_ACTIVE_CACHES) {
bf8fe701 240 debugs(80, 1, "Ignoring WCCP_I_SEE_YOU from " <<
cc192b50 241 from << " with number of caches set to " <<
bf8fe701 242 (int) ntohl(wccp_i_see_you.number));
243
eedab643 244 return;
245 }
246
eccaff9c 247 last_id = wccp_i_see_you.id;
eedab643 248
eccaff9c 249 if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
62e76326 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 {
eccaff9c 261 last_change = wccp_i_see_you.change;
62e76326 262 return;
263 }
b5b86e2c 264 }
62e76326 265
eccaff9c 266 if (last_change != wccp_i_see_you.change) {
267 last_change = wccp_i_see_you.change;
62e76326 268
269 if (wccpLowestIP() && wccp_i_see_you.number) {
eccaff9c 270 last_assign_buckets_change = last_change;
62e76326 271 wccpAssignBuckets();
272 }
b5b86e2c 273 }
274}
f6308664 275
1f38f50a 276static int
277wccpLowestIP(void)
b5b86e2c 278{
908b22c4 279 unsigned int loop;
eccaff9c 280 int found = 0;
62e76326 281
eedab643 282 /*
283 * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
284 */
285
e4049756 286 for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); loop++) {
eedab643 287 assert(loop < WCCP_ACTIVE_CACHES);
288
185d5b63 289 if (local_ip > wccp_i_see_you.wccp_cache_entry[loop].ip_addr)
62e76326 290 return 0;
eccaff9c 291
b7ac5457 292 if (local_ip == wccp_i_see_you.wccp_cache_entry[loop].ip_addr)
eccaff9c 293 found = 1;
f6308664 294 }
62e76326 295
eccaff9c 296 return found;
f6308664 297}
320e9f36 298
1f38f50a 299static void
320e9f36 300wccpHereIam(void *voidnotused)
301{
bf8fe701 302 debugs(80, 6, "wccpHereIam: Called");
320e9f36 303
eccaff9c 304 wccp_here_i_am.id = last_id;
0b0cfcf2 305 comm_udp_send(theWccpConnection,
62e76326 306 &wccp_here_i_am,
307 sizeof(wccp_here_i_am),
308 0);
320e9f36 309
1f38f50a 310 if (!eventFind(wccpHereIam, NULL))
62e76326 311 eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
320e9f36 312}
313
1f38f50a 314static void
7e3ce7b9 315wccpAssignBuckets(void)
320e9f36 316{
62e76326 317
7e3ce7b9 318 struct wccp_assign_bucket_t *wccp_assign_bucket;
319 int wab_len;
320 char *buckets;
9bc73deb 321 int buckets_per_cache;
908b22c4 322 unsigned int loop;
1f38f50a 323 int bucket = 0;
324 int *caches;
7e3ce7b9 325 int cache_len;
1f38f50a 326 char *buf;
320e9f36 327
bf8fe701 328 debugs(80, 6, "wccpAssignBuckets: Called");
b5b86e2c 329 number_caches = ntohl(wccp_i_see_you.number);
62e76326 330
eedab643 331 assert(number_caches > 0);
332 assert(number_caches <= WCCP_ACTIVE_CACHES);
62e76326 333
7e3ce7b9 334 wab_len = sizeof(struct wccp_assign_bucket_t);
62e76326 335
7e3ce7b9 336 cache_len = WCCP_CACHE_LEN * number_caches;
337
908b22c4 338 buf = (char *)xmalloc(wab_len +
62e76326 339 WCCP_BUCKETS +
340 cache_len);
341
7e3ce7b9 342 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
62e76326 343
7e3ce7b9 344 caches = (int *) (buf + wab_len);
62e76326 345
7e3ce7b9 346 buckets = buf + wab_len + cache_len;
347
55788a77 348 memset(wccp_assign_bucket, '\0', sizeof(*wccp_assign_bucket));
62e76326 349
7e3ce7b9 350 memset(buckets, 0xFF, WCCP_BUCKETS);
320e9f36 351
9bc73deb 352 buckets_per_cache = WCCP_BUCKETS / number_caches;
62e76326 353
f6308664 354 for (loop = 0; loop < number_caches; loop++) {
62e76326 355 int i;
41d00cd3 356 memcpy(&caches[loop],
e34763f4
A
357 &wccp_i_see_you.wccp_cache_entry[loop].ip_addr,
358 sizeof(*caches));
62e76326 359
360 for (i = 0; i < buckets_per_cache; i++) {
361 assert(bucket < WCCP_BUCKETS);
362 buckets[bucket++] = loop;
363 }
320e9f36 364 }
62e76326 365
994f613f 366 while (bucket < WCCP_BUCKETS) {
62e76326 367 buckets[bucket++] = number_caches - 1;
994f613f 368 }
62e76326 369
7e3ce7b9 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
0b0cfcf2 374 comm_udp_send(theWccpConnection,
62e76326 375 buf,
376 wab_len + WCCP_BUCKETS + cache_len,
377 0);
eccaff9c 378 last_change = 0;
1f38f50a 379 xfree(buf);
320e9f36 380}
eb824054 381
382#endif /* USE_WCCP */