Blob Blame History Raw
/*********************************************************/
/*  toksvc: a framework-native token broker service      */
/*  Copyright (C) 2020  Z. Gilboa                        */
/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
/*********************************************************/

#include <psxtypes/psxtypes.h>
#include <ntapi/ntapi.h>

#include <toksvc/toksvc.h>
#include "toksvc_daemon_impl.h"
#include "toksvc_driver_impl.h"
#include "toksvc_log_impl.h"

#define  TOKS_VTBL_ELEMENTS   TOKS_DAEMON_OPCODE_CAP - TOKS_DAEMON_OPCODE_BASE

#define  TOKS_OPCODE_IDX(IDX) TOKS_DAEMON_ ## IDX - TOKS_DAEMON_OPCODE_BASE
#define  TOKS_HANDLER(IDX,fn) [TOKS_OPCODE_IDX(IDX)] = fn


static toks_daemon_routine * toks_daemon_vtbl[TOKS_VTBL_ELEMENTS] = {
	TOKS_HANDLER(CONNECT,       toks_daemon_connect),
	TOKS_HANDLER(TTYSIGNAL,     toks_daemon_signal),
	TOKS_HANDLER(ACQUIRE,       toks_daemon_acquire),
	TOKS_HANDLER(RELEASE,       toks_daemon_release),
	TOKS_HANDLER(CANCEL,        toks_daemon_cancel),
	TOKS_HANDLER(ABORT,         toks_daemon_abort),
};

static toks_daemon_routine * toks_client_vtbl[TOKS_VTBL_ELEMENTS] = {
	TOKS_HANDLER(CONNECT,       toks_daemon_connect),
	TOKS_HANDLER(TTYSIGNAL,     toks_daemon_signal),
};

int32_t __stdcall toks_daemon_loop(void * ctx)
{
	struct toks_daemon_ctx *	dctx;
	toks_daemon_routine **		svcvtbl;
	nt_rtdata *			rtdata;

	nt_tty_port_msg *		request;
	nt_tty_port_msg *		reply;

	intptr_t			port_id;
	int32_t				opcode;

	if (ntapi->tt_get_runtime_data(&rtdata,0))
		return NT_STATUS_INTERNAL_ERROR;

	dctx = (struct toks_daemon_ctx *)ctx;

	svcvtbl = (dctx->driver_ctx->cctx->drvflags & TOKS_DRIVER_MODE_SERVER)
		? toks_daemon_vtbl
		: toks_client_vtbl;

	/* init */
	request = &dctx->request;
	reply   = &dctx->reply;

	ntapi->tt_aligned_block_memset(
		request,0,sizeof(*request));

	/* get first message */
	ntapi->zw_reply_wait_receive_port(
		dctx->hport_daemon,
		&port_id,
		0,(nt_port_message *)request);

	/* message loop */
	do {
		if (svcvtbl == toks_daemon_vtbl)
			toks_log_lpc_request(
				dctx,request);

		switch (request->header.msg_type) {
			case NT_LPC_REQUEST:
			case NT_LPC_DATAGRAM:
				opcode = request->ttyinfo.opcode;
				break;

			case NT_LPC_CONNECTION_REQUEST:
				opcode = TOKS_DAEMON_CONNECT;
				break;

			default:
				opcode = -1;
				break;
		}

		/* dispatch */
		dctx->opcode = opcode;

		ntapi->tt_aligned_block_memcpy(
			(uintptr_t *)reply,
			(uintptr_t *)request,
			sizeof(*reply));

		reply->header.msg_type = NT_LPC_REPLY;

		if ((opcode >= TOKS_DAEMON_OPCODE_BASE) && (opcode < TOKS_DAEMON_OPCODE_CAP)) {
			reply->ttyinfo.exarg = (void *)request->header.client_id.process_id;
			opcode -= TOKS_DAEMON_OPCODE_BASE;

			if (svcvtbl[opcode])
				reply->ttyinfo.status = svcvtbl[opcode](dctx);
			else
				reply->ttyinfo.status = NT_STATUS_NOT_IMPLEMENTED;
		} else {
			reply->ttyinfo.exarg    = NT_INVALID_HANDLE_VALUE;
			reply->ttyinfo.status   = NT_STATUS_LPC_INVALID_CONNECTION_USAGE;
		}

		ntapi->tt_aligned_block_memset(
			request,0,sizeof(*request));

		if (!reply->ttyinfo.exarg)
			ntapi->zw_reply_wait_receive_port(
				dctx->hport_daemon,
				&port_id,
				0,&request->header);
		else if (reply->header.client_id.process_id == rtdata->cid_self.process_id)
			ntapi->zw_reply_wait_receive_port(
				dctx->hport_daemon,
				&port_id,
				&reply->header,
				&request->header);
		else {
			ntapi->zw_reply_port(
				dctx->hport_daemon,
				&reply->header);

			ntapi->zw_reply_wait_receive_port(
				dctx->hport_daemon,
				&port_id,
				0,&request->header);
		}
	} while (request->header.msg_id);

	return NT_STATUS_INTERNAL_ERROR;
}