Remove hardcode of Find one device of midiout and wavout now scan for WaveOutXX,...
[reactos.git] / reactos / lib / netapi32 / nbnamecache.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include "nbnamecache.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(netbios);
29
30 typedef struct _NBNameCacheNode
31 {
32 DWORD expireTime;
33 NBNameCacheEntry *entry;
34 struct _NBNameCacheNode *next;
35 } NBNameCacheNode;
36
37 struct NBNameCache
38 {
39 HANDLE heap;
40 CRITICAL_SECTION cs;
41 DWORD entryExpireTimeMS;
42 NBNameCacheNode *head;
43 };
44
45 /* Unlinks the node pointed to by *prev, and frees any associated memory.
46 * If that node's next pointed to another node, *prev now points to it.
47 * Assumes the caller owns cache's lock.
48 */
49 static void NBNameCacheUnlinkNode(struct NBNameCache *cache,
50 NBNameCacheNode **prev)
51 {
52 if (cache && prev && *prev)
53 {
54 NBNameCacheNode *next = (*prev)->next;
55
56 if ((*prev)->entry)
57 HeapFree(cache->heap, 0, (*prev)->entry);
58 HeapFree(cache->heap, 0, *prev);
59 *prev = next;
60 }
61 }
62
63 /* Walks the list beginning with cache->head looking for the node with name
64 * name. If the node is found, returns a pointer to the next pointer of the
65 * node _prior_ to the found node (or head if head points to it). Thus, if the
66 * node's all you want, dereference the return value twice. If you want to
67 * modify the list, modify the referent of the return value.
68 * While it's at it, deletes nodes whose time has expired (except the node
69 * you're looking for, of course).
70 * Returns NULL if the node isn't found.
71 * Assumes the caller owns cache's lock.
72 */
73 static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache,
74 const char name[NCBNAMSZ])
75 {
76 NBNameCacheNode **ret = NULL;
77
78 if (cache && cache->head)
79 {
80 NBNameCacheNode **ptr;
81
82 ptr = &cache->head;
83 while (ptr && *ptr && (*ptr)->entry)
84 {
85 if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1))
86 ret = ptr;
87 else
88 {
89 if (GetTickCount() > (*ptr)->expireTime)
90 NBNameCacheUnlinkNode(cache, ptr);
91 }
92 if (*ptr)
93 ptr = &(*ptr)->next;
94 }
95 }
96 return ret;
97 }
98
99 struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
100 {
101 struct NBNameCache *cache;
102
103
104 if (!heap)
105 heap = GetProcessHeap();
106 cache = (struct NBNameCache *)HeapAlloc(heap, 0,
107 sizeof(struct NBNameCache));
108 if (cache)
109 {
110 cache->heap = heap;
111 InitializeCriticalSection(&cache->cs);
112 cache->entryExpireTimeMS = entryExpireTimeMS;
113 cache->head = NULL;
114 }
115 return cache;
116 }
117
118 BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
119 {
120 BOOL ret;
121
122 if (cache && entry)
123 {
124 NBNameCacheNode **node;
125
126 EnterCriticalSection(&cache->cs);
127 node = NBNameCacheWalk(cache, entry->name);
128 if (node)
129 {
130 (*node)->expireTime = GetTickCount() +
131 cache->entryExpireTimeMS;
132 HeapFree(cache->heap, 0, (*node)->entry);
133 (*node)->entry = entry;
134 ret = TRUE;
135 }
136 else
137 {
138 NBNameCacheNode *newNode = (NBNameCacheNode *)HeapAlloc(
139 cache->heap, 0, sizeof(NBNameCacheNode));
140 if (newNode)
141 {
142 newNode->expireTime = GetTickCount() +
143 cache->entryExpireTimeMS;
144 newNode->entry = entry;
145 newNode->next = cache->head;
146 cache->head = newNode;
147 ret = TRUE;
148 }
149 else
150 ret = FALSE;
151 }
152 LeaveCriticalSection(&cache->cs);
153 }
154 else
155 ret = FALSE;
156 return ret;
157 }
158
159 const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache,
160 const UCHAR name[NCBNAMSZ])
161 {
162 const NBNameCacheEntry *ret;
163 UCHAR printName[NCBNAMSZ];
164
165 memcpy(printName, name, NCBNAMSZ - 1);
166 printName[NCBNAMSZ - 1] = '\0';
167 if (cache)
168 {
169 NBNameCacheNode **node;
170
171 EnterCriticalSection(&cache->cs);
172 node = NBNameCacheWalk(cache, name);
173 if (node)
174 ret = (*node)->entry;
175 else
176 ret = NULL;
177 LeaveCriticalSection(&cache->cs);
178 }
179 else
180 ret = NULL;
181 return ret;
182 }
183
184 BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache,
185 const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ])
186 {
187 BOOL ret;
188
189 if (cache)
190 {
191 NBNameCacheNode **node;
192
193 EnterCriticalSection(&cache->cs);
194 node = NBNameCacheWalk(cache, name);
195 if (node && *node && (*node)->entry)
196 {
197 memcpy((*node)->entry->nbname, nbname, NCBNAMSZ);
198 ret = TRUE;
199 }
200 else
201 ret = FALSE;
202 LeaveCriticalSection(&cache->cs);
203 }
204 else
205 ret = FALSE;
206 return ret;
207 }
208
209 void NBNameCacheDestroy(struct NBNameCache *cache)
210 {
211 if (cache)
212 {
213 DeleteCriticalSection(&cache->cs);
214 while (cache->head)
215 NBNameCacheUnlinkNode(cache, &cache->head);
216 HeapFree(cache->heap, 0, cache);
217 }
218 }