/******************************************************************************/
/* */
/* X r d N e t C a c h e . c c */
/* */
/* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD 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 Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include "XrdNet/XrdNetAddrInfo.hh"
#include "XrdNet/XrdNetCache.hh"
/******************************************************************************/
/* S t a t i c M e m b e r s */
/******************************************************************************/
int XrdNetCache::keepTime = 0;
/******************************************************************************/
/* C o n s t r u c t o r */
/******************************************************************************/
XrdNetCache::XrdNetCache(int psize, int csize)
{
prevtablesize = psize;
nashtablesize = csize;
Threshold = (csize * LoadMax) / 100;
nashnum = 0;
nashtable = (anItem **)malloc( (size_t)(csize*sizeof(anItem *)) );
memset((void *)nashtable, 0, (size_t)(csize*sizeof(anItem *)));
}
/******************************************************************************/
/* public A d d */
/******************************************************************************/
void XrdNetCache::Add(XrdNetAddrInfo *hAddr, const char *hName)
{
anItem Item, *hip;
int kent;
// Get the key and make sure this is a valid address (should be)
//
if (!GenKey(Item, hAddr)) return;
// We may be in a race condition, check we have this item
//
myMutex.Lock();
if ((hip = Locate(Item)))
{if (hip->hName) free(hip->hName);
hip->hName = strdup(hName);
hip->expTime = time(0) + keepTime;
myMutex.UnLock();
return;
}
// Check if we should expand the table
//
if (++nashnum > Threshold) Expand();
// Allocate a new entry
//
hip = new anItem(Item, hName, keepTime);
// Add the entry to the table
//
kent = hip->aHash % nashtablesize;
hip->Next = nashtable[kent];
nashtable[kent] = hip;
myMutex.UnLock();
}
/******************************************************************************/
/* private E x p a n d */
/******************************************************************************/
void XrdNetCache::Expand()
{
int newsize, newent, i;
size_t memlen;
anItem **newtab, *nip, *nextnip;
// Compute new size for table using a fibonacci series
//
newsize = prevtablesize + nashtablesize;
// Allocate the new table
//
memlen = (size_t)(newsize*sizeof(anItem *));
if (!(newtab = (anItem **) malloc(memlen))) return;
memset((void *)newtab, 0, memlen);
// Redistribute all of the current items
//
for (i = 0; i < nashtablesize; i++)
{nip = nashtable[i];
while(nip)
{nextnip = nip->Next;
newent = nip->aHash % newsize;
nip->Next = newtab[newent];
newtab[newent] = nip;
nip = nextnip;
}
}
// Free the old table and plug in the new table
//
free((void *)nashtable);
nashtable = newtab;
prevtablesize = nashtablesize;
nashtablesize = newsize;
// Compute new expansion threshold
//
Threshold = static_cast((static_cast(newsize)*LoadMax)/100);
}
/******************************************************************************/
/* public F i n d */
/******************************************************************************/
char *XrdNetCache::Find(XrdNetAddrInfo *hAddr)
{
anItem Item, *nip, *pip = 0;
int kent;
// Get the hash for this address
//
if (!GenKey(Item, hAddr)) return 0;
// Compute position of the hash table entry
//
myMutex.Lock();
kent = Item.aHash%nashtablesize;
// Find the entry
//
nip = nashtable[kent];
while(nip && *nip != Item) {pip = nip; nip = nip->Next;}
if (!nip) {myMutex.UnLock(); return 0;}
// Make sure entry has not expired
//
if (nip->expTime > time(0))
{char *hName = strdup(nip->hName);
myMutex.UnLock();
return hName;
}
// Remove the entry and return not found
//
if (pip) pip->Next = nip->Next;
else nashtable[kent] = nip->Next;
myMutex.UnLock();
delete nip;
return 0;
}
/******************************************************************************/
/* G e n K e y */
/******************************************************************************/
int XrdNetCache::GenKey(XrdNetCache::anItem &Item, XrdNetAddrInfo *hAddr)
{
union aPoint
{const sockaddr *sAddr;
const sockaddr_in *sAddr4;
const sockaddr_in6 *sAddr6;
} aP;
aP.sAddr = hAddr->SockAddr();
union{long long llVal; int intVal[2];} Temp;
int family = hAddr->Family();
// Get the size, validate, and generate the key
//
if (family == AF_INET)
{memcpy(Item.aVal, &(aP.sAddr4->sin_addr), 4);
Item.aHash = Item.aV4[0];
Item.aLen = 4;
return 1;
}
if (family == AF_INET6)
{memcpy(Item.aVal, &(aP.sAddr6->sin6_addr), 16);
Temp.llVal = Item.aV6[0] ^ Item.aV6[1];
Item.aHash = Temp.intVal[0] ^ Temp.intVal[1];
Item.aLen = 16;
return 1;
}
return 0;
}
/******************************************************************************/
/* Private: L o c a t e */
/******************************************************************************/
XrdNetCache::anItem *XrdNetCache::Locate(XrdNetCache::anItem &Item)
{
anItem *nip;
unsigned int kent;
// Find the entry
//
kent = Item.aHash%nashtablesize;
nip = nashtable[kent];
while(nip && *nip != Item) nip = nip->Next;
return nip;
}