///|
/// AR startup request assembly for Write, PrmEnd, and ApplicationReady.
///
/// Both blocks use the ControlBlockConnect body layout. PrmEnd is sent as
/// IODControlReq (0x0110); ApplicationReady is sent as IOXControlReq0 (0x0112).
/// The CL-RPC envelope uses RPC opnum 3 for Write and opnum 4 for Control.
///|
pub fn encode_write_blocks(
req : @record.IODWriteReqHeader,
record_data : Bytes,
) -> Bytes {
encode_io_block_with_user_data(
@record.block_type_iod_write_req_header,
@record.encode_iod_write_req_with_data(req, record_data),
record_data.length(),
)
}
///|
pub fn encode_multiple_write_blocks(
outer_req : @record.IODWriteReqHeader,
embedded_write_blocks : Bytes,
) -> Bytes {
encode_io_block_with_user_data(
@record.block_type_iod_write_req_header,
@record.encode_iod_write_req_with_data(outer_req, embedded_write_blocks),
embedded_write_blocks.length(),
)
}
///|
pub fn encode_read_blocks(req : @record.IODReadReqHeader) -> Bytes {
encode_io_block(
@record.block_type_iod_read_req_header,
@record.encode_iod_read_req_header(req),
)
}
///|
pub fn encode_read_request(
blocks : Bytes,
activity_uuid : @rpc.Uuid,
object_uuid? : @rpc.Uuid = @rpc.Uuid::empty(),
sequence_number? : Int = 1,
opnum? : Int = 2,
) -> Bytes raise @frame.FrameError {
let ndr = @rpc.IoRequest::{
..@rpc.IoRequest::default(),
args_length: blocks.length(),
actual_count: blocks.length(),
payload: blocks,
}
let ndr_bytes = @rpc.encode_io_request(ndr)
let hdr = @rpc.DceHeader::{
..@rpc.DceHeader::default(),
packet_type: @rpc.packet_type_request,
object_uuid,
interface_uuid: @rpc.Uuid::from_hex(@rpc.uuid_pnio_device),
activity_uuid,
interface_version: 1,
opnum,
sequence_number,
body_length: ndr_bytes.length(),
}
let output : Array[Byte] = []
append_bytes(output, @rpc.encode_dce_header(hdr))
append_bytes(output, ndr_bytes)
Bytes::from_array(output)
}
///|
pub fn encode_write_request(
blocks : Bytes,
activity_uuid : @rpc.Uuid,
object_uuid? : @rpc.Uuid = @rpc.Uuid::empty(),
sequence_number? : Int = 1,
) -> Bytes raise @frame.FrameError {
let ndr = @rpc.IoRequest::{
..@rpc.IoRequest::default(),
args_length: blocks.length(),
actual_count: blocks.length(),
payload: blocks,
}
let ndr_bytes = @rpc.encode_io_request(ndr)
let hdr = @rpc.DceHeader::{
..@rpc.DceHeader::default(),
packet_type: @rpc.packet_type_request,
object_uuid,
interface_uuid: @rpc.Uuid::from_hex(@rpc.uuid_pnio_device),
activity_uuid,
interface_version: 1,
opnum: 3,
sequence_number,
body_length: ndr_bytes.length(),
}
let output : Array[Byte] = []
append_bytes(output, @rpc.encode_dce_header(hdr))
append_bytes(output, ndr_bytes)
Bytes::from_array(output)
}
///|
fn encode_control_body(
ar_uuid : @rpc.Uuid,
session_key : Int,
control_command : Int,
control_block_properties : Int,
) -> Bytes {
@record.encode_iod_control_req(@record.IODControlReq::{
ar_uuid,
session_key,
control_command,
control_block_properties,
})
}
///|
pub fn encode_prm_end_blocks(ar_uuid : @rpc.Uuid, session_key : Int) -> Bytes {
encode_io_block(
@record.block_type_iod_control_req,
encode_control_body(ar_uuid, session_key, @record.control_command_prmend, 0),
)
}
///|
pub fn encode_application_ready_blocks(
ar_uuid : @rpc.Uuid,
session_key : Int,
) -> Bytes {
encode_io_block(
block_type_iox_control_req,
encode_control_body(
ar_uuid, session_key, @record.control_command_application_ready, 0,
),
)
}
///|
pub fn encode_application_ready_response_blocks(
ar_uuid : @rpc.Uuid,
session_key : Int,
) -> Bytes {
encode_io_block(
block_type_iox_control_res,
encode_control_body(ar_uuid, session_key, @record.control_command_done, 0),
)
}
///|
pub fn encode_release_blocks(ar_uuid : @rpc.Uuid, session_key : Int) -> Bytes {
encode_io_block(
@record.block_type_release_req,
@record.encode_release_block_req({
ar_uuid,
session_key,
control_command: @record.control_command_release,
control_block_properties: 0,
}),
)
}
///|
pub fn encode_control_request(
blocks : Bytes,
activity_uuid : @rpc.Uuid,
object_uuid? : @rpc.Uuid = @rpc.Uuid::empty(),
sequence_number? : Int = 1,
) -> Bytes raise @frame.FrameError {
let ndr = @rpc.IoRequest::{
..@rpc.IoRequest::default(),
args_length: blocks.length(),
actual_count: blocks.length(),
payload: blocks,
}
let ndr_bytes = @rpc.encode_io_request(ndr)
let hdr = @rpc.DceHeader::{
..@rpc.DceHeader::default(),
packet_type: @rpc.packet_type_request,
object_uuid,
interface_uuid: @rpc.Uuid::from_hex(@rpc.uuid_pnio_device),
activity_uuid,
interface_version: 1,
opnum: 4,
sequence_number,
body_length: ndr_bytes.length(),
}
let output : Array[Byte] = []
append_bytes(output, @rpc.encode_dce_header(hdr))
append_bytes(output, ndr_bytes)
Bytes::from_array(output)
}
///|
pub fn encode_release_request(
blocks : Bytes,
activity_uuid : @rpc.Uuid,
object_uuid? : @rpc.Uuid = @rpc.Uuid::empty(),
sequence_number? : Int = 1,
) -> Bytes raise @frame.FrameError {
let ndr = @rpc.IoRequest::{
..@rpc.IoRequest::default(),
args_length: blocks.length(),
actual_count: blocks.length(),
payload: blocks,
}
let ndr_bytes = @rpc.encode_io_request(ndr)
let hdr = @rpc.DceHeader::{
..@rpc.DceHeader::default(),
packet_type: @rpc.packet_type_request,
object_uuid,
interface_uuid: @rpc.Uuid::from_hex(@rpc.uuid_pnio_device),
activity_uuid,
interface_version: 1,
opnum: 1,
sequence_number,
body_length: ndr_bytes.length(),
}
let output : Array[Byte] = []
append_bytes(output, @rpc.encode_dce_header(hdr))
append_bytes(output, ndr_bytes)
Bytes::from_array(output)
}
///|
pub fn encode_control_response(
blocks : Bytes,
request_header : @rpc.DceHeader,
) -> Bytes {
let ndr = @rpc.IoResponse::{
status: 0,
args_length: blocks.length(),
max_count: 0xFE4,
offset: 0,
actual_count: blocks.length(),
payload: blocks,
}
let ndr_bytes = @rpc.encode_io_response(ndr)
let hdr = @rpc.DceHeader::{
..@rpc.DceHeader::default(),
packet_type: @rpc.packet_type_response,
object_uuid: request_header.object_uuid,
interface_uuid: request_header.interface_uuid,
activity_uuid: request_header.activity_uuid,
interface_version: request_header.interface_version,
opnum: request_header.opnum,
sequence_number: request_header.sequence_number,
body_length: ndr_bytes.length(),
}
let output : Array[Byte] = []
append_bytes(output, @rpc.encode_dce_header(hdr))
append_bytes(output, ndr_bytes)
Bytes::from_array(output)
}
///|
fn push_u16_le_local(output : Array[Byte], value : Int) -> Unit {
output.push((value & 0xFF).to_byte())
output.push(((value >> 8) & 0xFF).to_byte())
}
///|
fn push_u32_le_local(output : Array[Byte], value : Int) -> Unit {
output.push((value & 0xFF).to_byte())
output.push(((value >> 8) & 0xFF).to_byte())
output.push(((value >> 16) & 0xFF).to_byte())
output.push(((value >> 24) & 0xFF).to_byte())
}
///|
fn control_request_uses_little_endian(request : Bytes) -> Bool {
request.length() >= 7 && request[4] == b'\x10'
}
///|
fn encode_control_io_response_with_endian(
blocks : Bytes,
little_endian : Bool,
) -> Bytes {
let output : Array[Byte] = []
if little_endian {
push_u32_le_local(output, 0)
push_u32_le_local(output, blocks.length())
push_u32_le_local(output, 0xFE4)
push_u32_le_local(output, 0)
push_u32_le_local(output, blocks.length())
} else {
push_u32_be(output, 0)
push_u32_be(output, blocks.length())
push_u32_be(output, 0xFE4)
push_u32_be(output, 0)
push_u32_be(output, blocks.length())
}
append_bytes(output, blocks)
Bytes::from_array(output)
}
///|
fn encode_control_response_header_from_request(
request : Bytes,
body_length : Int,
little_endian : Bool,
) -> Bytes raise @frame.FrameError {
guard request.length() >= 80 else {
raise @frame.FrameError::InvalidMacLength(request.length())
}
let output : Array[Byte] = []
for i = 0; i < 74; i = i + 1 {
if i == 1 {
output.push(@rpc.packet_type_response)
} else {
output.push(request[i])
}
}
if little_endian {
push_u16_le_local(output, body_length)
} else {
push_u16_be(output, body_length)
}
for i = 76; i < 80; i = i + 1 {
output.push(request[i])
}
Bytes::from_array(output)
}
///|
pub fn encode_control_response_from_request(
blocks : Bytes,
request : Bytes,
) -> Bytes raise @frame.FrameError {
let little_endian = control_request_uses_little_endian(request)
let ndr_bytes = encode_control_io_response_with_endian(blocks, little_endian)
let hdr = encode_control_response_header_from_request(
request,
ndr_bytes.length(),
little_endian,
)
let output : Array[Byte] = []
append_bytes(output, hdr)
append_bytes(output, ndr_bytes)
Bytes::from_array(output)
}