user game network communication beginning to work
This commit is contained in:
parent
84e64b5cce
commit
808edf6e57
19
src/byteio.c
19
src/byteio.c
@ -164,6 +164,12 @@ void bw_write_v2(struct byte_writer *bw, struct v2 v)
|
||||
bw_write_f32(bw, v.y);
|
||||
}
|
||||
|
||||
void bw_write_string(struct byte_writer *bw, struct string str)
|
||||
{
|
||||
bw_write_var_uint(bw, str.len);
|
||||
bw_write_buffer(bw, str);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Reader
|
||||
* ========================== */
|
||||
@ -313,3 +319,16 @@ struct v2 br_read_v2(struct byte_reader *br)
|
||||
res.y = br_read_f32(br);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct string br_read_string(struct arena *arena, struct byte_reader *br)
|
||||
{
|
||||
struct string res = ZI;
|
||||
u64 len = br_read_var_uint(br);
|
||||
u8 *text = br_seek(br, len);
|
||||
if (text != NULL) {
|
||||
res.len = len;
|
||||
res.text = arena_push_array(arena, u8, len);
|
||||
MEMCPY(res.text, text, len);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ void bw_write_var_sint(struct byte_writer *bw, i64 v);
|
||||
void bw_write_f32(struct byte_writer *bw, f32 v);
|
||||
void bw_write_f64(struct byte_writer *bw, f64 v);
|
||||
void bw_write_v2(struct byte_writer *bw, struct v2 v);
|
||||
void bw_write_string(struct byte_writer *bw, struct string str);
|
||||
|
||||
/* Returns a string containing written bytes only */
|
||||
INLINE struct string bw_get_written(struct byte_writer *bw)
|
||||
@ -80,6 +81,7 @@ i64 br_read_var_sint(struct byte_reader *br);
|
||||
f32 br_read_f32(struct byte_reader *br);
|
||||
f64 br_read_f64(struct byte_reader *br);
|
||||
struct v2 br_read_v2(struct byte_reader *br);
|
||||
struct string br_read_string(struct arena *arena, struct byte_reader *br);
|
||||
|
||||
INLINE u64 br_bytes_left(const struct byte_reader *br)
|
||||
{
|
||||
|
||||
56
src/game.c
56
src/game.c
@ -72,8 +72,8 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
||||
G.client_store = client_store_alloc();
|
||||
|
||||
/* Intialize host */
|
||||
struct sock_address bind_address = sock_address_from_any_local_interface_with_port(12345);
|
||||
G.host = host_alloc(bind_address);
|
||||
//struct sock_address bind_address = sock_address_from_port(12345);
|
||||
G.host = host_alloc(12345);
|
||||
|
||||
/* Initialize empty world */
|
||||
reset_world();
|
||||
@ -1460,10 +1460,12 @@ struct string game_string_from_events(struct arena *arena, struct game_event_lis
|
||||
for (struct game_event *event = events.first; event; event = event->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
bw_write_i8(&bw, event->kind);
|
||||
|
||||
switch (event->kind) {
|
||||
case GAME_EVENT_KIND_SNAPSHOT_FULL:
|
||||
{
|
||||
bw_write_string(&bw, event->snapshot_data);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -1505,6 +1507,7 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h
|
||||
switch (game_event->kind) {
|
||||
case GAME_EVENT_KIND_SNAPSHOT_FULL:
|
||||
{
|
||||
game_event->snapshot_data = br_read_string(arena, &br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -1533,17 +1536,54 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h
|
||||
|
||||
struct string game_string_from_tick(struct arena *arena, struct world *tick)
|
||||
{
|
||||
(UNUSED)arena;
|
||||
(UNUSED)tick;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
|
||||
struct string res = ZI;
|
||||
return res;
|
||||
bw_write_var_uint(&bw, tick->continuity_gen);
|
||||
bw_write_var_uint(&bw, tick->tick_id);
|
||||
bw_write_var_sint(&bw, tick->publishtime_ns);
|
||||
|
||||
bw_write_f64(&bw, tick->timescale);
|
||||
bw_write_var_sint(&bw, tick->dt_ns);
|
||||
bw_write_var_sint(&bw, tick->time_ns);
|
||||
|
||||
u64 num_entities = tick->entity_store->reserved;
|
||||
bw_write_var_uint(&bw, num_entities);
|
||||
|
||||
struct string entities_src = ZI;
|
||||
entities_src.text = (u8 *)tick->entity_store->entities;
|
||||
entities_src.len = sizeof(struct entity) * num_entities;
|
||||
bw_write_buffer(&bw, entities_src);
|
||||
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void game_tick_from_string(struct string str, struct world *tick_out)
|
||||
{
|
||||
(UNUSED)str;
|
||||
(UNUSED)tick_out;
|
||||
struct byte_reader br = br_from_buffer(str);
|
||||
|
||||
tick_out->continuity_gen = br_read_var_uint(&br);
|
||||
tick_out->tick_id = br_read_var_uint(&br);
|
||||
tick_out->publishtime_ns = br_read_var_sint(&br);
|
||||
|
||||
tick_out->timescale = br_read_f64(&br);
|
||||
tick_out->dt_ns = br_read_var_sint(&br);
|
||||
tick_out->time_ns = br_read_var_sint(&br);
|
||||
|
||||
u64 num_entities = br_read_var_uint(&br);
|
||||
arena_push_array(&tick_out->entity_store->arena, struct entity, num_entities - tick_out->entity_store->reserved);
|
||||
tick_out->entity_store->reserved = num_entities;
|
||||
|
||||
struct entity *entities_src = br_seek(&br, num_entities * sizeof(struct entity));
|
||||
if (entities_src) {
|
||||
for (u64 i = 0; i < num_entities; ++i) {
|
||||
struct entity *src = &entities_src[i];
|
||||
struct entity *dst = &tick_out->entity_store->entities[i];
|
||||
*dst = *src;
|
||||
DEBUGBREAKABLE;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGBREAKABLE;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
69
src/host.c
69
src/host.c
@ -63,6 +63,7 @@ struct host_channel {
|
||||
struct host_msg_assembler *least_recent_msg_assembler;
|
||||
struct host_msg_assembler *most_recent_msg_assembler;
|
||||
|
||||
u64 last_sent_msg_id;
|
||||
u64 their_acked_seq;
|
||||
u64 our_acked_seq;
|
||||
};
|
||||
@ -151,7 +152,7 @@ struct host_startup_receipt host_startup(struct sock_startup_receipt *sock_sr)
|
||||
* Host
|
||||
* ========================== */
|
||||
|
||||
struct host *host_alloc(struct sock_address bind_address)
|
||||
struct host *host_alloc(u16 listen_port)
|
||||
{
|
||||
struct arena arena = arena_alloc(GIGABYTE(64));
|
||||
struct host *host = arena_push_zero(&arena, struct host);
|
||||
@ -163,10 +164,13 @@ struct host *host_alloc(struct sock_address bind_address)
|
||||
|
||||
host->channels = arena_dry_push(&host->channel_arena, struct host_channel);
|
||||
|
||||
host->channel_lookup_buckets = arena_push_array_zero(&host->arena, struct host_channel_lookup_bucket, NUM_CHANNEL_LOOKUP_BUCKETS);
|
||||
host->msg_assembler_lookup_buckets = arena_push_array_zero(&host->arena, struct host_msg_assembler_lookup_bucket, NUM_MSG_ASSEMBLER_LOOKUP_BUCKETS);
|
||||
host->num_channel_lookup_buckets = NUM_CHANNEL_LOOKUP_BUCKETS;
|
||||
host->channel_lookup_buckets = arena_push_array_zero(&host->arena, struct host_channel_lookup_bucket, host->num_channel_lookup_buckets);
|
||||
|
||||
host->sock = sock_alloc(bind_address, SOCK_FLAG_NON_BLOCKING);
|
||||
host->num_msg_assembler_lookup_buckets = NUM_MSG_ASSEMBLER_LOOKUP_BUCKETS;
|
||||
host->msg_assembler_lookup_buckets = arena_push_array_zero(&host->arena, struct host_msg_assembler_lookup_bucket, host->num_msg_assembler_lookup_buckets);
|
||||
|
||||
host->sock = sock_alloc(listen_port, SOCK_FLAG_NON_BLOCKING);
|
||||
|
||||
return host;
|
||||
}
|
||||
@ -219,7 +223,7 @@ INTERNAL struct host_channel_list host_channels_from_id(struct arena *arena, str
|
||||
if (host_channel_id_eq(channel_id, HOST_CHANNEL_ID_ALL)) {
|
||||
for (u64 i = 0; i < host->num_channels_reserved; ++i) {
|
||||
struct host_channel *channel = &host->channels[i];
|
||||
if (channel->valid && channel->connected) {
|
||||
if (channel->valid) {
|
||||
struct host_channel_node *n = arena_push_zero(arena, struct host_channel_node);
|
||||
n->channel = channel;
|
||||
if (res.last) {
|
||||
@ -258,6 +262,7 @@ INTERNAL struct host_channel *host_channel_alloc(struct host *host, struct sock_
|
||||
++host->num_channels_reserved;
|
||||
}
|
||||
MEMZERO_STRUCT(channel);
|
||||
channel->valid = true;
|
||||
channel->id = id;
|
||||
channel->host = host;
|
||||
channel->address = address;
|
||||
@ -378,6 +383,18 @@ INTERNAL struct host_msg_assembler *host_msg_assembler_alloc(struct host_channel
|
||||
}
|
||||
channel->most_recent_msg_assembler = ma;
|
||||
|
||||
/* Insert into lookup table */
|
||||
u64 hash = hash_from_channel_msg(channel->id, msg_id);
|
||||
ma->hash = hash;
|
||||
struct host_msg_assembler_lookup_bucket *bucket = &host->msg_assembler_lookup_buckets[hash % host->num_msg_assembler_lookup_buckets];
|
||||
if (bucket->last) {
|
||||
bucket->last->next_hash = ma;
|
||||
ma->prev_hash = bucket->last;
|
||||
} else {
|
||||
bucket->first = ma;
|
||||
}
|
||||
bucket->last = ma;
|
||||
|
||||
return ma;
|
||||
}
|
||||
|
||||
@ -386,7 +403,7 @@ INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma)
|
||||
struct host *host = ma->host;
|
||||
struct host_channel *channel = ma->channel;
|
||||
|
||||
/* FIXME: Data should be in a buddy allocator or something */
|
||||
/* FIXME: Data should be in buddy allocator or something */
|
||||
arena_release(&ma->testarena);
|
||||
|
||||
/* Release from channel list */
|
||||
@ -405,6 +422,24 @@ INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma)
|
||||
}
|
||||
}
|
||||
|
||||
/* Release from lookup table */
|
||||
struct host_msg_assembler_lookup_bucket *bucket = &host->msg_assembler_lookup_buckets[ma->hash % host->num_msg_assembler_lookup_buckets];
|
||||
{
|
||||
struct host_msg_assembler *prev = ma->prev_hash;
|
||||
struct host_msg_assembler *next = ma->next_hash;
|
||||
if (prev) {
|
||||
prev->next_hash = next;
|
||||
} else {
|
||||
bucket->first = next;
|
||||
}
|
||||
if (next) {
|
||||
next->prev_hash = prev;
|
||||
} else {
|
||||
bucket->last = prev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ma->next_free = host->first_free_msg_assembler;
|
||||
host->first_free_msg_assembler = ma;
|
||||
}
|
||||
@ -484,21 +519,17 @@ void host_queue_connect_to_address(struct host *host, struct sock_address connec
|
||||
|
||||
void host_queue_disconnect(struct host *host, struct host_channel_id channel_id)
|
||||
{
|
||||
(UNUSED)host;
|
||||
(UNUSED)channel_id;
|
||||
|
||||
struct host_cmd *cmd = host_cmd_alloc_and_append(host);
|
||||
cmd->kind = HOST_CMD_KIND_DISCONNECT;
|
||||
cmd->channel_id = channel_id;
|
||||
}
|
||||
|
||||
void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg)
|
||||
{
|
||||
(UNUSED)host;
|
||||
(UNUSED)channel_id;
|
||||
(UNUSED)msg;
|
||||
|
||||
struct host_cmd *cmd = host_cmd_alloc_and_append(host);
|
||||
cmd->kind = HOST_CMD_KIND_WRITE;
|
||||
cmd->channel_id = channel_id;
|
||||
cmd->write_msg = string_copy(&host->cmd_arena, msg);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
@ -596,6 +627,7 @@ void host_update(struct host *host)
|
||||
|
||||
case HOST_PACKET_KIND_MSG_CHUNK:
|
||||
{
|
||||
if (channel->valid) {
|
||||
/* Packet is chunk <chunk_id> out of <chunk_count> belonging to message <msg_id> */
|
||||
u64 msg_id = br_read_var_uint(&br);
|
||||
u64 chunk_id = br_read_var_uint(&br);
|
||||
@ -636,6 +668,7 @@ void host_update(struct host *host)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -696,6 +729,7 @@ void host_update(struct host *host)
|
||||
u8 packet_flags = 0;
|
||||
struct host_packet *host_packet = host_channel_packet_alloc(channel, false);
|
||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
||||
bw_write_u32(&bw, PACKET_MAGIC);
|
||||
bw_write_i8(&bw, HOST_PACKET_KIND_TRY_CONNECT);
|
||||
bw_write_u8(&bw, packet_flags);
|
||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
||||
@ -707,6 +741,7 @@ void host_update(struct host *host)
|
||||
u8 packet_flags = 0;
|
||||
struct host_packet *host_packet = host_channel_packet_alloc(channel, false);
|
||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
||||
bw_write_u32(&bw, PACKET_MAGIC);
|
||||
bw_write_i8(&bw, HOST_PACKET_KIND_CONNECT_SUCCESS);
|
||||
bw_write_u8(&bw, packet_flags);
|
||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
||||
@ -718,6 +753,7 @@ void host_update(struct host *host)
|
||||
u8 packet_flags = 0;
|
||||
struct host_packet *host_packet = host_channel_packet_alloc(channel, false);
|
||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
||||
bw_write_u32(&bw, PACKET_MAGIC);
|
||||
bw_write_i8(&bw, HOST_PACKET_KIND_DISCONNECT);
|
||||
bw_write_u8(&bw, packet_flags);
|
||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
||||
@ -736,6 +772,7 @@ void host_update(struct host *host)
|
||||
}
|
||||
chunk_count += 1;
|
||||
|
||||
u64 msg_id = ++channel->last_sent_msg_id;
|
||||
for (u64 i = 0; i < chunk_count; ++i) {
|
||||
u64 data_len = PACKET_CHUNK_MAX_LEN;
|
||||
b32 is_last_chunk = i + 1 == chunk_count;
|
||||
@ -745,12 +782,16 @@ void host_update(struct host *host)
|
||||
u8 *data = msg.text + (i * PACKET_CHUNK_MAX_LEN);
|
||||
struct host_packet *host_packet = host_channel_packet_alloc(channel, is_reliable);
|
||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
||||
bw_write_u32(&bw, PACKET_MAGIC);
|
||||
bw_write_i8(&bw, HOST_PACKET_KIND_MSG_CHUNK);
|
||||
bw_write_u8(&bw, packet_flags);
|
||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
||||
if (is_reliable) {
|
||||
bw_write_var_uint(&bw, host_packet->seq);
|
||||
}
|
||||
bw_write_var_uint(&bw, msg_id);
|
||||
bw_write_var_uint(&bw, i);
|
||||
bw_write_var_uint(&bw, chunk_count);
|
||||
if (is_last_chunk) {
|
||||
/* FIXME: Ensure data_len can never be 0 */
|
||||
bw_write_u8(&bw, data_len - 1);
|
||||
@ -769,6 +810,7 @@ void host_update(struct host *host)
|
||||
/* TODO: Aggregate small packets */
|
||||
for (u64 i = 0; i < host->num_channels_reserved; ++i) {
|
||||
struct host_channel *channel = &host->channels[i];
|
||||
if (channel->valid) {
|
||||
struct sock_address address = channel->address;
|
||||
/* Send unreliable packets to channel */
|
||||
for (struct host_packet *host_packet = channel->first_unreliable_packet; host_packet; host_packet = host_packet->next) {
|
||||
@ -786,6 +828,7 @@ void host_update(struct host *host)
|
||||
channel->last_unreliable_packet = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Reset cmds */
|
||||
|
||||
@ -87,7 +87,7 @@ struct host_startup_receipt host_startup(struct sock_startup_receipt *sock_sr);
|
||||
* Host
|
||||
* ========================== */
|
||||
|
||||
struct host *host_alloc(struct sock_address bind_address);
|
||||
struct host *host_alloc(u16 listen_port);
|
||||
|
||||
void host_release(struct host *host);
|
||||
|
||||
|
||||
26
src/sock.h
26
src/sock.h
@ -13,22 +13,20 @@ enum sock_flag {
|
||||
};
|
||||
|
||||
struct sock {
|
||||
i32 _;
|
||||
u64 handle;
|
||||
};
|
||||
|
||||
enum sock_address_kind {
|
||||
SOCK_ADDRESS_KIND_NONE,
|
||||
SOCK_ADDRESS_KIND_UNBINDABLE,
|
||||
|
||||
/* Network addresses */
|
||||
SOCK_ADDRESS_KIND_ANY_LOCAL_INTERFACE,
|
||||
SOCK_ADDRESS_KIND_RAW
|
||||
enum sock_address_family {
|
||||
SOCK_ADDRESS_FAMILY_IPV4,
|
||||
SOCK_ADDRESS_FAMILY_IPV6
|
||||
};
|
||||
|
||||
struct sock_address {
|
||||
enum sock_address_kind kind;
|
||||
u8 ip[16];
|
||||
u16 port;
|
||||
b32 valid;
|
||||
enum sock_address_family family;
|
||||
/* NOTE: ipnb & portnb are stored in network byte order */
|
||||
u8 ipnb[16];
|
||||
u16 portnb;
|
||||
};
|
||||
|
||||
struct sock_read_result {
|
||||
@ -41,11 +39,9 @@ struct sock_startup_receipt { i32 _; };
|
||||
struct sock_startup_receipt sock_startup(void);
|
||||
|
||||
struct sock_address sock_address_from_string(struct string str);
|
||||
struct sock_address sock_address_from_any_local_interface_with_port(u16 port);
|
||||
struct sock_address sock_address_from_any_local_interface_with_dynamic_port(void);
|
||||
struct sock_address sock_address_unbindable(void);
|
||||
struct sock_address sock_address_from_port(u16 port);
|
||||
|
||||
struct sock sock_alloc(struct sock_address bind_address, u32 sock_flags);
|
||||
struct sock sock_alloc(u16 listen_port, u32 flags);
|
||||
void sock_release(struct sock *sock);
|
||||
struct sock_read_result sock_read(struct sock *sock, struct string read_buff);
|
||||
void sock_write(struct sock *sock, struct sock_address address, struct string data);
|
||||
|
||||
786
src/sock_win32.c
786
src/sock_win32.c
@ -1,11 +1,9 @@
|
||||
#if 1
|
||||
|
||||
|
||||
#include "sock.h"
|
||||
#include "sys.h"
|
||||
#include "log.h"
|
||||
#include "arena.h"
|
||||
#include "scratch.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
@ -14,6 +12,17 @@
|
||||
|
||||
//#define MAX_IP_STR_LEN 46
|
||||
|
||||
struct winsock_address {
|
||||
i32 size;
|
||||
i32 family;
|
||||
union {
|
||||
struct sockaddr_storage sas;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
};
|
||||
};
|
||||
|
||||
struct sock_startup_receipt sock_startup(void)
|
||||
{
|
||||
WSADATA wsa_data;
|
||||
@ -22,590 +31,241 @@ struct sock_startup_receipt sock_startup(void)
|
||||
return (struct sock_startup_receipt) { 0 };
|
||||
}
|
||||
|
||||
struct sock_address sock_address_from_string(struct string str)
|
||||
INTERNAL struct sock_address sock_address_from_ip_port_cstr(char *ip_cstr, char *port_cstr)
|
||||
{
|
||||
(UNUSED)str;
|
||||
|
||||
struct sock_address res = ZI;
|
||||
|
||||
#if 0
|
||||
struct addrinfo *servinfo;
|
||||
|
||||
struct addrinfo hints = ZI;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
status = getaddrinfo(NULL, "3490", &hints, &servinfo)
|
||||
struct addrinfo *ai_res = NULL;
|
||||
i32 status = getaddrinfo(ip_cstr, port_cstr, &hints, &ai_res);
|
||||
if (status == 0) {
|
||||
while (ai_res) {
|
||||
if (ai_res->ai_family == AF_INET) {
|
||||
struct sockaddr_in *sockaddr = (struct sockaddr_in *)ai_res->ai_addr;
|
||||
res.family = SOCK_ADDRESS_FAMILY_IPV4;
|
||||
res.portnb = sockaddr->sin_port;
|
||||
CT_ASSERT(sizeof(sockaddr->sin_addr) == 4);
|
||||
MEMCPY(res.ipnb, (void *)&sockaddr->sin_addr, 4);
|
||||
break;
|
||||
|
||||
} else if (ai_res->ai_family == AF_INET6) {
|
||||
/* FIXME: Why must this be disabled to work? */
|
||||
#if 0
|
||||
struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_res->ai_addr;
|
||||
res.family = SOCK_ADDRESS_FAMILY_IPV6;
|
||||
res.portnb = sockaddr->sin6_port;
|
||||
CT_ASSERT(sizeof(sockaddr->sin6_addr) == 16);
|
||||
MEMCPY(res.ipnb, (void *)&sockaddr->sin6_addr, 16);
|
||||
#endif
|
||||
}
|
||||
ai_res = ai_res->ai_next;
|
||||
}
|
||||
freeaddrinfo(ai_res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock_address sock_address_from_string(struct string str)
|
||||
{
|
||||
/* Parse string into ip & port */
|
||||
char *address_cstr = NULL;
|
||||
char *port_cstr = NULL;
|
||||
{
|
||||
u64 colon_count = 0;
|
||||
for (u64 i = 0; i < str.len; ++i) {
|
||||
u8 c = str.text[i];
|
||||
if (c == ':') {
|
||||
++colon_count;
|
||||
}
|
||||
}
|
||||
u8 address_buff[1024];
|
||||
u8 port_buff[ARRAY_COUNT(address_buff)];
|
||||
u64 address_len = 0;
|
||||
u64 port_len = 0;
|
||||
u64 parse_len = min_u64(min_u64(str.len, ARRAY_COUNT(address_buff) - 1), ARRAY_COUNT(port_buff) - 1);
|
||||
if (colon_count > 1 && str.text[0] == '[') {
|
||||
/* Parse ipv6 with port */
|
||||
b32 parse_addr = true;
|
||||
for (u64 i = 1; i < parse_len; ++i) {
|
||||
u8 c = str.text[i];
|
||||
if (parse_addr) {
|
||||
if (c == ']') {
|
||||
parse_addr = false;
|
||||
} else {
|
||||
address_buff[address_len] = c;
|
||||
++address_len;
|
||||
}
|
||||
} else if (c != ':') {
|
||||
port_buff[port_len] = c;
|
||||
++port_len;
|
||||
}
|
||||
}
|
||||
} else if (colon_count == 1) {
|
||||
/* Parse address with port */
|
||||
b32 parse_addr = true;
|
||||
for (u64 i = 0; i < parse_len; ++i) {
|
||||
u8 c = str.text[i];
|
||||
if (parse_addr) {
|
||||
if (c == ':') {
|
||||
parse_addr = false;
|
||||
} else {
|
||||
address_buff[address_len] = c;
|
||||
++address_len;
|
||||
}
|
||||
} else {
|
||||
port_buff[port_len] = c;
|
||||
++port_len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Copy address without port */
|
||||
address_len = min_u64(str.len, ARRAY_COUNT(address_buff) - 1);
|
||||
MEMCPY(address_buff, str.text, address_len);
|
||||
}
|
||||
if (address_len > 0) {
|
||||
address_buff[address_len] = 0;
|
||||
address_cstr = (char *)address_buff;
|
||||
}
|
||||
if (port_len > 0) {
|
||||
port_buff[port_len] = 0;
|
||||
port_cstr = (char *)port_buff;
|
||||
|
||||
}
|
||||
}
|
||||
struct sock_address res = sock_address_from_ip_port_cstr(address_cstr, port_cstr);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock_address sock_address_from_port(u16 port)
|
||||
{
|
||||
char *port_cstr = NULL;
|
||||
{
|
||||
u8 port_buff[128];
|
||||
u8 port_buff_reverse[ARRAY_COUNT(port_buff)];
|
||||
u64 port_len = 0;
|
||||
while (port > 0 && port_len < (ARRAY_COUNT(port_buff) - 1)) {
|
||||
u8 digit = port % 10;
|
||||
port /= 10;
|
||||
port_buff_reverse[port_len] = '0' + digit;
|
||||
++port_len;
|
||||
}
|
||||
for (u64 i = 0; i < port_len; ++i) {
|
||||
u64 j = port_len - 1 - i;
|
||||
port_buff[i] = port_buff_reverse[j];
|
||||
}
|
||||
if (port_len > 0) {
|
||||
port_buff[port_len] = 0;
|
||||
port_cstr = (char *)port_buff;
|
||||
}
|
||||
}
|
||||
|
||||
struct sock_address res = sock_address_from_ip_port_cstr(NULL, port_cstr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERNAL struct winsock_address winsock_address_from_sock_address(struct sock_address addr)
|
||||
{
|
||||
struct winsock_address res = ZI;
|
||||
if (addr.family == SOCK_ADDRESS_FAMILY_IPV4) {
|
||||
res.family = AF_INET;
|
||||
res.size = sizeof(struct sockaddr_in);
|
||||
res.sin.sin_port = addr.portnb;
|
||||
res.sin.sin_family = res.family;
|
||||
MEMCPY(&res.sin.sin_addr, addr.ipnb, 4);
|
||||
} else {
|
||||
res.family = AF_INET6;
|
||||
res.sin6.sin6_port = addr.portnb;
|
||||
res.sin6.sin6_family = res.family;
|
||||
res.size = sizeof(struct sockaddr_in6);
|
||||
MEMCPY(&res.sin6.sin6_addr.s6_addr, addr.ipnb, 16);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERNAL struct sock_address sock_address_from_winsock_address(struct winsock_address ws_addr)
|
||||
{
|
||||
struct sock_address res = ZI;
|
||||
if (ws_addr.family == AF_INET) {
|
||||
res.family = SOCK_ADDRESS_FAMILY_IPV4;
|
||||
res.portnb = ws_addr.sin.sin_port;
|
||||
MEMCPY(res.ipnb, &ws_addr.sin.sin_addr, 4);
|
||||
res.valid = true;
|
||||
} else if (ws_addr.family == AF_INET6) {
|
||||
res.family = SOCK_ADDRESS_FAMILY_IPV6;
|
||||
res.portnb = ws_addr.sin6.sin6_port;
|
||||
MEMCPY(res.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16);
|
||||
res.valid = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock sock_alloc(u16 listen_port, u32 flags)
|
||||
{
|
||||
struct sock_address addr = sock_address_from_port(listen_port);
|
||||
struct winsock_address ws_addr = winsock_address_from_sock_address(addr);
|
||||
|
||||
SOCKET ws = socket(ws_addr.family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (flags & SOCK_FLAG_NON_BLOCKING) {
|
||||
u_long mode = 1;
|
||||
ioctlsocket(ws, FIONBIO, &mode);
|
||||
}
|
||||
//setsockopt(ws, SOL_SOCKET, SO_REUSEADDR
|
||||
|
||||
#if 0
|
||||
if (listen_port != 0) {
|
||||
bind(ws, &ws_addr.sa, ws_addr.size);
|
||||
}
|
||||
#else
|
||||
bind(ws, &ws_addr.sa, ws_addr.size);
|
||||
#endif
|
||||
|
||||
struct sock res = ZI;
|
||||
res.handle = *(u64 *)&ws;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock_address sock_address_from_any_local_interface_with_port(u16 port)
|
||||
{
|
||||
(UNUSED)port;
|
||||
|
||||
struct sock_address res = ZI;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock_address sock_address_from_any_local_interface_with_dynamic_port(void)
|
||||
{
|
||||
struct sock_address res = ZI;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock_address sock_address_unbindable(void)
|
||||
{
|
||||
struct sock_address res = ZI;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock sock_alloc(struct sock_address bind_address, u32 sock_flags)
|
||||
{
|
||||
(UNUSED)bind_address;
|
||||
(UNUSED)sock_flags;
|
||||
|
||||
struct sock sock = ZI;
|
||||
|
||||
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
void sock_release(struct sock *sock)
|
||||
{
|
||||
(UNUSED)sock;
|
||||
SOCKET ws = *(SOCKET *)&sock->handle;
|
||||
closesocket(ws);
|
||||
}
|
||||
|
||||
struct sock_read_result sock_read(struct sock *sock, struct string read_buff)
|
||||
{
|
||||
(UNUSED)sock;
|
||||
(UNUSED)read_buff;
|
||||
SOCKET ws = *(SOCKET *)&sock->handle;
|
||||
|
||||
struct sock_read_result res = ZI;
|
||||
struct winsock_address ws_addr = ZI;
|
||||
ws_addr.size = sizeof(ws_addr.sas);
|
||||
i32 size = recvfrom(ws, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size);
|
||||
ws_addr.family = ws_addr.sin.sin_family;
|
||||
|
||||
res.address = sock_address_from_winsock_address(ws_addr);
|
||||
if (size > 0) {
|
||||
res.data.text = read_buff.text;
|
||||
res.data.len = size;
|
||||
res.valid = true;
|
||||
} else {
|
||||
#if RTC
|
||||
i32 err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK && err != WSAECONNRESET) {
|
||||
ASSERT(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void sock_write(struct sock *sock, struct sock_address address, struct string data)
|
||||
{
|
||||
(UNUSED)sock;
|
||||
(UNUSED)address;
|
||||
(UNUSED)data;
|
||||
SOCKET ws = *(SOCKET *)&sock->handle;
|
||||
struct winsock_address ws_addr = winsock_address_from_sock_address(address);
|
||||
sendto(ws, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
||||
|
||||
#include "sock.h"
|
||||
#include "sys.h"
|
||||
#include "log.h"
|
||||
#include "arena.h"
|
||||
#include "scratch.h"
|
||||
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
#define MAX_IP_STR_LEN 46
|
||||
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(win32_sock_receive_entry_point, arg);
|
||||
|
||||
struct win32_sock {
|
||||
SOCKET socket;
|
||||
struct sockaddr_in6 sa6;
|
||||
|
||||
sock_receive_callback_func *receive_callback;
|
||||
struct sys_thread receive_thread;
|
||||
|
||||
struct win32_sock *next_free;
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
* Global state
|
||||
* ========================== */
|
||||
|
||||
GLOBAL struct {
|
||||
struct sys_mutex win32_socks_mutex;
|
||||
struct arena win32_socks_arena;
|
||||
struct win32_sock *first_free_win32_sock;
|
||||
|
||||
WSADATA wsa_data;
|
||||
} G = ZI, DEBUG_ALIAS(G, G_sock_win32);
|
||||
|
||||
/* ========================== *
|
||||
* Startup
|
||||
* ========================== */
|
||||
|
||||
struct sock_startup_receipt sock_startup(void)
|
||||
{
|
||||
G.win32_socks_mutex = sys_mutex_alloc();
|
||||
G.win32_socks_arena = arena_alloc(GIGABYTE(64));
|
||||
|
||||
/* Initialize Winsock */
|
||||
WSAStartup(MAKEWORD(2, 2), &G.wsa_data);
|
||||
//WSACleanup();
|
||||
|
||||
return (struct sock_startup_receipt) { 0 };
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Address
|
||||
* ========================== */
|
||||
|
||||
#if 1
|
||||
|
||||
INTERNAL struct sockaddr_in6 win32_sa6_from_sock_address(struct sock_address sa)
|
||||
{
|
||||
struct sockaddr_in6 res = ZI;
|
||||
res.sin6_family = AF_INET6;
|
||||
res.sin6_port = htons(sa.port);
|
||||
CT_ASSERT(sizeof(res.sin6_addr.s6_addr) == 16);
|
||||
CT_ASSERT(sizeof(sa.ip) == 16);
|
||||
|
||||
b32 is_any = true;
|
||||
for (u64 i = 0; i < 16; ++i) {
|
||||
u8 b = sa.ip.b[i];
|
||||
res.sin6_addr.s6_addr[i] = b;
|
||||
is_any = (is_any && b == 0);
|
||||
}
|
||||
if (is_any) {
|
||||
res.sin6_addr = in6addr_any;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERNAL struct sock_address sock_address_from_win32_sa6(struct sockaddr_in6 sa6)
|
||||
{
|
||||
struct sock_address res = ZI;
|
||||
CT_ASSERT(sizeof(sa6.sin6_addr.s6_addr) == 16);
|
||||
CT_ASSERT(sizeof(res.ip) == 16);
|
||||
MEMCPY(res.ip.b, sa6.sin6_addr.s6_addr, 16);
|
||||
res.port = ntohs(sa6.sin6_port);
|
||||
return res;
|
||||
}
|
||||
|
||||
b32 sock_ip_is_ipv4(struct sock_ip ip)
|
||||
{
|
||||
return ((ip.b[0] == 0x00) &&
|
||||
(ip.b[1] == 0x00) &&
|
||||
(ip.b[2] == 0x00) &&
|
||||
(ip.b[3] == 0x00) &&
|
||||
(ip.b[4] == 0x00) &&
|
||||
(ip.b[5] == 0x00) &&
|
||||
(ip.b[6] == 0x00) &&
|
||||
(ip.b[7] == 0x00) &&
|
||||
(ip.b[8] == 0x00) &&
|
||||
(ip.b[9] == 0x00) &&
|
||||
(ip.b[10] == 0xFF) &&
|
||||
(ip.b[11] == 0xFF));
|
||||
}
|
||||
|
||||
b32 sock_string_is_ipv4(struct string s)
|
||||
{
|
||||
b32 ipv4 = true;
|
||||
for (u64 i = 0; i < s.len; ++i) {
|
||||
u8 c = s.text[i];
|
||||
if (c == '.') {
|
||||
ipv4 = true;
|
||||
break;
|
||||
} else if (c == ':') {
|
||||
ipv4 = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ipv4;
|
||||
}
|
||||
|
||||
struct sock_ip sock_ip_from_string(struct string s)
|
||||
{
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
char *cstr = cstr_from_string(scratch.arena, s);
|
||||
|
||||
u8 buff[16] = ZI;
|
||||
if (sock_string_is_ipv4(s)) {
|
||||
buff[10] = 0xFF;
|
||||
buff[11] = 0xFF;
|
||||
inet_pton(AF_INET, cstr, buff + 12);
|
||||
} else {
|
||||
inet_pton(AF_INET6, cstr, buff);
|
||||
}
|
||||
|
||||
struct sock_ip res = ZI;
|
||||
CT_ASSERT(sizeof(res.b) == sizeof(buff));
|
||||
MEMCPY(res.b, buff, sizeof(buff));
|
||||
|
||||
scratch_end(scratch);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct string sock_ip_to_string(struct arena *arena, struct sock_ip ip)
|
||||
{
|
||||
char buff[MAX_IP_STR_LEN];
|
||||
if (sock_ip_is_ipv4(ip)) {
|
||||
inet_ntop(AF_INET, ip.b + 12, buff, sizeof(buff));
|
||||
} else {
|
||||
inet_ntop(AF_INET6, ip.b, buff, sizeof(buff));
|
||||
}
|
||||
struct string res = string_copy(arena, string_from_cstr_limit(buff, sizeof(buff)));
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
INTERNAL struct sockaddr_in6 win32_sa6_from_sock_address(struct sock_address sa)
|
||||
{
|
||||
struct sockaddr_in6 res = ZI;
|
||||
res.sin6_family = AF_INET6;
|
||||
res.sin6_port = htons(sa.port);
|
||||
if (u128_eq(sa.ip, SOCK_IP_ANY_INTERFACE)) {
|
||||
res.sin6_addr = in6addr_any;
|
||||
} else {
|
||||
/* TODO: store address structure in network byte order by default */
|
||||
u64 hi = U128_HI(sa.ip);
|
||||
u64 lo = U128_LO(sa.ip);
|
||||
u8 *dst = res.sin6_addr.s6_addr;
|
||||
dst[0] = (hi >> 56) & 0xFF;
|
||||
dst[1] = (hi >> 48) & 0xFF;
|
||||
dst[2] = (hi >> 40) & 0xFF;
|
||||
dst[3] = (hi >> 32) & 0xFF;
|
||||
dst[4] = (hi >> 24) & 0xFF;
|
||||
dst[5] = (hi >> 16) & 0xFF;
|
||||
dst[6] = (hi >> 8) & 0xFF;
|
||||
dst[7] = (hi >> 0) & 0xFF;
|
||||
dst[8] = (lo >> 56) & 0xFF;
|
||||
dst[9] = (lo >> 48) & 0xFF;
|
||||
dst[10] = (lo >> 40) & 0xFF;
|
||||
dst[11] = (lo >> 32) & 0xFF;
|
||||
dst[12] = (lo >> 24) & 0xFF;
|
||||
dst[13] = (lo >> 16) & 0xFF;
|
||||
dst[14] = (lo >> 8) & 0xFF;
|
||||
dst[15] = (lo >> 0) & 0xFF;
|
||||
}
|
||||
res.sin6_port = htons(12345);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERNAL struct sock_address sock_address_from_win32_sa6(struct sockaddr_in6 sa6)
|
||||
{
|
||||
struct sock_address res = ZI;
|
||||
u8 *src = sa6.sin6_addr.s6_addr;
|
||||
/* TODO: store address structure in network byte order by default */
|
||||
u64 hi = ((u64)src[0] << 56) |
|
||||
((u64)src[1] << 48) |
|
||||
((u64)src[2] << 40) |
|
||||
((u64)src[3] << 32) |
|
||||
((u64)src[4] << 24) |
|
||||
((u64)src[5] << 16) |
|
||||
((u64)src[6] << 8) |
|
||||
((u64)src[7] << 0);
|
||||
u64 lo = ((u64)src[8] << 56) |
|
||||
((u64)src[9] << 48) |
|
||||
((u64)src[10] << 40) |
|
||||
((u64)src[11] << 32) |
|
||||
((u64)src[12] << 24) |
|
||||
((u64)src[13] << 16) |
|
||||
((u64)src[14] << 8) |
|
||||
((u64)src[15] << 0);
|
||||
res.ip = U128(hi, lo);
|
||||
res.port = ntohs(sa6.sin6_port);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sock_address sock_address_from_string(struct string s)
|
||||
{
|
||||
u64 hi = 0;
|
||||
u64 lo = 0;
|
||||
|
||||
b32 ipv4 = true;
|
||||
for (u64 i = 0; i < s.len; ++i) {
|
||||
u8 c = s.text[i];
|
||||
if (c == '.') {
|
||||
ipv4 = true;
|
||||
break;
|
||||
} else if (c == ':') {
|
||||
ipv4 = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipv4) {
|
||||
struct string seq = ZI;
|
||||
seq.text = s.text;
|
||||
|
||||
u8 byte_index = 0;
|
||||
u8 byte = 0;
|
||||
u8 factor = 100;
|
||||
for (u32 s_index = 0; s_index < s.len; ++s_index) {
|
||||
u8 c = s.text[s_index];
|
||||
if (c == '.' || s_index == (s.len - 1)) {
|
||||
if (byte_index < 8) {
|
||||
lo |= (byte << (byte_index * 8));
|
||||
} else {
|
||||
hi |= (byte << (byte_index * 8));
|
||||
}
|
||||
|
||||
byte = 0;
|
||||
factor = 100;
|
||||
++byte_index;
|
||||
} else {
|
||||
byte += ((c + 48) * factor);
|
||||
factor *= 0.1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* TODO */
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return U128(hi, lo);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* Sock
|
||||
* ========================== */
|
||||
|
||||
INTERNAL struct win32_sock *win32_sock_alloc(void)
|
||||
{
|
||||
struct win32_sock *ws = NULL;
|
||||
{
|
||||
struct sys_lock lock = sys_mutex_lock_e(&G.win32_socks_mutex);
|
||||
if (G.first_free_win32_sock) {
|
||||
ws = G.first_free_win32_sock;
|
||||
G.first_free_win32_sock = ws->next_free;
|
||||
} else {
|
||||
ws = arena_push(&G.win32_socks_arena, struct win32_sock);
|
||||
}
|
||||
sys_mutex_unlock(&lock);
|
||||
}
|
||||
MEMZERO_STRUCT(ws);
|
||||
return ws;
|
||||
}
|
||||
|
||||
INTERNAL void win32_sock_release(struct win32_sock *ws)
|
||||
{
|
||||
struct sys_lock lock = sys_mutex_lock_e(&G.win32_socks_mutex);
|
||||
ws->next_free = G.first_free_win32_sock;
|
||||
G.first_free_win32_sock = ws;
|
||||
sys_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
struct sock sock_alloc(struct sock_address bind_addr, u64 flags)
|
||||
{
|
||||
struct win32_sock *ws = win32_sock_alloc();
|
||||
|
||||
struct sockaddr_in6 sa6 = win32_sa6_from_sock_address(bind_addr);
|
||||
|
||||
ws->socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (bind_addr.) {
|
||||
/* TODO: Error checking */
|
||||
bind(ws->socket, (struct sockaddr *)&ws->sa6, sizeof(ws->sa6));
|
||||
}
|
||||
|
||||
if (receive_callback) {
|
||||
/* Spin up receive thread */
|
||||
ws->receive_thread = sys_thread_alloc(win32_sock_receive_entry_point, ws, LIT("[P8] Sock receive thread"));
|
||||
}
|
||||
|
||||
struct sock res = ZI;
|
||||
res.handle = (u64)ws;
|
||||
return res;
|
||||
}
|
||||
|
||||
void sock_release(struct sock *sock)
|
||||
{
|
||||
/* TODO */
|
||||
|
||||
struct win32_sock *ws = (struct win32_sock *)sock->handle;
|
||||
|
||||
//ws->shutdown_receiver
|
||||
|
||||
//closesocket(ws->socket);
|
||||
|
||||
win32_sock_release(ws);
|
||||
|
||||
}
|
||||
|
||||
struct sock_packet {
|
||||
struct sock_address addr;
|
||||
struct string msg;
|
||||
};
|
||||
|
||||
void sock_send(struct sock *sock, struct sock_packet p)
|
||||
{
|
||||
struct win32_sock *ws = (struct win32_sock *)sock->handle;
|
||||
struct sockaddr_in6 sa6 = win32_sa6_from_sock_address(p.addr);
|
||||
sendto(ws->socket, (char *)p.msg.text, p.msg.len, 0, (struct sockaddr *)&sa6, sizeof(sa6));
|
||||
}
|
||||
|
||||
struct sock_packet sock_recv(struct sock *sock, u8 *buffer, u64 buffer_size)
|
||||
{
|
||||
struct sock_packet p = ZI;
|
||||
struct win32_sock *ws = (struct win32_sock *)sock->handle;
|
||||
|
||||
|
||||
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Receive thread
|
||||
* ========================== */
|
||||
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(win32_sock_receive_entry_point, arg)
|
||||
{
|
||||
struct win32_sock *ws = (struct win32_sock *)arg;
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
u64 buffer_size = KILOBYTE(64);
|
||||
u8 *buffer = arena_push_array(scratch.arena, u8, buffer_size);
|
||||
|
||||
struct sockaddr_in6 client_sa6 = ZI;
|
||||
i32 client_sa6_size = sizeof(client_sa6);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct sock_address dummy = ZI;
|
||||
dummy.ip = sock_ip_from_string(LIT("127.0.0.1"));
|
||||
dummy.port = 12345;
|
||||
struct sockaddr_in6 dummy_sa6 = win32_sa6_from_sock_address(dummy);
|
||||
|
||||
char dummy_msg = 0;
|
||||
sendto(ws->socket, &dummy_msg, 1, 0, (struct sockaddr *)&dummy_sa6, sizeof(dummy_sa6));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* TODO: Allow thread shutdown */
|
||||
volatile b32 shutdown = false;
|
||||
while (!shutdown) {
|
||||
i32 msg_len = recvfrom(ws->socket, (char *)buffer, buffer_size, 0, (struct sockaddr *)&client_sa6, &client_sa6_size);
|
||||
if (msg_len == SOCKET_ERROR) {
|
||||
i32 err = WSAGetLastError();
|
||||
(UNUSED)err;
|
||||
ASSERT(false);
|
||||
} else if (msg_len > 0) {
|
||||
if (ws->receive_callback) {
|
||||
struct sock_address address = sock_address_from_win32_sa6(client_sa6);
|
||||
ws->receive_callback(address, STRING(msg_len, buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Test
|
||||
* ========================== */
|
||||
|
||||
void sock_testsend(void)
|
||||
{
|
||||
SOCKET sock;
|
||||
struct sockaddr_in serverAddr;
|
||||
char *message = "Hello, UDP!";
|
||||
|
||||
/* Create socket */
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
/* Set up the server address struct */
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_port = htons(12345); /* Port */
|
||||
// serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
if (inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr) <= 0) {
|
||||
sys_panic(LIT("Invalid address"));
|
||||
}
|
||||
|
||||
/* Send a message */
|
||||
sendto(sock, message, strlen(message), 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
|
||||
|
||||
/* Clean up */
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
void sock_testrecv(void)
|
||||
{
|
||||
SOCKET sock;
|
||||
char clientIP[INET_ADDRSTRLEN];
|
||||
struct sockaddr_in serverAddr, clientAddr;
|
||||
char buffer[1024];
|
||||
int clientAddrLen = sizeof(clientAddr);
|
||||
|
||||
/* Create socket */
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
/* Set up the server address struct */
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_port = htons(12345); /* Port */
|
||||
serverAddr.sin_addr.s_addr = INADDR_ANY; /* Accept any incoming address */
|
||||
|
||||
/* Bind the socket to the address */
|
||||
bind(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
|
||||
|
||||
/* Receive a message */
|
||||
volatile b32 run = true;
|
||||
while (run) {
|
||||
int recvLen = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&clientAddr, &clientAddrLen);
|
||||
if (recvLen > 0) {
|
||||
buffer[recvLen] = '\0'; /* Null-terminate the received message */
|
||||
|
||||
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, sizeof(clientIP));
|
||||
|
||||
struct string addr = string_from_cstr(clientIP);
|
||||
struct string msg = STRING((u64)recvLen, (u8 *)buffer);
|
||||
i32 port = ntohs(clientAddr.sin_port);
|
||||
|
||||
logf_info("Received from %F:%F - %F\n", FMT_STR(addr), FMT_SINT(port), FMT_STR(msg));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -158,8 +158,9 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
||||
G.sys_events_arena = arena_alloc(GIGABYTE(64));
|
||||
world_alloc(&G.world);
|
||||
|
||||
struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
|
||||
G.host = host_alloc(bind_addr);
|
||||
//struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
|
||||
//G.host = host_alloc(0);
|
||||
G.host = host_alloc(5920);
|
||||
|
||||
G.world_to_ui_xf = XFORM_IDENT;
|
||||
G.world_cmd_buffer = renderer_cmd_buffer_alloc();
|
||||
@ -617,7 +618,7 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
static f64 last_try_connect = 0;
|
||||
f64 now = SECONDS_FROM_NS(sys_time_ns());
|
||||
if (last_try_connect == 0 || (now - last_try_connect) > 5) {
|
||||
if (last_try_connect == 0 || (now - last_try_connect) > 0.1) {
|
||||
struct sock_address connect_addr = sock_address_from_string(LIT("127.0.0.1:12345"));
|
||||
host_queue_connect_to_address(G.host, connect_addr);
|
||||
last_try_connect = now;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user