diff --git a/src/base/base.cgh b/src/base/base.cgh index 920e665b..e8f0491f 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -250,6 +250,7 @@ //- Time #define NsFromSeconds(s) ((i64)((s) * 1000000000.0)) +#define MsFromNs(ns) ((f64)((ns) / 1000000.0)) #define SecondsFromNs(ns) ((f64)(ns) / 1000000000.0) //- Busy-wait diff --git a/src/net/net_win32/net_win32.c b/src/net/net_win32/net_win32.c index 81557e6e..d0be06f0 100644 --- a/src/net/net_win32/net_win32.c +++ b/src/net/net_win32/net_win32.c @@ -6,18 +6,68 @@ NET_W32_Ctx NET_W32 = Zi; void NET_Bootstrap(void) { Arena *perm = PermArena(); + + // Init winsock WSADATA wsa = Zi; i32 err = WSAStartup(MAKEWORD(2,2), &wsa); if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) { - Panic(StringF(perm, "Failed to initialize WinSock (error code - %F)", FmtSint(err))); + Panic(StringF(perm, "Failed to initialize Winsock (error code - %F)", FmtSint(err))); } + + // Init worker wake sockets + NET_W32.wake_send_sock = NET_W32_CreateDummySocket(); + NET_W32.wake_recv_sock = NET_W32_CreateDummySocket(); + + // Start worker DispatchWave(Lit("Net"), 1, NET_W32_TickForever, 0); } //////////////////////////////////////////////////////////// //~ Helpers +NET_W32_DummySocket NET_W32_CreateDummySocket(void) +{ + NET_W32_DummySocket result = Zi; + b32 ok = 1; + SOCKET sock = 0; + if (ok) + { + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ok = sock != INVALID_SOCKET; + } + if (ok) + { + struct sockaddr_in addr = Zi; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + ok = bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0; + } + struct sockaddr_storage ss = Zi; + i32 ss_sizeof = sizeof(ss); + if (ok) + { + ok = getsockname(sock, (struct sockaddr *)&ss, &ss_sizeof) != SOCKET_ERROR; + } + if (ok) + { + u_long nonblocking = 1; + ok = ioctlsocket(sock, FIONBIO, &nonblocking) == 0; + } + if (!ok) + { + if (sock != INVALID_SOCKET) + { + closesocket(sock); + sock = 0; + } + } + result.sock = sock; + result.addr_size = ss_sizeof; + result.addr = ss; + return result; +} + NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle) { return (NET_W32_Pipe *)pipe_handle.v; @@ -45,7 +95,21 @@ u64 NET_W32_HashFromKey(NET_Key key) void NET_W32_SignalWorker(void) { - // TODO + i32 err = sendto( + NET_W32.wake_send_sock.sock, + (char *)"1", + 1, + 0, + (struct sockaddr *)&NET_W32.wake_recv_sock.addr, + NET_W32.wake_send_sock.addr_size + ); + + + + i32 wsa_err = WSAGetLastError(); + + DEBUGBREAKABLE; + } NET_W32_Peer *NET_W32_TouchPeerFromKey(NET_W32_Pipe *pipe, NET_Key key) @@ -118,6 +182,7 @@ NET_PipeHandle NET_AcquirePipe(void) } UnlockTicketMutex(&NET_W32.pipes_tm); } + NET_W32_SignalWorker(); return (NET_PipeHandle) { .v = (u64) pipe }; } @@ -132,6 +197,7 @@ void NET_Bind(NET_PipeHandle pipe_handle, u64 port) { Atomic64Set(&pipe->desired_port, port); } + // FIXME: Signal here if ports don't match } NET_Key NET_KeyFromString(String host, String port) @@ -215,16 +281,75 @@ void NET_W32_TickForever(WaveLaneCtx *lane) { Arena *perm = PermArena(); + i64 seen_signal = 0; for (;;) { TempArena scratch = BeginScratchNoConflict(); u32 magic = 0xde8c590b; i64 heartbeat_threshold_ns = NsFromSeconds(0.250); - - // TODO: Block until send/recv/signal + i64 passive_run_threshold_ns = NsFromSeconds(0.250); ////////////////////////////// - //- Pop pipes + //- Wait + + { + // Build fd list containing every bound pipe's socket + the worker's signal socket + i64 fds_count = 0; + WSAPOLLFD *fds = 0; + { + LockTicketMutex(&NET_W32.pipes_tm); + { + for (NET_W32_Pipe *pipe = NET_W32.first_pipe; pipe; pipe = pipe->next) + { + if (pipe->udp) + { + fds_count += 1; + } + } + if (NET_W32.wake_recv_sock.sock != 0) + { + fds_count += 1; + } + fds = PushStructsNoZero(scratch.arena, WSAPOLLFD, fds_count); + { + i64 fd_idx = 0; + for (NET_W32_Pipe *pipe = NET_W32.first_pipe; pipe; pipe = pipe->next) + { + if (pipe->udp) + { + fds[fd_idx].fd = pipe->udp; + fds[fd_idx].events = POLLRDNORM; + fd_idx += 1; + } + } + if (NET_W32.wake_recv_sock.sock != 0) + { + fds[fd_idx].fd = NET_W32.wake_recv_sock.sock; + fds[fd_idx].events = POLLRDNORM; + fd_idx += 1; + } + } + } + UnlockTicketMutex(&NET_W32.pipes_tm); + } + + // Wait + i32 timeout_ms = MsFromNs(passive_run_threshold_ns); + WSAPoll(fds, fds_count, timeout_ms); + + // Drain wake recv sock + { + i32 len = 0; + while (len >= 0) + { + u8 buff[Kibi(2)]; + len = recv(NET_W32.wake_recv_sock.sock, (char *)buff, countof(buff), 0); + } + } + } + + ////////////////////////////// + //- Process pipes i64 pipes_count = 0; NET_W32_Pipe **pipes = 0; @@ -433,15 +558,15 @@ void NET_W32_TickForever(WaveLaneCtx *lane) src_data.text = buff + sizeof(header); src_data.len = len - sizeof(header); - // if (!(header.flags & NET_W32_PacketFlag_Heartbeat)) - // { - // LogDebugF( - // "Received msg. packet seq: %F, msg seq: %F, data: \"%F\"", - // FmtSint(header.seq), - // FmtSint(header.msg_seq), - // FmtString(src_data) - // ); - // } + if (!(header.flags & NET_W32_PacketFlag_Heartbeat)) + { + LogDebugF( + "Received msg. packet seq: %F, msg seq: %F, data: \"%F\"", + FmtSint(header.seq), + FmtSint(header.msg_seq), + FmtString(src_data) + ); + } //- Fetch peer NET_W32_Peer *peer = NET_W32_TouchPeerFromKey(pipe, key); @@ -786,7 +911,6 @@ void NET_W32_TickForever(WaveLaneCtx *lane) if (should_send_heartbeat) { struct sockaddr_in6 addr = NET_W32_AddressFromKey(peer->key); - i64 buff_len = 0; u8 buff[Kibi(2)]; NET_W32_PacketHeader header = Zi; diff --git a/src/net/net_win32/net_win32.h b/src/net/net_win32/net_win32.h index 317ce124..2c686c61 100644 --- a/src/net/net_win32/net_win32.h +++ b/src/net/net_win32/net_win32.h @@ -143,6 +143,13 @@ Struct(NET_W32_Pipe) //////////////////////////////////////////////////////////// //~ State types +Struct(NET_W32_DummySocket) +{ + SOCKET sock; + i32 addr_size; + struct sockaddr_storage addr; +}; + Struct(NET_W32_Ctx) { TicketMutex pipes_tm; @@ -152,6 +159,9 @@ Struct(NET_W32_Ctx) NET_W32_Peer *first_free_peer; NET_W32_Packet *first_free_packet; + + NET_W32_DummySocket wake_send_sock; + NET_W32_DummySocket wake_recv_sock; }; extern NET_W32_Ctx NET_W32; @@ -159,6 +169,7 @@ extern NET_W32_Ctx NET_W32; //////////////////////////////////////////////////////////// //~ Helpers +NET_W32_DummySocket NET_W32_CreateDummySocket(void); NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle); NET_Key NET_W32_KeyFromAddress(struct sockaddr_in6 addr); struct sockaddr_in6 NET_W32_AddressFromKey(NET_Key key); diff --git a/src/platform/platform.h b/src/platform/platform.h index 1fa5ca27..909c6dfe 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -2,7 +2,6 @@ //~ Opaque types Struct(PLT_Watch); -Struct(PLT_Sock); //////////////////////////////////////////////////////////// //~ File system types @@ -27,34 +26,6 @@ Struct(PLT_FileMap) b32 valid; }; -//////////////////////////////////////////////////////////// -//~ Address types - -Enum(PLT_AddressFamily) -{ - PLT_AddressFamily_Ipv4, - PLT_AddressFamily_Ipv6 -}; - -Struct(PLT_Address) -{ - b32 valid; - PLT_AddressFamily family; - // NOTE: ipnb & portnb are stored in network byte order - u8 ipnb[16]; - u16 portnb; -}; - -//////////////////////////////////////////////////////////// -//~ Sock types - -Struct(PLT_SockReadResult) -{ - b32 valid; // Since data.len = 0 can be valid - PLT_Address address; - String data; -}; - //////////////////////////////////////////////////////////// //~ Message box types @@ -102,23 +73,6 @@ PLT_FileMap PLT_OpenFileMap(PLT_File file); void PLT_CloseFileMap(PLT_FileMap map); String PLT_GetFileMapData(PLT_FileMap map); -//////////////////////////////////////////////////////////// -//~ @hookdecl Address helpers - -PLT_Address PLT_AddressFromString(String str); -PLT_Address PLT_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr); -PLT_Address PLT_AddressFromPort(u16 port); -String PLT_StringFromAddress(Arena *arena, PLT_Address address); -b32 PLT_MatchAddress(PLT_Address a, PLT_Address b); - -//////////////////////////////////////////////////////////// -//~ @hookdecl Socket - -PLT_Sock *PLT_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size); -void PLT_ReleaseSock(PLT_Sock *sock); -PLT_SockReadResult PLT_ReadSock(Arena *arena, PLT_Sock *sock); -void PLT_WriteSock(PLT_Sock *sock, PLT_Address address, String data); - //////////////////////////////////////////////////////////// //~ @hookdecl Utils diff --git a/src/platform/platform_win32/platform_win32.c b/src/platform/platform_win32/platform_win32.c index 1498b739..ca48d1f7 100644 --- a/src/platform/platform_win32/platform_win32.c +++ b/src/platform/platform_win32/platform_win32.c @@ -8,10 +8,6 @@ void PLT_Bootstrap(void) //- Init watches pool PLT_W32.watches_arena = AcquireArena(Gibi(64)); - // Init winsock - WSAStartup(MAKEWORD(2, 2), &PLT_W32.wsa_data); - PLT_W32.socks_arena = AcquireArena(Gibi(64)); - // Init timer DispatchWave(Lit("Win32 timer sync"), 1, PLT_W32_SyncTimerForever, 0); } @@ -62,92 +58,6 @@ String PLT_W32_StringFromWin32Path(Arena *arena, wchar_t *src) return result; } -//////////////////////////////////////////////////////////// -//~ Address - -PLT_W32_Address PLT_W32_Win32AddressFromPlatformAddress(PLT_Address addr) -{ - PLT_W32_Address result = Zi; - if (addr.family == PLT_AddressFamily_Ipv4) - { - result.family = AF_INET; - result.size = sizeof(struct sockaddr_in); - result.sin.sin_port = addr.portnb; - result.sin.sin_family = result.family; - CopyBytes(&result.sin.sin_addr, addr.ipnb, 4); - } - else - { - result.family = AF_INET6; - result.sin6.sin6_port = addr.portnb; - result.sin6.sin6_family = result.family; - result.size = sizeof(struct sockaddr_in6); - CopyBytes(&result.sin6.sin6_addr.s6_addr, addr.ipnb, 16); - } - return result; -} - -// If supplied address has ip INADDR_ANY (0), convert ip to localhost -PLT_W32_Address PLT_W32_ConvertAnyaddrToLocalhost(PLT_W32_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; -} - -PLT_Address PLT_W32_PlatformAddressFromWin32Address(PLT_W32_Address ws_addr) -{ - PLT_Address result = Zi; - if (ws_addr.family == AF_INET) - { - result.family = PLT_AddressFamily_Ipv4; - result.portnb = ws_addr.sin.sin_port; - CopyBytes(result.ipnb, &ws_addr.sin.sin_addr, 4); - result.valid = 1; - } - else if (ws_addr.family == AF_INET6) - { - result.family = PLT_AddressFamily_Ipv6; - result.portnb = ws_addr.sin6.sin6_port; - CopyBytes(result.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16); - result.valid = 1; - } - return result; -} - //////////////////////////////////////////////////////////// //~ Timer job @@ -503,317 +413,6 @@ String PLT_GetFileMapData(PLT_FileMap map) return map.mapped_memory; } -//////////////////////////////////////////////////////////// -//~ @hookimpl Address helpers - -PLT_Address PLT_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr) -{ - PLT_Address result = Zi; - - struct addrinfo hints = Zi; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; - - struct addrinfo *ai_result = 0; - i32 status = getaddrinfo(ip_cstr, port_cstr, &hints, &ai_result); - if (status == 0) - { - while (ai_result) - { - if (ai_result->ai_family == AF_INET) - { - struct sockaddr_in *sockaddr = (struct sockaddr_in *)ai_result->ai_addr; - result.valid = 1; - result.family = PLT_AddressFamily_Ipv4; - result.portnb = sockaddr->sin_port; - StaticAssert(sizeof(sockaddr->sin_addr) == 4); - CopyBytes(result.ipnb, (void *)&sockaddr->sin_addr, 4); - break; - } - else if (ai_result->ai_family == AF_INET6) - { - // TODO: Enable ipv6 - // struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr; - // result.valid = 1; - // result.family = PLT_AddressFamily_Ipv6; - // result.portnb = sockaddr->sin6_port; - // StaticAssert(sizeof(sockaddr->sin6_addr) == 16); - // CopyBytes(result.ipnb, (void *)&sockaddr->sin6_addr, 16); - // break; - } - ai_result = ai_result->ai_next; - } - freeaddrinfo(ai_result); - } - - return result; -} - -PLT_Address PLT_AddressFromString(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 = MinU64(MinU64(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 = MinU64(str.len, countof(ip_buff) - 1); - CopyBytes(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; - - } - } - - PLT_Address result = PLT_AddressFromIpPortCstr(ip_cstr, port_cstr); - return result; -} - -PLT_Address PLT_AddressFromPort(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; - } - } - - PLT_Address result = PLT_AddressFromIpPortCstr(0, port_cstr); - - return result; -} - -String PLT_StringFromAddress(Arena *arena, PLT_Address address) -{ - String result = Zi; - - if (address.family == PLT_AddressFamily_Ipv6) - { - // TODO - } - else - { - u8 ip[4]; - for (u32 i = 0; i < 4; ++i) - { - ip[i] = ntohs(address.ipnb[i]); - } - u16 port = ntohs(address.portnb); - result = StringF(arena, "%F.%F.%F.%F:%F", FmtUint(ip[0]), FmtUint(ip[1]), FmtUint(ip[2]), FmtUint(ip[3]), FmtUint(port)); - } - - return result; -} - -b32 PLT_MatchAddress(PLT_Address a, PLT_Address b) -{ - return MatchStruct(&a, &b); -} - -//////////////////////////////////////////////////////////// -//~ @hookimpl Socket - -PLT_Sock *PLT_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) -{ - PLT_W32_Sock *ws = 0; - { - Lock lock = LockE(&PLT_W32.socks_mutex); - if (PLT_W32.first_free_sock) - { - ws = PLT_W32.first_free_sock; - PLT_W32.first_free_sock = ws->next_free; - } - else - { - ws = PushStructNoZero(PLT_W32.socks_arena, PLT_W32_Sock); - } - Unlock(&lock); - } - ZeroStruct(ws); - - PLT_Address addr = PLT_AddressFromPort(listen_port); - PLT_W32_Address bind_address = PLT_W32_Win32AddressFromPlatformAddress(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 (PLT_Sock *)ws; -} - -void PLT_ReleaseSock(PLT_Sock *sock) -{ - PLT_W32_Sock *ws = (PLT_W32_Sock *)sock; - closesocket(ws->sock); - Lock lock = LockE(&PLT_W32.socks_mutex); - { - ws->next_free = PLT_W32.first_free_sock; - PLT_W32.first_free_sock = ws; - } - Unlock(&lock); -} - -PLT_SockReadResult PLT_ReadSock(Arena *arena, PLT_Sock *sock) -{ - PLT_W32_Sock *ws = (PLT_W32_Sock *)sock; - - u64 read_buff_size = Kibi(64); - String read_buff = Zi; - read_buff.len = read_buff_size; - read_buff.text = PushStructsNoZero(arena, u8, read_buff_size); - - PLT_SockReadResult result = Zi; - - PLT_W32_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; - - result.address = PLT_W32_PlatformAddressFromWin32Address(ws_addr); - if (size >= 0) - { - AddGstat(SockBytesReceived, size); - result.data.text = read_buff.text; - result.data.len = size; - result.valid = 1; - - // PopStruct arena back to end of msg - PopTo(arena, arena->pos - read_buff_size + size); - } - else - { - if (IsRtcEnabled) - { - i32 err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT && err != WSAECONNRESET) - { - Assert(0); - } - } - } - - return result; -} - -void PLT_WriteSock(PLT_Sock *sock, PLT_Address address, String data) -{ - PLT_W32_Sock *ws = (PLT_W32_Sock *)sock; - PLT_W32_Address ws_addr = PLT_W32_Win32AddressFromPlatformAddress(address); - i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); - if (size > 0) - { - AddGstat(SockBytesSent, size); - } - if (IsRtcEnabled) - { - if (size != (i32)data.len) - { - i32 err = WSAGetLastError(); - Assert(0); - } - } -} - //////////////////////////////////////////////////////////// //~ @hookimpl Utils diff --git a/src/platform/platform_win32/platform_win32.h b/src/platform/platform_win32/platform_win32.h index 41b46dbb..443ed784 100644 --- a/src/platform/platform_win32/platform_win32.h +++ b/src/platform/platform_win32/platform_win32.h @@ -9,31 +9,6 @@ Struct(PLT_W32_Watch) u8 results_buff[Kibi(64)]; }; -//////////////////////////////////////////////////////////// -//~ Address types - -Struct(PLT_W32_Address) -{ - i32 size; - i32 family; - union - { - struct sockaddr_storage sas; - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - }; -}; - -//////////////////////////////////////////////////////////// -//~ Sock types - -Struct(PLT_W32_Sock) -{ - SOCKET sock; - PLT_W32_Sock *next_free; -}; - //////////////////////////////////////////////////////////// //~ State types @@ -47,12 +22,6 @@ Struct(PLT_W32_Ctx) Arena *watches_arena; PLT_W32_Watch *watches_first_free; - //- Socket pool - WSADATA wsa_data; - Arena *socks_arena; - Mutex socks_mutex; - PLT_W32_Sock *first_free_sock; - //- Timer Fence timer_fence; Atomic64Padded average_timer_period_ns; @@ -70,13 +39,6 @@ DateTime PLT_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st); String PLT_W32_StringFromWin32Path(Arena *arena, wchar_t *src); -//////////////////////////////////////////////////////////// -//~ Address - -PLT_W32_Address PLT_W32_Win32AddressFromPlatformAddress(PLT_Address addr); -PLT_W32_Address PLT_W32_ConvertAnyaddrToLocalhost(PLT_W32_Address addr); -PLT_Address PLT_W32_PlatformAddressFromWin32Address(PLT_W32_Address ws_addr); - //////////////////////////////////////////////////////////// //~ Timer job diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 1cfb8c1e..6f2b429e 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -3759,7 +3759,11 @@ void V_TickForever(WaveLaneCtx *lane) // FIXME: Remove this (testing) NET_Key server_key = NET_KeyFromString(Lit("127.0.0.1"), Lit("22121")); - NET_Push(net_pipe, server_key, Lit("HELLO!!!!"), 0); + + if (frame->held_buttons[Button_R]) + { + NET_Push(net_pipe, server_key, Lit("HELLO!!!!"), 0); + }