//..............................................................................
//
// Mailslot Monitor
//

import "io_Monitor.jnc"
import "io_FileIdMgr.jnc"
import "std_String.jnc"
import "log.jnc"

//..............................................................................

class MailslotMonitor: io.Monitor
{
protected:
	MailslotMonSession* m_session;

public:
	construct (MailslotMonSession* session);

protected:
	override processNotification (io.DeviceMonitorNotifyHdr const* notifyHdr);
	override processError (std.Error const* error);

	setFileId (
		uint64_t timestamp,
		uint64_t loFileId,
		uint32_t processId
		);

	processFsctlNotification (
		int ntStatus,
		uint64_t timestamp,
		uint64_t loFileId,
		uint32_t processId,
		uint_t code,
		const void* inData,
		size_t inDataSize,
		const void* outData,
		size_t outDataSize
		);
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

MailslotMonitor.construct (MailslotMonSession* session)
{
	basetype.construct (session.m_pluginHost);
	m_session = session;
}

MailslotMonitor.setFileId (
	uint64_t timestamp,
	uint64_t loFileId,
	uint32_t processId
	)
{
	uint32_t lastFileId = m_fileIdMgr.m_lastHiFileId;
	uint32_t fileId = m_fileIdMgr.getHiFileId (loFileId);

	if (fileId != lastFileId)
	{
		uint32_t ids [] = { fileId, processId }
		m_pluginHost.m_log.m_writer.write (timestamp, MailslotMonLogRecordCode.FileIdChanged, ids, sizeof (ids));
	}
}

MailslotMonitor.processNotification (io.DeviceMonitorNotifyHdr const* notifyHdr)
{
	switch (notifyHdr.m_code)
	{
	case io.win.DeviceMonitorNotifyCode.Create:
		io.win.DeviceMonitorCreateNotifyParams const* params = (io.win.DeviceMonitorCreateNotifyParams const*) (notifyHdr + 1);

		uint_t recordCode;
		std.Buffer logParams;

		if (notifyHdr.m_ntStatus == 0)
		{
			recordCode = MailslotMonLogRecordCode.ClientFileOpened;
			uint32_t fileId = m_fileIdMgr.getHiFileId (params.m_fileId);
			logParams.append (&fileId, sizeof (fileId));
			logParams.append (&notifyHdr.m_processId, sizeof (notifyHdr.m_processId));
		}
		else
		{
			recordCode = MailslotMonLogRecordCode.ClientFileOpenError;

			std.Error error;
			error.m_size = sizeof (error);
			error.m_guid = std.g_ntStatusGuid;
			error.m_code = notifyHdr.m_ntStatus;

			logParams.append (&notifyHdr.m_processId, sizeof (notifyHdr.m_processId));
			logParams.append (&error, error.m_size);
		}

		std.StringBuilder name;
		name.copy ((utf16_t const*) (params + 1));
		logParams.append (name.m_sz, name.m_length + 1);

		m_pluginHost.m_log.m_writer.write (
			notifyHdr.m_timestamp,
			recordCode,
			logParams.m_p,
			logParams.m_size
			);

		break;

	case io.win.DeviceMonitorNotifyCode.CreateMailslot:
		io.win.DeviceMonitorCreateNamedPipeNotifyParams const* params = (io.win.DeviceMonitorCreateNamedPipeNotifyParams const*) (notifyHdr + 1);

		uint_t recordCode;
		std.Buffer logParams;

		if (notifyHdr.m_ntStatus == 0)
		{
			recordCode = MailslotMonLogRecordCode.ServerFileOpened;
			uint32_t fileId = m_fileIdMgr.getHiFileId (params.m_fileId);
			logParams.append (&fileId, sizeof (fileId));
			logParams.append (&notifyHdr.m_processId, sizeof (notifyHdr.m_processId));
		}
		else
		{
			recordCode = MailslotMonLogRecordCode.ServerFileOpenError;

			std.Error error;
			error.m_size = sizeof (error);
			error.m_guid = std.g_ntStatusGuid;
			error.m_code = notifyHdr.m_ntStatus;

			logParams.append (&notifyHdr.m_processId, sizeof (notifyHdr.m_processId));
			logParams.append (&error, error.m_size);
		}

		std.StringBuilder name;
		name.copy ((utf16_t const*) (params + 1));
		logParams.append (name.m_sz, name.m_length + 1);

		m_pluginHost.m_log.m_writer.write (
			notifyHdr.m_timestamp,
			recordCode,
			logParams.m_p,
			logParams.m_size
			);

		break;

	case io.win.DeviceMonitorNotifyCode.Close:
		io.win.DeviceMonitorCloseNotifyParams const* params = (io.win.DeviceMonitorCloseNotifyParams const*) (notifyHdr + 1);
		setFileId (notifyHdr.m_timestamp, params.m_fileId, notifyHdr.m_processId);
		m_fileIdMgr.removeLowFileId (params.m_fileId);
		m_pluginHost.m_log.m_writer.write (notifyHdr.m_timestamp, MailslotMonLogRecordCode.FileClosed);
		break;

	case io.win.DeviceMonitorNotifyCode.Read:
	case io.win.DeviceMonitorNotifyCode.FastIoRead:
		io.win.DeviceMonitorReadWriteNotifyParams const* params = (io.win.DeviceMonitorReadWriteNotifyParams const*) (notifyHdr + 1);
		if (!params.m_dataSize)
			break;

		setFileId (notifyHdr.m_timestamp, params.m_fileId, notifyHdr.m_processId);

		m_pluginHost.m_log.m_writer.write (
			notifyHdr.m_timestamp,
			log.StdRecordCode.Rx,
			params + 1,
			params.m_dataSize
			);
		break;
	}
}

MailslotMonitor.processError (std.Error const* error)
{
	m_pluginHost.m_log.m_writer.write (log.StdRecordCode.Error, error, error.m_size);
	m_session.close ();
}

//..............................................................................
