--------------------- PatchSet 4241 Date: 2002/06/14 07:21:17 Author: visolve Branch: visolve_wccpv2-s2_5 Tag: (none) Log: visolve_wccpv2-s2_5 Members: src/wccpv2.c:1.1->1.1.4.1 --- /dev/null Wed Feb 14 00:58:29 2007 +++ squid/src/wccpv2.c Wed Feb 14 00:59:00 2007 @@ -0,0 +1,500 @@ +/* + * $Id: wccpv2.c,v 1.1.4.1 2002/06/14 07:21:17 visolve 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 + +#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 */ +