xref: /reactos/dll/win32/netapi32/nbcmdqueue.c (revision c2c66aff)
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 
18 #include "netapi32.h"
19 
20 WINE_DEFAULT_DEBUG_CHANNEL(netbios);
21 
22 struct NBCmdQueue
23 {
24     HANDLE           heap;
25     CRITICAL_SECTION cs;
26     PNCB             head;
27 };
28 
29 #define CANCEL_EVENT_PTR(ncb) (PHANDLE)((ncb)->ncb_reserve)
30 #define NEXT_PTR(ncb) (PNCB *)((ncb)->ncb_reserve + sizeof(HANDLE))
31 
32 /* The reserved area of an ncb will be used for the following data:
33  * - a cancelled flag (BOOL, 4 bytes??)
34  * - a handle to an event that's set by a cancelled command on completion
35  *   (HANDLE, 4 bytes)
36  * These members are used in the following way
37  * - on cancel, set the event member of the reserved field (with create event)
38  * - NBCmdComplete will delete the ncb from the queue of there's no event;
39  *   otherwise it will set the event and not delete the ncb
40  * - cancel must lock the queue before finding the ncb in it, and can unlock it
41  *   once it's set the event (and the cancelled flag)
42  * - NBCmdComplete must lock the queue before attempting to remove the ncb or
43  *   check the event
44  * - NBCmdQueueCancelAll will lock the queue, and cancel all ncb's in the queue.
45  *   It'll then unlock the queue, and wait on the event in the head of the queue
46  *   until there's no more ncb's in the queue.
47  * Space optimization: use the handle as a boolean.  NULL == 0 => not cancelled.
48  * Non-NULL == valid handle => cancelled.  This allows storing a next pointer
49  * in the ncb's reserved field as well, avoiding a memory alloc for a new
50  * command (cool).
51  */
52 
NBCmdQueueCreate(HANDLE heap)53 struct NBCmdQueue *NBCmdQueueCreate(HANDLE heap)
54 {
55     struct NBCmdQueue *queue;
56 
57     if (heap == NULL)
58         heap = GetProcessHeap();
59     queue = HeapAlloc(heap, 0, sizeof(struct NBCmdQueue));
60     if (queue)
61     {
62         queue->heap = heap;
63         InitializeCriticalSection(&queue->cs);
64         queue->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NBCmdQueue.cs");
65         queue->head = NULL;
66     }
67     return queue;
68 }
69 
NBCmdQueueAdd(struct NBCmdQueue * queue,PNCB ncb)70 UCHAR NBCmdQueueAdd(struct NBCmdQueue *queue, PNCB ncb)
71 {
72     UCHAR ret;
73 
74     TRACE(": queue %p, ncb %p\n", queue, ncb);
75 
76     if (!queue)
77         return NRC_BADDR;
78     if (!ncb)
79         return NRC_INVADDRESS;
80 
81     *CANCEL_EVENT_PTR(ncb) = NULL;
82     EnterCriticalSection(&queue->cs);
83     *NEXT_PTR(ncb) = queue->head;
84     queue->head = ncb;
85     ret = NRC_GOODRET;
86     LeaveCriticalSection(&queue->cs);
87     TRACE("returning 0x%02x\n", ret);
88     return ret;
89 }
90 
NBCmdQueueFindNBC(struct NBCmdQueue * queue,PNCB ncb)91 static PNCB *NBCmdQueueFindNBC(struct NBCmdQueue *queue, PNCB ncb)
92 {
93     PNCB *ret;
94 
95     if (!queue || !ncb)
96         ret = NULL;
97     else
98     {
99         ret = &queue->head;
100         while (ret && *ret != ncb)
101             ret = NEXT_PTR(*ret);
102     }
103     return ret;
104 }
105 
NBCmdQueueCancel(struct NBCmdQueue * queue,PNCB ncb)106 UCHAR NBCmdQueueCancel(struct NBCmdQueue *queue, PNCB ncb)
107 {
108     UCHAR ret;
109     PNCB *spot;
110 
111     TRACE(": queue %p, ncb %p\n", queue, ncb);
112 
113     if (!queue)
114         return NRC_BADDR;
115     if (!ncb)
116         return NRC_INVADDRESS;
117 
118     EnterCriticalSection(&queue->cs);
119     spot = NBCmdQueueFindNBC(queue, ncb);
120     if (spot)
121     {
122         *CANCEL_EVENT_PTR(*spot) = CreateEventW(NULL, FALSE, FALSE, NULL);
123         WaitForSingleObject(*CANCEL_EVENT_PTR(*spot), INFINITE);
124         CloseHandle(*CANCEL_EVENT_PTR(*spot));
125         *spot = *NEXT_PTR(*spot);
126         if (ncb->ncb_retcode == NRC_CMDCAN)
127             ret = NRC_CMDCAN;
128         else
129             ret = NRC_CANOCCR;
130     }
131     else
132         ret = NRC_INVADDRESS;
133     LeaveCriticalSection(&queue->cs);
134     TRACE("returning 0x%02x\n", ret);
135     return ret;
136 }
137 
NBCmdQueueComplete(struct NBCmdQueue * queue,PNCB ncb,UCHAR retcode)138 UCHAR NBCmdQueueComplete(struct NBCmdQueue *queue, PNCB ncb, UCHAR retcode)
139 {
140     UCHAR ret;
141     PNCB *spot;
142 
143     TRACE(": queue %p, ncb %p\n", queue, ncb);
144 
145     if (!queue)
146         return NRC_BADDR;
147     if (!ncb)
148         return NRC_INVADDRESS;
149 
150     EnterCriticalSection(&queue->cs);
151     spot = NBCmdQueueFindNBC(queue, ncb);
152     if (spot)
153     {
154         if (*CANCEL_EVENT_PTR(*spot))
155             SetEvent(*CANCEL_EVENT_PTR(*spot));
156         else
157             *spot = *NEXT_PTR(*spot);
158         ret = NRC_GOODRET;
159     }
160     else
161         ret = NRC_INVADDRESS;
162     LeaveCriticalSection(&queue->cs);
163     TRACE("returning 0x%02x\n", ret);
164     return ret;
165 }
166 
NBCmdQueueCancelAll(struct NBCmdQueue * queue)167 UCHAR NBCmdQueueCancelAll(struct NBCmdQueue *queue)
168 {
169     UCHAR ret;
170 
171     TRACE(": queue %p\n", queue);
172 
173     if (!queue)
174         return NRC_BADDR;
175 
176     EnterCriticalSection(&queue->cs);
177     while (queue->head)
178     {
179         TRACE(": waiting for ncb %p (command 0x%02x)\n", queue->head,
180          queue->head->ncb_command);
181         NBCmdQueueCancel(queue, queue->head);
182     }
183     LeaveCriticalSection(&queue->cs);
184     ret = NRC_GOODRET;
185     TRACE("returning 0x%02x\n", ret);
186     return ret;
187 }
188 
NBCmdQueueDestroy(struct NBCmdQueue * queue)189 void NBCmdQueueDestroy(struct NBCmdQueue *queue)
190 {
191     TRACE(": queue %p\n", queue);
192 
193     if (queue)
194     {
195         NBCmdQueueCancelAll(queue);
196         queue->cs.DebugInfo->Spare[0] = 0;
197         DeleteCriticalSection(&queue->cs);
198         HeapFree(queue->heap, 0, queue);
199     }
200 }
201