/*++ Copyright (c) 1989 Microsoft Corporation Module Name: apireqst.c Abstract: This module implements the main loop servicing API RPC's. Author: Mark Lucovsky (markl) 05-Apr-1989 Revision History: --*/ #include "psxsrv.h" #define NOEXTAPI #include "wdbgexts.h" #include "ntdbg.h" // // API Dispatch Table // PPSX_API_ROUTINE PsxServerApiDispatch[PsxMaxApiNumber] = { PsxFork, PsxExec, PsxWaitPid, PsxExit, PsxKill, PsxSigAction, PsxSigProcMask, PsxSigPending, PsxSigSuspend, PsxAlarm, PsxGetIds, PsxSetUid, PsxSetGid, PsxGetGroups, PsxGetLogin, PsxCUserId, PsxSetSid, PsxSetPGroupId, PsxUname, PsxTime, PsxGetProcessTimes, PsxTtyName, PsxIsatty, PsxSysconf, PsxOpen, PsxUmask, PsxLink, PsxMkDir, PsxMkFifo, PsxRmDir, PsxRename, PsxStat, PsxFStat, PsxAccess, PsxChmod, PsxChown, PsxUtime, PsxPathConf, PsxFPathConf, PsxPipe, PsxDup, PsxDup2, PsxClose, PsxRead, PsxWrite, PsxFcntl, PsxLseek, PsxTcGetAttr, PsxTcSetAttr, PsxTcSendBreak, PsxTcDrain, PsxTcFlush, PsxTcFlow, PsxTcGetPGrp, PsxTcSetPGrp, PsxGetPwUid, PsxGetPwNam, PsxGetGrGid, PsxGetGrNam, PsxUnlink, PsxReadDir, PsxFtruncate, PsxNull #ifdef PSX_SOCKET , PsxSocket, PsxAccept, PsxBind, PsxConnect, PsxGetPeerName, PsxGetSockName, PsxGetSockOpt, PsxListen, PsxRecv, PsxSend, PsxSendTo, PsxSetSockOpt, PsxShutdown #endif // PSX_SOCKET }; #if DBG PSZ PsxServerApiName[PsxMaxApiNumber] = { "PsxFork", "PsxExec", "PsxWaitPid", "PsxExit", "PsxKill", "PsxSigAction", "PsxSigProcMask", "PsxSigPending", "PsxSigSuspend", "PsxAlarm", "PsxGetIds", "PsxSetUid", "PsxSetGid", "PsxGetGroups", "PsxGetLogin", "PsxCUserId", "PsxSetSid", "PsxSetPGroupId", "PsxUname", "PsxTime", "PsxGetProcessTimes", "PsxTtyName", "PsxIsatty", "PsxSysconf", "PsxOpen", "PsxUmask", "PsxLink", "PsxMkDir", "PsxMkFifo", "PsxRmDir", "PsxRename", "PsxStat", "PsxFStat", "PsxAccess", "PsxChmod", "PsxChown", "PsxUtime", "PsxPathConf", "PsxFPathConf", "PsxPipe", "PsxDup", "PsxDup2", "PsxClose", "PsxRead", "PsxWrite", "PsxFcntl", "PsxLseek", "PsxTcGetAttr", "PsxTcSetAttr", "PsxTcSendBreak", "PsxTcDrain", "PsxTcFlush", "PsxTcFlow", "PsxTcGetPGrp", "PsxTcSetPGrp", "PsxGetPwUid", "PsxGetPwNam", "PsxGetGrGid", "PsxGetGrNam", "PsxUnlink", "PsxReadDir", "PsxFtruncate", "PsxNull" #ifdef PSX_SOCKET , "PsxSocket", "PsxAccept", "PsxBind", "PsxConnect", "PsxGetPeerName", "PsxGetSockName", "PsxGetSockOpt", "PsxListen", "PsxRecv", "PsxRecvFrom", "PsxSend", "PsxSendTo", "PsxSetSockOpt", "PsxShutdown" #endif // PSX_SOCKET }; VOID dumpmsg( IN PPSX_API_MSG ReplyMsg); #endif //DBG #if _MSC_FULL_VER >= 13008827 #pragma warning(push) #pragma warning(disable:4715) // Not all control paths return (due to infinite loop) #endif NTSTATUS PsxApiRequestThread( IN PVOID Parameter ) { NTSTATUS Status; PPSX_PROCESS Process; PSX_API_MSG ReceiveMsg; PPSX_API_MSG ReplyMsg; USHORT MessageType; PVOID PortContext; // pointer to process structure KERNEL_USER_TIMES ThreadTime; ULONG PosixUTime1, PosixUTime2, Remainder, LengthNeeded; ULONG PosixSTime1, PosixSTime2; BOOLEAN Reply; UNREFERENCED_PARAMETER(Parameter); ReplyMsg = NULL; while (TRUE) { Status = NtQueryInformationThread(NtCurrentThread(), ThreadTimes, (PVOID)&ThreadTime, sizeof(ThreadTime), &LengthNeeded); ASSERT(NT_SUCCESS(Status)); PosixUTime1 = RtlExtendedLargeIntegerDivide( ThreadTime.UserTime, 10000, &Remainder).LowPart; PosixSTime1 = RtlExtendedLargeIntegerDivide( ThreadTime.KernelTime, 10000, &Remainder).LowPart; Status = NtReplyWaitReceivePort(PsxApiPort, &PortContext, (PPORT_MESSAGE)ReplyMsg, (PPORT_MESSAGE)&ReceiveMsg); if (Status != 0) { if (NT_SUCCESS(Status)) { continue; } if (STATUS_INVALID_CID == Status) { ReplyMsg = NULL; continue; } KdPrint(("PSXSS: ReceivePort failed: 0x%x\n", Status)); ReplyMsg = NULL; continue; } MessageType = ReceiveMsg.h.u2.s2.Type; if (MessageType == LPC_CONNECTION_REQUEST) { PsxApiHandleConnectionRequest( &ReceiveMsg ); ReplyMsg = NULL; continue; } Process = PsxLocateProcessByClientId(&ReceiveMsg.h.ClientId); if (NULL == Process) { if (LPC_CLIENT_DIED == MessageType || LPC_PORT_CLOSED == MessageType || LPC_ERROR_EVENT == MessageType ) { ReplyMsg = NULL; continue; } if (LPC_EXCEPTION == MessageType) { ReplyMsg = &ReceiveMsg; ReplyMsg->ReturnValue = DBG_CONTINUE; continue; } KdPrint(("PSXSS: msg %d from unknown client: %d, %d\n", ReceiveMsg.ApiNumber, ReceiveMsg.h.ClientId.UniqueProcess, ReceiveMsg.h.ClientId.UniqueThread)); ReceiveMsg.Error = ESRCH; ReplyMsg = NULL; continue; } // // For each POSIX API message // - Validate the API Number // - Dispatch the call // - Optionally Reply // if (LPC_CLIENT_DIED == MessageType) { // XXX.mjb: do we need to increment InPsx here? // XXX.mjb: this exit status should be meaningful. Exit(Process, (ULONG)-1); ReplyMsg = NULL; // no one to reply to. continue; } if (LPC_EXCEPTION == MessageType) { PDBGKM_APIMSG m; KdPrint(("PSXSS: Pid 0x%x has taken an exception\n", Process->Pid)); Exit(Process, (ULONG)-1); // // XXX.mjb: would be nice to print an error // message. // m = (PDBGKM_APIMSG)&ReceiveMsg; m->ReturnedStatus = DBG_CONTINUE; ReplyMsg = &ReceiveMsg; ReplyMsg->ReturnValue = DBG_CONTINUE; continue; } if (LPC_ERROR_EVENT == MessageType) { PHARDERROR_MSG m; m = (PHARDERROR_MSG)&ReceiveMsg; m->Response = (ULONG)ResponseNotHandled; Exit(Process, (ULONG)-1); ReplyMsg = NULL; // no one to reply to. continue; } if (LPC_REQUEST != MessageType) { KdPrint(("PSXSS: Unknown message type 0x%x\n", MessageType)); ReplyMsg = NULL; // no one to reply to. continue; } if (Process != PortContext) { // // This message was sent by a diffferent process than // the one that now has this ClientId. We discard // the message. // ReplyMsg = NULL; continue; } AcquireProcessLock(Process); Process->InPsx++; Process->IntControlBlock = (PINTCB) NULL; ReleaseProcessLock(Process); if (ReceiveMsg.ApiNumber >= PsxMaxApiNumber) { KdPrint(("PSXSS: %lx is invalid ApiNumber\n", ReceiveMsg.ApiNumber)); ReceiveMsg.Error = ENOSYS; ReplyMsg = &ReceiveMsg; continue; } ReplyMsg = &ReceiveMsg; ReceiveMsg.Error = 0L; ReceiveMsg.ReturnValue = 0L; Reply = (*PsxServerApiDispatch[ReceiveMsg.ApiNumber]) (Process, &ReceiveMsg); if (!(Process->Flags & P_FREE)) { // // the process has exited, don't try to fiddle // with times. // if (!Reply) { ReplyMsg = NULL; continue; } } // // the user and system time for the posix server are added to // the process *system* time (the system is executing in user // and kernel mode on behalf of the process). // Status = NtQueryInformationThread(NtCurrentThread(), ThreadTimes, (PVOID)&ThreadTime, sizeof(ThreadTime), &LengthNeeded); ASSERT(NT_SUCCESS(Status)); PosixUTime2 = RtlExtendedLargeIntegerDivide( ThreadTime.UserTime, 10000, &Remainder).LowPart; PosixSTime2 = RtlExtendedLargeIntegerDivide( ThreadTime.KernelTime, 10000, &Remainder).LowPart; Process->ProcessTimes.tms_stime += (PosixUTime2 - PosixUTime1); Process->ProcessTimes.tms_stime += (PosixSTime2 - PosixSTime1); if (!Reply) { ReplyMsg = NULL; continue; } if (PendingSignalHandledInside(Process, &ReceiveMsg, NULL)) { ReplyMsg = NULL; // Don't reply continue; } AcquireProcessLock(Process); --Process->InPsx; ReleaseProcessLock(Process); } NtTerminateThread(NtCurrentThread(), Status); return Status; } #if _MSC_FULL_VER >= 13008827 #pragma warning(pop) #endif VOID ApiReply( IN PPSX_PROCESS Process, IN PPSX_API_MSG ReplyMsg, IN sigset_t *RestoreBlockSigset OPTIONAL ) /*++ Routine Description: This routine issues a reply for the specified message on behalf of the specified process. Arguments: Process - Supplies the address of the process on whose behalf the reply is being made. ReplyMsg - Supplies the value of the reply message. RestoreBlockSigset - Supplies an optional blocked signal mask that should be restored after the signal completes Return Value: None. --*/ { NTSTATUS Status; HANDLE ReplyPort; if (!PendingSignalHandledInside(Process, ReplyMsg, RestoreBlockSigset)) { #if DBG IF_PSX_DEBUG( MSGDUMP ) { KdPrint(("--- REPLY TebServicer %lx Message... Pid %lx\n", NtCurrentTeb(), Process->Pid)); dumpmsg(ReplyMsg); } #endif //DBG ReplyPort = Process->ClientPort; Status = NtReplyPort(ReplyPort, (PPORT_MESSAGE)ReplyMsg); if (!NT_SUCCESS(Status)) { // // We can get here, if, for instance, somebody shoots a // process out from under us. // KdPrint(("PSXSS: ReplyPort: 0x%x\n", Status)); } --Process->InPsx; return; } } #if DBG VOID dumpmsg( IN PPSX_API_MSG Msg ) { PULONG l; ULONG p1,p2,p3; KdPrint(("Length %lx\n",Msg->h.u1.Length)); KdPrint(("MapInfo and Type %lx\n",Msg->h.u2.ZeroInit)); KdPrint(("ClientId %lx.%lx\n", Msg->h.ClientId.UniqueProcess, Msg->h.ClientId.UniqueThread)); KdPrint(("ApiName %lx %s\n",Msg->ApiNumber,PsxServerApiName[Msg->ApiNumber])); KdPrint(("Error %lx\n",Msg->Error)); KdPrint(("ReturnValue %lx\n",Msg->ReturnValue)); l = (PULONG) (&Msg->u.Fork); p1 = *l++; p2 = *l++; p3 = *l++; KdPrint(("Args[0..2] \t%lx\n\t\t%lx\n\t\t%lx\n",p1,p2,p3)); } #endif //DBG