/* * $Id$ * * 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; /* 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 // ftp made up, not part of spec #define WCCP2_SERVICE_ID_FTP 21 #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_CAPABILITY_INFO 8 typedef struct { struct in_addr addr; uint16_t version; uint16_t unassigned; uint32_t buckets[8]; uint16_t weight; uint16_t status; } wccp2_cache_identity_element_t; #if 0 typedef struct { uint16_t type; uint16_t length; uint32_t change; uint32_t key; uint32_t n_routers; struct in_addr routers[]; uint32_t n_caches; wccp2_cache_identity_element_t caches[]; } wccp2_router_view_t; typedef struct { uint16_t type; uint16_t length; uint32_t version; uint32_t n_routers; wccp2_router_id_element_t routers[]; uint32_t n_caches; struct in_addr caches[]; } wccp2_wc_view_info_t; #endif typedef struct { 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; // service_info uint16_t service_length; uint8_t service; // 0||1 (standard or dynamic) uint8_t serviceid; // well-known 0 - 50 // char service_filler[22]; uint8_t srv_priority; // well-known srv has prio of 240 uint8_t srv_protocol; // ip protocol identifier uint32_t srv_flags; uint16_t srv_ports[8]; // zero-terminated uint16_t cache_identity_type; uint16_t cache_identity_length; char data[WCCP_RESPONSE_SIZE]; int data_len; wccp2_cache_identity_element_t identity; } wccp2_here_i_am_t; typedef struct { uint32_t type; uint16_t version; uint16_t length; char data[WCCP_RESPONSE_SIZE]; int id; } wccp2_i_see_you_t; struct wccp2_item_header_t { uint16_t type; uint16_t length; }; struct wccp2_router_id_element_t { struct in_addr router_addr; uint32_t received_id; }; struct wccp2_router_info_t { uint16_t type; uint16_t length; uint32_t member_change; struct in_addr key_address; uint32_t key_version; uint32_t n_routers; }; typedef struct { struct in_addr router_id; uint32_t received_id; uint32_t version; } wccp2_router_assignment_element_t; struct wccp2_assign_bucket_t { int type; int id; int number; }; #define WCCP2_SRC_IP 0x0001 #define WCCP2_DST_IP 0x0002 #define WCCP2_SRC_PORT 0x0004 #define WCCP2_DST_PORT 0x0008 #define WCCP2_PORTS_DEFINED 0x0010 #define WCCP2_PORTS_SRC 0x0020 #define WCCP2_ALT_SRC_IP 0x0100 #define WCCP2_ALT_DST_IP 0x0200 #define WCCP2_ALT_SRC_PORT 0x0400 #define WCCP2_ALT_DST_PORT 0x0800 /* END WCCP V2 */ typedef struct { uint8_t service; // 0||1 (standard or dynamic) uint8_t serviceid; // well-known 0 - 50 uint8_t srv_priority; // well-known srv has prio of 240 uint8_t srv_protocol; // ip protocol identifier uint32_t srv_flags; uint16_t srv_ports[8]; // zero-terminated } service_t; struct _router_t { struct wccp2_router_id_element_t element; int state; uint32_t assignment_version; struct _router_t *next; }; typedef struct _router_t router_t; typedef struct { int change; int n_routers; router_t *routers; int n_caches; router_t *caches; // ugly hack for now service_t service; uint32_t assignment_version; wccp2_here_i_am_t h; } service_group_t; CBDATA_TYPE(service_group_t); struct service_list_t { service_group_t *sg; struct service_list_t *next; }; typedef struct service_list_t* service_list; static service_list services = NULL; 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; service_t service; uint16_t assignment_type; uint16_t assignment_length; struct in_addr assignment_key_address; uint32_t assignment_key_version; uint32_t assignment_num_routers; char data[WCCP_RESPONSE_SIZE]; }; router_t *routerFind (service_group_t *g, struct in_addr *addr) { router_t *s; if ((g == NULL) || (addr == NULL)) return NULL; for (s = g->routers; s; s = s->next) if (s->element.router_addr.s_addr == addr->s_addr) return s; return NULL; } void routerAdd(service_group_t *g, router_t *r) { if ((g == NULL) || (r == NULL)) return; r->next = NULL; if (g->routers == NULL) g->routers = r; else { r->next = g->routers; g->routers = r; } } service_group_t *serviceFind(uint8_t service_type, uint8_t service_id) { service_list s; for (s = services; s; s=s->next) if ((s->sg->service.service == service_type) && (s->sg->service.serviceid == service_id)) return s->sg; return NULL; } void serviceAdd(service_group_t *t) { struct service_list_t *q; if (serviceFind(t->service.service, t->service.serviceid)) return; q = xmalloc(sizeof(struct service_list_t)); q->sg = t; q->next = NULL; if (services == NULL) { services = q; } else { q->next = services; services = q; } return; } static PF wccp2HandleUdp; static int wccp2LowestIP(void); static EVH wccp2HereIam; static EVH wccp2AssignBuckets; /* * The functions used during startup: * wccp2Init * wccp2ConnectionOpen * wccp2ConnectionShutdown * wccp2ConnectionClose */ void make_hereiam(service_group_t *); void wccp2Init(void) { int n_routers, n_services; wordlist *s = Config.Wccp2.routers; router_t *rr; service_list sl; int i; service_group_t *http_sg, *ftp_sg; debug(80, 5) ("wccp2Init: Called\n"); if (eventFind(wccp2HereIam, NULL)) return; if (Config.Wccp2.routers == 0) return; for (s = Config.Wccp2.routers, n_routers = 0; s; s = s->next,n_routers++); CBDATA_INIT_TYPE(service_group_t); http_sg = cbdataAlloc(service_group_t); ftp_sg = cbdataAlloc(service_group_t); memset(http_sg, 0, sizeof(*http_sg)); memset(ftp_sg, 0, sizeof(*ftp_sg)); http_sg->change = 1; ftp_sg->change = 1; http_sg->service.service = WCCP2_SERVICE_STANDARD; ftp_sg->service.service = WCCP2_SERVICE_DYNAMIC; http_sg->service.serviceid = WCCP2_SERVICE_ID_HTTP; ftp_sg->service.serviceid = WCCP2_SERVICE_ID_FTP; http_sg->n_caches = 1; // for now ftp_sg->n_caches = 1; // for now // we assume all the routers do both groups for now http_sg->n_routers = n_routers; ftp_sg->n_routers = n_routers; http_sg->service.srv_priority = 240; ftp_sg->service.srv_priority = 240; http_sg->service.srv_protocol = IPPROTO_TCP; ftp_sg->service.srv_protocol = IPPROTO_TCP; http_sg->service.srv_flags = 0; ftp_sg->service.srv_flags = 0; ftp_sg->service.srv_flags &= WCCP2_DST_PORT; for (i = 0; i < 8; i++) { http_sg->service.srv_ports[i] = 0; ftp_sg->service.srv_ports[i] = 0; } http_sg->service.srv_ports[0] = 80; ftp_sg->service.srv_ports[0] = htons(21); ftp_sg->service.srv_ports[1] = htons(20); //serviceAdd (http_sg); serviceAdd(ftp_sg); cbdataFree(http_sg); for (s = Config.Wccp2.routers; s; s = s->next) { router_t *r = xmalloc(sizeof(router_t)); debug (80,9) ("JHALL: processing %s\n",s->key); memset(r, 0, sizeof(*r)); r->element.router_addr.s_addr = inet_addr(s->key); r->element.received_id = 0; r->state = 0; if (r->element.router_addr.s_addr != any_addr.s_addr) { // routerAdd(http_sg, r); routerAdd(ftp_sg, r); } else { xfree(r); } } for (rr = ftp_sg->routers; rr; rr = rr->next) if (rr->element.router_addr.s_addr != any_addr.s_addr) if (!eventFind(wccp2HereIam, NULL)) eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1); } void make_hereiam(service_group_t *srv) { int i, offset, len, n_routers; char *Short = 0; uint16_t tmp; uint32_t tmpl; router_t *rs = 0; if (srv == NULL) return; if (srv->routers == NULL) return; debug(80, 5) ("make_hereiam: Called for %d:%d\n", srv->service.service, srv->service.serviceid); srv->h.type = htonl(WCCP2_HERE_I_AM); srv->h.version = htons(WCCP2_VERSION); srv->h.length = htons(sizeof(srv->h)-8); srv->h.security_type = htons(WCCP2_SECURITY_INFO); srv->h.security_length = htons(sizeof(srv->h.security_option)); srv->h.security_option = htonl(WCCP2_NO_SECURITY); srv->h.service_type = htons(WCCP2_SERVICE_INFO); srv->h.service_length = htons(sizeof(srv->h.service) + sizeof(srv->h.serviceid) + sizeof (srv->h.srv_priority) + sizeof(srv->h.srv_protocol) + sizeof(srv->h.srv_flags) + (8*sizeof(uint16_t))); srv->h.service = srv->service.service; srv->h.serviceid = srv->service.serviceid; srv->h.srv_priority = srv->service.srv_priority; srv->h.srv_protocol = srv->service.srv_protocol; srv->h.srv_flags = srv->service.srv_flags; // memset(&srv->h.srv_ports, 0, sizeof(uint16_t)*2); for (i = 0; i < 8; i++) { srv->h.srv_ports[i] = srv->service.srv_ports[i]; srv->h.identity.buckets[i] = htonl(0); } srv->h.cache_identity_type = htons(WCCP2_WC_ID_INFO); srv->h.data_len = 0; offset = 0; srv->h.identity.addr.s_addr = Config.Wccp2.router_id.s_addr; srv->h.identity.version = htons(srv->change); srv->h.identity.unassigned = htons(0); srv->h.identity.weight = htons(0); srv->h.identity.status = htons(0); srv->h.data_len += sizeof(srv->h.identity); offset = srv->h.data_len; xmemcpy (&srv->h.data[0], &srv->h.identity, srv->h.data_len); srv->h.cache_identity_length = htons(srv->h.data_len); tmp = htons(WCCP2_WC_VIEW_INFO); xmemcpy(&srv->h.data[offset], &tmp, sizeof(uint16_t)); Short = &srv->h.data[offset+sizeof(uint16_t)]; // placeholder for len once it is known offset += 2 * sizeof(uint16_t); // type and length len = offset; // so we can do offset - len later tmpl = htonl(srv->change); xmemcpy (&srv->h.data[offset], &tmpl, sizeof(tmpl)); offset += sizeof(tmpl); n_routers = 0; for (rs = srv->routers; rs; rs = rs->next) if (rs->state) n_routers++; tmpl = htonl(n_routers); xmemcpy (&srv->h.data[offset], &tmpl, sizeof(tmpl)); offset += sizeof(tmpl); if (n_routers > 0) for (rs = srv->routers; rs; rs = rs->next) if (rs->state > 0) { xmemcpy(&srv->h.data[offset], &rs->element, sizeof(rs->element)); offset += sizeof(rs->element); } tmpl = htonl(1); // n_caches xmemcpy (&srv->h.data[offset], &tmpl, sizeof(tmpl)); offset += sizeof(tmpl); struct in_addr in = Config.Wccp2.router_id; xmemcpy(&srv->h.data[offset], &in, sizeof(in)); offset += sizeof (struct in_addr); tmp = htons(offset - len); xmemcpy(Short, &tmp, sizeof(uint16_t)); srv->h.data_len = offset; debug(80,5) ("JHALL: offset %d\n",offset); srv->h.length = htons(srv->h.data_len + sizeof(srv->h.security_type) + sizeof(srv->h.security_length) + sizeof(srv->h.security_option) + sizeof(srv->h.service_type) + sizeof(srv->h.service_length) + ntohs(srv->h.service_length) + (2 * sizeof(uint16_t))); // cache info type and length } void wccp2ConnectionOpen(void) { u_short port = WCCP_PORT; struct sockaddr_in router, local; router_t *s; service_list srv; int local_len, router_len; debug(80, 5) ("wccp2ConnectionOpen: Called\n"); for (srv = services; srv; srv=srv->next) { debug (80,9) ("JHALL: service type %d id %d\n",srv->sg->service.service, srv->sg->service.serviceid); for (s = srv->sg->routers; s; s=s->next) { debug (80,9) ("JHALL: found addr %s\n",inet_ntoa(s->element.router_addr)); if (s->element.router_addr.s_addr == any_addr.s_addr) { debug (80,9) ("JHALL: line %d\n", __LINE__); 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; } #if 0 router_len = sizeof(router); memset(&router, '\0', router_len); router.sin_family = AF_INET; router.sin_port = htons(port); router.sin_addr = Config.Wccp2.routers->s.sin_addr; 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; #else local_len = sizeof(local); memset(&local, '\0', local_len); local_ip.s_addr = Config.Wccp2.router_id.s_addr; #endif } 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) { service_list sl; wccp2ConnectionShutdown(); if (theOutWccpConnection > -1) { debug(80, 1) ("FD %d Closing WCCP socket\n", theOutWccpConnection); comm_close(theOutWccpConnection); } for (sl = services; sl; sl = sl->next) { router_t *rr; service_group_t *srv = sl->sg; for (rr = sl->sg->routers; rr; rr = rr->next) safe_free(rr); srv->routers = 0; cbdataFree(srv); } services = 0; } /* * Functions for handling the requests. */ /* * Accept the UDP packet */ static void wccp2HandleUdp(int sock, void *not_used) { struct sockaddr_in from; wordlist *s; socklen_t from_len; int len, offset; wccp2_i_see_you_t wccp2_i_see_you; service_group_t *srv; service_t service; struct wccp2_router_info_t wccp2_router_info; struct wccp2_item_header_t wccp2_item_header; struct wccp2_router_id_element_t wccp2_router_id_element; 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; for (s = Config.Wccp2.routers; s; s = s->next) if (inet_addr(s->key) == from.sin_addr.s_addr) break; if (s == NULL) { debug (80, 1) ("WCCPV2: %s is unknown, dropping him\n",inet_ntoa(from.sin_addr)); return; } if (ntohs(wccp2_i_see_you.version) != WCCP2_VERSION) return; if (ntohl(wccp2_i_see_you.type) != WCCP2_I_SEE_YOU) return; memset(&service, 0, sizeof(service)); debug(80, 1) ("Incoming WCCP v2 I_SEE_YOU from %s: length %d.\n", inet_ntoa(from.sin_addr), ntohs(wccp2_i_see_you.length)); xmemcpy(&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; xmemcpy(&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 from %s missing WCCP2_SERVICE_INFO offset %d\n", inet_ntoa(from.sin_addr), offset); return; } xmemcpy (&service, &wccp2_i_see_you.data[offset+4], ntohs(wccp2_item_header.length)); srv = serviceFind(service.service, service.serviceid); if (srv == 0) { debug(80,1) ("WARNING! router %s thinks we're in a service group we aren't, type %d id %d\n",inet_ntoa(from.sin_addr), service.service, service.serviceid); return; } offset += ntohs(wccp2_item_header.length) + 4; /* Skip WCCP2_SERVICE_INFO */ xmemcpy(&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 from %s missing WCCP2_ROUTER_ID_INFO\n", inet_ntoa(from.sin_addr)); return; } xmemcpy(&wccp2_router_id_element, &wccp2_i_see_you.data[offset+4], sizeof(wccp2_router_id_element)); debug(80, 1) ("Incoming WCCP2_I_SEE_YOU received from %s: id = %d.\n", inet_ntoa(wccp2_router_id_element.router_addr), ntohl(wccp2_router_id_element.received_id)); router_t *r = routerFind(srv, &wccp2_router_id_element.router_addr); if (r == NULL) { debug (80,1) ("WARNING: router %s not found in service %d\n",inet_ntoa(wccp2_router_id_element.router_addr), service.serviceid); return; } debug (80,9) ("JHALL: router with id %d, stored %d\n",ntohl(wccp2_router_id_element.received_id), ntohl(r->element.received_id)); if ((ntohl(r->element.received_id) +1) != ntohl(wccp2_router_id_element.received_id)) r->state = 0; if (((ntohl(r->element.received_id) +1) == ntohl(wccp2_router_id_element.received_id)) && (r->state == 0)) { r->state = 1; debug (80,6) ("Router %s now up\n", inet_ntoa(r->element.router_addr)); srv->change ++; if (wccp2LowestIP()) if (!eventFind(wccp2AssignBuckets, srv)) eventAdd("wccp2AssignBuckets", wccp2AssignBuckets, srv, 25.0, 1); } r->element.received_id = wccp2_router_id_element.received_id; offset += ntohs(wccp2_item_header.length) + 4; xmemcpy (&wccp2_router_info, &wccp2_i_see_you.data[offset], sizeof(wccp2_router_info)); debug(80, 1) ("Incoming WCCP2_I_SEE_YOU from %s member change = %d tmp=%d, key %s:%d, number of routers %d.\n", inet_ntoa(r->element.router_addr), srv->change,ntohl(wccp2_router_info.member_change), inet_ntoa(wccp2_router_info.key_address), ntohl(wccp2_router_info.key_version), ntohl(wccp2_router_info.n_routers)); r->assignment_version = ntohl(wccp2_router_info.member_change); if (!srv->change) { debug (80,9) ("JHALL: line %d\n", __LINE__); // srv->change = ntohl(wccp2_router_info.member_change); debug(80, 1) ("Incoming WCCP2_I_SEE_YOU member from %s change = %d.\n", inet_ntoa(r->element.router_addr), srv->change); // return; } debug (80,9) ("JHALL: line %d\n", __LINE__); } 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) { service_list sl; router_t *r; service_group_t *srv; debug(80, 6) ("wccp2HereIam: Called\n"); for (sl = services; sl; sl = sl->next) { srv = sl->sg; make_hereiam(srv); for (r = srv->routers; r; r = r->next) { struct sockaddr_in from; memset (&from, 0, sizeof(from)); from.sin_addr.s_addr = r->element.router_addr.s_addr; from.sin_port = htons(WCCP_PORT); debug (80,6) ("sending %d bytes to %s\n",ntohs(srv->h.length), inet_ntoa(from.sin_addr)); comm_udp_sendto(theOutWccpConnection, &from, sizeof(struct sockaddr_in), &srv->h, ntohs(srv->h.length) + 8); } } if (!eventFind(wccp2HereIam, NULL)) eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1); } static void wccp2AssignBuckets(void *voidsrv) { service_group_t *srv = (service_group_t *)voidsrv; struct wccp2_assign_bucket_t assign_bucket; int buckets_per_cache; router_t *r; int loop, i; uint32_t tmpl; int offset, len; char buckets[WCCP_BUCKETS]; struct sockaddr_in from; struct wccp2_redirect_assign_t redirect_assign; int n_routers = 0; debug(80, 6) ("wccp2AssignBuckets: Called\n"); if (srv == 0) return; memset (&from, 0, sizeof(from)); memset (&buckets, 0, 256); // bit 0 of the bucket is either 0 or 1, whether the data here is historic or // current. The other 7 bits are meant to be the cache index, so (index << 1) // since we're now forcing one cache for now, this all winds up to be 0 // but an enthusiastic soul might want to know this should they decide // to improve on this code. a value of 0xff means bucket unassigned. // deciding how to round-robin this hash to multiple caches probably depends // on the service definition and relies on a far greater inteligence than mine // jhall@maoz.com offset = 0; memset (&redirect_assign, 0, sizeof(redirect_assign)); debug(80, 1) ("WCCP2 Assigning Redirect\n"); for (r = srv->routers; r; r = r->next) if (r->state == 1) { n_routers++; xmemcpy(&redirect_assign.data[offset], &r->element, sizeof(r->element)); offset += sizeof(r->element); tmpl = htonl(r->assignment_version); xmemcpy(&redirect_assign.data[offset], &tmpl, sizeof(tmpl)); offset += sizeof(tmpl); debug (80,6) ("making %s:%d version %d\n",inet_ntoa(r->element.router_addr), ntohl(r->element.received_id), ntohl(tmpl)); } redirect_assign.type = htonl(WCCP2_REDIRECT_ASSIGN); redirect_assign.version = htons(WCCP2_VERSION); redirect_assign.security_type = htons(WCCP2_SECURITY_INFO); redirect_assign.security_length = htons(sizeof(redirect_assign.security_option)); redirect_assign.security_option = htonl(WCCP2_NO_SECURITY); redirect_assign.service_type = htons(WCCP2_SERVICE_INFO); redirect_assign.service_length = htons(sizeof(service_t)); xmemcpy (&redirect_assign.service, &srv->service, sizeof(service_t)); redirect_assign.assignment_type = htons(WCCP2_REDIRECT_ASSIGNMENT); redirect_assign.assignment_key_address = Config.Wccp2.router_id; redirect_assign.assignment_key_version = htonl(srv->change); redirect_assign.assignment_num_routers = htonl(n_routers); tmpl = htonl(1); // n_caches xmemcpy(&redirect_assign.data[offset], &tmpl, sizeof(tmpl)); offset += sizeof(tmpl); xmemcpy (&redirect_assign.data[offset], &Config.Wccp2.router_id, sizeof(struct in_addr)); offset += sizeof(struct in_addr); xmemcpy(&redirect_assign.data[offset], &buckets, sizeof (char) * 256); offset += 256; redirect_assign.assignment_length = htons(sizeof(redirect_assign.assignment_key_address) + sizeof(redirect_assign.assignment_key_version) + sizeof(redirect_assign.assignment_num_routers) + offset); redirect_assign.length = htons(ntohs(redirect_assign.assignment_length) + sizeof(service_t) + sizeof(redirect_assign.security_type) + sizeof(redirect_assign.security_length) + sizeof(redirect_assign.security_option) + sizeof(redirect_assign.service_type) + sizeof(redirect_assign.service_length) + sizeof(redirect_assign.assignment_type) + sizeof(redirect_assign.assignment_length) + sizeof(redirect_assign.assignment_key_address) + sizeof(redirect_assign.assignment_key_version) + sizeof(redirect_assign.assignment_num_routers)); for (r = srv->routers; r; r = r->next) { from.sin_addr.s_addr = r->element.router_addr.s_addr; from.sin_port = htons(WCCP_PORT); debug (80,6) ("sending %d bytes to %s\n",ntohs(redirect_assign.length), inet_ntoa(from.sin_addr)); comm_udp_sendto(theOutWccpConnection, &from, sizeof(struct sockaddr_in), &redirect_assign, ntohs(redirect_assign.length) + 8); } // srv->change = 0; } #endif /* USE_WCCPv2 */