]>
Commit | Line | Data |
---|---|---|
320e9f36 | 1 | |
2 | /* | |
1f38f50a | 3 | * $Id: wccp.cc,v 1.9 1999/08/02 06:18:51 wessels Exp $ |
320e9f36 | 4 | * |
f6308664 | 5 | * DEBUG: section 80 WCCP Support |
320e9f36 | 6 | * AUTHOR: Glenn Chisholm |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
9 | * ---------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by the | |
14 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
15 | * Duane Wessels and the University of California San Diego. Please | |
16 | * see the COPYRIGHT file for full details. Squid incorporates | |
17 | * software developed and/or copyrighted by other sources. Please see | |
18 | * 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 | ||
eb824054 | 37 | #if USE_WCCP |
38 | ||
320e9f36 | 39 | #define WCCP_PORT 2048 |
40 | #define WCCP_VERSION 4 | |
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 | |
46 | ||
47 | #define WCCP_HERE_I_AM 7 | |
48 | #define WCCP_I_SEE_YOU 8 | |
49 | #define WCCP_ASSIGN_BUCKET 9 | |
50 | ||
51 | struct wccp_here_i_am_t { | |
52 | int type; | |
53 | int version; | |
54 | int revision; | |
55 | char hash[WCCP_HASH_SIZE]; | |
56 | int reserved; | |
57 | int id; | |
58 | }; | |
59 | ||
60 | struct wccp_cache_entry_t { | |
1f38f50a | 61 | struct in_addr ip_addr; |
320e9f36 | 62 | int revision; |
ede4c165 | 63 | char hash[WCCP_HASH_SIZE]; |
320e9f36 | 64 | int reserved; |
65 | }; | |
66 | ||
67 | struct wccp_i_see_you_t { | |
68 | int type; | |
69 | int version; | |
70 | int change; | |
71 | int id; | |
72 | int number; | |
73 | struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES]; | |
74 | }; | |
75 | ||
76 | struct wccp_assign_bucket_t { | |
f6308664 | 77 | int type; |
78 | int id; | |
79 | int number; | |
320e9f36 | 80 | }; |
81 | ||
eb824054 | 82 | static int theInWccpConnection = -1; |
83 | static int theOutWccpConnection = -1; | |
320e9f36 | 84 | static struct wccp_here_i_am_t wccp_here_i_am; |
b5b86e2c | 85 | static struct wccp_i_see_you_t wccp_i_see_you; |
1f38f50a | 86 | static int change; |
87 | static struct in_addr local_ip; | |
b5b86e2c | 88 | |
1f38f50a | 89 | static PF wccpHandleUdp; |
90 | static int wccpLowestIP(void); | |
91 | static EVH wccpHereIam; | |
92 | static EVH wccpAssignBuckets; | |
320e9f36 | 93 | |
320e9f36 | 94 | /* |
95 | * The functions used during startup: | |
96 | * wccpInit | |
97 | * wccpConnectionOpen | |
98 | * wccpConnectionShutdown | |
99 | * wccpConnectionClose | |
100 | */ | |
101 | ||
102 | void | |
103 | wccpInit(void) | |
104 | { | |
105 | debug(80, 5) ("wccpInit: Called\n"); | |
1f38f50a | 106 | if (eventFind(wccpHereIam, NULL)) |
107 | return; | |
320e9f36 | 108 | memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am)); |
109 | wccp_here_i_am.type = htonl(WCCP_HERE_I_AM); | |
110 | wccp_here_i_am.version = htonl(WCCP_VERSION); | |
f6308664 | 111 | wccp_here_i_am.revision = htonl(WCCP_REVISION); |
b5b86e2c | 112 | change = 1; |
1f38f50a | 113 | if (Config.Wccp.router.s_addr != any_addr.s_addr) |
114 | if (!eventFind(wccpHereIam, NULL)) | |
115 | eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1); | |
320e9f36 | 116 | } |
117 | ||
118 | void | |
119 | wccpConnectionOpen(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 | ||
178 | void | |
179 | wccpConnectionShutdown(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); | |
186 | } | |
320e9f36 | 187 | assert(theOutWccpConnection > -1); |
188 | commSetSelect(theOutWccpConnection, COMM_SELECT_READ, NULL, NULL, 0); | |
189 | } | |
190 | ||
191 | void | |
192 | wccpConnectionClose(void) | |
193 | { | |
194 | wccpConnectionShutdown(); | |
195 | if (theOutWccpConnection > -1) { | |
196 | debug(80, 1) ("FD %d Closing WCCP socket\n", theOutWccpConnection); | |
197 | comm_close(theOutWccpConnection); | |
198 | } | |
199 | } | |
200 | ||
201 | /* | |
202 | * Functions for handling the requests. | |
203 | */ | |
204 | ||
320e9f36 | 205 | /* |
206 | * Accept the UDP packet | |
f6308664 | 207 | */ |
1f38f50a | 208 | static void |
320e9f36 | 209 | wccpHandleUdp(int sock, void *not_used) |
f6308664 | 210 | { |
320e9f36 | 211 | struct sockaddr_in from; |
f6308664 | 212 | socklen_t from_len; |
213 | int len; | |
320e9f36 | 214 | |
215 | debug(80, 6) ("wccpHandleUdp: Called.\n"); | |
f6308664 | 216 | |
320e9f36 | 217 | commSetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0); |
218 | from_len = sizeof(struct sockaddr_in); | |
219 | memset(&from, '\0', from_len); | |
b5b86e2c | 220 | memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you)); |
f6308664 | 221 | |
320e9f36 | 222 | Counter.syscalls.sock.recvfroms++; |
f6308664 | 223 | |
320e9f36 | 224 | len = recvfrom(sock, |
f6308664 | 225 | &wccp_i_see_you, |
226 | WCCP_RESPONSE_SIZE, | |
227 | 0, | |
228 | (struct sockaddr *) &from, | |
229 | &from_len); | |
b5b86e2c | 230 | if (len < 0) |
231 | return; | |
ede4c165 | 232 | if (Config.Wccp.router.s_addr != from.sin_addr.s_addr) |
b5b86e2c | 233 | return; |
234 | if (ntohl(wccp_i_see_you.version) != WCCP_VERSION) | |
235 | return; | |
236 | if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU) | |
237 | return; | |
ede4c165 | 238 | if (!change) { |
b5b86e2c | 239 | change = wccp_i_see_you.change; |
240 | return; | |
241 | } | |
242 | if (change != wccp_i_see_you.change) { | |
243 | change = wccp_i_see_you.change; | |
1f38f50a | 244 | if (wccpLowestIP()) |
b5b86e2c | 245 | if (!eventFind(wccpAssignBuckets, NULL)) |
ede4c165 | 246 | eventAdd("wccpAssignBuckets", wccpAssignBuckets, NULL, 30.0, 1); |
b5b86e2c | 247 | } |
248 | } | |
f6308664 | 249 | |
1f38f50a | 250 | static int |
251 | wccpLowestIP(void) | |
b5b86e2c | 252 | { |
253 | int loop; | |
254 | for (loop = 0; loop < ntohl(wccp_i_see_you.number); loop++) { | |
1f38f50a | 255 | if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr) |
256 | return 0; | |
f6308664 | 257 | } |
1f38f50a | 258 | return 1; |
f6308664 | 259 | } |
320e9f36 | 260 | |
1f38f50a | 261 | static void |
320e9f36 | 262 | wccpHereIam(void *voidnotused) |
263 | { | |
f6308664 | 264 | debug(80, 6) ("wccpHereIam: Called\n"); |
320e9f36 | 265 | |
b5b86e2c | 266 | wccp_here_i_am.id = wccp_i_see_you.id; |
267 | send(theOutWccpConnection, | |
f6308664 | 268 | &wccp_here_i_am, |
269 | sizeof(wccp_here_i_am), | |
b5b86e2c | 270 | 0); |
320e9f36 | 271 | |
1f38f50a | 272 | if (!eventFind(wccpHereIam, NULL)) |
273 | eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1); | |
320e9f36 | 274 | } |
275 | ||
1f38f50a | 276 | static void |
b5b86e2c | 277 | wccpAssignBuckets(void *voidnotused) |
320e9f36 | 278 | { |
279 | struct wccp_assign_bucket_t wccp_assign_bucket; | |
1f38f50a | 280 | int number_buckets; |
281 | int loop_buckets; | |
282 | int loop; | |
283 | int number_caches; | |
284 | int bucket = 0; | |
285 | int *caches; | |
286 | int offset; | |
f20d9f17 | 287 | char buckets[WCCP_BUCKETS]; |
1f38f50a | 288 | char *buf; |
320e9f36 | 289 | |
290 | debug(80, 6) ("wccpAssignBuckets: Called\n"); | |
291 | memset(&wccp_assign_bucket, '\0', sizeof(wccp_assign_bucket)); | |
f20d9f17 | 292 | memset(buckets, 0xFF, WCCP_BUCKETS); |
320e9f36 | 293 | |
b5b86e2c | 294 | number_caches = ntohl(wccp_i_see_you.number); |
f6308664 | 295 | if (number_caches > WCCP_ACTIVE_CACHES) |
320e9f36 | 296 | number_caches = WCCP_ACTIVE_CACHES; |
f20d9f17 | 297 | caches = xmalloc(sizeof(int) * number_caches); |
320e9f36 | 298 | |
f6308664 | 299 | number_buckets = WCCP_BUCKETS / number_caches; |
f6308664 | 300 | for (loop = 0; loop < number_caches; loop++) { |
1f38f50a | 301 | xmemcpy(&caches[loop], |
302 | &wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr, | |
303 | sizeof(*caches)); | |
f6308664 | 304 | for (loop_buckets = 0; loop_buckets < number_buckets; loop_buckets++) { |
f20d9f17 | 305 | buckets[bucket++] = loop; |
320e9f36 | 306 | } |
307 | } | |
f20d9f17 | 308 | offset = sizeof(wccp_assign_bucket); |
309 | buf = xmalloc(offset + WCCP_BUCKETS + (sizeof(*caches) * number_caches)); | |
ede4c165 | 310 | wccp_assign_bucket.type = htonl(WCCP_ASSIGN_BUCKET); |
b5b86e2c | 311 | wccp_assign_bucket.id = wccp_i_see_you.id; |
ede4c165 | 312 | wccp_assign_bucket.number = wccp_i_see_you.number; |
f20d9f17 | 313 | |
1f38f50a | 314 | xmemcpy(buf, &wccp_assign_bucket, offset); |
315 | xmemcpy(buf + offset, caches, (sizeof(*caches) * number_caches)); | |
f20d9f17 | 316 | offset += (sizeof(*caches) * number_caches); |
1f38f50a | 317 | xmemcpy(buf + offset, buckets, WCCP_BUCKETS); |
f20d9f17 | 318 | offset += WCCP_BUCKETS; |
b5b86e2c | 319 | send(theOutWccpConnection, |
f20d9f17 | 320 | buf, |
321 | offset, | |
b5b86e2c | 322 | 0); |
323 | change = 0; | |
1f38f50a | 324 | xfree(caches); |
325 | xfree(buf); | |
320e9f36 | 326 | } |
eb824054 | 327 | |
328 | #endif /* USE_WCCP */ |