1 /* $Id: csrterm.c,v 1.1 2002/03/17 22:15:39 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
;
63 /*** PRIVATE FUNCTIONS ***********************************************/
64 VOID STDCALL
Debug_Print (LPCSTR Format
, ...)
67 va_list ArgumentPointer
;
69 va_start(ArgumentPointer
, Format
);
70 vsprintf(Buffer
, Format
, ArgumentPointer
);
71 va_end(ArgumentPointer
);
72 OutputDebugStringA (Buffer
);
74 /**********************************************************************
78 * Notify to PSXSS that input data is ready by sending a
79 * software interrupt on the \POSIX+\SessionPort port.
81 PRIVATE DWORD STDCALL
OutPort (PCHAR Buffer
, ULONG Size
)
84 PSX_TERMINAL_READ TerminalRead
;
89 TerminalRead
.Header
.MessageType
= LPC_NEW_MESSAGE
;
90 TerminalRead
.PsxHeader
.Context
= PSX_CONNECTION_TYPE_TERMINAL
;
91 TerminalRead
.PsxHeader
.Procedure
= PSX_TERMINAL_INTERRUPT
;
93 TerminalRead
.Size
= Size
;
94 RtlCopyMemory (TerminalRead
.Buffer
, Buffer
, Size
);
96 Status
= NtRequestWaitReplyPort (
97 Session
.ServerPort
.Handle
,
102 if (!NT_SUCCESS(Status
))
104 vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
105 MyName
, __FUNCTION__
, Status
);
111 /**********************************************************************
112 * ProcessConnectionRequest/1 PRIVATE
115 * Initialize our data for managing the control connection
116 * initiated by the PSXSS.EXE process.
118 PRIVATE NTSTATUS STDCALL
ProcessConnectionRequest (PPSX_MAX_MESSAGE Request
)
121 Session
.SsLinkIsActive
= TRUE
;
122 return STATUS_SUCCESS
;
124 /**********************************************************************
125 * ProcessRequest/1 PRIVATE
130 PRIVATE NTSTATUS STDCALL
ProcessRequest (PPSX_MAX_MESSAGE Request
)
134 vtprintf("TEST VT-100\n");
136 return STATUS_SUCCESS
;
138 /**********************************************************************
139 * PsxSessionPortListener/1 PRIVATE
142 * Manage messages from the PSXSS, that is LPC messages we get
143 * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
146 * This function is the thread 's entry point created in
147 * CreateSessionObiects().
149 PRIVATE DWORD STDCALL
PsxSessionPortListener (LPVOID Arg
)
152 LPC_TYPE RequestType
;
153 PSX_MAX_MESSAGE Request
;
154 PPSX_MAX_MESSAGE Reply
= NULL
;
155 BOOL NullReply
= FALSE
;
164 Status
= NtReplyWaitReceivePort (
167 (PLPC_MESSAGE
) Reply
,
168 (PLPC_MESSAGE
) & Request
170 if (!NT_SUCCESS(Status
))
174 RequestType
= PORT_MESSAGE_TYPE(Request
);
177 case LPC_CONNECTION_REQUEST
:
178 ProcessConnectionRequest (& Request
);
181 case LPC_CLIENT_DIED
:
182 case LPC_PORT_CLOSED
:
183 case LPC_DEBUG_EVENT
:
184 case LPC_ERROR_EVENT
:
189 if (RequestType
!= LPC_REQUEST
)
196 Reply
->PsxHeader
.Status
= ProcessRequest (& Request
);
199 if ((STATUS_INVALID_HANDLE
== Status
) ||
200 (STATUS_OBJECT_TYPE_MISMATCH
== Status
))
205 Session
.SsLinkIsActive
= FALSE
;
206 TerminateThread (GetCurrentThread(), Status
);
208 /**********************************************************************
209 * CreateSessionObiects/1 PRIVATE
212 * Create the session objects which are mananged by our side:
214 * \POSIX+\Sessions\P<pid>
215 * \POSIX+\Sessions\D<pid>
217 PRIVATE NTSTATUS STDCALL
CreateSessionObjects (DWORD Pid
)
221 OBJECT_ATTRIBUTES Oa
;
226 /* Critical section */
227 Status
= RtlInitializeCriticalSection (& Session
.Lock
);
228 if (!NT_SUCCESS(Status
))
231 "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
232 MyName
, __FUNCTION__
, Status
);
235 /* Port and port management thread */
237 Session
.Port
.NameBuffer
,
238 PSX_NS_SESSION_PORT_TEMPLATE
,
239 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
240 PSX_NS_SESSION_DIRECTORY_NAME
,
243 RtlInitUnicodeString (& Session
.Port
.Name
, Session
.Port
.NameBuffer
);
244 InitializeObjectAttributes (& Oa
, & Session
.Port
.Name
, 0, NULL
, NULL
);
245 Status
= NtCreatePort (& Session
.Port
.Handle
, & Oa
, 0, 0, 0x10000);
246 if (!NT_SUCCESS(Status
))
248 RtlDeleteCriticalSection (& Session
.Lock
);
249 vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
250 MyName
, __FUNCTION__
, Status
);
253 Session
.Port
.Thread
.Handle
=
257 PsxSessionPortListener
,
260 & Session
.Port
.Thread
.Id
262 if ((HANDLE
) NULL
== Session
.Port
.Thread
.Handle
)
264 Status
= (NTSTATUS
) GetLastError();
265 NtClose (Session
.Port
.Handle
);
266 RtlDeleteCriticalSection (& Session
.Lock
);
267 vtprintf ("%s: %s: CreateThread failed with %d\n",
268 MyName
, __FUNCTION__
, Status
);
273 Session
.Section
.NameBuffer
,
274 PSX_NS_SESSION_DATA_TEMPLATE
,
275 PSX_NS_SUBSYSTEM_DIRECTORY_NAME
,
276 PSX_NS_SESSION_DIRECTORY_NAME
,
279 RtlInitUnicodeString (& Session
.Section
.Name
, Session
.Section
.NameBuffer
);
280 InitializeObjectAttributes (& Oa
, & Session
.Section
.Name
, 0, 0, 0);
281 Status
= NtCreateSection (
282 & Session
.Section
.Handle
,
283 0, /* DesiredAccess */
285 NULL
, /* SectionSize OPTIONAL */
286 PAGE_READWRITE
, /* Protect 4 */
287 SEC_COMMIT
, /* Attributes */
288 0 /* FileHandle: 0=pagefile.sys */
290 if (!NT_SUCCESS(Status
))
292 NtClose (Session
.Port
.Handle
);
293 NtTerminateThread (Session
.Port
.Thread
.Handle
, Status
);
294 RtlDeleteCriticalSection (& Session
.Lock
);
295 vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
296 MyName
, __FUNCTION__
, Status
);
299 Session
.Section
.BaseAddress
= NULL
;
300 Session
.Section
.ViewSize
= 0;
301 Status
= NtMapViewOfSection (
302 Session
.Section
.Handle
,
304 & Session
.Section
.BaseAddress
,
307 0, /* SectionOffset */
308 & Session
.Section
.ViewSize
,
310 0, /* AllocationType */
311 PAGE_READWRITE
/* Protect 4 */
313 if (!NT_SUCCESS(Status
))
315 NtClose (Session
.Port
.Handle
);
316 NtTerminateThread (Session
.Port
.Thread
.Handle
, Status
);
317 NtClose (Session
.Section
.Handle
);
318 RtlDeleteCriticalSection (& Session
.Lock
);
319 vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
320 MyName
, __FUNCTION__
, Status
);
326 /**********************************************************************
327 * CreateTerminalToPsxChannel/0 PRIVATE
332 PRIVATE NTSTATUS STDCALL
CreateTerminalToPsxChannel (VOID
)
334 PSX_CONNECT_PORT_DATA ConnectData
;
335 ULONG ConnectDataLength
= sizeof ConnectData
;
336 SECURITY_QUALITY_OF_SERVICE Sqos
;
343 * Initialize the connection data object before
346 ConnectData
.ConnectionType
= PSX_CONNECTION_TYPE_TERMINAL
;
347 ConnectData
.Version
= PSX_LPC_PROTOCOL_VERSION
;
349 * Try connecting to \POSIX+\SessionPort.
351 Status
= NtConnectPort (
352 & Session
.ServerPort
.Handle
,
353 & Session
.ServerPort
.Name
,
361 if (STATUS_SUCCESS
!= Status
)
363 vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
364 MyName
, __FUNCTION__
, Status
);
367 Session
.Identifier
= ConnectData
.PortIdentifier
;
368 return STATUS_SUCCESS
;
371 /**********************************************************************
372 * InitializeSsIoChannel PRIVATE
375 * Create our objects in the system name space
376 * (CreateSessionObjects) and then connect to the session port
377 * (CreateControChannel).
379 PRIVATE NTSTATUS STDCALL
InitializeSsIoChannel (VOID
)
381 NTSTATUS Status
= STATUS_SUCCESS
;
382 DWORD Pid
= GetCurrentProcessId();
387 Status
= CreateSessionObjects (Pid
);
388 if (STATUS_SUCCESS
!= Status
)
390 vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
391 MyName
, __FUNCTION__
, Status
);
394 Status
= CreateTerminalToPsxChannel ();
395 if (STATUS_SUCCESS
!= Status
)
397 vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
398 MyName
, __FUNCTION__
, Status
);
401 return STATUS_SUCCESS
;
403 /**********************************************************************
404 * PsxCreateLeaderProcess/1 PRIVATE
407 * Create a new PSXSS process.
409 PRIVATE NTSTATUS STDCALL
PsxCreateLeaderProcess (char * Command
)
418 /* TODO: request PSXSS to init the process slot */
419 return STATUS_NOT_IMPLEMENTED
;
421 /**********************************************************************
422 * PrintInformationProcess/0
426 PRIVATE VOID STDCALL
PrintInformationProcess (VOID
)
432 vtprintf (" UniqueProcess %08x\n", Session
.Client
.UniqueProcess
);
433 vtprintf (" UniqueThread %08x\n", Session
.Client
.UniqueThread
);
435 /**********************************************************************
440 PRIVATE INT STDCALL
PostMortem (VOID
)
447 PrintInformationProcess ();
448 if (TRUE
== GetExitCodeProcess (Session
.Client
.UniqueProcess
, & ExitCode
))
450 vtprintf (" ExitCode %d\n", ExitCode
);
454 /**********************************************************************
455 * InputTerminalEmulator/0
458 * Process user terminal input.
461 * This code is run in the main thread.
463 PRIVATE BOOL STDCALL
InputTerminalEmulator (VOID
)
465 HANDLE StandardInput
;
466 INPUT_RECORD InputRecord
[INPUT_QUEUE_SIZE
];
467 DWORD NumberOfEventsRead
= 0;
473 StandardInput
= GetStdHandle (STD_INPUT_HANDLE
);
474 if (INVALID_HANDLE_VALUE
== StandardInput
)
478 while ((TRUE
== Session
.SsLinkIsActive
) &&
482 (sizeof InputRecord
) / sizeof (INPUT_RECORD
),
486 for ( CurrentEvent
= 0;
487 (CurrentEvent
< NumberOfEventsRead
);
491 switch (InputRecord
[CurrentEvent
].EventType
)
494 OutPort (& InputRecord
[CurrentEvent
].Event
.KeyEvent
.uChar
.AsciiChar
, 1);
497 /* TODO: send a sequence of move cursor codes */
498 /* InputRecord [CurrentEvent].Event.MouseEvent; */
500 case WINDOW_BUFFER_SIZE_EVENT
:
501 /* TODO: send a SIGWINCH signal to the leader process. */
502 /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
504 /* Next events should be ignored. */
506 vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
508 vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName
, __FUNCTION__
);
512 NumberOfEventsRead
= 0;
516 /**********************************************************************
520 * Initialize the program.
522 PRIVATE VOID STDCALL
Startup (LPSTR Command
)
530 /* PSX process info */
531 Session
.Client
.UniqueProcess
= INVALID_HANDLE_VALUE
;
532 Session
.Client
.UniqueThread
= INVALID_HANDLE_VALUE
;
533 /* Initialize the VT-100 emulator */
535 /* Connect to PSXSS */
536 Status
= InitializeSsIoChannel ();
537 if (!NT_SUCCESS(Status
))
539 vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
543 /* Create the leading process for this session */
544 Status
= PsxCreateLeaderProcess (Command
);
545 if (!NT_SUCCESS(Status
))
547 vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
552 /**********************************************************************
556 * Shutdown the program.
558 PRIVATE INT STDCALL
Shutdown (VOID
)
563 /* TODO: try exiting cleanly: close any open resource */
564 /* TODO: notify PSXSS the session is terminating */
565 RtlDeleteCriticalSection (& Session
.Lock
);
566 return PostMortem ();
568 /**********************************************************************
572 *********************************************************************/
573 int main (int argc
, char * argv
[])
578 Startup (argv
[1]); /* Initialization */
579 InputTerminalEmulator (); /* Process user input */