ddraw: Use real handles for state blocks.
[wine] / dlls / 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., 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 "config.h"
23 #include "wine/port.h"
24
25 #include "nbnamecache.h"
26
27 typedef struct _NBNameCacheNode
28 {
29     DWORD expireTime;
30     NBNameCacheEntry *entry;
31     struct _NBNameCacheNode *next;
32 } NBNameCacheNode;
33
34 struct 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  */
46 static void NBNameCacheUnlinkNode(struct NBNameCache *cache,
47  NBNameCacheNode **prev)
48 {
49     if (cache && prev && *prev)
50     {
51         NBNameCacheNode *next = (*prev)->next;
52
53         HeapFree(cache->heap, 0, (*prev)->entry);
54         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  */
69 static 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
95 struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
96 {
97     struct NBNameCache *cache;
98     
99     
100     if (!heap)
101         heap = GetProcessHeap();
102     cache = HeapAlloc(heap, 0, sizeof(struct NBNameCache));
103     if (cache)
104     {
105         cache->heap = heap;
106         InitializeCriticalSection(&cache->cs);
107         cache->entryExpireTimeMS = entryExpireTimeMS;
108         cache->head = NULL;
109     }
110     return cache;
111 }
112
113 BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
114 {
115     BOOL ret;
116
117     if (cache && entry)
118     {
119         NBNameCacheNode **node;
120
121         EnterCriticalSection(&cache->cs);
122         node = NBNameCacheWalk(cache, (char*)entry->name);
123         if (node)
124         {
125             (*node)->expireTime = GetTickCount() +
126              cache->entryExpireTimeMS;
127             HeapFree(cache->heap, 0, (*node)->entry);
128             (*node)->entry = entry;
129             ret = TRUE;
130         }
131         else
132         {
133             NBNameCacheNode *newNode = HeapAlloc(cache->heap, 0, sizeof(NBNameCacheNode));
134             if (newNode)
135             {
136                 newNode->expireTime = GetTickCount() +
137                  cache->entryExpireTimeMS;
138                 newNode->entry = entry;
139                 newNode->next = cache->head;
140                 cache->head = newNode;
141                 ret = TRUE;
142             }
143             else
144                 ret = FALSE;
145         }
146         LeaveCriticalSection(&cache->cs);
147     }
148     else
149         ret = FALSE;
150     return ret;
151 }
152
153 const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache,
154  const UCHAR name[NCBNAMSZ])
155 {
156     const NBNameCacheEntry *ret;
157     UCHAR printName[NCBNAMSZ];
158
159     memcpy(printName, name, NCBNAMSZ - 1);
160     printName[NCBNAMSZ - 1] = '\0';
161     if (cache)
162     {
163         NBNameCacheNode **node;
164
165         EnterCriticalSection(&cache->cs);
166         node = NBNameCacheWalk(cache, (const char *)name);
167         if (node)
168             ret = (*node)->entry;
169         else
170             ret = NULL;
171         LeaveCriticalSection(&cache->cs);
172     }
173     else
174         ret = NULL;
175     return ret;
176 }
177
178 BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache,
179  const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ])
180 {
181     BOOL ret;
182
183     if (cache)
184     {
185         NBNameCacheNode **node;
186
187         EnterCriticalSection(&cache->cs);
188         node = NBNameCacheWalk(cache, (const char *)name);
189         if (node && *node && (*node)->entry)
190         {
191             memcpy((*node)->entry->nbname, nbname, NCBNAMSZ);
192             ret = TRUE;
193         }
194         else
195             ret = FALSE;
196         LeaveCriticalSection(&cache->cs);
197     }
198     else
199         ret = FALSE;
200     return ret;
201 }
202
203 void NBNameCacheDestroy(struct NBNameCache *cache)
204 {
205     if (cache)
206     {
207         DeleteCriticalSection(&cache->cs);
208         while (cache->head)
209             NBNameCacheUnlinkNode(cache, &cache->head);
210         HeapFree(cache->heap, 0, cache);
211     }
212 }