Squid Web Cache master
Loading...
Searching...
No Matches
wccp.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 80 WCCP Support */
10
11#include "squid.h"
12
13#if USE_WCCP
15#include "comm.h"
16#include "comm/Connection.h"
17#include "comm/Loops.h"
18#include "compat/socket.h"
19#include "event.h"
20#include "fatal.h"
21#include "SquidConfig.h"
22#include "tools.h"
23
24#define WCCP_PORT 2048
25#define WCCP_REVISION 0
26#define WCCP_ACTIVE_CACHES 32
27#define WCCP_HASH_SIZE 32
28#define WCCP_BUCKETS 256
29#define WCCP_CACHE_LEN 4
30
31#define WCCP_HERE_I_AM 7
32#define WCCP_I_SEE_YOU 8
33#define WCCP_ASSIGN_BUCKET 9
34
43
45 struct in_addr ip_addr; // WCCP on-the-wire in 32-bit IPv4-only.
49};
50
52 int32_t type;
53 int32_t version;
54 int32_t change;
55 int32_t id;
56 int32_t number;
57
59};
60
62 int type;
63 int id;
64 int number;
65};
66
67static int theWccpConnection = -1;
68
70
72static int last_change;
73static int last_id;
75static unsigned int number_caches;
76
78
80static int wccpLowestIP(void);
82static void wccpAssignBuckets(void);
83
84static void
86{
87 if (!IamPrimaryProcess())
88 return;
89
90 debugs(80, 5, "wccpInit: Called");
91 memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
95 last_change = 0;
96 last_id = 0;
98 number_caches = 0;
99
101 if (!eventFind(wccpHereIam, nullptr))
102 eventAdd("wccpHereIam", wccpHereIam, nullptr, 5.0, 1);
103}
104
105static void
107{
108 if (!IamPrimaryProcess())
109 return;
110
111 debugs(80, 5, "wccpConnectionOpen: Called");
112
113 if (Config.Wccp.router.isAnyAddr()) {
114 debugs(80, 2, "WCCPv1 disabled.");
115 return;
116 }
117
118 if ( !Config.Wccp.router.setIPv4() ) {
119 debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Router " << Config.Wccp.router << " is not an IPv4 address.");
120 return;
121 }
122
123 if ( !Config.Wccp.address.setIPv4() ) {
124 debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Local address " << Config.Wccp.address << " is not an IPv4 address.");
125 return;
126 }
127
130
132 IPPROTO_UDP,
135 "WCCP Socket");
136
137 if (theWccpConnection < 0)
138 fatal("Cannot open WCCP Port");
139
141
142 debugs(80, DBG_IMPORTANT, "Accepting WCCPv1 messages on " << Config.Wccp.address << ", FD " << theWccpConnection << ".");
143
144 // Sadly WCCP only does IPv4
145
146 struct sockaddr_in router;
148 if (xconnect(theWccpConnection, (struct sockaddr*)&router, sizeof(router)))
149 fatal("Unable to connect WCCP out socket");
150
151 struct sockaddr_in local;
152 memset(&local, '\0', sizeof(local));
153 socklen_t slen = sizeof(local);
154 if (xgetsockname(theWccpConnection, (struct sockaddr*)&local, &slen))
155 fatal("Unable to getsockname on WCCP out socket");
156
157 local_ip = local;
158}
159
160static void
162{
163 if (!IamPrimaryProcess())
164 return;
165
166 if (theWccpConnection > -1) {
167 debugs(80, DBG_IMPORTANT, "FD " << theWccpConnection << " Closing WCCPv1 socket");
170 }
171}
172
174{
175public:
176 void useConfig() override { wccpInit(); wccpConnectionOpen(); }
178 void syncConfig() override { wccpConnectionOpen(); }
179 void startShutdown() override { wccpConnectionClose(); }
180};
182
183/*
184 * Functions for handling the requests.
185 */
186
187/*
188 * Accept the UDP packet
189 */
190static void
191wccpHandleUdp(int sock, void *)
192{
193 Ip::Address from;
194 int len;
195
196 debugs(80, 6, "wccpHandleUdp: Called.");
197
199
200 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
201
202 len = comm_udp_recvfrom(sock,
203 (void *) &wccp_i_see_you,
204 sizeof(wccp_i_see_you),
205 0,
206 from);
207 debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " << from <<
208 ": type=" <<
209 (unsigned) ntohl(wccp_i_see_you.type) << ", version=" <<
210 (unsigned) ntohl(wccp_i_see_you.version) << ", change=" <<
211 (unsigned) ntohl(wccp_i_see_you.change) << ", id=" <<
212 (unsigned) ntohl(wccp_i_see_you.id) << ", number=" <<
213 (unsigned) ntohl(wccp_i_see_you.number));
214
215 if (len < 0)
216 return;
217
218 if (from != Config.Wccp.router)
219 return;
220
221 if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
222 return;
223
224 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
225 return;
226
228 debugs(80, DBG_IMPORTANT, "Ignoring WCCP_I_SEE_YOU from " <<
229 from << " with number of caches set to " <<
230 (int) ntohl(wccp_i_see_you.number));
231
232 return;
233 }
234
236
237 if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
239 /*
240 * After a WCCP_ASSIGN_BUCKET message, the router should
241 * update the change value. If not, maybe the route didn't
242 * receive our WCCP_ASSIGN_BUCKET message, so send it again.
243 *
244 * Don't update change here. Instead, fall through to
245 * the next block to call wccpAssignBuckets() again.
246 */
247 (void) 0;
248 } else {
250 return;
251 }
252 }
253
256
260 }
261 }
262}
263
264static int
266{
267 unsigned int loop;
268 int found = 0;
269
270 /*
271 * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
272 */
273
274 for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); ++loop) {
276
278 return 0;
279
281 found = 1;
282 }
283
284 return found;
285}
286
287static void
289{
290 debugs(80, 6, "wccpHereIam: Called");
291
293 double interval = 10.0; // TODO: make this configurable, possibly negotiate with the router.
294 ssize_t sent = comm_udp_send(theWccpConnection, &wccp_here_i_am, sizeof(wccp_here_i_am), 0);
295
296 // if we failed to send the whole lot, try again at a shorter interval (20%)
297 if (sent != sizeof(wccp_here_i_am)) {
298 int xerrno = errno;
299 debugs(80, 2, "ERROR: failed to send WCCP HERE_I_AM packet: " << xstrerr(xerrno));
300 interval = 2.0;
301 }
302
303 if (!eventFind(wccpHereIam, nullptr))
304 eventAdd("wccpHereIam", wccpHereIam, nullptr, interval, 1);
305}
306
307static void
309{
310
311 struct wccp_assign_bucket_t *wccp_assign_bucket;
312 int wab_len;
313 char *buckets;
314 int buckets_per_cache;
315 unsigned int loop;
316 int bucket = 0;
317 int *caches;
318 int cache_len;
319 char *buf;
320
321 debugs(80, 6, "wccpAssignBuckets: Called");
323
326
327 wab_len = sizeof(struct wccp_assign_bucket_t);
328
329 cache_len = WCCP_CACHE_LEN * number_caches;
330
331 buf = (char *)xmalloc(wab_len +
333 cache_len);
334
335 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
336
337 caches = (int *) (buf + wab_len);
338
339 buckets = buf + wab_len + cache_len;
340
341 memset(wccp_assign_bucket, '\0', sizeof(*wccp_assign_bucket));
342
343 memset(buckets, 0xFF, WCCP_BUCKETS);
344
345 buckets_per_cache = WCCP_BUCKETS / number_caches;
346
347 for (loop = 0; loop < number_caches; ++loop) {
348 int i;
349 memcpy(&caches[loop],
351 sizeof(*caches));
352
353 for (i = 0; i < buckets_per_cache; ++i) {
354 assert(bucket < WCCP_BUCKETS);
355 buckets[bucket] = loop;
356 ++bucket;
357 }
358 }
359
360 while (bucket < WCCP_BUCKETS) {
361 buckets[bucket] = number_caches - 1;
362 ++bucket;
363 }
364
365 wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
366 wccp_assign_bucket->id = wccp_i_see_you.id;
367 wccp_assign_bucket->number = wccp_i_see_you.number;
368
370 buf,
371 wab_len + WCCP_BUCKETS + cache_len,
372 0);
373 last_change = 0;
374 xfree(buf);
375}
376
377#endif /* USE_WCCP */
378
#define COMM_NONBLOCKING
Definition Connection.h:46
#define DefineRunnerRegistrator(ClassName)
class SquidConfig Config
#define assert(EX)
Definition assert.h:17
bool setIPv4()
Definition Address.cc:244
void getSockAddr(struct sockaddr_storage &addr, const int family) const
Definition Address.cc:936
bool isAnyAddr() const
Definition Address.cc:190
unsigned short port() const
Definition Address.cc:790
Ip::Address address
Ip::Address router
struct SquidConfig::@80 Wccp
void startReconfigure() override
Definition wccp.cc:177
void startShutdown() override
Definition wccp.cc:179
void syncConfig() override
Definition wccp.cc:178
void useConfig() override
Definition wccp.cc:176
void PF(int, void *)
Definition forward.h:18
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
Definition comm.cc:259
ssize_t comm_udp_send(int s, const void *buf, size_t len, int flags)
Definition comm.cc:148
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
Definition comm.cc:128
#define comm_close(x)
Definition comm.h:36
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
#define COMM_SELECT_READ
Definition defines.h:24
int eventFind(EVH *func, void *arg)
Definition event.cc:145
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition event.cc:107
void EVH(void *)
Definition event.h:18
void fatal(const char *message)
Definition fatal.cc:28
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
#define xfree
#define xmalloc
static struct tok * buckets[HASHSIZE]
Definition parse.c:219
int xgetsockname(int socketFd, struct sockaddr *sa, socklen_t *saLength)
POSIX getsockname(2) equivalent.
Definition socket.h:80
int xconnect(int socketFd, const struct sockaddr *sa, socklen_t saLength)
POSIX connect(2) equivalent.
Definition socket.h:74
Definition wccp.cc:44
int revision
Definition wccp.cc:46
struct in_addr ip_addr
Definition wccp.cc:45
char hash[WCCP_HASH_SIZE]
Definition wccp.cc:47
int reserved
Definition wccp.cc:48
char hash[WCCP_HASH_SIZE]
Definition wccp.cc:39
int32_t change
Definition wccp.cc:54
int32_t number
Definition wccp.cc:56
int32_t version
Definition wccp.cc:53
int32_t id
Definition wccp.cc:55
struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES]
Definition wccp.cc:58
int32_t type
Definition wccp.cc:52
bool IamPrimaryProcess()
Definition tools.cc:709
int socklen_t
Definition types.h:137
static void wccpConnectionClose(void)
Definition wccp.cc:161
#define WCCP_I_SEE_YOU
Definition wccp.cc:32
static PF wccpHandleUdp
Definition wccp.cc:79
static Ip::Address local_ip
Definition wccp.cc:77
#define WCCP_ACTIVE_CACHES
Definition wccp.cc:26
static int last_assign_buckets_change
Definition wccp.cc:74
#define WCCP_REVISION
Definition wccp.cc:25
static unsigned int number_caches
Definition wccp.cc:75
static int last_change
Definition wccp.cc:72
#define WCCP_CACHE_LEN
Definition wccp.cc:29
#define WCCP_ASSIGN_BUCKET
Definition wccp.cc:33
static int wccpLowestIP(void)
Definition wccp.cc:265
#define WCCP_BUCKETS
Definition wccp.cc:28
#define WCCP_PORT
Definition wccp.cc:24
static int theWccpConnection
Definition wccp.cc:67
static void wccpInit(void)
Definition wccp.cc:85
static void wccpAssignBuckets(void)
Definition wccp.cc:308
static void wccpConnectionOpen(void)
Definition wccp.cc:106
#define WCCP_HASH_SIZE
Definition wccp.cc:27
static struct wccp_i_see_you_t wccp_i_see_you
Definition wccp.cc:71
static EVH wccpHereIam
Definition wccp.cc:81
static struct wccp_here_i_am_t wccp_here_i_am
Definition wccp.cc:69
#define WCCP_HERE_I_AM
Definition wccp.cc:31
static int last_id
Definition wccp.cc:73
const char * xstrerr(int error)
Definition xstrerror.cc:83