--------------------- PatchSet 5946 Date: 2007/10/11 04:25:18 Author: amosjeffries Branch: squid3-ipv6 Tag: (none) Log: Add function to merge two IP address lists together - removes duplicates created by CNAME lookup process - also moves IPv4 results to least-preferred on the list Members: src/ipcache.cc:1.9.2.47->1.9.2.48 Index: squid3/src/ipcache.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ipcache.cc,v retrieving revision 1.9.2.47 retrieving revision 1.9.2.48 diff -u -r1.9.2.47 -r1.9.2.48 --- squid3/src/ipcache.cc 8 Oct 2007 12:28:55 -0000 1.9.2.47 +++ squid3/src/ipcache.cc 11 Oct 2007 04:25:18 -0000 1.9.2.48 @@ -1,6 +1,6 @@ /* - * $Id: ipcache.cc,v 1.9.2.47 2007/10/08 12:28:55 amosjeffries Exp $ + * $Id: ipcache.cc,v 1.9.2.48 2007/10/11 04:25:18 amosjeffries Exp $ * * DEBUG: section 14 IP Cache * AUTHOR: Harvest Derived @@ -807,14 +807,125 @@ } } +/** + * Takes two IPAddress arrays and merges them into a single array + * which is allocated dynamically to fit the number of unique addresses + * + \param aaddrs One list to merge + \param alen Size of list aaddrs + \param baddrs Other list to merge + \param alen Size of list baddrs + \param out Combined list of unique addresses (sorted with IPv6 first in IPv6-mode) + \param outlen Size of list out + */ +void +ipcacheMergeIPLists(IPAddress *aaddrs, int alen, + IPAddress *baddrs, int blen, + IPAddress **out, int &outlen ) +{ + int fc=0, t=0, c=0; + + IPAddress **ip4ptrs = new IPAddress*[255]; +#if USE_IPV6 + IPAddress **ip6ptrs = new IPAddress*[255]; +#endif + int num_ip4 = 0; + int num_ip6 = 0; + + memset(ip4ptrs, NULL, sizeof(IPAddress*)*32); +#if USE_IPV6 + memset(ip6ptrs, NULL, sizeof(IPAddress*)*32); +#endif + + // for each unique address in list A - grab ptr + for(t = 0; t < alen; t++) { + if(aaddrs[t].IsIPv4()) { + // check against IPv4 pruned list + for(c = 0; c <= num_ip4; c++) { + if(aaddrs[t] == *ip4ptrs[c]) break; // duplicate. + } + if(c > num_ip4 ) { + ip4ptrs[c] = &aaddrs[t]; + num_ip4++; + } + } +#if USE_IPV6 + else if(aaddrs[t].IsIPv6()) { + // check against IPv6 pruned list + for(c = 0; c <= num_ip6; c++) { + if(aaddrs[t] == *ip6ptrs[c]) break; // duplicate. + } + if(c > num_ip6 ) { + ip6ptrs[c] = &aaddrs[t]; + num_ip6++; + } + } +#endif + } + + // for each unique address in list B - grab ptr + for(t = 0; t < blen; t++) { + if(baddrs[t].IsIPv4()) { + // check against IPv4 pruned list + for(c = 0; c <= num_ip4; c++) { + if(baddrs[t] == *ip4ptrs[c]) break; // duplicate. + } + if(c > num_ip4 ) { + ip4ptrs[c] = &baddrs[t]; + num_ip4++; + } + } +#if USE_IPV6 + else if(baddrs[t].IsIPv6()) { + // check against IPv6 pruned list + for(c = 0; c <= num_ip6; c++) { + if(baddrs[t] == *ip6ptrs[c]) break; // duplicate. + } + if(c > num_ip6 ) { + ip6ptrs[c] = &baddrs[t]; + num_ip6++; + } + } +#endif + } + + fc = num_ip6 + num_ip4; + + debugs(14, 5, "ipcacheMergeIPLists: Merge " << alen << "+" << blen << " into " << fc << " unique IPs."); + + // copy the old IPs into the new list buffer. + out = (IPAddress**)xcalloc(fc, sizeof(IPAddress*)); + outlen=0; + +#if USE_IPV6 + /* IPv6 are preferred (tried first) over IPv4 */ + + for(int l = 0; outlen < num_ip6; l++, outlen++) { + (*out)[outlen] = *ip6ptrs[l]; + debugs(14, 5, "ipcacheMergeIPLists: #" << outlen << " " << (*out)[outlen] ); + } +#endif /* USE_IPV6 */ + + for(int l = 0; outlen < num_ip4; l++, outlen++) { + (*out)[outlen] = *ip4ptrs[l]; + debugs(14, 5, "ipcacheMergeIPLists: #" << outlen << " " << (*out)[outlen] ); + } + + assert(outlen == fc); // otherwise something broke badly! + + delete ip4ptrs; +#if USE_IPV6 + delete ip6ptrs; +#endif +} + static void ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata) { ipcache_entry *i = NULL; char *pname = NULL; - int j = 0; + IPAddress *tmpbuf = NULL; int fc = 0; - void *tmpbuf = NULL; int ttl = 0; generic_cbdata* gcb = (generic_cbdata*)cbdata; // count of addrs at parent and child (REQ as .count is a char type!) @@ -829,7 +940,7 @@ gcb->unwrap(&i); assert(i != NULL); - // make sure we are actualy waitign for a CNAME callback to be run. + // make sure we are actualy waiting for a CNAME callback to be run. assert(i->cname_wait > 0); // count this event. its being handled. i->cname_wait--; @@ -851,47 +962,28 @@ ccount = (0+ addrs->count); pcount = (0+ i->addrs.count); ttl = i->expires; - fc = pcount; /* IFF no CNAME results. do none of the processing BUT finish anyway. */ if(addrs) { - fc += ccount; debugs(14, 5, "ipcacheHandleCnameRecurse: Merge IP Lists for " << pname << " (" << pcount << "+" << ccount << ")"); + /* add new IP records to entry */ + tmpbuf = i->addrs.in_addrs; + i->addrs.in_addrs = NULL; + ipcacheMergeIPLists(tmpbuf, pcount, addrs->in_addrs, ccount, &(i->addrs.in_addrs), fc); + safe_free(tmpbuf); + if( pcount > 0) { /* IFF the parent initial lookup was given Additional records with A */ - /* FIXME INET6 : we need to merge the two lists dropping duplicates */ - - debugs(14, 5, "ipcacheHandleCnameRecurse: Add " << pcount << " IPs from Initial Lookup."); - - // copy the old IPs into the new list buffer. - tmpbuf = i->addrs.in_addrs; - i->addrs.in_addrs = (IPAddress *)xcalloc(fc, sizeof(IPAddress)); - for(int l = 0; j < pcount; l++, j++) { - i->addrs.in_addrs[j] = ((IPAddress*)tmpbuf)[l]; - debugs(14, 5, "ipcacheHandleCnameRecurse: CNAME (" << pname << ") #" << j << " " << i->addrs.in_addrs[j] ); - } - - // copy the 'bad IP mask' + // clear the 'bad IP mask' safe_free(i->addrs.bad_mask); + } + // create a new bad IP mask to fit the new size needed. + if(fc > 0) { i->addrs.bad_mask = (unsigned char*)xcalloc(fc, sizeof(unsigned char)); memset(i->addrs.bad_mask, 0, sizeof(unsigned char)*fc); } - else { - i->addrs.in_addrs = (IPAddress *)xcalloc(ccount, sizeof(IPAddress)); - i->addrs.bad_mask = (unsigned char *)xcalloc(ccount, sizeof(unsigned char)); - memset(i->addrs.bad_mask, 0, sizeof(unsigned char) * ccount); - } - - /* add new IP records to entry */ - debugs(14, 5, "ipcacheHandleCnameRecurse: Add " << ccount << " IPs from CNAME Lookup."); - for(int l = 0; l < ccount && j < fc; l++, j++) { - i->addrs.in_addrs[j] = addrs->in_addrs[l]; - debugs(14, 3, "ipcacheHandleCnameRecurse: CNAME (" << pname << ") #" << j << " " << i->addrs.in_addrs[j] ); - } - - assert(j == fc); if (fc < 256) i->addrs.count = (unsigned char) fc;