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