1 /* $Id: csrterm.c,v 1.2 2002/04/06 16:00:46 ea Exp $
3 * PROJECT : ReactOS Operating System / POSIX+ Environment Subsystem
4 * DESCRIPTION: CSRTERM - 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.
39 #define NTOS_MODE_USER
41 #include <psx/lpcproto.h>
46 /*** OPTIONS *********************************************************/
48 #define PRIVATE static
50 #define INPUT_QUEUE_SIZE 32
55 #define TRACE OutputDebugString(__FUNCTION__)
58 /*** GLOBALS *********************************************************/
60 PRIVATE LPCSTR MyName
= "CSRTERM";
61 PRIVATE CSRTERM_SESSION Session
=
66 L
"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME
"\\"PSX_NS_API_PORT_NAME
,
71 /*** PRIVATE FUNCTIONS ***********************************************/
72 VOID STDCALL
Debug_Print (LPCSTR Format
, ...)
75 va_list ArgumentPointer
;
77 va_start(ArgumentPointer
, Format
);
78 vsprintf(Buffer
, Format
, ArgumentPointer
);
79 va_end(ArgumentPointer
);
80 OutputDebugStringA (Buffer
);
82 /**********************************************************************
86 * Notify to PSXSS that input data is ready by sending a
87 * software interrupt on the \POSIX+\SessionPort port.
89 PRIVATE DWORD STDCALL
OutPort (PCHAR Buffer
, ULONG Size
)
92 PSX_TERMINAL_READ TerminalRead
;
97 TerminalRead
.Header
.MessageType
= LPC_NEW_MESSAGE
;
98 TerminalRead
.PsxHeader
.Context
= PSX_CONNECTION_TYPE_TERMINAL
;
99 TerminalRead
.PsxHeader
.Procedure
= PSX_TERMINAL_INTERRUPT
;
101 TerminalRead
.Size
= Size
;
102 RtlCopyMemory (TerminalRead
.Buffer
, Buffer
, Size
);
104 Status
= NtRequestWaitReplyPort (
105 Session
.ServerPort
.Handle
,
110 if (!NT_SUCCESS(Status
))
112 vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
113 MyName
, __FUNCTION__
, Status
);
119 /**********************************************************************
120 * ProcessConnectionRequest/1 PRIVATE
123 * Initialize our data for managing the control connection
124 * initiated by the PSXSS.EXE process.
126 PRIVATE NTSTATUS STDCALL
ProcessConnectionRequest (PPSX_MAX_MESSAGE Request
)
129 Session
.SsLinkIsActive
= TRUE
;
130 return STATUS_SUCCESS
;
132 /**********************************************************************
133 * ProcessRequest/1 PRIVATE
138 PRIVATE NTSTATUS STDCALL
ProcessRequest (PPSX_MAX_MESSAGE Request
)
142 vtprintf("TEST VT-100\n");
144 return STATUS_SUCCESS
;
146 /**********************************************************************
147 * PsxSessionPortListener/1 PRIVATE
150 * Manage messages from the PSXSS, that is LPC messages we get
151 * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
154 * This function is the thread 's entry point created in
155 * CreateSessionObiects().
157 PRIVATE DWORD STDCALL
PsxSessionPortListener (LPVOID Arg
)
160 LPC_TYPE RequestType
;
161 PSX_MAX_MESSAGE Request
;
162 PPSX_MAX_MESSAGE Reply
= NULL
;
163 BOOL NullReply
= FALSE
;
172 Status
= NtReplyWaitReceivePort (
175 (PLPC_MESSAGE
) Reply
,
176 (PLPC_MESSAGE
) & Request
178 if (!NT_SUCCESS(Status
))
182 RequestType
= PORT_MESSAGE_TYPE(Request
);
185 case LPC_CONNECTION_REQUEST
:
186 ProcessConnectionRequest (& Request
);
189 case LPC_CLIENT_DIED
:
190 case LPC_PORT_CLOSED
:
191 case LPC_DEBUG_EVENT
:
192 case LPC_ERROR_EVENT
:
197 if (RequestType
!= LPC_REQUEST
)
204 Reply
->PsxHeader
.Status
= ProcessRequest (& Request
);
207 if ((STATUS_INVALID_HANDLE
== Status
) ||
208 (STATUS_OBJECT_TYPE_MISMATCH
== Status
))
213 Session
.SsLinkIsActive
= FALSE
;
214 TerminateThread (GetCurrentThread(), Status
);
216 /**********************************************************************
217 * CreateSessionObiects/1 PRIVATE
220 * Create the session objects which are mananged by our side:
222 * \POSIX+\Sessions\P<pid>
223 * \POSIX+\Sessions\D<pid>
225 PRIVATE NTSTATUS STDCALL
CreateSessionObjects (DWORD Pid
)
229 OBJECT_ATTRIBUTES Oa
;
230 LARGE_INTEGER SectionSize
= {65536L,0};
235 /* Critical section */
236 Status
= RtlInitializeCriticalSection (& Session
.Lock
);
237 if (!NT_SUCCESS(Status
))
240 "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
241 MyName
, __FUNCTION__
, Status
);
244 /* Port and port management thread */
246 Session
.Port
.NameBuffer
,
247 PSX_NS_SESSION_PORT_TEMPLATE
,
248 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
249 PSX_NS_SESSION_DIRECTORY_NAME
,
252 OutputDebugStringW(Session
.Port
.NameBuffer
);
253 RtlInitUnicodeString (& Session
.Port
.Name
, Session
.Port
.NameBuffer
);
254 InitializeObjectAttributes (& Oa
, & Session
.Port
.Name
, 0, NULL
, NULL
);
255 Status
= NtCreatePort (& Session
.Port
.Handle
, & Oa
, 0, 0, 0x10000);
256 if (!NT_SUCCESS(Status
))
258 RtlDeleteCriticalSection (& Session
.Lock
);
259 vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
260 MyName
, __FUNCTION__
, Status
);
263 Session
.Port
.Thread
.Handle
=
267 PsxSessionPortListener
,
270 & Session
.Port
.Thread
.Id
272 if ((HANDLE
) NULL
== Session
.Port
.Thread
.Handle
)
274 Status
= (NTSTATUS
) GetLastError();
275 NtClose (Session
.Port
.Handle
);
276 RtlDeleteCriticalSection (& Session
.Lock
);
277 vtprintf ("%s: %s: CreateThread failed with %d\n",
278 MyName
, __FUNCTION__
, Status
);
283 Session
.Section
.NameBuffer
,
284 PSX_NS_SESSION_DATA_TEMPLATE
,
285 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
286 PSX_NS_SESSION_DIRECTORY_NAME
,
289 OutputDebugStringW(Session
.Section
.NameBuffer
);
290 RtlInitUnicodeString (& Session
.Section
.Name
, Session
.Section
.NameBuffer
);
291 InitializeObjectAttributes (& Oa
, & Session
.Section
.Name
, 0, 0, 0);
292 Status
= NtCreateSection (
293 & Session
.Section
.Handle
,
294 SECTION_ALL_ACCESS
, /* DesiredAccess */
297 PAGE_READWRITE
, /* Protect 4 */
298 SEC_COMMIT
, /* Attributes */
299 0 /* FileHandle: 0=pagefile.sys */
301 if (!NT_SUCCESS(Status
))
303 NtClose (Session
.Port
.Handle
);
304 NtTerminateThread (Session
.Port
.Thread
.Handle
, Status
);
305 RtlDeleteCriticalSection (& Session
.Lock
);
306 vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
307 MyName
, __FUNCTION__
, Status
);
310 Session
.Section
.BaseAddress
= NULL
;
311 Session
.Section
.ViewSize
= 0;
312 Status
= NtMapViewOfSection (
313 Session
.Section
.Handle
,
315 & Session
.Section
.BaseAddress
,
318 0, /* SectionOffset */
319 & Session
.Section
.ViewSize
,
321 0, /* AllocationType */
322 PAGE_READWRITE
/* Protect 4 */
324 if (!NT_SUCCESS(Status
))
326 NtClose (Session
.Port
.Handle
);
327 NtTerminateThread (Session
.Port
.Thread
.Handle
, Status
);
328 NtClose (Session
.Section
.Handle
);
329 RtlDeleteCriticalSection (& Session
.Lock
);
330 vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
331 MyName
, __FUNCTION__
, Status
);
337 /**********************************************************************
338 * CreateTerminalToPsxChannel/0 PRIVATE
343 PRIVATE NTSTATUS STDCALL
CreateTerminalToPsxChannel (VOID
)
345 PSX_CONNECT_PORT_DATA ConnectData
;
346 ULONG ConnectDataLength
= sizeof ConnectData
;
347 SECURITY_QUALITY_OF_SERVICE Sqos
;
354 * Initialize the connection data object before
357 ConnectData
.ConnectionType
= PSX_CONNECTION_TYPE_TERMINAL
;
358 ConnectData
.Version
= PSX_LPC_PROTOCOL_VERSION
;
360 * Try connecting to \POSIX+\SessionPort.
362 RtlInitUnicodeString (& Session
.ServerPort
.Name
, Session
.ServerPort
.NameBuffer
);
363 OutputDebugStringW(Session
.ServerPort
.Name
.Buffer
);
364 Status
= NtConnectPort (
365 & Session
.ServerPort
.Handle
,
366 & Session
.ServerPort
.Name
,
374 if (STATUS_SUCCESS
!= Status
)
376 vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
377 MyName
, __FUNCTION__
, Status
);
380 Session
.Identifier
= ConnectData
.PortIdentifier
;
381 return STATUS_SUCCESS
;
384 /**********************************************************************
385 * InitializeSsIoChannel PRIVATE
388 * Create our objects in the system name space
389 * (CreateSessionObjects) and then connect to the session port
390 * (CreateControChannel).
392 PRIVATE NTSTATUS STDCALL
InitializeSsIoChannel (VOID
)
394 NTSTATUS Status
= STATUS_SUCCESS
;
395 DWORD Pid
= GetCurrentProcessId();
400 Status
= CreateSessionObjects (Pid
);
401 if (STATUS_SUCCESS
!= Status
)
403 vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
404 MyName
, __FUNCTION__
, Status
);
407 Status
= CreateTerminalToPsxChannel ();
408 if (STATUS_SUCCESS
!= Status
)
410 vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
411 MyName
, __FUNCTION__
, Status
);
414 return STATUS_SUCCESS
;
416 /**********************************************************************
417 * PsxCreateLeaderProcess/1 PRIVATE
420 * Create a new PSXSS process.
422 PRIVATE NTSTATUS STDCALL
PsxCreateLeaderProcess (char * Command
)
431 /* TODO: request PSXSS to init the process slot */
432 return STATUS_NOT_IMPLEMENTED
;
434 /**********************************************************************
435 * PrintInformationProcess/0
439 PRIVATE VOID STDCALL
PrintInformationProcess (VOID
)
445 vtprintf (" UniqueProcess %08x\n", Session
.Client
.UniqueProcess
);
446 vtprintf (" UniqueThread %08x\n", Session
.Client
.UniqueThread
);
448 /**********************************************************************
453 PRIVATE INT STDCALL
PostMortem (VOID
)
460 PrintInformationProcess ();
461 if (TRUE
== GetExitCodeProcess (Session
.Client
.UniqueProcess
, & ExitCode
))
463 vtprintf (" ExitCode %d\n", ExitCode
);
467 /**********************************************************************
468 * InputTerminalEmulator/0
471 * Process user terminal input.
474 * This code is run in the main thread.
476 PRIVATE BOOL STDCALL
InputTerminalEmulator (VOID
)
478 HANDLE StandardInput
;
479 INPUT_RECORD InputRecord
[INPUT_QUEUE_SIZE
];
480 DWORD NumberOfEventsRead
= 0;
486 StandardInput
= GetStdHandle (STD_INPUT_HANDLE
);
487 if (INVALID_HANDLE_VALUE
== StandardInput
)
491 while ((TRUE
== Session
.SsLinkIsActive
) &&
495 (sizeof InputRecord
) / sizeof (INPUT_RECORD
),
499 for ( CurrentEvent
= 0;
500 (CurrentEvent
< NumberOfEventsRead
);
504 switch (InputRecord
[CurrentEvent
].EventType
)
507 OutPort (& InputRecord
[CurrentEvent
].Event
.KeyEvent
.uChar
.AsciiChar
, 1);
510 /* TODO: send a sequence of move cursor codes */
511 /* InputRecord [CurrentEvent].Event.MouseEvent; */
513 case WINDOW_BUFFER_SIZE_EVENT
:
514 /* TODO: send a SIGWINCH signal to the leader process. */
515 /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
517 /* Next events should be ignored. */
519 vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
521 vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
525 NumberOfEventsRead
= 0;
529 /**********************************************************************
533 * Initialize the program.
535 PRIVATE VOID STDCALL
Startup (LPSTR Command
)
543 /* PSX process info */
544 Session
.Client
.UniqueProcess
= INVALID_HANDLE_VALUE
;
545 Session
.Client
.UniqueThread
= INVALID_HANDLE_VALUE
;
546 /* Initialize the VT-100 emulator */
548 /* Connect to PSXSS */
549 Status
= InitializeSsIoChannel ();
550 if (!NT_SUCCESS(Status
))
552 vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
556 /* Create the leading process for this session */
557 Status
= PsxCreateLeaderProcess (Command
);
558 if (!NT_SUCCESS(Status
))
560 vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
565 /**********************************************************************
569 * Shutdown the program.
571 PRIVATE INT STDCALL
Shutdown (VOID
)
576 /* TODO: try exiting cleanly: close any open resource */
577 /* TODO: notify PSXSS the session is terminating */
578 RtlDeleteCriticalSection (& Session
.Lock
);
579 return PostMortem ();
581 /**********************************************************************
585 *********************************************************************/
586 int main (int argc
, char * argv
[])
591 Startup (argv
[1]); /* Initialization */
592 InputTerminalEmulator (); /* Process user input */