1 /* $Id: posixw32.c,v 1.3 2002/10/29 04:44:59 rex Exp $
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 <psx/lpcproto.h>
47 /*** OPTIONS *********************************************************/
49 #define PRIVATE static
51 #define INPUT_QUEUE_SIZE 32
56 #define TRACE OutputDebugString(__FUNCTION__)
59 /*** GLOBALS *********************************************************/
61 PRIVATE LPCSTR MyName
= "POSIXW32";
62 PRIVATE CSRTERM_SESSION Session
=
67 L
"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME
"\\"PSX_NS_SESSIONAPI_PORT_NAME
,
72 /*** PRIVATE FUNCTIONS ***********************************************/
73 VOID STDCALL
Debug_Print (LPCSTR Format
, ...)
76 va_list ArgumentPointer
;
78 va_start(ArgumentPointer
, Format
);
79 vsprintf(Buffer
, Format
, ArgumentPointer
);
80 va_end(ArgumentPointer
);
81 OutputDebugStringA (Buffer
);
83 /**********************************************************************
87 * Notify to PSXSS that input data is ready by sending a
88 * software interrupt on the \POSIX+\SessionPort port.
90 PRIVATE DWORD STDCALL
OutPort (PCHAR Buffer
, ULONG Size
)
93 PSX_TERMINAL_READ TerminalRead
;
98 TerminalRead
.Header
.MessageType
= LPC_NEW_MESSAGE
;
99 TerminalRead
.PsxHeader
.Context
= PSX_CONNECTION_TYPE_TERMINAL
;
100 TerminalRead
.PsxHeader
.Procedure
= PSX_TERMINAL_INTERRUPT
;
102 TerminalRead
.Size
= Size
;
104 RtlCopyMemory (TerminalRead
.Buffer
, Buffer
, Size
);
105 Status
= NtRequestWaitReplyPort (
106 Session
.ServerPort
.Handle
,
111 if (!NT_SUCCESS(Status
))
113 vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
114 MyName
, __FUNCTION__
, Status
);
120 /**********************************************************************
121 * ProcessConnectionRequest/1 PRIVATE
124 * Initialize our data for managing the control connection
125 * initiated by the PSXSS.EXE process.
127 PRIVATE NTSTATUS STDCALL
ProcessConnectionRequest (PLPC_MAX_MESSAGE Request
)
129 PPSX_CONNECT_PORT_DATA ConnectData
= (PPSX_CONNECT_PORT_DATA
) & Request
->Data
;
132 if (PSX_CONNECTION_TYPE_SERVER
!= ConnectData
->ConnectionType
)
135 return STATUS_UNSUCCESSFUL
;
137 if (PSX_LPC_PROTOCOL_VERSION
!= ConnectData
->Version
)
140 return STATUS_UNSUCCESSFUL
;
142 Session
.SsLinkIsActive
= TRUE
;
143 return STATUS_SUCCESS
;
145 /**********************************************************************
146 * ProcessRequest/1 PRIVATE
151 PRIVATE NTSTATUS STDCALL
ProcessRequest (PPSX_MAX_MESSAGE Request
)
155 vtprintf("TEST VT-100\n");
157 return STATUS_SUCCESS
;
159 /**********************************************************************
160 * PsxSessionPortListener/1 PRIVATE
163 * Manage messages from the PSXSS, that is LPC messages we get
164 * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
167 * This function is the thread 's entry point created in
168 * CreateSessionObiects().
170 PRIVATE DWORD STDCALL
PsxSessionPortListener (LPVOID Arg
)
173 LPC_TYPE RequestType
;
174 PSX_MAX_MESSAGE Request
;
175 PPSX_MAX_MESSAGE Reply
= NULL
;
176 BOOL NullReply
= FALSE
;
186 Status
= NtReplyWaitReceivePort (
189 (PLPC_MESSAGE
) Reply
,
190 (PLPC_MESSAGE
) & Request
192 if (!NT_SUCCESS(Status
))
196 RequestType
= PORT_MESSAGE_TYPE(Request
);
199 case LPC_CONNECTION_REQUEST
:
200 ProcessConnectionRequest ((PLPC_MAX_MESSAGE
) & Request
);
203 case LPC_CLIENT_DIED
:
204 case LPC_PORT_CLOSED
:
205 case LPC_DEBUG_EVENT
:
206 case LPC_ERROR_EVENT
:
211 if (RequestType
!= LPC_REQUEST
)
218 Reply
->PsxHeader
.Status
= ProcessRequest (& Request
);
221 if ((STATUS_INVALID_HANDLE
== Status
) ||
222 (STATUS_OBJECT_TYPE_MISMATCH
== Status
))
227 Session
.SsLinkIsActive
= FALSE
;
228 TerminateThread (GetCurrentThread(), Status
);
230 /**********************************************************************
231 * CreateSessionObiects/1 PRIVATE
234 * Create the session objects which are mananged by our side:
236 * \POSIX+\Sessions\P<pid>
237 * \POSIX+\Sessions\D<pid>
239 PRIVATE NTSTATUS STDCALL
CreateSessionObjects (DWORD Pid
)
243 OBJECT_ATTRIBUTES Oa
;
244 LARGE_INTEGER SectionSize
= {PSX_TERMINAL_SECTION_SIZE
,0};
249 /* Critical section */
250 Status
= RtlInitializeCriticalSection (& Session
.Lock
);
251 if (!NT_SUCCESS(Status
))
254 "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
255 MyName
, __FUNCTION__
, Status
);
258 /* Port and port management thread */
260 Session
.Port
.NameBuffer
,
261 PSX_NS_SESSION_PORT_TEMPLATE
,
262 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
263 PSX_NS_SESSION_DIRECTORY_NAME
,
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
))
272 RtlDeleteCriticalSection (& Session
.Lock
);
273 vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
274 MyName
, __FUNCTION__
, Status
);
277 Session
.Port
.Thread
.Handle
=
281 PsxSessionPortListener
,
284 & Session
.Port
.Thread
.Id
286 if ((HANDLE
) NULL
== Session
.Port
.Thread
.Handle
)
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
);
297 Session
.Section
.NameBuffer
,
298 PSX_NS_SESSION_DATA_TEMPLATE
,
299 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
300 PSX_NS_SESSION_DIRECTORY_NAME
,
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 */
311 PAGE_READWRITE
, /* Protect 4 */
312 SEC_COMMIT
, /* Attributes */
313 0 /* FileHandle: 0=pagefile.sys */
315 if (!NT_SUCCESS(Status
))
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
);
324 Session
.Section
.BaseAddress
= NULL
;
325 Session
.Section
.ViewSize
= SectionSize
.u
.LowPart
;
326 Status
= NtMapViewOfSection (
327 Session
.Section
.Handle
,
329 & Session
.Section
.BaseAddress
,
332 0, /* SectionOffset */
333 & Session
.Section
.ViewSize
,
335 0, /* AllocationType */
336 PAGE_READWRITE
/* Protect 4 */
338 if (!NT_SUCCESS(Status
))
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
);
351 /**********************************************************************
352 * CreateTerminalToPsxChannel/0 PRIVATE
357 PRIVATE NTSTATUS STDCALL
CreateTerminalToPsxChannel (VOID
)
359 PSX_CONNECT_PORT_DATA ConnectData
;
360 ULONG ConnectDataLength
= sizeof ConnectData
;
361 SECURITY_QUALITY_OF_SERVICE Sqos
;
368 * Initialize the connection data object before
371 ConnectData
.ConnectionType
= PSX_CONNECTION_TYPE_TERMINAL
;
372 ConnectData
.Version
= PSX_LPC_PROTOCOL_VERSION
;
374 * Try connecting to \POSIX+\SessionPort.
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
,
388 if (STATUS_SUCCESS
!= Status
)
390 vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
391 MyName
, __FUNCTION__
, Status
);
394 Session
.Identifier
= ConnectData
.PortIdentifier
;
395 return STATUS_SUCCESS
;
398 /**********************************************************************
399 * InitializeSsIoChannel PRIVATE
402 * Create our objects in the system name space
403 * (CreateSessionObjects) and then connect to the session port
404 * (CreateControChannel).
406 PRIVATE NTSTATUS STDCALL
InitializeSsIoChannel (VOID
)
408 NTSTATUS Status
= STATUS_SUCCESS
;
409 DWORD Pid
= GetCurrentProcessId();
414 Status
= CreateSessionObjects (Pid
);
415 if (STATUS_SUCCESS
!= Status
)
417 vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
418 MyName
, __FUNCTION__
, Status
);
421 Status
= CreateTerminalToPsxChannel ();
422 if (STATUS_SUCCESS
!= Status
)
424 vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
425 MyName
, __FUNCTION__
, Status
);
428 return STATUS_SUCCESS
;
430 /**********************************************************************
431 * PsxCreateLeaderProcess/1 PRIVATE
434 * Create a new PSXSS process.
436 PRIVATE NTSTATUS STDCALL
PsxCreateLeaderProcess (char * Command
)
445 /* TODO: request PSXSS to init the process slot */
446 vtprintf ("%s: %s: calling CSRSS not implemented!", MyName
, __FUNCTION__
);
447 return STATUS_SUCCESS
;
449 /**********************************************************************
450 * PrintInformationProcess/0
454 PRIVATE VOID STDCALL
PrintInformationProcess (VOID
)
460 vtprintf (" UniqueProcess %08x\n", Session
.Client
.UniqueProcess
);
461 vtprintf (" UniqueThread %08x\n", Session
.Client
.UniqueThread
);
463 /**********************************************************************
468 PRIVATE INT STDCALL
PostMortem (VOID
)
475 PrintInformationProcess ();
476 if (TRUE
== GetExitCodeProcess (Session
.Client
.UniqueProcess
, & ExitCode
))
478 vtprintf (" ExitCode %d\n", ExitCode
);
482 /**********************************************************************
483 * InputTerminalEmulator/0
486 * Process user terminal input.
489 * This code is run in the main thread.
491 PRIVATE BOOL STDCALL
InputTerminalEmulator (VOID
)
493 HANDLE StandardInput
;
494 INPUT_RECORD InputRecord
[INPUT_QUEUE_SIZE
];
495 DWORD NumberOfEventsRead
= 0;
501 StandardInput
= GetStdHandle (STD_INPUT_HANDLE
);
502 if (INVALID_HANDLE_VALUE
== StandardInput
)
506 while ((TRUE
== Session
.SsLinkIsActive
) &&
510 (sizeof InputRecord
) / sizeof (INPUT_RECORD
),
514 for ( CurrentEvent
= 0;
515 (CurrentEvent
< NumberOfEventsRead
);
519 switch (InputRecord
[CurrentEvent
].EventType
)
522 OutPort (& InputRecord
[CurrentEvent
].Event
.KeyEvent
.uChar
.AsciiChar
, 1);
525 /* TODO: send a sequence of move cursor codes */
526 /* InputRecord [CurrentEvent].Event.MouseEvent; */
528 case WINDOW_BUFFER_SIZE_EVENT
:
529 /* TODO: send a SIGWINCH signal to the leader process. */
530 /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
532 /* Next events should be ignored. */
534 vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
536 vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
540 NumberOfEventsRead
= 0;
544 /**********************************************************************
548 * Initialize the program.
550 PRIVATE VOID STDCALL
Startup (LPSTR Command
)
558 /* PSX process info */
559 Session
.Client
.UniqueProcess
= INVALID_HANDLE_VALUE
;
560 Session
.Client
.UniqueThread
= INVALID_HANDLE_VALUE
;
561 /* Initialize the VT-100 emulator */
563 /* Connect to PSXSS */
564 Status
= InitializeSsIoChannel ();
565 if (!NT_SUCCESS(Status
))
567 vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
571 /* Create the leading process for this session */
572 Status
= PsxCreateLeaderProcess (Command
);
573 if (!NT_SUCCESS(Status
))
575 vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
580 /**********************************************************************
584 * Shutdown the program.
586 PRIVATE INT STDCALL
Shutdown (VOID
)
591 /* TODO: try exiting cleanly: close any open resource */
592 /* TODO: notify PSXSS the session is terminating */
593 RtlDeleteCriticalSection (& Session
.Lock
);
594 return PostMortem ();
596 /**********************************************************************
600 *********************************************************************/
601 int main (int argc
, char * argv
[])
606 Startup (argv
[1]); /* Initialization */
607 InputTerminalEmulator (); /* Process user input */