Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: 58badfca4f
Fetching contributors…

Cannot retrieve contributors at this time

336 lines (304 sloc) 9.311 kB
/*
* $Id: wccp.c,v 1.31 2006/06/26 15:01:59 hno Exp $
*
* DEBUG: section 80 WCCP Support
* AUTHOR: Glenn Chisholm
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
* ----------------------------------------------------------
*
* Squid is the result of efforts by numerous individuals from
* the Internet community; see the CONTRIBUTORS file for full
* details. Many organizations have provided support for Squid's
* development; see the SPONSORS file for full details. Squid is
* Copyrighted (C) 2001 by the Regents of the University of
* California; see the COPYRIGHT file for full details. Squid
* incorporates software developed and/or copyrighted by other
* sources; see the CREDITS file for full details.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
#include "squid.h"
#if USE_WCCP
#define WCCP_PORT 2048
#define WCCP_REVISION 0
#define WCCP_ACTIVE_CACHES 32
#define WCCP_HASH_SIZE 32
#define WCCP_BUCKETS 256
#define WCCP_CACHE_LEN 4
#define WCCP_HERE_I_AM 7
#define WCCP_I_SEE_YOU 8
#define WCCP_ASSIGN_BUCKET 9
struct wccp_here_i_am_t {
int type;
int version;
int revision;
char hash[WCCP_HASH_SIZE];
int reserved;
int id;
};
struct wccp_cache_entry_t {
struct in_addr ip_addr;
int revision;
char hash[WCCP_HASH_SIZE];
int reserved;
};
struct wccp_i_see_you_t {
int type;
int version;
int change;
int id;
int number;
struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES];
};
struct wccp_assign_bucket_t {
int type;
int id;
int number;
};
static int theWccpConnection = -1;
static struct wccp_here_i_am_t wccp_here_i_am;
static struct wccp_i_see_you_t wccp_i_see_you;
static int last_change;
static int last_id;
static int last_assign_buckets_change;
static int number_caches;
static struct in_addr local_ip;
static PF wccpHandleUdp;
static int wccpLowestIP(void);
static EVH wccpHereIam;
static void wccpAssignBuckets(void);
/*
* The functions used during startup:
* wccpInit
* wccpConnectionOpen
* wccpConnectionShutdown
* wccpConnectionClose
*/
void
wccpInit(void)
{
debug(80, 5) ("wccpInit: Called\n");
memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
wccp_here_i_am.type = htonl(WCCP_HERE_I_AM);
wccp_here_i_am.version = htonl(Config.Wccp.version);
wccp_here_i_am.revision = htonl(WCCP_REVISION);
last_change = 0;
last_id = 0;
last_assign_buckets_change = 0;
number_caches = 0;
if (Config.Wccp.router.s_addr != any_addr.s_addr)
if (!eventFind(wccpHereIam, NULL))
eventAdd("wccpHereIam", wccpHereIam, NULL, 5.0, 1);
}
void
wccpConnectionOpen(void)
{
u_short port = WCCP_PORT;
struct sockaddr_in router, local;
socklen_t local_len, router_len;
debug(80, 5) ("wccpConnectionOpen: Called\n");
if (Config.Wccp.router.s_addr == any_addr.s_addr) {
debug(1, 1) ("WCCP Disabled.\n");
return;
}
theWccpConnection = comm_open(SOCK_DGRAM,
IPPROTO_UDP,
Config.Wccp.address,
port,
COMM_NONBLOCKING,
"WCCP Socket");
if (theWccpConnection < 0)
fatal("Cannot open WCCP Port");
commSetSelect(theWccpConnection,
COMM_SELECT_READ,
wccpHandleUdp,
NULL,
0);
debug(1, 1) ("Accepting WCCP messages on port %d, FD %d.\n",
(int) port, theWccpConnection);
router_len = sizeof(router);
memset(&router, '\0', router_len);
router.sin_family = AF_INET;
router.sin_port = htons(port);
router.sin_addr = Config.Wccp.router;
if (connect(theWccpConnection, (struct sockaddr *) &router, router_len))
fatal("Unable to connect WCCP out socket");
local_len = sizeof(local);
memset(&local, '\0', local_len);
if (getsockname(theWccpConnection, (struct sockaddr *) &local, &local_len))
fatal("Unable to getsockname on WCCP out socket");
local_ip.s_addr = local.sin_addr.s_addr;
}
void
wccpConnectionClose(void)
{
if (theWccpConnection > -1) {
debug(80, 1) ("FD %d Closing WCCP socket\n", theWccpConnection);
comm_close(theWccpConnection);
theWccpConnection = -1;
}
}
/*
* Functions for handling the requests.
*/
/*
* Accept the UDP packet
*/
static void
wccpHandleUdp(int sock, void *not_used)
{
struct sockaddr_in from;
socklen_t from_len;
int len;
debug(80, 6) ("wccpHandleUdp: Called.\n");
commSetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
from_len = sizeof(struct sockaddr_in);
memset(&from, '\0', from_len);
memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
statCounter.syscalls.sock.recvfroms++;
len = recvfrom(sock,
(void *) &wccp_i_see_you,
sizeof(wccp_i_see_you),
0,
(struct sockaddr *) &from,
&from_len);
debug(80, 3) ("wccpHandleUdp: %d bytes WCCP pkt from %s: type=%u, version=%u, change=%u, id=%u, number=%u\n",
len,
inet_ntoa(from.sin_addr),
(unsigned) ntohl(wccp_i_see_you.type),
(unsigned) ntohl(wccp_i_see_you.version),
(unsigned) ntohl(wccp_i_see_you.change),
(unsigned) ntohl(wccp_i_see_you.id),
(unsigned) ntohl(wccp_i_see_you.number));
if (len < 0)
return;
if (Config.Wccp.router.s_addr != from.sin_addr.s_addr)
return;
if (ntohl(wccp_i_see_you.version) != Config.Wccp.version)
return;
if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
return;
if (ntohl(wccp_i_see_you.number) > WCCP_ACTIVE_CACHES) {
debug(80, 1) ("Ignoring WCCP_I_SEE_YOU from %s with number of caches set to %d\n",
inet_ntoa(from.sin_addr), (int) ntohl(wccp_i_see_you.number));
return;
}
last_id = wccp_i_see_you.id;
if ((0 == last_change) && (number_caches == ntohl(wccp_i_see_you.number))) {
if (last_assign_buckets_change == wccp_i_see_you.change) {
/*
* After a WCCP_ASSIGN_BUCKET message, the router should
* update the change value. If not, maybe the route didn't
* receive our WCCP_ASSIGN_BUCKET message, so send it again.
*
* Don't update change here. Instead, fall through to
* the next block to call wccpAssignBuckets() again.
*/
(void) 0;
} else {
last_change = wccp_i_see_you.change;
return;
}
}
if (last_change != wccp_i_see_you.change) {
last_change = wccp_i_see_you.change;
if (wccpLowestIP() && wccp_i_see_you.number) {
last_assign_buckets_change = last_change;
wccpAssignBuckets();
}
}
}
static int
wccpLowestIP(void)
{
int loop;
int found = 0;
/*
* We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
*/
for (loop = 0; loop < ntohl(wccp_i_see_you.number); loop++) {
assert(loop < WCCP_ACTIVE_CACHES);
if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr)
return 0;
if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr == local_ip.s_addr)
found = 1;
}
return found;
}
static void
wccpHereIam(void *voidnotused)
{
debug(80, 6) ("wccpHereIam: Called\n");
wccp_here_i_am.id = last_id;
send(theWccpConnection,
&wccp_here_i_am,
sizeof(wccp_here_i_am),
0);
if (!eventFind(wccpHereIam, NULL))
eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
}
static void
wccpAssignBuckets(void)
{
struct wccp_assign_bucket_t *wccp_assign_bucket;
int wab_len;
char *buckets;
int buckets_per_cache;
int loop;
int bucket = 0;
int *caches;
int cache_len;
char *buf;
debug(80, 6) ("wccpAssignBuckets: Called\n");
number_caches = ntohl(wccp_i_see_you.number);
assert(number_caches > 0);
assert(number_caches <= WCCP_ACTIVE_CACHES);
wab_len = sizeof(struct wccp_assign_bucket_t);
cache_len = WCCP_CACHE_LEN * number_caches;
buf = xmalloc(wab_len +
WCCP_BUCKETS +
cache_len);
wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
caches = (int *) (buf + wab_len);
buckets = buf + wab_len + cache_len;
memset(wccp_assign_bucket, '\0', sizeof(wccp_assign_bucket));
memset(buckets, 0xFF, WCCP_BUCKETS);
buckets_per_cache = WCCP_BUCKETS / number_caches;
for (loop = 0; loop < number_caches; loop++) {
int i;
xmemcpy(&caches[loop],
&wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr,
sizeof(*caches));
for (i = 0; i < buckets_per_cache; i++) {
assert(bucket < WCCP_BUCKETS);
buckets[bucket++] = loop;
}
}
while (bucket < WCCP_BUCKETS) {
buckets[bucket++] = number_caches - 1;
}
wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
wccp_assign_bucket->id = wccp_i_see_you.id;
wccp_assign_bucket->number = wccp_i_see_you.number;
send(theWccpConnection,
buf,
wab_len + WCCP_BUCKETS + cache_len,
0);
last_change = 0;
xfree(buf);
}
#endif /* USE_WCCP */
Jump to Line
Something went wrong with that request. Please try again.