1 /* Copyright (c) 2003 Juan Lang 2 * 3 * This library is free software; you can redistribute it and/or 4 * modify it under the terms of the GNU Lesser General Public 5 * License as published by the Free Software Foundation; either 6 * version 2.1 of the License, or (at your option) any later version. 7 * 8 * This library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public 14 * License along with this library; if not, write to the Free Software 15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 16 * 17 * This implementation uses a linked list, because I don't have a decent 18 * hash table implementation handy. This is somewhat inefficient, but it's 19 * rather more efficient than not having a name cache at all. 20 */ 21 22 #include "netapi32.h" 23 24 typedef struct _NBNameCacheNode 25 { 26 DWORD expireTime; 27 NBNameCacheEntry *entry; 28 struct _NBNameCacheNode *next; 29 } NBNameCacheNode; 30 31 struct NBNameCache 32 { 33 HANDLE heap; 34 CRITICAL_SECTION cs; 35 DWORD entryExpireTimeMS; 36 NBNameCacheNode *head; 37 }; 38 39 /* Unlinks the node pointed to by *prev, and frees any associated memory. 40 * If that node's next pointed to another node, *prev now points to it. 41 * Assumes the caller owns cache's lock. 42 */ 43 static void NBNameCacheUnlinkNode(struct NBNameCache *cache, 44 NBNameCacheNode **prev) 45 { 46 if (cache && prev && *prev) 47 { 48 NBNameCacheNode *next = (*prev)->next; 49 50 HeapFree(cache->heap, 0, (*prev)->entry); 51 HeapFree(cache->heap, 0, *prev); 52 *prev = next; 53 } 54 } 55 56 /* Walks the list beginning with cache->head looking for the node with name 57 * name. If the node is found, returns a pointer to the next pointer of the 58 * node _prior_ to the found node (or head if head points to it). Thus, if the 59 * node's all you want, dereference the return value twice. If you want to 60 * modify the list, modify the referent of the return value. 61 * While it's at it, deletes nodes whose time has expired (except the node 62 * you're looking for, of course). 63 * Returns NULL if the node isn't found. 64 * Assumes the caller owns cache's lock. 65 */ 66 static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache, 67 const char name[NCBNAMSZ]) 68 { 69 NBNameCacheNode **ret = NULL; 70 71 if (cache && cache->head) 72 { 73 NBNameCacheNode **ptr; 74 75 ptr = &cache->head; 76 while (ptr && *ptr && (*ptr)->entry) 77 { 78 if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1)) 79 ret = ptr; 80 else 81 { 82 if (GetTickCount() > (*ptr)->expireTime) 83 NBNameCacheUnlinkNode(cache, ptr); 84 } 85 if (*ptr) 86 ptr = &(*ptr)->next; 87 } 88 } 89 return ret; 90 } 91 92 struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS) 93 { 94 struct NBNameCache *cache; 95 96 97 if (!heap) 98 heap = GetProcessHeap(); 99 cache = HeapAlloc(heap, 0, sizeof(struct NBNameCache)); 100 if (cache) 101 { 102 cache->heap = heap; 103 InitializeCriticalSection(&cache->cs); 104 cache->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NBNameCache.cs"); 105 cache->entryExpireTimeMS = entryExpireTimeMS; 106 cache->head = NULL; 107 } 108 return cache; 109 } 110 111 BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry) 112 { 113 BOOL ret; 114 115 if (cache && entry) 116 { 117 NBNameCacheNode **node; 118 119 EnterCriticalSection(&cache->cs); 120 node = NBNameCacheWalk(cache, (char*)entry->name); 121 if (node) 122 { 123 (*node)->expireTime = GetTickCount() + 124 cache->entryExpireTimeMS; 125 HeapFree(cache->heap, 0, (*node)->entry); 126 (*node)->entry = entry; 127 ret = TRUE; 128 } 129 else 130 { 131 NBNameCacheNode *newNode = HeapAlloc(cache->heap, 0, sizeof(NBNameCacheNode)); 132 if (newNode) 133 { 134 newNode->expireTime = GetTickCount() + 135 cache->entryExpireTimeMS; 136 newNode->entry = entry; 137 newNode->next = cache->head; 138 cache->head = newNode; 139 ret = TRUE; 140 } 141 else 142 ret = FALSE; 143 } 144 LeaveCriticalSection(&cache->cs); 145 } 146 else 147 ret = FALSE; 148 return ret; 149 } 150 151 const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache, 152 const UCHAR name[NCBNAMSZ]) 153 { 154 const NBNameCacheEntry *ret; 155 UCHAR printName[NCBNAMSZ]; 156 157 memcpy(printName, name, NCBNAMSZ - 1); 158 printName[NCBNAMSZ - 1] = '\0'; 159 if (cache) 160 { 161 NBNameCacheNode **node; 162 163 EnterCriticalSection(&cache->cs); 164 node = NBNameCacheWalk(cache, (const char *)name); 165 if (node) 166 ret = (*node)->entry; 167 else 168 ret = NULL; 169 LeaveCriticalSection(&cache->cs); 170 } 171 else 172 ret = NULL; 173 return ret; 174 } 175 176 void NBNameCacheDestroy(struct NBNameCache *cache) 177 { 178 if (cache) 179 { 180 cache->cs.DebugInfo->Spare[0] = 0; 181 DeleteCriticalSection(&cache->cs); 182 while (cache->head) 183 NBNameCacheUnlinkNode(cache, &cache->head); 184 HeapFree(cache->heap, 0, cache); 185 } 186 } 187