Merge the MDI and common window creation code. Change the way MDI
[wine.git] / dlls / netapi32 / nbnamecache.c
blob60ed1f8be92edb1964126b619560ab515ac3083b
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wine/debug.h"
23 #include "nbnamecache.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(netbios);
27 typedef struct _NBNameCacheNode
29 DWORD expireTime;
30 NBNameCacheEntry *entry;
31 struct _NBNameCacheNode *next;
32 } NBNameCacheNode;
34 struct NBNameCache
36 HANDLE heap;
37 CRITICAL_SECTION cs;
38 DWORD entryExpireTimeMS;
39 NBNameCacheNode *head;
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.
46 static void NBNameCacheUnlinkNode(struct NBNameCache *cache,
47 NBNameCacheNode **prev)
49 if (cache && prev && *prev)
51 NBNameCacheNode *next = (*prev)->next;
53 if ((*prev)->entry)
54 HeapFree(cache->heap, 0, (*prev)->entry);
55 HeapFree(cache->heap, 0, *prev);
56 *prev = next;
60 /* Walks the list beginning with cache->head looking for the node with name
61 * name. If the node is found, returns a pointer to the next pointer of the
62 * node _prior_ to the found node (or head if head points to it). Thus, if the
63 * node's all you want, dereference the return value twice. If you want to
64 * modify the list, modify the referent of the return value.
65 * While it's at it, deletes nodes whose time has expired (except the node
66 * you're looking for, of course).
67 * Returns NULL if the node isn't found.
68 * Assumes the caller owns cache's lock.
70 static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache,
71 const char name[NCBNAMSZ])
73 NBNameCacheNode **ret = NULL;
75 if (cache && cache->head)
77 NBNameCacheNode **ptr;
79 ptr = &cache->head;
80 while (ptr && *ptr && (*ptr)->entry)
82 if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1))
83 ret = ptr;
84 else
86 if (GetTickCount() > (*ptr)->expireTime)
87 NBNameCacheUnlinkNode(cache, ptr);
89 if (*ptr)
90 ptr = &(*ptr)->next;
93 return ret;
96 struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
98 struct NBNameCache *cache;
101 if (!heap)
102 heap = GetProcessHeap();
103 cache = (struct NBNameCache *)HeapAlloc(heap, 0,
104 sizeof(struct NBNameCache));
105 if (cache)
107 cache->heap = heap;
108 InitializeCriticalSection(&cache->cs);
109 cache->entryExpireTimeMS = entryExpireTimeMS;
110 cache->head = NULL;
112 return cache;
115 BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
117 BOOL ret;
119 if (cache && entry)
121 NBNameCacheNode **node;
123 EnterCriticalSection(&cache->cs);
124 node = NBNameCacheWalk(cache, entry->name);
125 if (node)
127 (*node)->expireTime = GetTickCount() +
128 cache->entryExpireTimeMS;
129 HeapFree(cache->heap, 0, (*node)->entry);
130 (*node)->entry = entry;
131 ret = TRUE;
133 else
135 NBNameCacheNode *newNode = (NBNameCacheNode *)HeapAlloc(
136 cache->heap, 0, sizeof(NBNameCacheNode));
137 if (newNode)
139 newNode->expireTime = GetTickCount() +
140 cache->entryExpireTimeMS;
141 newNode->entry = entry;
142 newNode->next = cache->head;
143 cache->head = newNode;
144 ret = TRUE;
146 else
147 ret = FALSE;
149 LeaveCriticalSection(&cache->cs);
151 else
152 ret = FALSE;
153 return ret;
156 const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache,
157 const UCHAR name[NCBNAMSZ])
159 const NBNameCacheEntry *ret;
160 UCHAR printName[NCBNAMSZ];
162 memcpy(printName, name, NCBNAMSZ - 1);
163 printName[NCBNAMSZ - 1] = '\0';
164 if (cache)
166 NBNameCacheNode **node;
168 EnterCriticalSection(&cache->cs);
169 node = NBNameCacheWalk(cache, name);
170 if (node)
171 ret = (*node)->entry;
172 else
173 ret = NULL;
174 LeaveCriticalSection(&cache->cs);
176 else
177 ret = NULL;
178 return ret;
181 BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache,
182 const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ])
184 BOOL ret;
186 if (cache)
188 NBNameCacheNode **node;
190 EnterCriticalSection(&cache->cs);
191 node = NBNameCacheWalk(cache, name);
192 if (node && *node && (*node)->entry)
194 memcpy((*node)->entry->nbname, nbname, NCBNAMSZ);
195 ret = TRUE;
197 else
198 ret = FALSE;
199 LeaveCriticalSection(&cache->cs);
201 else
202 ret = FALSE;
203 return ret;
206 void NBNameCacheDestroy(struct NBNameCache *cache)
208 if (cache)
210 DeleteCriticalSection(&cache->cs);
211 while (cache->head)
212 NBNameCacheUnlinkNode(cache, &cache->head);
213 HeapFree(cache->heap, 0, cache);