#define HOST_CHANNEL_ID_NIL (N_ChannelId) { .gen = 0, .idx = 0 } #define HOST_CHANNEL_ID_ALL (N_ChannelId) { .gen = U32_MAX, .idx = U32_MAX } #define N_PacketMagic 0xd9e3b8b6 #define N_MaxPacketChunkLen 1024 #define N_MaxPacketLen 1280 /* Give enough space for msg chunk + header */ #define N_NumChannelLookupBins 512 #define N_NumMsgAssemblerLookupBins 16384 typedef i32 N_CmdKind; enum { HOST_CMD_KIND_NONE, HOST_CMD_KIND_TRY_CONNECT, HOST_CMD_KIND_CONNECT_SUCCESS, HOST_CMD_KIND_DISCONNECT, HOST_CMD_KIND_HEARTBEAT, HOST_CMD_KIND_WRITE }; typedef i32 N_EventKind; enum { HOST_EVENT_KIND_NONE, HOST_EVENT_KIND_CHANNEL_OPENED, HOST_EVENT_KIND_CHANNEL_CLOSED, HOST_EVENT_KIND_MSG }; typedef i32 N_WriteFlag; enum { HOST_WRITE_FLAG_NONE = 0, HOST_WRITE_FLAG_RELIABLE = (1 << 0) }; Struct(N_ChannelId) { u32 gen; u32 idx; }; Struct(N_Cmd) { N_CmdKind kind; N_ChannelId channel_id; u16 heartbeat_id; u16 heartbeat_ack_id; b32 write_reliable; String write_msg; N_Cmd *next; }; Struct(N_Event) { N_EventKind kind; N_ChannelId channel_id; String msg; N_Event *next; }; Struct(N_EventList) { N_Event *first; N_Event *last; }; Struct(N_ChannelLookupBin) { struct host_channel *first; struct host_channel *last; }; Struct(N_RcvBuffer) { Arena *arena; struct host_rcv_packet *first_packet; struct host_rcv_packet *last_packet; }; Struct(N_SndPacket) { N_SndPacket *next; u64 seq; u64 data_len; u8 data[N_MaxPacketLen]; }; Struct(N_Host) { Arena *arena; P_Sock *sock; BuddyCtx *buddy; /* For storing msg assembler data */ Arena *cmd_arena; N_Cmd *first_cmd; N_Cmd *last_cmd; N_Cmd *first_free_cmd; Arena *channel_arena; struct host_channel *channels; struct host_channel *first_free_channel; u64 num_channels_reserved; N_SndPacket *first_free_packet; /* Allocated in `arena` */ struct host_msg_assembler *first_free_msg_assembler; /* Allocated in `arena` */ N_ChannelLookupBin *channel_lookup_bins; /* Allocated in `arena` */ u64 num_channel_lookup_bins; struct host_msg_assembler_lookup_bin *msg_assembler_lookup_bins; /* Allocated in `arena` */ u64 num_msg_assembler_lookup_bins; /* Double buffer for incoming data */ P_Mutex rcv_buffer_write_mutex; N_RcvBuffer *rcv_buffer_read; N_RcvBuffer *rcv_buffer_write; u64 bytes_received; u64 bytes_sent; }; /* ========================== * * Startup * ========================== */ Struct(N_StartupReceipt) { i32 _; }; N_StartupReceipt host_startup(void); /* ========================== * * Host * ========================== */ N_Host *host_alloc(u16 listen_port); void host_release(N_Host *host); /* ========================== * * Queue * ========================== */ void host_queue_connect_to_address(N_Host *host, P_Address connect_address); void host_queue_disconnect(N_Host *host, N_ChannelId channel_id); void host_queue_write(N_Host *host, N_ChannelId channel_id, String msg, u32 flags); /* ========================== * * Info * ========================== */ i64 host_get_channel_last_rtt_ns(N_Host *host, N_ChannelId channel_id); INLINE b32 host_channel_id_eq(N_ChannelId a, N_ChannelId b) { return a.idx == b.idx && a.gen == b.gen; } INLINE b32 host_channel_id_is_nil(N_ChannelId id) { return id.gen == 0 && id.idx == 0; } /* ========================== * * Update * ========================== */ N_EventList host_update_begin(Arena *arena, N_Host *host); void host_update_end(N_Host *host);