flatbuffer base
This commit is contained in:
28
AVRrc.toml
Normal file
28
AVRrc.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[dev]
|
||||
libpath = "/home/nikto_b/Documents/baum/hmmmm/devices/avr_generic/AVRrc_build/device.so"
|
||||
|
||||
|
||||
[mem]
|
||||
|
||||
[mem.ps]
|
||||
start = 0
|
||||
len = 1024
|
||||
wordLen = 2
|
||||
executable = true
|
||||
|
||||
[mem.reg_gp]
|
||||
start = 2048
|
||||
len = 32
|
||||
wordLen = 1
|
||||
|
||||
[mem.reg_io]
|
||||
start = 2080
|
||||
len = 255
|
||||
wordLen = 1
|
||||
|
||||
[mem.ds]
|
||||
start = 2335
|
||||
len = 65535
|
||||
wordLen = 1
|
||||
|
||||
|
||||
61
Makefile
61
Makefile
@@ -4,13 +4,27 @@ SRC_DIR=src
|
||||
INC_DIR=inc
|
||||
CC=gcc
|
||||
OBJDUMP=objdump
|
||||
LIBS=deps/tomlc99/libtoml.a deps/ptQueue/out/ptQueue.a deps/wsServer/libws.a
|
||||
LIBS=deps/tomlc99/libtoml.a deps/ptQueue/out/ptQueue.a deps/wsServer/libws.a deps/flatcc/lib/libflatccrt.a
|
||||
LIBS_HEADERS=deps/ $(OPENSSL_INCLUDE)
|
||||
# flatcc runtime and generated reader headers use const-dropping casts;
|
||||
# include both as system headers so -Wcast-qual doesn't apply to them
|
||||
SYSTEM_INCLUDES=-isystem deps/flatcc/include/ -isystem $(PROTO_INC_DIR)/
|
||||
STATIC_LIBS=crypto
|
||||
STANDART=c23
|
||||
OPTIMIZE=-O3
|
||||
TARGET=main
|
||||
|
||||
FLATCC = deps/flatcc/bin/flatcc
|
||||
FLATC = deps/flatbuffers/build/flatc
|
||||
FBS_DIR = flatbuffers
|
||||
PROTO_INC_DIR = inc/flatbuf_autogen
|
||||
PROTO_SRC_DIR = src/flatbuf_autogen
|
||||
PROTO_STAMP = $(BUILD_DIR)/.proto_stamp
|
||||
PY_PROTO_DIR = hmmmm_scripts/flatbuf_autogen
|
||||
PY_PROTO_STAMP = $(BUILD_DIR)/.py_proto_stamp
|
||||
|
||||
FBS_SOURCES := $(shell find $(FBS_DIR) -name '*.fbs')
|
||||
|
||||
|
||||
DEFINES=#-DOPCODE_WORDSIZE=2 -DMEM_CELL_WORDS=1 -DPC_WORDSIZE=2 -DGP_REG_CELL_WORDS=1 -DIO_REG_CELL_WORDS=1
|
||||
|
||||
@@ -24,9 +38,10 @@ DISABLE_FLAGS=-Wno-unused-variable -Wno-unused-parameter -Wno-write-strings -Wno
|
||||
PEDANTIC_FLAGS=-pedantic -pedantic-errors $(DISABLE_FLAGS) -Wall -Wcast-align -Wcast-qual -Wconversion -Wduplicated-branches -Wduplicated-cond -Werror -Wextra -Wfloat-equal -Wlogical-op -Wpedantic -Wredundant-decls -Wsign-conversion
|
||||
ANALYZER_FLAGS=-fanalyzer -fdiagnostics-show-option -fdiagnostics-color=always
|
||||
LSECTIONS=-ffunction-sections -fdata-sections -Wl,--gc-sections
|
||||
CFLAGS=$(C_DEFS) -g $(C_INCLUDES) $(DEFINES) $(OPTIMIZE) --std=$(STANDART) $(PEDANTIC_FLAGS) $(ANALYZER_FLAGS) -MMD -MP
|
||||
CFLAGS=$(C_DEFS) -g $(C_INCLUDES) $(SYSTEM_INCLUDES) $(DEFINES) $(OPTIMIZE) --std=$(STANDART) $(PEDANTIC_FLAGS) $(ANALYZER_FLAGS) -MMD -MP # -fno-omit-frame-pointer -fno-inline -fno-lto
|
||||
STATICLIBS_FLAGS=$(addprefix -l,$(STATIC_LIBS))
|
||||
LFLAGS=$(OPTIMIZE) -g $(PEDANTIC_FLAGS) $(DEFINES) $(STATICLIBS_FLAGS) -flto -fuse-linker-plugin $(LSECTIONS) -lm
|
||||
# LFLAGS=$(OPTIMIZE) -g $(PEDANTIC_FLAGS) $(DEFINES) $(STATICLIBS_FLAGS) $(LSECTIONS) -lm -fno-omit-frame-pointer -fno-inline -fno-lto
|
||||
LFLAGS=$(OPTIMIZE) -g $(PEDANTIC_FLAGS) $(DEFINES) $(STATICLIBS_FLAGS) -flto -fuse-linker-plugin $(LSECTIONS) -lm -fno-omit-frame-pointer -fno-inline
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +56,7 @@ vpath %.c $(sort $(dir $(C_SOURCES)))
|
||||
|
||||
all: build
|
||||
|
||||
build: date deps Dir target compile_commands
|
||||
build: date deps Dir proto target compile_commands
|
||||
|
||||
rebuild: clean | build
|
||||
|
||||
@@ -54,7 +69,7 @@ $(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
|
||||
@$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
|
||||
@$(OBJDUMP) -d -S $@ > $(BUILD_DIR)/$(notdir $(<:.c=.casm))
|
||||
|
||||
target: date $(BUILD_DIR)/$(TARGET).elf
|
||||
target: date proto $(BUILD_DIR)/$(TARGET).elf
|
||||
|
||||
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS)
|
||||
@echo -e '\033[1;32mELF\t'$(OBJECTS)'\n\t\t\t->\t'$@'\033[0m'
|
||||
@@ -63,6 +78,16 @@ $(BUILD_DIR)/$(TARGET).elf: $(OBJECTS)
|
||||
deps:
|
||||
@make -C deps all
|
||||
|
||||
proto: $(PROTO_STAMP)
|
||||
|
||||
$(PROTO_STAMP): $(FBS_SOURCES) | ProtoDir BuildDir
|
||||
@echo -e '\033[1;32mFLATCC\tGenerating FlatBuffers headers\033[0m'
|
||||
@for fbs in $(FBS_SOURCES); do \
|
||||
echo -e '\033[1;32mFLATCC\t'$$fbs'\033[0m'; \
|
||||
$(FLATCC) -a -I $(FBS_DIR) -o $(PROTO_INC_DIR) $$fbs || exit 1; \
|
||||
done
|
||||
@touch $@
|
||||
|
||||
|
||||
|
||||
BuildDir:
|
||||
@@ -75,16 +100,34 @@ SrcDir:
|
||||
IncDir:
|
||||
@mkdir -p $(INC_DIR)
|
||||
|
||||
Dir: BuildDir SrcDir IncDir
|
||||
ProtoDir:
|
||||
@mkdir -p $(PROTO_INC_DIR)
|
||||
@mkdir -p $(PROTO_SRC_DIR)
|
||||
|
||||
Dir: BuildDir SrcDir IncDir ProtoDir
|
||||
|
||||
|
||||
.PHONY: clean deps
|
||||
python-proto: $(PY_PROTO_STAMP)
|
||||
|
||||
$(PY_PROTO_STAMP): $(FBS_SOURCES) $(FLATC) | $(PY_PROTO_DIR) BuildDir
|
||||
@echo -e '\033[1;32mFLATC\tGenerating Python FlatBuffers bindings\033[0m'
|
||||
@$(FLATC) --python --gen-all -I $(FBS_DIR) -o $(PY_PROTO_DIR) $(FBS_DIR)/proto.fbs
|
||||
@touch $@
|
||||
|
||||
$(PY_PROTO_DIR):
|
||||
@mkdir -p $@
|
||||
|
||||
$(FLATC):
|
||||
@$(MAKE) -C deps flatbuffers/build/flatc
|
||||
|
||||
|
||||
.PHONY: clean deps proto python-proto
|
||||
clean:
|
||||
@rm -rf $(BUILD_DIR)/*
|
||||
@rm -rf $(BUILD_DIR)/* $(BUILD_DIR)/.* $(PROTO_INC_DIR)/* $(PROTO_SRC_DIR)/*
|
||||
# @rm -f compile_commands.json
|
||||
@echo -e '\033[0;31mCleaned\033[0m'
|
||||
|
||||
.NOTPARALLEL: date target rebuild deps
|
||||
.NOTPARALLEL: date target rebuild deps proto
|
||||
date:
|
||||
@echo -e '\033[1;32m'"Starting build at " | tr -d '\n'
|
||||
@date
|
||||
|
||||
1
deps/.gitignore
vendored
1
deps/.gitignore
vendored
@@ -3,3 +3,4 @@ ptQueue
|
||||
tomlc99
|
||||
wsServer
|
||||
flatcc
|
||||
flatbuffers
|
||||
|
||||
25
deps/Makefile
vendored
25
deps/Makefile
vendored
@@ -1,4 +1,4 @@
|
||||
all: tomlc99/libtoml.a ptQueue/out/ptQueue.a wsServer/libws.a flatcc
|
||||
all: tomlc99/libtoml.a ptQueue/out/ptQueue.a wsServer/libws.a flatcc/bin/flatcc flatbuffers/build/flatc
|
||||
|
||||
tomlc99:
|
||||
@git clone https://github.com/cktan/tomlc99
|
||||
@@ -7,13 +7,13 @@ tomlc99/libtoml.a: tomlc99
|
||||
@make -C tomlc99 libtoml.a
|
||||
|
||||
|
||||
flatcc_src:
|
||||
flatcc:
|
||||
@git clone https://github.com/dvidelabs/flatcc
|
||||
|
||||
flatcc: flatcc/bin/flatcc
|
||||
flatcc_src: flatcc/bin/flatcc
|
||||
flatcc/lib/libflatccrt.a: flatcc/bin/flatcc
|
||||
|
||||
flatcc/bin/flatcc: flatcc_src
|
||||
flatcc/bin/flatcc: flatcc
|
||||
@flatcc/scripts/initbuild.sh make
|
||||
@flatcc/scripts/build.sh
|
||||
|
||||
@@ -30,8 +30,23 @@ wsServer:
|
||||
wsServer/libws.a: wsServer
|
||||
@make -C wsServer
|
||||
|
||||
flatbuffers:
|
||||
@git clone --depth=1 https://github.com/google/flatbuffers
|
||||
|
||||
flatbuffers/build/flatc: flatbuffers
|
||||
@cmake -B flatbuffers/build -S flatbuffers \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DFLATBUFFERS_BUILD_TESTS=OFF \
|
||||
-DFLATBUFFERS_BUILD_FLATLIB=OFF \
|
||||
-DFLATBUFFERS_BUILD_FLATHASH=OFF \
|
||||
-DFLATBUFFERS_BUILD_GRPCTEST=OFF \
|
||||
-DFLATBUFFERS_BUILD_SHAREDLIB=OFF \
|
||||
-DFLATBUFFERS_INSTALL=OFF
|
||||
@cmake --build flatbuffers/build --target flatc -j$(shell nproc)
|
||||
|
||||
|
||||
clean:
|
||||
@rm -rf wsServer ptQueue tomlc99 flatcc
|
||||
@rm -rf wsServer ptQueue tomlc99 flatcc flatbuffers
|
||||
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
1
deps/flatbuffers
vendored
Submodule
1
deps/flatbuffers
vendored
Submodule
Submodule deps/flatbuffers added at 4e582b0c1d
0
flamegraph.svg
Normal file
0
flamegraph.svg
Normal file
11
flatbuffers/auth/auth.fbs
Normal file
11
flatbuffers/auth/auth.fbs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace hmmmm.auth;
|
||||
|
||||
// Client → Server: SHA-512(access_token + str(unix_timestamp / 30))
|
||||
table AuthRequest {
|
||||
hash: [ubyte]; // 64 bytes
|
||||
}
|
||||
|
||||
// Server → Client: seat assigned, current emulation state echoed
|
||||
table AuthResponse {
|
||||
seat_id: uint64;
|
||||
}
|
||||
16
flatbuffers/config/clock.fbs
Normal file
16
flatbuffers/config/clock.fbs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace hmmmm.config;
|
||||
|
||||
// Global emulator clock constraints.
|
||||
table ClockConfig {
|
||||
// Maximum emulated ticks per real second.
|
||||
// 0 = unlimited (run as fast as possible).
|
||||
limiter: uint64;
|
||||
}
|
||||
|
||||
// Clock source and frequency relationship for one device.
|
||||
// Devices form a clock tree: each node derives its frequency from its src.
|
||||
table DeviceClockConfig {
|
||||
src: string; // id of the parent device; empty = root clock
|
||||
divider: uint32 = 1;
|
||||
multiplier: uint32 = 1;
|
||||
}
|
||||
20
flatbuffers/config/config.fbs
Normal file
20
flatbuffers/config/config.fbs
Normal file
@@ -0,0 +1,20 @@
|
||||
include "device.fbs";
|
||||
include "mem_config.fbs";
|
||||
include "clock.fbs";
|
||||
|
||||
namespace hmmmm.config;
|
||||
|
||||
// Top-level emulator / system configuration.
|
||||
// Equivalent to glob.toml — describes a full composite device tree.
|
||||
//
|
||||
// File use: flatcc -a config/config.fbs → binary system config files
|
||||
// WS use: embed in ConfigCtrlMessage when config-change protocol is ready
|
||||
table SystemConfig {
|
||||
devices: [DeviceEntry]; // ordered list; id must be unique
|
||||
clock: ClockConfig;
|
||||
projections: [Projection];
|
||||
intercepts: [Intercept];
|
||||
mem_setup: [MemSetup];
|
||||
}
|
||||
|
||||
root_type SystemConfig;
|
||||
39
flatbuffers/config/device.fbs
Normal file
39
flatbuffers/config/device.fbs
Normal file
@@ -0,0 +1,39 @@
|
||||
include "mem_config.fbs";
|
||||
include "clock.fbs";
|
||||
|
||||
namespace hmmmm.config;
|
||||
|
||||
// Configuration for a single base device (leaf node in the device tree).
|
||||
// Equivalent to a standalone device TOML (e.g. AVRrc.toml, gpio.toml).
|
||||
table BaseDeviceConfig {
|
||||
libpath: string;
|
||||
mem_segments: [MemSegment];
|
||||
}
|
||||
|
||||
// Override for one memory segment within a child device.
|
||||
// Only fields that need changing from the base config must be set.
|
||||
table MemSegOverride {
|
||||
segment: string;
|
||||
start: uint32;
|
||||
len: uint32;
|
||||
word_len: uint8;
|
||||
executable: bool;
|
||||
}
|
||||
|
||||
// One device entry in a composite configuration.
|
||||
table DeviceEntry {
|
||||
// Local identifier, unique within this composite (e.g. "core", "gpio_a").
|
||||
id: string;
|
||||
|
||||
// Exactly one of config or config_path must be set.
|
||||
// config: inline base device configuration.
|
||||
// config_path: path to a serialised BaseDeviceConfig FlatBuffer file.
|
||||
config: BaseDeviceConfig;
|
||||
config_path: string;
|
||||
|
||||
clock: DeviceClockConfig;
|
||||
overrides: [MemSegOverride];
|
||||
}
|
||||
|
||||
// Root type when serialising a standalone device config to a binary file.
|
||||
root_type BaseDeviceConfig;
|
||||
73
flatbuffers/config/mem_config.fbs
Normal file
73
flatbuffers/config/mem_config.fbs
Normal file
@@ -0,0 +1,73 @@
|
||||
namespace hmmmm.config;
|
||||
|
||||
// Named offset within a segment — symbolic variable for protocol/tool use
|
||||
// (e.g. PIN=0, PORT=1, DDR=2 in a GPIO device).
|
||||
table NamedOffset {
|
||||
name: string;
|
||||
offset: uint32;
|
||||
}
|
||||
|
||||
// A contiguous memory segment within a base device.
|
||||
table MemSegment {
|
||||
name: string;
|
||||
start: uint32; // base address in device flat address space
|
||||
len: uint32;
|
||||
word_len: uint8 = 1; // word size in bytes
|
||||
executable: bool = false;
|
||||
variables: [NamedOffset]; // optional symbolic offsets within segment
|
||||
}
|
||||
|
||||
// ── Projections ──────────────────────────────────────────────────────────────
|
||||
|
||||
// Maps a segment from one device into the flat address space of another.
|
||||
// After projection, accesses to [base_seg + shift .. shift+len) in base_at
|
||||
// are transparently forwarded to target_at:target_seg.
|
||||
table Projection {
|
||||
base_at: string; // device where the projection appears
|
||||
base_seg: string; // segment in that device that is the projection window
|
||||
target_at: string; // device owning the real data
|
||||
target_seg: string;
|
||||
shift: uint32 = 0; // offset from base_seg start
|
||||
}
|
||||
|
||||
// ── Intercepts ───────────────────────────────────────────────────────────────
|
||||
|
||||
enum InterceptOp: byte {
|
||||
op_read = 0,
|
||||
op_write = 1,
|
||||
op_both = 2,
|
||||
}
|
||||
|
||||
enum InterceptMode: byte {
|
||||
shadow_copy = 1, // duplicate write to point_at:point_addr as well
|
||||
shadow_replace = 2, // redirect access to point_at:point_addr instead
|
||||
callback = 3, // invoke a handler registered by point_at device
|
||||
}
|
||||
|
||||
table Intercept {
|
||||
name: string;
|
||||
op: InterceptOp = op_both;
|
||||
mode: InterceptMode = callback;
|
||||
base_at: string; // device where the triggering access occurs
|
||||
base_seg: string;
|
||||
base_addr: uint32;
|
||||
point_at: string; // device that handles/receives the intercept
|
||||
point_seg: string;
|
||||
point_addr: uint32;
|
||||
}
|
||||
|
||||
// ── Memory initialisation ─────────────────────────────────────────────────────
|
||||
|
||||
enum OverflowBehaviour: byte {
|
||||
overflow_error = 0, // abort if file is larger than segment
|
||||
overflow_ignore = 1, // stop reading at segment end, no error
|
||||
overflow_wrap = 2, // wrap around and continue writing from segment start
|
||||
}
|
||||
|
||||
// Load initial segment contents from a file (e.g. firmware binary, /dev/urandom).
|
||||
table MemSetup {
|
||||
device: string;
|
||||
segment: string;
|
||||
filepath: string;
|
||||
overflow: OverflowBehaviour = overflow_error;
|
||||
}
|
||||
8
flatbuffers/control/config_ctrl.fbs
Normal file
8
flatbuffers/control/config_ctrl.fbs
Normal file
@@ -0,0 +1,8 @@
|
||||
// Config change control — WIP.
|
||||
// Schema stub; content will be defined when the config-change sub-protocol
|
||||
// is specified (requires device-loading control in the protocol first).
|
||||
namespace hmmmm.ctrl.config_ctrl;
|
||||
|
||||
table ConfigCtrlMessage {
|
||||
// TODO
|
||||
}
|
||||
37
flatbuffers/control/config_notif.fbs
Normal file
37
flatbuffers/control/config_notif.fbs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace hmmmm.ctrl.config_notif;
|
||||
|
||||
// Notification subtype 0001 — a device's configuration was updated.
|
||||
// Carries the path of the affected device; client should re-request full config.
|
||||
table DeviceConfigUpdateNotif {
|
||||
device_path: [string]; // hierarchical path, e.g. ["core"] or ["gpio_a"]
|
||||
}
|
||||
|
||||
// Numeric ID assigned to one named segment within a device.
|
||||
table SegIdEntry {
|
||||
name: string;
|
||||
id: uint32;
|
||||
}
|
||||
|
||||
// Maps a hierarchical device path to a compact numeric device_id + segment IDs.
|
||||
// Clients use these IDs in stream and mem packets instead of string paths.
|
||||
table DeviceIdEntry {
|
||||
path: [string]; // hierarchical device id, e.g. ["core"]
|
||||
device_id: uint32;
|
||||
seg_ids: [SegIdEntry];
|
||||
}
|
||||
|
||||
// Notification subtype 0010 — full device-id / segment-id mapping table.
|
||||
// Sent after auth and after any config change that affects the device tree.
|
||||
table DeviceIdMappingNotif {
|
||||
entries: [DeviceIdEntry];
|
||||
}
|
||||
|
||||
union ConfigNotifPayload {
|
||||
DeviceConfigUpdateNotif,
|
||||
DeviceIdMappingNotif,
|
||||
}
|
||||
|
||||
table ConfigNotifMessage {
|
||||
tclk: uint64;
|
||||
payload: ConfigNotifPayload;
|
||||
}
|
||||
39
flatbuffers/control/control.fbs
Normal file
39
flatbuffers/control/control.fbs
Normal file
@@ -0,0 +1,39 @@
|
||||
include "exec_ctrl.fbs";
|
||||
include "exec_notif.fbs";
|
||||
include "config_ctrl.fbs";
|
||||
include "config_notif.fbs";
|
||||
include "lost.fbs";
|
||||
include "orphaned.fbs";
|
||||
include "setup_buf.fbs";
|
||||
include "qos.fbs";
|
||||
|
||||
namespace hmmmm.ctrl;
|
||||
|
||||
// ── Client → Server ──────────────────────────────────────────────────────────
|
||||
|
||||
union CtrlClientPayload {
|
||||
hmmmm.ctrl.exec.ExecCtrlMessage,
|
||||
hmmmm.ctrl.config_ctrl.ConfigCtrlMessage,
|
||||
hmmmm.ctrl.lost.LostMessagesRequest,
|
||||
hmmmm.ctrl.orphaned.OrphanedRequest,
|
||||
hmmmm.ctrl.setup_buf.SetupBuf,
|
||||
}
|
||||
|
||||
table CtrlClientMessage {
|
||||
payload: CtrlClientPayload;
|
||||
}
|
||||
|
||||
// ── Server → Client ──────────────────────────────────────────────────────────
|
||||
|
||||
union CtrlServerPayload {
|
||||
hmmmm.ctrl.exec_notif.ExecNotifyMessage,
|
||||
hmmmm.ctrl.config_notif.ConfigNotifMessage,
|
||||
hmmmm.ctrl.lost.LostMessagesResponse,
|
||||
hmmmm.ctrl.orphaned.OrphanedResponse,
|
||||
hmmmm.ctrl.setup_buf.SetupBuf,
|
||||
hmmmm.ctrl.qos.QosReport,
|
||||
}
|
||||
|
||||
table CtrlServerMessage {
|
||||
payload: CtrlServerPayload;
|
||||
}
|
||||
14
flatbuffers/control/exec_ctrl.fbs
Normal file
14
flatbuffers/control/exec_ctrl.fbs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace hmmmm.ctrl.exec;
|
||||
|
||||
enum ExecPrompt: byte {
|
||||
_invalid = 0,
|
||||
start = 1,
|
||||
pause = 2,
|
||||
resume = 3,
|
||||
stop = 4,
|
||||
reset = 5,
|
||||
}
|
||||
|
||||
table ExecCtrlMessage {
|
||||
prompt: ExecPrompt;
|
||||
}
|
||||
13
flatbuffers/control/exec_notif.fbs
Normal file
13
flatbuffers/control/exec_notif.fbs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace hmmmm.ctrl.exec_notif;
|
||||
|
||||
enum ExecState: byte {
|
||||
still = 0,
|
||||
executing = 1,
|
||||
paused = 2,
|
||||
stopped = 3,
|
||||
}
|
||||
|
||||
table ExecNotifyMessage {
|
||||
tclk: uint64;
|
||||
state: ExecState;
|
||||
}
|
||||
19
flatbuffers/control/lost.fbs
Normal file
19
flatbuffers/control/lost.fbs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace hmmmm.ctrl.lost;
|
||||
|
||||
// Client → Server: request buffered (undelivered) messages for a seat.
|
||||
table LostMessagesRequest {
|
||||
seat_id: uint64;
|
||||
clear: bool = false; // if true, drop the buffer after reading
|
||||
}
|
||||
|
||||
// One buffered message that was not delivered before the seat disconnected.
|
||||
table LostMessage {
|
||||
original_nonce: uint64;
|
||||
data: [ubyte]; // raw FlatBuffer bytes of the original ServerMessage
|
||||
}
|
||||
|
||||
// Server → Client: buffered messages for the requested seat.
|
||||
table LostMessagesResponse {
|
||||
seat_id: uint64;
|
||||
messages: [LostMessage];
|
||||
}
|
||||
16
flatbuffers/control/orphaned.fbs
Normal file
16
flatbuffers/control/orphaned.fbs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace hmmmm.ctrl.orphaned;
|
||||
|
||||
// Client → Server: enumerate disconnected seats that still have buffered messages.
|
||||
// No body — request is the signal itself.
|
||||
table OrphanedRequest {}
|
||||
|
||||
table OrphanedEntry {
|
||||
seat_id: uint64;
|
||||
disconnect_tclk: uint64; // virtual clock tick at time of disconnect
|
||||
lost_count: uint32; // number of buffered messages waiting
|
||||
}
|
||||
|
||||
// Server → Client: list of orphaned seats with pending buffers.
|
||||
table OrphanedResponse {
|
||||
entries: [OrphanedEntry];
|
||||
}
|
||||
10
flatbuffers/control/qos.fbs
Normal file
10
flatbuffers/control/qos.fbs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace hmmmm.ctrl.qos;
|
||||
|
||||
// Server → Client: connection quality snapshot.
|
||||
// Sent periodically or on request (TBD).
|
||||
table QosReport {
|
||||
rtt_us: uint64; // measured round-trip time, microseconds
|
||||
packets_sent: uint64;
|
||||
packets_lost: uint32;
|
||||
buf_pressure: float; // outgoing buffer fill level, 0.0 .. 1.0
|
||||
}
|
||||
8
flatbuffers/control/setup_buf.fbs
Normal file
8
flatbuffers/control/setup_buf.fbs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace hmmmm.ctrl.setup_buf;
|
||||
|
||||
// Client → Server: configure the lost-message buffer for this seat.
|
||||
// Server → Client: echoes back the confirmed (possibly clamped) settings.
|
||||
table SetupBuf {
|
||||
lost_buf_size: uint32; // max buffered messages per seat
|
||||
client_lifetime_ticks: uint64; // virtual ticks to keep buffer after disconnect
|
||||
}
|
||||
46
flatbuffers/mem/mem.fbs
Normal file
46
flatbuffers/mem/mem.fbs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace hmmmm.mem;
|
||||
|
||||
// Client → Server: read a contiguous memory region. Server responds with
|
||||
// MemReadResponse carrying the same nonce as the enclosing ClientMessage.
|
||||
table MemReadRequest {
|
||||
device_id: uint32;
|
||||
seg_id: uint32;
|
||||
offset: uint32;
|
||||
length: uint32;
|
||||
}
|
||||
|
||||
// Server → Client: memory region contents at the moment of the read.
|
||||
table MemReadResponse {
|
||||
tclk: uint64; // virtual clock tick at time of read
|
||||
device_id: uint32;
|
||||
seg_id: uint32;
|
||||
offset: uint32;
|
||||
data: [ubyte];
|
||||
}
|
||||
|
||||
// Client → Server: write a contiguous memory region. No response.
|
||||
table MemWriteRequest {
|
||||
device_id: uint32;
|
||||
seg_id: uint32;
|
||||
offset: uint32;
|
||||
data: [ubyte];
|
||||
}
|
||||
|
||||
// ── Unions ───────────────────────────────────────────────────────────────────
|
||||
|
||||
union MemClientPayload {
|
||||
MemReadRequest,
|
||||
MemWriteRequest,
|
||||
}
|
||||
|
||||
table MemClientMessage {
|
||||
payload: MemClientPayload;
|
||||
}
|
||||
|
||||
union MemServerPayload {
|
||||
MemReadResponse,
|
||||
}
|
||||
|
||||
table MemServerMessage {
|
||||
payload: MemServerPayload;
|
||||
}
|
||||
42
flatbuffers/proto.fbs
Normal file
42
flatbuffers/proto.fbs
Normal file
@@ -0,0 +1,42 @@
|
||||
include "auth/auth.fbs";
|
||||
include "control/control.fbs";
|
||||
include "stream/stream.fbs";
|
||||
include "mem/mem.fbs";
|
||||
|
||||
namespace hmmmm;
|
||||
|
||||
// ── Client → Server ──────────────────────────────────────────────────────────
|
||||
|
||||
union ClientPayload {
|
||||
hmmmm.auth.AuthRequest,
|
||||
hmmmm.ctrl.CtrlClientMessage,
|
||||
hmmmm.stream.StreamClientMessage,
|
||||
hmmmm.mem.MemClientMessage,
|
||||
}
|
||||
|
||||
// Every frame sent by the client is a ClientMessage.
|
||||
// nonce: client-chosen identifier echoed in the server response.
|
||||
// Use 0xFFFFFFFFFFFFFFFF for fire-and-forget messages (no reply expected).
|
||||
table ClientMessage {
|
||||
nonce: uint64;
|
||||
payload: ClientPayload;
|
||||
}
|
||||
|
||||
// ── Server → Client ──────────────────────────────────────────────────────────
|
||||
|
||||
union ServerPayload {
|
||||
hmmmm.auth.AuthResponse,
|
||||
hmmmm.ctrl.CtrlServerMessage,
|
||||
hmmmm.stream.StreamServerMessage,
|
||||
hmmmm.mem.MemServerMessage,
|
||||
}
|
||||
|
||||
// Every frame sent by the server is a ServerMessage.
|
||||
// nonce: echoes the triggering ClientMessage nonce.
|
||||
// 0xFFFFFFFFFFFFFFFF for unsolicited notifications (state changes, stream pushes).
|
||||
table ServerMessage {
|
||||
nonce: uint64;
|
||||
payload: ServerPayload;
|
||||
}
|
||||
|
||||
root_type ClientMessage;
|
||||
27
flatbuffers/stream/stream.fbs
Normal file
27
flatbuffers/stream/stream.fbs
Normal file
@@ -0,0 +1,27 @@
|
||||
include "stream_reg.fbs";
|
||||
include "stream_data.fbs";
|
||||
|
||||
namespace hmmmm.stream;
|
||||
|
||||
// ── Client → Server ──────────────────────────────────────────────────────────
|
||||
|
||||
union StreamClientPayload {
|
||||
StreamRegRequest,
|
||||
StreamDeregRequest,
|
||||
StreamWritePush,
|
||||
}
|
||||
|
||||
table StreamClientMessage {
|
||||
payload: StreamClientPayload;
|
||||
}
|
||||
|
||||
// ── Server → Client ──────────────────────────────────────────────────────────
|
||||
|
||||
union StreamServerPayload {
|
||||
StreamRegConfirm,
|
||||
StreamDataPush,
|
||||
}
|
||||
|
||||
table StreamServerMessage {
|
||||
payload: StreamServerPayload;
|
||||
}
|
||||
18
flatbuffers/stream/stream_data.fbs
Normal file
18
flatbuffers/stream/stream_data.fbs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace hmmmm.stream;
|
||||
|
||||
// Server → Client: memory region snapshot pushed by the server.
|
||||
// tclk is the virtual clock tick at which this data became valid —
|
||||
// clients may buffer and apply it at the appropriate simulation point.
|
||||
table StreamDataPush {
|
||||
stream_id: uint32;
|
||||
tclk: uint64;
|
||||
data: [ubyte];
|
||||
}
|
||||
|
||||
// Client → Server: write into a registered write-mode stream.
|
||||
// offset is relative to the registered region start.
|
||||
table StreamWritePush {
|
||||
stream_id: uint32;
|
||||
offset: uint32;
|
||||
data: [ubyte];
|
||||
}
|
||||
32
flatbuffers/stream/stream_reg.fbs
Normal file
32
flatbuffers/stream/stream_reg.fbs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace hmmmm.stream;
|
||||
|
||||
enum StreamMode: byte {
|
||||
mode_read = 0,
|
||||
mode_write = 1,
|
||||
}
|
||||
|
||||
// Client → Server: subscribe to a memory region.
|
||||
table StreamRegRequest {
|
||||
device_id: uint32; // from DeviceIdMappingNotif
|
||||
seg_id: uint32; // from DeviceIdMappingNotif
|
||||
offset: uint32; // start offset within segment, in bytes
|
||||
length: uint32; // region length, in bytes
|
||||
mode: StreamMode;
|
||||
}
|
||||
|
||||
// Client → Server: cancel a stream subscription.
|
||||
// No confirmation is sent by the server.
|
||||
table StreamDeregRequest {
|
||||
stream_id: uint32;
|
||||
}
|
||||
|
||||
// Server → Client: subscription confirmed, stream_id assigned.
|
||||
// Echoes the original request fields for client-side reconciliation.
|
||||
table StreamRegConfirm {
|
||||
stream_id: uint32;
|
||||
device_id: uint32;
|
||||
seg_id: uint32;
|
||||
offset: uint32;
|
||||
length: uint32;
|
||||
mode: StreamMode;
|
||||
}
|
||||
120
flatbuffers_example_main.c
Normal file
120
flatbuffers_example_main.c
Normal file
@@ -0,0 +1,120 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "monster_reader.h"
|
||||
#include "monster_verifier.h"
|
||||
#include "monster_builder.h"
|
||||
|
||||
#undef ns
|
||||
#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x)
|
||||
|
||||
#define c_vec_len(V) (sizeof(V)/sizeof((V)[0]))
|
||||
|
||||
int main()
|
||||
{
|
||||
flatcc_builder_t builder, *B = &builder;
|
||||
flatcc_builder_init(B);
|
||||
|
||||
printf("[+] Builder initialized\n");
|
||||
|
||||
flatbuffers_string_ref_t weapon_one_name =
|
||||
flatbuffers_string_create_str(B, "Sword");
|
||||
flatbuffers_string_ref_t weapon_two_name =
|
||||
flatbuffers_string_create_str(B, "Axe");
|
||||
|
||||
ns(Weapon_ref_t) sword =
|
||||
ns(Weapon_create(B, weapon_one_name, 3));
|
||||
ns(Weapon_ref_t) axe =
|
||||
ns(Weapon_create(B, weapon_two_name, 5));
|
||||
|
||||
ns(Weapon_vec_start(B));
|
||||
ns(Weapon_vec_push(B, sword));
|
||||
ns(Weapon_vec_push(B, axe));
|
||||
ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B));
|
||||
|
||||
uint8_t treasure[] = {0,1,2,3,4,5,6,7,8,9};
|
||||
flatbuffers_uint8_vec_ref_t inventory =
|
||||
flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure));
|
||||
|
||||
flatbuffers_string_ref_t name =
|
||||
flatbuffers_string_create_str(B, "Orc");
|
||||
|
||||
uint16_t hp = 300;
|
||||
uint16_t mana = 150;
|
||||
|
||||
ns(Vec3_t) pos = {1.0f, 2.0f, 3.0f};
|
||||
|
||||
ns(Vec3_vec_start(B));
|
||||
ns(Vec3_vec_push(B, &pos));
|
||||
ns(Vec3_vec_ref_t) path = ns(Vec3_vec_end(B));
|
||||
|
||||
ns(Equipment_union_ref_t) equipped =
|
||||
ns(Equipment_as_Weapon(axe));
|
||||
|
||||
ns(Monster_create_as_root(
|
||||
B, &pos, mana, hp, name,
|
||||
inventory, ns(Color_Red),
|
||||
weapons, equipped, path));
|
||||
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
|
||||
buf = flatcc_builder_finalize_buffer(B, &size);
|
||||
|
||||
printf("[+] Buffer built, size = %zu bytes\n", size);
|
||||
|
||||
|
||||
// 🔍 Верификация
|
||||
if (ns(Monster_verify_as_root(buf, size))) {
|
||||
printf("[!] Buffer verification FAILED\n");
|
||||
return -1;
|
||||
}
|
||||
printf("[+] Buffer verification OK\n");
|
||||
|
||||
// 📖 Чтение
|
||||
ns(Monster_table_t) m = ns(Monster_as_root(buf));
|
||||
|
||||
printf("\n===== MONSTER DUMP =====\n");
|
||||
|
||||
printf("Name: %s\n", ns(Monster_name(m)));
|
||||
printf("HP: %u\n", ns(Monster_hp(m)));
|
||||
printf("Mana: %u\n", ns(Monster_mana(m)));
|
||||
|
||||
ns(Vec3_struct_t) p = ns(Monster_pos(m));
|
||||
printf("Position: x=%.2f y=%.2f z=%.2f\n",
|
||||
ns(Vec3_x(p)), ns(Vec3_y(p)), ns(Vec3_z(p)));
|
||||
|
||||
flatbuffers_uint8_vec_t inv = ns(Monster_inventory(m));
|
||||
size_t inv_len = flatbuffers_uint8_vec_len(inv);
|
||||
|
||||
printf("Inventory (%zu): ", inv_len);
|
||||
for (size_t i = 0; i < inv_len; i++) {
|
||||
printf("%u ", flatbuffers_uint8_vec_at(inv, i));
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
ns(Weapon_vec_t) wv = ns(Monster_weapons(m));
|
||||
size_t wlen = ns(Weapon_vec_len(wv));
|
||||
|
||||
printf("Weapons (%zu):\n", wlen);
|
||||
for (size_t i = 0; i < wlen; i++) {
|
||||
ns(Weapon_table_t) w = ns(Weapon_vec_at(wv, i));
|
||||
printf(" - %s (dmg=%u)\n",
|
||||
ns(Weapon_name(w)),
|
||||
ns(Weapon_damage(w)));
|
||||
}
|
||||
|
||||
if (ns(Monster_equipped_type(m)) == ns(Equipment_Weapon)) {
|
||||
ns(Weapon_table_t) w = ns(Monster_equipped(m));
|
||||
printf("Equipped: %s (dmg=%u)\n",
|
||||
ns(Weapon_name(w)),
|
||||
ns(Weapon_damage(w)));
|
||||
}
|
||||
|
||||
printf("========================\n\n");
|
||||
|
||||
free(buf);
|
||||
flatcc_builder_clear(B);
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
gpio.toml
Normal file
23
gpio.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[dev]
|
||||
libpath = "avr_gpio/out/device.so"
|
||||
|
||||
|
||||
|
||||
[mem.ext_reg_io]
|
||||
start = 0
|
||||
len = 255
|
||||
wordLen = 1
|
||||
|
||||
[mem.extstate]
|
||||
start = 256
|
||||
len = 1
|
||||
wordLen = 1
|
||||
|
||||
[mem.variables]
|
||||
PIN = 0
|
||||
PORT = 1
|
||||
DDR = 2
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "sized_ptr.h"
|
||||
|
||||
#include "streamed.h"
|
||||
#include "flatcc/flatcc_builder.h"
|
||||
|
||||
typedef struct {
|
||||
SizedPtr* bufs;
|
||||
@@ -30,6 +31,7 @@ typedef struct {
|
||||
DeviceSegStreamReg** deviceStreamRegs;
|
||||
uint8_t** devicesMem;
|
||||
size_t devicesCount;
|
||||
flatcc_builder_t stream_builder;
|
||||
} EmulContext;
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#ifndef __PROTO_HANDLERS_CONTROL_H__
|
||||
#define __PROTO_HANDLERS_CONTROL_H__
|
||||
|
||||
#include "proto/msg.h"
|
||||
#include <stdint.h>
|
||||
#include "client.h"
|
||||
#include "context.h"
|
||||
#include "proto/dial.h"
|
||||
#include "control_reader.h"
|
||||
|
||||
void handleIncomingControlMessage(BaseMessage* msg, EmulContext* emulContext);
|
||||
void handleIncomingCtrlMessage(
|
||||
hmmmm_ctrl_CtrlClientMessage_table_t msg,
|
||||
uint64_t nonce,
|
||||
ClientContext* ctx,
|
||||
EmulContext* emulContext);
|
||||
|
||||
|
||||
#endif //ifndef __PROTO_HANDLERS_CONTROL_H__
|
||||
#endif // __PROTO_HANDLERS_CONTROL_H__
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#ifndef __PROTO_HANDLERS_MEM_H__
|
||||
#define __PROTO_HANDLERS_MEM_H__
|
||||
|
||||
#include "proto/msg.h"
|
||||
#include <stdint.h>
|
||||
#include "context.h"
|
||||
#include "client.h"
|
||||
#include "proto/dial.h"
|
||||
#include "mem_reader.h"
|
||||
|
||||
void handleIncomingMemMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext);
|
||||
|
||||
#endif //ifndef __PROTO_HANDLERS_MEM_H__
|
||||
void handleIncomingMemMessage(
|
||||
hmmmm_mem_MemClientMessage_table_t msg,
|
||||
uint64_t nonce,
|
||||
ClientContext* ctx,
|
||||
EmulContext* emulContext);
|
||||
|
||||
#endif // __PROTO_HANDLERS_MEM_H__
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#ifndef __PROTO_HANDLERS_STREAM_H__
|
||||
#define __PROTO_HANDLERS_STREAM_H__
|
||||
|
||||
#include "proto/msg.h"
|
||||
#include <stdint.h>
|
||||
#include "context.h"
|
||||
#include "client.h"
|
||||
#include "proto/dial.h"
|
||||
|
||||
#include "stream_reader.h"
|
||||
|
||||
void unregisterClientStream(EmulContext* emulContext, ClientContext* ctx, uint32_t regId);
|
||||
void unregisterClientStreams(EmulContext* emulContext, ClientContext* ctx);
|
||||
void handleIncomingStreamMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext);
|
||||
|
||||
#endif //ifndef __PROTO_HANDLERS_STREAM_H__
|
||||
void handleIncomingStreamMessage(
|
||||
hmmmm_stream_StreamClientMessage_table_t msg,
|
||||
uint64_t nonce,
|
||||
ClientContext* ctx,
|
||||
EmulContext* emulContext);
|
||||
|
||||
#endif // __PROTO_HANDLERS_STREAM_H__
|
||||
|
||||
@@ -2,7 +2,15 @@
|
||||
#define __PROTO_MSG_H__
|
||||
|
||||
#include "wsServer/include/ws.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "flatcc/flatcc_builder.h"
|
||||
|
||||
// Raw FlatBuffers frame copied from the WS thread, queued to the main loop.
|
||||
typedef struct {
|
||||
uint8_t* data;
|
||||
size_t size;
|
||||
} FbMessage;
|
||||
|
||||
typedef struct {
|
||||
ws_cli_conn_t clientIdx;
|
||||
@@ -10,17 +18,43 @@ typedef struct {
|
||||
size_t msgLen;
|
||||
} OutgoingMessage;
|
||||
|
||||
typedef struct {
|
||||
uint64_t nonce;
|
||||
uint8_t packetType;
|
||||
uint8_t payloadHeader;
|
||||
const void* payload;
|
||||
size_t payloadLen;
|
||||
} BaseMessage;
|
||||
// Build a ServerMessage{AuthResponse} frame. Returns a malloc'd buffer;
|
||||
// ownership is transferred to the caller (dispatchOutgoingMessage will free it).
|
||||
uint8_t* fb_build_auth_response(uint64_t nonce, uint64_t seat_id, size_t* len_out);
|
||||
|
||||
BaseMessage* parseMessage(const uint8_t* bytes, size_t size);
|
||||
uint8_t* createControlNotifyMessage(uint64_t nonce, uint64_t clockCounter, uint8_t newEmulState, size_t* lenOut);
|
||||
uint8_t* createDoneRegMessage(uint64_t nonce, uint8_t X, uint64_t devId, uint64_t segId, uint64_t startAddr, uint64_t segLength, uint32_t regId, size_t* lenOut);
|
||||
uint8_t* createStreamSegmentPush(uint8_t mode, uint32_t regId, uint64_t clockCounter, uint8_t* payload, size_t payloadLen, size_t* lenOut);
|
||||
// Build a ServerMessage{CtrlServerMessage{ExecNotifyMessage}} frame.
|
||||
uint8_t* fb_build_exec_notify(uint64_t nonce, uint64_t tclk, uint8_t state, size_t* len_out);
|
||||
|
||||
#endif //ifndef __PROTO_MSG_H__
|
||||
// Build a ServerMessage{StreamServerMessage{StreamDataPush}} frame.
|
||||
// B must be a pre-initialized flatcc_builder_t; it is reset before use
|
||||
// so the caller does not need to reset it manually between calls.
|
||||
uint8_t* fb_build_stream_data_push(
|
||||
flatcc_builder_t *B,
|
||||
uint64_t nonce, uint32_t stream_id, uint64_t tclk,
|
||||
const uint8_t* data, size_t data_len,
|
||||
size_t* len_out);
|
||||
|
||||
// Build a ServerMessage{CtrlServerMessage{SetupBuf}} frame (echo back to client).
|
||||
uint8_t* fb_build_setup_buf(uint64_t nonce, uint32_t lost_buf_size,
|
||||
uint64_t client_lifetime_ticks, size_t* len_out);
|
||||
|
||||
// Build a ServerMessage{CtrlServerMessage{OrphanedResponse{entries=[]}}} frame.
|
||||
uint8_t* fb_build_orphaned_response(uint64_t nonce, size_t* len_out);
|
||||
|
||||
// Build a ServerMessage{CtrlServerMessage{LostMessagesResponse{seat_id, messages=[]}}} frame.
|
||||
uint8_t* fb_build_lost_messages_response(uint64_t nonce, uint64_t seat_id, size_t* len_out);
|
||||
|
||||
// Build a ServerMessage{MemServerMessage{MemReadResponse}} frame.
|
||||
uint8_t* fb_build_mem_read_response(
|
||||
uint64_t nonce, uint64_t tclk,
|
||||
uint32_t device_id, uint32_t seg_id, uint32_t offset,
|
||||
const uint8_t* data, size_t data_len,
|
||||
size_t* len_out);
|
||||
|
||||
// Build a ServerMessage{StreamServerMessage{StreamRegConfirm}} frame.
|
||||
uint8_t* fb_build_stream_reg_confirm(
|
||||
uint64_t nonce, uint32_t stream_id,
|
||||
uint32_t device_id, uint32_t seg_id, uint32_t offset, uint32_t length,
|
||||
uint8_t mode, size_t* len_out);
|
||||
|
||||
#endif // __PROTO_MSG_H__
|
||||
|
||||
46
src/main.c
46
src/main.c
@@ -185,9 +185,7 @@ void* outgoingMain(void* args)
|
||||
{
|
||||
panic("Got double read on buf %d while writing on buf %d\n", currBufIdx, currWritingIdxPtr);
|
||||
}
|
||||
// printf("\t%lu -> [%lu]\n", outMsg->msgLen, outMsg->clientIdx);
|
||||
ws_sendframe_bin(outMsg->clientIdx, (const char*)outMsg->msg, outMsg->msgLen);
|
||||
// printf("running free on buf %d message %lu\n", currBufIdx, i);
|
||||
free(outMsg->msg);
|
||||
outMsg->msg = NULL;
|
||||
// printf("done free on buf %d message %lu\n", currBufIdx, i);
|
||||
@@ -251,7 +249,10 @@ void mockDevice1(uint8_t* mem, uint64_t* readAddrs, size_t* readAddrsLen, uint64
|
||||
void dispatchStreamSegment(EmulContext* emulContext, StreamReg* reg, uint8_t* mem)
|
||||
{
|
||||
size_t mlen = 0;
|
||||
uint8_t* msg = createStreamSegmentPush(reg->mode, reg->regId, *emulContext->clockCounter, mem + reg->startAddr, reg->segLen, &mlen);
|
||||
uint8_t* msg = fb_build_stream_data_push(
|
||||
&emulContext->stream_builder,
|
||||
UINT64_MAX, reg->regId, *emulContext->clockCounter,
|
||||
mem + reg->startAddr, reg->segLen, &mlen);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, reg->clientContext->clientId, msg, mlen);
|
||||
}
|
||||
|
||||
@@ -320,17 +321,18 @@ int main(int argc, char** argv)
|
||||
DeviceSegStreamReg* device0SegStreamRegs = malloc(sizeof(DeviceSegStreamReg) * 4);
|
||||
NULL_GUARD(device0SegStreamRegs);
|
||||
|
||||
device0SegStreamRegs->allocatedSize = 0;
|
||||
device0SegStreamRegs->allocatedSize = 4;
|
||||
device0SegStreamRegs->regCount = 0;
|
||||
device0SegStreamRegs->regs = NULL;
|
||||
device0SegStreamRegs->regs = malloc(sizeof(StreamReg) * 4);
|
||||
NULL_GUARD(device0SegStreamRegs->regs);
|
||||
|
||||
DeviceSegStreamReg* device1SegStreamRegs = malloc(sizeof(DeviceSegStreamReg) * 4);
|
||||
NULL_GUARD(device1SegStreamRegs);
|
||||
|
||||
|
||||
device1SegStreamRegs->allocatedSize = 0;
|
||||
device1SegStreamRegs->allocatedSize = 4;
|
||||
device1SegStreamRegs->regCount = 0;
|
||||
device1SegStreamRegs->regs = NULL;
|
||||
device1SegStreamRegs->regs = malloc(sizeof(StreamReg) * 4);
|
||||
NULL_GUARD(device1SegStreamRegs->regs);
|
||||
|
||||
DeviceSegStreamReg** deviceStreamRegs = malloc(sizeof(DeviceSegStreamReg*) * deviceCount);
|
||||
NULL_GUARD(deviceStreamRegs);
|
||||
@@ -409,8 +411,12 @@ int main(int argc, char** argv)
|
||||
&outBufs,
|
||||
deviceStreamRegs,
|
||||
devicesMem,
|
||||
deviceCount
|
||||
deviceCount,
|
||||
{0} /* stream_builder — initialized below */
|
||||
};
|
||||
if (flatcc_builder_init(&emulContext.stream_builder)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
|
||||
uint8_t access_token[] = "jtd3dhBWG2p73mkRCyaZ63KLmOjl5OgItIDAPa8HcyGQI2SOFA6hsJVr1NiG2Y96AvwyYSShr4GAL3sjJEo1wsmCo2vuhiqRhj8HVRrOVocD2e1jtuMwMsCmizYakT63";
|
||||
@@ -443,6 +449,8 @@ int main(int argc, char** argv)
|
||||
|
||||
ptQueueElem* regQueueTail = regQ->tail;
|
||||
|
||||
uint8_t clients_try_timer = 100;
|
||||
|
||||
while(1)
|
||||
{
|
||||
ClientRegistrationEvent* payload = regQueueTail->payload;
|
||||
@@ -455,12 +463,19 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
|
||||
if (clients_try_timer == 0)
|
||||
{
|
||||
handleAllClients(&emulContext);
|
||||
clients_try_timer = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
clients_try_timer--;
|
||||
}
|
||||
|
||||
uint8_t readReqIdx = atomic_load(&outBufs.readRequestIdx);
|
||||
if(readReqIdx == outBufs.currWritingIdx || outBufs.bufs[outBufs.currWritingIdx].size >= outBufs.bufs[outBufs.currWritingIdx].allocatedSize / 2)
|
||||
{
|
||||
uint8_t oldWriteIdx = outBufs.currWritingIdx;
|
||||
uint8_t newWriteIdx = outBufs.currWritingIdx + 1;
|
||||
if(outBufs.bufs[outBufs.currWritingIdx].size != 0 || readReqIdx != newWriteIdx)
|
||||
{
|
||||
@@ -468,13 +483,6 @@ int main(int argc, char** argv)
|
||||
{
|
||||
newWriteIdx = 0;
|
||||
}
|
||||
// printf("Switching write idx %d->%d\n", oldWriteIdx, newWriteIdx);
|
||||
|
||||
|
||||
// if(readReqIdx == newWriteIdx)
|
||||
// {
|
||||
// printf("Flood control breach, waiting until outgoing buffers empty!\n");
|
||||
// }
|
||||
while(readReqIdx == newWriteIdx)
|
||||
{
|
||||
my_sleep(1000);
|
||||
@@ -487,7 +495,7 @@ int main(int argc, char** argv)
|
||||
|
||||
if(emulState == EMUL_STATE_EXEC)
|
||||
{
|
||||
printf("Running...\n");
|
||||
// printf("Running...\n");
|
||||
device0readAddrsLen = 0;
|
||||
device0writeAddrsLen = 0;
|
||||
|
||||
@@ -507,7 +515,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
else if(!utilizedFlag)
|
||||
{
|
||||
my_sleep(100);
|
||||
my_sleep(1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ void dispatchOutgoingMessage(OutgoingBuffers* outBufs, ws_cli_conn_t clientIdx,
|
||||
SizedPtr* p = &outBufs->bufs[outBufs->currWritingIdx];
|
||||
if(p->size + 1 >= p->allocatedSize)
|
||||
{
|
||||
printf("\t>>Reallocating buf %d\n", outBufs->currWritingIdx);
|
||||
// printf("\t>>Reallocating buf %d\n", outBufs->currWritingIdx);
|
||||
OutgoingMessage* newPtr = realloc(p->ptr, sizeof(OutgoingMessage) * p->allocatedSize * 2);
|
||||
NULL_GUARD(newPtr);
|
||||
p->ptr = newPtr;
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
#include "proto/handlers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "proto/enums.h"
|
||||
#include "panic.h"
|
||||
|
||||
#include "proto/enums.h"
|
||||
#include "proto/handlers/auth.h"
|
||||
#include "proto/handlers/stream.h"
|
||||
#include "proto/handlers/control.h"
|
||||
#include "proto/handlers/mem.h"
|
||||
#include "proto/msg.h"
|
||||
|
||||
#include "proto_reader.h"
|
||||
#include "proto_verifier.h"
|
||||
#include "control_reader.h"
|
||||
#include "stream_reader.h"
|
||||
#include "mem_reader.h"
|
||||
|
||||
|
||||
void handleCloseClient(EmulContext* emulContext, ClientContext* ctx)
|
||||
{
|
||||
if(ctx->streamRegIterator > 0)
|
||||
{
|
||||
if (ctx->streamRegIterator > 0) {
|
||||
unregisterClientStreams(emulContext, ctx);
|
||||
}
|
||||
}
|
||||
@@ -21,29 +27,25 @@ void handleCloseClient(EmulContext* emulContext, ClientContext* ctx)
|
||||
|
||||
void handleRegEvent(EmulContext* emulContext, ClientRegistrationEvent* ev)
|
||||
{
|
||||
if(ev->regType == REG_EVTYPE_CONNECT)
|
||||
if (ev->regType == REG_EVTYPE_CONNECT)
|
||||
{
|
||||
printf("open client %lu\n", ev->ctx->clientId);
|
||||
LinkedListEntry* newClientsLinkedListHead = malloc(sizeof(LinkedListEntry));
|
||||
NULL_GUARD(newClientsLinkedListHead);
|
||||
LinkedListEntry* entry = malloc(sizeof(LinkedListEntry));
|
||||
NULL_GUARD(entry);
|
||||
|
||||
newClientsLinkedListHead->payload = ev->ctx;
|
||||
if(*emulContext->clientsHead != NULL)
|
||||
{
|
||||
(*emulContext->clientsHead)->prevEntry = newClientsLinkedListHead;
|
||||
entry->payload = ev->ctx;
|
||||
if (*emulContext->clientsHead != NULL) {
|
||||
(*emulContext->clientsHead)->prevEntry = entry;
|
||||
}
|
||||
newClientsLinkedListHead->prevEntry = NULL;
|
||||
newClientsLinkedListHead->nextEntry = *emulContext->clientsHead;
|
||||
*emulContext->clientsHead = newClientsLinkedListHead;
|
||||
entry->prevEntry = NULL;
|
||||
entry->nextEntry = *emulContext->clientsHead;
|
||||
*emulContext->clientsHead = entry;
|
||||
}
|
||||
else if (ev->regType == REG_EVTYPE_CLOSE)
|
||||
{
|
||||
LinkedListEntry* clientEntry = *emulContext->clientsHead;
|
||||
|
||||
while(clientEntry != NULL)
|
||||
{
|
||||
if(clientEntry->payload == ev->ctx)
|
||||
{
|
||||
while (clientEntry != NULL) {
|
||||
if (clientEntry->payload == ev->ctx) {
|
||||
printf("close client %lu\n", ev->ctx->clientId);
|
||||
handleCloseClient(emulContext, ev->ctx);
|
||||
removeLinkedListEntry(emulContext->clientsHead, clientEntry);
|
||||
@@ -61,33 +63,47 @@ void handleRegEvent(EmulContext* emulContext, ClientRegistrationEvent* ev)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void handleIncomingMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext)
|
||||
static void handleIncomingMessage(
|
||||
hmmmm_ClientMessage_table_t cm, ClientContext* ctx, EmulContext* emulContext)
|
||||
{
|
||||
switch (msg->packetType)
|
||||
uint64_t nonce = hmmmm_ClientMessage_nonce(cm);
|
||||
hmmmm_ClientPayload_union_type_t ptype = hmmmm_ClientMessage_payload_type(cm);
|
||||
|
||||
printf("client %lu: nonce=%lu payload=%s\n",
|
||||
ctx->clientId, nonce, hmmmm_ClientPayload_type_name(ptype));
|
||||
|
||||
switch (ptype)
|
||||
{
|
||||
case PACKET_TYPE_CTRL:
|
||||
case hmmmm_ClientPayload_CtrlClientMessage:
|
||||
{
|
||||
printf("CTRL packet\n");
|
||||
handleIncomingControlMessage(msg, emulContext);
|
||||
hmmmm_ctrl_CtrlClientMessage_table_t ctrl =
|
||||
(hmmmm_ctrl_CtrlClientMessage_table_t)hmmmm_ClientMessage_payload(cm);
|
||||
handleIncomingCtrlMessage(ctrl, nonce, ctx, emulContext);
|
||||
break;
|
||||
}
|
||||
case PACKET_TYPE_STREAM:
|
||||
case hmmmm_ClientPayload_StreamClientMessage:
|
||||
{
|
||||
printf("STREAM packet\n");
|
||||
handleIncomingStreamMessage(msg, ctx, emulContext);
|
||||
hmmmm_stream_StreamClientMessage_table_t stream =
|
||||
(hmmmm_stream_StreamClientMessage_table_t)hmmmm_ClientMessage_payload(cm);
|
||||
handleIncomingStreamMessage(stream, nonce, ctx, emulContext);
|
||||
break;
|
||||
}
|
||||
case PACKET_TYPE_MEM:
|
||||
case hmmmm_ClientPayload_MemClientMessage:
|
||||
{
|
||||
printf("MEM packet\n");
|
||||
handleIncomingMemMessage(msg, ctx, emulContext);
|
||||
hmmmm_mem_MemClientMessage_table_t mem =
|
||||
(hmmmm_mem_MemClientMessage_table_t)hmmmm_ClientMessage_payload(cm);
|
||||
handleIncomingMemMessage(mem, nonce, ctx, emulContext);
|
||||
break;
|
||||
}
|
||||
case hmmmm_ClientPayload_AuthRequest:
|
||||
{
|
||||
// AuthRequest must only arrive before auth; drop if seen here
|
||||
printf("client %lu: unexpected AuthRequest after auth\n", ctx->clientId);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printf("Unsupported packet type: %u\n", msg->packetType);
|
||||
printf("client %lu: unknown payload type %u\n", ctx->clientId, ptype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -97,46 +113,34 @@ void handleIncomingMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* em
|
||||
void handleAllClients(EmulContext* emulContext)
|
||||
{
|
||||
LinkedListEntry* clientEntry = *emulContext->clientsHead;
|
||||
|
||||
size_t handleLimit = 128;
|
||||
|
||||
while(clientEntry != NULL && handleLimit > 0)
|
||||
{
|
||||
while (clientEntry != NULL && handleLimit > 0) {
|
||||
handleLimit--;
|
||||
ClientContext* ctx = clientEntry->payload;
|
||||
if(!ctx->isAuthed)
|
||||
{
|
||||
|
||||
if (!ctx->isAuthed) {
|
||||
clientEntry = disconnectDueTimeout(emulContext, clientEntry);
|
||||
if(clientEntry == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(*emulContext->utilizedFlag)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
void* payload = ctx->incomeQ->head->payload;
|
||||
if(payload != NULL)
|
||||
{
|
||||
if (clientEntry == NULL) break;
|
||||
if (*emulContext->utilizedFlag) continue;
|
||||
} else {
|
||||
FbMessage* fbmsg = ctx->incomeQ->head->payload;
|
||||
if (fbmsg != NULL) {
|
||||
*emulContext->utilizedFlag = 1;
|
||||
BaseMessage* msg = payload;
|
||||
printf("client %lu sent data: \nnonce %lu, ptype %4u, ph: %u\n", ctx->clientId, msg->nonce, msg->packetType, msg->payloadHeader);
|
||||
|
||||
handleIncomingMessage(msg, ctx, emulContext);
|
||||
if (hmmmm_ClientMessage_verify_as_root(fbmsg->data, fbmsg->size) == 0) {
|
||||
hmmmm_ClientMessage_table_t cm =
|
||||
hmmmm_ClientMessage_as_root(fbmsg->data);
|
||||
handleIncomingMessage(cm, ctx, emulContext);
|
||||
} else {
|
||||
printf("client %lu: dropped malformed FlatBuffer\n", ctx->clientId);
|
||||
}
|
||||
|
||||
|
||||
free(payload);
|
||||
free(fbmsg->data);
|
||||
free(fbmsg);
|
||||
ctx->incomeQ->head = ctx->incomeQ->head->nextEl;
|
||||
}
|
||||
clientEntry = clientEntry->nextEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,97 +1,105 @@
|
||||
#include "proto/handlers/auth.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "my_mutex.h"
|
||||
|
||||
#include "proto/enums.h"
|
||||
#include "events.h"
|
||||
#include "panic.h"
|
||||
|
||||
|
||||
#include "proto/pack.h"
|
||||
#include "proto/enums.h"
|
||||
#include "proto/msg.h"
|
||||
#include "proto/dial.h"
|
||||
#include "proto/handlers/control.h"
|
||||
|
||||
uint8_t validateAccessTokenDeterministic(const uint8_t* data, const uint8_t* token, uint64_t timestamp)
|
||||
#include "proto_reader.h"
|
||||
#include "proto_verifier.h"
|
||||
#include "auth_reader.h"
|
||||
|
||||
|
||||
static uint8_t validateAccessTokenDeterministic(
|
||||
const uint8_t* data, const uint8_t* token, uint64_t timestamp)
|
||||
{
|
||||
char buf[1024];
|
||||
sprintf(buf, "%s%lu", token, timestamp);
|
||||
(void)snprintf(buf, sizeof(buf), "%s%lu", token, timestamp);
|
||||
|
||||
uint8_t hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512((uint8_t*)buf, strlen(buf), hash);
|
||||
SHA512((const uint8_t*)buf, strlen(buf), hash);
|
||||
|
||||
uint8_t valid = 1;
|
||||
|
||||
for(size_t i = 0; i < SHA512_DIGEST_LENGTH; i++)
|
||||
{
|
||||
if (data[i] != hash[i])
|
||||
{
|
||||
for (size_t i = 0; i < SHA512_DIGEST_LENGTH; i++) {
|
||||
if (data[i] != hash[i]) {
|
||||
valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
uint8_t validateAccessToken(const uint8_t* data, const uint8_t* access_token)
|
||||
static uint8_t validateAccessToken(const uint8_t* data, const uint8_t* access_token)
|
||||
{
|
||||
uint64_t t = (uint64_t)time(NULL) / 30;
|
||||
|
||||
uint8_t valid1 = validateAccessTokenDeterministic(data, access_token, t);
|
||||
uint8_t valid2 = validateAccessTokenDeterministic(data, access_token, t - 1);
|
||||
|
||||
return valid1 || valid2;
|
||||
return validateAccessTokenDeterministic(data, access_token, t)
|
||||
|| validateAccessTokenDeterministic(data, access_token, t - 1);
|
||||
}
|
||||
|
||||
|
||||
uint8_t handle_auth(ClientContext* cctx, ws_cli_conn_t client, const uint8_t* msg, uint64_t msgSize, int msgType)
|
||||
uint8_t handle_auth(
|
||||
ClientContext* cctx, ws_cli_conn_t client,
|
||||
const uint8_t* msg, uint64_t msgSize, int msgType)
|
||||
{
|
||||
(void)msgType;
|
||||
|
||||
ServerContext* ctx = ws_get_server_context(client);
|
||||
if(msgSize != SHA512_DIGEST_LENGTH)
|
||||
{
|
||||
int ret = ws_close_client(client);
|
||||
if(ret == -1)
|
||||
{
|
||||
printf("Unable to close client %lu\n", client);
|
||||
}
|
||||
|
||||
// Verify it's a valid ClientMessage FlatBuffer
|
||||
if (hmmmm_ClientMessage_verify_as_root(msg, (size_t)msgSize)) {
|
||||
printf("Auth: invalid FlatBuffer from client %lu\n", client);
|
||||
ws_close_client(client);
|
||||
return 0;
|
||||
}
|
||||
uint8_t isValid = validateAccessToken(msg, (const uint8_t*)ctx->accessToken);
|
||||
if(!isValid)
|
||||
{
|
||||
printf("Auth token invalid\n");
|
||||
int ret = ws_close_client(client);
|
||||
if(ret == -1)
|
||||
{
|
||||
printf("Unable to close client %lu\n", client);
|
||||
}
|
||||
|
||||
hmmmm_ClientMessage_table_t cm = hmmmm_ClientMessage_as_root(msg);
|
||||
|
||||
if (hmmmm_ClientMessage_payload_type(cm) != hmmmm_ClientPayload_AuthRequest) {
|
||||
printf("Auth: expected AuthRequest, got type %u from client %lu\n",
|
||||
hmmmm_ClientMessage_payload_type(cm), client);
|
||||
ws_close_client(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hmmmm_auth_AuthRequest_table_t ar =
|
||||
(hmmmm_auth_AuthRequest_table_t)hmmmm_ClientMessage_payload(cm);
|
||||
|
||||
flatbuffers_uint8_vec_t hash_vec = hmmmm_auth_AuthRequest_hash(ar);
|
||||
size_t hash_len = flatbuffers_uint8_vec_len(hash_vec);
|
||||
|
||||
if (hash_len != SHA512_DIGEST_LENGTH) {
|
||||
printf("Auth: wrong hash length %zu from client %lu\n", hash_len, client);
|
||||
ws_close_client(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!validateAccessToken(hash_vec, (const uint8_t*)ctx->accessToken)) {
|
||||
printf("Auth: token invalid for client %lu\n", client);
|
||||
ws_close_client(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Auth: token valid for client %lu\n", client);
|
||||
|
||||
char errbuf[1024];
|
||||
|
||||
printf("Auth token is valid\n");
|
||||
|
||||
ClientRegistrationEvent* ev = malloc(sizeof(ClientContext));
|
||||
if(ev == NULL)
|
||||
{
|
||||
ClientRegistrationEvent* ev = malloc(sizeof(ClientRegistrationEvent));
|
||||
if (ev == NULL) {
|
||||
panic("Unable to allocate register event");
|
||||
}
|
||||
ev->regType = REG_EVTYPE_AUTH;
|
||||
ev->ctx = cctx;
|
||||
|
||||
ws_set_connection_context(client, cctx);
|
||||
|
||||
|
||||
with_lock(&ctx->registerMutex)
|
||||
{
|
||||
printf("Writing auth event\n");
|
||||
int exitCode = ptQueuePush(ctx->regQueue, ev, errbuf);
|
||||
if(exitCode)
|
||||
{
|
||||
if (exitCode) {
|
||||
panic("Unable to push to reg queue: %s\n", errbuf);
|
||||
}
|
||||
}
|
||||
@@ -99,42 +107,38 @@ uint8_t handle_auth(ClientContext* cctx, ws_cli_conn_t client, const uint8_t* ms
|
||||
}
|
||||
|
||||
|
||||
LinkedListEntry* disconnectDueTimeout(EmulContext* emulContext, LinkedListEntry* clientEntry)
|
||||
LinkedListEntry* disconnectDueTimeout(
|
||||
EmulContext* emulContext, LinkedListEntry* clientEntry)
|
||||
{
|
||||
ClientContext* ctx = clientEntry->payload;
|
||||
ClientContext* cctx = clientEntry->payload;
|
||||
|
||||
uint64_t now = (uint64_t)time(NULL);
|
||||
if(now - ctx->connectedAt <= 30)
|
||||
{
|
||||
if (now - cctx->connectedAt <= 30) {
|
||||
return clientEntry->nextEntry;
|
||||
}
|
||||
|
||||
printf("Timeout on connection %lu\n", ctx->clientId);
|
||||
int ret = ws_close_client(ctx->clientId);
|
||||
if(ret == -1)
|
||||
{
|
||||
printf("Timeout on connection %lu\n", cctx->clientId);
|
||||
int ret = ws_close_client(cctx->clientId);
|
||||
if (ret == -1) {
|
||||
printf("Unable to close client\n");
|
||||
}
|
||||
LinkedListEntry* nextEntry = clientEntry->nextEntry;
|
||||
|
||||
removeLinkedListEntry(emulContext->clientsHead, clientEntry);
|
||||
clientEntry = nextEntry;
|
||||
*emulContext->utilizedFlag = 1;
|
||||
return clientEntry;
|
||||
return nextEntry;
|
||||
}
|
||||
|
||||
void handleOnClientAuthDone(ClientContext* ctx, EmulContext* emulContext)
|
||||
|
||||
void handleOnClientAuthDone(ClientContext* cctx, EmulContext* emulContext)
|
||||
{
|
||||
uint8_t* framedata = malloc(sizeof(uint8_t) * 8);
|
||||
NULL_GUARD(framedata);
|
||||
|
||||
encodeUintToBytes(ctx->clientId, framedata);
|
||||
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, framedata, 8);
|
||||
|
||||
|
||||
// Send AuthResponse with assigned seat_id
|
||||
size_t len = 0;
|
||||
uint8_t* msg = createControlNotifyMessage((uint64_t)~0, *emulContext->clockCounter, *emulContext->emulState, &len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, msg, len);
|
||||
uint8_t* authResp = fb_build_auth_response(UINT64_MAX, cctx->clientId, &len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, cctx->clientId, authResp, len);
|
||||
|
||||
// Send current execution state
|
||||
len = 0;
|
||||
uint8_t* stateMsg = fb_build_exec_notify(
|
||||
UINT64_MAX, *emulContext->clockCounter, *emulContext->emulState, &len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, cctx->clientId, stateMsg, len);
|
||||
}
|
||||
@@ -1,33 +1,107 @@
|
||||
#include "proto/handlers/control.h"
|
||||
|
||||
#include "proto/pack.h"
|
||||
#include "proto/enums.h"
|
||||
#include "panic.h"
|
||||
#include <stdio.h>
|
||||
#include "state.h"
|
||||
#include "proto/msg.h"
|
||||
#include "proto/dial.h"
|
||||
|
||||
#include "control_reader.h"
|
||||
#include "exec_ctrl_reader.h"
|
||||
#include "setup_buf_reader.h"
|
||||
#include "orphaned_reader.h"
|
||||
#include "lost_reader.h"
|
||||
|
||||
|
||||
|
||||
|
||||
void handleIncomingControlMessage(BaseMessage* msg, EmulContext* emulContext)
|
||||
// Maps FlatBuffers ExecPrompt values to EMUL_STATE_OP_* constants.
|
||||
// ExecPrompt: start=1, pause=2, resume=3, stop=4, reset=5
|
||||
// EMUL_STATE_OP: START=1, PAUSE=2, RESUME=3, RESET=4, STOP=5
|
||||
static uint8_t prompt_to_state_op(hmmmm_ctrl_exec_ExecPrompt_enum_t prompt)
|
||||
{
|
||||
if(msg->payloadHeader == CTRL_TYPE_EXEC)
|
||||
{
|
||||
printf("ctrl exec\n");
|
||||
uint8_t stateOp = ((const uint8_t*)(msg->payload))[0];
|
||||
printf("state operation: %u\n", stateOp);
|
||||
uint8_t newEmulState = switchNewEmulState(*emulContext->emulState, stateOp);
|
||||
if(newEmulState != *emulContext->emulState)
|
||||
{
|
||||
printf("Switch state %u -> %u\n", *emulContext->emulState, newEmulState);
|
||||
*emulContext->emulState = newEmulState;
|
||||
|
||||
size_t len = 0;
|
||||
uint8_t* notify = createControlNotifyMessage(msg->nonce, *emulContext->clockCounter, newEmulState, &len);
|
||||
broadcastClients(emulContext, notify, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid payload header: %u\n", msg->payloadHeader);
|
||||
switch (prompt) {
|
||||
case hmmmm_ctrl_exec_ExecPrompt_start: return EMUL_STATE_OP_START;
|
||||
case hmmmm_ctrl_exec_ExecPrompt_pause: return EMUL_STATE_OP_PAUSE;
|
||||
case hmmmm_ctrl_exec_ExecPrompt_resume: return EMUL_STATE_OP_RESUME;
|
||||
case hmmmm_ctrl_exec_ExecPrompt_stop: return EMUL_STATE_OP_STOP;
|
||||
case hmmmm_ctrl_exec_ExecPrompt_reset: return EMUL_STATE_OP_RESET;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleIncomingCtrlMessage(
|
||||
hmmmm_ctrl_CtrlClientMessage_table_t msg,
|
||||
uint64_t nonce,
|
||||
ClientContext* ctx,
|
||||
EmulContext* emulContext)
|
||||
{
|
||||
hmmmm_ctrl_CtrlClientPayload_union_type_t ptype =
|
||||
hmmmm_ctrl_CtrlClientMessage_payload_type(msg);
|
||||
|
||||
printf("[CTRL] client=%lu nonce=%lu type=%s\n",
|
||||
ctx->clientId, nonce,
|
||||
hmmmm_ctrl_CtrlClientPayload_type_name(ptype));
|
||||
|
||||
if (ptype == hmmmm_ctrl_CtrlClientPayload_ExecCtrlMessage)
|
||||
{
|
||||
hmmmm_ctrl_exec_ExecCtrlMessage_table_t exec =
|
||||
(hmmmm_ctrl_exec_ExecCtrlMessage_table_t)
|
||||
hmmmm_ctrl_CtrlClientMessage_payload(msg);
|
||||
|
||||
hmmmm_ctrl_exec_ExecPrompt_enum_t prompt =
|
||||
hmmmm_ctrl_exec_ExecCtrlMessage_prompt(exec);
|
||||
|
||||
printf("[CTRL/EXEC] prompt=%s\n", hmmmm_ctrl_exec_ExecPrompt_name(prompt));
|
||||
|
||||
uint8_t state_op = prompt_to_state_op(prompt);
|
||||
if (state_op == 0) {
|
||||
printf("[CTRL/EXEC] unknown prompt, ignoring\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t new_state = switchNewEmulState(*emulContext->emulState, state_op);
|
||||
*emulContext->emulState = new_state;
|
||||
printf("[CTRL/EXEC] state -> %u\n", new_state);
|
||||
|
||||
size_t msg_len;
|
||||
uint8_t* out = fb_build_exec_notify(0, *emulContext->clockCounter, new_state, &msg_len);
|
||||
broadcastClients(emulContext, out, msg_len);
|
||||
}
|
||||
else if (ptype == hmmmm_ctrl_CtrlClientPayload_SetupBuf)
|
||||
{
|
||||
hmmmm_ctrl_setup_buf_SetupBuf_table_t sb =
|
||||
(hmmmm_ctrl_setup_buf_SetupBuf_table_t)
|
||||
hmmmm_ctrl_CtrlClientMessage_payload(msg);
|
||||
|
||||
uint32_t lost_buf_size = hmmmm_ctrl_setup_buf_SetupBuf_lost_buf_size(sb);
|
||||
uint64_t lifetime_ticks = hmmmm_ctrl_setup_buf_SetupBuf_client_lifetime_ticks(sb);
|
||||
|
||||
printf("[CTRL/SETUP] lost_buf_size=%u lifetime_ticks=%lu\n",
|
||||
lost_buf_size, lifetime_ticks);
|
||||
|
||||
size_t msg_len;
|
||||
uint8_t* out = fb_build_setup_buf(nonce, lost_buf_size, lifetime_ticks, &msg_len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len);
|
||||
}
|
||||
else if (ptype == hmmmm_ctrl_CtrlClientPayload_OrphanedRequest)
|
||||
{
|
||||
printf("[CTRL/ORPHANED] returning empty list\n");
|
||||
|
||||
size_t msg_len;
|
||||
uint8_t* out = fb_build_orphaned_response(nonce, &msg_len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len);
|
||||
}
|
||||
else if (ptype == hmmmm_ctrl_CtrlClientPayload_LostMessagesRequest)
|
||||
{
|
||||
hmmmm_ctrl_lost_LostMessagesRequest_table_t req =
|
||||
(hmmmm_ctrl_lost_LostMessagesRequest_table_t)
|
||||
hmmmm_ctrl_CtrlClientMessage_payload(msg);
|
||||
|
||||
uint64_t seat_id = hmmmm_ctrl_lost_LostMessagesRequest_seat_id(req);
|
||||
|
||||
printf("[CTRL/LOST] seat_id=%lu returning empty list\n", seat_id);
|
||||
|
||||
size_t msg_len;
|
||||
uint8_t* out = fb_build_lost_messages_response(nonce, seat_id, &msg_len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,92 @@
|
||||
#include "proto/handlers/mem.h"
|
||||
#include "proto/enums.h"
|
||||
#include "proto/pack.h"
|
||||
#include "panic.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "proto/msg.h"
|
||||
#include "proto/dial.h"
|
||||
#include "mem_reader.h"
|
||||
|
||||
#define DEVICE_MEM_SIZE ((size_t)(128 * 1024))
|
||||
|
||||
|
||||
uint8_t* createMemReadResponseMessage(uint64_t nonce, uint64_t clockCounter, uint8_t* payload, size_t payloadLen, size_t* lenOut)
|
||||
void handleIncomingMemMessage(
|
||||
hmmmm_mem_MemClientMessage_table_t msg,
|
||||
uint64_t nonce,
|
||||
ClientContext* ctx,
|
||||
EmulContext* emulContext)
|
||||
{
|
||||
*lenOut = 9 + 8 + payloadLen;
|
||||
uint8_t* outmsg = malloc(sizeof(uint8_t) * (*lenOut));
|
||||
NULL_GUARD(outmsg);
|
||||
hmmmm_mem_MemClientPayload_union_type_t ptype =
|
||||
hmmmm_mem_MemClientMessage_payload_type(msg);
|
||||
|
||||
encodeUintToBytes(nonce, outmsg);
|
||||
printf("[MEM] client=%lu nonce=%lu type=%s\n",
|
||||
ctx->clientId, nonce,
|
||||
hmmmm_mem_MemClientPayload_type_name(ptype));
|
||||
|
||||
outmsg[8] = PACKET_TYPE_MEM << 4;
|
||||
outmsg[8] |= MEM_TYPE_READ_RESP;
|
||||
|
||||
encodeUintToBytes(clockCounter, outmsg + 9);
|
||||
|
||||
memcpy(outmsg + 9 + 8, payload, payloadLen);
|
||||
|
||||
return outmsg;
|
||||
}
|
||||
|
||||
void handleIncomingMemReadReq(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext)
|
||||
{
|
||||
uint64_t devId = decodeBytesToU64(msg->payload);
|
||||
uint64_t segId = decodeBytesToU64(msg->payload + 8);
|
||||
uint64_t startAddr = decodeBytesToU64(msg->payload + 16);
|
||||
uint64_t readLen = decodeBytesToU64(msg->payload + 24);
|
||||
|
||||
if(devId >= emulContext->devicesCount)
|
||||
if (ptype == hmmmm_mem_MemClientPayload_MemReadRequest)
|
||||
{
|
||||
hmmmm_mem_MemReadRequest_table_t req =
|
||||
(hmmmm_mem_MemReadRequest_table_t)
|
||||
hmmmm_mem_MemClientMessage_payload(msg);
|
||||
|
||||
uint32_t dev_id = hmmmm_mem_MemReadRequest_device_id(req);
|
||||
uint32_t seg_id = hmmmm_mem_MemReadRequest_seg_id(req);
|
||||
uint32_t offset = hmmmm_mem_MemReadRequest_offset(req);
|
||||
uint32_t length = hmmmm_mem_MemReadRequest_length(req);
|
||||
|
||||
printf("[MEM/READ] device=%u seg=%u offset=%u len=%u\n",
|
||||
dev_id, seg_id, offset, length);
|
||||
|
||||
if (dev_id >= (uint32_t)emulContext->devicesCount) {
|
||||
printf("[MEM/READ] invalid device %u\n", dev_id);
|
||||
return;
|
||||
}
|
||||
if ((size_t)offset + (size_t)length > DEVICE_MEM_SIZE) {
|
||||
printf("[MEM/READ] out of bounds\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//TODO: lookup config for global addr conversion
|
||||
uint64_t globalAddr = startAddr + segId * 128;
|
||||
|
||||
uint8_t* readPtr = emulContext->devicesMem[devId] + globalAddr;
|
||||
|
||||
size_t outLen = 0;
|
||||
uint8_t* outMsg = createMemReadResponseMessage(msg->nonce, *emulContext->clockCounter, readPtr, readLen, &outLen);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, outMsg, outLen);
|
||||
}
|
||||
|
||||
|
||||
void handleIncomingMemWrite(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext)
|
||||
{
|
||||
uint64_t devId = decodeBytesToU64(msg->payload);
|
||||
uint64_t segId = decodeBytesToU64(msg->payload + 8);
|
||||
uint64_t startAddr = decodeBytesToU64(msg->payload + 16);
|
||||
|
||||
if(devId >= emulContext->devicesCount)
|
||||
const uint8_t* base = emulContext->devicesMem[dev_id];
|
||||
size_t out_len;
|
||||
uint8_t* out = fb_build_mem_read_response(
|
||||
nonce, *emulContext->clockCounter,
|
||||
dev_id, seg_id, offset,
|
||||
base + offset, (size_t)length,
|
||||
&out_len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, out_len);
|
||||
}
|
||||
else if (ptype == hmmmm_mem_MemClientPayload_MemWriteRequest)
|
||||
{
|
||||
hmmmm_mem_MemWriteRequest_table_t req =
|
||||
(hmmmm_mem_MemWriteRequest_table_t)
|
||||
hmmmm_mem_MemClientMessage_payload(msg);
|
||||
|
||||
uint32_t dev_id = hmmmm_mem_MemWriteRequest_device_id(req);
|
||||
uint32_t seg_id = hmmmm_mem_MemWriteRequest_seg_id(req);
|
||||
uint32_t offset = hmmmm_mem_MemWriteRequest_offset(req);
|
||||
flatbuffers_uint8_vec_t data = hmmmm_mem_MemWriteRequest_data(req);
|
||||
size_t data_len = flatbuffers_uint8_vec_len(data);
|
||||
|
||||
printf("[MEM/WRITE] device=%u seg=%u offset=%u len=%zu\n",
|
||||
dev_id, seg_id, offset, data_len);
|
||||
|
||||
if (dev_id >= (uint32_t)emulContext->devicesCount) {
|
||||
printf("[MEM/WRITE] invalid device %u\n", dev_id);
|
||||
return;
|
||||
}
|
||||
if ((size_t)offset + data_len > DEVICE_MEM_SIZE) {
|
||||
printf("[MEM/WRITE] out of bounds\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: lookup config for global addr conversion
|
||||
uint64_t globalAddr = startAddr + segId * 128;
|
||||
uint8_t* base = emulContext->devicesMem[dev_id];
|
||||
memcpy(base + offset, data, data_len);
|
||||
|
||||
uint8_t* writePtr = emulContext->devicesMem[devId] + globalAddr;
|
||||
|
||||
memcpy(writePtr, msg->payload + 24, msg->payloadLen - 24);
|
||||
}
|
||||
|
||||
|
||||
void handleIncomingMemMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext)
|
||||
{
|
||||
if(msg->payloadHeader == MEM_TYPE_READ_REQ)
|
||||
{
|
||||
handleIncomingMemReadReq(msg, ctx, emulContext);
|
||||
}
|
||||
else if(msg->payloadHeader == MEM_TYPE_WRITE_PUSH)
|
||||
{
|
||||
handleIncomingMemWrite(msg, ctx, emulContext);
|
||||
size_t out_len;
|
||||
uint8_t* out = fb_build_mem_read_response(
|
||||
nonce, *emulContext->clockCounter,
|
||||
dev_id, seg_id, offset,
|
||||
base + offset, data_len,
|
||||
&out_len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, out_len);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,31 @@
|
||||
#include "proto/handlers/stream.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "streamed.h"
|
||||
#include "proto/pack.h"
|
||||
#include "proto/enums.h"
|
||||
#include "panic.h"
|
||||
#include "proto/msg.h"
|
||||
#include "proto/dial.h"
|
||||
|
||||
#include "stream_reader.h"
|
||||
#include "stream_reg_reader.h"
|
||||
|
||||
|
||||
// ── Stream registration bookkeeping (unchanged logic) ────────────────────────
|
||||
|
||||
void unregisterClientStream(EmulContext* emulContext, ClientContext* ctx, uint32_t regId)
|
||||
void unregisterClientStream(
|
||||
EmulContext* emulContext, ClientContext* ctx, uint32_t regId)
|
||||
{
|
||||
for(size_t deviceId = 0; deviceId < emulContext->devicesCount; deviceId++)
|
||||
{
|
||||
for (size_t deviceId = 0; deviceId < emulContext->devicesCount; deviceId++) {
|
||||
DeviceSegStreamReg* deviceRegs = emulContext->deviceStreamRegs[deviceId];
|
||||
for(size_t i = 0; i < deviceRegs->regCount; i++)
|
||||
{
|
||||
for (size_t i = 0; i < deviceRegs->regCount; i++) {
|
||||
StreamReg* iReg = &deviceRegs->regs[i];
|
||||
if(iReg->clientContext->clientId == ctx->clientId && iReg->regId == regId)
|
||||
{
|
||||
printf("Discard stream %u register for client %lu\n", regId, ctx->clientId);
|
||||
deviceRegs->regCount -= 1;
|
||||
for(size_t j = i; j < deviceRegs->regCount; j++)
|
||||
if (iReg->clientContext->clientId == ctx->clientId
|
||||
&& iReg->regId == regId)
|
||||
{
|
||||
printf("Discard stream %u for client %lu\n", regId, ctx->clientId);
|
||||
deviceRegs->regCount--;
|
||||
for (size_t j = i; j < deviceRegs->regCount; j++) {
|
||||
deviceRegs->regs[j] = deviceRegs->regs[j + 1];
|
||||
}
|
||||
break;
|
||||
@@ -31,94 +36,112 @@ void unregisterClientStream(EmulContext* emulContext, ClientContext* ctx, uint32
|
||||
|
||||
void unregisterClientStreams(EmulContext* emulContext, ClientContext* ctx)
|
||||
{
|
||||
for(size_t deviceId = 0; deviceId < emulContext->devicesCount; deviceId++)
|
||||
{
|
||||
for (size_t deviceId = 0; deviceId < emulContext->devicesCount; deviceId++) {
|
||||
DeviceSegStreamReg* deviceRegs = emulContext->deviceStreamRegs[deviceId];
|
||||
|
||||
StreamReg* newStreamRegs = malloc(sizeof(StreamReg) * deviceRegs->regCount);
|
||||
NULL_GUARD(newStreamRegs);
|
||||
size_t newStreamRegsId = 0;
|
||||
StreamReg* newRegs = malloc(sizeof(StreamReg) * deviceRegs->regCount);
|
||||
NULL_GUARD(newRegs);
|
||||
size_t newCount = 0;
|
||||
|
||||
for(size_t i = 0; i < deviceRegs->regCount; i++)
|
||||
{
|
||||
for (size_t i = 0; i < deviceRegs->regCount; i++) {
|
||||
StreamReg* reg = &deviceRegs->regs[i];
|
||||
if(reg->clientContext->clientId != ctx->clientId)
|
||||
{
|
||||
newStreamRegs[newStreamRegsId] = *reg;
|
||||
newStreamRegsId++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Removing reg %d mode stream for %lu/%lu+%lu: [%u]\n", reg->mode, deviceId, reg->startAddr, reg->segLen, reg->regId);
|
||||
if (reg->clientContext->clientId != ctx->clientId) {
|
||||
newRegs[newCount++] = *reg;
|
||||
} else {
|
||||
printf("Removing stream reg [%u] for client %lu\n",
|
||||
reg->regId, ctx->clientId);
|
||||
}
|
||||
}
|
||||
free(deviceRegs->regs);
|
||||
deviceRegs->regCount = newStreamRegsId;
|
||||
deviceRegs->regs = newStreamRegs;
|
||||
deviceRegs->regCount = newCount;
|
||||
deviceRegs->regs = newRegs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleStreamRegMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext, uint8_t X)
|
||||
{
|
||||
uint64_t devId = decodeBytesToU64(msg->payload);
|
||||
uint64_t segId = decodeBytesToU64(msg->payload + 8);
|
||||
uint64_t startAddr = decodeBytesToU64(msg->payload + 16);
|
||||
uint64_t segLen = decodeBytesToU64(msg->payload + 24);
|
||||
// ── Incoming stream messages ──────────────────────────────────────────────────
|
||||
|
||||
if(devId >= emulContext->devicesCount)
|
||||
void handleIncomingStreamMessage(
|
||||
hmmmm_stream_StreamClientMessage_table_t msg,
|
||||
uint64_t nonce,
|
||||
ClientContext* ctx,
|
||||
EmulContext* emulContext)
|
||||
{
|
||||
hmmmm_stream_StreamClientPayload_union_type_t ptype =
|
||||
hmmmm_stream_StreamClientMessage_payload_type(msg);
|
||||
|
||||
printf("[STREAM] client=%lu nonce=%lu type=%s\n",
|
||||
ctx->clientId, nonce,
|
||||
hmmmm_stream_StreamClientPayload_type_name(ptype));
|
||||
|
||||
if (ptype == hmmmm_stream_StreamClientPayload_StreamRegRequest)
|
||||
{
|
||||
hmmmm_stream_StreamRegRequest_table_t req =
|
||||
(hmmmm_stream_StreamRegRequest_table_t)
|
||||
hmmmm_stream_StreamClientMessage_payload(msg);
|
||||
|
||||
uint32_t dev_id = hmmmm_stream_StreamRegRequest_device_id(req);
|
||||
uint32_t seg_id = hmmmm_stream_StreamRegRequest_seg_id(req);
|
||||
uint32_t offset = hmmmm_stream_StreamRegRequest_offset(req);
|
||||
uint32_t length = hmmmm_stream_StreamRegRequest_length(req);
|
||||
hmmmm_stream_StreamMode_enum_t mode = hmmmm_stream_StreamRegRequest_mode(req);
|
||||
|
||||
printf("[STREAM/REG] device=%u seg=%u offset=%u len=%u mode=%d\n",
|
||||
dev_id, seg_id, offset, length, (int)mode);
|
||||
|
||||
if (dev_id >= (uint32_t)emulContext->devicesCount) {
|
||||
printf("[STREAM/REG] invalid device %u\n", dev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceSegStreamReg* deviceRegs = emulContext->deviceStreamRegs[devId];
|
||||
if(deviceRegs->regCount + 1 >= deviceRegs->allocatedSize)
|
||||
{
|
||||
size_t newAllocatedSize = deviceRegs->allocatedSize;
|
||||
if(newAllocatedSize <= deviceRegs->regCount + 1)
|
||||
{
|
||||
newAllocatedSize = deviceRegs->regCount + 1;
|
||||
}
|
||||
StreamReg* newRegs = realloc(deviceRegs->regs, sizeof(StreamReg) * newAllocatedSize);
|
||||
NULL_GUARD(newRegs);
|
||||
deviceRegs->allocatedSize = newAllocatedSize;
|
||||
deviceRegs->regs = newRegs;
|
||||
DeviceSegStreamReg* deviceRegs = emulContext->deviceStreamRegs[dev_id];
|
||||
|
||||
if (deviceRegs->regCount >= deviceRegs->allocatedSize) {
|
||||
size_t new_size = deviceRegs->allocatedSize * 2;
|
||||
StreamReg* new_regs = realloc(deviceRegs->regs, sizeof(StreamReg) * new_size);
|
||||
NULL_GUARD(new_regs);
|
||||
deviceRegs->regs = new_regs;
|
||||
deviceRegs->allocatedSize = new_size;
|
||||
}
|
||||
|
||||
//TODO: lookup config for global segment addr conversion
|
||||
uint64_t globalStartAddr = startAddr + segId * 128;
|
||||
|
||||
StreamReg* reg = &deviceRegs->regs[deviceRegs->regCount];
|
||||
|
||||
uint32_t reg_id = ctx->streamRegIterator++;
|
||||
StreamReg* reg = &deviceRegs->regs[deviceRegs->regCount++];
|
||||
reg->clientContext = ctx;
|
||||
reg->segLen = segLen;
|
||||
reg->startAddr = globalStartAddr;
|
||||
reg->regId = ctx->streamRegIterator;
|
||||
reg->mode = X;
|
||||
reg->regId = reg_id;
|
||||
reg->startAddr = (uint64_t)offset;
|
||||
reg->segLen = (uint64_t)length;
|
||||
reg->mode = (uint8_t)mode;
|
||||
|
||||
ctx->streamRegIterator++;
|
||||
deviceRegs->regCount++;
|
||||
printf("[STREAM/REG] assigned reg_id=%u to client=%lu\n", reg_id, ctx->clientId);
|
||||
|
||||
printf("Done registering %d mode stream for %lu/%lu+%lu: [%u]\n", X, devId, globalStartAddr, segLen, reg->regId);
|
||||
|
||||
size_t len = 0;
|
||||
uint8_t* notifMsg = createDoneRegMessage(msg->nonce, X, devId, segId, startAddr, segLen, reg->regId, &len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, notifMsg, len);
|
||||
|
||||
}
|
||||
|
||||
void handleIncomingStreamMessage(BaseMessage* msg, ClientContext* ctx, EmulContext* emulContext)
|
||||
{
|
||||
uint8_t X = msg->payloadHeader >> 3;
|
||||
uint8_t streamType = msg->payloadHeader & 0b111;
|
||||
|
||||
if(streamType == STREAM_TYPE_REG_REQUEST)
|
||||
{
|
||||
handleStreamRegMessage(msg, ctx, emulContext, X);
|
||||
size_t msg_len;
|
||||
uint8_t* out = fb_build_stream_reg_confirm(
|
||||
nonce, reg_id, dev_id, seg_id, offset, length, (uint8_t)mode, &msg_len);
|
||||
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len);
|
||||
}
|
||||
else if(streamType == STREAM_TYPE_REG_DISCARD)
|
||||
else if (ptype == hmmmm_stream_StreamClientPayload_StreamDeregRequest)
|
||||
{
|
||||
uint32_t regId = decodeBytesToU32(msg->payload);
|
||||
unregisterClientStream(emulContext, ctx, regId);
|
||||
hmmmm_stream_StreamDeregRequest_table_t req =
|
||||
(hmmmm_stream_StreamDeregRequest_table_t)
|
||||
hmmmm_stream_StreamClientMessage_payload(msg);
|
||||
|
||||
uint32_t stream_id = hmmmm_stream_StreamDeregRequest_stream_id(req);
|
||||
printf("[STREAM/DEREG] stream_id=%u\n", stream_id);
|
||||
|
||||
unregisterClientStream(emulContext, ctx, stream_id);
|
||||
}
|
||||
else if (ptype == hmmmm_stream_StreamClientPayload_StreamWritePush)
|
||||
{
|
||||
hmmmm_stream_StreamWritePush_table_t push =
|
||||
(hmmmm_stream_StreamWritePush_table_t)
|
||||
hmmmm_stream_StreamClientMessage_payload(msg);
|
||||
|
||||
printf("[STREAM/WRITE] stream_id=%u offset=%u len=%zu\n",
|
||||
hmmmm_stream_StreamWritePush_stream_id(push),
|
||||
hmmmm_stream_StreamWritePush_offset(push),
|
||||
flatbuffers_uint8_vec_len(
|
||||
hmmmm_stream_StreamWritePush_data(push)));
|
||||
|
||||
// TODO: apply write to device memory
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
#include "proto/handlers/ws.h"
|
||||
#include "proto/handlers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "panic.h"
|
||||
#include "proto/enums.h"
|
||||
#include "my_mutex.h"
|
||||
#include "proto/enums.h"
|
||||
#include "proto/handlers/auth.h"
|
||||
#include "proto/msg.h"
|
||||
|
||||
#include "proto_verifier.h"
|
||||
#include "proto_reader.h"
|
||||
|
||||
|
||||
void onWsOpen(ws_cli_conn_t client)
|
||||
{
|
||||
char errbuf[1024];
|
||||
@@ -15,12 +20,10 @@ void onWsOpen(ws_cli_conn_t client)
|
||||
NULL_GUARD(incomeQueue, "Unable to create income queue: %s\n", errbuf);
|
||||
|
||||
ptQueue* outcomeQueue = ptQueueCreate(errbuf);
|
||||
|
||||
NULL_GUARD(outcomeQueue, "Unable to create outcome queue: %s\n", errbuf);
|
||||
|
||||
ClientContext* cctx = malloc(sizeof(ClientContext));
|
||||
if(cctx == NULL)
|
||||
{
|
||||
if (cctx == NULL) {
|
||||
ptQueueFree(incomeQueue);
|
||||
ptQueueFree(outcomeQueue);
|
||||
panic("Unable to allocate client context\n");
|
||||
@@ -32,13 +35,11 @@ void onWsOpen(ws_cli_conn_t client)
|
||||
cctx->outcomeQ = outcomeQueue;
|
||||
cctx->connectedAt = (uint64_t)time(NULL);
|
||||
|
||||
ClientRegistrationEvent* ev = malloc(sizeof(ClientContext));
|
||||
if(ev == NULL)
|
||||
{
|
||||
ClientRegistrationEvent* ev = malloc(sizeof(ClientRegistrationEvent));
|
||||
if (ev == NULL) {
|
||||
ptQueueFree(incomeQueue);
|
||||
ptQueueFree(outcomeQueue);
|
||||
free(cctx);
|
||||
|
||||
panic("Unable to allocate register event");
|
||||
}
|
||||
ev->regType = REG_EVTYPE_CONNECT;
|
||||
@@ -51,90 +52,87 @@ void onWsOpen(ws_cli_conn_t client)
|
||||
with_lock(&ctx->registerMutex)
|
||||
{
|
||||
int exitCode = ptQueuePush(ctx->regQueue, ev, errbuf);
|
||||
if(exitCode)
|
||||
{
|
||||
if (exitCode) {
|
||||
ptQueueFree(incomeQueue);
|
||||
ptQueueFree(outcomeQueue);
|
||||
free(cctx);
|
||||
|
||||
panic("Unable to push to reg queue: %s\n", errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
char *cli;
|
||||
cli = ws_getaddress(client);
|
||||
char* cli = ws_getaddress(client);
|
||||
printf("Connection %lu opened, addr: %s\n", client, cli);
|
||||
}
|
||||
|
||||
|
||||
void onWsClose(ws_cli_conn_t client)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
char *cli;
|
||||
cli = ws_getaddress(client);
|
||||
printf("Connection %lu closed, addr: %s, thread id: %lu\n", client, cli, tid);
|
||||
|
||||
char* cli = ws_getaddress(client);
|
||||
printf("Connection %lu closed, addr: %s\n", client, cli);
|
||||
|
||||
char errbuf[1024];
|
||||
|
||||
ClientContext* cctx = ws_get_connection_context(client);
|
||||
if(cctx == NULL)
|
||||
{
|
||||
cctx = NULL;
|
||||
printf("Unable to get client context\n");
|
||||
if (cctx == NULL) {
|
||||
printf("Unable to get client context for %lu\n", client);
|
||||
}
|
||||
|
||||
|
||||
ServerContext* ctx = ws_get_server_context(client);
|
||||
if(ctx == NULL)
|
||||
{
|
||||
printf("Unable to get server context\n");
|
||||
if (ctx == NULL) {
|
||||
printf("Unable to get server context for %lu\n", client);
|
||||
return;
|
||||
}
|
||||
|
||||
ClientRegistrationEvent* ev = malloc(sizeof(ClientContext));
|
||||
ClientRegistrationEvent* ev = malloc(sizeof(ClientRegistrationEvent));
|
||||
NULL_GUARD(ev);
|
||||
ev->regType = REG_EVTYPE_CLOSE;
|
||||
ev->ctx = cctx;
|
||||
|
||||
|
||||
with_lock(&ctx->registerMutex)
|
||||
{
|
||||
int exitCode = ptQueuePush(ctx->regQueue, ev, errbuf);
|
||||
if(exitCode)
|
||||
{
|
||||
if (exitCode) {
|
||||
panic("Unable to push to reg queue: %s\n", errbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void onWsMessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t size, int type)
|
||||
void onWsMessage(
|
||||
ws_cli_conn_t client, const unsigned char* msg, uint64_t size, int type)
|
||||
{
|
||||
ClientContext* cctx = ws_get_connection_context(client);
|
||||
if(cctx == NULL)
|
||||
{
|
||||
if (cctx == NULL) {
|
||||
panic("Unable to get client context\n");
|
||||
}
|
||||
|
||||
if (cctx->isAuthed == 0)
|
||||
{
|
||||
if (!cctx->isAuthed) {
|
||||
handle_auth(cctx, client, msg, size, type);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Verify the FlatBuffer before queuing
|
||||
if (hmmmm_ClientMessage_verify_as_root(msg, (size_t)size)) {
|
||||
printf("Client %lu sent invalid FlatBuffer, dropping\n", client);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy bytes — the WS buffer is only valid for this callback's duration
|
||||
FbMessage* fbmsg = malloc(sizeof(FbMessage));
|
||||
NULL_GUARD(fbmsg);
|
||||
fbmsg->data = malloc((size_t)size);
|
||||
if (fbmsg->data == NULL) {
|
||||
free(fbmsg);
|
||||
panic("Unable to allocate FbMessage buffer\n");
|
||||
}
|
||||
fbmsg->size = (size_t)size;
|
||||
memcpy(fbmsg->data, msg, (size_t)size);
|
||||
|
||||
char errbuf[1024];
|
||||
BaseMessage* baseMsg = parseMessage(msg, size);
|
||||
printf("msg\n");
|
||||
int isErr = ptQueuePush(cctx->incomeQ, baseMsg, errbuf);
|
||||
if(isErr)
|
||||
{
|
||||
panic("Unable to dispatch client message: %s\n", errbuf);
|
||||
}
|
||||
int isErr = ptQueuePush(cctx->incomeQ, fbmsg, errbuf);
|
||||
if (isErr) {
|
||||
free(fbmsg->data);
|
||||
free(fbmsg);
|
||||
panic("Unable to queue client message: %s\n", errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
273
src/proto/msg.c
273
src/proto/msg.c
@@ -1,85 +1,250 @@
|
||||
#include "proto/msg.h"
|
||||
#include "panic.h"
|
||||
|
||||
#include "proto/enums.h"
|
||||
#include "proto/pack.h"
|
||||
#include "flatcc/flatcc_builder.h"
|
||||
#include "proto_builder.h"
|
||||
#include "control_builder.h"
|
||||
#include "exec_notif_builder.h"
|
||||
#include "auth_builder.h"
|
||||
#include "stream_builder.h"
|
||||
#include "stream_data_builder.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
BaseMessage* parseMessage(const uint8_t* bytes, size_t size)
|
||||
uint8_t* fb_build_auth_response(uint64_t nonce, uint64_t seat_id, size_t* len_out)
|
||||
{
|
||||
const uint8_t headerSize = 9;
|
||||
BaseMessage* msg = malloc(sizeof(BaseMessage));
|
||||
NULL_GUARD(msg);
|
||||
uint64_t nonce = decodeBytesToU64(bytes);
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
hmmmm_auth_AuthResponse_ref_t ar =
|
||||
hmmmm_auth_AuthResponse_create(&B, seat_id);
|
||||
|
||||
msg->nonce = nonce;
|
||||
hmmmm_ServerPayload_union_ref_t payload =
|
||||
hmmmm_ServerPayload_as_AuthResponse(ar);
|
||||
|
||||
msg->packetType = bytes[8] >> 4;
|
||||
msg->payloadHeader = bytes[8] & 0b1111;
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, payload);
|
||||
|
||||
msg->payloadLen = size - headerSize;
|
||||
|
||||
uint8_t* payload = malloc(sizeof(uint8_t) * (msg->payloadLen));
|
||||
NULL_GUARD(payload);
|
||||
|
||||
memcpy(payload, bytes + headerSize, msg->payloadLen);
|
||||
msg->payload = payload;
|
||||
|
||||
return msg;
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* createControlNotifyMessage(uint64_t nonce, uint64_t clockCounter, uint8_t newEmulState, size_t* lenOut)
|
||||
uint8_t* fb_build_exec_notify(uint64_t nonce, uint64_t tclk, uint8_t state, size_t* len_out)
|
||||
{
|
||||
*lenOut = 9 + 10;
|
||||
uint8_t* outmsg = malloc(sizeof(uint8_t) * (*lenOut));
|
||||
NULL_GUARD(outmsg, "Unable to allocate message");
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
encodeUintToBytes(nonce, outmsg);
|
||||
hmmmm_ctrl_exec_notif_ExecNotifyMessage_ref_t notif =
|
||||
hmmmm_ctrl_exec_notif_ExecNotifyMessage_create(
|
||||
&B, tclk, (hmmmm_ctrl_exec_notif_ExecState_enum_t)(int8_t)state);
|
||||
|
||||
outmsg[8] = PACKET_TYPE_CTRL << 4;
|
||||
outmsg[8] |= CTRL_TYPE_NOTIF_STATE;
|
||||
hmmmm_ctrl_CtrlServerPayload_union_ref_t ctrl_payload =
|
||||
hmmmm_ctrl_CtrlServerPayload_as_ExecNotifyMessage(notif);
|
||||
|
||||
outmsg[9] = NOTIF_TYPE_EXEC;
|
||||
encodeUintToBytes(clockCounter, outmsg + 10);
|
||||
outmsg[18] = newEmulState;
|
||||
return outmsg;
|
||||
hmmmm_ctrl_CtrlServerMessage_ref_t ctrl_msg =
|
||||
hmmmm_ctrl_CtrlServerMessage_create(&B, ctrl_payload);
|
||||
|
||||
hmmmm_ServerPayload_union_ref_t payload =
|
||||
hmmmm_ServerPayload_as_CtrlServerMessage(ctrl_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, payload);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* createDoneRegMessage(uint64_t nonce, uint8_t X, uint64_t devId, uint64_t segId, uint64_t startAddr, uint64_t segLength, uint32_t regId, size_t* lenOut)
|
||||
uint8_t* fb_build_stream_data_push(
|
||||
flatcc_builder_t *B,
|
||||
uint64_t nonce, uint32_t stream_id, uint64_t tclk,
|
||||
const uint8_t* data, size_t data_len,
|
||||
size_t* len_out)
|
||||
{
|
||||
*lenOut = 36 + 9;
|
||||
uint8_t* outmsg = malloc(sizeof(uint8_t) * (*lenOut));
|
||||
NULL_GUARD(outmsg);
|
||||
flatcc_builder_reset(B);
|
||||
|
||||
encodeUintToBytes(nonce, outmsg);
|
||||
outmsg[8] = (uint8_t)((PACKET_TYPE_STREAM << 4) | (X << 3) | STREAM_TYPE_REG_CONFIRM);
|
||||
encodeUintToBytes(devId, outmsg + 9);
|
||||
encodeUintToBytes(segId, outmsg + 9 + 8);
|
||||
encodeUintToBytes(startAddr, outmsg + 9 + 8 + 8);
|
||||
encodeUintToBytes(segLength, outmsg + 9 + 8 + 8 + 8);
|
||||
encodeUintToBytes(regId, outmsg + 9 + 8 + 8 + 8 + 8);
|
||||
return outmsg;
|
||||
flatbuffers_uint8_vec_ref_t data_vec =
|
||||
flatbuffers_uint8_vec_create(B, data, data_len);
|
||||
|
||||
hmmmm_stream_StreamDataPush_ref_t push =
|
||||
hmmmm_stream_StreamDataPush_create(B, stream_id, tclk, data_vec);
|
||||
|
||||
hmmmm_stream_StreamServerPayload_union_ref_t stream_payload =
|
||||
hmmmm_stream_StreamServerPayload_as_StreamDataPush(push);
|
||||
|
||||
hmmmm_stream_StreamServerMessage_ref_t stream_msg =
|
||||
hmmmm_stream_StreamServerMessage_create(B, stream_payload);
|
||||
|
||||
hmmmm_ServerPayload_union_ref_t payload =
|
||||
hmmmm_ServerPayload_as_StreamServerMessage(stream_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(B, nonce, payload);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(B, len_out);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* createStreamSegmentPush(uint8_t mode, uint32_t regId, uint64_t clockCounter, uint8_t* payload, size_t payloadLen, size_t* lenOut)
|
||||
uint8_t* fb_build_setup_buf(uint64_t nonce, uint32_t lost_buf_size,
|
||||
uint64_t client_lifetime_ticks, size_t* len_out)
|
||||
{
|
||||
*lenOut = 9 + 4 + 8 + payloadLen;
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
uint8_t* outmsg = malloc(sizeof(uint8_t) * (*lenOut));
|
||||
NULL_GUARD(outmsg);
|
||||
hmmmm_ctrl_setup_buf_SetupBuf_ref_t sb =
|
||||
hmmmm_ctrl_setup_buf_SetupBuf_create(&B, lost_buf_size, client_lifetime_ticks);
|
||||
|
||||
uint64_t nonce = (uint64_t)~0;
|
||||
encodeUintToBytes(nonce, outmsg);
|
||||
outmsg[8] = (uint8_t)((PACKET_TYPE_STREAM << 4) | (mode << 3) | STREAM_TYPE_SEND);
|
||||
hmmmm_ctrl_CtrlServerPayload_union_ref_t ctrl_payload =
|
||||
hmmmm_ctrl_CtrlServerPayload_as_SetupBuf(sb);
|
||||
|
||||
encodeUintToBytes(regId, outmsg + 9);
|
||||
encodeUintToBytes(clockCounter, outmsg + 9 + 4);
|
||||
memcpy(outmsg + 9 + 4 + 8, payload, payloadLen);
|
||||
hmmmm_ctrl_CtrlServerMessage_ref_t ctrl_msg =
|
||||
hmmmm_ctrl_CtrlServerMessage_create(&B, ctrl_payload);
|
||||
|
||||
return outmsg;
|
||||
hmmmm_ServerPayload_union_ref_t setup_outer =
|
||||
hmmmm_ServerPayload_as_CtrlServerMessage(ctrl_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, setup_outer);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* fb_build_orphaned_response(uint64_t nonce, size_t* len_out)
|
||||
{
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
// Use start/end directly: passing 0 to _create causes entries_add to return -1
|
||||
hmmmm_ctrl_orphaned_OrphanedResponse_start(&B);
|
||||
hmmmm_ctrl_orphaned_OrphanedResponse_ref_t resp =
|
||||
hmmmm_ctrl_orphaned_OrphanedResponse_end(&B);
|
||||
|
||||
hmmmm_ctrl_CtrlServerPayload_union_ref_t ctrl_payload =
|
||||
hmmmm_ctrl_CtrlServerPayload_as_OrphanedResponse(resp);
|
||||
|
||||
hmmmm_ctrl_CtrlServerMessage_ref_t ctrl_msg =
|
||||
hmmmm_ctrl_CtrlServerMessage_create(&B, ctrl_payload);
|
||||
|
||||
hmmmm_ServerPayload_union_ref_t orphan_outer =
|
||||
hmmmm_ServerPayload_as_CtrlServerMessage(ctrl_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, orphan_outer);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* fb_build_lost_messages_response(uint64_t nonce, uint64_t seat_id, size_t* len_out)
|
||||
{
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
// Use start/end directly: passing 0 for messages vec causes messages_add to return -1
|
||||
hmmmm_ctrl_lost_LostMessagesResponse_start(&B);
|
||||
hmmmm_ctrl_lost_LostMessagesResponse_seat_id_add(&B, seat_id);
|
||||
hmmmm_ctrl_lost_LostMessagesResponse_ref_t resp =
|
||||
hmmmm_ctrl_lost_LostMessagesResponse_end(&B);
|
||||
|
||||
hmmmm_ctrl_CtrlServerPayload_union_ref_t ctrl_payload =
|
||||
hmmmm_ctrl_CtrlServerPayload_as_LostMessagesResponse(resp);
|
||||
|
||||
hmmmm_ctrl_CtrlServerMessage_ref_t ctrl_msg =
|
||||
hmmmm_ctrl_CtrlServerMessage_create(&B, ctrl_payload);
|
||||
|
||||
hmmmm_ServerPayload_union_ref_t lost_outer =
|
||||
hmmmm_ServerPayload_as_CtrlServerMessage(ctrl_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, lost_outer);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* fb_build_mem_read_response(
|
||||
uint64_t nonce, uint64_t tclk,
|
||||
uint32_t device_id, uint32_t seg_id, uint32_t offset,
|
||||
const uint8_t* data, size_t data_len,
|
||||
size_t* len_out)
|
||||
{
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
flatbuffers_uint8_vec_ref_t data_vec =
|
||||
flatbuffers_uint8_vec_create(&B, data, data_len);
|
||||
|
||||
hmmmm_mem_MemReadResponse_ref_t resp =
|
||||
hmmmm_mem_MemReadResponse_create(&B, tclk, device_id, seg_id, offset, data_vec);
|
||||
|
||||
hmmmm_mem_MemServerPayload_union_ref_t mem_payload =
|
||||
hmmmm_mem_MemServerPayload_as_MemReadResponse(resp);
|
||||
|
||||
hmmmm_mem_MemServerMessage_ref_t mem_msg =
|
||||
hmmmm_mem_MemServerMessage_create(&B, mem_payload);
|
||||
|
||||
hmmmm_ServerPayload_union_ref_t mem_outer =
|
||||
hmmmm_ServerPayload_as_MemServerMessage(mem_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, mem_outer);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* fb_build_stream_reg_confirm(
|
||||
uint64_t nonce, uint32_t stream_id,
|
||||
uint32_t device_id, uint32_t seg_id, uint32_t offset, uint32_t length,
|
||||
uint8_t mode, size_t* len_out)
|
||||
{
|
||||
flatcc_builder_t B;
|
||||
if (flatcc_builder_init(&B)) {
|
||||
panic("flatcc_builder_init failed\n");
|
||||
}
|
||||
|
||||
hmmmm_stream_StreamRegConfirm_ref_t confirm =
|
||||
hmmmm_stream_StreamRegConfirm_create(
|
||||
&B, stream_id, device_id, seg_id, offset, length,
|
||||
(hmmmm_stream_StreamMode_enum_t)(int8_t)mode);
|
||||
|
||||
hmmmm_stream_StreamServerPayload_union_ref_t sreg_payload =
|
||||
hmmmm_stream_StreamServerPayload_as_StreamRegConfirm(confirm);
|
||||
|
||||
hmmmm_stream_StreamServerMessage_ref_t sreg_msg =
|
||||
hmmmm_stream_StreamServerMessage_create(&B, sreg_payload);
|
||||
|
||||
hmmmm_ServerPayload_union_ref_t sreg_outer =
|
||||
hmmmm_ServerPayload_as_StreamServerMessage(sreg_msg);
|
||||
|
||||
hmmmm_ServerMessage_create_as_root(&B, nonce, sreg_outer);
|
||||
|
||||
uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out);
|
||||
flatcc_builder_clear(&B);
|
||||
NULL_GUARD(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user