From a504b27767d71d708619bb605490b6a99afeeebe Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 14 Jul 2025 17:04:39 -0500 Subject: [PATCH] move sock into sys layer --- build.c | 2 - src/app.c | 4 +- src/host.c | 49 +++--- src/host.h | 7 +- src/sock.h | 49 ------ src/sock_win32.c | 398 ----------------------------------------------- src/sys.h | 38 +++++ src/sys_win32.c | 381 ++++++++++++++++++++++++++++++++++++++++++++- src/user.c | 3 +- 9 files changed, 442 insertions(+), 489 deletions(-) delete mode 100644 src/sock.h delete mode 100644 src/sock_win32.c diff --git a/build.c b/build.c index dc412686..96360e87 100644 --- a/build.c +++ b/build.c @@ -837,14 +837,12 @@ void OnBuild(StringList cli_args) Bool is_cpp = !is_dir && !is_c && StringEqual(extension, Lit("cpp")); if (is_c || is_cpp) { if (StringBeginsWith(name, Lit("sys_")) || - StringBeginsWith(name, Lit("sock_")) || StringBeginsWith(name, Lit("gp_")) || StringBeginsWith(name, Lit("playback_")) || StringBeginsWith(name, Lit("mp3_")) || StringBeginsWith(name, Lit("ttf_"))) { if (PlatformWindows) { ignore = !(StringEqual(name, Lit("sys_win32.c")) || - StringEqual(name, Lit("sock_win32.c")) || StringEqual(name, Lit("gp_dx12.c")) || StringEqual(name, Lit("playback_wasapi.c")) || StringEqual(name, Lit("mp3_mmf.c")) || diff --git a/src/app.c b/src/app.c index a422ef60..f293070d 100644 --- a/src/app.c +++ b/src/app.c @@ -19,7 +19,6 @@ #include "math.h" #include "gp.h" #include "phys.h" -#include "sock.h" #include "host.h" #include "bitbuff.h" @@ -282,8 +281,7 @@ void sys_app_startup(struct string args_str) gp_startup(); /* Subsystems */ - struct sock_startup_receipt sock_sr = sock_startup(); - struct host_startup_receipt host_sr = host_startup(&sock_sr); + struct host_startup_receipt host_sr = host_startup(); struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup(); struct ttf_startup_receipt ttf_sr = ttf_startup(); struct font_startup_receipt font_sr = font_startup(&asset_cache_sr, &ttf_sr); diff --git a/src/host.c b/src/host.c index d68d2f54..5088ef1f 100644 --- a/src/host.c +++ b/src/host.c @@ -58,7 +58,7 @@ struct host_channel { struct host_channel *next_free; - struct sock_address address; + struct sys_address address; u64 address_hash; struct host_channel *next_address_hash; struct host_channel *prev_address_hash; @@ -105,7 +105,7 @@ struct host_channel_lookup_bin { struct host_rcv_packet { struct sock *sock; - struct sock_address address; + struct sys_address address; struct string data; struct host_rcv_packet *next; }; @@ -162,10 +162,9 @@ INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma); * Startup * ========================== */ -struct host_startup_receipt host_startup(struct sock_startup_receipt *sock_sr) +struct host_startup_receipt host_startup(void) { __prof; - (UNUSED)sock_sr; return (struct host_startup_receipt) { 0 }; } @@ -195,14 +194,14 @@ struct host *host_alloc(u16 listen_port) host->num_msg_assembler_lookup_bins = NUM_MSG_ASSEMBLER_LOOKUP_BINS; host->msg_assembler_lookup_bins = arena_push_array(host->arena, struct host_msg_assembler_lookup_bin, host->num_msg_assembler_lookup_bins); - host->sock = sock_alloc(listen_port, MEBI(2), MEBI(2)); + host->sock = sys_sock_alloc(listen_port, MEBI(2), MEBI(2)); return host; } void host_release(struct host *host) { - sock_release(host->sock); + sys_sock_release(host->sock); buddy_ctx_release(host->buddy); arena_release(host->rcv_buffer_write->arena); @@ -216,17 +215,17 @@ void host_release(struct host *host) * Channel * ========================== */ -INTERNAL u64 hash_from_address(struct sock_address address) +INTERNAL u64 hash_from_address(struct sys_address address) { return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&address)); } -INTERNAL struct host_channel *host_channel_from_address(struct host *host, struct sock_address address) +INTERNAL struct host_channel *host_channel_from_address(struct host *host, struct sys_address address) { u64 hash = hash_from_address(address); struct host_channel_lookup_bin *bin = &host->channel_lookup_bins[hash % host->num_channel_lookup_bins]; for (struct host_channel *channel = bin->first; channel; channel = channel->next_address_hash) { - if (channel->address_hash == hash && sock_address_eq(channel->address, address)) { + if (channel->address_hash == hash && sys_address_eq(channel->address, address)) { return channel; } } @@ -274,7 +273,7 @@ INTERNAL struct host_channel_list host_channels_from_id(struct arena *arena, str return res; } -INTERNAL struct host_channel *host_channel_alloc(struct host *host, struct sock_address address) +INTERNAL struct host_channel *host_channel_alloc(struct host *host, struct sys_address address) { struct host_channel_id id = ZI; struct host_channel *channel; @@ -582,7 +581,7 @@ INTERNAL struct host_cmd *host_cmd_alloc_and_append(struct host *host) return cmd; } -void host_queue_connect_to_address(struct host *host, struct sock_address connect_address) +void host_queue_connect_to_address(struct host *host, struct sys_address connect_address) { struct host_channel *channel = host_channel_from_address(host, connect_address); if (!channel->valid) { @@ -647,14 +646,10 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host) struct host_rcv_packet *last_packet = 0; { __profn("Read socket"); - struct sock_array socks = ZI; - socks.socks = &host->sock; - socks.count = 1; - - struct sock *sock = host->sock; - struct sock_read_result res = ZI; - while ((res = sock_read(scratch.arena, sock)).valid) { - struct sock_address address = res.address; + struct sys_sock *sock = host->sock; + struct sys_sock_read_result res = ZI; + while ((res = sys_sock_read(scratch.arena, sock)).valid) { + struct sys_address address = res.address; struct string data = res.data; if (data.len > 0) { struct host_rcv_packet *packet = arena_push(scratch.arena, struct host_rcv_packet); @@ -675,7 +670,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host) __profn("Process host packets"); for (struct host_rcv_packet *packet = first_packet; packet; packet = packet->next) { //struct sock *sock = packet->sock; - struct sock_address address = packet->address; + struct sys_address address = packet->address; struct bitbuff bb = bitbuff_from_string(packet->data); struct bitbuff_reader br = br_from_bitbuff(&bb); u32 magic = br_read_ubits(&br, 32); /* TODO: implicitly encode magic into crc32 */ @@ -712,7 +707,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host) { /* A foreign host is trying to connect to us */ if (!channel->valid) { - logf_info("Host received conection attempt from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); + logf_info("Host received conection attempt from %F", FMT_STR(sys_string_from_address(scratch.arena, address))); /* TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect? */ channel = host_channel_alloc(host, address); } @@ -725,7 +720,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host) { /* We successfully connected to a foreign host and they are ready to receive messages */ if (channel->valid && !channel->connected) { - logf_info("Host received connection from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); + logf_info("Host received connection from %F", FMT_STR(sys_string_from_address(scratch.arena, address))); struct host_event *event = push_event(arena, &events); event->kind = HOST_EVENT_KIND_CHANNEL_OPENED; event->channel_id = channel->id; @@ -737,7 +732,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host) { /* A foreign host disconnected from us */ if (channel->valid) { - logf_info("Host received disconnection from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); + logf_info("Host received disconnection from %F", FMT_STR(sys_string_from_address(scratch.arena, address))); struct host_event *event = push_event(arena, &events); event->kind = HOST_EVENT_KIND_CHANNEL_CLOSED; event->channel_id = channel->id; @@ -1021,19 +1016,19 @@ void host_update_end(struct host *host) { __profn("Send host packets"); for (u64 i = 0; i < host->num_channels_reserved; ++i) { - struct sock *sock = host->sock; + struct sys_sock *sock = host->sock; struct host_channel *channel = &host->channels[i]; u64 total_sent = 0; if (channel->valid) { - struct sock_address address = channel->address; + struct sys_address address = channel->address; /* Send reliable packets to channel */ for (struct host_snd_packet *packet = channel->first_reliable_packet; packet; packet = packet->next) { - sock_write(sock, address, STRING(packet->data_len, packet->data)); + sys_sock_write(sock, address, STRING(packet->data_len, packet->data)); total_sent += packet->data_len; } /* Send unreliable packets to channel */ for (struct host_snd_packet *packet = channel->first_unreliable_packet; packet; packet = packet->next) { - sock_write(sock, address, STRING(packet->data_len, packet->data)); + sys_sock_write(sock, address, STRING(packet->data_len, packet->data)); total_sent += packet->data_len; } /* Release unreliable packets */ diff --git a/src/host.h b/src/host.h index 2cfd3e57..65a6ed8b 100644 --- a/src/host.h +++ b/src/host.h @@ -2,7 +2,6 @@ #define HOST_H #include "sys.h" -#include "sock.h" #include "snc.h" #define HOST_CHANNEL_ID_NIL (struct host_channel_id) { .gen = 0, .idx = 0 } @@ -67,7 +66,7 @@ struct host_event_list { struct host { struct arena *arena; - struct sock *sock; + struct sys_sock *sock; struct buddy_ctx *buddy; /* For storing msg assembler data */ @@ -104,7 +103,7 @@ struct host { * ========================== */ struct host_startup_receipt { i32 _; }; -struct host_startup_receipt host_startup(struct sock_startup_receipt *sock_sr); +struct host_startup_receipt host_startup(void); /* ========================== * * Host @@ -118,7 +117,7 @@ void host_release(struct host *host); * Queue * ========================== */ -void host_queue_connect_to_address(struct host *host, struct sock_address connect_address); +void host_queue_connect_to_address(struct host *host, struct sys_address connect_address); void host_queue_disconnect(struct host *host, struct host_channel_id channel_id); diff --git a/src/sock.h b/src/sock.h deleted file mode 100644 index a7f09c13..00000000 --- a/src/sock.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef SOCK_H -#define SOCK_H - -#include "memory.h" - -enum sock_address_family { - SOCK_ADDRESS_FAMILY_IPV4, - SOCK_ADDRESS_FAMILY_IPV6 -}; - -struct sock; - -struct sock_array { - struct sock **socks; - u64 count; -}; - -struct sock_address { - 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 { - b32 valid; /* Since data.len = 0 can be valid */ - struct sock_address address; - struct string data; -}; - -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_port(u16 port); -struct string sock_string_from_address(struct arena *arena, struct sock_address address); -INLINE b32 sock_address_eq(struct sock_address a, struct sock_address b) -{ - return MEMEQ_STRUCT(&a, &b); -} - -struct sock *sock_alloc(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size); -void sock_release(struct sock *sock); - -struct sock_read_result sock_read(struct arena *arena, struct sock *sock); -void sock_write(struct sock *sock, struct sock_address address, struct string data); - -#endif diff --git a/src/sock_win32.c b/src/sock_win32.c deleted file mode 100644 index ead9bd51..00000000 --- a/src/sock_win32.c +++ /dev/null @@ -1,398 +0,0 @@ -#include "sock.h" -#include "sys.h" -#include "arena.h" -#include "log.h" -#include "string.h" -#include "gstat.h" -#include "snc.h" - -#define WIN32_LEAN_AND_MEAN -#define UNICODE -#include -#include -#include - -#pragma comment(lib, "ws2_32.lib") - -struct win32_address { - i32 size; - i32 family; - union { - struct sockaddr_storage sas; - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - }; -}; - -struct win32_sock { - SOCKET sock; - struct win32_sock *next_free; -}; - -/* ========================== * - * Global state - * ========================== */ - -GLOBAL struct { - WSADATA wsa_data; - struct arena *win32_socks_arena; - struct snc_mutex win32_socks_mutex; - struct win32_sock *first_free_win32_sock; -} G = ZI, DEBUG_ALIAS(G, G_sock_win32); - -/* ========================== * - * Startup - * ========================== */ - -struct sock_startup_receipt sock_startup(void) -{ - __prof; - /* Startup winsock */ - WSAStartup(MAKEWORD(2, 2), &G.wsa_data); - G.win32_socks_arena = arena_alloc(GIBI(64)); - return (struct sock_startup_receipt) { 0 }; -} - -/* ========================== * - * Address - * ========================== */ - -INTERNAL struct sock_address sock_address_from_ip_port_cstr(char *ip_cstr, char *port_cstr) -{ - struct sock_address res = ZI; - - struct addrinfo hints = ZI; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; - - struct addrinfo *ai_res = 0; - 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.valid = 1; - res.family = SOCK_ADDRESS_FAMILY_IPV4; - res.portnb = sockaddr->sin_port; - STATIC_ASSERT(sizeof(sockaddr->sin_addr) == 4); - MEMCPY(res.ipnb, (void *)&sockaddr->sin_addr, 4); - break; - } else if (ai_res->ai_family == AF_INET6) { - /* TODO: Enable ipv6 */ -#if 0 - struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_res->ai_addr; - res.valid = 1; - res.family = SOCK_ADDRESS_FAMILY_IPV6; - res.portnb = sockaddr->sin6_port; - STATIC_ASSERT(sizeof(sockaddr->sin6_addr) == 16); - MEMCPY(res.ipnb, (void *)&sockaddr->sin6_addr, 16); - break; -#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 */ - u8 ip_buff[1024]; - u8 port_buff[countof(ip_buff)]; - char *ip_cstr = 0; - char *port_cstr = 0; - { - u64 colon_count = 0; - for (u64 i = 0; i < str.len; ++i) { - u8 c = str.text[i]; - if (c == ':') { - ++colon_count; - } - } - u64 ip_len = 0; - u64 port_len = 0; - u64 parse_len = min_u64(min_u64(str.len, countof(ip_buff) - 1), countof(port_buff) - 1); - if (colon_count > 1 && str.text[0] == '[') { - /* Parse ipv6 with port */ - b32 parse_addr = 1; - for (u64 i = 1; i < parse_len; ++i) { - u8 c = str.text[i]; - if (parse_addr) { - if (c == ']') { - parse_addr = 0; - } else { - ip_buff[ip_len] = c; - ++ip_len; - } - } else if (c != ':') { - port_buff[port_len] = c; - ++port_len; - } - } - } else if (colon_count == 1) { - /* Parse address with port */ - b32 parse_addr = 1; - for (u64 i = 0; i < parse_len; ++i) { - u8 c = str.text[i]; - if (parse_addr) { - if (c == ':') { - parse_addr = 0; - } else { - ip_buff[ip_len] = c; - ++ip_len; - } - } else { - port_buff[port_len] = c; - ++port_len; - } - } - } else { - /* Copy address without port */ - ip_len = min_u64(str.len, countof(ip_buff) - 1); - MEMCPY(ip_buff, str.text, ip_len); - } - if (ip_len > 0) { - ip_buff[ip_len] = 0; - ip_cstr = (char *)ip_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(ip_cstr, port_cstr); - return res; -} - -struct sock_address sock_address_from_port(u16 port) -{ - u8 port_buff[128]; - char *port_cstr = 0; - { - u8 port_buff_reverse[countof(port_buff)]; - u64 port_len = 0; - while (port > 0 && port_len < (countof(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(0, port_cstr); - - return res; -} - -struct string sock_string_from_address(struct arena *arena, struct sock_address address) -{ - struct string res = ZI; - - if (address.family == SOCK_ADDRESS_FAMILY_IPV6) { - /* TODO */ - } else { - u8 ip[4]; - for (u32 i = 0; i < 4; ++i) { - ip[i] = ntohs(address.ipnb[i]); - } - u16 port = ntohs(address.portnb); - res = string_format(arena, LIT("%F.%F.%F.%F:%F"), FMT_UINT(ip[0]), FMT_UINT(ip[1]), FMT_UINT(ip[2]), FMT_UINT(ip[3]), FMT_UINT(port)); - } - - return res; -} - -INTERNAL struct win32_address win32_address_from_sock_address(struct sock_address addr) -{ - struct win32_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; -} - -#if 0 -/* If supplied address has ip INADDR_ANY (0), convert ip to localhost */ -INTERNAL struct win32_address win32_address_convert_any_to_localhost(struct win32_address addr) -{ - if (addr.family == AF_INET) { - u8 *bytes = (u8 *)&addr.sin.sin_addr; - b32 is_any = 1; - for (u64 i = 0; i < 4; ++i) { - if (bytes[i] != 0) { - is_any = 0; - break; - } - } - if (is_any) { - bytes[0] = 127; - bytes[3] = 1; - } - } else if (addr.family == AF_INET6) { - u8 *bytes = (u8 *)&addr.sin.sin_addr; - b32 is_any = 1; - for (u64 i = 0; i < 16; ++i) { - if (bytes[i] != 0) { - is_any = 0; - break; - } - } - if (is_any) { - bytes[15] = 1; - } - } - return addr; -} -#endif - -INTERNAL struct sock_address sock_address_from_win32_address(struct win32_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 = 1; - } 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 = 1; - } - return res; -} - -/* ========================== * - * Sock - * ========================== */ - -struct sock *sock_alloc(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) -{ - struct win32_sock *ws = 0; - { - struct snc_lock lock = snc_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_no_zero(G.win32_socks_arena, struct win32_sock); - } - snc_unlock(&lock); - } - MEMZERO_STRUCT(ws); - struct sock_address addr = sock_address_from_port(listen_port); - struct win32_address bind_address = win32_address_from_sock_address(addr); - ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP); - { - i32 sb = sndbuf_size; - i32 rb = rcvbuf_size; - setsockopt(ws->sock, SOL_SOCKET, SO_SNDBUF, (char *)&sb, sizeof(sb)); - setsockopt(ws->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rb, sizeof(rb)); - } - - bind(ws->sock, &bind_address.sa, bind_address.size); - u32 imode = 1; - ioctlsocket(ws->sock, FIONBIO, (unsigned long *)&imode); - - return (struct sock *)ws; -} - -void sock_release(struct sock *sock) -{ - struct win32_sock *ws = (struct win32_sock *)sock; - closesocket(ws->sock); - struct snc_lock lock = snc_lock_e(&G.win32_socks_mutex); - { - ws->next_free = G.first_free_win32_sock; - G.first_free_win32_sock = ws; - } - snc_unlock(&lock); -} - -/* ========================== * - * Read - * ========================== */ - -struct sock_read_result sock_read(struct arena *arena, struct sock *sock) -{ - struct win32_sock *ws = (struct win32_sock *)sock; - - u64 read_buff_size = KIBI(64); - struct string read_buff = ZI; - read_buff.len = read_buff_size; - read_buff.text = arena_push_array_no_zero(arena, u8, read_buff_size); - - struct sock_read_result res = ZI; - - struct win32_address ws_addr = ZI; - ws_addr.size = sizeof(ws_addr.sas); - - i32 size = recvfrom(ws->sock, (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_win32_address(ws_addr); - if (size >= 0) { - gstat_add(GSTAT_SOCK_BYTES_RECEIVED, size); - res.data.text = read_buff.text; - res.data.len = size; - res.valid = 1; - - /* Pop arena back to end of msg */ - arena_pop_to(arena, arena->pos - read_buff_size + size); - } else { -#if RTC - i32 err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT && err != WSAECONNRESET) { - ASSERT(0); - } -#endif - } - - return res; -} - -/* ========================== * - * Write - * ========================== */ - -void sock_write(struct sock *sock, struct sock_address address, struct string data) -{ - struct win32_sock *ws = (struct win32_sock *)sock; - struct win32_address ws_addr = win32_address_from_sock_address(address); - i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); - if (size > 0) { - gstat_add(GSTAT_SOCK_BYTES_SENT, size); - } -#if RTC - if (size != (i32)data.len) { - i32 err = WSAGetLastError(); - (UNUSED)err; - ASSERT(0); - } -#endif -} diff --git a/src/sys.h b/src/sys.h index 986b29a9..0e9f8d26 100644 --- a/src/sys.h +++ b/src/sys.h @@ -527,6 +527,44 @@ void sys_message_box(enum sys_message_box_kind kind, struct string message); void sys_set_clipboard_text(struct string str); struct string sys_get_clipboard_text(struct arena *arena); +/* ========================== * + * Address + * ========================== */ + +enum sys_address_family { + SYS_ADDRESS_FAMILY_IPV4, + SYS_ADDRESS_FAMILY_IPV6 +}; + +struct sys_address { + b32 valid; + enum sys_address_family family; + /* NOTE: ipnb & portnb are stored in network byte order */ + u8 ipnb[16]; + u16 portnb; +}; + +struct sys_address sys_address_from_string(struct string str); +struct sys_address sys_address_from_port(u16 port); +struct string sys_string_from_address(struct arena *arena, struct sys_address address); +b32 sys_address_eq(struct sys_address a, struct sys_address b); + +/* ========================== * + * Sock + * ========================== */ + +struct sys_sock_read_result { + b32 valid; /* Since data.len = 0 can be valid */ + struct sys_address address; + struct string data; +}; + +struct sys_sock *sys_sock_alloc(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size); +void sys_sock_release(struct sys_sock *sock); + +struct sys_sock_read_result sys_sock_read(struct arena *arena, struct sys_sock *sock); +void sys_sock_write(struct sys_sock *sock, struct sys_address address, struct string data); + /* ========================== * * Util * ========================== */ diff --git a/src/sys_win32.c b/src/sys_win32.c index 5ce73f4f..df91e20b 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -9,17 +9,22 @@ #include "util.h" #include "uni.h" #include "resource.h" +#include "gstat.h" #pragma warning(push, 0) # define UNICODE +# define WIN32_LEAN_AND_MEAN # include +# include +# include +# include # include # include # include # include # include # include -# include +# include #pragma warning(pop) #pragma comment(lib, "kernel32") @@ -31,6 +36,7 @@ #pragma comment(lib, "bcrypt") #pragma comment(lib, "synchronization") #pragma comment(lib, "avrt") +#pragma comment(lib, "ws2_32.lib") #define SYS_WINDOW_EVENT_LISTENERS_MAX 512 #define WINDOW_CLASS_NAME L"power_play_window_class" @@ -115,6 +121,22 @@ struct win32_window { struct win32_window *next_free; }; +struct win32_address { + i32 size; + i32 family; + union { + struct sockaddr_storage sas; + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + }; +}; + +struct win32_sock { + SOCKET sock; + struct win32_sock *next_free; +}; + struct alignas(64) wait_list { u64 value; i16 first_waiter; @@ -292,6 +314,12 @@ GLOBAL struct { struct arena *windows_arena; struct win32_window *first_free_window; + /* Sockets pool */ + WSADATA wsa_data; + struct arena *socks_arena; + struct snc_mutex socks_mutex; + struct win32_sock *first_free_sock; + /* Exit funcs */ @@ -3129,6 +3157,347 @@ u32 sys_num_logical_processors(void) return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); } +/* ========================== * + * Address + * ========================== */ + +INTERNAL struct sys_address sys_address_from_ip_port_cstr(char *ip_cstr, char *port_cstr) +{ + struct sys_address res = ZI; + + struct addrinfo hints = ZI; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + + struct addrinfo *ai_res = 0; + 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.valid = 1; + res.family = SYS_ADDRESS_FAMILY_IPV4; + res.portnb = sockaddr->sin_port; + STATIC_ASSERT(sizeof(sockaddr->sin_addr) == 4); + MEMCPY(res.ipnb, (void *)&sockaddr->sin_addr, 4); + break; + } else if (ai_res->ai_family == AF_INET6) { + /* TODO: Enable ipv6 */ +#if 0 + struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_res->ai_addr; + res.valid = 1; + res.family = SYS_ADDRESS_FAMILY_IPV6; + res.portnb = sockaddr->sin6_port; + STATIC_ASSERT(sizeof(sockaddr->sin6_addr) == 16); + MEMCPY(res.ipnb, (void *)&sockaddr->sin6_addr, 16); + break; +#endif + } + ai_res = ai_res->ai_next; + } + freeaddrinfo(ai_res); + } + + return res; +} + +struct sys_address sys_address_from_string(struct string str) +{ + /* Parse string into ip & port */ + u8 ip_buff[1024]; + u8 port_buff[countof(ip_buff)]; + char *ip_cstr = 0; + char *port_cstr = 0; + { + u64 colon_count = 0; + for (u64 i = 0; i < str.len; ++i) { + u8 c = str.text[i]; + if (c == ':') { + ++colon_count; + } + } + u64 ip_len = 0; + u64 port_len = 0; + u64 parse_len = min_u64(min_u64(str.len, countof(ip_buff) - 1), countof(port_buff) - 1); + if (colon_count > 1 && str.text[0] == '[') { + /* Parse ipv6 with port */ + b32 parse_addr = 1; + for (u64 i = 1; i < parse_len; ++i) { + u8 c = str.text[i]; + if (parse_addr) { + if (c == ']') { + parse_addr = 0; + } else { + ip_buff[ip_len] = c; + ++ip_len; + } + } else if (c != ':') { + port_buff[port_len] = c; + ++port_len; + } + } + } else if (colon_count == 1) { + /* Parse address with port */ + b32 parse_addr = 1; + for (u64 i = 0; i < parse_len; ++i) { + u8 c = str.text[i]; + if (parse_addr) { + if (c == ':') { + parse_addr = 0; + } else { + ip_buff[ip_len] = c; + ++ip_len; + } + } else { + port_buff[port_len] = c; + ++port_len; + } + } + } else { + /* Copy address without port */ + ip_len = min_u64(str.len, countof(ip_buff) - 1); + MEMCPY(ip_buff, str.text, ip_len); + } + if (ip_len > 0) { + ip_buff[ip_len] = 0; + ip_cstr = (char *)ip_buff; + } + if (port_len > 0) { + port_buff[port_len] = 0; + port_cstr = (char *)port_buff; + + } + } + + struct sys_address res = sys_address_from_ip_port_cstr(ip_cstr, port_cstr); + return res; +} + +struct sys_address sys_address_from_port(u16 port) +{ + u8 port_buff[128]; + char *port_cstr = 0; + { + u8 port_buff_reverse[countof(port_buff)]; + u64 port_len = 0; + while (port > 0 && port_len < (countof(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 sys_address res = sys_address_from_ip_port_cstr(0, port_cstr); + + return res; +} + +struct string sys_string_from_address(struct arena *arena, struct sys_address address) +{ + struct string res = ZI; + + if (address.family == SYS_ADDRESS_FAMILY_IPV6) { + /* TODO */ + } else { + u8 ip[4]; + for (u32 i = 0; i < 4; ++i) { + ip[i] = ntohs(address.ipnb[i]); + } + u16 port = ntohs(address.portnb); + res = string_format(arena, LIT("%F.%F.%F.%F:%F"), FMT_UINT(ip[0]), FMT_UINT(ip[1]), FMT_UINT(ip[2]), FMT_UINT(ip[3]), FMT_UINT(port)); + } + + return res; +} + +b32 sys_address_eq(struct sys_address a, struct sys_address b) +{ + return MEMEQ_STRUCT(&a, &b); +} + +INTERNAL struct win32_address win32_address_from_sys_address(struct sys_address addr) +{ + struct win32_address res = ZI; + if (addr.family == SYS_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; +} + +#if 0 +/* If supplied address has ip INADDR_ANY (0), convert ip to localhost */ +INTERNAL struct win32_address win32_address_convert_any_to_localhost(struct win32_address addr) +{ + if (addr.family == AF_INET) { + u8 *bytes = (u8 *)&addr.sin.sin_addr; + b32 is_any = 1; + for (u64 i = 0; i < 4; ++i) { + if (bytes[i] != 0) { + is_any = 0; + break; + } + } + if (is_any) { + bytes[0] = 127; + bytes[3] = 1; + } + } else if (addr.family == AF_INET6) { + u8 *bytes = (u8 *)&addr.sin.sin_addr; + b32 is_any = 1; + for (u64 i = 0; i < 16; ++i) { + if (bytes[i] != 0) { + is_any = 0; + break; + } + } + if (is_any) { + bytes[15] = 1; + } + } + return addr; +} +#endif + +INTERNAL struct sys_address sys_address_from_win32_address(struct win32_address ws_addr) +{ + struct sys_address res = ZI; + if (ws_addr.family == AF_INET) { + res.family = SYS_ADDRESS_FAMILY_IPV4; + res.portnb = ws_addr.sin.sin_port; + MEMCPY(res.ipnb, &ws_addr.sin.sin_addr, 4); + res.valid = 1; + } else if (ws_addr.family == AF_INET6) { + res.family = SYS_ADDRESS_FAMILY_IPV6; + res.portnb = ws_addr.sin6.sin6_port; + MEMCPY(res.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16); + res.valid = 1; + } + return res; +} + + +/* ========================== * + * Sock + * ========================== */ + +struct sys_sock *sys_sock_alloc(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) +{ + struct win32_sock *ws = 0; + { + struct snc_lock lock = snc_lock_e(&G.socks_mutex); + if (G.first_free_sock) { + ws = G.first_free_sock; + G.first_free_sock = ws->next_free; + } else { + ws = arena_push_no_zero(G.socks_arena, struct win32_sock); + } + snc_unlock(&lock); + } + MEMZERO_STRUCT(ws); + + struct sys_address addr = sys_address_from_port(listen_port); + struct win32_address bind_address = win32_address_from_sys_address(addr); + ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP); + { + i32 sb = sndbuf_size; + i32 rb = rcvbuf_size; + u32 imode = 1; + setsockopt(ws->sock, SOL_SOCKET, SO_SNDBUF, (char *)&sb, sizeof(sb)); + setsockopt(ws->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rb, sizeof(rb)); + ioctlsocket(ws->sock, FIONBIO, (unsigned long *)&imode); + } + bind(ws->sock, &bind_address.sa, bind_address.size); + + return (struct sys_sock *)ws; +} + +void sys_sock_release(struct sys_sock *sock) +{ + struct win32_sock *ws = (struct win32_sock *)sock; + closesocket(ws->sock); + struct snc_lock lock = snc_lock_e(&G.socks_mutex); + { + ws->next_free = G.first_free_sock; + G.first_free_sock = ws; + } + snc_unlock(&lock); +} + +struct sys_sock_read_result sys_sock_read(struct arena *arena, struct sys_sock *sock) +{ + struct win32_sock *ws = (struct win32_sock *)sock; + + u64 read_buff_size = KIBI(64); + struct string read_buff = ZI; + read_buff.len = read_buff_size; + read_buff.text = arena_push_array_no_zero(arena, u8, read_buff_size); + + struct sys_sock_read_result res = ZI; + + struct win32_address ws_addr = ZI; + ws_addr.size = sizeof(ws_addr.sas); + + i32 size = recvfrom(ws->sock, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size); + ws_addr.family = ws_addr.sin.sin_family; + + res.address = sys_address_from_win32_address(ws_addr); + if (size >= 0) { + gstat_add(GSTAT_SOCK_BYTES_RECEIVED, size); + res.data.text = read_buff.text; + res.data.len = size; + res.valid = 1; + + /* Pop arena back to end of msg */ + arena_pop_to(arena, arena->pos - read_buff_size + size); + } else { +#if RTC + i32 err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT && err != WSAECONNRESET) { + ASSERT(0); + } +#endif + } + + return res; +} + +void sys_sock_write(struct sys_sock *sock, struct sys_address address, struct string data) +{ + struct win32_sock *ws = (struct win32_sock *)sock; + struct win32_address ws_addr = win32_address_from_sys_address(address); + i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); + if (size > 0) { + gstat_add(GSTAT_SOCK_BYTES_SENT, size); + } +#if RTC + if (size != (i32)data.len) { + i32 err = WSAGetLastError(); + (UNUSED)err; + ASSERT(0); + } +#endif +} + /* ========================== * * Entry point * ========================== */ @@ -3273,15 +3642,19 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Query system info */ GetSystemInfo(&G.info); - /* Set up threads */ + /* Init threads pool */ G.threads_arena = arena_alloc(GIBI(64)); - /* Set up watches */ + /* Init watches pool */ G.watches_arena = arena_alloc(GIBI(64)); - /* Set up windows */ + /* Init windows pool */ G.windows_arena = arena_alloc(GIBI(64)); + /* Init winsock */ + WSAStartup(MAKEWORD(2, 2), &G.wsa_data); + G.socks_arena = arena_alloc(GIBI(64)); + /* Initialize vk table */ win32_init_vk_btn_table(); diff --git a/src/user.c b/src/user.c index 9cb85ce9..92ef51e1 100644 --- a/src/user.c +++ b/src/user.c @@ -16,7 +16,6 @@ #include "collider.h" #include "rand.h" #include "log.h" -#include "sock.h" #include "host.h" #include "bitbuff.h" #include "gstat.h" @@ -2163,7 +2162,7 @@ INTERNAL SYS_JOB_DEF(local_sim_job, _) struct host *host; if (G.connect_address_str.len > 0) { host = host_alloc(0); - struct sock_address addr = sock_address_from_string(G.connect_address_str); + struct sys_address addr = sys_address_from_string(G.connect_address_str); host_queue_connect_to_address(host, addr); } else { host = host_alloc(12345);