1 /* Copyright (c) 2003 Juan Lang
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.
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.
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
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.
22 #include "nbnamecache.h"
24 typedef struct _NBNameCacheNode
27 NBNameCacheEntry
*entry
;
28 struct _NBNameCacheNode
*next
;
35 DWORD entryExpireTimeMS
;
36 NBNameCacheNode
*head
;
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.
43 static void NBNameCacheUnlinkNode(struct NBNameCache
*cache
,
44 NBNameCacheNode
**prev
)
46 if (cache
&& prev
&& *prev
)
48 NBNameCacheNode
*next
= (*prev
)->next
;
50 HeapFree(cache
->heap
, 0, (*prev
)->entry
);
51 HeapFree(cache
->heap
, 0, *prev
);
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.
66 static NBNameCacheNode
**NBNameCacheWalk(struct NBNameCache
*cache
,
67 const char name
[NCBNAMSZ
])
69 NBNameCacheNode
**ret
= NULL
;
71 if (cache
&& cache
->head
)
73 NBNameCacheNode
**ptr
;
76 while (ptr
&& *ptr
&& (*ptr
)->entry
)
78 if (!memcmp((*ptr
)->entry
->name
, name
, NCBNAMSZ
- 1))
82 if (GetTickCount() > (*ptr
)->expireTime
)
83 NBNameCacheUnlinkNode(cache
, ptr
);
92 struct NBNameCache
*NBNameCacheCreate(HANDLE heap
, DWORD entryExpireTimeMS
)
94 struct NBNameCache
*cache
;
98 heap
= GetProcessHeap();
99 cache
= HeapAlloc(heap
, 0, sizeof(struct NBNameCache
));
103 InitializeCriticalSection(&cache
->cs
);
104 cache
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": NBNameCache.cs");
105 cache
->entryExpireTimeMS
= entryExpireTimeMS
;
111 BOOL
NBNameCacheAddEntry(struct NBNameCache
*cache
, NBNameCacheEntry
*entry
)
117 NBNameCacheNode
**node
;
119 EnterCriticalSection(&cache
->cs
);
120 node
= NBNameCacheWalk(cache
, (char*)entry
->name
);
123 (*node
)->expireTime
= GetTickCount() +
124 cache
->entryExpireTimeMS
;
125 HeapFree(cache
->heap
, 0, (*node
)->entry
);
126 (*node
)->entry
= entry
;
131 NBNameCacheNode
*newNode
= HeapAlloc(cache
->heap
, 0, sizeof(NBNameCacheNode
));
134 newNode
->expireTime
= GetTickCount() +
135 cache
->entryExpireTimeMS
;
136 newNode
->entry
= entry
;
137 newNode
->next
= cache
->head
;
138 cache
->head
= newNode
;
144 LeaveCriticalSection(&cache
->cs
);
151 const NBNameCacheEntry
*NBNameCacheFindEntry(struct NBNameCache
*cache
,
152 const UCHAR name
[NCBNAMSZ
])
154 const NBNameCacheEntry
*ret
;
155 UCHAR printName
[NCBNAMSZ
];
157 memcpy(printName
, name
, NCBNAMSZ
- 1);
158 printName
[NCBNAMSZ
- 1] = '\0';
161 NBNameCacheNode
**node
;
163 EnterCriticalSection(&cache
->cs
);
164 node
= NBNameCacheWalk(cache
, (const char *)name
);
166 ret
= (*node
)->entry
;
169 LeaveCriticalSection(&cache
->cs
);
176 void NBNameCacheDestroy(struct NBNameCache
*cache
)
180 cache
->cs
.DebugInfo
->Spare
[0] = 0;
181 DeleteCriticalSection(&cache
->cs
);
183 NBNameCacheUnlinkNode(cache
, &cache
->head
);
184 HeapFree(cache
->heap
, 0, cache
);