- Clean up the mask drawing code.
[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., 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 }