[DRIVERS] Fix 64 bit issues
[reactos.git] / drivers / sac / driver / chanmgr.c
1 /*
2 * PROJECT: ReactOS Drivers
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/sac/driver/chanmgr.c
5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "sacdrv.h"
12
13 /* GLOBALS ********************************************************************/
14
15 SAC_CHANNEL_LOCK ChannelCreateLock;
16 BOOLEAN ChannelCreateEnabled;
17 PSAC_CHANNEL ChannelArray[SAC_MAX_CHANNELS];
18 LONG ChannelRefCount[SAC_MAX_CHANNELS];
19 LONG ChannelReaped[SAC_MAX_CHANNELS];
20 SAC_CHANNEL_LOCK ChannelSlotLock[SAC_MAX_CHANNELS];
21
22 /* FUNCTIONS ******************************************************************/
23
24 #define MAX_REF_COUNT 100
25
26 #define CHANNEL_SLOT_IS_IN_USE(x) (ChannelRefCount[(x)] > 0)
27
28 FORCEINLINE
29 PSAC_CHANNEL
30 ChannelFromIndex(IN ULONG Index)
31 {
32 return ChannelArray[Index];
33 }
34
35 FORCEINLINE
36 LONG
37 ChannelGetReferenceCount(IN LONG Index)
38 {
39 return ChannelRefCount[Index];
40 }
41
42 FORCEINLINE
43 LONG
44 ChannelReferenceByIndex(IN LONG Index)
45 {
46 if (ChannelGetReferenceCount(Index) > 0)
47 {
48 ASSERT(ChannelRefCount[Index] <= MAX_REF_COUNT);
49 ASSERT(ChannelRefCount[Index] >= 1);
50 _InterlockedIncrement(&ChannelRefCount[Index]);
51 ASSERT(ChannelRefCount[Index] <= MAX_REF_COUNT);
52 ASSERT(ChannelRefCount[Index] >= 2);
53 }
54
55 return ChannelGetReferenceCount(Index);
56 }
57
58 FORCEINLINE
59 LONG
60 ChannelReferenceByIndexWithLock(IN LONG Index)
61 {
62 LONG RefCount;
63
64 ChannelSlotLock(Index);
65 RefCount = ChannelReferenceByIndex(Index);
66 ChannelSlotUnlock(Index);
67 return RefCount;
68 }
69
70 FORCEINLINE
71 LONG
72 ChannelDereferenceByIndex(IN LONG Index)
73 {
74 ASSERT(ChannelGetReferenceCount(Index) <= MAX_REF_COUNT);
75 ASSERT(ChannelGetReferenceCount(Index) > 1);
76 _InterlockedDecrement(&ChannelRefCount[Index]);
77 ASSERT(ChannelGetReferenceCount(Index) >= 1);
78 return ChannelGetReferenceCount(Index);
79 }
80
81 FORCEINLINE
82 VOID
83 ChannelDereferenceByIndexWithLock(IN LONG Index)
84 {
85 ChannelSlotLock(Index);
86 ChannelDereferenceByIndex(Index);
87 ChannelSlotUnlock(Index);
88 }
89
90 FORCEINLINE
91 VOID
92 ChannelDereferenceToZeroByIndex(IN LONG Index)
93 {
94 ASSERT(ChannelGetReferenceCount(Index) == 1);
95 ASSERT(ChannelIsActive(ChannelFromIndex(Index)) == FALSE);
96 _InterlockedExchange(&ChannelRefCount[Index], 0);
97 }
98
99 FORCEINLINE
100 VOID
101 ChannelReferenceToOneByIndex(IN LONG Index)
102 {
103 ASSERT(ChannelGetReferenceCount(Index) == 0);
104 _InterlockedExchange(&ChannelRefCount[Index], 1);
105 }
106
107 FORCEINLINE
108 VOID
109 ChannelReferenceToOneByIndexWithLock(IN LONG Index)
110 {
111 ChannelSlotLock(Index);
112 ChannelReferenceToOneByIndex(Index);
113 ChannelSlotUnlock(Index);
114 }
115
116 NTSTATUS
117 NTAPI
118 ChanMgrInitialize(VOID)
119 {
120 ULONG i;
121
122 /* Initialize the channel lock */
123 SacInitializeLock(&ChannelCreateLock);
124 ChannelCreateEnabled = TRUE;
125
126 /* Loop through the channel arrays */
127 for (i = 0; i < SAC_MAX_CHANNELS; i++)
128 {
129 /* Clear and initialize their locks */
130 ChannelArray[i] = NULL;
131 SacInitializeLock(&ChannelSlotLock[i]);
132
133 /* Clear their statuses and reference counts */
134 _InterlockedExchange(&ChannelRefCount[i], 0);
135 _InterlockedExchange(&ChannelReaped[i], 1);
136 }
137
138 /* All good */
139 return STATUS_SUCCESS;
140 }
141
142 NTSTATUS
143 NTAPI
144 ChanMgrShutdown(VOID)
145 {
146 /* FIXME: TODO */
147 return STATUS_NOT_IMPLEMENTED;
148 }
149
150 NTSTATUS
151 NTAPI
152 ChanMgrGetChannelByName(IN PWCHAR Name,
153 OUT PSAC_CHANNEL* Channel)
154 {
155 NTSTATUS Status, Status1;
156 ULONG i;
157 PSAC_CHANNEL CurrentChannel;
158 PWCHAR ChannelName;
159 BOOLEAN Found;
160 CHECK_PARAMETER1(Name);
161 CHECK_PARAMETER2(Channel);
162
163 /* Assume failure */
164 *Channel = NULL;
165 Status = STATUS_NOT_FOUND;
166
167 /* Loop through all channels */
168 for (i = 0; i < SAC_MAX_CHANNELS; i++)
169 {
170 /* Reference this one and check if it's valid */
171 if (ChannelReferenceByIndexWithLock(i) > 0)
172 {
173 /* All good, grab it */
174 CurrentChannel = ChannelFromIndex(i);
175 ASSERT(CurrentChannel != NULL);
176
177 /* Get its name */
178 Status1 = ChannelGetName(CurrentChannel, &ChannelName);
179 ASSERT(NT_SUCCESS(Status1));
180
181 /* Check if this is the name that was passed in */
182 Found = wcsicmp(Name, ChannelName);
183 SacFreePool(ChannelName);
184 if (Found)
185 {
186 /* We found it, return it (with a reference held) */
187 *Channel = CurrentChannel;
188 return STATUS_SUCCESS;
189 }
190
191 /* Not the one we want, dereference this one and keep going */
192 ChannelDereferenceByIndexWithLock(i);
193 }
194 }
195
196 /* No channels with this name were found */
197 return Status;
198 }
199
200 NTSTATUS
201 NTAPI
202 ChanMgrGetByHandle(IN SAC_CHANNEL_ID ChannelId,
203 OUT PSAC_CHANNEL* TargetChannel)
204 {
205 NTSTATUS Status;
206 ULONG i;
207 PSAC_CHANNEL Channel;
208 CHECK_PARAMETER2(TargetChannel);
209
210 /* Assume failure */
211 *TargetChannel = NULL;
212 Status = STATUS_NOT_FOUND;
213
214 /* Loop through all channels */
215 for (i = 0; i < SAC_MAX_CHANNELS; i++)
216 {
217 /* Reference this one and check if it's valid */
218 if (ChannelReferenceByIndexWithLock(i) > 0)
219 {
220 /* All good, grab it */
221 Channel = ChannelFromIndex(i);
222 ASSERT(Channel != NULL);
223
224 /* Check if the channel ID matches */
225 if (ChannelIsEqual(Channel, &ChannelId))
226 {
227 /* We found it, return it (with a reference held) */
228 *TargetChannel = Channel;
229 return STATUS_SUCCESS;
230 }
231
232 /* Not the one we want, dereference this one and keep going */
233 ChannelDereferenceByIndexWithLock(i);
234 }
235 }
236
237 /* No channels with this ID were found */
238 return Status;
239 }
240
241 NTSTATUS
242 NTAPI
243 ChanMgrReleaseChannel(IN PSAC_CHANNEL Channel)
244 {
245 LONG Index;
246 ULONG RefCount;
247 PSAC_CHANNEL ThisChannel;
248 CHECK_PARAMETER(Channel);
249
250 /* Get the index of the channel */
251 Index = ChannelGetIndex(Channel);
252
253 /* Drop a reference -- there should still be at least the keepalive left */
254 ChannelSlotLock(Index);
255 RefCount = ChannelDereferenceByIndex(Index);
256 ASSERT(RefCount > 0);
257
258 /* Do we only have the keep-alive left, and the channel is dead? */
259 if ((RefCount == 1) && !(ChannelIsActive(Channel)))
260 {
261 /* Check if the ??? flag is set, or if there's no output data */
262 ThisChannel = ChannelFromIndex(Index);
263 if (!(ThisChannel->Flags & 1))
264 {
265 /* Nope, we can wipe the references and get rid of it */
266 ChannelDereferenceToZeroByIndex(Index);
267 }
268 else if (!ThisChannel->ChannelHasNewOBufferData)
269 {
270 /* No data, we can wipe the references and get rid of it */
271 ChannelDereferenceToZeroByIndex(Index);
272 }
273 }
274
275 /* We're done, we can unlock the slot now */
276 ChannelSlotUnlock(Index);
277 return STATUS_SUCCESS;
278 }
279
280 BOOLEAN
281 NTAPI
282 ChanMgrIsUniqueName(IN PWCHAR ChannelName)
283 {
284 NTSTATUS Status;
285 BOOLEAN IsUnique = FALSE;
286 PSAC_CHANNEL Channel;
287
288 /* Check if a channel with this name already exists */
289 Status = ChanMgrGetChannelByName(ChannelName, &Channel);
290 if (Status == STATUS_NOT_FOUND) IsUnique = TRUE;
291
292 /* If one did, dereference it, all we wanted was to check uniqueness */
293 if (NT_SUCCESS(Status)) ChanMgrReleaseChannel(Channel);
294
295 /* Return if one was found or not */
296 return IsUnique;
297 }
298
299 NTSTATUS
300 NTAPI
301 ChanMgrReapChannel(IN ULONG ChannelIndex)
302 {
303 /* FIXME: TODO */
304 return STATUS_NOT_IMPLEMENTED;
305 }
306
307 NTSTATUS
308 NTAPI
309 ChanMgrReapChannels(VOID)
310 {
311 ULONG i;
312 NTSTATUS Status = STATUS_SUCCESS;
313
314 /* Loop all the channels */
315 for (i = 0; i < SAC_MAX_CHANNELS; i++)
316 {
317 /* Lock this index and see if the channel was reaped */
318 ChannelSlotLock(i);
319 if (!ChannelReaped[i])
320 {
321 /* It was not reaped yet, so a channel should still be here */
322 ASSERT(ChannelFromIndex(i) != NULL);
323 if (ChannelGetReferenceCount(i) <= 0)
324 {
325 /* The channel has no more references, so clear the buffer flags */
326 _InterlockedExchange(&ChannelArray[i]->ChannelHasNewIBufferData, 0);
327 _InterlockedExchange(&ChannelArray[i]->ChannelHasNewOBufferData, 0);
328
329 /* And reap it */
330 Status = ChanMgrReapChannel(i);
331 }
332 }
333
334 /* Release the lock, and move on unless reaping failed */
335 ChannelSlotUnlock(i);
336 if (!NT_SUCCESS(Status)) break;
337 }
338
339 /* Return reaping status */
340 return Status;
341 }
342
343 NTSTATUS
344 NTAPI
345 ChanMgrCreateChannel(OUT PSAC_CHANNEL *Channel,
346 IN PSAC_CHANNEL_ATTRIBUTES Attributes)
347 {
348 NTSTATUS Status;
349 PSAC_CHANNEL NewChannel;
350 SAC_CHANNEL_ID ChanId;
351 ULONG i;
352 CHECK_PARAMETER(Channel);
353 CHECK_PARAMETER2(Attributes);
354
355 /* No other channel create attempts can happen */
356 ChannelLockCreates();
357
358 /* Is the channel manager initialized? */
359 if (!ChannelCreateEnabled)
360 {
361 /* Nope, bail out */
362 Status = STATUS_UNSUCCESSFUL;
363 goto ReturnStatus;
364 }
365
366 /* Reap any zombie channels */
367 Status = ChanMgrReapChannels();
368 if (!NT_SUCCESS(Status))
369 {
370 /* Bail out on error */
371 Status = STATUS_UNSUCCESSFUL;
372 goto ReturnStatus;
373 }
374
375 /* Check if we already have a channel with this name */
376 if (!ChanMgrIsUniqueName(Attributes->NameBuffer))
377 {
378 /* We do, fail */
379 Status = STATUS_DUPLICATE_NAME;
380 goto ReturnStatus;
381 }
382
383 /* Allocate this channel */
384 NewChannel = SacAllocatePool(sizeof(SAC_CHANNEL), CHANNEL_BLOCK_TAG);
385 CHECK_PARAMETER_WITH_STATUS(NewChannel, STATUS_NO_MEMORY); // bug
386 RtlZeroMemory(NewChannel, sizeof(SAC_CHANNEL));
387
388 /* Loop channel slots */
389 for (i = 0; i < SAC_MAX_CHANNELS; i++)
390 {
391 /* Find a free spot for it */
392 if (ChannelReaped[i])
393 {
394 /* Free slot found, attempt to use it */
395 ASSERT(!CHANNEL_SLOT_IS_IN_USE(i));
396 InterlockedCompareExchangePointer((PVOID*)&ChannelArray[i], NewChannel, NULL);
397 if (ChannelArray[i] == NewChannel) break;
398 }
399 }
400
401 /* Did we not find a single free slot? */
402 if (i == SAC_MAX_CHANNELS)
403 {
404 /* Bail out */
405 goto ReturnStatus;
406 }
407
408 /* Create an ID for this channel */
409 RtlZeroMemory(&ChanId, sizeof(ChanId));
410 Status = ExUuidCreate(&ChanId.ChannelGuid);
411 if (!NT_SUCCESS(Status))
412 {
413 /* Bail out if we couldn't */
414 SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to get GUID\n");
415 goto ReturnStatus;
416 }
417
418 /* Now create the channel proper */
419 Status = ChannelCreate(NewChannel, Attributes, ChanId);
420 if (NT_SUCCESS(Status))
421 {
422 /* Set the channel index */
423 _InterlockedExchange(&NewChannel->Index, i);
424
425 /* Add the initial reference to the channel */
426 ChannelReferenceToOneByIndexWithLock(i);
427
428 /* Return it to the caller */
429 *Channel = NewChannel;
430
431 /* This slot is now occupied */
432 ASSERT(ChannelReaped[i] == 1);
433 _InterlockedExchange(&ChannelReaped[i], 0);
434 }
435 else
436 {
437 /* We couldn't create it, free the buffer */
438 SacFreePool(NewChannel);
439 }
440
441 ReturnStatus:
442 /* Return whatever the operation status was */
443 ChannelUnlockCreates();
444 return Status;
445 }
446
447 NTSTATUS
448 NTAPI
449 ChanMgrGetByHandleAndFileObject(IN SAC_CHANNEL_ID ChannelId,
450 IN PFILE_OBJECT FileObject,
451 OUT PSAC_CHANNEL* TargetChannel)
452 {
453 NTSTATUS Status;
454 PSAC_CHANNEL FoundChannel;
455
456 /* Lookup the channel by ID first */
457 Status = ChanMgrGetByHandle(ChannelId, &FoundChannel);
458 if (NT_SUCCESS(Status))
459 {
460 /* We found it, now check if the file object matches */
461 if (FoundChannel->FileObject == FileObject)
462 {
463 /* Yep, return success */
464 *TargetChannel = FoundChannel;
465 }
466 else
467 {
468 /* Nope, drop the reference on the channel */
469 ChanMgrReleaseChannel(FoundChannel);
470
471 /* And return failure */
472 *TargetChannel = NULL;
473 Status = STATUS_NOT_FOUND;
474 }
475 }
476
477 /* Return if we found it or not */
478 return Status;
479 }
480
481 NTSTATUS
482 NTAPI
483 ChanMgrGetChannelIndex(IN PSAC_CHANNEL Channel,
484 IN PLONG ChannelIndex)
485 {
486 CHECK_PARAMETER1(Channel);
487 CHECK_PARAMETER2(ChannelIndex);
488
489 /* Just return the index of the channel */
490 *ChannelIndex = ChannelGetIndex(Channel);
491 return STATUS_SUCCESS;
492 }
493
494 NTSTATUS
495 NTAPI
496 ChanMgrGetByIndex(IN LONG TargetIndex,
497 IN PSAC_CHANNEL* TargetChannel)
498 {
499 NTSTATUS Status;
500 CHECK_PARAMETER1(TargetIndex < SAC_MAX_CHANNELS);
501 CHECK_PARAMETER2(TargetChannel);
502
503 /* Assume failure */
504 *TargetChannel = NULL;
505 Status = STATUS_NOT_FOUND;
506
507 /* Reference this one and check if it's valid */
508 if (ChannelReferenceByIndexWithLock(TargetIndex) > 0)
509 {
510 /* We found it, return it (with a reference held) */
511 *TargetChannel = ChannelFromIndex(TargetIndex);
512 return STATUS_SUCCESS;
513 }
514
515 /* No channels with this ID were found */
516 return Status;
517 }
518
519 NTSTATUS
520 NTAPI
521 ChanMgrGetNextActiveChannel(IN PSAC_CHANNEL CurrentChannel,
522 IN PULONG TargetIndex,
523 OUT PSAC_CHANNEL *TargetChannel)
524 {
525 NTSTATUS Status;
526 ULONG i;
527 LONG ChannelIndex, StartIndex;
528 PSAC_CHANNEL FoundChannel;
529 BOOLEAN ChannelFound;
530 CHECK_PARAMETER1(CurrentChannel);
531 CHECK_PARAMETER2(TargetIndex);
532 CHECK_PARAMETER3(TargetChannel);
533
534 /* Get the current channel index */
535 Status = ChanMgrGetChannelIndex(CurrentChannel, &ChannelIndex);
536 if (!NT_SUCCESS(Status)) return Status;
537
538 /* Assume failure */
539 ChannelFound = FALSE;
540
541 /* Loop through all the possible active channels */
542 StartIndex = (ChannelIndex + 1) % SAC_MAX_CHANNELS;
543 for (i = StartIndex; i != StartIndex; i = (i + 1) % SAC_MAX_CHANNELS)
544 {
545 /* Get the channel and see if it exists*/
546 Status = ChanMgrGetByIndex(i, &FoundChannel);
547 if (Status != STATUS_NOT_FOUND)
548 {
549 /* Bail out if we failed for some reason */
550 if (!NT_SUCCESS(Status)) return Status;
551
552 /* It exists -- is it active? Or, does it have output data? */
553 if ((ChannelIsActive(FoundChannel)) ||
554 (!(ChannelIsActive(FoundChannel)) &&
555 (FoundChannel->ChannelHasNewOBufferData)))
556 {
557 /* It's active or has output data, return with it */
558 ChannelFound = TRUE;
559 break;
560 }
561
562 /* Drop the reference on this channel and try the next one */
563 Status = ChanMgrReleaseChannel(FoundChannel);
564 if (!NT_SUCCESS(Status)) return Status;
565 }
566 }
567
568 /* Check if we successfully found a channel */
569 if ((NT_SUCCESS(Status)) && (ChannelFound))
570 {
571 /* Return it and its indexed. Remember we still hold the reference */
572 *TargetIndex = i;
573 *TargetChannel = FoundChannel;
574 }
575
576 /* All done */
577 return Status;
578 }
579
580 NTSTATUS
581 NTAPI
582 ChanMgrChannelDestroy(IN PSAC_CHANNEL Channel)
583 {
584 CHECK_PARAMETER1(Channel);
585 CHECK_PARAMETER(ChannelGetReferenceCount(Channel->Index) > 0);
586
587 /* Destroy the channel */
588 return Channel->ChannelDestroy(Channel);
589 }
590
591 NTSTATUS
592 NTAPI
593 ChanMgrCloseChannel(IN PSAC_CHANNEL Channel)
594 {
595 NTSTATUS Status;
596 CHECK_PARAMETER(Channel);
597
598 /* Check if the channel is active */
599 if (ChannelIsActive(Channel))
600 {
601 /* Yep, close it */
602 Status = ChannelClose(Channel);
603 }
604 else
605 {
606 /* Nothing to do */
607 Status = STATUS_ALREADY_DISCONNECTED;
608 }
609
610 /* Handle the channel close */
611 ConMgrHandleEvent(TRUE, Channel, &Status);
612 return Status;
613 }
614
615 NTSTATUS
616 NTAPI
617 ChanMgrGetChannelCount(OUT PULONG ChannelCount)
618 {
619 ULONG i;
620 PSAC_CHANNEL Channel;
621 NTSTATUS Status;
622 CHECK_PARAMETER(ChannelCount);
623
624 /* Assume no channels */
625 *ChannelCount = 0;
626
627 /* Loop every channel */
628 for (i = 0; i < SAC_MAX_CHANNELS; i++)
629 {
630 /* See if this one exists */
631 Status = ChanMgrGetByIndex(i, &Channel);
632 if (Status != STATUS_NOT_FOUND)
633 {
634 /* Sanity checks*/
635 ASSERT(NT_SUCCESS(Status));
636 ASSERT(Channel != NULL);
637
638 /* It exists -- is it active? Or, does it have output data? */
639 if ((ChannelIsActive(Channel)) ||
640 (!(ChannelIsActive(Channel)) &&
641 (Channel->ChannelHasNewOBufferData)))
642 {
643 /* It's active or has output data, increase the count */
644 ++*ChannelCount;
645 break;
646 }
647
648 /* Drop the reference on this channel and try the next one */
649 Status = ChanMgrReleaseChannel(Channel);
650 if (!NT_SUCCESS(Status)) return Status;
651 }
652 else
653 {
654 /* Channel doesn't exist, nothing wrong with that, keep going */
655 Status = STATUS_SUCCESS;
656 }
657 }
658
659 /* We should always succeed if we get here */
660 ASSERT(NT_SUCCESS(Status));
661 return Status;
662 }
663
664 NTSTATUS
665 NTAPI
666 ChanMgrIsFull(OUT PBOOLEAN IsFull)
667 {
668 NTSTATUS Status;
669 ULONG Count;
670
671 /* Count the channels */
672 Status = ChanMgrGetChannelCount(&Count);
673 CHECK_PARAMETER(Status == STATUS_SUCCESS);
674
675 /* Return if we hit the limit */
676 *IsFull = (Count == SAC_MAX_CHANNELS);
677 return Status;
678 }
679
680 NTSTATUS
681 NTAPI
682 ChanMgrCloseChannelsWithFileObject(IN PFILE_OBJECT FileObject)
683 {
684 PSAC_CHANNEL Channel;
685 ULONG i;
686 NTSTATUS Status;
687 CHECK_PARAMETER1(FileObject);
688
689 /* Loop all channels */
690 for (i = 0; i < SAC_MAX_CHANNELS; i++)
691 {
692 /* Try to get this one */
693 Status = ChanMgrGetByIndex(i, &Channel);
694 if (!NT_SUCCESS(Status)) break;
695
696 /* Check if the FO matches, if so, close the channel */
697 if (Channel->FileObject == FileObject) ChanMgrCloseChannel(Channel);
698
699 /* Drop the reference and try the next channel(s) */
700 Status = ChanMgrReleaseChannel(Channel);
701 if (!NT_SUCCESS(Status)) break;
702 }
703
704 /* All done */
705 return Status;
706 }
707
708 NTSTATUS
709 NTAPI
710 ChanMgrGenerateUniqueCmdName(IN PWCHAR ChannelName)
711 {
712 return STATUS_NOT_IMPLEMENTED;
713 }