]> git.ipfire.org Git - thirdparty/squid.git/blame - src/wccp.cc
sendto() -> comm_udp_sendto()
[thirdparty/squid.git] / src / wccp.cc
CommitLineData
320e9f36 1
2/*
03c5d1ff 3 * $Id: wccp.cc,v 1.27 2002/10/21 05:54:36 adrian 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;
994f613f 88static int number_caches;
1f38f50a 89static struct in_addr local_ip;
b5b86e2c 90
1f38f50a 91static PF wccpHandleUdp;
92static int wccpLowestIP(void);
93static EVH wccpHereIam;
7e3ce7b9 94static void wccpAssignBuckets(void);
320e9f36 95
320e9f36 96/*
97 * The functions used during startup:
98 * wccpInit
99 * wccpConnectionOpen
100 * wccpConnectionShutdown
101 * wccpConnectionClose
102 */
103
104void
105wccpInit(void)
106{
107 debug(80, 5) ("wccpInit: Called\n");
320e9f36 108 memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
109 wccp_here_i_am.type = htonl(WCCP_HERE_I_AM);
d20b1cd0 110 wccp_here_i_am.version = htonl(Config.Wccp.version);
f6308664 111 wccp_here_i_am.revision = htonl(WCCP_REVISION);
7e3ce7b9 112 change = 0;
1f38f50a 113 if (Config.Wccp.router.s_addr != any_addr.s_addr)
114 if (!eventFind(wccpHereIam, NULL))
7e3ce7b9 115 eventAdd("wccpHereIam", wccpHereIam, NULL, 5.0, 1);
320e9f36 116}
117
118void
119wccpConnectionOpen(void)
120{
121 u_short port = WCCP_PORT;
b5b86e2c 122 struct sockaddr_in router, local;
ede4c165 123 int local_len, router_len;
320e9f36 124 debug(80, 5) ("wccpConnectionOpen: Called\n");
1f38f50a 125 if (Config.Wccp.router.s_addr == any_addr.s_addr) {
126 debug(1, 1) ("WCCP Disabled.\n");
127 return;
128 }
129 theInWccpConnection = comm_open(SOCK_DGRAM,
130 0,
131 Config.Wccp.incoming,
132 port,
133 COMM_NONBLOCKING,
134 "WCCP Socket");
135 if (theInWccpConnection < 0)
136 fatal("Cannot open WCCP Port");
137 commSetSelect(theInWccpConnection,
138 COMM_SELECT_READ,
139 wccpHandleUdp,
140 NULL,
141 0);
142 debug(1, 1) ("Accepting WCCP messages on port %d, FD %d.\n",
143 (int) port, theInWccpConnection);
144 if (Config.Wccp.outgoing.s_addr != no_addr.s_addr) {
145 theOutWccpConnection = comm_open(SOCK_DGRAM,
320e9f36 146 0,
1f38f50a 147 Config.Wccp.outgoing,
320e9f36 148 port,
149 COMM_NONBLOCKING,
1f38f50a 150 "WCCP Socket");
151 if (theOutWccpConnection < 0)
152 fatal("Cannot open Outgoing WCCP Port");
153 commSetSelect(theOutWccpConnection,
154 COMM_SELECT_READ,
155 wccpHandleUdp,
156 NULL, 0);
157 debug(1, 1) ("Outgoing WCCP messages on port %d, FD %d.\n",
158 (int) port, theOutWccpConnection);
159 fd_note(theOutWccpConnection, "Outgoing WCCP socket");
160 fd_note(theInWccpConnection, "Incoming WCCP socket");
f6308664 161 } else {
1f38f50a 162 theOutWccpConnection = theInWccpConnection;
320e9f36 163 }
b5b86e2c 164 router_len = sizeof(router);
165 memset(&router, '\0', router_len);
166 router.sin_family = AF_INET;
1f38f50a 167 router.sin_port = htons(port);
ede4c165 168 router.sin_addr = Config.Wccp.router;
169 if (connect(theOutWccpConnection, (struct sockaddr *) &router, router_len))
170 fatal("Unable to connect WCCP out socket");
ede4c165 171 local_len = sizeof(local);
b5b86e2c 172 memset(&local, '\0', local_len);
ede4c165 173 if (getsockname(theOutWccpConnection, (struct sockaddr *) &local, &local_len))
b5b86e2c 174 fatal("Unable to getsockname on WCCP out socket");
1f38f50a 175 local_ip.s_addr = local.sin_addr.s_addr;
320e9f36 176}
177
178void
179wccpConnectionShutdown(void)
180{
181 if (theInWccpConnection < 0)
182 return;
183 if (theInWccpConnection != theOutWccpConnection) {
184 debug(80, 1) ("FD %d Closing WCCP socket\n", theInWccpConnection);
185 comm_close(theInWccpConnection);
6f333fe5 186 theInWccpConnection = -1;
320e9f36 187 }
320e9f36 188 assert(theOutWccpConnection > -1);
189 commSetSelect(theOutWccpConnection, COMM_SELECT_READ, NULL, NULL, 0);
190}
191
192void
193wccpConnectionClose(void)
194{
195 wccpConnectionShutdown();
196 if (theOutWccpConnection > -1) {
197 debug(80, 1) ("FD %d Closing WCCP socket\n", theOutWccpConnection);
198 comm_close(theOutWccpConnection);
199 }
200}
201
202/*
203 * Functions for handling the requests.
204 */
205
320e9f36 206/*
207 * Accept the UDP packet
f6308664 208 */
1f38f50a 209static void
320e9f36 210wccpHandleUdp(int sock, void *not_used)
f6308664 211{
320e9f36 212 struct sockaddr_in from;
f6308664 213 socklen_t from_len;
47ac1af3 214 int len;
320e9f36 215
216 debug(80, 6) ("wccpHandleUdp: Called.\n");
f6308664 217
320e9f36 218 commSetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
219 from_len = sizeof(struct sockaddr_in);
220 memset(&from, '\0', from_len);
b5b86e2c 221 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
f6308664 222
063dc1eb 223 len = comm_recvfrom(sock,
8c89c9c5 224 (void *) &wccp_i_see_you,
f6308664 225 WCCP_RESPONSE_SIZE,
226 0,
227 (struct sockaddr *) &from,
228 &from_len);
8e640afb 229 debug(80, 3) ("wccpHandleUdp: %d bytes WCCP pkt from %s: type=%u, version=%u, change=%u, id=%u, number=%u\n",
a2a4289a 230 len,
231 inet_ntoa(from.sin_addr),
8e640afb 232 (unsigned) ntohl(wccp_i_see_you.type),
233 (unsigned) ntohl(wccp_i_see_you.version),
234 (unsigned) ntohl(wccp_i_see_you.change),
235 (unsigned) ntohl(wccp_i_see_you.id),
236 (unsigned) ntohl(wccp_i_see_you.number));
b5b86e2c 237 if (len < 0)
238 return;
ede4c165 239 if (Config.Wccp.router.s_addr != from.sin_addr.s_addr)
b5b86e2c 240 return;
d20b1cd0 241 if (ntohl(wccp_i_see_you.version) != Config.Wccp.version)
b5b86e2c 242 return;
243 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
244 return;
2f49e55e 245 if ((!change) && (number_caches == ntohl(wccp_i_see_you.number))) {
b5b86e2c 246 change = wccp_i_see_you.change;
247 return;
248 }
249 if (change != wccp_i_see_you.change) {
250 change = wccp_i_see_you.change;
7e3ce7b9 251 if (wccpLowestIP() && wccp_i_see_you.number)
252 wccpAssignBuckets();
b5b86e2c 253 }
254}
f6308664 255
1f38f50a 256static int
257wccpLowestIP(void)
b5b86e2c 258{
259 int loop;
260 for (loop = 0; loop < ntohl(wccp_i_see_you.number); loop++) {
1f38f50a 261 if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr)
262 return 0;
f6308664 263 }
1f38f50a 264 return 1;
f6308664 265}
320e9f36 266
1f38f50a 267static void
320e9f36 268wccpHereIam(void *voidnotused)
269{
f6308664 270 debug(80, 6) ("wccpHereIam: Called\n");
320e9f36 271
b5b86e2c 272 wccp_here_i_am.id = wccp_i_see_you.id;
03c5d1ff 273 comm_send(theOutWccpConnection,
efd900cb 274 &wccp_here_i_am,
f6308664 275 sizeof(wccp_here_i_am),
b5b86e2c 276 0);
320e9f36 277
1f38f50a 278 if (!eventFind(wccpHereIam, NULL))
279 eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
320e9f36 280}
281
1f38f50a 282static void
7e3ce7b9 283wccpAssignBuckets(void)
320e9f36 284{
7e3ce7b9 285 struct wccp_assign_bucket_t *wccp_assign_bucket;
286 int wab_len;
287 char *buckets;
9bc73deb 288 int buckets_per_cache;
1f38f50a 289 int loop;
1f38f50a 290 int bucket = 0;
291 int *caches;
7e3ce7b9 292 int cache_len;
1f38f50a 293 char *buf;
320e9f36 294
295 debug(80, 6) ("wccpAssignBuckets: Called\n");
b5b86e2c 296 number_caches = ntohl(wccp_i_see_you.number);
f6308664 297 if (number_caches > WCCP_ACTIVE_CACHES)
320e9f36 298 number_caches = WCCP_ACTIVE_CACHES;
7e3ce7b9 299 wab_len = sizeof(struct wccp_assign_bucket_t);
300 cache_len = WCCP_CACHE_LEN * number_caches;
301
302 buf = xmalloc(wab_len +
303 WCCP_BUCKETS +
304 cache_len);
305 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
306 caches = (int *) (buf + wab_len);
307 buckets = buf + wab_len + cache_len;
308
309 memset(wccp_assign_bucket, '\0', sizeof(wccp_assign_bucket));
310 memset(buckets, 0xFF, WCCP_BUCKETS);
320e9f36 311
9bc73deb 312 buckets_per_cache = WCCP_BUCKETS / number_caches;
f6308664 313 for (loop = 0; loop < number_caches; loop++) {
9bc73deb 314 int i;
1f38f50a 315 xmemcpy(&caches[loop],
316 &wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr,
317 sizeof(*caches));
9bc73deb 318 for (i = 0; i < buckets_per_cache; i++) {
319 assert(bucket < WCCP_BUCKETS);
f20d9f17 320 buckets[bucket++] = loop;
320e9f36 321 }
322 }
994f613f 323 while (bucket < WCCP_BUCKETS) {
2f49e55e 324 buckets[bucket++] = number_caches - 1;
994f613f 325 }
7e3ce7b9 326 wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
327 wccp_assign_bucket->id = wccp_i_see_you.id;
328 wccp_assign_bucket->number = wccp_i_see_you.number;
329
03c5d1ff 330 comm_send(theOutWccpConnection,
f20d9f17 331 buf,
7e3ce7b9 332 wab_len + WCCP_BUCKETS + cache_len,
b5b86e2c 333 0);
334 change = 0;
1f38f50a 335 xfree(buf);
320e9f36 336}
eb824054 337
338#endif /* USE_WCCP */