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
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 * --------------------------------------------------------------------
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.
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.
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,
32 * --------------------------------------------------------------------
33 * 2002-03-16 EA Today it actually compiled.
34 * 2002-06-08 EA Renamed (old name was CSRTERM)
40 #define NTOS_MODE_USER
42 #include <sm/helper.h>
43 #include <psx/lpcproto.h>
48 /*** OPTIONS *********************************************************/
50 #define PRIVATE static
52 #define INPUT_QUEUE_SIZE 32
57 //#define TRACE OutputDebugString(__FUNCTION__)
58 #define TRACE vtprintf("%s\n",__FUNCTION__)
61 /*** GLOBALS *********************************************************/
63 PRIVATE LPCSTR MyName
= "POSIXW32";
64 PRIVATE CSRTERM_SESSION Session
=
69 L
"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME
"\\"PSX_NS_SESSIONAPI_PORT_NAME
,
74 /*** PRIVATE FUNCTIONS ***********************************************/
75 VOID STDCALL
Debug_Print (LPCSTR Format
, ...)
78 va_list ArgumentPointer
;
80 va_start(ArgumentPointer
, Format
);
81 vsprintf(Buffer
, Format
, ArgumentPointer
);
82 va_end(ArgumentPointer
);
83 OutputDebugStringA (Buffer
);
85 /**********************************************************************
89 * Notify to PSXSS that input data is ready by sending a
90 * software interrupt on the \POSIX+\SessionPort port.
92 PRIVATE DWORD STDCALL
OutPort (PCHAR Buffer
, ULONG Size
)
95 PSX_TERMINAL_READ TerminalRead
;
100 TerminalRead
.Header
.MessageType
= LPC_NEW_MESSAGE
;
101 TerminalRead
.PsxHeader
.Context
= PSX_CONNECTION_TYPE_TERMINAL
;
102 TerminalRead
.PsxHeader
.Procedure
= PSX_TERMINAL_INTERRUPT
;
104 TerminalRead
.Size
= Size
;
106 RtlCopyMemory (TerminalRead
.Buffer
, Buffer
, Size
);
107 Status
= NtRequestWaitReplyPort (
108 Session
.ServerPort
.Handle
,
113 if (!NT_SUCCESS(Status
))
115 vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
116 MyName
, __FUNCTION__
, Status
);
122 /**********************************************************************
123 * ProcessConnectionRequest/1 PRIVATE
126 * Initialize our data for managing the control connection
127 * initiated by the PSXSS.EXE process.
129 PRIVATE NTSTATUS STDCALL
ProcessConnectionRequest (PLPC_MAX_MESSAGE Request
)
131 PPSX_CONNECT_PORT_DATA ConnectData
= (PPSX_CONNECT_PORT_DATA
) & Request
->Data
;
134 if (PSX_CONNECTION_TYPE_SERVER
!= ConnectData
->ConnectionType
)
137 return STATUS_UNSUCCESSFUL
;
139 if (PSX_LPC_PROTOCOL_VERSION
!= ConnectData
->Version
)
142 return STATUS_UNSUCCESSFUL
;
144 Session
.SsLinkIsActive
= TRUE
;
145 return STATUS_SUCCESS
;
147 /**********************************************************************
148 * ProcessRequest/1 PRIVATE
153 PRIVATE NTSTATUS STDCALL
ProcessRequest (PPSX_MAX_MESSAGE Request
)
157 vtprintf("TEST VT-100\n");
159 return STATUS_SUCCESS
;
161 /**********************************************************************
162 * PsxSessionPortListener/1 PRIVATE
165 * Manage messages from the PSXSS, that is LPC messages we get
166 * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
169 * This function is the thread 's entry point created in
170 * CreateSessionObiects().
172 PRIVATE DWORD STDCALL
PsxSessionPortListener (LPVOID Arg
)
175 LPC_TYPE RequestType
;
176 PSX_MAX_MESSAGE Request
;
177 PPSX_MAX_MESSAGE Reply
= NULL
;
178 BOOL NullReply
= FALSE
;
188 Status
= NtReplyWaitReceivePort (
191 (PLPC_MESSAGE
) Reply
,
192 (PLPC_MESSAGE
) & Request
194 if (!NT_SUCCESS(Status
))
198 RequestType
= PORT_MESSAGE_TYPE(Request
);
201 case LPC_CONNECTION_REQUEST
:
202 ProcessConnectionRequest ((PLPC_MAX_MESSAGE
) & Request
);
205 case LPC_CLIENT_DIED
:
206 case LPC_PORT_CLOSED
:
207 case LPC_DEBUG_EVENT
:
208 case LPC_ERROR_EVENT
:
213 if (RequestType
!= LPC_REQUEST
)
220 Reply
->PsxHeader
.Status
= ProcessRequest (& Request
);
223 if ((STATUS_INVALID_HANDLE
== Status
) ||
224 (STATUS_OBJECT_TYPE_MISMATCH
== Status
))
229 Session
.SsLinkIsActive
= FALSE
;
230 TerminateThread (GetCurrentThread(), Status
);
232 /**********************************************************************
233 * CreateSessionObiects/1 PRIVATE
236 * Create the session objects which are mananged by our side:
238 * \POSIX+\Sessions\P<pid>
239 * \POSIX+\Sessions\D<pid>
241 PRIVATE NTSTATUS STDCALL
CreateSessionObjects (DWORD Pid
)
245 OBJECT_ATTRIBUTES Oa
;
246 LARGE_INTEGER SectionSize
= {PSX_TERMINAL_SECTION_SIZE
,0};
251 /* Critical section */
252 Status
= RtlInitializeCriticalSection (& Session
.Lock
);
253 if (!NT_SUCCESS(Status
))
256 "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
257 MyName
, __FUNCTION__
, Status
);
260 /* Port and port management thread */
262 Session
.Port
.NameBuffer
,
263 PSX_NS_SESSION_PORT_TEMPLATE
,
264 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
265 PSX_NS_SESSION_DIRECTORY_NAME
,
268 OutputDebugStringW(Session
.Port
.NameBuffer
);
269 RtlInitUnicodeString (& Session
.Port
.Name
, Session
.Port
.NameBuffer
);
270 InitializeObjectAttributes (& Oa
, & Session
.Port
.Name
, 0, NULL
, NULL
);
271 Status
= NtCreatePort (& Session
.Port
.Handle
, & Oa
, 0, 0, 0x10000);
272 if (!NT_SUCCESS(Status
))
274 RtlDeleteCriticalSection (& Session
.Lock
);
275 vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
276 MyName
, __FUNCTION__
, Status
);
279 Session
.Port
.Thread
.Handle
=
283 PsxSessionPortListener
,
286 & Session
.Port
.Thread
.Id
288 if ((HANDLE
) NULL
== Session
.Port
.Thread
.Handle
)
290 Status
= (NTSTATUS
) GetLastError();
291 NtClose (Session
.Port
.Handle
);
292 RtlDeleteCriticalSection (& Session
.Lock
);
293 vtprintf ("%s: %s: CreateThread failed with %d\n",
294 MyName
, __FUNCTION__
, Status
);
299 Session
.Section
.NameBuffer
,
300 PSX_NS_SESSION_DATA_TEMPLATE
,
301 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
302 PSX_NS_SESSION_DIRECTORY_NAME
,
305 OutputDebugStringW(Session
.Section
.NameBuffer
);
306 RtlInitUnicodeString (& Session
.Section
.Name
, Session
.Section
.NameBuffer
);
307 InitializeObjectAttributes (& Oa
, & Session
.Section
.Name
, 0, 0, 0);
308 Status
= NtCreateSection (
309 & Session
.Section
.Handle
,
310 SECTION_ALL_ACCESS
, /* DesiredAccess */
313 PAGE_READWRITE
, /* Protect 4 */
314 SEC_COMMIT
, /* Attributes */
315 0 /* FileHandle: 0=pagefile.sys */
317 if (!NT_SUCCESS(Status
))
319 NtClose (Session
.Port
.Handle
);
320 NtTerminateThread (Session
.Port
.Thread
.Handle
, Status
);
321 RtlDeleteCriticalSection (& Session
.Lock
);
322 vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
323 MyName
, __FUNCTION__
, Status
);
326 Session
.Section
.BaseAddress
= NULL
;
327 Session
.Section
.ViewSize
= SectionSize
.u
.LowPart
;
328 Status
= NtMapViewOfSection (
329 Session
.Section
.Handle
,
331 & Session
.Section
.BaseAddress
,
334 0, /* SectionOffset */
335 & Session
.Section
.ViewSize
,
337 0, /* AllocationType */
338 PAGE_READWRITE
/* Protect 4 */
340 if (!NT_SUCCESS(Status
))
342 NtClose (Session
.Port
.Handle
);
343 NtTerminateThread (Session
.Port
.Thread
.Handle
, Status
);
344 NtClose (Session
.Section
.Handle
);
345 RtlDeleteCriticalSection (& Session
.Lock
);
346 vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
347 MyName
, __FUNCTION__
, Status
);
352 /**********************************************************************
356 * This function is called only when initializing the session
357 * with PSXSS fails. We assume that it failed because the
358 * subsystem, being optional, is not running, therefore we
359 * ask the SM to start it up.
361 PRIVATE NTSTATUS
RunPsxSs(VOID
)
365 UNICODE_STRING Program
;
367 RtlInitUnicodeString (& Program
, L
"POSIX");
368 Status
= SmConnectApiPort (NULL
, 0, 0, & SmApiPort
);
369 if(!NT_SUCCESS(Status
))
373 Status
= SmExecuteProgram (SmApiPort
, & Program
);
377 /**********************************************************************
378 * CreateTerminalToPsxChannel/0 PRIVATE
383 PRIVATE NTSTATUS STDCALL
CreateTerminalToPsxChannel (VOID
)
385 PSX_CONNECT_PORT_DATA ConnectData
;
386 ULONG ConnectDataLength
= sizeof ConnectData
;
387 SECURITY_QUALITY_OF_SERVICE Sqos
;
395 * Initialize the connection data object before
398 ConnectData
.ConnectionType
= PSX_CONNECTION_TYPE_TERMINAL
;
399 ConnectData
.Version
= PSX_LPC_PROTOCOL_VERSION
;
401 * Try connecting to \POSIX+\SessionPort.
403 RtlInitUnicodeString (& Session
.ServerPort
.Name
, Session
.ServerPort
.NameBuffer
);
406 OutputDebugStringW(Session
.ServerPort
.Name
.Buffer
);
407 Status
= NtConnectPort (
408 & Session
.ServerPort
.Handle
,
409 & Session
.ServerPort
.Name
,
417 if (STATUS_SUCCESS
!= Status
)
421 vtprintf("%s: %s: asking SM to start PSXSS...\n",MyName
,__FUNCTION__
);
425 vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
426 MyName
, __FUNCTION__
, Status
);
431 Session
.Identifier
= ConnectData
.PortIdentifier
;
432 return STATUS_SUCCESS
;
435 /**********************************************************************
436 * InitializeSsIoChannel PRIVATE
439 * Connect to the session port (CreateControChannel) of the PSX
440 * subsystem. If that succeeds, create our objects in the system
441 * name space (CreateSessionObjects).
443 PRIVATE NTSTATUS STDCALL
InitializeSsIoChannel (VOID
)
445 NTSTATUS Status
= STATUS_SUCCESS
;
446 DWORD Pid
= GetCurrentProcessId();
451 Status
= CreateTerminalToPsxChannel ();
452 if (STATUS_SUCCESS
!= Status
)
454 vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
455 MyName
, __FUNCTION__
, Status
);
458 Status
= CreateSessionObjects (Pid
);
459 if (STATUS_SUCCESS
!= Status
)
461 vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
462 MyName
, __FUNCTION__
, Status
);
465 return STATUS_SUCCESS
;
467 /**********************************************************************
468 * PsxCreateLeaderProcess/1 PRIVATE
471 * Create a new PSXSS process. We are running under Win32 server
472 * and can not run directly a PSX image: we make SM run it for us.
475 PRIVATE NTSTATUS STDCALL
PsxCreateLeaderProcess (char * Command
)
484 /* TODO: request SM to create the process: LPC:SmExecPgm() */
485 vtprintf ("%s: %s: calling SMSS not implemented!", MyName
, __FUNCTION__
);
486 return STATUS_SUCCESS
;
488 /**********************************************************************
489 * PrintInformationProcess/0
493 PRIVATE VOID STDCALL
PrintInformationProcess (VOID
)
499 vtprintf (" UniqueProcess %08x\n", Session
.Client
.UniqueProcess
);
500 vtprintf (" UniqueThread %08x\n", Session
.Client
.UniqueThread
);
502 /**********************************************************************
507 PRIVATE INT STDCALL
PostMortem (VOID
)
514 PrintInformationProcess ();
515 if (TRUE
== GetExitCodeProcess (Session
.Client
.UniqueProcess
, & ExitCode
))
517 vtprintf (" ExitCode %d\n", ExitCode
);
521 /**********************************************************************
522 * InputTerminalEmulator/0
525 * Process user terminal input.
528 * This code is run in the main thread.
530 PRIVATE BOOL STDCALL
InputTerminalEmulator (VOID
)
532 HANDLE StandardInput
;
533 INPUT_RECORD InputRecord
[INPUT_QUEUE_SIZE
];
534 DWORD NumberOfEventsRead
= 0;
540 StandardInput
= GetStdHandle (STD_INPUT_HANDLE
);
541 if (INVALID_HANDLE_VALUE
== StandardInput
)
545 while ((TRUE
== Session
.SsLinkIsActive
) &&
549 (sizeof InputRecord
) / sizeof (INPUT_RECORD
),
553 for ( CurrentEvent
= 0;
554 (CurrentEvent
< NumberOfEventsRead
);
558 switch (InputRecord
[CurrentEvent
].EventType
)
561 OutPort (& InputRecord
[CurrentEvent
].Event
.KeyEvent
.uChar
.AsciiChar
, 1);
564 /* TODO: send a sequence of move cursor codes */
565 /* InputRecord [CurrentEvent].Event.MouseEvent; */
567 case WINDOW_BUFFER_SIZE_EVENT
:
568 /* TODO: send a SIGWINCH signal to the leader process. */
569 /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
571 /* Next events should be ignored. */
573 vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
575 vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
579 NumberOfEventsRead
= 0;
583 /**********************************************************************
587 * Initialize the program.
589 PRIVATE VOID STDCALL
Startup (LPSTR Command
)
597 /* PSX process info */
598 Session
.Client
.UniqueProcess
= INVALID_HANDLE_VALUE
;
599 Session
.Client
.UniqueThread
= INVALID_HANDLE_VALUE
;
600 /* Initialize the VT-100 emulator */
602 /* Connect to PSXSS */
603 Status
= InitializeSsIoChannel ();
604 if (!NT_SUCCESS(Status
))
606 vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
610 /* Create the leading process for this session */
611 Status
= PsxCreateLeaderProcess (Command
);
612 if (!NT_SUCCESS(Status
))
614 vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
619 /**********************************************************************
623 * Shutdown the program.
625 PRIVATE INT STDCALL
Shutdown (VOID
)
630 /* TODO: try exiting cleanly: close any open resource */
631 /* TODO: notify PSXSS the session is terminating */
632 RtlDeleteCriticalSection (& Session
.Lock
);
633 return PostMortem ();
635 /**********************************************************************
639 *********************************************************************/
640 int main (int argc
, char * argv
[])
645 Startup (argv
[1]); /* Initialization */
646 InputTerminalEmulator (); /* Process user input */