From 38dce94577ba96a6b39fdef3ead0235924da80b7 Mon Sep 17 00:00:00 2001 From: Jak Barnes Date: Sun, 17 Feb 2019 18:56:14 +0000 Subject: [PATCH] added more api calls to rnet.c, updated examples to support ipv4/6 Signed-off-by: Jak Barnes --- examples/network/network_ping_pong.c | 80 +-- examples/network/network_resolve_host.c | 8 +- .../VS2017/examples/core_basic_window.vcxproj | 362 ++++++------- .../examples/core_basic_window_cpp.vcxproj | 358 ++++++------- projects/VS2017/raylib.sln | 21 +- src/raylib.h | 86 +++- src/rnet.c | 482 +++++++++++++++--- 7 files changed, 912 insertions(+), 485 deletions(-) diff --git a/examples/network/network_ping_pong.c b/examples/network/network_ping_pong.c index c8fb84741..1bf8fb572 100644 --- a/examples/network/network_ping_pong.c +++ b/examples/network/network_ping_pong.c @@ -20,7 +20,7 @@ * ********************************************************************************************/ -#include "raylib.h" +#include "raylib.h" int main() { @@ -31,27 +31,38 @@ int main() screenWidth, screenHeight, "raylib [network] example - ping pong"); SetTargetFPS(60); + SetTraceLogLevel(LOG_INFO); + // Networking - TCPSocket server; - TCPSocket client; - TCPSocket connection; - ResetSocket(&server); - ResetSocket(&client); - ResetSocket(&connection); - InitNetwork(); - CreateTCPListenServer(&server, "127.0.0.1", "3490"); - CreateTCPClient(&client, "127.0.0.1", "3490"); - // Timer - float elapsed = 0.0f, delay = 1.0f; // ms - bool ping = false, pong = false; - char recvBuffer[512]; + // Server socket and address + AddressInformation serveraddr; + Socket server; + server.blocking = false; + GetAddressInformation(&serveraddr, "localhost", "3490", SOCKET_TCP, PROTOCOL_TCP); + CreateSocket(&server, serveraddr); + BindSocket(server, serveraddr); + ListenSocket(server); + + // Client socket and address + AddressInformation clientaddr; + Socket client; + client.blocking = false; + GetAddressInformation(&clientaddr, "localhost", "3490", SOCKET_TCP, PROTOCOL_TCP); + CreateSocket(&client, clientaddr); + ConnectSocket(client, clientaddr); + + Socket connection; // The socket connection between server->client + float elapsed = 0.0f, delay = 1.0f; // ms + bool ping = false, pong = false; + char recvBuffer[512]; + bool connected = false; memset(&recvBuffer, 0, 8); // Main game loop - while (!WindowShouldClose()) { - + while (!WindowShouldClose()) + { // Draw BeginDrawing(); @@ -59,34 +70,43 @@ int main() ClearBackground(RAYWHITE); // A valid connection will != -1 - if (!connection.ready) { - AcceptIncomingConnections(&connection, server.sockfd); - ping = true; + if (!connected) + { + AcceptSocket(server, &connection); + ping = true; + connected = true; } // Connected - if (connection.ready) { - - int bytesRecv = ReceiveTCP(connection.sockfd, recvBuffer, 5); - if (bytesRecv > 0) { - if (strcmp(recvBuffer, "Ping!") == 0) { + if (connected) + { + int bytesRecv = ReceiveTCP(connection.handle, recvBuffer, 5); + if (bytesRecv > 0) + { + if (strcmp(recvBuffer, "Ping!") == 0) + { pong = true; printf("Ping!\n"); } - if (strcmp(recvBuffer, "Pong!") == 0) { + if (strcmp(recvBuffer, "Pong!") == 0) + { ping = true; printf("Pong!\n"); } } elapsed += GetFrameTime(); - if (elapsed > delay) { - if (ping) { + if (elapsed > delay) + { + if (ping) + { ping = false; - SendTCP(client.sockfd, "Ping!", 5); - } else if (pong) { + SendTCP(client.handle, "Ping!", 5); + } + else if (pong) + { pong = false; - SendTCP(client.sockfd, "Pong!", 5); + SendTCP(client.handle, "Pong!", 5); } elapsed = 0.0f; } diff --git a/examples/network/network_resolve_host.c b/examples/network/network_resolve_host.c index de18c4fc6..a470bede4 100644 --- a/examples/network/network_resolve_host.c +++ b/examples/network/network_resolve_host.c @@ -33,11 +33,13 @@ int main() // Networking InitNetwork(); - ResolveHost("www.raylib.com"); + ResolveHost("www.google.com"); + ResolveIP("2001:4860:4860::8888"); + ResolveIP("8.8.8.8"); // Main game loop - while (!WindowShouldClose()) { - + while (!WindowShouldClose()) + { // Draw BeginDrawing(); diff --git a/projects/VS2017/examples/core_basic_window.vcxproj b/projects/VS2017/examples/core_basic_window.vcxproj index 48e06e448..ad6e050e7 100644 --- a/projects/VS2017/examples/core_basic_window.vcxproj +++ b/projects/VS2017/examples/core_basic_window.vcxproj @@ -1,182 +1,182 @@ - - - - - Debug.DLL - Win32 - - - Debug - Win32 - - - Release.DLL - Win32 - - - Release - Win32 - - - - {0981CA98-E4A5-4DF1-987F-A41D09131EFC} - Win32Proj - core_basic_window - 10.0.14393.0 - core_basic_window - - - - Application - true - v141 - Unicode - - - Application - true - v141 - Unicode - - - Application - false - v141 - true - Unicode - - - Application - false - v141 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(ProjectDir)$(ProjectName)\$(Configuration)\ - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - true - $(ProjectDir)$(ProjectName)\$(Configuration)\ - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - false - $(ProjectDir)$(ProjectName)\$(Configuration)\ - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - false - $(ProjectDir)$(ProjectName)\$(Configuration)\ - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - %(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - %(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - - - - - - - - {e89d61ac-55de-4482-afd4-df7242ebc859} - - - - - + + + + + Debug.DLL + Win32 + + + Debug + Win32 + + + Release.DLL + Win32 + + + Release + Win32 + + + + {0981CA98-E4A5-4DF1-987F-A41D09131EFC} + Win32Proj + core_basic_window + 10.0.17763.0 + core_basic_window + + + + Application + true + v141 + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + true + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + false + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + false + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + %(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + %(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + \ No newline at end of file diff --git a/projects/VS2017/examples/core_basic_window_cpp.vcxproj b/projects/VS2017/examples/core_basic_window_cpp.vcxproj index 39a2aee77..6387e80c1 100644 --- a/projects/VS2017/examples/core_basic_window_cpp.vcxproj +++ b/projects/VS2017/examples/core_basic_window_cpp.vcxproj @@ -1,180 +1,180 @@ - - - - - Debug.DLL - Win32 - - - Debug - Win32 - - - Release.DLL - Win32 - - - Release - Win32 - - - - {B655E850-3322-42F7-941D-6AC18FD66CA1} - Win32Proj - raylib_example_cpp - 10.0.14393.0 - core_basic_window_cpp - - - - Application - true - v141 - Unicode - - - Application - true - v141 - Unicode - - - Application - false - v141 - true - Unicode - - - Application - false - v141 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(ProjectDir)$(ProjectName)\$(Configuration) - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - true - $(ProjectDir)$(ProjectName)\$(Configuration) - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - false - $(ProjectDir)$(ProjectName)\$(Configuration) - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - false - $(ProjectDir)$(ProjectName)\$(Configuration) - $(ProjectDir)$(ProjectName)\$(Configuration)\temp - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsCpp - - - Console - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsCpp - - - Console - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - CompileAsCpp - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - true - true - $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - CompileAsCpp - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - true - true - %(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - {e89d61ac-55de-4482-afd4-df7242ebc859} - - - - - - - - + + + + + Debug.DLL + Win32 + + + Debug + Win32 + + + Release.DLL + Win32 + + + Release + Win32 + + + + {B655E850-3322-42F7-941D-6AC18FD66CA1} + Win32Proj + raylib_example_cpp + 10.0.17763.0 + core_basic_window_cpp + + + + Application + true + v141 + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(ProjectName)\$(Configuration) + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + true + $(ProjectDir)$(ProjectName)\$(Configuration) + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + false + $(ProjectDir)$(ProjectName)\$(Configuration) + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + false + $(ProjectDir)$(ProjectName)\$(Configuration) + $(ProjectDir)$(ProjectName)\$(Configuration)\temp + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsCpp + + + Console + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsCpp + + + Console + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + CompileAsCpp + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + CompileAsCpp + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + true + true + %(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + + + \ No newline at end of file diff --git a/projects/VS2017/raylib.sln b/projects/VS2017/raylib.sln index b8657d46d..b104e1519 100644 --- a/projects/VS2017/raylib.sln +++ b/projects/VS2017/raylib.sln @@ -13,7 +13,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_ping_pong", "exampl EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_basic_window", "examples\core_basic_window.vcxproj", "{0981CA98-E4A5-4DF1-987F-A41D09131EFC}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_interfaces", "examples\network_interfaces.vcxproj", "{A16D19CB-6AF4-4D17-8318-EABD8805247C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_resolve_host", "examples\network_interfaces.vcxproj", "{A16D19CB-6AF4-4D17-8318-EABD8805247C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network_stream_client", "examples\network_stream_client.vcxproj", "{BC49AAF0-E8C2-4F94-A60A-C56993023C6D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -95,6 +97,22 @@ Global {A16D19CB-6AF4-4D17-8318-EABD8805247C}.Release|x64.Build.0 = Release|x64 {A16D19CB-6AF4-4D17-8318-EABD8805247C}.Release|x86.ActiveCfg = Release|Win32 {A16D19CB-6AF4-4D17-8318-EABD8805247C}.Release|x86.Build.0 = Release|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug.DLL|x64.ActiveCfg = Debug|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug.DLL|x64.Build.0 = Debug|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug.DLL|x86.ActiveCfg = Debug|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug.DLL|x86.Build.0 = Debug|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug|x64.ActiveCfg = Debug|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug|x64.Build.0 = Debug|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug|x86.ActiveCfg = Debug|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Debug|x86.Build.0 = Debug|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release.DLL|x64.ActiveCfg = Release|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release.DLL|x64.Build.0 = Release|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release.DLL|x86.ActiveCfg = Release|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release.DLL|x86.Build.0 = Release|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release|x64.ActiveCfg = Release|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release|x64.Build.0 = Release|x64 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release|x86.ActiveCfg = Release|Win32 + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -104,6 +122,7 @@ Global {56EB485C-00A9-459E-B758-2E86316EB7FD} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} {0981CA98-E4A5-4DF1-987F-A41D09131EFC} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} {A16D19CB-6AF4-4D17-8318-EABD8805247C} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + {BC49AAF0-E8C2-4F94-A60A-C56993023C6D} = {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 7c77ed8af..b53926702 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -97,6 +97,10 @@ #define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct #define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct +// Network limits +#define MAX_SOCKET_SET_SIZE 32 +#define MAX_SOCKET_QUEUE_SIZE 16 + // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. #if defined(__cplusplus) @@ -151,6 +155,9 @@ typedef enum { false, true } bool; #endif +// Network typedefs +typedef int SocketHandle; + // Vector2 type typedef struct Vector2 { float x; @@ -417,18 +424,57 @@ typedef struct VrStereoConfig { int eyeViewportRight[4]; // VR stereo rendering right eye viewport [x, y, w, h] int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h] } VrStereoConfig; - -// TCP Stream socket -typedef struct TCPSocket { - int sockfd; - int server; - bool ready; -} TCPSocket; + +typedef struct AddressInformation +{ + int flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST + int family; // PF_xxx + int socktype; // SOCK_xxx + int protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 + size_t addrlen; // Length of ai_addr + char * canonname; // Canonical name for nodename + struct SocketAddress *sockaddr; // Binary address + struct AddressInformation *next; // Next structure in linked list +} AddressInformation; + +typedef struct SocketAddress +{ + unsigned short family; // Address family. + char data[14]; // Up to 14 bytes of direct address. +} SocketAddress; + +// Socket +typedef struct Socket +{ + SocketHandle handle; + bool blocking; +} Socket; + +typedef struct SocketSet +{ + Socket sockets[MAX_SOCKET_SET_SIZE]; +} SocketSet; + + //---------------------------------------------------------------------------------- // Enumerators Definition //---------------------------------------------------------------------------------- +typedef enum +{ + SOCKET_ANY = 0, // ACCEPT_ALL + SOCKET_TCP = 1, // SOCK_STREAM + SOCKET_UDP = 2 // SOCK_DGRAM +} SocketType; + +typedef enum +{ + PROTOCOL_ANY = 0, // ACCEPT_ALL + PROTOCOL_TCP = 6, // IPPROTO_TCP + PROTOCOL_UDP = 17 // IPPROTO_UDP +} ProtocolType; + // System config flags // NOTE: Used for bit masks typedef enum { @@ -1385,13 +1431,27 @@ RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pit // Network functions RLAPI bool InitNetwork(void); RLAPI void CloseNetwork(void); -RLAPI void CreateTCPListenServer(TCPSocket* socket, const char* address, const int port); -RLAPI void CreateTCPClient(TCPSocket* socket, const char* address, const char* port); -RLAPI void AcceptIncomingConnections(TCPSocket* sock, int sockfd); -RLAPI int SendTCP(int sockfd, const char* data, int len); -RLAPI int ReceiveTCP(int sockfd, const char* data, int len); -RLAPI void ResetSocket(TCPSocket* socket); + +RLAPI void GetAddressInformation(AddressInformation* outaddr, const char* address, const char* port, int socketType, int protocolType); + +RLAPI bool CreateSocket(Socket *socket, AddressInformation outaddr); +RLAPI bool BindSocket(Socket socket, const AddressInformation addr); +RLAPI bool ConnectSocket(Socket socket, const AddressInformation addr); +RLAPI bool ListenSocket(Socket socket); +RLAPI void CloseSocket(Socket* socket); +RLAPI void AcceptSocket(Socket listenSock, Socket *newSock); + +RLAPI char* SocketAddressToString(SocketAddress* sockaddr, char buffer[]); +RLAPI void PrintSocket(SocketAddress* addr, const int family, const int socktype, const int protocol); RLAPI void ResolveHost(const char* hostname); +RLAPI void ResolveIP(const char* ip); + +RLAPI void CreateListenServer(Socket* socket, const char* address, const int port, SocketType socketType); +RLAPI void CreateClient(Socket* socket, const char* address, const char* port, SocketType socketType); +RLAPI int Send(SocketHandle sockfd, const char* data, int len); +RLAPI int Receive(SocketHandle sockfd, const char* data, int len); +RLAPI void ResetSocket(Socket* socket); + #if defined(__cplusplus) } diff --git a/src/rnet.c b/src/rnet.c index 83da3d10e..6d1720c33 100644 --- a/src/rnet.c +++ b/src/rnet.c @@ -47,14 +47,20 @@ #include #include +#define errno WSAGetLastError() + +// Initialise the network (requires for windows platforms only) bool InitNetwork() { #if PLATFORM == PLATFORM_WINDOWS WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR) { + if (WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR) + { TraceLog(LOG_INFO, "WinSock initialised."); return true; - } else { + } + else + { TraceLog(LOG_WARNING, "WinSock failed to initialise."); return false; } @@ -63,6 +69,7 @@ bool InitNetwork() #endif } +// Cleanup, and close the network void CloseNetwork() { #if PLATFORM == PLATFORM_WINDOWS @@ -70,59 +77,230 @@ void CloseNetwork() #endif } -void CreateTCPListenServer(TCPSocket* tcpsock, const char* address, const char* port) +// Get address information +void GetAddressInformation(AddressInformation* outaddr, const char* address, const char* port, int socketType, int protocolType) { // Variables - int status; // Status value to return (0) is success - struct addrinfo hints; // Address flags (IPV4, IPV6, UDP?) + 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 // Set the hints memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; // Either IPv4 or IPv6 (AF_INET, AF_INET6) - hints.ai_socktype = SOCK_STREAM; // TCP (SOCK_STREAM), UDP (SOCK_DGRAM) + hints.ai_family = AF_UNSPEC; // Either IPv4 or IPv6 (AF_INET, AF_INET6) + hints.ai_socktype = socketType; // TCP (SOCK_STREAM), UDP (SOCK_DGRAM) + hints.ai_protocol = protocolType; // TCP (IPPROTO_TCP), UDP (IPPROTO_UDP) // Populate address information status = getaddrinfo(address, // e.g. "www.example.com" or IP - port, // e.g. "http" or port number - &hints, // e.g. SOCK_STREAM/SOCK_DGRAM + port, // e.g. "http" or port number + &hints, // e.g. SOCK_STREAM/SOCK_DGRAM + &results // The struct to populate + ); + + memcpy(outaddr, results, sizeof(struct addrinfo)); + + // Did we succeed? + if (status != 0) + { + TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %ls", address, port, gai_strerror(status)); + } + else + { + TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, port); + } + + struct addrinfo* iterator; + for (iterator = outaddr; iterator != NULL; iterator = iterator->ai_next) + { + TraceLog(LOG_DEBUG, "GetAddressInformation"); + TraceLog(LOG_DEBUG, "Flags: 0x%x", iterator->ai_flags); + PrintSocket(iterator->ai_addr, + iterator->ai_family, + iterator->ai_socktype, + iterator->ai_protocol); + TraceLog(LOG_DEBUG, "Length of this sockaddr: %d", iterator->ai_addrlen); + TraceLog(LOG_DEBUG, "Canonical name: %s", iterator->ai_canonname); + } + + freeaddrinfo(results); +} + +// Create a socket from information provided by the filled Address information struct +bool CreateSocket(Socket* sock, const AddressInformation addr) +{ + // Create a socket from provided address data + sock->handle = socket(addr.family, addr.socktype, addr.protocol); + + // Did we succeed? + if (sock->handle == INVALID_SOCKET) + { + TraceLog(LOG_WARNING, "Failed to get create socket: %ls", gai_strerror(sock->handle)); + CloseSocket(sock->handle); + return false; + } + else + { + TraceLog(LOG_INFO, "Successfully created socket"); + PrintSocket(addr.sockaddr, addr.family, addr.socktype, addr.protocol); + } + + // Return true if we've successfully created the socket + return true; +} + +// Bind the socket to a specific port, this is usually used if you're going to listen for incoming connections on a specific port +bool BindSocket(Socket sock, const AddressInformation addr) +{ + // Bind the socket handle to the socket address defined in sockaddr + int status = bind(sock.handle, addr.sockaddr, addr.addrlen); + + // Did we succeed? + if (status == SOCKET_ERROR) + { + TraceLog(LOG_WARNING, "Failed to get bind socket: %ls", gai_strerror(status)); + return false; + } + else + { + char buff[INET6_ADDRSTRLEN]; + TraceLog(LOG_INFO, "Successfully bound socket to address: %s", SocketAddressToString(addr.sockaddr, buff)); + } + + // Return true if we've successfully bound the socket + return true; +} + +// Connect the socket to an address +bool ConnectSocket(Socket socket, AddressInformation addr) +{ + int status = connect(socket.handle, addr.sockaddr, addr.addrlen); + + // Did we succeed? + if (status == SOCKET_ERROR) + { + TraceLog(LOG_WARNING, "Failed to connect socket: %ls", gai_strerror(status)); + return false; + } + else + { + char buff[INET6_ADDRSTRLEN]; + TraceLog(LOG_INFO, "Successfully connected socket to address: %s", SocketAddressToString(addr.sockaddr, buff)); + } + + // Return true if we've successfully connected the socket + return true; +} + +// +bool ListenSocket(Socket socket) +{ + int status = listen(socket.handle, MAX_SOCKET_QUEUE_SIZE); + + // Did we succeed? + if (status == SOCKET_ERROR) + { + TraceLog(LOG_WARNING, "Failed to listen to socket: %ls", gai_strerror(errno)); + return false; + } + else + { + TraceLog(LOG_INFO, "Success, socket now listening"); + } + + // Set the socket i/o mode to blocking, or non-blocking + unsigned long blocking = socket.blocking ? 0 : 1; + status = ioctlsocket(socket.handle, FIONBIO, &blocking); + + if (status != NO_ERROR) + { + TraceLog(LOG_WARNING, "Failed to set socket io mode to: %s", (blocking ? "non-blocking" : "blocking")); + } + else + { + TraceLog(LOG_INFO, "Successfully set socket io mode to: %s", (blocking ? "non-blocking" : "blocking")); + } + + // Return true if we've successfully connected the socket + return true; +} + +// Close a socket +void CloseSocket(Socket* socket) +{ +#if PLATFORM_WINDOWS + closesocket(socket); +#elif PLATFORM == PLATFORM_UNIX + close(socket); +#endif +} + +// +void CreateListenServer(Socket* tcpsock, const char* address, const char* port, SocketType socketType) +{ + // Variables + 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 + + // Set the hints + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // Either IPv4 or IPv6 (AF_INET, AF_INET6) + hints.ai_socktype = socketType; // TCP (SOCK_STREAM), UDP (SOCK_DGRAM) + + // Populate address information + status = getaddrinfo(address, // e.g. "www.example.com" or IP + port, // e.g. "http" or port number + &hints, // e.g. SOCK_STREAM/SOCK_DGRAM &results // The struct to populate ); // Did we succeed? - if (status == -1) { - TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %s", address, port, strerror(status)); - } else { + if (status == -1) + { + TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %ls", address, port, gai_strerror(status)); + } + else + { TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, port); } // Create our server socket - int sockfd = socket(results->ai_family, results->ai_socktype, results->ai_protocol); + int handle = socket(results->ai_family, results->ai_socktype, results->ai_protocol); // Bind it to the port we passed in to getaddrinfo(): - status = bind(sockfd, results->ai_addr, results->ai_addrlen); + status = bind(handle, results->ai_addr, results->ai_addrlen); // Did we succeed? - if (status == -1) { - TraceLog(LOG_WARNING, "Failed to get bind socket to port (%s): %s", port, strerror(errno)); - } else { + if (status == -1) + { + TraceLog(LOG_WARNING, "Failed to get bind socket to port (%s): %ls", port, gai_strerror(errno)); + } + else + { TraceLog(LOG_INFO, "Successfully bound %s to port (%s)", address, port); } // Listen on the bound port - status = listen(sockfd, 5); + status = listen(handle, 5); // Did we succeed? - if (status == -1) { - TraceLog(LOG_WARNING, "Failed to listen to socket: %s", strerror(errno)); - } else { + if (status == -1) + { + TraceLog(LOG_WARNING, "Failed to listen to socket: %ls", gai_strerror(errno)); + } + else + { TraceLog(LOG_INFO, "Successfully started listen server."); } DWORD nonBlocking = 1; - if (ioctlsocket(sockfd, FIONBIO, &nonBlocking) == -1) { + if (ioctlsocket(handle, FIONBIO, &nonBlocking) == -1) + { TraceLog(LOG_WARNING, "Failed to set socket to non-blocking."); - } else { + } + else + { TraceLog(LOG_INFO, "Successfully set socket to non-blocking."); } @@ -130,109 +308,128 @@ void CreateTCPListenServer(TCPSocket* tcpsock, const char* address, const char* freeaddrinfo(results); // Finally, return our socket descriptor - tcpsock->sockfd = sockfd; - tcpsock->server = 1; - tcpsock->ready = true; + tcpsock->handle = handle; return; } -void CreateTCPClient(TCPSocket* tcpsock, char* address, char* port) +// +void CreateClient(Socket* tcpsock, char* address, char* port, SocketType socketType) { int status; - int sockfd; + int handle; struct addrinfo hints; struct addrinfo* results; // Will point to the results memset(&hints, 0, sizeof hints); // Make sure the struct is empty - hints.ai_family = AF_UNSPEC; // Don't care IPv4 or IPv6 - hints.ai_socktype = SOCK_STREAM; // TCP stream sockets + hints.ai_family = AF_UNSPEC; // Don't care IPv4 or IPv6 + hints.ai_socktype = socketType; // TCP stream sockets // Get ready to connect status = getaddrinfo(address, port, &hints, &results); // Did we succeed? - if (status != 0) { - TraceLog(LOG_WARNING, "Failed to get address information: %s", strerror(errno)); - } else { + if (status != 0) + { + TraceLog(LOG_WARNING, "Failed to get address information: %ls", gai_strerror(errno)); + } + else + { TraceLog(LOG_INFO, "Successfully created TCP client on port (%s)", port); } // Create our socket - sockfd = socket(results->ai_family, results->ai_socktype, results->ai_protocol); + handle = socket(results->ai_family, results->ai_socktype, results->ai_protocol); // Did it succeed? - if (sockfd == -1) { - TraceLog(LOG_WARNING, "Failed to create socket: %s", strerror(errno)); - } else { + if (handle == -1) + { + TraceLog(LOG_WARNING, "Failed to create socket: %ls", gai_strerror(errno)); + } + else + { TraceLog(LOG_INFO, "Successfully created socket"); } // Connect to the server - status = connect(sockfd, results->ai_addr, results->ai_addrlen); + status = connect(handle, results->ai_addr, results->ai_addrlen); - if (status == -1) { + if (status == -1) + { TraceLog(LOG_WARNING, "Failed to connect to server %s:%s", address, port); - } else { + } + else + { TraceLog(LOG_INFO, "Successfully connected to %s:%s", address, port); } freeaddrinfo(results); // Finally, return our socket descriptor - tcpsock->sockfd = sockfd; - tcpsock->server = 0; - tcpsock->ready = true; + tcpsock->handle = handle; } -void AcceptIncomingConnections(TCPSocket* tcpsock, int sockfd) +// +void AcceptSocket(Socket listenSock, Socket* newSock) { struct sockaddr_storage their_addr; - socklen_t addr_size; - int new_fd; - addr_size = sizeof their_addr; - new_fd = accept(sockfd, (struct sockaddr*) &their_addr, &addr_size); + socklen_t addrSize; + int newHandle; + addrSize = sizeof their_addr; + newHandle = accept(listenSock.handle, (struct sockaddr*) &their_addr, &addrSize); - if (new_fd == -1) { - TraceLog(LOG_DEBUG, "Failed to accept incoming connection: %s", strerror(errno)); - } else { - tcpsock->sockfd = new_fd; - tcpsock->server = false; - tcpsock->ready = true; + if (newHandle == INVALID_SOCKET) + { + TraceLog(LOG_DEBUG, "Failed to accept incoming connection: %ls", gai_strerror(errno)); + } + else + { + newSock->handle = newHandle; TraceLog(LOG_INFO, "Successfully accepted a new connection."); } } -int SendTCP(int sockfd, const char* data, int len) +// +int SendTCP(SocketHandle handle, const char* data, int len) { - int sentBytes = send(sockfd, data, len, 0); - if (sentBytes == -1) { - TraceLog(LOG_WARNING, "Failed to send data: %s", strerror(errno)); - } else { + int sentBytes = send(handle, data, len, 0); + if (sentBytes == SOCKET_ERROR) + { + TraceLog(LOG_WARNING, "Failed to send data: %ls", gai_strerror(errno)); + } + else + { TraceLog(LOG_DEBUG, "Successfully sent %d bytes.", sentBytes); } } -int ReceiveTCP(int sockfd, const char* data, int len) +// +int ReceiveTCP(SocketHandle handle, const char* data, int len) { - int receiveBytes = recv(sockfd, data, len, 0); - if (receiveBytes == -1) { - TraceLog(LOG_DEBUG, "Failed to receive data: %s", strerror(errno)); - } else if (receiveBytes == 0) { - TraceLog(LOG_INFO, "Connection closed."); - } else { - TraceLog(LOG_DEBUG, "Successfully received %d bytes.", receiveBytes); + int status = recv(handle, data, len, 0); + if (status == SOCKET_ERROR && errno == EWOULDBLOCK) + { + TraceLog(LOG_DEBUG, "Failed to receive data: %ls", gai_strerror(errno)); } - return receiveBytes; + else if (status > 0) + { + TraceLog(LOG_DEBUG, "Successfully received %d bytes.", status); + } + else if (status == 0) + { + TraceLog(LOG_INFO, "Connection closed."); + } + return status; } -void ResetSocket(TCPSocket* socket) +// Reset a socket +void ResetSocket(Socket* socket) { - socket->ready = false; - socket->server = 0; - socket->sockfd = -1; + socket->handle = -1; + socket->blocking = false; }; +// Resolve the hostname void ResolveHost(const char* hostname) { struct addrinfo hints, *res, *p; @@ -240,27 +437,32 @@ void ResolveHost(const char* hostname) char ipstr[INET6_ADDRSTRLEN]; memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; // AF_INET or AF_INET6 to force version + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version hints.ai_socktype = SOCK_STREAM; - if ((status = getaddrinfo(hostname, NULL, &hints, &res)) != 0) { - TraceLog(LOG_WARNING, "getaddrinfo: %s", strerror(status)); + if ((status = getaddrinfo(hostname, NULL, &hints, &res)) != 0) + { + TraceLog(LOG_WARNING, "getaddrinfo: %ls", gai_strerror(status)); return 2; } TraceLog(LOG_INFO, "IP addresses for %s:", hostname); - for (p = res; p != NULL; p = p->ai_next) { + for (p = res; p != NULL; p = p->ai_next) + { void* addr; char* ipver; // get the pointer to the address itself, // different fields in IPv4 and IPv6: - if (p->ai_family == AF_INET) { // IPv4 + if (p->ai_family == AF_INET) + { // IPv4 struct sockaddr_in* ipv4 = (struct sockaddr_in*) p->ai_addr; addr = &(ipv4->sin_addr); ipver = "IPv4"; - } else { // IPv6 + } + else + { // IPv6 struct sockaddr_in6* ipv6 = (struct sockaddr_in6*) p->ai_addr; addr = &(ipv6->sin6_addr); ipver = "IPv6"; @@ -273,3 +475,127 @@ void ResolveHost(const char* hostname) freeaddrinfo(res); // free the linked list } + +// Resolve the hostname +void ResolveIP(const char* ip) +{ + struct hostent* he; + struct in_addr ipv4addr; + struct in6_addr ipv6addr; + inet_pton(AF_INET, ip, &ipv4addr); + he = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET); + if (he != NULL) + { + printf("Host name: %s\n", he->h_name); + } + inet_pton(AF_INET6, ip, &ipv6addr); + he = gethostbyaddr(&ipv6addr, sizeof ipv6addr, AF_INET6); + if (he != NULL) + { + printf("Host name: %s\n", he->h_name); + } +} + +// Print socket information +void PrintSocket(struct SocketAddress* addr, const int family, const int socktype, const int protocol) +{ + struct sockaddr_in* sockaddr_ipv4; + struct sockaddr_in6* sockaddr_ipv6; + struct sockaddr* sockaddr_ip; + char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string + char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string + switch (family) + { + case AF_UNSPEC: + { + TraceLog(LOG_DEBUG, "Family: Unspecified"); + } + break; + case AF_INET: + { + TraceLog(LOG_DEBUG, "Family: AF_INET (IPv4)"); + TraceLog(LOG_INFO, "- IPv4 address %s", SocketAddressToString(addr, ip4)); + } + break; + case AF_INET6: + { + TraceLog(LOG_DEBUG, "Family: AF_INET6 (IPv6)"); + TraceLog(LOG_INFO, "- IPv6 address %s", SocketAddressToString(addr, ip6)); + } + break; + case AF_NETBIOS: + { + TraceLog(LOG_DEBUG, "Family: AF_NETBIOS (NetBIOS)"); + } + break; + default: + { + TraceLog(LOG_DEBUG, "Family: Other %ld", family); + } + break; + } + TraceLog(LOG_DEBUG, "Socket type:"); + switch (socktype) + { + case 0: + TraceLog(LOG_DEBUG, "- Unspecified"); + break; + case SOCK_STREAM: + TraceLog(LOG_DEBUG, "- SOCK_STREAM (stream)"); + break; + case SOCK_DGRAM: + TraceLog(LOG_DEBUG, "- SOCK_DGRAM (datagram)"); + break; + case SOCK_RAW: + TraceLog(LOG_DEBUG, "- SOCK_RAW (raw)"); + break; + case SOCK_RDM: + TraceLog(LOG_DEBUG, "- SOCK_RDM (reliable message datagram)"); + break; + case SOCK_SEQPACKET: + TraceLog(LOG_DEBUG, "- SOCK_SEQPACKET (pseudo-stream packet)"); + break; + default: + TraceLog(LOG_DEBUG, "- Other %ld", socktype); + break; + } + TraceLog(LOG_DEBUG, "Protocol:"); + switch (protocol) + { + case 0: + TraceLog(LOG_DEBUG, "- Unspecified"); + break; + case IPPROTO_TCP: + TraceLog(LOG_DEBUG, "- IPPROTO_TCP (TCP)"); + break; + case IPPROTO_UDP: + TraceLog(LOG_DEBUG, "- IPPROTO_UDP (UDP)"); + break; + default: + TraceLog(LOG_DEBUG, "- Other %ld", protocol); + break; + } +} + +// Convert network ordered socket address to human readable string (127.0.0.1) +char* SocketAddressToString(struct SocketAddress* sockaddr, char buffer[]) +{ + switch (sockaddr->family) + { + case AF_INET: + { + return inet_ntop(AF_INET, &((struct sockaddr_in*) sockaddr)->sin_addr, buffer, INET_ADDRSTRLEN); + } + break; + case AF_INET6: + { + return inet_ntop(AF_INET6, &((struct sockaddr_in6*) sockaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN); + } + break; + default: + { + return NULL; + } + break; + } +}