//..............................................................................
//
// TCP flow monitor address log filter
//

import "log_Filter.jnc"
import "TcpFlowLogRecordCode.jnc"

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

class TcpFlowLogFilter: log.Filter {
protected:
	io.SocketAddress m_filterAddress;
	io.SocketAddress m_lastVisibleClientAddress;
	io.SocketAddress m_lastVisibleServerAddress;
	bool m_isVisible;

public:
	// suspend log engine before calling setFilter

	bool errorcode setFilter(string_t filter);

protected:
	override void reset();

	override bool filter(
		uint64_t timestamp,
		uint64_t recordCode,
		void const* p,
		size_t size
	);
}

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

bool errorcode TcpFlowLogFilter.setFilter(string_t filter) {
	if (filter)
		return m_filterAddress.parse(filter);

	m_filterAddress = null;
	return true;
}

void TcpFlowLogFilter.reset() {
	m_isVisible = false;
	m_lastVisibleClientAddress = null;
	m_lastVisibleServerAddress = null;
}

bool TcpFlowLogFilter.filter(
	uint64_t timestamp,
	uint64_t recordCode,
	void const* p,
	size_t size
) {
	if (!m_filterAddress.m_family) // empty address means, filtering is off
		return true;

	switch (recordCode) {
	case SocketLogRecordCode.ConnectingFrom:
	case TcpFlowLogRecordCode.ConnectionPickedUp:
	case TcpFlowLogRecordCode.ConnectionChanged:
		io.SocketAddress const* serverAddress = (io.SocketAddress const*)p;
		io.SocketAddress const* clientAddress = serverAddress + 1;

		m_isVisible =
			serverAddress.isMatch(m_filterAddress) ||
			clientAddress.isMatch(m_filterAddress);

		if (!m_isVisible)
			return false;

		if (recordCode == TcpFlowLogRecordCode.ConnectionChanged &&
			m_lastVisibleClientAddress.isEqual(clientAddress) &&
			m_lastVisibleServerAddress.isEqual(serverAddress))
			return false; // don't show unnecessary connection-changed messages

		m_lastVisibleClientAddress = *clientAddress;
		m_lastVisibleServerAddress = *serverAddress;
		return true;

	case TcpFlowLogRecordCode.Disconnected:
	case TcpFlowLogRecordCode.Reset:
		io.SocketAddress const* remoteAddress = (io.SocketAddress const*)p;
		io.SocketAddress const* localAddress = remoteAddress + 1;

		bool result =
			remoteAddress.isMatch(m_filterAddress) ||
			localAddress.isMatch(m_filterAddress);

		if (result) {
			m_lastVisibleClientAddress = null;
			m_lastVisibleServerAddress = null;
		}

		m_isVisible = false;
		return result;

	default:
		return m_isVisible;
	}
}

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