--- /dev/null
+/* $Id: posixw32.c,v 1.1 2002/06/09 08:37:07 ea Exp $
+ *
+ * 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 <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__)
+#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;
+}
+
+/**********************************************************************
+ * 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;
+
+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);
+ OutputDebugStringW(Session.ServerPort.Name.Buffer);
+ Status = NtConnectPort (
+ & Session.ServerPort.Handle,
+ & Session.ServerPort.Name,
+ & Sqos,
+ NULL,
+ NULL,
+ 0,
+ & ConnectData,
+ & ConnectDataLength
+ );
+ if (STATUS_SUCCESS != Status)
+ {
+ vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
+ MyName, __FUNCTION__, Status);
+ return Status;
+ }
+ Session.Identifier = ConnectData.PortIdentifier;
+ return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * InitializeSsIoChannel PRIVATE
+ *
+ * DESCRIPTION
+ * Create our objects in the system name space
+ * (CreateSessionObjects) and then connect to the session port
+ * (CreateControChannel).
+ */
+PRIVATE NTSTATUS STDCALL InitializeSsIoChannel (VOID)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ DWORD Pid = GetCurrentProcessId();
+
+TRACE;
+
+
+ Status = CreateSessionObjects (Pid);
+ if (STATUS_SUCCESS != Status)
+ {
+ vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
+ MyName, __FUNCTION__, Status);
+ return Status;
+ }
+ Status = CreateTerminalToPsxChannel ();
+ if (STATUS_SUCCESS != Status)
+ {
+ vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
+ MyName, __FUNCTION__, Status);
+ return Status;
+ }
+ return STATUS_SUCCESS;
+}
+/**********************************************************************
+ * PsxCreateLeaderProcess/1 PRIVATE
+ *
+ * DESCRIPTION
+ * Create a new PSXSS process.
+ */
+PRIVATE NTSTATUS STDCALL PsxCreateLeaderProcess (char * Command)
+{
+ NTSTATUS Status;
+TRACE;
+
+ if (NULL == Command)
+ {
+ Command = "sh";
+ }
+ /* TODO: request PSXSS to init the process slot */
+ vtprintf ("%s: %s: calling CSRSS 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 */