diff --git a/examples/network/network_ping_pong.c b/examples/network/network_ping_pong.c index 990f56ef8..22962b439 100644 --- a/examples/network/network_ping_pong.c +++ b/examples/network/network_ping_pong.c @@ -36,8 +36,8 @@ bool client_connected = false; const char * pingmsg = "Ping!"; const char * pongmsg = "Pong!"; int msglen = 0; -SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .type = SOCKET_TCP, .server = true, .nonblocking = true}; -SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .type = SOCKET_TCP, .nonblocking = true}; +SocketConfig server_cfg = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .server = true, .nonblocking = true}; +SocketConfig client_cfg = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .nonblocking = true}; SocketConfig connection_cfg = {.nonblocking = true}; SocketResult *server_res = NULL; SocketResult *client_res = NULL; @@ -100,14 +100,14 @@ void NetworkUpdate() int bytesRecv = 0; if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) { if (IsSocketReady(client_res->socket)) { - bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen, 0); + bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen); } if (IsSocketReady(server_res->socket)) { - bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0); + bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen); } } else { if (IsSocketReady(connection)) { - bytesRecv = SocketReceive(connection, recvBuffer, msglen, 0); + bytesRecv = SocketReceive(connection, recvBuffer, msglen); } } diff --git a/examples/network/network_resolve_host.c b/examples/network/network_resolve_host.c index f0f132943..bfef660bb 100644 --- a/examples/network/network_resolve_host.c +++ b/examples/network/network_resolve_host.c @@ -36,9 +36,22 @@ int main() // Networking InitNetwork(); - ResolveHost("www.google.com", "80"); - ResolveIP("8.8.8.8", NULL, NAME_INFO_DEFAULT); - ResolveIP("2001:4860:4860::8888", "80", NAME_INFO_NUMERICSERV); + AddressInformation* addr = NULL; + int count = ResolveHost( + NULL, + "5210", + ADDRESS_TYPE_IPV4, + 0 // Uncomment any of these flags + // ADDRESS_INFO_NUMERICHOST // or try them in conjunction to + // ADDRESS_INFO_NUMERICSERV // specify custom behaviour from + // ADDRESS_INFO_DNS_ONLY // the function getaddrinfo() + // ADDRESS_INFO_ALL // + // ADDRESS_INFO_FQDN // e.g. ADDRESS_INFO_CANONNAME | ADDRESS_INFO_NUMERICSERV + , + addr + ); + ResolveIP("8.8.8.8", NULL, NAME_INFO_DEFAULT, NULL, NULL); + ResolveIP("2001:4860:4860::8888", "80", NAME_INFO_NUMERICSERV, NULL, NULL); // Main game loop while (!WindowShouldClose()) diff --git a/examples/network/network_tcp_client.c b/examples/network/network_tcp_client.c index a8cce001f..7b9172708 100644 --- a/examples/network/network_tcp_client.c +++ b/examples/network/network_tcp_client.c @@ -13,7 +13,7 @@ bool connected = false; const char * pingmsg = "Ping!"; const char * pongmsg = "Pong!"; int msglen = 0; -SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .type = SOCKET_TCP, .nonblocking = true}; +SocketConfig client_cfg = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .nonblocking = true}; SocketResult *client_res = NULL; SocketSet * socket_set = NULL; char recvBuffer[512]; @@ -48,7 +48,7 @@ void NetworkUpdate() // If the socket is ready, attempt to receive data from the socket int bytesRecv = 0; if (IsSocketReady(client_res->socket)) { - bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen, 0); + bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen); } // If we received data, was that data a "Ping!" or a "Pong!" @@ -77,7 +77,7 @@ int main() int screenWidth = 800; int screenHeight = 450; InitWindow( - screenWidth, screenHeight, "raylib [network] example - ping pong"); + screenWidth, screenHeight, "raylib [network] example - tcp client"); SetTargetFPS(60); SetTraceLogLevel(LOG_DEBUG); diff --git a/examples/network/network_tcp_server.c b/examples/network/network_tcp_server.c index 905742a34..b6ae7b5e7 100644 --- a/examples/network/network_tcp_server.c +++ b/examples/network/network_tcp_server.c @@ -13,7 +13,7 @@ bool connected = false; const char * pingmsg = "Ping!"; const char * pongmsg = "Pong!"; int msglen = 0; -SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .type = SOCKET_TCP, .server = true, .nonblocking = true}; +SocketConfig server_cfg = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .server = true, .nonblocking = true}; SocketConfig connection_cfg = {.nonblocking = true}; SocketResult *server_res = NULL; SocketSet * socket_set = NULL; @@ -56,7 +56,7 @@ void NetworkUpdate() // If the socket is ready, attempt to receive data from the socket int bytesRecv = 0; if (IsSocketReady(connection)) { - bytesRecv = SocketReceive(connection, recvBuffer, msglen, 0); + bytesRecv = SocketReceive(connection, recvBuffer, msglen); } // If we received data, was that data a "Ping!" or a "Pong!" @@ -85,7 +85,7 @@ int main() int screenWidth = 800; int screenHeight = 450; InitWindow( - screenWidth, screenHeight, "raylib [network] example - ping pong"); + screenWidth, screenHeight, "raylib [network] example - tcp server"); SetTargetFPS(60); SetTraceLogLevel(LOG_DEBUG); diff --git a/examples/network/network_test.c b/examples/network/network_test.c index 00b483170..e3107f66c 100644 --- a/examples/network/network_test.c +++ b/examples/network/network_test.c @@ -28,39 +28,40 @@ void test_resolve_ip() const char *host = "8.8.8.8"; const char *port = "8080"; char ip[ADDRESS_IPV6_ADDRSTRLEN]; + char service[ADDRESS_MAXSERV]; memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip); + ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "8.8.8.8") == 0); memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_DEFAULT, ip); + ResolveIP(host, port, NAME_INFO_DEFAULT, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "google-public-dns-a.google.com") == 0); memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_NOFQDN, ip); + ResolveIP(host, port, NAME_INFO_NOFQDN, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "google-public-dns-a") == 0); memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip); + ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "8.8.8.8") == 0); memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_NAMEREQD, ip); + ResolveIP(host, port, NAME_INFO_NAMEREQD, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "google-public-dns-a.google.com") == 0); memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_NUMERICSERV, ip); + ResolveIP(host, port, NAME_INFO_NUMERICSERV, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "google-public-dns-a.google.com") == 0); memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN); - ResolveIP(host, port, NAME_INFO_DGRAM, ip); + ResolveIP(host, port, NAME_INFO_DGRAM, ip, service); TraceLog(LOG_INFO, "Resolved %s to %s", host, ip); assert(strcmp(ip, "google-public-dns-a.google.com") == 0); } @@ -75,7 +76,7 @@ void test_resolve_host() assert(GetAddressFamily(addr[1]) == ADDRESS_TYPE_IPV4); assert(GetAddressSocketType(addr[0]) == 0); assert(GetAddressProtocol(addr[0]) == 0); - for (size_t i = 0; i < count; i++) { PrintAddressInfo(addr[i]); } + // for (size_t i = 0; i < count; i++) { PrintAddressInfo(addr[i]); } } void test_address() diff --git a/examples/network/network_udp_client.c b/examples/network/network_udp_client.c index 54153a3ee..091b8099a 100644 --- a/examples/network/network_udp_client.c +++ b/examples/network/network_udp_client.c @@ -35,7 +35,7 @@ void NetworkUpdate() // If the socket is ready, attempt to receive data from the socket int bytesRecv = 0; if (IsSocketReady(client_res->socket)) { - bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen, 0); + bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen); } // If we received data, was that data a "Ping!" or a "Pong!" diff --git a/examples/network/network_udp_server.c b/examples/network/network_udp_server.c index 68610496e..97161a865 100644 --- a/examples/network/network_udp_server.c +++ b/examples/network/network_udp_server.c @@ -35,9 +35,9 @@ void NetworkUpdate() // If the socket is ready, attempt to receive data from the socket // int bytesRecv = 0; // if (IsSocketReady(server_res->socket)) { - // bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0); + // bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen); // } - int bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0); + int bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen); // If we received data, was that data a "Ping!" or a "Pong!" if (bytesRecv > 0) { diff --git a/projects/VS2017/examples/network_resolve_host.vcxproj b/projects/VS2017/examples/network_resolve_host.vcxproj index f184462cb..7a354192b 100644 --- a/projects/VS2017/examples/network_resolve_host.vcxproj +++ b/projects/VS2017/examples/network_resolve_host.vcxproj @@ -89,6 +89,8 @@ false + $(ProjectDir)$(ProjectName)\$(Configuration)\ + $(ProjectDir)$(ProjectName)\$(Configuration)\temp false @@ -131,7 +133,7 @@ - Use + NotUsing Level3 MaxSpeed true @@ -140,6 +142,7 @@ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) Console diff --git a/src/raylib.h b/src/raylib.h index 80b3a7fe5..7d00842a2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -98,26 +98,55 @@ #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 defines -#define SOCKET_MAX_SET_SIZE 32 -#define SOCKET_MAX_QUEUE_SIZE 16 -#define SOCKET_MAX_SOCK_OPTS 4 -#define SOCKET_MAX_UDPCHANNELS (32) -#define SOCKET_MAX_UDPADDRESSES (4) +// Network connection related defines +#define SOCKET_MAX_SET_SIZE (32) // Maximum sockets in a set +#define SOCKET_MAX_QUEUE_SIZE (16) // Maximum socket queue size +#define SOCKET_MAX_SOCK_OPTS (4) // Maximum socket options +#define SOCKET_MAX_UDPCHANNELS (32) // Maximum UDP channels +#define SOCKET_MAX_UDPADDRESSES (4) // Maximum bound UDP addresses -// -#define ADDRESS_IPV4_ADDRSTRLEN 22 -#define ADDRESS_IPV6_ADDRSTRLEN 65 -#define ADDRESS_TYPE_IPV4 2 -#define ADDRESS_TYPE_IPV6 23 +// Network address related defines +#define ADDRESS_IPV4_ADDRSTRLEN (22) // IPv4 string length +#define ADDRESS_IPV6_ADDRSTRLEN (65) // IPv6 string length +#define ADDRESS_TYPE_ANY (0) // AF_UNSPEC +#define ADDRESS_TYPE_IPV4 (2) // AF_INET +#define ADDRESS_TYPE_IPV6 (23) // AF_INET6 +#define ADDRESS_MAXHOST (1025) // Max size of a fully-qualified domain name +#define ADDRESS_MAXSERV (32) // Max size of a service name -// getnameinfo() defines -#define NAME_INFO_DEFAULT 0x00 /* No flags set */ -#define NAME_INFO_NOFQDN 0x01 /* Only return nodename portion for local hosts */ -#define NAME_INFO_NUMERICHOST 0x02 /* Return numeric form of the host's address */ -#define NAME_INFO_NAMEREQD 0x04 /* Error if the host's name not in DNS */ -#define NAME_INFO_NUMERICSERV 0x08 /* Return numeric form of the service (port #) */ -#define NAME_INFO_DGRAM 0x10 /* Service is a datagram service */ +// Network address related defines +#define ADDRESS_ANY ((unsigned long) 0x00000000) +#define ADDRESS_LOOPBACK (0x7f000001) +#define ADDRESS_BROADCAST ((unsigned long) 0xffffffff) +#define ADDRESS_NONE (0xffffffff) + +// Address resolution related defines +#if defined(_WIN32) + #define ADDRESS_INFO_PASSIVE (0x00000001) // Socket address will be used in bind() call + #define ADDRESS_INFO_CANONNAME (0x00000002) // Return canonical name in first ai_canonname + #define ADDRESS_INFO_NUMERICHOST (0x00000004) // Nodename must be a numeric address string + #define ADDRESS_INFO_NUMERICSERV (0x00000008) // Servicename must be a numeric port number + #define ADDRESS_INFO_DNS_ONLY (0x00000010) // Restrict queries to unicast DNS only (no LLMNR, netbios, etc.) + #define ADDRESS_INFO_ALL (0x00000100) // Query both IP6 and IP4 with AI_V4MAPPED + #define ADDRESS_INFO_ADDRCONFIG (0x00000400) // Resolution only if global address configured + #define ADDRESS_INFO_V4MAPPED (0x00000800) // On v6 failure, query v4 and convert to V4MAPPED format + #define ADDRESS_INFO_NON_AUTHORITATIVE (0x00004000) // LUP_NON_AUTHORITATIVE + #define ADDRESS_INFO_SECURE (0x00008000) // LUP_SECURE + #define ADDRESS_INFO_RETURN_PREFERRED_NAMES (0x00010000) // LUP_RETURN_PREFERRED_NAMES + #define ADDRESS_INFO_FQDN (0x00020000) // Return the FQDN in ai_canonname + #define ADDRESS_INFO_FILESERVER (0x00040000) // Resolving fileserver name resolution + #define ADDRESS_INFO_DISABLE_IDN_ENCODING (0x00080000) // Disable Internationalized Domain Names handling + #define ADDRESS_INFO_EXTENDED (0x80000000) // Indicates this is extended ADDRINFOEX(2/..) struct + #define ADDRESS_INFO_RESOLUTION_HANDLE (0x40000000) // Request resolution handle +#endif + +// Network resolution related defines +#define NAME_INFO_DEFAULT (0x00) // No flags set +#define NAME_INFO_NOFQDN (0x01) // Only return nodename portion for local hosts +#define NAME_INFO_NUMERICHOST (0x02) // Return numeric form of the host's address +#define NAME_INFO_NAMEREQD (0x04) // Error if the host's name not in DNS +#define NAME_INFO_NUMERICSERV (0x08) // Return numeric form of the service (port #) +#define NAME_INFO_DGRAM (0x10) // Service is a datagram service // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. @@ -1502,14 +1531,15 @@ RLAPI bool InitNetwork(void); RLAPI void CloseNetwork(void); // Address API -RLAPI void ResolveIP(const char *host, const char *port, int flags, char *outhost); -RLAPI int ResolveHost(const char *address, const char *port, struct _AddressInformation *addr); -RLAPI int GetAddressFamily(); +RLAPI void ResolveIP(const char *ip, const char *service, int flags, char *outhost, char *outserv); +RLAPI int ResolveHost(const char *address, const char *service, int addressType, int flags, AddressInformation* outAddr); +RLAPI int GetAddressFamily(); RLAPI int GetAddressSocketType(AddressInformation address); RLAPI int GetAddressProtocol(AddressInformation address); RLAPI void PrintAddressInfo(AddressInformation address); RLAPI AddressInformation AllocAddress(); -RLAPI AddressInformation* AllocAddressList(int size); +RLAPI void FreeAddress(AddressInformation* addressInfo); +RLAPI AddressInformation *AllocAddressList(int size); // Socket API RLAPI bool SocketCreate(SocketConfig *config, SocketResult* result); @@ -1520,12 +1550,12 @@ RLAPI Socket *SocketAccept(Socket *server, SocketConfig *config); // UDP Socket API RLAPI int SocketSetChannel(Socket *socket, int channel, const IPAddress *address); -RLAPI int SocketUnsetChannel(Socket *socket, int channel); +RLAPI void SocketUnsetChannel(Socket *socket, int channel); RLAPI IPAddress* SocketGetPeerAddress(Socket *socket, int channel); // General Socket API RLAPI int SocketSend(Socket *sock, const void *datap, int len); -RLAPI int SocketReceive(Socket *sock, void *data, int maxlen, int timeout); +RLAPI int SocketReceive(Socket *sock, void *data, int maxlen); RLAPI void SocketClose(Socket* sock); RLAPI int SocketReady(Socket* sock); diff --git a/src/rnet.c b/src/rnet.c index 253a02564..2893d372c 100644 --- a/src/rnet.c +++ b/src/rnet.c @@ -43,6 +43,7 @@ #include "raylib.h" +#include // Required for: assert() #include // Required for: FILE, fopen(), fclose(), fread() #include // Required for: malloc(), free() #include // Required for: strcmp(), strncmp() @@ -51,10 +52,7 @@ // Module defines //---------------------------------------------------------------------------------- -#define NET_SOCKET_BACKLOG_SIZE (20) -#define NET_MAXHOST (1025) // Max size of a fully-qualified domain name -#define NET_MAXSERV (32) // Max size of a service name -#define NET_DEBUG_ENABLED (0) +#define NET_DEBUG_ENABLED (1) //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -80,24 +78,24 @@ typedef struct _AddressInformation { // Global module forward declarations //---------------------------------------------------------------------------------- -static bool IsSocketValid(Socket *sock); -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, struct addrinfo *addr); -static bool CreateSocket(SocketConfig *config, SocketResult *outresult); -static bool SocketSetBlocking(Socket *out); -static bool SocketSetNonBlocking(Socket *out); -static bool SocketSetOptions(SocketConfig *config, Socket *channel); -static void *GetSocketAddressPtr(struct sockaddr *sa); -static void *GetSocketPortPtr(struct sockaddr *sa); -static void SocketSetHints(SocketConfig *config, struct addrinfo *hints); -static bool IsIPv4Address(const char *ip); -static bool IsIPv6Address(const char *ip); -static char *SocketAddressToString(struct sockaddr_storage *sockaddr); -static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol); +static bool IsSocketValid(Socket *sock); +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, struct addrinfo *addr); +static bool CreateSocket(SocketConfig *config, SocketResult *outresult); +static bool SocketSetBlocking(Socket *out); +static bool SocketSetNonBlocking(Socket *out); +static bool SocketSetOptions(SocketConfig *config, Socket *channel); +static void * GetSocketAddressPtr(struct sockaddr *sa); +static void * GetSocketPortPtr(struct sockaddr *sa); +static void SocketSetHints(SocketConfig *config, struct addrinfo *hints); +static bool IsIPv4Address(const char *ip); +static bool IsIPv6Address(const char *ip); +static const char *SocketAddressToString(struct sockaddr_storage *sockaddr); +static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol); //---------------------------------------------------------------------------------- // Global module implementation @@ -153,9 +151,11 @@ static void PrintSocket(struct sockaddr_storage *addr, const int family, const i } // Convert network ordered socket address to human readable string (127.0.0.1) -static char *SocketAddressToString(struct sockaddr_storage *sockaddr) +static const char *SocketAddressToString(struct sockaddr_storage *sockaddr) { static ipv6[INET6_ADDRSTRLEN]; + assert(sockaddr != NULL); + assert(sockaddr->ss_family == AF_INET || sockaddr->ss_family == AF_INET6); switch (sockaddr->ss_family) { case AF_INET: { struct sockaddr_in *s = ((struct sockaddr_in *) sockaddr); @@ -165,10 +165,8 @@ static char *SocketAddressToString(struct sockaddr_storage *sockaddr) struct sockaddr_in6 *s = ((struct sockaddr_in6 *) sockaddr); return inet_ntop(AF_INET6, &s->sin6_addr, ipv6, INET6_ADDRSTRLEN); } break; - default: { - return NULL; - } break; } + return NULL; } // Check if the null terminated string ip is a valid IPv4 address @@ -210,7 +208,9 @@ void *GetSocketAddressPtr(struct sockaddr *sa) // Is the socket in a valid state? static bool IsSocketValid(Socket *sock) { - if (sock != NULL) { return (sock->channel != INVALID_SOCKET); } + if (sock != NULL) { + return (sock->channel != INVALID_SOCKET); + } return false; } @@ -256,7 +256,7 @@ static char *SocketErrorCodeToString(int err) static bool SocketSetDefaults(SocketConfig *config) { if (config->backlog_size == 0) { - config->backlog_size = NET_SOCKET_BACKLOG_SIZE; + config->backlog_size = SOCKET_MAX_QUEUE_SIZE; } return true; @@ -364,7 +364,7 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult) } // Set socket options - if (!SocketSetOptions(config, outresult->socket->channel)) { + if (!SocketSetOptions(config, outresult->socket)) { outresult->socket->status = SocketGetLastError(); TraceLog(LOG_WARNING, "Socket Error: %s", @@ -398,16 +398,18 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult) if (outresult->socket->addripv4 != NULL) { memset(outresult->socket->addripv4, 0, sizeof(*outresult->socket->addripv4)); + if (outresult->socket->addripv4 != NULL) { + memcpy(&outresult->socket->addripv4->address, + (struct sockaddr_in *) res->ai_addr, sizeof(struct sockaddr_in)); + outresult->socket->isIPv6 = false; + char hoststr[NI_MAXHOST]; + char portstr[NI_MAXSERV]; + socklen_t client_len = sizeof(struct sockaddr_storage); + getnameinfo( + (struct sockaddr *) &outresult->socket->addripv4->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV); + TraceLog(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr); + } } - memcpy(&outresult->socket->addripv4->address, - (struct sockaddr_in *) res->ai_addr, sizeof(struct sockaddr_in)); - outresult->socket->isIPv6 = false; - char hoststr[NI_MAXHOST]; - char portstr[NI_MAXSERV]; - socklen_t client_len = sizeof(struct sockaddr_storage); - int rc = getnameinfo( - (struct sockaddr *) &outresult->socket->addripv4->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV); - TraceLog(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr); } break; case AF_INET6: { outresult->socket->addripv6 = (struct _SocketAddressIPv6 *) malloc( @@ -415,16 +417,18 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult) if (outresult->socket->addripv6 != NULL) { memset(outresult->socket->addripv6, 0, sizeof(*outresult->socket->addripv6)); + if (outresult->socket->addripv6 != NULL) { + memcpy(&outresult->socket->addripv6->address, + (struct sockaddr_in6 *) res->ai_addr, sizeof(struct sockaddr_in6)); + outresult->socket->isIPv6 = true; + char hoststr[NI_MAXHOST]; + char portstr[NI_MAXSERV]; + socklen_t client_len = sizeof(struct sockaddr_storage); + getnameinfo( + (struct sockaddr *) &outresult->socket->addripv6->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV); + TraceLog(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr); + } } - memcpy(&outresult->socket->addripv6->address, - (struct sockaddr_in6 *) res->ai_addr, sizeof(struct sockaddr_in6)); - outresult->socket->isIPv6 = true; - char hoststr[NI_MAXHOST]; - char portstr[NI_MAXSERV]; - socklen_t client_len = sizeof(struct sockaddr_storage); - int rc = getnameinfo( - (struct sockaddr *) &outresult->socket->addripv6->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV); - TraceLog(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr); } break; } } @@ -474,7 +478,9 @@ static bool SocketSetOptions(SocketConfig *config, Socket *sock) { for (int i = 0; i < SOCKET_MAX_SOCK_OPTS; i++) { SocketOpt *opt = &config->sockopts[i]; - if (opt->id == 0) { break; } + if (opt->id == 0) { + break; + } if (setsockopt(sock->channel, SOL_SOCKET, opt->id, opt->value, opt->valueLen) < 0) { return false; @@ -487,7 +493,9 @@ static bool SocketSetOptions(SocketConfig *config, Socket *sock) // Set "hints" in an addrinfo struct, to be passed to getaddrinfo. static void SocketSetHints(SocketConfig *config, struct addrinfo *hints) { - if (config == NULL || hints == NULL) { return; } + if (config == NULL || hints == NULL) { + return; + } memset(hints, 0, sizeof(*hints)); // Check if the ip supplied in the config is a valid ipv4 ip ipv6 address @@ -552,12 +560,7 @@ bool InitNetwork() void CloseNetwork() { #if PLATFORM == PLATFORM_WINDOWS - if (WSACleanup() == SOCKET_ERROR) { - if (WSAGetLastError() == WSAEINPROGRESS) { - WSACancelBlockingCall(); - WSACleanup(); - } - } + WSACleanup(); #endif } @@ -606,18 +609,18 @@ void ResolveIP(const char *ip, const char *port, int flags, char *host, char *se status = getnameinfo(&*((struct sockaddr *) res->ai_addr), sizeof(*((struct sockaddr_in *) res->ai_addr)), host, - NET_MAXHOST, + NI_MAXHOST, serv, - NET_MAXSERV, + NI_MAXSERV, flags); break; case AF_INET6: status = getnameinfo(&*((struct sockaddr_in6 *) res->ai_addr), sizeof(*((struct sockaddr_in6 *) res->ai_addr)), host, - NET_MAXHOST, + NI_MAXHOST, serv, - NET_MAXSERV, + NI_MAXSERV, flags); break; default: break; @@ -639,10 +642,14 @@ void ResolveIP(const char *ip, const char *port, int flags, char *host, char *se // const char* address = "127.0.0.1" (local address) // const char* port = "80" // +// Parameters: +// const char* address - A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string. +// const char* service - A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string. +// // Returns: // The total amount of addresses found, -1 on error // -int ResolveHost(const char *address, const char *port, AddressInformation *addrlist) +int ResolveHost(const char *address, const char *service, int addressType, int flags, AddressInformation *outAddr) { // Variables int status; // Status value to return (0) is success @@ -650,27 +657,41 @@ int ResolveHost(const char *address, const char *port, AddressInformation *addrl struct addrinfo *res; // will point to the results struct addrinfo *iterator; int portptr; + assert(((address != NULL || address != 0) || (service != NULL || service != 0))); + assert(((addressType == AF_INET) || (addressType == AF_INET6) || (addressType == AF_UNSPEC))); // Set the hints memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // Either IPv4 or IPv6 (AF_INET, AF_INET6) + hints.ai_family = addressType; // Either IPv4 or IPv6 (ADDRESS_TYPE_IPV4, ADDRESS_TYPE_IPV6) hints.ai_protocol = 0; // Automatically select correct protocol (IPPROTO_TCP), (IPPROTO_UDP) + hints.ai_flags = flags; + assert(hints.ai_addrlen == NULL || hints.ai_addrlen == 0); + assert(hints.ai_canonname == NULL || hints.ai_canonname == 0); + assert(hints.ai_addr == NULL || hints.ai_addr == 0); + assert(hints.ai_next == NULL || hints.ai_next == 0); // When the address is NULL, populate the IP for me - if (address == NULL) { hints.ai_flags = AI_PASSIVE; } + if (address == NULL) { + hints.ai_flags |= AI_PASSIVE; + } + + TraceLog(LOG_INFO, "Resolving host..."); // Populate address information status = getaddrinfo(address, // e.g. "www.example.com" or IP - port, // e.g. "http" or port number + service, // e.g. "http" or port number &hints, // e.g. SOCK_STREAM/SOCK_DGRAM &res // The struct to populate ); // Did we succeed? if (status != 0) { - TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %s", address, port, gai_strerror(errno)); + int error = SocketGetLastError(); + SocketSetLastError(0); + TraceLog(LOG_WARNING, "Failed to get resolve host: %s", SocketErrorCodeToString(error)); + return -1; } else { - TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, port); + TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, service); } // Calculate the size of the address information list @@ -685,38 +706,48 @@ int ResolveHost(const char *address, const char *port, AddressInformation *addrl return -1; } + // If not address list was allocated, allocate it dynamically with the known address size + if (outAddr == NULL) { + outAddr = AllocAddressList(size); + } + // Dynamically allocate an array of address information structs - if (addrlist != NULL) { + if (outAddr != NULL) { int i; for (i = 0; i < size; ++i) { - addrlist[i] = AllocAddress(); - if (addrlist[i] == NULL) { break; } + outAddr[i] = AllocAddress(); + if (outAddr[i] == NULL) { + break; + } + } + outAddr[i] = NULL; + if (i != size) { + outAddr = NULL; } - addrlist[i] = NULL; - if (i != size) { addrlist = NULL; } } else { TraceLog(LOG_WARNING, "Error, failed to dynamically allocate memory for the address list"); + return -1; } // Copy all the address information from res into outAddrList int i = 0; for (iterator = res; iterator != NULL; iterator = iterator->ai_next) { if (i < size) { - addrlist[i]->addr.ai_flags = iterator->ai_flags; - addrlist[i]->addr.ai_family = iterator->ai_family; - addrlist[i]->addr.ai_socktype = iterator->ai_socktype; - addrlist[i]->addr.ai_protocol = iterator->ai_protocol; - addrlist[i]->addr.ai_addrlen = iterator->ai_addrlen; - memcpy(&addrlist[i]->addr.ai_addr, iterator->ai_addr, iterator->ai_addrlen); + outAddr[i]->addr.ai_flags = iterator->ai_flags; + outAddr[i]->addr.ai_family = iterator->ai_family; + outAddr[i]->addr.ai_socktype = iterator->ai_socktype; + outAddr[i]->addr.ai_protocol = iterator->ai_protocol; + outAddr[i]->addr.ai_addrlen = iterator->ai_addrlen; + *outAddr[i]->addr.ai_addr = *iterator->ai_addr; #if NET_DEBUG_ENABLED TraceLog(LOG_DEBUG, "GetAddressInformation"); TraceLog(LOG_DEBUG, "\tFlags: 0x%x", iterator->ai_flags); - PrintSocket(&addrlist[i]->addr.ai_addr, - addrlist[i]->addr.ai_family, - addrlist[i]->addr.ai_socktype, - addrlist[i]->addr.ai_protocol); - TraceLog(LOG_DEBUG, "Length of this sockaddr: %d", addrlist[i]->addr.ai_addrlen); + PrintSocket(outAddr[i]->addr.ai_addr, + outAddr[i]->addr.ai_family, + outAddr[i]->addr.ai_socktype, + outAddr[i]->addr.ai_protocol); + TraceLog(LOG_DEBUG, "Length of this sockaddr: %d", outAddr[i]->addr.ai_addrlen); TraceLog(LOG_DEBUG, "Canonical name: %s", iterator->ai_canonname); #endif i++; @@ -750,7 +781,9 @@ bool SocketCreate(SocketConfig *config, SocketResult *result) bool success = true; // Make sure we've not received a null config or result pointer - if (config == NULL || result == NULL) { return (success = false); } + if (config == NULL || result == NULL) { + return (success = false); + } // Set the defaults based on the config if (!SocketSetDefaults(config)) { @@ -871,7 +904,9 @@ bool SocketConnect(SocketConfig *config, SocketResult *result) if (IsIPv4Address(config->host)) { struct sockaddr_in ip4addr; ip4addr.sin_family = AF_INET; - ip4addr.sin_port = config->port; + unsigned long hport; + hport = strtoul(config->port, NULL, 0); + ip4addr.sin_port = htons(hport); inet_pton(AF_INET, config->host, &ip4addr.sin_addr); int connect_result = connect(result->socket->channel, (struct sockaddr *) &ip4addr, sizeof(ip4addr)); if (connect_result == SOCKET_ERROR) { @@ -897,7 +932,9 @@ bool SocketConnect(SocketConfig *config, SocketResult *result) if (IsIPv6Address(config->host)) { struct sockaddr_in6 ip6addr; ip6addr.sin6_family = AF_INET6; - ip6addr.sin6_port = config->port; + unsigned long hport; + hport = strtoul(config->port, NULL, 0); + ip6addr.sin6_port = htons(hport); inet_pton(AF_INET6, config->host, &ip6addr.sin6_addr); int connect_result = connect(result->socket->channel, (struct sockaddr *) &ip6addr, sizeof(ip6addr)); if (connect_result == SOCKET_ERROR) { @@ -938,7 +975,9 @@ bool SocketConnect(SocketConfig *config, SocketResult *result) void SocketClose(Socket *sock) { if (sock != NULL) { - if (sock->channel != INVALID_SOCKET) { closesocket(sock->channel); } + if (sock->channel != INVALID_SOCKET) { + closesocket(sock->channel); + } } } @@ -960,7 +999,9 @@ void SocketClose(Socket *sock) // } Socket *SocketAccept(Socket *server, SocketConfig *config) { - if (!server->isServer || server->type == SOCKET_UDP) { return NULL; } + if (!server->isServer || server->type == SOCKET_UDP) { + return NULL; + } struct sockaddr_storage sock_addr; socklen_t sock_alen; Socket * sock; @@ -1025,10 +1066,14 @@ int SocketSetChannel(Socket *socket, int channel, const IPAddress *address) if (channel == -1) { for (channel = 0; channel < SOCKET_MAX_UDPCHANNELS; ++channel) { binding = &socket->binding[channel]; - if (binding->numbound < SOCKET_MAX_UDPADDRESSES) { break; } + if (binding->numbound < SOCKET_MAX_UDPADDRESSES) { + break; + } } } else { - if (!ValidChannel(channel)) { return (-1); } + if (!ValidChannel(channel)) { + return (-1); + } binding = &socket->binding[channel]; } if (binding->numbound == SOCKET_MAX_UDPADDRESSES) { @@ -1040,7 +1085,7 @@ int SocketSetChannel(Socket *socket, int channel, const IPAddress *address) } // Remove the socket channel -int SocketUnsetChannel(Socket *socket, int channel) +void SocketUnsetChannel(Socket *socket, int channel) { if ((channel >= 0) && (channel < SOCKET_MAX_UDPCHANNELS)) { socket->binding[channel].numbound = 0; @@ -1144,7 +1189,7 @@ int SocketSend(Socket *sock, const void *datap, int length) // 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 *sock, void *data, int maxlen, int timeout) +int SocketReceive(Socket *sock, void *data, int maxlen) { int len = 0; int numrecv = 0; @@ -1260,7 +1305,9 @@ bool IsSocketConnected(Socket *sock) } else if (total == 0) { // Timeout return false; } else { - if (FD_ISSET(sock->channel, &writefds)) { return true; } + if (FD_ISSET(sock->channel, &writefds)) { + return true; + } } return false; #else @@ -1287,7 +1334,9 @@ SocketResult *AllocSocketResult() void FreeSocketResult(SocketResult **result) { if (*result != NULL) { - if ((*result)->socket != NULL) { FreeSocket(&((*result)->socket)); } + if ((*result)->socket != NULL) { + FreeSocket(&((*result)->socket)); + } free(*result); *result = NULL; } @@ -1332,7 +1381,9 @@ SocketSet *AllocSocketSet(int max) set->maxsockets = max; set->sockets = (struct Socket **) malloc(max * sizeof(*set->sockets)); if (set->sockets != NULL) { - for (i = 0; i < max; ++i) { set->sockets[i] = NULL; } + for (i = 0; i < max; ++i) { + set->sockets[i] = NULL; + } } else { free(set); set = NULL; @@ -1375,7 +1426,9 @@ int RemoveSocket(SocketSet *set, Socket *sock) if (sock != NULL) { for (i = 0; i < set->numsockets; ++i) { - if (set->sockets[i] == (struct Socket *) sock) { break; } + if (set->sockets[i] == (struct Socket *) sock) { + break; + } } if (i == set->numsockets) { TraceLog(LOG_DEBUG, "Socket Error: %s", "Socket not found"); @@ -1473,9 +1526,32 @@ void FreePacket(Packet *packet) // Allocate an AddressInformation AddressInformation AllocAddress() { - AddressInformation addr; - addr = (AddressInformation) calloc(1, sizeof(*addr)); - return addr; + AddressInformation addressInfo = NULL; + addressInfo = (AddressInformation) calloc(1, sizeof(*addressInfo)); + if (addressInfo != NULL) { + addressInfo->addr.ai_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr)); + if (addressInfo->addr.ai_addr == NULL) { + TraceLog(LOG_WARNING, + "Failed to allocate memory for \"struct sockaddr\""); + } + } else { + TraceLog(LOG_WARNING, + "Failed to allocate memory for \"struct AddressInformation\""); + } + return addressInfo; +} + +// Free an AddressInformation struct +void FreeAddress(AddressInformation *addressInfo) +{ + if (*addressInfo != NULL) { + if ((*addressInfo)->addr.ai_addr != NULL) { + free((*addressInfo)->addr.ai_addr); + (*addressInfo)->addr.ai_addr = NULL; + } + free(*addressInfo); + *addressInfo = NULL; + } } // Allocate a list of AddressInformation