xref: /reactos/drivers/sac/driver/channel.c (revision c2c66aff)
1 /*
2  * PROJECT:     ReactOS Drivers
3  * LICENSE:     BSD - See COPYING.ARM in the top level directory
4  * FILE:        drivers/sac/driver/channel.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 /* FUNCTIONS ******************************************************************/
14 
15 BOOLEAN
16 NTAPI
ChannelIsValidType(IN SAC_CHANNEL_TYPE ChannelType)17 ChannelIsValidType(IN SAC_CHANNEL_TYPE ChannelType)
18 {
19     /* Check if the type is valid */
20     return ((ChannelType >= VtUtf8) && (ChannelType <= Raw));
21 }
22 
23 BOOLEAN
24 NTAPI
ChannelIsEqual(IN PSAC_CHANNEL Channel,IN PSAC_CHANNEL_ID ChannelId)25 ChannelIsEqual(IN PSAC_CHANNEL Channel,
26                IN PSAC_CHANNEL_ID ChannelId)
27 {
28     /* Check if the GUIDs match */
29     return IsEqualGUIDAligned(&Channel->ChannelId.ChannelGuid,
30                               &ChannelId->ChannelGuid);
31 }
32 
33 NTSTATUS
34 NTAPI
ChannelDereferenceHandles(IN PSAC_CHANNEL Channel)35 ChannelDereferenceHandles(IN PSAC_CHANNEL Channel)
36 {
37     CHECK_PARAMETER(Channel);
38 
39     /* Clear the data event */
40     if (Channel->HasNewDataEvent)
41     {
42         ChannelUninitializeEvent(Channel,
43                                  HasNewDataEvent,
44                                  SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT);
45     }
46 
47     /* Clear the close event */
48     if (Channel->CloseEvent)
49     {
50         ChannelUninitializeEvent(Channel,
51                                  CloseEvent,
52                                  SAC_CHANNEL_FLAG_CLOSE_EVENT);
53     }
54 
55     /* Clear the lock event */
56     if (Channel->LockEvent)
57     {
58         ChannelUninitializeEvent(Channel,
59                                  LockEvent,
60                                  SAC_CHANNEL_FLAG_LOCK_EVENT);
61     }
62 
63     /* Clear the redraw event */
64     if (Channel->RedrawEvent)
65     {
66         ChannelUninitializeEvent(Channel,
67                                  RedrawEvent,
68                                  SAC_CHANNEL_FLAG_REDRAW_EVENT);
69     }
70 
71     /* All done */
72     return STATUS_SUCCESS;
73 }
74 
75 NTSTATUS
76 NTAPI
ChannelDestroy(IN PSAC_CHANNEL Channel)77 ChannelDestroy(IN PSAC_CHANNEL Channel)
78 {
79     CHECK_PARAMETER(Channel);
80 
81     /* Same thing as dereferencing all the handles */
82     return ChannelDereferenceHandles(Channel);
83 }
84 
85 NTSTATUS
86 NTAPI
ChannelOWrite(IN PSAC_CHANNEL Channel,IN PCHAR Buffer,IN ULONG BufferSize)87 ChannelOWrite(IN PSAC_CHANNEL Channel,
88               IN PCHAR Buffer,
89               IN ULONG BufferSize)
90 {
91     NTSTATUS Status;
92     CHECK_PARAMETER3(BufferSize < SAC_OBUFFER_SIZE);
93 
94     /* While holding the output lock, write to the output buffer */
95     ChannelLockOBuffer(Channel);
96     Status = Channel->ChannelOutputWrite(Channel, Buffer, BufferSize);
97     ChannelUnlockOBuffer(Channel);
98     return Status;
99 }
100 
101 NTSTATUS
102 NTAPI
ChannelOFlush(IN PSAC_CHANNEL Channel)103 ChannelOFlush(IN PSAC_CHANNEL Channel)
104 {
105     NTSTATUS Status;
106 
107     /* While holding the output lock, flush to the output buffer */
108     ChannelLockOBuffer(Channel);
109     Status = Channel->ChannelOutputFlush(Channel);
110     ChannelUnlockOBuffer(Channel);
111     return Status;
112 }
113 
114 NTSTATUS
115 NTAPI
ChannelIWrite(IN PSAC_CHANNEL Channel,IN PCHAR Buffer,IN ULONG BufferSize)116 ChannelIWrite(IN PSAC_CHANNEL Channel,
117               IN PCHAR Buffer,
118               IN ULONG BufferSize)
119 {
120     NTSTATUS Status;
121 
122     /* Write into the input buffer while holding the lock */
123     ChannelLockIBuffer(Channel);
124     Status = Channel->ChannelInputWrite(Channel, Buffer, BufferSize);
125     ChannelUnlockIBuffer(Channel);
126     return Status;
127 }
128 
129 NTSTATUS
130 NTAPI
ChannelIRead(IN PSAC_CHANNEL Channel,IN PCHAR Buffer,IN ULONG BufferSize,IN OUT PULONG ResultBufferSize)131 ChannelIRead(IN PSAC_CHANNEL Channel,
132              IN PCHAR Buffer,
133              IN ULONG BufferSize,
134              IN OUT PULONG ResultBufferSize)
135 {
136     NTSTATUS Status;
137 
138     /* Read the input buffer while holding the lock */
139     ChannelLockIBuffer(Channel);
140     Status = Channel->ChannelInputRead(Channel,
141                                        Buffer,
142                                        BufferSize,
143                                        ResultBufferSize);
144     ChannelUnlockIBuffer(Channel);
145     return Status;
146 }
147 
148 WCHAR
149 NTAPI
ChannelIReadLast(IN PSAC_CHANNEL Channel)150 ChannelIReadLast(IN PSAC_CHANNEL Channel)
151 {
152     WCHAR LastChar;
153 
154     /* Read the last character while holding the lock */
155     ChannelLockIBuffer(Channel);
156     LastChar = Channel->ChannelInputReadLast(Channel);
157     ChannelUnlockIBuffer(Channel);
158     return LastChar;
159 }
160 
161 ULONG
162 NTAPI
ChannelIBufferLength(IN PSAC_CHANNEL Channel)163 ChannelIBufferLength(IN PSAC_CHANNEL Channel)
164 {
165     ULONG Length;
166 
167     /* Get the input buffer length while holding the lock */
168     ChannelLockOBuffer(Channel);
169     Length = Channel->ChannelInputBufferLength(Channel);
170     ChannelUnlockOBuffer(Channel);
171     return Length;
172 }
173 
174 NTSTATUS
175 NTAPI
ChannelSetRedrawEvent(IN PSAC_CHANNEL Channel)176 ChannelSetRedrawEvent(IN PSAC_CHANNEL Channel)
177 {
178     NTSTATUS Status;
179 
180     /* Set the event */
181     ChannelSetEvent(Channel, RedrawEvent);
182     return Status;
183 }
184 
185 NTSTATUS
186 NTAPI
ChannelSetLockEvent(IN PSAC_CHANNEL Channel)187 ChannelSetLockEvent(IN PSAC_CHANNEL Channel)
188 {
189     NTSTATUS Status;
190 
191     /* Set the event */
192     ChannelSetEvent(Channel, LockEvent);
193     return Status;
194 }
195 
196 NTSTATUS
197 NTAPI
ChannelClearRedrawEvent(IN PSAC_CHANNEL Channel)198 ChannelClearRedrawEvent(IN PSAC_CHANNEL Channel)
199 {
200     NTSTATUS Status;
201 
202     /* Clear the event */
203     ChannelClearEvent(Channel, RedrawEvent);
204     return Status;
205 }
206 
207 NTSTATUS
208 NTAPI
ChannelHasRedrawEvent(IN PSAC_CHANNEL Channel,OUT PBOOLEAN Present)209 ChannelHasRedrawEvent(IN PSAC_CHANNEL Channel,
210                       OUT PBOOLEAN Present)
211 {
212     CHECK_PARAMETER1(Channel);
213     CHECK_PARAMETER2(Present);
214 
215     /* Return if the flag is set */
216     *Present = Channel->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT;
217     return STATUS_SUCCESS;
218 }
219 
220 NTSTATUS
221 NTAPI
ChannelGetStatus(IN PSAC_CHANNEL Channel,OUT PSAC_CHANNEL_STATUS ChannelStatus)222 ChannelGetStatus(IN PSAC_CHANNEL Channel,
223                  OUT PSAC_CHANNEL_STATUS ChannelStatus)
224 {
225     CHECK_PARAMETER1(Channel);
226 
227     /* Read the status while holding the attribute lock */
228     ChannelLockAttributes(Channel);
229     *ChannelStatus = Channel->ChannelStatus;
230     ChannelUnlockAttributes(Channel);
231     return STATUS_SUCCESS;
232 }
233 
234 NTSTATUS
235 NTAPI
ChannelSetStatus(IN PSAC_CHANNEL Channel,IN SAC_CHANNEL_STATUS ChannelStatus)236 ChannelSetStatus(IN PSAC_CHANNEL Channel,
237                  IN SAC_CHANNEL_STATUS ChannelStatus)
238 {
239     CHECK_PARAMETER1(Channel);
240 
241     /* Read the status while holding the attribute lock */
242     ChannelLockAttributes(Channel);
243     Channel->ChannelStatus = ChannelStatus;
244     ChannelUnlockAttributes(Channel);
245     return STATUS_SUCCESS;
246 }
247 
248 BOOLEAN
249 NTAPI
ChannelIsActive(IN PSAC_CHANNEL Channel)250 ChannelIsActive(IN PSAC_CHANNEL Channel)
251 {
252     SAC_CHANNEL_STATUS ChannelStatus;
253     BOOLEAN IsActive;
254 
255     /* Get the status */
256     if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus)))
257     {
258         /* We couldn't even do that, assume it's inactive */
259         IsActive = FALSE;
260     }
261     else
262     {
263         /* Check if the status shows activity */
264         IsActive = (ChannelStatus == Active);
265     }
266 
267     /* Return the state */
268     return IsActive;
269 }
270 
271 BOOLEAN
272 NTAPI
ChannelIsClosed(IN PSAC_CHANNEL Channel)273 ChannelIsClosed(IN PSAC_CHANNEL Channel)
274 {
275     SAC_CHANNEL_STATUS ChannelStatus;
276     BOOLEAN IsClosed;
277 
278     /* Get the status */
279     if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus)))
280     {
281         /* We couldn't even do that, assume it's inactive */
282         IsClosed = FALSE;
283     }
284     else
285     {
286         /* Check if the status shows activity */
287         IsClosed = ((ChannelStatus == Inactive) &&
288                     (Channel->ChannelHasNewOBufferData));
289     }
290 
291     /* Return the state */
292     return IsClosed;
293 }
294 
295 NTSTATUS
296 NTAPI
ChannelGetName(IN PSAC_CHANNEL Channel,OUT PWCHAR * Name)297 ChannelGetName(IN PSAC_CHANNEL Channel,
298                OUT PWCHAR *Name)
299 {
300     CHECK_PARAMETER1(Channel);
301     CHECK_PARAMETER2(Name);
302 
303     /* Allocate space to hold the name */
304     *Name = SacAllocatePool(sizeof(Channel->NameBuffer), GLOBAL_BLOCK_TAG);
305     CHECK_ALLOCATION(*Name);
306 
307     /* Lock the attributes while we copy the name */
308     ChannelLockAttributes(Channel);
309 
310     /* Copy the name and null-terminate it */
311     ASSERT(((wcslen(Channel->NameBuffer) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
312     wcsncpy(*Name, Channel->NameBuffer, RTL_NUMBER_OF(Channel->NameBuffer)); // bug
313     (*Name)[SAC_CHANNEL_NAME_SIZE] = UNICODE_NULL;
314 
315     /* Release the lock and return */
316     ChannelUnlockAttributes(Channel);
317     return STATUS_SUCCESS;
318 }
319 
320 NTSTATUS
321 NTAPI
ChannelSetName(IN PSAC_CHANNEL Channel,IN PWCHAR Name)322 ChannelSetName(IN PSAC_CHANNEL Channel,
323                IN PWCHAR Name)
324 {
325     CHECK_PARAMETER1(Channel);
326     CHECK_PARAMETER2(Name);
327 
328     /* Lock the attributes while we copy the name */
329     ChannelLockAttributes(Channel);
330 
331     /* Copy the name and null-terminate it */
332     ASSERT(((wcslen(Name) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
333     wcsncpy(Channel->NameBuffer, Name, RTL_NUMBER_OF(Channel->NameBuffer)); // bug
334     Channel->NameBuffer[SAC_CHANNEL_NAME_SIZE] = UNICODE_NULL;
335 
336     /* Release the lock and return */
337     ChannelUnlockAttributes(Channel);
338     return STATUS_SUCCESS;
339 }
340 
341 NTSTATUS
342 NTAPI
ChannelGetDescription(IN PSAC_CHANNEL Channel,IN PWCHAR * Description)343 ChannelGetDescription(IN PSAC_CHANNEL Channel,
344                       IN PWCHAR* Description)
345 {
346     CHECK_PARAMETER1(Channel);
347     CHECK_PARAMETER2(Description);
348 
349     /* Allocate space to hold the description */
350     *Description = SacAllocatePool(sizeof(Channel->DescriptionBuffer), GLOBAL_BLOCK_TAG);
351     CHECK_ALLOCATION(*Description);
352 
353     /* Lock the attributes while we copy the name */
354     ChannelLockAttributes(Channel);
355 
356     /* Copy the name and null-terminate it */
357     ASSERT(((wcslen(Channel->DescriptionBuffer) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_DESCRIPTION_SIZE + 1) * sizeof(WCHAR)));
358     wcsncpy(*Description, Channel->DescriptionBuffer, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug
359     (*Description)[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL;
360 
361     /* Release the lock and return */
362     ChannelUnlockAttributes(Channel);
363     return STATUS_SUCCESS;
364 }
365 
366 NTSTATUS
367 NTAPI
ChannelSetDescription(IN PSAC_CHANNEL Channel,IN PWCHAR Description)368 ChannelSetDescription(IN PSAC_CHANNEL Channel,
369                       IN PWCHAR Description)
370 {
371     CHECK_PARAMETER1(Channel);
372     CHECK_PARAMETER2(Description);
373 
374     /* Lock the attributes while we copy the name */
375     ChannelLockAttributes(Channel);
376 
377     /* Copy the name and null-terminate it */
378     ASSERT(((wcslen(Description) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
379     wcsncpy(Channel->DescriptionBuffer, Description, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug
380     Channel->DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL;
381 
382     /* Release the lock and return */
383     ChannelUnlockAttributes(Channel);
384     return STATUS_SUCCESS;
385 }
386 
387 NTSTATUS
388 NTAPI
ChannelGetApplicationType(IN PSAC_CHANNEL Channel,OUT PGUID ApplicationType)389 ChannelGetApplicationType(IN PSAC_CHANNEL Channel,
390                           OUT PGUID ApplicationType)
391 {
392     CHECK_PARAMETER1(Channel);
393 
394     /* Read the application type GUID */
395     ChannelLockAttributes(Channel);
396     *ApplicationType = Channel->ApplicationType;
397     ChannelUnlockAttributes(Channel);
398 
399     /* Always return success */
400     return STATUS_SUCCESS;
401 }
402 
403 NTSTATUS
404 NTAPI
ChannelInitializeVTable(IN PSAC_CHANNEL Channel)405 ChannelInitializeVTable(IN PSAC_CHANNEL Channel)
406 {
407     /* What kind of channel is this? */
408     switch (Channel->ChannelType)
409     {
410         case VtUtf8:
411             /* Setup the calls for a VT-UTF8 channel */
412             Channel->ChannelCreate = VTUTF8ChannelCreate;
413             Channel->ChannelDestroy = VTUTF8ChannelDestroy;
414             Channel->ChannelOutputFlush = VTUTF8ChannelOFlush;
415             Channel->ChannelOutputEcho = VTUTF8ChannelOEcho;
416             Channel->ChannelOutputWrite = VTUTF8ChannelOWrite;
417             Channel->ChannelOutputRead = VTUTF8ChannelORead;
418             Channel->ChannelInputWrite = VTUTF8ChannelIWrite;
419             Channel->ChannelInputRead = VTUTF8ChannelIRead;
420             Channel->ChannelInputReadLast = VTUTF8ChannelIReadLast;
421             Channel->ChannelInputBufferIsFull = VTUTF8ChannelIBufferIsFull;
422             Channel->ChannelInputBufferLength = VTUTF8ChannelIBufferLength;
423             break;
424 
425         case Cmd:
426             /* FIXME: TODO */
427             ASSERT(FALSE);
428             return STATUS_NOT_IMPLEMENTED;
429 
430         case Raw:
431 
432             /* Setup the calls for a raw channel */
433             Channel->ChannelCreate = RawChannelCreate;
434             Channel->ChannelDestroy = RawChannelDestroy;
435             Channel->ChannelOutputFlush = RawChannelOFlush;
436             Channel->ChannelOutputEcho = RawChannelOEcho;
437             Channel->ChannelOutputWrite = RawChannelOWrite;
438             Channel->ChannelOutputRead = RawChannelORead;
439             Channel->ChannelInputWrite = RawChannelIWrite;
440             Channel->ChannelInputRead = RawChannelIRead;
441             Channel->ChannelInputReadLast = RawChannelIReadLast;
442             Channel->ChannelInputBufferIsFull = RawChannelIBufferIsFull;
443             Channel->ChannelInputBufferLength = RawChannelIBufferLength;
444             break;
445 
446         default:
447             /* Unsupported channel type */
448             return STATUS_INVALID_PARAMETER;
449     }
450 
451     /* If we got here, the channel was supported */
452     return STATUS_SUCCESS;
453 }
454 
455 NTSTATUS
456 NTAPI
ChannelCreate(IN PSAC_CHANNEL Channel,IN PSAC_CHANNEL_ATTRIBUTES Attributes,IN SAC_CHANNEL_ID ChannelId)457 ChannelCreate(IN PSAC_CHANNEL Channel,
458               IN PSAC_CHANNEL_ATTRIBUTES Attributes,
459               IN SAC_CHANNEL_ID ChannelId)
460 {
461     NTSTATUS Status;
462     CHECK_PARAMETER1(Channel);
463     CHECK_PARAMETER2(Attributes);
464 
465     /* If a close event is being passed in, it must exist, and vice-versa */
466     if (Attributes->Flag & SAC_CHANNEL_FLAG_CLOSE_EVENT)
467     {
468         CHECK_PARAMETER(Attributes->CloseEvent != NULL);
469     }
470     else
471     {
472         CHECK_PARAMETER(Attributes->CloseEvent == NULL);
473     }
474 
475     /* If a new data event is being passed in, it must exist, and vice-versa */
476     if (Attributes->Flag & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
477     {
478         CHECK_PARAMETER(Attributes->HasNewDataEvent != NULL);
479     }
480     else
481     {
482         CHECK_PARAMETER(Attributes->HasNewDataEvent == NULL);
483     }
484 
485     /* If a lock event is being passed in, it must exist, and vice-versa */
486     if (Attributes->Flag & SAC_CHANNEL_FLAG_LOCK_EVENT)
487     {
488         CHECK_PARAMETER(Attributes->LockEvent != NULL);
489     }
490     else
491     {
492         CHECK_PARAMETER(Attributes->LockEvent == NULL);
493     }
494 
495     /* If a redraw event is being passed in, it must exist, and vice-versa */
496     if (Attributes->Flag & SAC_CHANNEL_FLAG_REDRAW_EVENT)
497     {
498         CHECK_PARAMETER(Attributes->RedrawEvent != NULL);
499     }
500     else
501     {
502         CHECK_PARAMETER(Attributes->RedrawEvent == NULL);
503     }
504 
505     /* Initialize the channel structure */
506     RtlZeroMemory(Channel, sizeof(SAC_CHANNEL));
507     Channel->ChannelId = ChannelId;
508     Channel->ChannelType = Attributes->ChannelType;
509     Channel->Flags = Attributes->Flag;
510     if (Attributes->Flag & SAC_CHANNEL_FLAG_APPLICATION)
511     {
512         Channel->ApplicationType = Attributes->ChannelId;
513     }
514 
515     /* Initialize all the locks and events */
516     SacInitializeLock(&Channel->ChannelAttributeLock);
517     SacInitializeLock(&Channel->ChannelOBufferLock);
518     SacInitializeLock(&Channel->ChannelIBufferLock);
519     ChannelInitializeEvent(Channel, Attributes, CloseEvent);
520     ChannelInitializeEvent(Channel, Attributes, HasNewDataEvent);
521     ChannelInitializeEvent(Channel, Attributes, LockEvent);
522     ChannelInitializeEvent(Channel, Attributes, RedrawEvent);
523 
524     /* Set the name and description */
525     ChannelSetName(Channel, Attributes->NameBuffer);
526     ChannelSetDescription(Channel, Attributes->DescriptionBuffer);
527 
528     /* Initialize the function table for the type of channel this is */
529     Status = ChannelInitializeVTable(Channel);
530     if (!NT_SUCCESS(Status))
531     {
532         /* This is critical */
533         SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to initialize vtable\n");
534         goto FailChannel;
535     }
536 
537     /* Now call the channel specific type constructor */
538     Status = Channel->ChannelCreate(Channel);
539     if (!NT_SUCCESS(Status))
540     {
541         /* This is critical */
542         SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed channel specific initialization\n");
543         goto FailChannel;
544     }
545 
546     /* Finally, mark the channel as active */
547     ChannelSetStatus(Channel, Active);
548     return STATUS_SUCCESS;
549 
550 FailChannel:
551     /* Destroy the channel and return the failure code */
552     Channel->ChannelDestroy(Channel);
553     return Status;
554 }
555 
556 NTSTATUS
557 NTAPI
ChannelClose(IN PSAC_CHANNEL Channel)558 ChannelClose(IN PSAC_CHANNEL Channel)
559 {
560     NTSTATUS Status;
561     CHECK_PARAMETER(Channel);
562 
563     /* Set the channel inactive */
564     ChannelSetStatus(Channel, Inactive);
565 
566     /* Set the close event */
567     if (Channel->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT)
568     {
569         ChannelSetEvent(Channel, CloseEvent);
570     }
571 
572     /* Close all the handles */
573     Status = ChannelDereferenceHandles(Channel);
574     return Status;
575 }
576