PSXSS: It seems the renamed csrterm did not get in the repository.
[reactos.git] / posix / apps / posixw32 / posixw32.c
1 /* $Id: posixw32.c,v 1.1 2002/06/09 08:37:07 ea Exp $
2 *
3 * PROJECT : ReactOS Operating System / POSIX+ Environment Subsystem
4 * DESCRIPTION: POSIXW32 - A DEC VT-100 terminal emulator for the PSX subsystem
5 * DESCRIPTION: that runs in the Win32 subsystem.
6 * COPYRIGHT : Copyright (c) 2001-2002 Emanuele Aliberti
7 * LICENSE : GNU GPL v2
8 * DATE : 2001-05-05
9 * AUTHOR : Emanuele Aliberti <ea@iol.it>
10 * NOTE : This IS a Win32 program, but will fail if the PSX subsystem
11 * NOTE : is not installed. The PSX subsystem consists of two more
12 * NOTE : files: PSXSS.EXE, PSXDLL.DLL.
13 * WARNING : If you use this program under a real NT descendant, be
14 * WARNING : sure to have disabled the PSX subsystem.
15 * --------------------------------------------------------------------
16 *
17 * This software is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of the
20 * License, or (at your option) any later version.
21 *
22 * This software is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this software; see the file COPYING. If not, write
29 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
30 * MA 02139, USA.
31 *
32 * --------------------------------------------------------------------
33 * 2002-03-16 EA Today it actually compiled.
34 * 2002-06-08 EA Renamed (old name was CSRTERM)
35 */
36 #include <windows.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39
40 #define NTOS_MODE_USER
41 #include <ntos.h>
42 #include <psx/lpcproto.h>
43
44 #include "vt100.h"
45 #include "posixw32.h"
46
47 /*** OPTIONS *********************************************************/
48
49 #define PRIVATE static
50
51 #define INPUT_QUEUE_SIZE 32
52
53 #ifdef NDEBUG
54 #define TRACE
55 #else
56 #define TRACE OutputDebugString(__FUNCTION__)
57 #endif
58
59 /*** GLOBALS *********************************************************/
60
61 PRIVATE LPCSTR MyName = "POSIXW32";
62 PRIVATE CSRTERM_SESSION Session =
63 {
64 0, //Identifier
65 { //ServerPort
66 {0,0,NULL},
67 L"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME"\\"PSX_NS_SESSIONAPI_PORT_NAME,
68 INVALID_HANDLE_VALUE
69 }
70 };
71
72 /*** PRIVATE FUNCTIONS ***********************************************/
73 VOID STDCALL Debug_Print (LPCSTR Format, ...)
74 {
75 CHAR Buffer [512];
76 va_list ArgumentPointer;
77
78 va_start(ArgumentPointer, Format);
79 vsprintf(Buffer, Format, ArgumentPointer);
80 va_end(ArgumentPointer);
81 OutputDebugStringA (Buffer);
82 }
83 /**********************************************************************
84 * OutPort/2 PRIVATE
85 *
86 * DESCRIPTION
87 * Notify to PSXSS that input data is ready by sending a
88 * software interrupt on the \POSIX+\SessionPort port.
89 */
90 PRIVATE DWORD STDCALL OutPort (PCHAR Buffer, ULONG Size)
91 {
92 NTSTATUS Status;
93 PSX_TERMINAL_READ TerminalRead;
94 TRACE;
95 if (Size > 0)
96 {
97 /* LPC */
98 TerminalRead.Header.MessageType = LPC_NEW_MESSAGE;
99 TerminalRead.PsxHeader.Context = PSX_CONNECTION_TYPE_TERMINAL;
100 TerminalRead.PsxHeader.Procedure = PSX_TERMINAL_INTERRUPT;
101 /* Terminal I/O */
102 TerminalRead.Size = Size;
103 #if 0
104 RtlCopyMemory (TerminalRead.Buffer, Buffer, Size);
105 Status = NtRequestWaitReplyPort (
106 Session.ServerPort.Handle,
107 & TerminalRead
108 /* FIXME */
109 );
110 #endif
111 if (!NT_SUCCESS(Status))
112 {
113 vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
114 MyName, __FUNCTION__, Status);
115 return 0;
116 }
117 }
118 return Size;
119 }
120 /**********************************************************************
121 * ProcessConnectionRequest/1 PRIVATE
122 *
123 * DESCRIPTION
124 * Initialize our data for managing the control connection
125 * initiated by the PSXSS.EXE process.
126 */
127 PRIVATE NTSTATUS STDCALL ProcessConnectionRequest (PLPC_MAX_MESSAGE Request)
128 {
129 PPSX_CONNECT_PORT_DATA ConnectData = (PPSX_CONNECT_PORT_DATA) & Request->Data;
130
131 TRACE;
132 if (PSX_CONNECTION_TYPE_SERVER != ConnectData->ConnectionType)
133 {
134
135 return STATUS_UNSUCCESSFUL;
136 }
137 if (PSX_LPC_PROTOCOL_VERSION != ConnectData->Version)
138 {
139
140 return STATUS_UNSUCCESSFUL;
141 }
142 Session.SsLinkIsActive = TRUE;
143 return STATUS_SUCCESS;
144 }
145 /**********************************************************************
146 * ProcessRequest/1 PRIVATE
147 *
148 * DESCRIPTION
149 *
150 */
151 PRIVATE NTSTATUS STDCALL ProcessRequest (PPSX_MAX_MESSAGE Request)
152 {
153 TRACE;
154 /* TODO */
155 vtprintf("TEST VT-100\n");
156
157 return STATUS_SUCCESS;
158 }
159 /**********************************************************************
160 * PsxSessionPortListener/1 PRIVATE
161 *
162 * DESCRIPTION
163 * Manage messages from the PSXSS, that is LPC messages we get
164 * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
165 *
166 * NOTE
167 * This function is the thread 's entry point created in
168 * CreateSessionObiects().
169 */
170 PRIVATE DWORD STDCALL PsxSessionPortListener (LPVOID Arg)
171 {
172 NTSTATUS Status;
173 LPC_TYPE RequestType;
174 PSX_MAX_MESSAGE Request;
175 PPSX_MAX_MESSAGE Reply = NULL;
176 BOOL NullReply = FALSE;
177
178 TRACE;
179
180 while (TRUE)
181 {
182 Reply = NULL;
183 NullReply = FALSE;
184 while (!NullReply)
185 {
186 Status = NtReplyWaitReceivePort (
187 Session.Port.Handle,
188 0,
189 (PLPC_MESSAGE) Reply,
190 (PLPC_MESSAGE) & Request
191 );
192 if (!NT_SUCCESS(Status))
193 {
194 break;
195 }
196 RequestType = PORT_MESSAGE_TYPE(Request);
197 switch (RequestType)
198 {
199 case LPC_CONNECTION_REQUEST:
200 ProcessConnectionRequest ((PLPC_MAX_MESSAGE) & Request);
201 NullReply = TRUE;
202 continue;
203 case LPC_CLIENT_DIED:
204 case LPC_PORT_CLOSED:
205 case LPC_DEBUG_EVENT:
206 case LPC_ERROR_EVENT:
207 case LPC_EXCEPTION:
208 NullReply = TRUE;
209 continue;
210 default:
211 if (RequestType != LPC_REQUEST)
212 {
213 NullReply = TRUE;
214 continue;
215 }
216 }
217 Reply = & Request;
218 Reply->PsxHeader.Status = ProcessRequest (& Request);
219 NullReply = FALSE;
220 }
221 if ((STATUS_INVALID_HANDLE == Status) ||
222 (STATUS_OBJECT_TYPE_MISMATCH == Status))
223 {
224 break;
225 }
226 }
227 Session.SsLinkIsActive = FALSE;
228 TerminateThread (GetCurrentThread(), Status);
229 }
230 /**********************************************************************
231 * CreateSessionObiects/1 PRIVATE
232 *
233 * DESCRIPTION
234 * Create the session objects which are mananged by our side:
235 *
236 * \POSIX+\Sessions\P<pid>
237 * \POSIX+\Sessions\D<pid>
238 */
239 PRIVATE NTSTATUS STDCALL CreateSessionObjects (DWORD Pid)
240 {
241 NTSTATUS Status;
242 ULONG Id = 0;
243 OBJECT_ATTRIBUTES Oa;
244 LARGE_INTEGER SectionSize = {PSX_TERMINAL_SECTION_SIZE,0};
245
246 TRACE;
247
248
249 /* Critical section */
250 Status = RtlInitializeCriticalSection (& Session.Lock);
251 if (!NT_SUCCESS(Status))
252 {
253 vtprintf (
254 "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
255 MyName, __FUNCTION__, Status);
256 return Status;
257 }
258 /* Port and port management thread */
259 swprintf (
260 Session.Port.NameBuffer,
261 PSX_NS_SESSION_PORT_TEMPLATE,
262 PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
263 PSX_NS_SESSION_DIRECTORY_NAME,
264 Pid
265 );
266 OutputDebugStringW(Session.Port.NameBuffer);
267 RtlInitUnicodeString (& Session.Port.Name, Session.Port.NameBuffer);
268 InitializeObjectAttributes (& Oa, & Session.Port.Name, 0, NULL, NULL);
269 Status = NtCreatePort (& Session.Port.Handle, & Oa, 0, 0, 0x10000);
270 if (!NT_SUCCESS(Status))
271 {
272 RtlDeleteCriticalSection (& Session.Lock);
273 vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
274 MyName, __FUNCTION__, Status);
275 return Status;
276 }
277 Session.Port.Thread.Handle =
278 CreateThread (
279 NULL,
280 0,
281 PsxSessionPortListener,
282 0,
283 CREATE_SUSPENDED,
284 & Session.Port.Thread.Id
285 );
286 if ((HANDLE) NULL == Session.Port.Thread.Handle)
287 {
288 Status = (NTSTATUS) GetLastError();
289 NtClose (Session.Port.Handle);
290 RtlDeleteCriticalSection (& Session.Lock);
291 vtprintf ("%s: %s: CreateThread failed with %d\n",
292 MyName, __FUNCTION__, Status);
293 return Status;
294 }
295 /* Section */
296 swprintf (
297 Session.Section.NameBuffer,
298 PSX_NS_SESSION_DATA_TEMPLATE,
299 PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
300 PSX_NS_SESSION_DIRECTORY_NAME,
301 Pid
302 );
303 OutputDebugStringW(Session.Section.NameBuffer);
304 RtlInitUnicodeString (& Session.Section.Name, Session.Section.NameBuffer);
305 InitializeObjectAttributes (& Oa, & Session.Section.Name, 0, 0, 0);
306 Status = NtCreateSection (
307 & Session.Section.Handle,
308 SECTION_ALL_ACCESS, /* DesiredAccess */
309 & Oa,
310 & SectionSize,
311 PAGE_READWRITE, /* Protect 4 */
312 SEC_COMMIT, /* Attributes */
313 0 /* FileHandle: 0=pagefile.sys */
314 );
315 if (!NT_SUCCESS(Status))
316 {
317 NtClose (Session.Port.Handle);
318 NtTerminateThread (Session.Port.Thread.Handle, Status);
319 RtlDeleteCriticalSection (& Session.Lock);
320 vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
321 MyName, __FUNCTION__, Status);
322 return Status;
323 }
324 Session.Section.BaseAddress = NULL;
325 Session.Section.ViewSize = SectionSize.u.LowPart;
326 Status = NtMapViewOfSection (
327 Session.Section.Handle,
328 NtCurrentProcess(),
329 & Session.Section.BaseAddress,
330 0, /* ZeroBits */
331 0, /* Commitsize */
332 0, /* SectionOffset */
333 & Session.Section.ViewSize,
334 ViewUnmap,
335 0, /* AllocationType */
336 PAGE_READWRITE /* Protect 4 */
337 );
338 if (!NT_SUCCESS(Status))
339 {
340 NtClose (Session.Port.Handle);
341 NtTerminateThread (Session.Port.Thread.Handle, Status);
342 NtClose (Session.Section.Handle);
343 RtlDeleteCriticalSection (& Session.Lock);
344 vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
345 MyName, __FUNCTION__, Status);
346 return Status;
347 }
348 return Status;
349 }
350
351 /**********************************************************************
352 * CreateTerminalToPsxChannel/0 PRIVATE
353 *
354 * DESCRIPTION
355 *
356 */
357 PRIVATE NTSTATUS STDCALL CreateTerminalToPsxChannel (VOID)
358 {
359 PSX_CONNECT_PORT_DATA ConnectData;
360 ULONG ConnectDataLength = sizeof ConnectData;
361 SECURITY_QUALITY_OF_SERVICE Sqos;
362 NTSTATUS Status;
363
364 TRACE;
365
366
367 /*
368 * Initialize the connection data object before
369 * calling PSXSS.
370 */
371 ConnectData.ConnectionType = PSX_CONNECTION_TYPE_TERMINAL;
372 ConnectData.Version = PSX_LPC_PROTOCOL_VERSION;
373 /*
374 * Try connecting to \POSIX+\SessionPort.
375 */
376 RtlInitUnicodeString (& Session.ServerPort.Name, Session.ServerPort.NameBuffer);
377 OutputDebugStringW(Session.ServerPort.Name.Buffer);
378 Status = NtConnectPort (
379 & Session.ServerPort.Handle,
380 & Session.ServerPort.Name,
381 & Sqos,
382 NULL,
383 NULL,
384 0,
385 & ConnectData,
386 & ConnectDataLength
387 );
388 if (STATUS_SUCCESS != Status)
389 {
390 vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
391 MyName, __FUNCTION__, Status);
392 return Status;
393 }
394 Session.Identifier = ConnectData.PortIdentifier;
395 return STATUS_SUCCESS;
396 }
397
398 /**********************************************************************
399 * InitializeSsIoChannel PRIVATE
400 *
401 * DESCRIPTION
402 * Create our objects in the system name space
403 * (CreateSessionObjects) and then connect to the session port
404 * (CreateControChannel).
405 */
406 PRIVATE NTSTATUS STDCALL InitializeSsIoChannel (VOID)
407 {
408 NTSTATUS Status = STATUS_SUCCESS;
409 DWORD Pid = GetCurrentProcessId();
410
411 TRACE;
412
413
414 Status = CreateSessionObjects (Pid);
415 if (STATUS_SUCCESS != Status)
416 {
417 vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
418 MyName, __FUNCTION__, Status);
419 return Status;
420 }
421 Status = CreateTerminalToPsxChannel ();
422 if (STATUS_SUCCESS != Status)
423 {
424 vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
425 MyName, __FUNCTION__, Status);
426 return Status;
427 }
428 return STATUS_SUCCESS;
429 }
430 /**********************************************************************
431 * PsxCreateLeaderProcess/1 PRIVATE
432 *
433 * DESCRIPTION
434 * Create a new PSXSS process.
435 */
436 PRIVATE NTSTATUS STDCALL PsxCreateLeaderProcess (char * Command)
437 {
438 NTSTATUS Status;
439 TRACE;
440
441 if (NULL == Command)
442 {
443 Command = "sh";
444 }
445 /* TODO: request PSXSS to init the process slot */
446 vtprintf ("%s: %s: calling CSRSS not implemented!", MyName, __FUNCTION__);
447 return STATUS_SUCCESS;
448 }
449 /**********************************************************************
450 * PrintInformationProcess/0
451 *
452 * DESCRIPTION
453 */
454 PRIVATE VOID STDCALL PrintInformationProcess (VOID)
455 {
456
457 TRACE;
458
459 vtputs ("Leader:");
460 vtprintf (" UniqueProcess %08x\n", Session.Client.UniqueProcess);
461 vtprintf (" UniqueThread %08x\n", Session.Client.UniqueThread);
462 }
463 /**********************************************************************
464 * PostMortem/0
465 *
466 * DESCRIPTION
467 */
468 PRIVATE INT STDCALL PostMortem (VOID)
469 {
470 DWORD ExitCode;
471
472 TRACE;
473
474
475 PrintInformationProcess ();
476 if (TRUE == GetExitCodeProcess (Session.Client.UniqueProcess, & ExitCode))
477 {
478 vtprintf (" ExitCode %d\n", ExitCode);
479 }
480 return 0;
481 }
482 /**********************************************************************
483 * InputTerminalEmulator/0
484 *
485 * DESCRIPTION
486 * Process user terminal input.
487 *
488 * NOTE
489 * This code is run in the main thread.
490 */
491 PRIVATE BOOL STDCALL InputTerminalEmulator (VOID)
492 {
493 HANDLE StandardInput;
494 INPUT_RECORD InputRecord [INPUT_QUEUE_SIZE];
495 DWORD NumberOfEventsRead = 0;
496 INT CurrentEvent;
497
498
499 TRACE;
500
501 StandardInput = GetStdHandle (STD_INPUT_HANDLE);
502 if (INVALID_HANDLE_VALUE == StandardInput)
503 {
504 return FALSE;
505 }
506 while ((TRUE == Session.SsLinkIsActive) &&
507 ReadConsoleInput (
508 StandardInput,
509 InputRecord,
510 (sizeof InputRecord) / sizeof (INPUT_RECORD),
511 & NumberOfEventsRead
512 ))
513 {
514 for ( CurrentEvent = 0;
515 (CurrentEvent < NumberOfEventsRead);
516 CurrentEvent ++
517 )
518 {
519 switch (InputRecord [CurrentEvent].EventType)
520 {
521 case KEY_EVENT:
522 OutPort (& InputRecord [CurrentEvent].Event.KeyEvent.uChar.AsciiChar, 1);
523 break;
524 case MOUSE_EVENT:
525 /* TODO: send a sequence of move cursor codes */
526 /* InputRecord [CurrentEvent].Event.MouseEvent; */
527 break;
528 case WINDOW_BUFFER_SIZE_EVENT:
529 /* TODO: send a SIGWINCH signal to the leader process. */
530 /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
531 break;
532 /* Next events should be ignored. */
533 case MENU_EVENT:
534 vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName, __FUNCTION__);
535 case FOCUS_EVENT:
536 vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName, __FUNCTION__);
537 break;
538 }
539 }
540 NumberOfEventsRead = 0;
541 }
542 return TRUE;
543 }
544 /**********************************************************************
545 * Startup/1
546 *
547 * DESCRIPTION
548 * Initialize the program.
549 */
550 PRIVATE VOID STDCALL Startup (LPSTR Command)
551 {
552 NTSTATUS Status;
553 DWORD ThreadId;
554
555
556 TRACE;
557
558 /* PSX process info */
559 Session.Client.UniqueProcess = INVALID_HANDLE_VALUE;
560 Session.Client.UniqueThread = INVALID_HANDLE_VALUE;
561 /* Initialize the VT-100 emulator */
562 vtInitVT100 ();
563 /* Connect to PSXSS */
564 Status = InitializeSsIoChannel ();
565 if (!NT_SUCCESS(Status))
566 {
567 vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
568 MyName, Status);
569 exit (EXIT_FAILURE);
570 }
571 /* Create the leading process for this session */
572 Status = PsxCreateLeaderProcess (Command);
573 if (!NT_SUCCESS(Status))
574 {
575 vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
576 MyName, Status);
577 exit (EXIT_FAILURE);
578 }
579 }
580 /**********************************************************************
581 * Shutdown/0 PRIVATE
582 *
583 * DESCRIPTION
584 * Shutdown the program.
585 */
586 PRIVATE INT STDCALL Shutdown (VOID)
587 {
588
589 TRACE;
590
591 /* TODO: try exiting cleanly: close any open resource */
592 /* TODO: notify PSXSS the session is terminating */
593 RtlDeleteCriticalSection (& Session.Lock);
594 return PostMortem ();
595 }
596 /**********************************************************************
597 *
598 * ENTRY POINT PUBLIC
599 *
600 *********************************************************************/
601 int main (int argc, char * argv [])
602 {
603
604 TRACE;
605
606 Startup (argv[1]); /* Initialization */
607 InputTerminalEmulator (); /* Process user input */
608 return Shutdown ();
609 }
610 /* EOF */