+++ /dev/null
-/* $Id$
- *
- * PROJECT : ReactOS Operating System / POSIX+ Environment Subsystem
- * DESCRIPTION: POSIXW32 - A DEC VT-100 terminal emulator for the PSX subsystem
- * DESCRIPTION: that runs in the Win32 subsystem.
- * COPYRIGHT : Copyright (c) 2001-2002 Emanuele Aliberti
- * LICENSE : GNU GPL v2
- * DATE : 2001-05-05
- * AUTHOR : Emanuele Aliberti <ea@iol.it>
- * NOTE : This IS a Win32 program, but will fail if the PSX subsystem
- * NOTE : is not installed. The PSX subsystem consists of two more
- * NOTE : files: PSXSS.EXE, PSXDLL.DLL.
- * WARNING : If you use this program under a real NT descendant, be
- * WARNING : sure to have disabled the PSX subsystem.
- * --------------------------------------------------------------------
- *
- * This software is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING. If not, write
- * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
- * MA 02139, USA.
- *
- * --------------------------------------------------------------------
- * 2002-03-16 EA Today it actually compiled.
- * 2002-06-08 EA Renamed (old name was CSRTERM)
- */
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define NTOS_MODE_USER
-#include <ntos.h>
-#include <sm/helper.h>
-#include <psx/lpcproto.h>
-
-#include "vt100.h"
-#include "posixw32.h"
-
-/*** OPTIONS *********************************************************/
-
-#define PRIVATE static
-
-#define INPUT_QUEUE_SIZE 32
-
-#ifdef NDEBUG
-#define TRACE
-#else
-//#define TRACE OutputDebugString(__FUNCTION__)
-#define TRACE vtprintf("%s\n",__FUNCTION__)
-#endif
-
-/*** GLOBALS *********************************************************/
-
-PRIVATE LPCSTR MyName = "POSIXW32";
-PRIVATE CSRTERM_SESSION Session =
-{
- 0, //Identifier
- { //ServerPort
- {0,0,NULL},
- L"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME"\\"PSX_NS_SESSIONAPI_PORT_NAME,
- INVALID_HANDLE_VALUE
- }
-};
-
-/*** PRIVATE FUNCTIONS ***********************************************/
-VOID STDCALL Debug_Print (LPCSTR Format, ...)
-{
- CHAR Buffer [512];
- va_list ArgumentPointer;
-
- va_start(ArgumentPointer, Format);
- vsprintf(Buffer, Format, ArgumentPointer);
- va_end(ArgumentPointer);
- OutputDebugStringA (Buffer);
-}
-/**********************************************************************
- * OutPort/2 PRIVATE
- *
- * DESCRIPTION
- * Notify to PSXSS that input data is ready by sending a
- * software interrupt on the \POSIX+\SessionPort port.
- */
-PRIVATE DWORD STDCALL OutPort (PCHAR Buffer, ULONG Size)
-{
- NTSTATUS Status;
- PSX_TERMINAL_READ TerminalRead;
-TRACE;
- if (Size > 0)
- {
- /* LPC */
- TerminalRead.Header.MessageType = LPC_NEW_MESSAGE;
- TerminalRead.PsxHeader.Context = PSX_CONNECTION_TYPE_TERMINAL;
- TerminalRead.PsxHeader.Procedure = PSX_TERMINAL_INTERRUPT;
- /* Terminal I/O */
- TerminalRead.Size = Size;
-#if 0
- RtlCopyMemory (TerminalRead.Buffer, Buffer, Size);
- Status = NtRequestWaitReplyPort (
- Session.ServerPort.Handle,
- & TerminalRead
- /* FIXME */
- );
-#endif
- if (!NT_SUCCESS(Status))
- {
- vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return 0;
- }
- }
- return Size;
-}
-/**********************************************************************
- * ProcessConnectionRequest/1 PRIVATE
- *
- * DESCRIPTION
- * Initialize our data for managing the control connection
- * initiated by the PSXSS.EXE process.
- */
-PRIVATE NTSTATUS STDCALL ProcessConnectionRequest (PLPC_MAX_MESSAGE Request)
-{
- PPSX_CONNECT_PORT_DATA ConnectData = (PPSX_CONNECT_PORT_DATA) & Request->Data;
-
-TRACE;
- if (PSX_CONNECTION_TYPE_SERVER != ConnectData->ConnectionType)
- {
-
- return STATUS_UNSUCCESSFUL;
- }
- if (PSX_LPC_PROTOCOL_VERSION != ConnectData->Version)
- {
-
- return STATUS_UNSUCCESSFUL;
- }
- Session.SsLinkIsActive = TRUE;
- return STATUS_SUCCESS;
-}
-/**********************************************************************
- * ProcessRequest/1 PRIVATE
- *
- * DESCRIPTION
- *
- */
-PRIVATE NTSTATUS STDCALL ProcessRequest (PPSX_MAX_MESSAGE Request)
-{
-TRACE;
- /* TODO */
- vtprintf("TEST VT-100\n");
-
- return STATUS_SUCCESS;
-}
-/**********************************************************************
- * PsxSessionPortListener/1 PRIVATE
- *
- * DESCRIPTION
- * Manage messages from the PSXSS, that is LPC messages we get
- * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
- *
- * NOTE
- * This function is the thread 's entry point created in
- * CreateSessionObiects().
- */
-PRIVATE DWORD STDCALL PsxSessionPortListener (LPVOID Arg)
-{
- NTSTATUS Status;
- LPC_TYPE RequestType;
- PSX_MAX_MESSAGE Request;
- PPSX_MAX_MESSAGE Reply = NULL;
- BOOL NullReply = FALSE;
-
-TRACE;
-
- while (TRUE)
- {
- Reply = NULL;
- NullReply = FALSE;
- while (!NullReply)
- {
- Status = NtReplyWaitReceivePort (
- Session.Port.Handle,
- 0,
- (PLPC_MESSAGE) Reply,
- (PLPC_MESSAGE) & Request
- );
- if (!NT_SUCCESS(Status))
- {
- break;
- }
- RequestType = PORT_MESSAGE_TYPE(Request);
- switch (RequestType)
- {
- case LPC_CONNECTION_REQUEST:
- ProcessConnectionRequest ((PLPC_MAX_MESSAGE) & Request);
- NullReply = TRUE;
- continue;
- case LPC_CLIENT_DIED:
- case LPC_PORT_CLOSED:
- case LPC_DEBUG_EVENT:
- case LPC_ERROR_EVENT:
- case LPC_EXCEPTION:
- NullReply = TRUE;
- continue;
- default:
- if (RequestType != LPC_REQUEST)
- {
- NullReply = TRUE;
- continue;
- }
- }
- Reply = & Request;
- Reply->PsxHeader.Status = ProcessRequest (& Request);
- NullReply = FALSE;
- }
- if ((STATUS_INVALID_HANDLE == Status) ||
- (STATUS_OBJECT_TYPE_MISMATCH == Status))
- {
- break;
- }
- }
- Session.SsLinkIsActive = FALSE;
- TerminateThread (GetCurrentThread(), Status);
-}
-/**********************************************************************
- * CreateSessionObiects/1 PRIVATE
- *
- * DESCRIPTION
- * Create the session objects which are mananged by our side:
- *
- * \POSIX+\Sessions\P<pid>
- * \POSIX+\Sessions\D<pid>
- */
-PRIVATE NTSTATUS STDCALL CreateSessionObjects (DWORD Pid)
-{
- NTSTATUS Status;
- ULONG Id = 0;
- OBJECT_ATTRIBUTES Oa;
- LARGE_INTEGER SectionSize = {PSX_TERMINAL_SECTION_SIZE,0};
-
-TRACE;
-
-
- /* Critical section */
- Status = RtlInitializeCriticalSection (& Session.Lock);
- if (!NT_SUCCESS(Status))
- {
- vtprintf (
- "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- /* Port and port management thread */
- swprintf (
- Session.Port.NameBuffer,
- PSX_NS_SESSION_PORT_TEMPLATE,
- PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
- PSX_NS_SESSION_DIRECTORY_NAME,
- Pid
- );
- OutputDebugStringW(Session.Port.NameBuffer);
- RtlInitUnicodeString (& Session.Port.Name, Session.Port.NameBuffer);
- InitializeObjectAttributes (& Oa, & Session.Port.Name, 0, NULL, NULL);
- Status = NtCreatePort (& Session.Port.Handle, & Oa, 0, 0, 0x10000);
- if (!NT_SUCCESS(Status))
- {
- RtlDeleteCriticalSection (& Session.Lock);
- vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- Session.Port.Thread.Handle =
- CreateThread (
- NULL,
- 0,
- PsxSessionPortListener,
- 0,
- CREATE_SUSPENDED,
- & Session.Port.Thread.Id
- );
- if ((HANDLE) NULL == Session.Port.Thread.Handle)
- {
- Status = (NTSTATUS) GetLastError();
- NtClose (Session.Port.Handle);
- RtlDeleteCriticalSection (& Session.Lock);
- vtprintf ("%s: %s: CreateThread failed with %d\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- /* Section */
- swprintf (
- Session.Section.NameBuffer,
- PSX_NS_SESSION_DATA_TEMPLATE,
- PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
- PSX_NS_SESSION_DIRECTORY_NAME,
- Pid
- );
- OutputDebugStringW(Session.Section.NameBuffer);
- RtlInitUnicodeString (& Session.Section.Name, Session.Section.NameBuffer);
- InitializeObjectAttributes (& Oa, & Session.Section.Name, 0, 0, 0);
- Status = NtCreateSection (
- & Session.Section.Handle,
- SECTION_ALL_ACCESS, /* DesiredAccess */
- & Oa,
- & SectionSize,
- PAGE_READWRITE, /* Protect 4 */
- SEC_COMMIT, /* Attributes */
- 0 /* FileHandle: 0=pagefile.sys */
- );
- if (!NT_SUCCESS(Status))
- {
- NtClose (Session.Port.Handle);
- NtTerminateThread (Session.Port.Thread.Handle, Status);
- RtlDeleteCriticalSection (& Session.Lock);
- vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- Session.Section.BaseAddress = NULL;
- Session.Section.ViewSize = SectionSize.u.LowPart;
- Status = NtMapViewOfSection (
- Session.Section.Handle,
- NtCurrentProcess(),
- & Session.Section.BaseAddress,
- 0, /* ZeroBits */
- 0, /* Commitsize */
- 0, /* SectionOffset */
- & Session.Section.ViewSize,
- ViewUnmap,
- 0, /* AllocationType */
- PAGE_READWRITE /* Protect 4 */
- );
- if (!NT_SUCCESS(Status))
- {
- NtClose (Session.Port.Handle);
- NtTerminateThread (Session.Port.Thread.Handle, Status);
- NtClose (Session.Section.Handle);
- RtlDeleteCriticalSection (& Session.Lock);
- vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- return Status;
-}
-/**********************************************************************
- * RunPsxSs/0
- *
- * DESCRIPTION
- * This function is called only when initializing the session
- * with PSXSS fails. We assume that it failed because the
- * subsystem, being optional, is not running, therefore we
- * ask the SM to start it up.
- */
-PRIVATE NTSTATUS RunPsxSs(VOID)
-{
- NTSTATUS Status;
- HANDLE SmApiPort;
- UNICODE_STRING Program;
-
- RtlInitUnicodeString (& Program, L"POSIX");
- Status = SmConnectApiPort (NULL, 0, 0, & SmApiPort);
- if(!NT_SUCCESS(Status))
- {
- return Status;
- }
- Status = SmExecuteProgram (SmApiPort, & Program);
- NtClose (SmApiPort);
- return Status;
-}
-/**********************************************************************
- * CreateTerminalToPsxChannel/0 PRIVATE
- *
- * DESCRIPTION
- *
- */
-PRIVATE NTSTATUS STDCALL CreateTerminalToPsxChannel (VOID)
-{
- PSX_CONNECT_PORT_DATA ConnectData;
- ULONG ConnectDataLength = sizeof ConnectData;
- SECURITY_QUALITY_OF_SERVICE Sqos;
- NTSTATUS Status;
- LONG Count = 2;
-
-TRACE;
-
-
- /*
- * Initialize the connection data object before
- * calling PSXSS.
- */
- ConnectData.ConnectionType = PSX_CONNECTION_TYPE_TERMINAL;
- ConnectData.Version = PSX_LPC_PROTOCOL_VERSION;
- /*
- * Try connecting to \POSIX+\SessionPort.
- */
- RtlInitUnicodeString (& Session.ServerPort.Name, Session.ServerPort.NameBuffer);
- while (Count--)
- {
- OutputDebugStringW(Session.ServerPort.Name.Buffer);
- Status = NtConnectPort (
- & Session.ServerPort.Handle,
- & Session.ServerPort.Name,
- & Sqos,
- NULL,
- NULL,
- 0,
- & ConnectData,
- & ConnectDataLength
- );
- if (STATUS_SUCCESS != Status)
- {
- if(Count)
- {
- vtprintf("%s: %s: asking SM to start PSXSS...\n",MyName,__FUNCTION__);
- RunPsxSs();
- continue;
- }
- vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- break;
- }
- Session.Identifier = ConnectData.PortIdentifier;
- return STATUS_SUCCESS;
-}
-
-/**********************************************************************
- * InitializeSsIoChannel PRIVATE
- *
- * DESCRIPTION
- * Connect to the session port (CreateControChannel) of the PSX
- * subsystem. If that succeeds, create our objects in the system
- * name space (CreateSessionObjects).
- */
-PRIVATE NTSTATUS STDCALL InitializeSsIoChannel (VOID)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- DWORD Pid = GetCurrentProcessId();
-
-TRACE;
-
-
- Status = CreateTerminalToPsxChannel ();
- if (STATUS_SUCCESS != Status)
- {
- vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- Status = CreateSessionObjects (Pid);
- if (STATUS_SUCCESS != Status)
- {
- vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
- MyName, __FUNCTION__, Status);
- return Status;
- }
- return STATUS_SUCCESS;
-}
-/**********************************************************************
- * PsxCreateLeaderProcess/1 PRIVATE
- *
- * DESCRIPTION
- * Create a new PSXSS process. We are running under Win32 server
- * and can not run directly a PSX image: we make SM run it for us.
- *
- */
-PRIVATE NTSTATUS STDCALL PsxCreateLeaderProcess (char * Command)
-{
- NTSTATUS Status;
-TRACE;
-
- if (NULL == Command)
- {
- Command = "sh";
- }
- /* TODO: request SM to create the process: LPC:SmExecPgm() */
- vtprintf ("%s: %s: calling SMSS not implemented!", MyName, __FUNCTION__);
- return STATUS_SUCCESS;
-}
-/**********************************************************************
- * PrintInformationProcess/0
- *
- * DESCRIPTION
- */
-PRIVATE VOID STDCALL PrintInformationProcess (VOID)
-{
-
-TRACE;
-
- vtputs ("Leader:");
- vtprintf (" UniqueProcess %08x\n", Session.Client.UniqueProcess);
- vtprintf (" UniqueThread %08x\n", Session.Client.UniqueThread);
-}
-/**********************************************************************
- * PostMortem/0
- *
- * DESCRIPTION
- */
-PRIVATE INT STDCALL PostMortem (VOID)
-{
- DWORD ExitCode;
-
-TRACE;
-
-
- PrintInformationProcess ();
- if (TRUE == GetExitCodeProcess (Session.Client.UniqueProcess, & ExitCode))
- {
- vtprintf (" ExitCode %d\n", ExitCode);
- }
- return 0;
-}
-/**********************************************************************
- * InputTerminalEmulator/0
- *
- * DESCRIPTION
- * Process user terminal input.
- *
- * NOTE
- * This code is run in the main thread.
- */
-PRIVATE BOOL STDCALL InputTerminalEmulator (VOID)
-{
- HANDLE StandardInput;
- INPUT_RECORD InputRecord [INPUT_QUEUE_SIZE];
- DWORD NumberOfEventsRead = 0;
- INT CurrentEvent;
-
-
-TRACE;
-
- StandardInput = GetStdHandle (STD_INPUT_HANDLE);
- if (INVALID_HANDLE_VALUE == StandardInput)
- {
- return FALSE;
- }
- while ((TRUE == Session.SsLinkIsActive) &&
- ReadConsoleInput (
- StandardInput,
- InputRecord,
- (sizeof InputRecord) / sizeof (INPUT_RECORD),
- & NumberOfEventsRead
- ))
- {
- for ( CurrentEvent = 0;
- (CurrentEvent < NumberOfEventsRead);
- CurrentEvent ++
- )
- {
- switch (InputRecord [CurrentEvent].EventType)
- {
- case KEY_EVENT:
- OutPort (& InputRecord [CurrentEvent].Event.KeyEvent.uChar.AsciiChar, 1);
- break;
- case MOUSE_EVENT:
- /* TODO: send a sequence of move cursor codes */
- /* InputRecord [CurrentEvent].Event.MouseEvent; */
- break;
- case WINDOW_BUFFER_SIZE_EVENT:
- /* TODO: send a SIGWINCH signal to the leader process. */
- /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
- break;
- /* Next events should be ignored. */
- case MENU_EVENT:
- vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName, __FUNCTION__);
- case FOCUS_EVENT:
- vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName, __FUNCTION__);
- break;
- }
- }
- NumberOfEventsRead = 0;
- }
- return TRUE;
-}
-/**********************************************************************
- * Startup/1
- *
- * DESCRIPTION
- * Initialize the program.
- */
-PRIVATE VOID STDCALL Startup (LPSTR Command)
-{
- NTSTATUS Status;
- DWORD ThreadId;
-
-
-TRACE;
-
- /* PSX process info */
- Session.Client.UniqueProcess = INVALID_HANDLE_VALUE;
- Session.Client.UniqueThread = INVALID_HANDLE_VALUE;
- /* Initialize the VT-100 emulator */
- vtInitVT100 ();
- /* Connect to PSXSS */
- Status = InitializeSsIoChannel ();
- if (!NT_SUCCESS(Status))
- {
- vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
- MyName, Status);
- exit (EXIT_FAILURE);
- }
- /* Create the leading process for this session */
- Status = PsxCreateLeaderProcess (Command);
- if (!NT_SUCCESS(Status))
- {
- vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
- MyName, Status);
- exit (EXIT_FAILURE);
- }
-}
-/**********************************************************************
- * Shutdown/0 PRIVATE
- *
- * DESCRIPTION
- * Shutdown the program.
- */
-PRIVATE INT STDCALL Shutdown (VOID)
-{
-
-TRACE;
-
- /* TODO: try exiting cleanly: close any open resource */
- /* TODO: notify PSXSS the session is terminating */
- RtlDeleteCriticalSection (& Session.Lock);
- return PostMortem ();
-}
-/**********************************************************************
- *
- * ENTRY POINT PUBLIC
- *
- *********************************************************************/
-int main (int argc, char * argv [])
-{
-
-TRACE;
-
- Startup (argv[1]); /* Initialization */
- InputTerminalEmulator (); /* Process user input */
- return Shutdown ();
-}
-/* EOF */