
%%{
#include "zeek/File.h"
#include "zeek/session/Manager.h"
#include "zeek/Reporter.h"
#include "zeek/analyzer/protocol/tcp/TCP.h"
%%}

## Get the originator sequence number of a TCP connection. Sequence numbers
## are absolute (i.e., they reflect the values seen directly in packet headers;
## they are not relative to the beginning of the connection).
##
## cid: The connection ID.
##
## Returns: The highest sequence number sent by a connection's originator, or 0
##          if *cid* does not point to an active TCP connection.
##
## .. zeek:see:: get_resp_seq
function get_orig_seq%(cid: conn_id%): count
	%{
	zeek::Connection* c = zeek::session_mgr->FindConnection(cid);
	if ( ! c )
		return zeek::val_mgr->Count(0);

	if ( c->ConnTransport() != TRANSPORT_TCP )
		return zeek::val_mgr->Count(0);

	zeek::analyzer::Analyzer* tc = c->FindAnalyzer("TCP");
	if ( tc )
		return zeek::val_mgr->Count(static_cast<zeek::packet_analysis::TCP::TCPSessionAdapter*>(tc)->OrigSeq());
	else
		{
		reporter->Error("connection does not have TCP analyzer");
		return zeek::val_mgr->Count(0);
		}
	%}

## Get the responder sequence number of a TCP connection. Sequence numbers
## are absolute (i.e., they reflect the values seen directly in packet headers;
## they are not relative to the beginning of the connection).
##
## cid: The connection ID.
##
## Returns: The highest sequence number sent by a connection's responder, or 0
##          if *cid* does not point to an active TCP connection.
##
## .. zeek:see:: get_orig_seq
function get_resp_seq%(cid: conn_id%): count
	%{
	zeek::Connection* c = zeek::session_mgr->FindConnection(cid);
	if ( ! c )
		return zeek::val_mgr->Count(0);

	if ( c->ConnTransport() != TRANSPORT_TCP )
		return zeek::val_mgr->Count(0);

	zeek::analyzer::Analyzer* tc = c->FindAnalyzer("TCP");
	if ( tc )
		return zeek::val_mgr->Count(static_cast<zeek::packet_analysis::TCP::TCPSessionAdapter*>(tc)->RespSeq());
	else
		{
		reporter->Error("connection does not have TCP analyzer");
		return zeek::val_mgr->Count(0);
		}
	%}

## Associates a file handle with a connection for writing TCP byte stream
## contents.
##
## cid: The connection ID.
##
## direction: Controls what sides of the connection to record. The argument can
##            take one of the four values:
##
##            - ``CONTENTS_NONE``: Stop recording the connection's content.
##            - ``CONTENTS_ORIG``: Record the data sent by the connection
##              originator (often the client).
##            - ``CONTENTS_RESP``: Record the data sent by the connection
##              responder (often the server).
##            - ``CONTENTS_BOTH``: Record the data sent in both directions.
##              Results in the two directions being intermixed in the file,
##              in the order the data was seen by Zeek.
##
## f: The file handle of the file to write the contents to.
##
## Returns: Returns false if *cid* does not point to an active connection, and
##          true otherwise.
##
## .. note::
##
##     The data recorded to the file reflects the byte stream, not the
##     contents of individual packets. Reordering and duplicates are
##     removed. If any data is missing, the recording stops at the
##     missing data; this can happen, e.g., due to an
##     :zeek:id:`content_gap` event.
##
## .. zeek:see:: get_contents_file set_record_packets contents_file_write_failure
function set_contents_file%(cid: conn_id, direction: count, f: file%): bool
	%{
	zeek::Connection* c = zeek::session_mgr->FindConnection(cid);
	if ( ! c )
		return zeek::val_mgr->False();

	c->GetSessionAdapter()->SetContentsFile(direction, {zeek::NewRef{}, f});
	return zeek::val_mgr->True();
	%}

## Returns the file handle of the contents file of a connection.
##
## cid: The connection ID.
##
## direction: Controls what sides of the connection to record. See
##            :zeek:id:`set_contents_file` for possible values.
##
## Returns: The :zeek:type:`file` handle for the contents file of the
##          connection identified by *cid*. If the connection exists
##          but there is no contents file for *direction*, then the function
##          generates an error and returns a file handle to ``stderr``.
##
## .. zeek:see:: set_contents_file set_record_packets contents_file_write_failure
function get_contents_file%(cid: conn_id, direction: count%): file
	%{
	zeek::Connection* c = zeek::session_mgr->FindConnection(cid);

	if ( c )
		{
		auto cf = c->GetSessionAdapter()->GetContentsFile(direction);

		if ( cf )
			return zeek::make_intrusive<zeek::FileVal>(std::move(cf));
		}

	// Return some sort of error value.
	if ( ! c )
		zeek::emit_builtin_error("unknown connection id in get_contents_file()", cid);
	else
		zeek::emit_builtin_error("no contents file for given direction");

	return zeek::make_intrusive<zeek::FileVal>(zeek::make_intrusive<zeek::File>(stderr, "-", "w"));
	%}
