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

Index: squid/acconfig.h
diff -u squid/acconfig.h:1.18 squid/acconfig.h:1.18.4.1
--- squid/acconfig.h:1.18	Sat Apr 13 16:09:52 2002
+++ squid/acconfig.h	Sun May 19 22:27:00 2002
@@ -118,11 +118,16 @@
 #undef SQUID_SNMP
 
 /*
- * Define to enable WCCP
+ * Define to enable WCCPv1
  */
 #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.55 squid/configure.in:1.55.2.1
--- squid/configure.in:1.55	Sun May 19 18:03:01 2002
+++ squid/configure.in	Sun May 19 22:27:00 2002
@@ -485,14 +485,24 @@
 ])
 
 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,
+[  --enble-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
Index: squid/src/Makefile.am
diff -u squid/src/Makefile.am:1.19 squid/src/Makefile.am:1.19.4.1
--- squid/src/Makefile.am:1.19	Sun Apr 14 16:07:00 2002
+++ squid/src/Makefile.am	Fri Jun 14 00:07:43 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 = \
@@ -197,6 +204,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.62 squid/src/cf.data.pre:1.62.2.1
--- squid/src/cf.data.pre:1.62	Fri May  3 07:32:42 2002
+++ squid/src/cf.data.pre	Sun May 19 22:27:01 2002
@@ -3140,10 +3140,16 @@
 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)
-	disables WCCP.
+        Use this option to define your WCCP ``home'' router for
+        Squid.   Setting the 'wccp_router' to 0.0.0.0 (the default)
+        disables WCCP.
 DOC_END
 
 NAME: wccp_version
@@ -3151,10 +3157,16 @@
 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
-	this value to 3.
+        According to some users, Cisco IOS 11.2 only supports WCCP
+        version 3.  If you're using that version of IOS, change
+        this value to 3.
 DOC_END
 
 NAME: wccp_incoming_address
@@ -3168,20 +3180,32 @@
 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
-				interface.  Do NOT use this option if
-				you're unsure how many interfaces you
-				have, or if you know you have only one
-				interface.
-
-	wccp_outgoing_address	Use this option if you require WCCP
-				messages to be sent out on only one
-				interface.  Do NOT use this option if
-				you're unsure how many interfaces you
-				have, or if you know you have only one
-				interface.
+                                messages to be received on only one
+                                interface.  Do NOT use this option if
+                                you're unsure how many interfaces you
+                                have, or if you know you have only one
+                                interface.
+
+        wccp_outgoing_address   Use this option if you require WCCP
+                                messages to be sent out on only one
+                                interface.  Do NOT use this option if
+                                you're unsure how many interfaces you
+                                have, or if you know you have only one
+                                interface.
 
         The default behavior is to not bind to any specific address.
 
Index: squid/src/cf_gen_defines
diff -u squid/src/cf_gen_defines:1.5 squid/src/cf_gen_defines:1.5.24.1
--- squid/src/cf_gen_defines:1.5	Mon Dec  3 00:03:21 2001
+++ squid/src/cf_gen_defines	Sun May 19 22:27:01 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.32 squid/src/main.c:1.32.6.1
--- squid/src/main.c:1.32	Sat Apr  6 03:34:50 2002
+++ squid/src/main.c	Sun May 19 22:27:01 2002
@@ -290,6 +290,9 @@
 #if USE_WCCP
     wccpConnectionOpen();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionOpen();
+#endif
     clientdbInit();
     icmpOpen();
     netdbInit();
@@ -316,6 +319,9 @@
 #if USE_WCCP
     wccpConnectionShutdown();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionShutdown();
+#endif
     asnFreeMemory();
 }
 
@@ -336,6 +342,9 @@
 #if USE_WCCP
     wccpConnectionClose();
 #endif
+#if USE_WCCPv2
+    wccp2ConnectionClose();
+#endif
 #if USE_DNSSERVERS
     dnsShutdown();
 #else
@@ -364,6 +373,9 @@
 #if USE_WCCP
     wccpInit();
 #endif
+#if USE_WCCPv2
+    wccp2Init();
+#endif
     serverConnectionsOpen();
     if (theOutIcpConnection >= 0) {
 	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
@@ -521,6 +533,9 @@
 #if USE_WCCP
     wccpInit();
 #endif
+#if USE_WCCPv2
+    wccp2Init();
+#endif
     serverConnectionsOpen();
     if (theOutIcpConnection >= 0) {
 	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
@@ -942,6 +957,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.54 squid/src/protos.h:1.54.2.1
--- squid/src/protos.h:1.54	Sun Apr 21 14:56:26 2002
+++ squid/src/protos.h	Sun May 19 22:27:01 2002
@@ -567,6 +567,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_WCCP */
+
 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.57 squid/src/structs.h:1.57.2.1
--- squid/src/structs.h:1.57	Mon Apr 29 23:19:26 2002
+++ squid/src/structs.h	Sun May 19 22:27:01 2002
@@ -445,6 +445,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.2.1
--- /dev/null	Tue Aug 17 12:00:41 2004
+++ squid/src/wccpv2.c	Sun May 19 22:27:01 2002
@@ -0,0 +1,499 @@
+/*
+ * $Id: squid-visolve_wccpv2-HEAD,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 */