From ee85f59643d608757608068e4847aae88cdde2a5 Mon Sep 17 00:00:00 2001 From: Jak Barnes Date: Sun, 24 Feb 2019 01:59:09 +0000 Subject: [PATCH] more example stubs more changes to rnet i'm tired, it's 2am why am i doing this --- examples/network/network_ping_pong.c | 41 +- examples/network/network_resolve_host.c | 4 +- examples/network/network_tcp_client.c | 93 +++ examples/network/network_tcp_server.c | 100 +++ examples/network/network_udp_client.c | 74 ++ examples/network/network_udp_server.c | 74 ++ .../examples/network_tcp_client.vcxproj | 173 +++++ .../examples/network_tcp_server.vcxproj | 173 +++++ .../examples/network_udp_client.vcxproj | 173 +++++ .../examples/network_udp_server.vcxproj | 173 +++++ projects/VS2017/raylib.sln | 80 ++- src/raylib.h | 123 +--- src/rnet.c | 666 +++++++++++------- src/sysnet.h | 266 +++++-- 14 files changed, 1782 insertions(+), 431 deletions(-) create mode 100644 examples/network/network_tcp_client.c create mode 100644 examples/network/network_tcp_server.c create mode 100644 examples/network/network_udp_client.c create mode 100644 examples/network/network_udp_server.c create mode 100644 projects/VS2017/examples/network_tcp_client.vcxproj create mode 100644 projects/VS2017/examples/network_tcp_server.vcxproj create mode 100644 projects/VS2017/examples/network_udp_client.vcxproj create mode 100644 projects/VS2017/examples/network_udp_server.vcxproj diff --git a/examples/network/network_ping_pong.c b/examples/network/network_ping_pong.c index 309b8f507..9377b5019 100644 --- a/examples/network/network_ping_pong.c +++ b/examples/network/network_ping_pong.c @@ -25,7 +25,7 @@ int main() { // Setup - int screenWidth = 800; + int screenWidth = 800; int screenHeight = 450; InitWindow( screenWidth, screenHeight, "raylib [network] example - ping pong"); @@ -38,23 +38,26 @@ int main() // Create the server SocketConfig server_cfg = { - .host = "127.0.0.1", - .port = 8080, - .server = true, - .nonblocking = true, + .host = "127.0.0.1", + .port = "8080", + .server = true, + .nonblocking = true }; SocketResult server_res; memset(&server_res, 0, sizeof(SocketResult)); { bool ok = SocketOpen(&server_cfg, &server_res); - if (!ok) { return false; } + if (!ok) + { + return false; + } } // Create the client SocketConfig client_cfg = { - .host = "127.0.0.1", - .port = 8080, + .host = "127.0.0.1", + .port = "8080" }; SocketResult client_res; @@ -63,8 +66,8 @@ int main() bool ok = SocketOpen(&client_cfg, &client_res); if (!ok) { - printf("failed to open: status %d, errno %d\n", - client_res.status, client_res.saved_errno); + printf("failed to open: status %d, errno %d\n", client_res.status, + client_res.socket.error); return false; } } @@ -76,6 +79,8 @@ int main() char recvBuffer[512]; bool connected = false; memset(&recvBuffer, 0, 8); + char pingmsg[6] = "Ping!"; + char pongmsg[6] = "Pong!"; // Main game loop while (!WindowShouldClose()) @@ -91,7 +96,7 @@ int main() { if (SocketAccept(server_res.socket.handle, &connection)) { - ping = true; + ping = true; connected = true; } } @@ -99,18 +104,18 @@ int main() // Connected if (connected) { - int bytesRecv = SocketReceive(&connection.socket, recvBuffer, 5); + int bytesRecv = SocketReceive(&connection.socket, recvBuffer, sizeof(pingmsg)); if (bytesRecv > 0) { - if (strcmp(recvBuffer, "Ping!") == 0) + if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; - printf("Ping!\n"); + printf("%s\n", pingmsg); } - if (strcmp(recvBuffer, "Pong!") == 0) + if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; - printf("Pong!\n"); + printf("%s\n", pongmsg); } } @@ -120,12 +125,12 @@ int main() if (ping) { ping = false; - SocketSend(&client_res.socket, "Ping!", 5); + SocketSend(&client_res.socket, pingmsg, sizeof(pingmsg)); } else if (pong) { pong = false; - SocketSend(&client_res.socket, "Pong!", 5); + SocketSend(&client_res.socket, pongmsg, sizeof(pongmsg)); } elapsed = 0.0f; } diff --git a/examples/network/network_resolve_host.c b/examples/network/network_resolve_host.c index 6ad77c591..c0ae9025c 100644 --- a/examples/network/network_resolve_host.c +++ b/examples/network/network_resolve_host.c @@ -38,8 +38,8 @@ int main() AddressInformation addr; ResolveHost("www.google.com", "80", &addr); - // ResolveIP("8.8.8.8", NULL, NAME_INFO_DEFAULT); - // ResolveIP("2001:4860:4860::8888", "80", NAME_INFO_NUMERICSERV); + ResolveIP("8.8.8.8", NULL, NAME_INFO_DEFAULT); + ResolveIP("2001:4860:4860::8888", "80", NAME_INFO_NUMERICSERV); // Main game loop while (!WindowShouldClose()) diff --git a/examples/network/network_tcp_client.c b/examples/network/network_tcp_client.c new file mode 100644 index 000000000..e1bd57f95 --- /dev/null +++ b/examples/network/network_tcp_client.c @@ -0,0 +1,93 @@ +/******************************************************************************************* + * + * raylib [network] example - Resolve host + * + * Welcome to raylib! + * + * To test examples, just press F6 and execute raylib_compile_execute script + * Note that compiled executable is placed in the same folder as .c file + * + * You can find all basic examples on C:\raylib\raylib\examples folder or + * raylib official webpage: www.raylib.com + * + * Enjoy using raylib. :) + * + * This example has been created using raylib 2.0 (www.raylib.com) + * raylib is licensed under an unmodified zlib/libpng license (View raylib.h + *for details) + * + * Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + +#include "raylib.h" + +#include + +#define PORT "3490" // the port client will be connecting to +#define MAXDATASIZE 100 // max number of bytes we can get at once + +int main() +{ + // Setup + int screenWidth = 800; + int screenHeight = 450; + InitWindow( + screenWidth, screenHeight, "raylib [network] example - ping pong"); + SetTargetFPS(60); + + SetTraceLogLevel(LOG_DEBUG); + + // Networking + InitNetwork(); + + int numbytes; + char buf[MAXDATASIZE]; + + // Create the client + SocketConfig client_cfg = { + .host = "127.0.0.1", + .port = "8080" + }; + SocketResult client_res; + memset(&client_res, 0, sizeof(SocketResult)); + { + bool ok = SocketOpen(&client_cfg, &client_res); + if (!ok) + { + printf("Failed to open: status %d, errno %d\n", client_res.status, + client_res.socket.error); + return false; + } + } + + // Main game loop + while (!WindowShouldClose()) + { + // Draw + BeginDrawing(); + + // Clear + ClearBackground(RAYWHITE); + + // Receive bytes from the server + numbytes = SocketReceive(client_res.socket.handle, buf, MAXDATASIZE - 1); + if (numbytes == -1) + { + printf("Client: error recv '%s'\n", buf); + break; + } + buf[numbytes] = '\0'; + printf("Client: received '%s'\n", buf); + break; + + // End draw + EndDrawing(); + } + + // Cleanup + SocketClose(client_res.socket.handle); + CloseNetwork(); + CloseWindow(); + return 0; +} \ No newline at end of file diff --git a/examples/network/network_tcp_server.c b/examples/network/network_tcp_server.c new file mode 100644 index 000000000..2dca7c0f9 --- /dev/null +++ b/examples/network/network_tcp_server.c @@ -0,0 +1,100 @@ +/******************************************************************************************* + * + * raylib [network] example - Resolve host + * + * Welcome to raylib! + * + * To test examples, just press F6 and execute raylib_compile_execute script + * Note that compiled executable is placed in the same folder as .c file + * + * You can find all basic examples on C:\raylib\raylib\examples folder or + * raylib official webpage: www.raylib.com + * + * Enjoy using raylib. :) + * + * This example has been created using raylib 2.0 (www.raylib.com) + * raylib is licensed under an unmodified zlib/libpng license (View raylib.h + *for details) + * + * Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + + +#include "raylib.h" +#include + +int main() +{ + // Setup + int screenWidth = 800; + int screenHeight = 450; + InitWindow( + screenWidth, screenHeight, "raylib [network] example - ping pong"); + SetTargetFPS(60); + + SetTraceLogLevel(LOG_DEBUG); + + // Networking + InitNetwork(); + + + // Create the server + SocketConfig server_cfg = { + .host = "127.0.0.1", + .port = "8080", + .server = true, + .nonblocking = true + }; + + SocketResult server_res; + memset(&server_res, 0, sizeof(SocketResult)); + { + bool ok = SocketOpen(&server_cfg, &server_res); + if (!ok) + { + return false; + } + } + + + SocketResult connection; + memset(&connection, 0, sizeof(SocketResult)); + + char recvBuffer[512]; + memset(&recvBuffer, 0, 8); + + bool connected = false; + + + // Main game loop + while (!WindowShouldClose()) + { + // Draw + BeginDrawing(); + + // Clear + ClearBackground(RAYWHITE); + + // Wait for a valid connection + if (!connected) + { + if (SocketAccept(server_res.socket.handle, &connection)) + { + connected = true; + } + } + + if (connected) + { + SocketSend(&connection, "Hello, world!", 13); + } + + // End draw + EndDrawing(); + } + + // Cleanup + CloseWindow(); + return 0; +} \ No newline at end of file diff --git a/examples/network/network_udp_client.c b/examples/network/network_udp_client.c new file mode 100644 index 000000000..a3be400fd --- /dev/null +++ b/examples/network/network_udp_client.c @@ -0,0 +1,74 @@ +/******************************************************************************************* + * + * raylib [network] example - Resolve host + * + * Welcome to raylib! + * + * To test examples, just press F6 and execute raylib_compile_execute script + * Note that compiled executable is placed in the same folder as .c file + * + * You can find all basic examples on C:\raylib\raylib\examples folder or + * raylib official webpage: www.raylib.com + * + * Enjoy using raylib. :) + * + * This example has been created using raylib 2.0 (www.raylib.com) + * raylib is licensed under an unmodified zlib/libpng license (View raylib.h + *for details) + * + * Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + + +#include "raylib.h" +#include + +int main() +{ + // Setup + int screenWidth = 800; + int screenHeight = 450; + InitWindow( + screenWidth, screenHeight, "raylib [network] example - ping pong"); + SetTargetFPS(60); + + SetTraceLogLevel(LOG_DEBUG); + + // Networking + InitNetwork(); + + unsigned char buf[1024]; + unsigned char magic; + int monkeycount; + long altitude; + double absurdityfactor; + char* s = "Great unmitigated Zot! You've found the Runestaff!"; + char s2[96]; + unsigned int packetsize, ps2; + + packetsize = PackData(buf, "CHhlsd", 'B', 0, 37, -5, s, -3490.5); + packi16(buf + 1, packetsize); // store packet size in packet for kicks + + printf("packet is %u bytes\n", packetsize); + UnpackData(buf, "CHhl96sd", &magic, &ps2, &monkeycount, &altitude, s2, &absurdityfactor); + printf("'%c' %hhu %u %ld \"%s\" %f\n", magic, ps2, monkeycount, altitude, s2, absurdityfactor); + + + // Main game loop + while (!WindowShouldClose()) + { + // Draw + BeginDrawing(); + + // Clear + ClearBackground(RAYWHITE); + + // End draw + EndDrawing(); + } + + // Cleanup + CloseWindow(); + return 0; +} \ No newline at end of file diff --git a/examples/network/network_udp_server.c b/examples/network/network_udp_server.c new file mode 100644 index 000000000..a3be400fd --- /dev/null +++ b/examples/network/network_udp_server.c @@ -0,0 +1,74 @@ +/******************************************************************************************* + * + * raylib [network] example - Resolve host + * + * Welcome to raylib! + * + * To test examples, just press F6 and execute raylib_compile_execute script + * Note that compiled executable is placed in the same folder as .c file + * + * You can find all basic examples on C:\raylib\raylib\examples folder or + * raylib official webpage: www.raylib.com + * + * Enjoy using raylib. :) + * + * This example has been created using raylib 2.0 (www.raylib.com) + * raylib is licensed under an unmodified zlib/libpng license (View raylib.h + *for details) + * + * Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + + +#include "raylib.h" +#include + +int main() +{ + // Setup + int screenWidth = 800; + int screenHeight = 450; + InitWindow( + screenWidth, screenHeight, "raylib [network] example - ping pong"); + SetTargetFPS(60); + + SetTraceLogLevel(LOG_DEBUG); + + // Networking + InitNetwork(); + + unsigned char buf[1024]; + unsigned char magic; + int monkeycount; + long altitude; + double absurdityfactor; + char* s = "Great unmitigated Zot! You've found the Runestaff!"; + char s2[96]; + unsigned int packetsize, ps2; + + packetsize = PackData(buf, "CHhlsd", 'B', 0, 37, -5, s, -3490.5); + packi16(buf + 1, packetsize); // store packet size in packet for kicks + + printf("packet is %u bytes\n", packetsize); + UnpackData(buf, "CHhl96sd", &magic, &ps2, &monkeycount, &altitude, s2, &absurdityfactor); + printf("'%c' %hhu %u %ld \"%s\" %f\n", magic, ps2, monkeycount, altitude, s2, absurdityfactor); + + + // Main game loop + while (!WindowShouldClose()) + { + // Draw + BeginDrawing(); + + // Clear + ClearBackground(RAYWHITE); + + // End draw + EndDrawing(); + } + + // Cleanup + CloseWindow(); + return 0; +} \ No newline at end of file diff --git a/projects/VS2017/examples/network_tcp_client.vcxproj b/projects/VS2017/examples/network_tcp_client.vcxproj new file mode 100644 index 000000000..d33fa7424 --- /dev/null +++ b/projects/VS2017/examples/network_tcp_client.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + + 15.0 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5} + Win32Proj + network_tcp_client + 10.0.17763.0 + network_tcp_client + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + true + + + false + + + false + + + + NotUsing + Level4 + Disabled + + + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + false + + + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + false + + + Console + true + %(AdditionalLibraryDirectories) + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/projects/VS2017/examples/network_tcp_server.vcxproj b/projects/VS2017/examples/network_tcp_server.vcxproj new file mode 100644 index 000000000..6da6ecf53 --- /dev/null +++ b/projects/VS2017/examples/network_tcp_server.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + + 15.0 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131} + Win32Proj + network_tcp_server + 10.0.17763.0 + network_tcp_server + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + true + + + false + + + false + + + + NotUsing + Level4 + Disabled + + + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + false + + + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + false + + + Console + true + %(AdditionalLibraryDirectories) + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/projects/VS2017/examples/network_udp_client.vcxproj b/projects/VS2017/examples/network_udp_client.vcxproj new file mode 100644 index 000000000..cd93a1c4c --- /dev/null +++ b/projects/VS2017/examples/network_udp_client.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + + 15.0 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D} + Win32Proj + network_udp_client + 10.0.17763.0 + network_udp_client + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + true + + + false + + + false + + + + NotUsing + Level4 + Disabled + + + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + false + + + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + false + + + Console + true + %(AdditionalLibraryDirectories) + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/projects/VS2017/examples/network_udp_server.vcxproj b/projects/VS2017/examples/network_udp_server.vcxproj new file mode 100644 index 000000000..1a47e09f0 --- /dev/null +++ b/projects/VS2017/examples/network_udp_server.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + + 15.0 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A} + Win32Proj + network_udp_server + 10.0.17763.0 + network_udp_server + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + true + + + false + + + false + + + + NotUsing + Level4 + Disabled + + + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + false + + + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + false + + + Console + true + %(AdditionalLibraryDirectories) + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/projects/VS2017/raylib.sln b/projects/VS2017/raylib.sln index 7a104cad6..1fd86c930 100644 --- a/projects/VS2017/raylib.sln +++ b/projects/VS2017/raylib.sln @@ -17,9 +17,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_chat_server", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_ping_pong", "examples\network_ping_pong.vcxproj", "{56EB485C-00A9-459E-B758-2E86316EB7FD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_serialisation", "examples\network_resolve_host.vcxproj", "{A16D19CB-6AF4-4D17-8318-EABD8805247C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_resolve_host", "examples\network_resolve_host.vcxproj", "{A16D19CB-6AF4-4D17-8318-EABD8805247C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_resolve_host", "examples\network_serialisation.vcxproj", "{46B18968-56BC-4FB1-A7C0-FA418E095AFD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_serialisation", "examples\network_serialisation.vcxproj", "{46B18968-56BC-4FB1-A7C0-FA418E095AFD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_tcp_client", "examples\network_tcp_client.vcxproj", "{3415FF09-CF64-451E-AC03-F2A30EC2AFD5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_tcp_server", "examples\network_tcp_server.vcxproj", "{B7AA867E-AA24-4CD6-A61E-5A0B9A068131}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_udp_client", "examples\network_udp_client.vcxproj", "{0207D9BA-25E0-44A0-9B54-952FFDA3D58D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_udp_server", "examples\network_udp_server.vcxproj", "{C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -149,6 +157,70 @@ Global {46B18968-56BC-4FB1-A7C0-FA418E095AFD}.Release|x64.Build.0 = Release|x64 {46B18968-56BC-4FB1-A7C0-FA418E095AFD}.Release|x86.ActiveCfg = Release|Win32 {46B18968-56BC-4FB1-A7C0-FA418E095AFD}.Release|x86.Build.0 = Release|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug.DLL|x64.ActiveCfg = Debug|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug.DLL|x64.Build.0 = Debug|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug.DLL|x86.ActiveCfg = Debug|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug.DLL|x86.Build.0 = Debug|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug|x64.ActiveCfg = Debug|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug|x64.Build.0 = Debug|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug|x86.ActiveCfg = Debug|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Debug|x86.Build.0 = Debug|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release.DLL|x64.ActiveCfg = Release|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release.DLL|x64.Build.0 = Release|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release.DLL|x86.ActiveCfg = Release|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release.DLL|x86.Build.0 = Release|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release|x64.ActiveCfg = Release|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release|x64.Build.0 = Release|x64 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release|x86.ActiveCfg = Release|Win32 + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5}.Release|x86.Build.0 = Release|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug.DLL|x64.ActiveCfg = Debug|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug.DLL|x64.Build.0 = Debug|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug.DLL|x86.ActiveCfg = Debug|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug.DLL|x86.Build.0 = Debug|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug|x64.ActiveCfg = Debug|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug|x64.Build.0 = Debug|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug|x86.ActiveCfg = Debug|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Debug|x86.Build.0 = Debug|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release.DLL|x64.ActiveCfg = Release|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release.DLL|x64.Build.0 = Release|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release.DLL|x86.ActiveCfg = Release|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release.DLL|x86.Build.0 = Release|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release|x64.ActiveCfg = Release|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release|x64.Build.0 = Release|x64 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release|x86.ActiveCfg = Release|Win32 + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131}.Release|x86.Build.0 = Release|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug.DLL|x64.ActiveCfg = Debug|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug.DLL|x64.Build.0 = Debug|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug.DLL|x86.ActiveCfg = Debug|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug.DLL|x86.Build.0 = Debug|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug|x64.ActiveCfg = Debug|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug|x64.Build.0 = Debug|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug|x86.ActiveCfg = Debug|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Debug|x86.Build.0 = Debug|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release.DLL|x64.ActiveCfg = Release|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release.DLL|x64.Build.0 = Release|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release.DLL|x86.ActiveCfg = Release|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release.DLL|x86.Build.0 = Release|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release|x64.ActiveCfg = Release|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release|x64.Build.0 = Release|x64 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release|x86.ActiveCfg = Release|Win32 + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D}.Release|x86.Build.0 = Release|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug.DLL|x64.ActiveCfg = Debug|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug.DLL|x64.Build.0 = Debug|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug.DLL|x86.ActiveCfg = Debug|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug.DLL|x86.Build.0 = Debug|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug|x64.ActiveCfg = Debug|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug|x64.Build.0 = Debug|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug|x86.ActiveCfg = Debug|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Debug|x86.Build.0 = Debug|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release.DLL|x64.ActiveCfg = Release|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release.DLL|x64.Build.0 = Release|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release.DLL|x86.ActiveCfg = Release|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release.DLL|x86.Build.0 = Release|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release|x64.ActiveCfg = Release|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release|x64.Build.0 = Release|x64 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release|x86.ActiveCfg = Release|Win32 + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -161,6 +233,10 @@ Global {56EB485C-00A9-459E-B758-2E86316EB7FD} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} {A16D19CB-6AF4-4D17-8318-EABD8805247C} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} {46B18968-56BC-4FB1-A7C0-FA418E095AFD} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + {3415FF09-CF64-451E-AC03-F2A30EC2AFD5} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + {B7AA867E-AA24-4CD6-A61E-5A0B9A068131} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + {0207D9BA-25E0-44A0-9B54-952FFDA3D58D} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + {C8C754B7-E53D-4D7D-A3F7-F52F5B55FA2A} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/src/raylib.h b/src/raylib.h index df7073fc2..42c287987 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -168,7 +168,7 @@ #endif // Network typedefs -typedef int SocketHandle; +typedef unsigned int SocketHandle; // Vector2 type typedef struct Vector2 { @@ -440,7 +440,7 @@ typedef struct VrStereoConfig { typedef struct IPAddress { unsigned char* host; /* 32-bit IPv4 host address */ - unsigned char* port; /* 16-bit protocol port */ + unsigned int port; /* 16-bit protocol port */ } IPAddress; // Used by the getaddrinfo function to hold host address information. @@ -456,8 +456,6 @@ typedef struct AddressInformation struct AddressInformation *next; // Next structure in linked list } AddressInformation; -// Used -// // The sockaddr structure varies depending on the protocol selected. // Except for the sin*_family parameter, sockaddr contents are expressed // in network byte order. @@ -474,96 +472,56 @@ typedef struct SocketOpt { int valueLen; } SocketOpt; +typedef enum +{ + SOCKET_TCP = 1, // SOCK_STREAM + SOCKET_UDP = 2 // SOCK_DGRAM +} SocketType; + typedef struct Socket { - int ready; // Is the socket ready? i.e. has information - SocketHandle handle; // The socket handle id - IPAddress host; // The host/target ip for this socket - int sflag; // Is this socket a server socket (i.e. TCP/UDP Listen Server) + int ready; // Is the socket ready? i.e. has information + int error; // The last error code to have occured using this socket + bool isServer; // Is this socket a server socket (i.e. TCP/UDP Listen Server) + IPAddress address; // The host/target ip for this socket + SocketType type; // Is this socket a TCP or UDP socket? + SocketHandle handle; // The socket handle id } Socket; // Configuration for a socket. Not all of these fields need to // be set, and ones omitted from a C99-style "designated initializer" -// struct literal will be zeroed out and replaced with defaults. -typedef struct SocketConfig { - /* Hostname and port, for TCP or UDP sockets. */ - char *host; - int port; +// struct literal will be zeroed out and replaced with defaults. +typedef struct SocketConfig +{ + // Hostname and port, for TCP or UDP sockets. */ + char *host; + char *port; - /* Path, for Unix domain socket. */ - char *path; + // IPv4 or IPv6 address; if neither is specified, let OS decide. + // These fields should be used in place of 'host' above. + char *IPv4; + char *IPv6; + bool server; // Listen for incoming clients? + bool datagram; // TCP or UDP? + bool nonblocking; // non-blocking operation? + int backlog_size; // set a custom backlog size - /* IPv4 or IPv6 address; if neither is specified, let OS decide. - * These fields should be used in place of 'host' above. */ - char *IPv4; - char *IPv6; + SocketOpt sockopts[MAX_SOCK_OPTS]; - bool server; /* Listen for incoming clients? */ - bool datagram; /* UDP or datagram? */ - bool nonblocking; /* non-blocking operation? */ - - int backlog_size; /* set a custom backlog size */ - - SocketOpt sockopts[MAX_SOCK_OPTS]; } SocketConfig; - -enum SocketStatus { - - /* Socket created. */ - SOCKET_OK = 0, - - /* Failures from socket API functions; most also save errno. */ - SOCKET_ERROR_GETADDRINFO = -1, - SOCKET_ERROR_SOCKET = -2, - SOCKET_ERROR_BIND = -3, - SOCKET_ERROR_LISTEN = -4, - SOCKET_ERROR_CONNECT = -5, - SOCKET_ERROR_FCNTL = -6, - SOCKET_ERROR_ACCEPT = -7, - SOCKET_ERROR_SEND = -8, - - /* Failure from snprintf: name too long. */ - SOCKET_ERROR_SNPRINTF = -100, - - /* Invalid combination of options in configuration. */ - SOCKET_ERROR_CONFIGURATION = -200, - - /* Error in setsockopt(2). */ - SOCKET_ERROR_SETSOCKOPT = -300, - - /* Other unknown error. */ - SOCKET_ERROR_UNKNOWN = -400, -}; - -/* Result from calling open with a given config. */ -typedef struct SocketResult { - /* Result code and errno value from failure (if any). */ - enum SocketStatus status; - - /* File descriptor, set if status is SOCKET99_OK (success). */ - Socket socket; - - /* Address information populated from getaddrinfo() */ + +// Result from calling open with a given config. +typedef struct SocketResult +{ + int status; + Socket socket; AddressInformation addrinfo; - - /* Error code from socket(2), bind(2), etc. */ - int saved_errno; - - /* Error code from getaddrinfo, only set if status is - * SOCKET99_ERROR_GETADDRINFO. See: gai_strerror(3). */ - int getaddrinfo_error; } SocketResult; //---------------------------------------------------------------------------------- // Enumerators Definition //---------------------------------------------------------------------------------- -typedef enum -{ - SOCKET_TCP = 1, // SOCK_STREAM - SOCKET_UDP = 2 // SOCK_DGRAM -} SocketType; - // System config flags // NOTE: Used for bit masks typedef enum { @@ -1530,22 +1488,17 @@ RLAPI char* ResolveIP(const char *host, const char *port, int flags); // Protocol-independent translation from an ANSI host name to an address. RLAPI char* ResolveHost(const char *address, const char *port, AddressInformation *outaddr); - -// IP -RLAPI void GetLocalAddresses(); - + // Socket API RLAPI bool SocketOpen(SocketConfig *cfg, SocketResult *res); RLAPI void SocketClose(SocketHandle socket); RLAPI bool SocketAccept(SocketHandle listener, SocketResult* res); RLAPI int SocketSend(Socket* socket, const void *datap, int len); -RLAPI int SocketReceive(Socket* socket, void *data, int maxlen); -RLAPI int SocketGetError(char *buf, int buf_size, SocketResult *res); -RLAPI void SocketPrintError(SocketResult *res); +RLAPI int SocketReceive(Socket* socket, void *data, int maxlen); RLAPI void SocketSetHints(SocketConfig *cfg, AddressInformation *hints); // Utility print methods -RLAPI char *SocketAddressToString(SocketAddress *sockaddr, char buffer[]); +RLAPI char *SocketAddressToString(SocketAddress *sockaddr, char buffer[], int* port); RLAPI void PrintSocket(SocketAddress *addr, const int family, const int socktype, const int protocol); // Network conversion methods diff --git a/src/rnet.c b/src/rnet.c index 7cfd776aa..eaeda5bd4 100644 --- a/src/rnet.c +++ b/src/rnet.c @@ -43,6 +43,12 @@ # include "config.h" // Defines module configuration flags #endif +//---------------------------------------------------------------------------------- +// Module defines +//---------------------------------------------------------------------------------- + +#define SOCKET_BACKLOG_SIZE 20 + //---------------------------------------------------------------------------------- // Module dependencies //---------------------------------------------------------------------------------- @@ -52,26 +58,58 @@ #include "sysnet.h" //---------------------------------------------------------------------------------- -// Module defines +// Module variables //---------------------------------------------------------------------------------- -#if PLATFORM_WINDOWS -# define errno WSAGetLastError() // Support UNIX socket error codes -#endif +//---------------------------------------------------------------------------------- +// Module methods +//---------------------------------------------------------------------------------- -#define DEF_BACKLOG_SIZE SOMAXCONN -#define PORT_STR_BUFSZ 6 +static bool IsSocketValid(SocketHandle handle); +static void SocketSetLastError(int err); +static int SocketGetLastError(); +static char* SocketGetLastErrorString(); +static char* SocketErrorCodeToString(int err); +static bool SocketSetDefaults(SocketConfig* config); +static bool InitSocket(Socket* outsock); +static bool CreateSocket(SocketConfig* config, SocketResult* outresult); +static int BindSocket(SocketHandle handle, SocketConfig* config, struct addrinfo* iterator); +static int ConnectSocket(SocketHandle handle, SocketConfig* config, struct addrinfo* iterator); +static bool SocketSetNonBlocking(SocketResult* out); +static bool SocketSetOptions(SocketConfig* config, SocketHandle handle); +static void* GetSocketAddressPtr(struct sockaddr* sa); +static void* GetSocketPortPtr(struct sockaddr* sa); -static bool SocketSetDefaults(SocketConfig* cfg); -static bool CreateSocket(SocketConfig* cfg, SocketResult* out); -static bool SocketSetNonBlocking(SocketResult* out); -static bool SocketSetOptions(SocketConfig* cfg, SocketResult* out, int fd); -static const char* SocketStatusToString(enum SocketStatus s); +// +void* GetSocketPortPtr(struct sockaddr* sa) +{ + if (sa->sa_family == AF_INET) + { + return &(((struct sockaddr_in*) sa)->sin_port); + } -/* Static network API methods */ + return &(((struct sockaddr_in6*) sa)->sin6_port); +} + +// +void* GetSocketAddressPtr(struct sockaddr* sa) +{ + if (sa->sa_family == AF_INET) + { + return &(((struct sockaddr_in*) sa)->sin_addr); + } + + return &(((struct sockaddr_in6*) sa)->sin6_addr); +} + +// +static bool IsSocketValid(SocketHandle handle) +{ + return (handle != INVALID_SOCKET); +} // Sets the error code that can be retrieved through the WSAGetLastError function. -static void SocketSetError(int err) +static void SocketSetLastError(int err) { #if PLATFORM == PLATFORM_WINDOWS WSASetLastError(err); @@ -93,216 +131,294 @@ static int SocketGetLastError() // Returns a human-readable string representing the last error message static char* SocketGetLastErrorString() { - return gai_strerror(SocketGetLastError()); + return SocketErrorCodeToString(SocketGetLastError()); } -static bool SocketSetDefaults(SocketConfig* cfg) +// Returns a human-readable string representing the error message (err) +static char* SocketErrorCodeToString(int err) { - if (cfg->backlog_size == 0) +#if PLATFORM == PLATFORM_WINDOWS + static char gaiStrErrorBuffer[GAI_STRERROR_BUFFER_SIZE]; + sprintf(gaiStrErrorBuffer, "%ws", gai_strerror(err)); + return gaiStrErrorBuffer; +#else + return gai_strerror(err); +#endif +} + +// +static bool SocketSetDefaults(SocketConfig* config) +{ + if (config->backlog_size == 0) { - cfg->backlog_size = DEF_BACKLOG_SIZE; + config->backlog_size = SOCKET_BACKLOG_SIZE; } - /* Screen out contradictory settings */ - if (cfg->IPv6 && cfg->IPv4) + if (config->IPv6 && config->IPv4) { return false; } + return true; } -static bool SocketSaveError(SocketResult* out, enum SocketStatus status) +// Create the socket handle +static bool InitSocket(Socket* outsock) { - out->status = status; - out->saved_errno = SocketGetLastError(); - SocketSetError(0); - return false; + switch (outsock->type) + { + case SOCKET_TCP: + outsock->handle = socket(AF_INET, SOCK_STREAM, 0); + break; + case SOCKET_UDP: + outsock->handle = socket(AF_INET, SOCK_DGRAM, 0); + break; + default: + break; + } + return IsSocketValid(outsock->handle); } -static bool CreateSocket(SocketConfig* cfg, SocketResult* out) +// CreateSocket() - Interally called by OpenSocket() +// +// This here is the bread and butter of the socket API, This function will +// attempt to open a socket, bind and listen to it based on the config passed in +// +// SocketConfig* config - Configuration for which socket to open +// SocketResult* result - The results of this function (if any, including errors) +// +// e.g. +// SocketConfig server_cfg = { SocketConfig client_cfg = { +// .host = "127.0.0.1", .host = "127.0.0.1", +// .port = 8080, .port = 8080, +// .server = true, }; +// .nonblocking = true, +// }; +// SocketResult server_res; SocketResult client_res; +static bool CreateSocket(SocketConfig* config, SocketResult* outresult) { - struct addrinfo hints; - struct addrinfo* res = NULL; + int status; // Status value to return (0) is success + struct addrinfo hints; // Address flags (IPV4, IPV6, UDP?) + struct addrinfo* res; // A pointer to the resulting address list + Socket* outsocket; + outsocket = &outresult->socket; + outsocket->handle = INVALID_SOCKET; + outresult->status = RESULT_FAILURE; - int fd = -1; - char port_str[PORT_STR_BUFSZ]; - memset(port_str, 0, PORT_STR_BUFSZ); + // Set the socket type + outresult->socket.type = (config->datagram) ? SOCKET_UDP : SOCKET_TCP; - SocketSetHints(cfg, &hints); + // Set the hints based on information in the config + // + // AI_CANONNAME Causes the ai_canonname of the result to the filled out with the host's canonical (real) name. + // AI_PASSIVE: Causes the result's IP address to be filled out with INADDR_ANY (IPv4)or in6addr_any (IPv6); + // Note: This causes a subsequent call to bind() to auto-fill the IP address + // of the struct sockaddr with the address of the current host. + // + SocketSetHints(config, &hints); - if (PORT_STR_BUFSZ < snprintf(port_str, PORT_STR_BUFSZ, "%u", cfg->port)) + // Populate address information + status = getaddrinfo(config->host, // e.g. "www.example.com" or IP (Can be null if AI_PASSIVE flag is set + config->port, // e.g. "http" or port number + &hints, // e.g. SOCK_STREAM/SOCK_DGRAM + &res // The struct to populate + ); + + // Did we succeed? + if (status != 0) { - return SocketSaveError(out, SOCKET_ERROR_SNPRINTF); - } - - struct addrinfo* ai = NULL; - int addr_res = getaddrinfo(cfg->host, port_str, &hints, &res); - if (addr_res != 0) - { - out->getaddrinfo_error = addr_res; + outsocket->error = SocketGetLastError(); + TraceLog( + LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(outsocket->error)); + SocketSetLastError(0); + TraceLog(LOG_WARNING, + "Failed to get resolve host %s:%s: %s", + config->host, + config->port, + SocketGetLastErrorString()); freeaddrinfo(res); - return SocketSaveError(out, SOCKET_ERROR_GETADDRINFO); + return false; } - memcpy(&out->addrinfo, res, sizeof(struct addrinfo)); - - for (ai = res; ai != NULL; ai = ai->ai_next) + else { - fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (fd == -1) + TraceLog( + LOG_INFO, "Successfully resolved host %s:%s", config->host, config->port); + } + memcpy(&outresult->addrinfo, res, sizeof(struct addrinfo)); + + // Walk the addrinfo struct + struct addrinfo* it; + for (it = res; it != NULL; it = it->ai_next) + { + // Initialise the socket + if (!InitSocket(outsocket)) { - /* Save errno, but will be clobbered if others succeed. */ - out->status = SOCKET_ERROR_SOCKET; - out->saved_errno = SocketGetLastError(); - SocketSetError(0); + outsocket->error = SocketGetLastError(); + TraceLog( + LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(outsocket->error)); + SocketSetLastError(0); continue; } - if (!SocketSetOptions(cfg, out, fd)) + // Set socket options + if (!SocketSetOptions(config, outsocket->handle)) { + outsocket->error = SocketGetLastError(); + TraceLog( + LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(outsocket->error)); + SocketSetLastError(0); freeaddrinfo(res); return false; } - if (cfg->server) + // Only bind to sockets marked as server + if (config->server) { - int bind_res = bind(fd, res->ai_addr, res->ai_addrlen); - if (bind_res == -1) + if (BindSocket(outsocket->handle, config, it)) { + TraceLog(LOG_INFO, "Successfully bound socket."); + } + else + { + outsocket->error = SocketGetLastError(); + TraceLog(LOG_DEBUG, + "Socket Error: %s", + SocketErrorCodeToString(outsocket->error)); + SocketSetLastError(0); freeaddrinfo(res); - return SocketSaveError(out, SOCKET_ERROR_BIND); + return false; } - - if (!cfg->datagram) - { - int listen_res = listen(fd, cfg->backlog_size); - if (listen_res == -1) - { - freeaddrinfo(res); - return SocketSaveError(out, SOCKET_ERROR_LISTEN); - } - } - break; } - else /* client */ + else { - if (cfg->datagram) - { - break; - } - - int connect_res = connect(fd, ai->ai_addr, ai->ai_addrlen); - if (connect_res == 0) + if (ConnectSocket(outsocket->handle, config, it)) { + TraceLog(LOG_INFO, "Successfully connected to socket."); break; } else { - close(fd); - fd = -1; - out->status = SOCKET_ERROR_CONNECT; + outsocket->error = SocketGetLastError(); + TraceLog(LOG_DEBUG, + "Socket Error: %s", + SocketErrorCodeToString(outsocket->error)); + SocketSetLastError(0); + SocketClose(outsocket->handle); continue; } } } - if (fd == -1) + if (!IsSocketValid(outsocket->handle)) { - if (out->status == SOCKET_OK) - { - freeaddrinfo(res); - return SocketSaveError(out, SOCKET_ERROR_UNKNOWN); - } - else - { - out->saved_errno = SocketGetLastError(); - SocketSetError(0); - freeaddrinfo(res); - return false; - } + outsocket->error = SocketGetLastError(); + TraceLog( + LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(outresult->status)); + SocketSetLastError(0); + freeaddrinfo(res); + return false; } - out->status = SOCKET_OK; + outresult->status = RESULT_SUCCESS; + outresult->socket.ready = 0; + outresult->socket.error = 0; + outresult->socket.isServer = config->server; + outresult->socket.address.host = (char*) malloc(INET6_ADDRSTRLEN); + SocketAddressToString(res->ai_addr, outresult->socket.address.host, &outresult->socket.address.port); freeaddrinfo(res); - out->saved_errno = 0; - out->socket.handle = fd; - out->socket.ready = 0; - out->socket.host.host = ((struct sockaddr_in*) res->ai_addr)->sin_addr.s_addr; - out->socket.host.port = ((struct sockaddr_in*) res->ai_addr)->sin_port; - out->socket.sflag = cfg->server; return true; } +// +static bool BindSocket(SocketHandle handle, SocketConfig* config, struct addrinfo* iterator) +{ + // Attempt to bind the socket + if (bind(handle, iterator->ai_addr, iterator->ai_addrlen) == SOCKET_ERROR) + { + SocketClose(handle); + return false; + } + + // Don't listen on UDP sockets + if (!config->datagram) + { + if (listen(handle, config->backlog_size) != 0) + { + return false; + } + else + { + TraceLog(LOG_INFO, "Started listening on socket..."); + } + } + + return true; +} + +// +static bool ConnectSocket(SocketHandle handle, SocketConfig* config, struct addrinfo* iterator) +{ + // Don't connect datagram sockets + if (config->datagram) + { + return true; + } + + // Did we connect successfully? + if (connect(handle, iterator->ai_addr, iterator->ai_addrlen) != SOCKET_ERROR) + { + return true; + } + else + { + return false; + } +} + +// +static bool SocketSetBlocking(SocketResult* out) +{ +#if PLATFORM == PLATFORM_WINDOWS + unsigned long mode = 0; + ioctlsocket(out->socket.handle, FIONBIO, &mode); +#else + int flags = fcntl(out->socket.handle, F_GETFL, 0); + fcntl(out->socket.handle, F_SETFL, flags & ~O_NONBLOCK); +#endif +} + +// static bool SocketSetNonBlocking(SocketResult* out) { #if PLATFORM == PLATFORM_WINDOWS unsigned long mode = 1; - if (ioctlsocket(out->socket.handle, FIONBIO, &mode) != 0) - { - return SocketSaveError(out, SOCKET_ERROR_FCNTL); - } + ioctlsocket(out->socket.handle, FIONBIO, &mode); #else - int flags = fcntl(out->socket.handle, F_GETFL, 0); - if (flags == -1) - { - return SocketSaveError(out, SOCKET_ERROR_FCNTL); - } - if (fcntl(out->socket, F_SETFL, flags | O_NONBLOCK) < 0) - { - return SocketSaveError(out, SOCKET_ERROR_FCNTL); - } + fcntl(out->socket.handle, F_SETFL, O_NONBLOCK); #endif return true; } -static bool SocketSetOptions(SocketConfig* cfg, SocketResult* out, int fd) +// +static bool SocketSetOptions(SocketConfig* config, SocketHandle handle) { for (int i = 0; i < MAX_SOCK_OPTS; i++) { - SocketOpt* opt = &cfg->sockopts[i]; + SocketOpt* opt = &config->sockopts[i]; if (opt->id == 0) { break; } - if (setsockopt(fd, SOL_SOCKET, opt->id, opt->value, opt->valueLen) < 0) + if (setsockopt(handle, SOL_SOCKET, opt->id, opt->value, opt->valueLen) < 0) { - return SocketSaveError(out, SOCKET_ERROR_SETSOCKOPT); + return false; } } return true; } -static const char* SocketStatusToString(enum SocketStatus s) -{ - switch (s) - { - case SOCKET_OK: - return "ok"; - case SOCKET_ERROR_GETADDRINFO: - return "getaddrinfo"; - case SOCKET_ERROR_SOCKET: - return "socket"; - case SOCKET_ERROR_BIND: - return "bind"; - case SOCKET_ERROR_LISTEN: - return "listen"; - case SOCKET_ERROR_CONNECT: - return "connect"; - case SOCKET_ERROR_FCNTL: - return "fcntl"; - case SOCKET_ERROR_SNPRINTF: - return "snprintf"; - case SOCKET_ERROR_CONFIGURATION: - return "configuration"; - case SOCKET_ERROR_SETSOCKOPT: - return "setsockopt"; - case SOCKET_ERROR_UNKNOWN: - default: - return "unknown"; - } -} - //---------------------------------------------------------------------------------- // Module implementation //---------------------------------------------------------------------------------- @@ -396,7 +512,7 @@ char* ResolveIP(const char* ip, const char* port, int flags) // Did we succeed? if (status != 0) { - TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %ls", ip, port, gai_strerror(errno)); + TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %s", ip, port, gai_strerror(errno)); } else { @@ -431,7 +547,7 @@ char* ResolveIP(const char* ip, const char* port, int flags) // Did we succeed? if (status != 0) { - TraceLog(LOG_WARNING, "Failed to resolve ip %s: %ls", ip, SocketGetLastErrorString()); + TraceLog(LOG_WARNING, "Failed to resolve ip %s: %s", ip, SocketGetLastErrorString()); } else { @@ -457,6 +573,8 @@ char* ResolveHost(const char* address, const char* port, AddressInformation* out int status; // Status value to return (0) is success struct addrinfo hints; // Address flags (IPV4, IPV6, UDP?) struct addrinfo* results; // A pointer to the resulting address list + char ip[INET6_ADDRSTRLEN]; // Enough pace to hold a IPv6 string + int portptr; // Set the hints memset(&hints, 0, sizeof hints); @@ -481,7 +599,7 @@ char* ResolveHost(const char* address, const char* port, AddressInformation* out // Did we succeed? if (status != 0) { - TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %ls", address, port, gai_strerror(errno)); + TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %s", address, port, gai_strerror(errno)); } else { @@ -489,7 +607,7 @@ char* ResolveHost(const char* address, const char* port, AddressInformation* out } struct addrinfo* iterator; - for (iterator = outaddr; iterator != NULL; iterator = iterator->ai_next) + for (iterator = results; iterator != NULL; iterator = iterator->ai_next) { TraceLog(LOG_DEBUG, "GetAddressInformation"); TraceLog(LOG_DEBUG, "\tFlags: 0x%x", iterator->ai_flags); @@ -505,7 +623,7 @@ char* ResolveHost(const char* address, const char* port, AddressInformation* out freeaddrinfo(results); // Return the resulting hostname - return SocketAddressToString(outaddr->ai_addr); + return SocketAddressToString(outaddr->sockaddr, ip, &portptr); } // This here is the bread and butter of the socket API, This function will @@ -524,23 +642,27 @@ char* ResolveHost(const char* address, const char* port, AddressInformation* out // SocketResult server_res; SocketResult client_res; bool SocketOpen(SocketConfig* config, SocketResult* result) { + // Make sure we've not received a null config or result pointer if (config == NULL || result == NULL) { return false; } memset(result, 0, sizeof(*result)); + // Set the defaults based on the config if (!SocketSetDefaults(config)) { - result->status = SOCKET_ERROR_CONFIGURATION; + TraceLog(LOG_DEBUG, "Configuration Error."); return false; } + // Create the socket if (!CreateSocket(config, result)) { return false; } + // If the config states non-blocking, set the socket to non-blocking if (config->nonblocking) { if (!SocketSetNonBlocking(result)) @@ -563,86 +685,134 @@ void SocketClose(SocketHandle socket) } } -// The accept function permits an incoming connection attempt on a socket. +// The accept function permits an incoming connection attempt on a socket. // +// SocketHandle listener - The socket to listen for incoming connections on (i.e. server) +// SocketResult* out - The result of this function (if any, including errors) +// +// e.g. +// +// SocketResult connection; +// bool connected = false; +// if (!connected) +// { +// if (SocketAccept(server_res.socket.handle, &connection)) +// { +// connected = true; +// } +// } bool SocketAccept(SocketHandle listener, SocketResult* out) { - struct sockaddr_in sock_addr; - socklen_t sock_alen; - sock_alen = sizeof(sock_addr); - out->socket.handle = accept(listener, (struct sockaddr*) &sock_addr, &sock_alen); + char ip[INET6_ADDRSTRLEN]; + struct sockaddr_storage sockAddr; + socklen_t sockAddrLen; + sockAddrLen = sizeof(sockAddr); + out->socket.handle = accept(listener, (struct sockaddr*) &sockAddr, &sockAddrLen); if (out->socket.handle == INVALID_SOCKET) { - /* Save errno, but will be clobbered if others succeed. */ - out->status = SOCKET_ERROR_ACCEPT; - out->saved_errno = SocketGetLastError(); - SocketSetError(0); + out->socket.error = SocketGetLastError(); + TraceLog( + LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(out->socket.error)); + SocketSetLastError(0); return false; } - memcpy(&out->addrinfo, &sock_addr, sizeof(struct sockaddr)); - out->socket.host.host = sock_addr.sin_addr.s_addr; - out->socket.host.port = sock_addr.sin_port; - + memcpy(&out->addrinfo, &sockAddr, sizeof(struct sockaddr)); + out->socket.address.host = inet_ntop(sockAddr.ss_family, GetSocketAddressPtr((struct sockaddr*) &sockAddr), ip, sizeof ip); + out->socket.address.port = ntohs(GetSocketPortPtr((struct sockaddr*) &sockAddr)); + TraceLog(LOG_DEBUG, "Server: Got connection from %s\n", out->socket.address.host); return true; } -/* Send 'len' bytes of 'data' over the non-server socket 'sock' - This function returns the actual amount of data sent. If the return value - is less than the amount of data sent, then either the remote connection was - closed, or an unknown socket error occurred. -*/ -int SocketSend(Socket* socket, const void* datap, int len) +// Send 'len' bytes of 'data' over the non-server socket 'sock' +// +// Example +int SocketSend(Socket* socket, const char* buffer, int length) { - const unsigned char* data = (const unsigned char*) datap; /* For pointer arithmetic */ - int sent, left; + int sentTotal = 0; // How many bytes we've sent + int bytesleft = length; // How many do we have left to send + int actuallySent; // How many bytes did we send this tick? + struct sockaddr_in dest; // The datagram (UDP) destination + dest.sin_addr.s_addr = socket->address.host; + dest.sin_port = socket->address.port; - // /* Server sockets are for accepting connections only */ - if (socket->sflag) + // Which socket are we trying to send data on + switch (socket->type) { - // out->status = SOCKET_ERROR_SEND; - // out->saved_errno = SocketGetLastError(); - // SocketSetError(0); - return (-1); + case SOCKET_TCP: + if (IsSocketValid(socket->handle)) + { + if ((length > 0) && (buffer != NULL)) + { + SocketSetLastError(0); + do + { + actuallySent = send(socket->handle, buffer + sentTotal, bytesleft, 0); + if (actuallySent > 0) + { + sentTotal += actuallySent; + bytesleft -= actuallySent; + } + } while ((bytesleft > 0) && // While we still have bytes left to send + ((actuallySent > 0) || // The amount of bytes we actually sent is > 0 + (SocketGetLastError() == EINTR)) // The socket was interupted + ); + } + } + break; + case SOCKET_UDP: + if (IsSocketValid(socket->handle)) + { + if ((length > 0) && (buffer != NULL)) + { + SocketSetLastError(0); + do + { + actuallySent = sendto(socket->handle, buffer + sentTotal, bytesleft, 0, (struct sockaddr*) &dest, sizeof dest); + if (actuallySent > 0) + { + sentTotal += actuallySent; + bytesleft -= actuallySent; + } + } while ((bytesleft > 0) && // While we still have bytes left to send + ((actuallySent > 0) || // The amount of bytes we actually sent is > 0 + (SocketGetLastError() == EINTR)) // The socket was interupted + ); + } + } + break; + default: + break; } - /* Keep sending data until it's sent or an error occurs */ - left = len; - sent = 0; - SocketSetError(0); - do + // Server sockets are for accepting connections only + if (socket->isServer) { - len = send(socket->handle, (const char*) data, left, 0); - if (len > 0) - { - sent += len; - left -= len; - data += len; - } - } while ((left > 0) && ((len > 0) || (SocketGetLastError() == EINTR))); + TraceLog(LOG_WARNING, "Cannot send information on a server socket"); + return -1; + } - return (sent); + return sentTotal; } -/* Receive up to 'maxlen' bytes of data over the non-server socket 'sock', - and store them in the buffer pointed to by 'data'. - This function returns the actual amount of data received. If the return - value is less than or equal to zero, then either the remote connection was - closed, or an unknown socket error occurred. -*/ +// Receive up to 'maxlen' bytes of data over the non-server socket 'sock', +// and store them in the buffer pointed to by 'data'. +// This function returns the actual amount of data received. If the return +// value is less than or equal to zero, then either the remote connection was +// closed, or an unknown socket error occurred. int SocketReceive(Socket* socket, void* data, int maxlen) { int len; /* Server sockets are for accepting connections only */ - if (socket->sflag) + if (socket->isServer) { // out->status = SOCKET_ERROR_RECEIVE; // out->saved_errno = SocketGetLastError(); - // SocketSetError(0); + // SocketSetLastError(0); return (-1); } - SocketSetError(0); + SocketSetLastError(0); do { len = recv(socket->handle, (char*) data, maxlen, 0); @@ -652,30 +822,7 @@ int SocketReceive(Socket* socket, void* data, int maxlen) return (len); } -/* Construct an error message in BUF, based on the status codes - * in *RES. This has the same return value and general behavior - * as snprintf -- if the return value is >= buf_size, the string - * has been truncated. Returns -1 if either BUF or RES are NULL. */ -int SocketGetError(char* buf, size_t buf_size, SocketResult* res) -{ - if (buf == NULL || res == NULL) - { - return 0; - } - return snprintf(buf, buf_size, "%s: %ls", SocketStatusToString(res->status), (res->status == SOCKET_ERROR_GETADDRINFO ? gai_strerror(res->getaddrinfo_error) : strerror(res->saved_errno))); -} - -/* Print an error message based on the status contained in *RES. */ -void SocketPrintError(SocketResult* res) -{ - if (res == NULL) - { - return; - } - printf("%s: %ls\n", SocketStatusToString(res->status), (res->status == SOCKET_ERROR_GETADDRINFO ? gai_strerror(res->getaddrinfo_error) : strerror(res->saved_errno))); -} - -/* Set "hints" in an addrinfo struct, to be passed to getaddrinfo. */ +// Set "hints" in an addrinfo struct, to be passed to getaddrinfo. void SocketSetHints(SocketConfig* cfg, struct addrinfo* hints) { if (cfg == NULL || hints == NULL) @@ -685,11 +832,7 @@ void SocketSetHints(SocketConfig* cfg, struct addrinfo* hints) memset(hints, 0, sizeof(*hints)); /* if .IPv4 or .IPv6 are used, set and use that instead of *host */ - if (cfg->path) - { - hints->ai_family = AF_UNIX; - } - else if (cfg->IPv6) + if (cfg->IPv6) { hints->ai_family = AF_INET6; } @@ -728,6 +871,7 @@ void PrintSocket(struct SocketAddress* addr, const int family, const int socktyp { struct sockaddr* sockaddr_ip; char ip[INET6_ADDRSTRLEN]; // Enough pace to hold a IPv6 string + int port; switch (family) { case AF_UNSPEC: @@ -738,13 +882,13 @@ void PrintSocket(struct SocketAddress* addr, const int family, const int socktyp case AF_INET: { TraceLog(LOG_DEBUG, "\tFamily: AF_INET (IPv4)"); - TraceLog(LOG_INFO, "\t- IPv4 address %s", SocketAddressToString(addr, ip)); + TraceLog(LOG_INFO, "\t- IPv4 address %s", SocketAddressToString(addr, ip, &port)); } break; case AF_INET6: { TraceLog(LOG_DEBUG, "\tFamily: AF_INET6 (IPv6)"); - TraceLog(LOG_INFO, "\t- IPv6 address %s", SocketAddressToString(addr, ip)); + TraceLog(LOG_INFO, "\t- IPv6 address %s", SocketAddressToString(addr, ip, &port)); } break; case AF_NETBIOS: @@ -802,18 +946,22 @@ void PrintSocket(struct SocketAddress* addr, const int family, const int socktyp } // Convert network ordered socket address to human readable string (127.0.0.1) -char* SocketAddressToString(struct SocketAddress* sockaddr, char buffer[]) +char* SocketAddressToString(struct SocketAddress* sockaddr, char buffer[], int* port) { switch (sockaddr->family) { case AF_INET: { - return inet_ntop(AF_INET, &((struct sockaddr_in*) sockaddr)->sin_addr, buffer, INET_ADDRSTRLEN); + struct sockaddr_in* s = ((struct sockaddr_in*) sockaddr); + *port = ntohs(s->sin_port); + return inet_ntop(AF_INET, &s->sin_addr, buffer, INET_ADDRSTRLEN); } break; case AF_INET6: { - return inet_ntop(AF_INET6, &((struct sockaddr_in6*) sockaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN); + struct sockaddr_in6* s = ((struct sockaddr_in6*) sockaddr); + *port = ntohs(s->sin6_port); + return inet_ntop(AF_INET6, &s->sin6_addr, buffer, INET6_ADDRSTRLEN); } break; default: @@ -824,19 +972,17 @@ char* SocketAddressToString(struct SocketAddress* sockaddr, char buffer[]) } } -/* -** PackData() -- store data dictated by the format string in the buffer -** -** bits |signed unsigned float string -** -----+---------------------------------- -** 8 | c C -** 16 | h H f -** 32 | l L d -** 64 | q Q g -** - | s -** -** (16-bit unsigned length is automatically prepended to strings) -*/ +// PackData() -- store data dictated by the format string in the buffer +// +// bits |signed unsigned float string +// -----+---------------------------------- +// 8 | c C +// 16 | h H f +// 32 | l L d +// 64 | q Q g +// - | s +// +// (16-bit unsigned length is automatically prepended to strings) unsigned int PackData(unsigned char* buf, char* format, ...) { va_list ap; @@ -964,20 +1110,18 @@ unsigned int PackData(unsigned char* buf, char* format, ...) return size; } -/* -** UnpackData() -- unpack data dictated by the format string into the buffer -** -** bits |signed unsigned float string -** -----+---------------------------------- -** 8 | c C -** 16 | h H f -** 32 | l L d -** 64 | q Q g -** - | s -** -** (string is extracted based on its stored length, but 's' can be -** prepended with a max length) -*/ +// UnpackData() -- unpack data dictated by the format string into the buffer +// +// bits |signed unsigned float string +// -----+---------------------------------- +// 8 | c C +// 16 | h H f +// 32 | l L d +// 64 | q Q g +// - | s +// +// (string is extracted based on its stored length, but 's' can be +// prepended with a max length) void UnpackData(unsigned char* buf, char* format, ...) { va_list ap; diff --git a/src/sysnet.h b/src/sysnet.h index aa73673a1..40a5cf887 100644 --- a/src/sysnet.h +++ b/src/sysnet.h @@ -1,47 +1,93 @@ +/********************************************************************************************** +* +* sysnet - Provides cross-platform network defines, macros etc +* +* DEPENDENCIES: +* - Used for cross-platform type specifiers +* +* INSPIRED BY: +* SFML Sockets - https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Socket.php +* SDL_net - https://www.libsdl.org/projects/SDL_net/ +* BSD Sockets - https://www.gnu.org/software/libc/manual/html_node/Sockets.html +* BEEJ - https://beej.us/guide/bgnet/html/single/bgnet.html +* Winsock2 - https://docs.microsoft.com/en-us/windows/desktop/api/winsock2 +* +* +* CONTRIBUTORS: +* Jak Barnes (github: @syphonx) (Feb. 2019): +* - Initial version +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +//---------------------------------------------------------------------------------- +// Platform type sizes +//---------------------------------------------------------------------------------- + +#include + //---------------------------------------------------------------------------------- // Undefine any conflicting windows.h symbols //---------------------------------------------------------------------------------- // If defined, the following flags inhibit definition of the indicated items. -#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_ +#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_ #define NOVIRTUALKEYCODES // VK_* -#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_* -#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* -#define NOSYSMETRICS // SM_* -#define NOMENUS // MF_* -#define NOICONS // IDI_* -#define NOKEYSTATES // MK_* -#define NOSYSCOMMANDS // SC_* -#define NORASTEROPS // Binary and Tertiary raster ops -#define NOSHOWWINDOW // SW_* -#define OEMRESOURCE // OEM Resource values -#define NOATOM // Atom Manager routines -#define NOCLIPBOARD // Clipboard routines -#define NOCOLOR // Screen colors -#define NOCTLMGR // Control and Dialog routines -#define NODRAWTEXT // DrawText() and DT_* -#define NOGDI // All GDI defines and routines -#define NOKERNEL // All KERNEL defines and routines -#define NOUSER // All USER defines and routines -#define NONLS // All NLS defines and routines -#define NOMB // MB_* and MessageBox() -#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines -#define NOMETAFILE // typedef METAFILEPICT -#define NOMINMAX // Macros min(a,b) and max(a,b) -#define NOMSG // typedef MSG and associated routines -#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_* -#define NOSCROLL // SB_* and scrolling routines -#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. -#define NOSOUND // Sound driver routines +#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_* +#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* +#define NOSYSMETRICS // SM_* +#define NOMENUS // MF_* +#define NOICONS // IDI_* +#define NOKEYSTATES // MK_* +#define NOSYSCOMMANDS // SC_* +#define NORASTEROPS // Binary and Tertiary raster ops +#define NOSHOWWINDOW // SW_* +#define OEMRESOURCE // OEM Resource values +#define NOATOM // Atom Manager routines +#define NOCLIPBOARD // Clipboard routines +#define NOCOLOR // Screen colors +#define NOCTLMGR // Control and Dialog routines +#define NODRAWTEXT // DrawText() and DT_* +#define NOGDI // All GDI defines and routines +#define NOKERNEL // All KERNEL defines and routines +#define NOUSER // All USER defines and routines +#define NONLS // All NLS defines and routines +#define NOMB // MB_* and MessageBox() +#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines +#define NOMETAFILE // typedef METAFILEPICT +#define NOMINMAX // Macros min(a,b) and max(a,b) +#define NOMSG // typedef MSG and associated routines +#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_* +#define NOSCROLL // SB_* and scrolling routines +#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. +#define NOSOUND // Sound driver routines #define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines -#define NOWH // SetWindowsHook and WH_* +#define NOWH // SetWindowsHook and WH_* #define NOWINOFFSETS // GWL_*, GCL_*, associated routines -#define NOCOMM // COMM driver routines -#define NOKANJI // Kanji support stuff. -#define NOHELP // Help engine interface. -#define NOPROFILER // Profiler interface. +#define NOCOMM // COMM driver routines +#define NOKANJI // Kanji support stuff. +#define NOHELP // Help engine interface. +#define NOPROFILER // Profiler interface. #define NODEFERWINDOWPOS // DeferWindowPos routines -#define NOMCX // Modem Configuration Extensions +#define NOMCX // Modem Configuration Extensions #define MMNOSOUND @@ -50,52 +96,146 @@ //---------------------------------------------------------------------------------- #define PLATFORM_WINDOWS 1 -#define PLATFORM_UNIX 2 +#define PLATFORM_LINUX 2 #if defined(__WIN32__) || defined(WIN32) # define PLATFORM PLATFORM_WINDOWS -#else -# define PLATFORM PLATFORM_UNIX +#elif defined(_LINUX) +# define PLATFORM PLATFORM_LINUX #endif //---------------------------------------------------------------------------------- -// Platform specific network includes +// Platform type definitions +// From: https://github.com/DFHack/clsocket/blob/master/src/Host.h //---------------------------------------------------------------------------------- -#if PLATFORM_WINDOWS - #define __USE_W32_SOCKETS - #pragma comment(lib, "ws2_32.lib") - #include - #include - #include -#else /* UNIX */ - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include +#ifndef __WORDSIZE +# define __WORDSIZE 32 +#endif + +#if defined(_LINUX) || defined(_DARWIN) +typedef unsigned char uint8; +typedef char int8; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned int uint32; +typedef int int32; +typedef int SOCKET; +#endif + +#ifdef WIN32 +typedef unsigned char uint8; +typedef char int8; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned int uint32; +typedef int int32; +#endif + +#ifdef WIN32 +typedef int socklen_t; +#endif + +#if defined(WIN32) +typedef unsigned long long int uint64; +typedef long long int int64; +#elif (__WORDSIZE == 32) +__extension__ typedef long long int int64; +__extension__ typedef unsigned long long int uint64; +#elif (__WORDSIZE == 64) +typedef unsigned long int uint64; +typedef long int int64; +#endif + +#ifdef WIN32 +# ifndef UINT8_MAX +# define UINT8_MAX (UCHAR_MAX) +# endif // UINT8_MAX +# ifndef UINT16_MAX +# define UINT16_MAX (USHRT_MAX) +# endif // UINT16_MAX +# ifndef UINT32_MAX +# define UINT32_MAX (ULONG_MAX) +# endif // UINT32_MAX +# if __WORDSIZE == 64 +# define SIZE_MAX (18446744073709551615UL) +# else +# ifndef SIZE_MAX +# define SIZE_MAX (4294967295U) +# endif // SIZE_MAX +# endif // __WORDSIZE == 64 +#endif // WIN32 + +#if defined(WIN32) +# define ssize_t size_t +#endif // WIN32 + +#ifndef TRUE +# define TRUE 1 +#endif // TRUE + +#ifndef FALSE +# define FALSE 0 +#endif // FALSE + +#ifndef RESULT_SUCCESS +# define RESULT_SUCCESS 0 +#endif // RESULT_SUCCESS + +#ifndef RESULT_FAILURE +# define RESULT_FAILURE 1 +#endif // RESULT_FAILURE + +#ifndef htonll +# ifdef _BIG_ENDIAN +# define htonll(x) (x) +# define ntohll(x) (x) +# else +# define htonll(x) ((((uint64) htonl(x)) << 32) + htonl(x >> 32)) +# define ntohll(x) ((((uint64) ntohl(x)) << 32) + ntohl(x >> 32)) +# endif // _BIG_ENDIAN +#endif // htonll + +//---------------------------------------------------------------------------------- +// Platform specific network includes +// From: https://github.com/SDL-mirror/SDL_net/blob/master/SDLnetsys.h +//---------------------------------------------------------------------------------- + +// Include system network headers + +#ifdef _WIN32 +# pragma comment(lib, "ws2_32.lib") +# define __USE_W32_SOCKETS +# include +# include +# include +# define IPTOS_LOWDELAY 0x10 +#else /* UNIX */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif /* WIN32 */ -/* System-dependent definitions */ +#ifndef INVALID_SOCKET +# define INVALID_SOCKET ~(0) +#endif + #ifndef __USE_W32_SOCKETS # define closesocket close # define SOCKET int # define INVALID_SOCKET -1 # define SOCKET_ERROR -1 -#endif /* __USE_W32_SOCKETS */ +#endif #ifdef __USE_W32_SOCKETS -# define RNet_GetLastError WSAGetLastError -# define RNet_SetLastError WSASetLastError # ifndef EINTR # define EINTR WSAEINTR # endif -#else -int RNet_GetLastError(void); -void RNet_SetLastError(int err); #endif \ No newline at end of file