This patch is generated from the visolve_wccpv2-s2_5 branch of s2_5 in squid
Tue Aug 17 18:57:13 2004 GMT
See http://devel.squid-cache.org/

Index: squid/acconfig.h
diff -u squid/acconfig.h:1.13.2.2 squid/acconfig.h:1.13.2.2.4.1
--- squid/acconfig.h:1.13.2.2	Sat Apr 13 16:11:22 2002
+++ squid/acconfig.h	Fri Jun 14 00:09:47 2002
@@ -112,11 +112,16 @@
 #undef SQUID_SNMP
 
 /*
- * Define to enable WCCP
+ * Define to enable WCCP V1
  */
 #define USE_WCCP 1
 
 /*
+ * Define to enable WCCP V2
+ */
+#undef USE_WCCPv2
+
+/*
  * Squid frequently calls gettimeofday() for accurate timestamping.
  * If you are concerned that gettimeofday() is called too often, and
  * could be causing performance degradation, then you can define
Index: squid/configure.in
diff -u squid/configure.in:1.42.2.14 squid/configure.in:1.42.2.14.2.1
--- squid/configure.in:1.42.2.14	Sun May 19 18:05:14 2002
+++ squid/configure.in	Fri Jun 14 00:09:47 2002
@@ -471,15 +471,27 @@
 ])
 
 AC_ARG_ENABLE(wccp,  
-[  --disable-wccp          Disable Web Cache Coordination Protocol],
+[  --disable-wccp          Disable Web Cache Coordination V1 Protocol],
 [ if test "$enableval" = "no" ; then
-    echo "Web Cache Coordination Protocol disabled"
+    echo "Web Cache Coordination V1 Protocol disabled"
     AC_DEFINE(USE_WCCP, 0)
   else
     AC_DEFINE(USE_WCCP, 1)
   fi
 ])      
 
+AM_CONDITIONAL(USE_WCCPv2, false)
+AC_ARG_ENABLE(wccpv2,
+[  --enable-wccpv2          Enable Web Cache Coordination V2 Protocol],
+[ if test "$enableval" = "yes" ; then
+    echo "Web Cache Coordination V2 Protocol enabled"
+    AC_DEFINE(USE_WCCPv2, 1)
+    AM_CONDITIONAL(USE_WCCPv2, true)
+  fi
+])
+ 
+
+
 AC_ARG_ENABLE(kill-parent-hack,
 [  --enable-kill-parent-hack
                           Kill parent on shutdown],
Index: squid/src/Makefile.am
diff -u squid/src/Makefile.am:1.13.2.3 squid/src/Makefile.am:1.13.2.3.4.1
--- squid/src/Makefile.am:1.13.2.3	Sun Apr 14 16:08:55 2002
+++ squid/src/Makefile.am	Fri Jun 14 00:09:47 2002
@@ -26,6 +26,12 @@
 DELAY_POOL_SOURCE = 
 endif
 
+if USE_WCCPv2
+WCCPv2_SOURCE = wccpv2.c
+else
+WCCPv2_SOURCE = 
+endif
+
 if ENABLE_HTCP
 HTCPSOURCE = htcp.c
 endif
@@ -97,6 +103,7 @@
 	unlinkd.c \
 	ssl_support.c \
 	ssl_support.h \
+	wccpv2.c \
 	win32.c
 
 squid_SOURCES = \
@@ -196,6 +203,7 @@
 	useragent.c \
 	wais.c \
 	wccp.c \
+	$(WCCPv2_SOURCE) \
 	whois.c \
 	$(WIN32SOURCE)
 
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.49.2.10 squid/src/cf.data.pre:1.49.2.10.4.1
--- squid/src/cf.data.pre:1.49.2.10	Sun Apr 21 14:30:12 2002
+++ squid/src/cf.data.pre	Fri Jun 14 00:09:47 2002
@@ -3115,6 +3115,12 @@
 LOC: Config.Wccp.router
 DEFAULT: 0.0.0.0
 IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_router
+TYPE: address
+LOC: Config.Wccp2.router
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCPv2
 DOC_START
 	Use this option to define your WCCP ``home'' router for
 	Squid.   Setting the 'wccp_router' to 0.0.0.0 (the default)
@@ -3126,6 +3132,12 @@
 LOC: Config.Wccp.version
 DEFAULT: 4
 IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_version
+TYPE: int
+LOC: Config.Wccp2.version
+DEFAULT: 4
+IFDEF: USE_WCCPv2
 DOC_START
 	According to some users, Cisco IOS 11.2 only supports WCCP
 	version 3.  If you're using that version of IOS, change
@@ -3143,6 +3155,18 @@
 LOC: Config.Wccp.outgoing
 DEFAULT: 255.255.255.255
 IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_incoming_address
+TYPE: address
+LOC: Config.Wccp2.incoming
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCPv2
+DOC_NONE
+NAME: wccp2_outgoing_address
+TYPE: address
+LOC: Config.Wccp2.outgoing
+DEFAULT: 255.255.255.255
+IFDEF: USE_WCCPv2
 DOC_START
         wccp_incoming_address   Use this option if you require WCCP
 				messages to be received on only one
Index: squid/src/cf_gen_defines
diff -u squid/src/cf_gen_defines:1.5 squid/src/cf_gen_defines:1.5.26.1
--- squid/src/cf_gen_defines:1.5	Mon Dec  3 00:03:21 2001
+++ squid/src/cf_gen_defines	Fri Jun 14 00:09:47 2002
@@ -18,6 +18,7 @@
 	define["USE_UNLINKD"]="--enable-unlinkd"
 	define["USE_USERAGENT_LOG"]="--enable-useragent-log"
 	define["USE_WCCP"]="--enable-wccp"
+	define["USE_WCCPv2"]="--enable-wccpv2"
 }
 /^IFDEF:/ {
 	if (define[$2] != "")
Index: squid/src/main.c
diff -u squid/src/main.c:1.28.6.2 squid/src/main.c:1.28.6.2.2.1
--- squid/src/main.c:1.28.6.2	Thu May 23 07:10:19 2002
+++ squid/src/main.c	Fri Jun 14 00:09:47 2002
@@ -292,6 +292,9 @@
 #if USE_WCCP
     wccpConnectionOpen();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionOpen();
+#endif
     clientdbInit();
     icmpOpen();
     netdbInit();
@@ -318,6 +321,9 @@
 #if USE_WCCP
     wccpConnectionShutdown();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionShutdown();
+#endif
     asnFreeMemory();
 }
 
@@ -338,6 +344,9 @@
 #if USE_WCCP
     wccpConnectionClose();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionClose();
+#endif
 #if USE_DNSSERVERS
     dnsShutdown();
 #else
@@ -366,6 +375,9 @@
 #if USE_WCCP
     wccpInit();
 #endif
+#if USE_WCCPv2
+    wccp2Init();
+#endif
     serverConnectionsOpen();
     if (theOutIcpConnection >= 0) {
 	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
@@ -526,6 +538,9 @@
 #if USE_WCCP
     wccpInit();
 #endif
+#if USE_WCCPv2
+    wccp2Init();
+#endif
     serverConnectionsOpen();
     if (theOutIcpConnection >= 0) {
 	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
@@ -950,6 +965,9 @@
 #if USE_WCCP
     wccpConnectionClose();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionClose();
+#endif
     releaseServerSockets();
     commCloseAllSockets();
     authenticateShutdown();
Index: squid/src/protos.h
diff -u squid/src/protos.h:1.41.6.5 squid/src/protos.h:1.41.6.5.4.1
--- squid/src/protos.h:1.41.6.5	Sun Apr 21 14:30:12 2002
+++ squid/src/protos.h	Fri Jun 14 00:09:47 2002
@@ -570,6 +570,13 @@
 extern void wccpConnectionClose(void);
 #endif /* USE_WCCP */
 
+#if USE_WCCPv2
+extern void wccp2Init(void);
+extern void wccp2ConnectionOpen(void);
+extern void wccp2ConnectionShutdown(void);
+extern void wccp2ConnectionClose(void);
+#endif /* USE_WCCPv2 */
+
 extern void icpHandleIcpV3(int, struct sockaddr_in, char *, int);
 extern int icpCheckUdpHit(StoreEntry *, request_t * request);
 extern void icpConnectionsOpen(void);
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.48.2.3 squid/src/structs.h:1.48.2.3.4.1
--- squid/src/structs.h:1.48.2.3	Mon Apr 29 23:21:12 2002
+++ squid/src/structs.h	Fri Jun 14 00:09:49 2002
@@ -444,6 +444,14 @@
 	int version;
     } Wccp;
 #endif
+#if USE_WCCPv2
+    struct {
+        struct in_addr router;
+        struct in_addr incoming;
+        struct in_addr outgoing;
+        int version;
+    } Wccp2;
+#endif
     char *as_whois_server;
     struct {
 	char *log;
Index: squid/src/wccpv2.c
diff -u /dev/null squid/src/wccpv2.c:1.1.4.1
--- /dev/null	Tue Aug 17 12:00:04 2004
+++ squid/src/wccpv2.c	Fri Jun 14 00:21:17 2002
@@ -0,0 +1,500 @@
+/*
+ * $Id: squid-visolve_wccpv2-s2_5-s2_5,v 1.2 2004/09/29 00:22:51 hno Exp $
+ *
+ * DEBUG: section 80     WCCP Support
+ * AUTHOR: Glenn Chisholm
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  Duane Wessels and the University of California San Diego.  Please
+ *  see the COPYRIGHT file for full details.  Squid incorporates
+ *  software developed and/or copyrighted by other sources.  Please 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"
+#include <netdb.h>
+
+#if USE_WCCPv2
+
+#define WCCP_PORT 2048
+#define WCCP_VERSION 4
+#define WCCP_REVISION 0
+#define WCCP_RESPONSE_SIZE 12448
+#define WCCP_ACTIVE_CACHES 32
+#define WCCP_HASH_SIZE 32
+#define WCCP_BUCKETS 256
+
+#define WCCP_HERE_I_AM 7
+#define WCCP_I_SEE_YOU 8
+#define WCCP_ASSIGN_BUCKET 9
+
+static int theInWccpConnection = -1;
+static int theOutWccpConnection = -1;
+static int change;
+static struct in_addr local_ip;
+
+static PF wccp2HandleUdp;
+static int wccp2LowestIP(void);
+static EVH wccp2HereIam;
+static EVH wccp2AssignBuckets;
+
+/* KDW WCCP V2 */
+#define WCCP2_HERE_I_AM		10
+#define WCCP2_I_SEE_YOU		11
+#define WCCP2_REDIRECT_ASSIGN		12
+#define WCCP2_REMOVAL_QUERY		13
+#define WCCP2_VERSION			0x200
+
+#define WCCP2_SECURITY_INFO		0
+#define WCCP2_NO_SECURITY		0
+#define WCCP2_MD5_SECURITY		1	/* Not Supported Yet */
+
+#define WCCP2_SERVICE_INFO		1
+#define WCCP2_SERVICE_STANDARD		0
+#define WCCP2_SERVICE_DYNAMIC		1	/* Not Supported Yet */
+#define WCCP2_SERVICE_ID_HTTP		0x00
+
+#define WCCP2_ROUTER_ID_INFO		2
+
+#define WCCP2_WC_ID_INFO		3
+
+#define WCCP2_RTR_VIEW_INFO		4
+
+#define WCCP2_WC_VIEW_INFO		5
+
+#define WCCP2_REDIRECT_ASSIGNMENT	6
+
+#define WCCP2_QUERY_INFO		7
+
+#define WCCP2_CAPABILTIY_INFO		8
+
+struct wccp2_here_i_am_t {
+	uint32_t type;
+	uint16_t version;
+	uint16_t length;
+  	uint16_t security_type;
+	uint16_t security_length;
+	uint32_t security_option;
+	uint16_t service_type;
+	uint16_t service_length;
+	uint8_t service;
+	uint8_t serviceid;
+	char service_filler[22];
+	uint16_t cache_identity_type;
+	uint16_t cache_identity_length;
+	struct in_addr cache_identity_addr;
+	char cache_identity_filler[40];
+	uint16_t cache_view_type;
+	uint16_t cache_view_length;
+	uint32_t cache_view_version;
+	uint32_t cache_view_num_routers;
+	struct in_addr cache_view_rtr1_addr;
+	uint32_t cache_view_rtr1_receive_id;
+	uint32_t cache_view_num_caches;
+	int id;
+};
+
+static struct wccp2_here_i_am_t wccp2_here_i_am;
+
+struct wccp2_i_see_you_t {
+	uint32_t type;
+	uint16_t version;
+	uint16_t length;
+	char data[WCCP_RESPONSE_SIZE];
+	int id;
+};
+
+static struct wccp2_i_see_you_t wccp2_i_see_you;
+
+struct wccp2_item_header_t {
+	uint16_t type;
+	uint16_t length;
+};
+
+static struct wccp2_item_header_t wccp2_item_header;
+
+struct wccp2_router_id_element_t {
+	uint16_t type;
+	uint16_t length;
+	struct in_addr router_addr;
+	uint32_t received_id;
+};
+
+static struct wccp2_router_id_element_t wccp2_router_id_element;
+
+struct wccp2_router_info_t {
+	uint16_t type;
+	uint16_t length;
+	uint32_t member_change;
+};
+
+static struct wccp2_router_info_t wccp2_router_info;
+
+struct wccp2_redirect_assign_t {
+	uint32_t type;
+	uint16_t version;
+	uint16_t length;
+  	uint16_t security_type;
+	uint16_t security_length;
+	uint32_t security_option;
+	uint16_t service_type;
+	uint16_t service_length;
+	uint8_t service;
+	uint8_t serviceid;
+	char service_filler[22];
+	uint16_t assignment_type;
+	uint16_t assignment_length;
+	struct in_addr assignment_key;
+	uint32_t assignment_key_change;
+	uint32_t assignment_num_routers;
+	struct in_addr assignment_router1_addr;
+	uint32_t assignment_router1_receive_id;
+	uint32_t assignment_router1_change_number;
+	uint32_t assignment_num_caches;
+	struct in_addr assignment_cache1_addr;
+	char buckets[WCCP_BUCKETS];
+};
+
+static struct wccp2_redirect_assign_t wccp2_redirect_assign;
+
+struct wccp2_assign_bucket_t {
+    int type;
+    int id;
+    int number;
+};
+
+static uint32_t wccp2_received_id;
+static struct in_addr wccp2_router_addr;
+
+
+/* END WCCP V2 */
+
+/*
+ * The functions used during startup:
+ * wccp2Init
+ * wccp2ConnectionOpen
+ * wccp2ConnectionShutdown
+ * wccp2ConnectionClose
+ */
+
+void
+wccp2Init(void)
+{
+    debug(80, 5) ("wccp2Init: Called\n");
+    if (eventFind(wccp2HereIam, NULL))
+	return;
+    change = 1;
+    wccp2_here_i_am.type = htonl(WCCP2_HERE_I_AM);
+    wccp2_here_i_am.version = htons(WCCP2_VERSION);
+    wccp2_here_i_am.length = htons(sizeof(wccp2_here_i_am)-8);
+    wccp2_here_i_am.security_type = htons(WCCP2_SECURITY_INFO);
+    wccp2_here_i_am.security_length = htons(sizeof(wccp2_here_i_am.security_option));
+    wccp2_here_i_am.security_option = htonl(WCCP2_NO_SECURITY);
+    wccp2_here_i_am.service_type = htons(WCCP2_SERVICE_INFO);
+    wccp2_here_i_am.service_length = htons(sizeof(wccp2_here_i_am.service) +
+                                     sizeof(wccp2_here_i_am.serviceid) +
+                                      sizeof(wccp2_here_i_am.service_filler));
+	wccp2_here_i_am.service = WCCP2_SERVICE_STANDARD;
+	wccp2_here_i_am.serviceid = WCCP2_SERVICE_ID_HTTP;
+	memset(&wccp2_here_i_am.service_filler, '\0', sizeof(wccp2_here_i_am.service_filler));
+	wccp2_here_i_am.cache_identity_type = htons(WCCP2_WC_ID_INFO);
+	wccp2_here_i_am.cache_identity_length = htons(sizeof(wccp2_here_i_am.cache_identity_addr) +
+                                       sizeof(wccp2_here_i_am.cache_identity_filler));
+	memset(&wccp2_here_i_am.cache_identity_filler, '\0', sizeof(wccp2_here_i_am.cache_identity_filler));
+	wccp2_here_i_am.cache_view_type = htons(WCCP2_WC_VIEW_INFO);
+	wccp2_here_i_am.cache_view_length = htons(sizeof(wccp2_here_i_am.cache_view_version) +
+                                   sizeof(wccp2_here_i_am.cache_view_num_routers)+
+                                   sizeof(wccp2_here_i_am.cache_view_num_caches) +
+                                   sizeof(wccp2_here_i_am.cache_view_rtr1_addr) +
+                                   sizeof(wccp2_here_i_am.cache_view_rtr1_receive_id));
+	wccp2_here_i_am.cache_view_version = htonl(1);
+	wccp2_here_i_am.cache_view_num_routers = htonl(1);
+	wccp2_here_i_am.cache_view_rtr1_addr = Config.Wccp2.router;
+	wccp2_here_i_am.cache_view_rtr1_receive_id = wccp2_router_id_element.received_id;
+	wccp2_here_i_am.cache_view_num_caches = htonl(0);
+
+
+    if (Config.Wccp2.router.s_addr != any_addr.s_addr)
+	if (!eventFind(wccp2HereIam, NULL))
+	    eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1);
+}
+
+void
+wccp2ConnectionOpen(void)
+{
+    u_short port = WCCP_PORT;
+    struct sockaddr_in router, local;
+    int local_len, router_len;
+    debug(80, 5) ("wccp2ConnectionOpen: Called\n");
+    if (Config.Wccp2.router.s_addr == any_addr.s_addr) {
+	debug(1, 1) ("WCCP Disabled.\n");
+	return;
+    }
+    theInWccpConnection = comm_open(SOCK_DGRAM,
+	0,
+	Config.Wccp2.incoming,
+	port,
+	COMM_NONBLOCKING,
+	"WCCP Socket");
+    if (theInWccpConnection < 0)
+	fatal("Cannot open WCCP Port");
+    commSetSelect(theInWccpConnection,
+	COMM_SELECT_READ,
+	wccp2HandleUdp,
+	NULL,
+	0);
+    debug(1, 1) ("Accepting WCCP v2 messages on port %d, FD %d.\n",
+	(int) port, theInWccpConnection);
+    if (Config.Wccp2.outgoing.s_addr != no_addr.s_addr) {
+	theOutWccpConnection = comm_open(SOCK_DGRAM,
+	    0,
+	    Config.Wccp2.outgoing,
+	    port,
+	    COMM_NONBLOCKING,
+	    "WCCP Socket");
+	if (theOutWccpConnection < 0)
+	    fatal("Cannot open Outgoing WCCP Port");
+	commSetSelect(theOutWccpConnection,
+	    COMM_SELECT_READ,
+    wccp2HandleUdp,
+	    NULL, 0);
+	debug(1, 1) ("Outgoing WCCP v2 messages on port %d, FD %d.\n",
+	    (int) port, theOutWccpConnection);
+	fd_note(theOutWccpConnection, "Outgoing WCCP socket");
+	fd_note(theInWccpConnection, "Incoming WCCP socket");
+    } else {
+	theOutWccpConnection = theInWccpConnection;
+    }
+    router_len = sizeof(router);
+    memset(&router, '\0', router_len);
+    router.sin_family = AF_INET;
+    router.sin_port = htons(port);
+    router.sin_addr = Config.Wccp2.router;
+    if (connect(theOutWccpConnection, (struct sockaddr *) &router, router_len))
+	fatal("Unable to connect WCCP out socket");
+    local_len = sizeof(local);
+    memset(&local, '\0', local_len);
+    if (getsockname(theOutWccpConnection, (struct sockaddr *) &local, &local_len))
+	fatal("Unable to getsockname on WCCP out socket");
+    local_ip.s_addr = local.sin_addr.s_addr;
+}
+
+void
+wccp2ConnectionShutdown(void)
+{
+    if (theInWccpConnection < 0)
+	return;
+    if (theInWccpConnection != theOutWccpConnection) {
+	debug(80, 1) ("FD %d Closing WCCP socket\n", theInWccpConnection);
+	comm_close(theInWccpConnection);
+    }
+    assert(theOutWccpConnection > -1);
+    commSetSelect(theOutWccpConnection, COMM_SELECT_READ, NULL, NULL, 0);
+}
+
+void
+wccp2ConnectionClose(void)
+{
+    wccp2ConnectionShutdown();
+    if (theOutWccpConnection > -1) {
+	debug(80, 1) ("FD %d Closing WCCP socket\n", theOutWccpConnection);
+	comm_close(theOutWccpConnection);
+    }
+}
+
+/*
+ * Functions for handling the requests.
+ */
+
+/*
+ * Accept the UDP packet
+ */
+static void
+wccp2HandleUdp(int sock, void *not_used)
+{
+    struct sockaddr_in from;
+    socklen_t from_len;
+    int len, offset;
+    uint32_t tmp;
+
+    debug(80, 6) ("wccp2HandleUdp: Called.\n");
+
+    commSetSelect(sock, COMM_SELECT_READ, wccp2HandleUdp, NULL, 0);
+    from_len = sizeof(struct sockaddr_in);
+    memset(&from, '\0', from_len);
+    memset(&wccp2_i_see_you, '\0', sizeof(wccp2_i_see_you));
+
+    statCounter.syscalls.sock.recvfroms++;
+
+    len = recvfrom(sock,
+	&wccp2_i_see_you,
+	WCCP_RESPONSE_SIZE,
+	0,
+	(struct sockaddr *) &from,
+	&from_len);
+
+    if (len < 0)
+	return;
+    if (Config.Wccp2.router.s_addr != from.sin_addr.s_addr)
+	return;
+    if (ntohs(wccp2_i_see_you.version) != WCCP2_VERSION)
+	return;
+    if (ntohl(wccp2_i_see_you.type) != WCCP2_I_SEE_YOU)
+	return;
+
+	debug(80, 1) ("Incoming WCCP v2 I_SEE_YOU length %d.\n",
+                 ntohs(wccp2_i_see_you.length));
+	memcpy(&wccp2_item_header, &wccp2_i_see_you.data[0], sizeof(wccp2_item_header));
+	if (ntohs(wccp2_item_header.type) != WCCP2_SECURITY_INFO) {
+		debug(80,1) ("WCCP2_I_SEE_YOU missing WCCP2_SECURITY_INFO\n");
+		return;
+	}
+
+	offset = ntohs(wccp2_item_header.length) + 4;
+    memcpy(&wccp2_item_header, &wccp2_i_see_you.data[offset], sizeof(wccp2_item_header));
+	if (ntohs(wccp2_item_header.type) != WCCP2_SERVICE_INFO) {
+		debug(80,1) ("WCCP2_I_SEE_YOU missing WCCP2_SERVICE_INFO offset %d\n", offset);
+		return;
+	}
+	offset += ntohs(wccp2_item_header.length) + 4; /* Skip WCCP2_SERVICE_INFO */
+	memcpy(&wccp2_item_header, &wccp2_i_see_you.data[offset], sizeof(wccp2_item_header));
+	if (ntohs(wccp2_item_header.type) != WCCP2_ROUTER_ID_INFO) {
+		debug(80,1) ("WCCP2_I_SEE_YOU missing WCCP2_ROUTER_ID_INFO\n");
+		return;
+	}
+	memcpy(&wccp2_router_id_element, &wccp2_i_see_you.data[offset], sizeof(wccp2_router_id_element));
+	debug(80, 1) ("Incoming WCCP2_I_SEE_YOU received id = %d.\n", ntohl(wccp2_router_id_element.received_id));
+
+	wccp2_router_addr = wccp2_router_id_element.router_addr;
+	wccp2_received_id = wccp2_router_id_element.received_id;
+
+    offset += ntohs(wccp2_router_id_element.length) + 4;
+    memcpy (&wccp2_router_info, &wccp2_i_see_you.data[offset], sizeof(wccp2_router_info));
+
+	debug(80, 1) ("Incoming WCCP2_I_SEE_YOU member change = %d tmp=%d.\n", change,ntohl(wccp2_router_info.member_change));
+    if (!change) {
+	change = ntohl(wccp2_router_info.member_change);
+	debug(80, 1) ("Incoming WCCP2_I_SEE_YOU member change = %d.\n", change);
+	return;
+    }
+    if (change != ntohl(wccp2_router_info.member_change)) {
+	change = ntohl(wccp2_router_info.member_change);
+	if (wccp2LowestIP())
+    if (!eventFind(wccp2AssignBuckets, NULL))
+		eventAdd("wccp2AssignBuckets", wccp2AssignBuckets, NULL, 25.0, 1);
+    }
+}
+
+static int
+wccp2LowestIP(void)
+{
+/* Force Election for now
+    int loop;
+    for (loop = 0; loop < ntohl(wccp2_i_see_you.number); loop++) {
+	if (wccp2_i_see_you.wccp2_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr)
+	    return 0;
+    }
+*/
+    return 1;
+}
+
+static void
+wccp2HereIam(void *voidnotused)
+{
+    debug(80, 6) ("wccp2HereIam: Called\n");
+
+	wccp2_here_i_am.cache_identity_addr = local_ip;
+    wccp2_here_i_am.id = wccp2_i_see_you.id;
+	wccp2_here_i_am.cache_view_rtr1_receive_id = wccp2_received_id;
+	wccp2_here_i_am.cache_view_rtr1_addr = wccp2_router_addr;
+    send(theOutWccpConnection,
+	&wccp2_here_i_am,
+	sizeof(wccp2_here_i_am),
+	0);
+
+    if (!eventFind(wccp2HereIam, NULL))
+	eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1);
+}
+
+static void
+wccp2AssignBuckets(void *voidnotused)
+{
+    struct wccp2_assign_bucket_t wccp2_assign_bucket;
+    int buckets_per_cache;
+    int loop;
+    int number_caches;
+    int bucket = 0;
+    int *caches;
+    int offset;
+    char buckets[WCCP_BUCKETS];
+    char *buf;
+
+    debug(80, 6) ("wccp2AssignBuckets: Called\n");
+    debug(80, 1) ("WCCP2 Assigning Redirect\n");
+    memset(&wccp2_redirect_assign.buckets, '\0', sizeof(wccp2_redirect_assign.buckets));
+    memset(&wccp2_redirect_assign.buckets, 0xFF, WCCP_BUCKETS);
+	for (bucket = 0; bucket < WCCP_BUCKETS; bucket++) {
+		wccp2_redirect_assign.buckets[bucket] = 0;
+    }
+    wccp2_redirect_assign.type = htonl(WCCP2_REDIRECT_ASSIGN);
+    wccp2_redirect_assign.version = htons(WCCP2_VERSION);
+    wccp2_redirect_assign.length = htons(sizeof(wccp2_redirect_assign)-8);
+	wccp2_redirect_assign.security_type = htons(WCCP2_SECURITY_INFO);
+	wccp2_redirect_assign.security_length = htons(sizeof(wccp2_redirect_assign.security_option));
+	wccp2_redirect_assign.security_option = htonl(WCCP2_NO_SECURITY);
+	wccp2_redirect_assign.service_type = htons(WCCP2_SERVICE_INFO);
+	wccp2_redirect_assign.service_length = htons(sizeof(wccp2_redirect_assign.service) +
+                                      sizeof(wccp2_redirect_assign.serviceid) +
+                                      sizeof(wccp2_redirect_assign.service_filler));
+	wccp2_redirect_assign.service = WCCP2_SERVICE_STANDARD;
+	wccp2_redirect_assign.serviceid = WCCP2_SERVICE_ID_HTTP;
+	memset(&wccp2_redirect_assign.service_filler, '\0', sizeof(wccp2_redirect_assign.service_filler));
+	wccp2_redirect_assign.assignment_type = htons(WCCP2_REDIRECT_ASSIGNMENT);
+	wccp2_redirect_assign.assignment_length =
+        htons(sizeof(wccp2_redirect_assign.assignment_key) +
+              sizeof(wccp2_redirect_assign.assignment_key_change) +
+              sizeof(wccp2_redirect_assign.assignment_num_routers) +
+              sizeof(wccp2_redirect_assign.assignment_router1_addr) +
+              sizeof(wccp2_redirect_assign.assignment_router1_receive_id) +
+              sizeof(wccp2_redirect_assign.assignment_router1_change_number) +
+              sizeof(wccp2_redirect_assign.assignment_num_caches) +
+              sizeof(wccp2_redirect_assign.assignment_cache1_addr) +
+              sizeof(wccp2_redirect_assign.buckets));
+	wccp2_redirect_assign.assignment_key = wccp2_here_i_am.cache_identity_addr;
+	wccp2_redirect_assign.assignment_key_change = htonl(change);
+	wccp2_redirect_assign.assignment_num_routers = htonl(1);
+	wccp2_redirect_assign.assignment_router1_addr = wccp2_router_addr;
+	wccp2_redirect_assign.assignment_router1_receive_id = wccp2_received_id;
+	wccp2_redirect_assign.assignment_router1_change_number = htonl(change);
+	wccp2_redirect_assign.assignment_num_caches = htonl(1);
+	wccp2_redirect_assign.assignment_cache1_addr = wccp2_here_i_am.cache_identity_addr;
+
+    send(theOutWccpConnection,
+	&wccp2_redirect_assign,
+	sizeof(wccp2_redirect_assign),
+	0);
+    change = 0;
+}
+
+#endif /* USE_WCCPv2 */
+
