blob: b9ed15911c7a7e99a46394699634b394ff6a1bd8 [file] [log] [blame]
Juan Lange7fd6fd2003-11-29 00:19:19 +00001/* 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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020015 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Juan Lange7fd6fd2003-11-29 00:19:19 +000016 *
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
Steven Edwards000a5c72004-02-10 20:09:43 +000022#include "config.h"
23#include "wine/port.h"
Steven Edwards000a5c72004-02-10 20:09:43 +000024
Juan Lange7fd6fd2003-11-29 00:19:19 +000025#include "nbnamecache.h"
26
Juan Lange7fd6fd2003-11-29 00:19:19 +000027typedef struct _NBNameCacheNode
28{
29 DWORD expireTime;
30 NBNameCacheEntry *entry;
31 struct _NBNameCacheNode *next;
32} NBNameCacheNode;
33
34struct NBNameCache
35{
36 HANDLE heap;
37 CRITICAL_SECTION cs;
38 DWORD entryExpireTimeMS;
39 NBNameCacheNode *head;
40};
41
42/* Unlinks the node pointed to by *prev, and frees any associated memory.
43 * If that node's next pointed to another node, *prev now points to it.
44 * Assumes the caller owns cache's lock.
45 */
46static void NBNameCacheUnlinkNode(struct NBNameCache *cache,
47 NBNameCacheNode **prev)
48{
49 if (cache && prev && *prev)
50 {
51 NBNameCacheNode *next = (*prev)->next;
52
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +000053 HeapFree(cache->heap, 0, (*prev)->entry);
Juan Lange7fd6fd2003-11-29 00:19:19 +000054 HeapFree(cache->heap, 0, *prev);
55 *prev = next;
56 }
57}
58
59/* Walks the list beginning with cache->head looking for the node with name
60 * name. If the node is found, returns a pointer to the next pointer of the
61 * node _prior_ to the found node (or head if head points to it). Thus, if the
62 * node's all you want, dereference the return value twice. If you want to
63 * modify the list, modify the referent of the return value.
64 * While it's at it, deletes nodes whose time has expired (except the node
65 * you're looking for, of course).
66 * Returns NULL if the node isn't found.
67 * Assumes the caller owns cache's lock.
68 */
69static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache,
70 const char name[NCBNAMSZ])
71{
72 NBNameCacheNode **ret = NULL;
73
74 if (cache && cache->head)
75 {
76 NBNameCacheNode **ptr;
77
78 ptr = &cache->head;
79 while (ptr && *ptr && (*ptr)->entry)
80 {
81 if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1))
82 ret = ptr;
83 else
84 {
85 if (GetTickCount() > (*ptr)->expireTime)
86 NBNameCacheUnlinkNode(cache, ptr);
87 }
88 if (*ptr)
89 ptr = &(*ptr)->next;
90 }
91 }
92 return ret;
93}
94
95struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
96{
97 struct NBNameCache *cache;
98
99
100 if (!heap)
101 heap = GetProcessHeap();
Jakob Eriksson9ed61de2005-03-24 21:01:35 +0000102 cache = HeapAlloc(heap, 0, sizeof(struct NBNameCache));
Juan Lange7fd6fd2003-11-29 00:19:19 +0000103 if (cache)
104 {
105 cache->heap = heap;
106 InitializeCriticalSection(&cache->cs);
Jan Zerebecki4a5f61b2007-03-10 22:09:30 +0100107 cache->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NBNameCache.cs");
Juan Lange7fd6fd2003-11-29 00:19:19 +0000108 cache->entryExpireTimeMS = entryExpireTimeMS;
109 cache->head = NULL;
110 }
111 return cache;
112}
113
114BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
115{
116 BOOL ret;
117
118 if (cache && entry)
119 {
120 NBNameCacheNode **node;
121
122 EnterCriticalSection(&cache->cs);
Mike McCormacka1072342005-08-29 09:38:19 +0000123 node = NBNameCacheWalk(cache, (char*)entry->name);
Juan Lange7fd6fd2003-11-29 00:19:19 +0000124 if (node)
125 {
126 (*node)->expireTime = GetTickCount() +
127 cache->entryExpireTimeMS;
128 HeapFree(cache->heap, 0, (*node)->entry);
129 (*node)->entry = entry;
130 ret = TRUE;
131 }
132 else
133 {
Jakob Eriksson9ed61de2005-03-24 21:01:35 +0000134 NBNameCacheNode *newNode = HeapAlloc(cache->heap, 0, sizeof(NBNameCacheNode));
Juan Lange7fd6fd2003-11-29 00:19:19 +0000135 if (newNode)
136 {
137 newNode->expireTime = GetTickCount() +
138 cache->entryExpireTimeMS;
139 newNode->entry = entry;
140 newNode->next = cache->head;
141 cache->head = newNode;
142 ret = TRUE;
143 }
144 else
145 ret = FALSE;
146 }
147 LeaveCriticalSection(&cache->cs);
148 }
149 else
150 ret = FALSE;
151 return ret;
152}
153
154const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache,
155 const UCHAR name[NCBNAMSZ])
156{
157 const NBNameCacheEntry *ret;
158 UCHAR printName[NCBNAMSZ];
159
160 memcpy(printName, name, NCBNAMSZ - 1);
161 printName[NCBNAMSZ - 1] = '\0';
162 if (cache)
163 {
164 NBNameCacheNode **node;
165
166 EnterCriticalSection(&cache->cs);
Andrew Talbotc4f4c2f2006-09-19 17:59:56 +0100167 node = NBNameCacheWalk(cache, (const char *)name);
Juan Lange7fd6fd2003-11-29 00:19:19 +0000168 if (node)
169 ret = (*node)->entry;
170 else
171 ret = NULL;
172 LeaveCriticalSection(&cache->cs);
173 }
174 else
175 ret = NULL;
176 return ret;
177}
178
179BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache,
180 const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ])
181{
182 BOOL ret;
183
184 if (cache)
185 {
186 NBNameCacheNode **node;
187
188 EnterCriticalSection(&cache->cs);
Andrew Talbotc4f4c2f2006-09-19 17:59:56 +0100189 node = NBNameCacheWalk(cache, (const char *)name);
Juan Lange7fd6fd2003-11-29 00:19:19 +0000190 if (node && *node && (*node)->entry)
191 {
192 memcpy((*node)->entry->nbname, nbname, NCBNAMSZ);
193 ret = TRUE;
194 }
195 else
196 ret = FALSE;
197 LeaveCriticalSection(&cache->cs);
198 }
199 else
200 ret = FALSE;
201 return ret;
202}
203
204void NBNameCacheDestroy(struct NBNameCache *cache)
205{
206 if (cache)
207 {
Jan Zerebecki4a5f61b2007-03-10 22:09:30 +0100208 cache->cs.DebugInfo->Spare[0] = 0;
Juan Lange7fd6fd2003-11-29 00:19:19 +0000209 DeleteCriticalSection(&cache->cs);
210 while (cache->head)
211 NBNameCacheUnlinkNode(cache, &cache->head);
212 HeapFree(cache->heap, 0, cache);
213 }
214}