diff --git a/src/byteio.c b/src/byteio.c index 74418c5a..2a3d968e 100644 --- a/src/byteio.c +++ b/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; +} diff --git a/src/byteio.h b/src/byteio.h index 3bb3c152..c35f67db 100644 --- a/src/byteio.h +++ b/src/byteio.h @@ -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) { diff --git a/src/game.c b/src/game.c index e3b7eb79..1f4331ee 100644 --- a/src/game.c +++ b/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; } /* ========================== * diff --git a/src/host.c b/src/host.c index 8be85e92..f78220f7 100644 --- a/src/host.c +++ b/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,42 +627,44 @@ void host_update(struct host *host) case HOST_PACKET_KIND_MSG_CHUNK: { - /* Packet is chunk out of belonging to message */ - u64 msg_id = br_read_var_uint(&br); - u64 chunk_id = br_read_var_uint(&br); - u64 chunk_count = br_read_var_uint(&br); + if (channel->valid) { + /* Packet is chunk out of belonging to message */ + u64 msg_id = br_read_var_uint(&br); + u64 chunk_id = br_read_var_uint(&br); + u64 chunk_count = br_read_var_uint(&br); - b32 is_last_chunk = (chunk_id + 1) == chunk_count; - u64 data_len = is_last_chunk ? (br_read_u8(&br) + 1) : PACKET_CHUNK_MAX_LEN; + b32 is_last_chunk = (chunk_id + 1) == chunk_count; + u64 data_len = is_last_chunk ? (br_read_u8(&br) + 1) : PACKET_CHUNK_MAX_LEN; - struct host_msg_assembler *ma = host_get_msg_assembler(host, channel->id, msg_id); - if (!ma) { - ma = host_msg_assembler_alloc(channel, msg_id, chunk_count, now_ns); - } + struct host_msg_assembler *ma = host_get_msg_assembler(host, channel->id, msg_id); + if (!ma) { + ma = host_msg_assembler_alloc(channel, msg_id, chunk_count, now_ns); + } - if (chunk_count == ma->num_chunks_total && chunk_id < chunk_count) { - if (!host_msg_assembler_is_chunk_filled(ma, chunk_id)) { - u8 *src = br_seek(&br, data_len); - if (src) { - u8 *dst = &ma->data[chunk_id * PACKET_CHUNK_MAX_LEN]; - MEMCPY(dst, src, data_len); - if (is_last_chunk) { - ma->last_chunk_len = data_len; - } - host_msg_assembler_set_chunk_received(ma, chunk_id); - ++ma->num_chunks_received; - ma->touched_ns = now_ns; - if (ma->num_chunks_received == chunk_count) { - /* All chunks filled, message has finished assembling */ - /* TODO: Message ordering */ - struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); - struct string data = ZI; - data.len = ((chunk_count - 1) * PACKET_CHUNK_MAX_LEN) + ma->last_chunk_len; - data.text = arena_push_array(&host->queued_event_arena, u8, data.len); - MEMCPY(data.text, ma->data, data.len); - queued_event->event.kind = HOST_EVENT_KIND_MSG; - queued_event->event.msg = data; - queued_event->event.channel_id = channel->id; + if (chunk_count == ma->num_chunks_total && chunk_id < chunk_count) { + if (!host_msg_assembler_is_chunk_filled(ma, chunk_id)) { + u8 *src = br_seek(&br, data_len); + if (src) { + u8 *dst = &ma->data[chunk_id * PACKET_CHUNK_MAX_LEN]; + MEMCPY(dst, src, data_len); + if (is_last_chunk) { + ma->last_chunk_len = data_len; + } + host_msg_assembler_set_chunk_received(ma, chunk_id); + ++ma->num_chunks_received; + ma->touched_ns = now_ns; + if (ma->num_chunks_received == chunk_count) { + /* All chunks filled, message has finished assembling */ + /* TODO: Message ordering */ + struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); + struct string data = ZI; + data.len = ((chunk_count - 1) * PACKET_CHUNK_MAX_LEN) + ma->last_chunk_len; + data.text = arena_push_array(&host->queued_event_arena, u8, data.len); + MEMCPY(data.text, ma->data, data.len); + queued_event->event.kind = HOST_EVENT_KIND_MSG; + queued_event->event.msg = data; + queued_event->event.channel_id = channel->id; + } } } } @@ -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,21 +810,23 @@ 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]; - 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) { - sock_write(sock, address, STRING(host_packet->data_len, host_packet->data)); - } - /* Send un-acked reliable packets to channel */ - for (struct host_packet *host_packet = channel->first_reliable_packet; host_packet; host_packet = host_packet->next) { - sock_write(sock, address, STRING(host_packet->data_len, host_packet->data)); - } - /* Release unreliable packets */ - if (channel->first_unreliable_packet) { - host->first_free_packet = channel->first_unreliable_packet; - channel->last_unreliable_packet->next = host->first_free_packet; - channel->first_unreliable_packet = NULL; - channel->last_unreliable_packet = NULL; + 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) { + sock_write(sock, address, STRING(host_packet->data_len, host_packet->data)); + } + /* Send un-acked reliable packets to channel */ + for (struct host_packet *host_packet = channel->first_reliable_packet; host_packet; host_packet = host_packet->next) { + sock_write(sock, address, STRING(host_packet->data_len, host_packet->data)); + } + /* Release unreliable packets */ + if (channel->first_unreliable_packet) { + host->first_free_packet = channel->first_unreliable_packet; + channel->last_unreliable_packet->next = host->first_free_packet; + channel->first_unreliable_packet = NULL; + channel->last_unreliable_packet = NULL; + } } } diff --git a/src/host.h b/src/host.h index 6770b770..96538723 100644 --- a/src/host.h +++ b/src/host.h @@ -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); diff --git a/src/sock.h b/src/sock.h index 2498a6b4..dd5beb8a 100644 --- a/src/sock.h +++ b/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); diff --git a/src/sock_win32.c b/src/sock_win32.c index 5b7591b0..115a9403 100644 --- a/src/sock_win32.c +++ b/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 #include @@ -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 -#include - -#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 diff --git a/src/user.c b/src/user.c index 37d6289d..fb4ce2c7 100644 --- a/src/user.c +++ b/src/user.c @@ -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;