]> git.ipfire.org Git - thirdparty/squid.git/blame - src/wccp.cc
Document the 'carp' cache_peer option
[thirdparty/squid.git] / src / wccp.cc
CommitLineData
320e9f36 1
2/*
528b2c61 3 * $Id: wccp.cc,v 1.32 2003/01/23 00:37:29 robertc 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"
320e9f36 37
eb824054 38#if USE_WCCP
39
320e9f36 40#define WCCP_PORT 2048
320e9f36 41#define WCCP_REVISION 0
42#define WCCP_RESPONSE_SIZE 12448
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
52struct wccp_here_i_am_t {
53 int type;
54 int version;
55 int revision;
56 char hash[WCCP_HASH_SIZE];
57 int reserved;
58 int id;
59};
60
61struct wccp_cache_entry_t {
1f38f50a 62 struct in_addr ip_addr;
320e9f36 63 int revision;
ede4c165 64 char hash[WCCP_HASH_SIZE];
320e9f36 65 int reserved;
66};
67
68struct wccp_i_see_you_t {
69 int type;
70 int version;
71 int change;
72 int id;
73 int number;
74 struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES];
75};
76
77struct wccp_assign_bucket_t {
f6308664 78 int type;
79 int id;
80 int number;
320e9f36 81};
82
eb824054 83static int theInWccpConnection = -1;
84static int theOutWccpConnection = -1;
320e9f36 85static struct wccp_here_i_am_t wccp_here_i_am;
b5b86e2c 86static struct wccp_i_see_you_t wccp_i_see_you;
1f38f50a 87static int change;
1addf64a 88static int last_assign_buckets_change;
908b22c4 89static unsigned int number_caches;
1f38f50a 90static struct in_addr local_ip;
b5b86e2c 91
1f38f50a 92static PF wccpHandleUdp;
93static int wccpLowestIP(void);
94static EVH wccpHereIam;
7e3ce7b9 95static void wccpAssignBuckets(void);
320e9f36 96
320e9f36 97/*
98 * The functions used during startup:
99 * wccpInit
100 * wccpConnectionOpen
101 * wccpConnectionShutdown
102 * wccpConnectionClose
103 */
104
105void
106wccpInit(void)
107{
108 debug(80, 5) ("wccpInit: Called\n");
320e9f36 109 memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
110 wccp_here_i_am.type = htonl(WCCP_HERE_I_AM);
d20b1cd0 111 wccp_here_i_am.version = htonl(Config.Wccp.version);
f6308664 112 wccp_here_i_am.revision = htonl(WCCP_REVISION);
7e3ce7b9 113 change = 0;
1addf64a 114 last_assign_buckets_change = 0;
1f38f50a 115 if (Config.Wccp.router.s_addr != any_addr.s_addr)
116 if (!eventFind(wccpHereIam, NULL))
7e3ce7b9 117 eventAdd("wccpHereIam", wccpHereIam, NULL, 5.0, 1);
320e9f36 118}
119
120void
121wccpConnectionOpen(void)
122{
123 u_short port = WCCP_PORT;
b5b86e2c 124 struct sockaddr_in router, local;
908b22c4 125 socklen_t local_len, router_len;
320e9f36 126 debug(80, 5) ("wccpConnectionOpen: Called\n");
1f38f50a 127 if (Config.Wccp.router.s_addr == any_addr.s_addr) {
128 debug(1, 1) ("WCCP Disabled.\n");
129 return;
130 }
131 theInWccpConnection = comm_open(SOCK_DGRAM,
132 0,
133 Config.Wccp.incoming,
134 port,
135 COMM_NONBLOCKING,
136 "WCCP Socket");
137 if (theInWccpConnection < 0)
138 fatal("Cannot open WCCP Port");
139 commSetSelect(theInWccpConnection,
140 COMM_SELECT_READ,
141 wccpHandleUdp,
142 NULL,
143 0);
144 debug(1, 1) ("Accepting WCCP messages on port %d, FD %d.\n",
145 (int) port, theInWccpConnection);
146 if (Config.Wccp.outgoing.s_addr != no_addr.s_addr) {
147 theOutWccpConnection = comm_open(SOCK_DGRAM,
320e9f36 148 0,
1f38f50a 149 Config.Wccp.outgoing,
320e9f36 150 port,
151 COMM_NONBLOCKING,
1f38f50a 152 "WCCP Socket");
153 if (theOutWccpConnection < 0)
154 fatal("Cannot open Outgoing WCCP Port");
155 commSetSelect(theOutWccpConnection,
156 COMM_SELECT_READ,
157 wccpHandleUdp,
158 NULL, 0);
159 debug(1, 1) ("Outgoing WCCP messages on port %d, FD %d.\n",
160 (int) port, theOutWccpConnection);
161 fd_note(theOutWccpConnection, "Outgoing WCCP socket");
162 fd_note(theInWccpConnection, "Incoming WCCP socket");
f6308664 163 } else {
1f38f50a 164 theOutWccpConnection = theInWccpConnection;
320e9f36 165 }
b5b86e2c 166 router_len = sizeof(router);
167 memset(&router, '\0', router_len);
168 router.sin_family = AF_INET;
1f38f50a 169 router.sin_port = htons(port);
ede4c165 170 router.sin_addr = Config.Wccp.router;
171 if (connect(theOutWccpConnection, (struct sockaddr *) &router, router_len))
172 fatal("Unable to connect WCCP out socket");
ede4c165 173 local_len = sizeof(local);
b5b86e2c 174 memset(&local, '\0', local_len);
ede4c165 175 if (getsockname(theOutWccpConnection, (struct sockaddr *) &local, &local_len))
b5b86e2c 176 fatal("Unable to getsockname on WCCP out socket");
1f38f50a 177 local_ip.s_addr = local.sin_addr.s_addr;
320e9f36 178}
179
180void
181wccpConnectionShutdown(void)
182{
183 if (theInWccpConnection < 0)
184 return;
185 if (theInWccpConnection != theOutWccpConnection) {
186 debug(80, 1) ("FD %d Closing WCCP socket\n", theInWccpConnection);
187 comm_close(theInWccpConnection);
6f333fe5 188 theInWccpConnection = -1;
320e9f36 189 }
320e9f36 190 assert(theOutWccpConnection > -1);
191 commSetSelect(theOutWccpConnection, COMM_SELECT_READ, NULL, NULL, 0);
192}
193
194void
195wccpConnectionClose(void)
196{
197 wccpConnectionShutdown();
198 if (theOutWccpConnection > -1) {
199 debug(80, 1) ("FD %d Closing WCCP socket\n", theOutWccpConnection);
200 comm_close(theOutWccpConnection);
201 }
202}
203
204/*
205 * Functions for handling the requests.
206 */
207
320e9f36 208/*
209 * Accept the UDP packet
f6308664 210 */
1f38f50a 211static void
320e9f36 212wccpHandleUdp(int sock, void *not_used)
f6308664 213{
320e9f36 214 struct sockaddr_in from;
f6308664 215 socklen_t from_len;
47ac1af3 216 int len;
320e9f36 217
218 debug(80, 6) ("wccpHandleUdp: Called.\n");
f6308664 219
320e9f36 220 commSetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
221 from_len = sizeof(struct sockaddr_in);
222 memset(&from, '\0', from_len);
b5b86e2c 223 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
f6308664 224
7d21986b 225 len = comm_udp_recvfrom(sock,
8c89c9c5 226 (void *) &wccp_i_see_you,
f6308664 227 WCCP_RESPONSE_SIZE,
228 0,
229 (struct sockaddr *) &from,
230 &from_len);
8e640afb 231 debug(80, 3) ("wccpHandleUdp: %d bytes WCCP pkt from %s: type=%u, version=%u, change=%u, id=%u, number=%u\n",
a2a4289a 232 len,
233 inet_ntoa(from.sin_addr),
8e640afb 234 (unsigned) ntohl(wccp_i_see_you.type),
235 (unsigned) ntohl(wccp_i_see_you.version),
236 (unsigned) ntohl(wccp_i_see_you.change),
237 (unsigned) ntohl(wccp_i_see_you.id),
238 (unsigned) ntohl(wccp_i_see_you.number));
b5b86e2c 239 if (len < 0)
240 return;
ede4c165 241 if (Config.Wccp.router.s_addr != from.sin_addr.s_addr)
b5b86e2c 242 return;
908b22c4 243 if (ntohl(wccp_i_see_you.version) != (unsigned)Config.Wccp.version)
b5b86e2c 244 return;
245 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
246 return;
1addf64a 247 if ((0 == change) && (number_caches == ntohl(wccp_i_see_you.number))) {
248 if (last_assign_buckets_change == wccp_i_see_you.change) {
249 /*
250 * After a WCCP_ASSIGN_BUCKET message, the router should
251 * update the change value. If not, maybe the route didn't
252 * receive our WCCP_ASSIGN_BUCKET message, so send it again.
253 *
254 * Don't update change here. Instead, fall through to
255 * the next block to call wccpAssignBuckets() again.
256 */
257 (void) 0;
258 } else {
259 change = wccp_i_see_you.change;
260 return;
261 }
b5b86e2c 262 }
263 if (change != wccp_i_see_you.change) {
264 change = wccp_i_see_you.change;
1addf64a 265 if (wccpLowestIP() && wccp_i_see_you.number) {
266 last_assign_buckets_change = change;
7e3ce7b9 267 wccpAssignBuckets();
1addf64a 268 }
b5b86e2c 269 }
270}
f6308664 271
1f38f50a 272static int
273wccpLowestIP(void)
b5b86e2c 274{
908b22c4 275 unsigned int loop;
b5b86e2c 276 for (loop = 0; loop < ntohl(wccp_i_see_you.number); loop++) {
1f38f50a 277 if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr)
278 return 0;
f6308664 279 }
1f38f50a 280 return 1;
f6308664 281}
320e9f36 282
1f38f50a 283static void
320e9f36 284wccpHereIam(void *voidnotused)
285{
f6308664 286 debug(80, 6) ("wccpHereIam: Called\n");
320e9f36 287
b5b86e2c 288 wccp_here_i_am.id = wccp_i_see_you.id;
259fa633 289 comm_udp_send(theOutWccpConnection,
efd900cb 290 &wccp_here_i_am,
f6308664 291 sizeof(wccp_here_i_am),
b5b86e2c 292 0);
320e9f36 293
1f38f50a 294 if (!eventFind(wccpHereIam, NULL))
295 eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
320e9f36 296}
297
1f38f50a 298static void
7e3ce7b9 299wccpAssignBuckets(void)
320e9f36 300{
7e3ce7b9 301 struct wccp_assign_bucket_t *wccp_assign_bucket;
302 int wab_len;
303 char *buckets;
9bc73deb 304 int buckets_per_cache;
908b22c4 305 unsigned int loop;
1f38f50a 306 int bucket = 0;
307 int *caches;
7e3ce7b9 308 int cache_len;
1f38f50a 309 char *buf;
320e9f36 310
311 debug(80, 6) ("wccpAssignBuckets: Called\n");
b5b86e2c 312 number_caches = ntohl(wccp_i_see_you.number);
f6308664 313 if (number_caches > WCCP_ACTIVE_CACHES)
320e9f36 314 number_caches = WCCP_ACTIVE_CACHES;
7e3ce7b9 315 wab_len = sizeof(struct wccp_assign_bucket_t);
316 cache_len = WCCP_CACHE_LEN * number_caches;
317
908b22c4 318 buf = (char *)xmalloc(wab_len +
7e3ce7b9 319 WCCP_BUCKETS +
320 cache_len);
321 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
322 caches = (int *) (buf + wab_len);
323 buckets = buf + wab_len + cache_len;
324
325 memset(wccp_assign_bucket, '\0', sizeof(wccp_assign_bucket));
326 memset(buckets, 0xFF, WCCP_BUCKETS);
320e9f36 327
9bc73deb 328 buckets_per_cache = WCCP_BUCKETS / number_caches;
f6308664 329 for (loop = 0; loop < number_caches; loop++) {
9bc73deb 330 int i;
1f38f50a 331 xmemcpy(&caches[loop],
332 &wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr,
333 sizeof(*caches));
9bc73deb 334 for (i = 0; i < buckets_per_cache; i++) {
335 assert(bucket < WCCP_BUCKETS);
f20d9f17 336 buckets[bucket++] = loop;
320e9f36 337 }
338 }
994f613f 339 while (bucket < WCCP_BUCKETS) {
2f49e55e 340 buckets[bucket++] = number_caches - 1;
994f613f 341 }
7e3ce7b9 342 wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
343 wccp_assign_bucket->id = wccp_i_see_you.id;
344 wccp_assign_bucket->number = wccp_i_see_you.number;
345
259fa633 346 comm_udp_send(theOutWccpConnection,
f20d9f17 347 buf,
7e3ce7b9 348 wab_len + WCCP_BUCKETS + cache_len,
b5b86e2c 349 0);
350 change = 0;
1f38f50a 351 xfree(buf);
320e9f36 352}
eb824054 353
354#endif /* USE_WCCP */