power_play/src/net/net.h

319 lines
6.8 KiB
C

////////////////////////////////
//~ Channel ID
Struct(N_ChannelId)
{
u32 gen;
u32 idx;
};
////////////////////////////////
//~ Host command types
Enum(N_CmdKind)
{
N_CmdKind_None,
N_CmdKind_TryConnect,
N_CmdKind_ConnectSuccess,
N_CmdKind_Disconnect,
N_CmdKind_Heartbeat,
N_CmdKind_Write
};
Enum(N_WriteFlag)
{
N_WriteFlag_None = 0,
N_WriteFlag_Reliable = (1 << 0)
};
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;
};
////////////////////////////////
//~ Event types
Enum(N_EventKind)
{
N_EventKind_None,
N_EventKind_ChannelOpened,
N_EventKind_ChannelClosed,
N_EventKind_Msg
};
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 N_Channel *first;
struct N_Channel *last;
};
////////////////////////////////
//~ Packet types
#define N_PacketMagic 0xd9e3b8b6
#define N_MaxPacketChunkLen 1024
#define N_MaxPacketLen 1280 /* Give enough space for msg chunk + header */
Enum(N_PacketKind)
{
N_PacketKind_None,
N_PacketKind_TryConnect,
N_PacketKind_ConnectSuccess,
N_PacketKind_Disconnect,
N_PacketKind_Heartbeat,
N_PacketKind_MsgChunk
};
Enum(N_PacketFlag)
{
N_PacketFlag_None = 0,
N_PacketFlag_Reliable = (1 << 0)
};
Struct(N_SndPacket)
{
N_SndPacket *next;
u64 seq;
u64 data_len;
u8 data[N_MaxPacketLen];
};
Struct(N_RcvPacket)
{
P_Sock *sock;
P_Address address;
String data;
N_RcvPacket *next;
};
Struct(N_RcvBuffer)
{
Arena *arena;
N_RcvPacket *first_packet;
N_RcvPacket *last_packet;
};
////////////////////////////////
//~ Channel types
Struct(N_Channel)
{
N_ChannelId id;
b32 valid;
b32 connected;
struct N_Host *host;
N_Channel *next_free;
P_Address address;
u64 address_hash;
N_Channel *next_address_hash;
N_Channel *prev_address_hash;
/* NOTE: Packets are allocated in host's `arena` */
N_SndPacket *first_reliable_packet;
N_SndPacket *last_reliable_packet;
N_SndPacket *first_unreliable_packet;
N_SndPacket *last_unreliable_packet;
u64 num_reliable_packets;
u64 num_unreliable_packets;
/* NOTE: Msg assemblers are allocated in host's `arena` */
struct N_MsgAssembler *least_recent_msg_assembler;
struct N_MsgAssembler *most_recent_msg_assembler;
u16 last_heartbeat_received_id;
u16 last_heartbeat_acked_id;
i64 last_heartbeat_acked_ns;
i64 last_heartbeat_rtt_ns;
u64 last_sent_msg_id;
u64 their_acked_seq;
u64 our_acked_seq;
u64 last_sent_seq;
i64 last_packet_received_ns;
};
Struct(N_ChannelNode)
{
N_Channel *channel;
N_ChannelNode *next;
};
Struct(N_ChannelList)
{
N_ChannelNode *first;
N_ChannelNode *last;
};
////////////////////////////////
//~ Message asssembler types
Struct(N_MsgAssembler)
{
N_Channel *channel;
b32 is_reliable;
/* Free list */
N_MsgAssembler *next_free;
/* Bucket list */
N_MsgAssembler *next_hash;
N_MsgAssembler *prev_hash;
/* Channel list */
N_MsgAssembler *less_recent;
N_MsgAssembler *more_recent;
u64 msg_id;
u64 hash;
u64 last_chunk_len;
u64 num_chunks_total;
u64 num_chunks_received;
i64 touched_ns;
BuddyBlock *buddy_block;
u8 *chunk_bitmap;
u8 *chunk_data;
};
Struct(N_MsgAssemblerLookupBin)
{
N_MsgAssembler *first;
N_MsgAssembler *last;
};
////////////////////////////////
//~ Host types
#define N_NumChannelLookupBins 512
#define N_NumMsgAssemblerLookupBins 16384
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;
N_Channel *channels;
N_Channel *first_free_channel;
u64 num_channels_reserved;
N_SndPacket *first_free_packet; /* Acquired in `arena` */
N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */
N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */
u64 num_channel_lookup_bins;
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */
u64 num_msg_assembler_lookup_bins;
/* Double buffer for incoming data */
Mutex rcv_buffer_write_mutex;
N_RcvBuffer *rcv_buffer_read;
N_RcvBuffer *rcv_buffer_write;
u64 bytes_received;
u64 bytes_sent;
};
////////////////////////////////
//~ Nil constants
Readonly Global N_Channel N_nil_channel = { .valid = 0 };
////////////////////////////////
//~ Host initialization
N_Host *N_AcquireHost(u16 listen_port);
void N_ReleaseHost(N_Host *host);
////////////////////////////////
//~ Channel operations
#define N_NilChannelId (N_ChannelId) { .gen = 0, .idx = 0 }
#define N_AllChannelsId (N_ChannelId) { .gen = U32Max, .idx = U32Max }
#define N_EqChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
u64 N_HashFromAddress(P_Address address);
N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address);
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
N_Channel *N_AcquireChannel(N_Host *host, P_Address address);
void N_ReleaseChannel(N_Channel *channel);
////////////////////////////////
//~ Message assembler operations
u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_MsgAssemblerFromMsg(N_Host *host, N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_count, u64 now_ns, b32 is_reliable);
void N_ReleaseMessageAssembler(N_MsgAssembler *ma);
void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns);
b32 N_IsChunkFilled(N_MsgAssembler *ma, u64 chunk_id);
void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id);
////////////////////////////////
//~ Packet operations
N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable);
////////////////////////////////
//~ Host command operations
N_Cmd *N_PushCmd(N_Host *host);
void N_Connect(N_Host *host, P_Address connect_address);
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
////////////////////////////////
//~ Channel info operations
i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id);
////////////////////////////////
//~ Update
N_Event *N_PushEvent(Arena *arena, N_EventList *list);
N_EventList N_BeginUpdate(Arena *arena, N_Host *host);
void N_EndUpdate(N_Host *host);