updated rnet api, fixed ping-pong example

This commit is contained in:
Jak Barnes 2019-03-16 00:48:42 +00:00
parent 22249b72cf
commit 38b77c7cc0
8 changed files with 353 additions and 278 deletions

View File

@ -27,50 +27,61 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
char recvBuffer[512]; float elapsed = 0.0f;
float elapsed = 0.0f; float delay = 1.0f;
float delay = 1.0f; bool ping = false;
bool ping = false; bool pong = false;
bool pong = false; bool connected = false;
bool connected = false; bool client_connected = false;
const char* pingmsg = "Ping!"; const char * pingmsg = "Ping!";
const char* pongmsg = "Pong!"; const char * pongmsg = "Pong!";
int msglen = 0; int msglen = 0;
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true}; SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .datagram = true, .server = true, .nonblocking = true};
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .nonblocking = true}; SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .datagram = true, .nonblocking = true};
SocketConfig connection_cfg = {.nonblocking = true}; SocketConfig connection_cfg = {.nonblocking = true};
SocketResult* server_res = NULL; SocketResult *server_res = NULL;
SocketResult* client_res = NULL; SocketResult *client_res = NULL;
SocketSet* socket_set = NULL; SocketSet * socket_set = NULL;
Socket* connection = NULL; Socket * connection = NULL;
char recvBuffer[512];
/*
** packshort() -- store a 16-bit int into a char buffer (like htons())
*/
void packshort(unsigned short s)
{
unsigned char* sptr = ((unsigned char*) &(s));
printf("before: %02X %02X\n", sptr[0], sptr[1]);
unsigned short ns = htons(s);
memcpy(packbuf + packlen, (unsigned char*) &(ns), sizeof(short));
printf("after: %02X %02X\n", (packbuf + packlen)[0], (packbuf + packlen)[1]);
packlen += sizeof(s);
}
// Attempt to connect to the network (Either TCP, or UDP)
void NetworkConnect() void NetworkConnect()
{ {
if (server_cfg.datagram) { // If the server is configured as UDP, ignore connection requests
if (server_cfg.datagram == true && client_cfg.datagram == true) {
ping = true; ping = true;
connected = true; connected = true;
} else { } else {
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) { // If the client is connected, run the server code to check for a connection
AddSocket(socket_set, connection); if (client_connected) {
ping = true; int active = CheckSockets(socket_set, 0);
connected = true; if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
if (active > 0) {
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
AddSocket(socket_set, connection);
ping = true;
connected = true;
}
}
} else {
// Check if we're connected every _delay_ seconds
elapsed += GetFrameTime();
if (elapsed > delay) {
if (IsSocketConnected(client_res->socket)) {
client_connected = true;
}
elapsed = 0.0f;
}
} }
} }
} }
// Once connected to the network, check the sockets for pending information
// and when information is ready, send either a Ping or a Pong.
void NetworkUpdate() void NetworkUpdate()
{ {
int active = CheckSockets(socket_set, 0); int active = CheckSockets(socket_set, 0);
@ -81,7 +92,7 @@ void NetworkUpdate()
int bytesRecv = 0; int bytesRecv = 0;
if (server_cfg.datagram) { if (server_cfg.datagram) {
if (IsSocketReady(server_res->socket)) { if (IsSocketReady(client_res->socket)) {
bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0); bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0);
} }
} else { } else {
@ -106,10 +117,6 @@ void NetworkUpdate()
elapsed = 0.0f; elapsed = 0.0f;
} }
} }
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
int main() int main()
{ {
@ -122,23 +129,54 @@ int main()
SetTraceLogLevel(LOG_DEBUG); SetTraceLogLevel(LOG_DEBUG);
// Networking // Networking
InitNetwork(); InitNetwork();
// Create the server // Create the server
//
// Performs
// getaddrinfo
// socket
// setsockopt
// bind
// listen
server_res = AllocSocketResult(); server_res = AllocSocketResult();
if (!SocketOpen(&server_cfg, server_res)) { if (!SocketCreate(&server_cfg, server_res)) {
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d\n", TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
server_res->status, server_res->socket->status); server_res->status, server_res->socket->status);
} else {
if (!SocketBind(&server_cfg, server_res)) {
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
server_res->status, server_res->socket->status);
} else {
if (!SocketListen(&server_cfg, server_res)) {
TraceLog(LOG_WARNING,
"Failed to start listen server: status %d, errno %d",
server_res->status, server_res->socket->status);
}
}
} }
// Create the client // Create the client
//
// Performs
// getaddrinfo
// socket
// setsockopt
// connect
client_res = AllocSocketResult(); client_res = AllocSocketResult();
if (!SocketOpen(&client_cfg, client_res)) { if (!SocketCreate(&client_cfg, client_res)) {
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d\n", TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
client_res->status, client_res->socket->status); client_res->status, client_res->socket->status);
} else {
if (!SocketConnect(&client_cfg, client_res)) {
TraceLog(LOG_WARNING,
"Failed to connect to server: status %d, errno %d",
client_res->status, client_res->socket->status);
}
} }
socket_set = CreateSocketSet(3); // Create & Add sockets to the socket set
socket_set = AllocSocketSet(3);
msglen = strlen(pingmsg) + 1; msglen = strlen(pingmsg) + 1;
memset(recvBuffer, '\0', sizeof(recvBuffer)); memset(recvBuffer, '\0', sizeof(recvBuffer));
AddSocket(socket_set, server_res->socket); AddSocket(socket_set, server_res->socket);

View File

@ -67,24 +67,35 @@ void test_resolve_ip()
void test_resolve_host() void test_resolve_host()
{ {
const char * address = "localhost"; const char * address = "localhost";
const char * port = "80"; const char * port = "80";
struct _AddressInformation **addr = AllocAddressList(3); AddressInformation *addr = AllocAddressList(3);
int count = ResolveHost(address, port, addr); int count = ResolveHost(address, port, addr);
assert(GetAddressFamily(addr[0]) == ADDRESS_TYPE_IPV6); assert(GetAddressFamily(addr[0]) == ADDRESS_TYPE_IPV6);
assert(GetAddressFamily(addr[1]) == ADDRESS_TYPE_IPV4); 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() void test_address()
{ {
} }
void test_address_list() void test_address_list()
{ {
}
} void test_socket_create()
{
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true};
Socket * socket = AllocSocket();
SocketResult *server_res = AllocSocketResult();
SocketSet * socket_set = AllocSocketSet(1);
assert(SocketCreate(&server_cfg, server_res));
assert(AddSocket(socket_set, server_res->socket));
assert(SocketListen(&server_cfg, server_res));
}
int main() int main()
{ {
@ -96,10 +107,8 @@ int main()
// Run the tests // Run the tests
test_network_initialise(); test_network_initialise();
// test_socket_result(); // test_resolve_host();
// test_socket(); test_socket_create();
// test_resolve_ip();
test_resolve_host();
// Main game loop // Main game loop
while (!WindowShouldClose()) { while (!WindowShouldClose()) {

View File

@ -1,24 +1,3 @@
/*******************************************************************************************
*
* raylib [core] example - Basic window
*
* 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 1.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 "raylib.h"
int main() int main()

View File

@ -1,24 +1,3 @@
/*******************************************************************************************
*
* raylib [core] example - Basic window
*
* 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 1.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 "raylib.h"
int main() int main()
@ -29,9 +8,13 @@ int main()
screenWidth, screenHeight, "raylib [core] example - basic window"); screenWidth, screenHeight, "raylib [core] example - basic window");
SetTargetFPS(60); SetTargetFPS(60);
// Initialise networking
InitNetwork();
//
// Main game loop // Main game loop
while (!WindowShouldClose()) while (!WindowShouldClose()) {
{
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);

View File

@ -185,7 +185,7 @@
<ClInclude Include="..\..\..\src\raylib.h" /> <ClInclude Include="..\..\..\src\raylib.h" />
<ClInclude Include="..\..\..\src\raymath.h" /> <ClInclude Include="..\..\..\src\raymath.h" />
<ClInclude Include="..\..\..\src\rlgl.h" /> <ClInclude Include="..\..\..\src\rlgl.h" />
<ClInclude Include="..\..\..\src\sysnet.h" /> <ClInclude Include="..\..\..\src\rnet.h" />
<ClInclude Include="..\..\..\src\utils.h" /> <ClInclude Include="..\..\..\src\utils.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -455,10 +455,17 @@ typedef struct VrStereoConfig {
// IPAddress definition (in network byte order) // IPAddress definition (in network byte order)
typedef struct IPAddress { typedef struct IPv4Address {
unsigned long host; /* 32-bit IPv4 host address */ unsigned long host; /* 32-bit IPv4 host address */
unsigned short port; /* 16-bit protocol port */ unsigned short port; /* 16-bit protocol port */
} IPAddress; } IPv4Address;
typedef struct IPv6Address {
union {
uint8_t byte[16];
uint16_t word[8];
} u;
};
// An option ID, value, sizeof(value) tuple for setsockopt(2). // An option ID, value, sizeof(value) tuple for setsockopt(2).
typedef struct SocketOpt { typedef struct SocketOpt {
@ -474,7 +481,7 @@ typedef enum {
typedef struct UDPChannel { typedef struct UDPChannel {
int numbound; // The total number of addresses this channel is bound to int numbound; // The total number of addresses this channel is bound to
IPAddress address[SOCKET_MAX_UDPADDRESSES]; // The list of remote addresses this channel is bound to IPv4Address address[SOCKET_MAX_UDPADDRESSES]; // The list of remote addresses this channel is bound to
} UDPChannel; } UDPChannel;
typedef struct Socket { typedef struct Socket {
@ -483,7 +490,7 @@ typedef struct Socket {
bool isServer; // Is this socket a server socket (i.e. TCP/UDP Listen Server) bool isServer; // Is this socket a server socket (i.e. TCP/UDP Listen Server)
SocketChannel channel; // The socket handle id SocketChannel channel; // The socket handle id
SocketType type; // Is this socket a TCP or UDP socket? SocketType type; // Is this socket a TCP or UDP socket?
IPAddress address; // The host/target ip for this socket (in network byte order) IPv4Address address; // The host/target ip for this socket (in network byte order)
struct UDPChannel bindings[SOCKET_MAX_UDPCHANNELS]; // The amount of channels (if UDP) this socket is bound to struct UDPChannel bindings[SOCKET_MAX_UDPCHANNELS]; // The amount of channels (if UDP) this socket is bound to
} Socket; } Socket;
@ -499,19 +506,18 @@ typedef struct SocketDataPacket {
int len; /* The length of the packet data */ int len; /* The length of the packet data */
int maxlen; /* The size of the data buffer */ int maxlen; /* The size of the data buffer */
int status; /* packet status after sending */ int status; /* packet status after sending */
IPAddress address; /* The source/dest address of an incoming/outgoing packet */ IPv4Address address; /* The source/dest address of an incoming/outgoing packet */
} SocketDataPacket; } SocketDataPacket;
// Configuration for a socket. Not all of these fields need to // Configuration for a socket. Not all of these fields need to
// be set, and ones omitted from a C99-style "designated initializer" // be set, and ones omitted from a C99-style "designated initializer"
// struct literal will be zeroed out and replaced with defaults. // struct literal will be zeroed out and replaced with defaults.
typedef struct SocketConfig { typedef struct SocketConfig {
// Hostname and port, for TCP or UDP sockets. */
char * host; // The host address in xxx.xxx.xxx.xxx form char * host; // The host address in xxx.xxx.xxx.xxx form
char * port; // The target port/server in the form "http" or "25565" char * port; // The target port/server in the form "http" or "25565"
bool server; // Listen for incoming clients? bool server; // Listen for incoming clients?
bool datagram; // TCP or UDP? bool datagram; // TCP or UDP?
bool nonblocking; // non-blocking operation? bool nonblocking; // non-blocking operation?
int backlog_size; // set a custom backlog size int backlog_size; // set a custom backlog size
SocketOpt sockopts[SOCKET_MAX_SOCK_OPTS]; SocketOpt sockopts[SOCKET_MAX_SOCK_OPTS];
} SocketConfig; } SocketConfig;
@ -1510,30 +1516,31 @@ RLAPI int GetAddressFamily();
RLAPI int GetAddressSocketType(AddressInformation address); RLAPI int GetAddressSocketType(AddressInformation address);
RLAPI int GetAddressProtocol(AddressInformation address); RLAPI int GetAddressProtocol(AddressInformation address);
RLAPI void PrintAddressInfo(AddressInformation address); RLAPI void PrintAddressInfo(AddressInformation address);
RLAPI AddressInformation AllocAddress(); RLAPI AddressInformation AllocAddress();
RLAPI struct _AddressInformation **AllocAddressList(int size); RLAPI AddressInformation* AllocAddressList(int size);
// Socket API // Socket API
RLAPI bool SocketCreate(SocketConfig *cfg, SocketResult *res); RLAPI bool SocketCreate(SocketConfig *cfg, SocketResult *res);
RLAPI void SocketClose(SocketChannel socket); RLAPI bool SocketBind(SocketConfig *cfg, SocketResult *res);
RLAPI bool SocketListen(SocketConfig *cfg, SocketResult *res); RLAPI bool SocketListen(SocketConfig *cfg, SocketResult *res);
RLAPI bool SocketConnect(SocketConfig *cfg, SocketResult *res); RLAPI bool SocketConnect(SocketConfig *cfg, SocketResult *res);
RLAPI Socket *SocketAccept(Socket *server, SocketConfig *cfg); RLAPI Socket *SocketAccept(Socket *server, SocketConfig *cfg);
RLAPI int SocketSend(Socket *socket, const void *datap, int len); RLAPI int SocketSend(Socket *socket, const void *datap, int len);
RLAPI int SocketReceive(Socket *socket, void *data, int maxlen, int timeout); RLAPI int SocketReceive(Socket *socket, void *data, int maxlen, int timeout);
RLAPI void SocketClose(SocketChannel socket);
RLAPI Socket *AllocSocket(); RLAPI Socket *AllocSocket();
RLAPI void FreeSocket(Socket **sock);
RLAPI SocketResult *AllocSocketResult(); RLAPI SocketResult *AllocSocketResult();
RLAPI void FreeSocket(Socket **sock); RLAPI void FreeSocketResult(SocketResult **result);
RLAPI void FreeSocketResult(SocketResult **result); RLAPI SocketSet *AllocSocketSet(int max);
RLAPI void FreeSocketSet(SocketSet *sockset);
// Socket I/O API // Socket I/O API
RLAPI bool IsSocketReady(Socket *sock); RLAPI bool IsSocketReady(Socket *sock);
RLAPI SocketSet *AllocSocketSet(int max); RLAPI bool IsSocketConnected(Socket *sock);
RLAPI void FreeSocketSet(SocketSet *sockset); RLAPI int AddSocket(SocketSet *set, Socket *sock);
RLAPI int AddSocket(SocketSet *set, Socket *sock); RLAPI int RemoveSocket(SocketSet *set, Socket *sock);
RLAPI int RemoveSocket(SocketSet *set, Socket *sock); RLAPI int CheckSockets(SocketSet *set, unsigned int timeout);
RLAPI int CheckSockets(SocketSet *set, unsigned int timeout);
// Packet API // Packet API
Packet * AllocPacket(int size); Packet * AllocPacket(int size);

View File

@ -39,16 +39,9 @@
// Check if config flags have been externally provided on compilation line // Check if config flags have been externally provided on compilation line
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(RNET_STANDALONE) #include "rnet.h"
# include "rnet.h"
# include <stdarg.h> #include "raylib.h"
#else
# include "raylib.h"
# include "rnet.h"
# if !defined(EXTERNAL_CONFIG_FLAGS)
# include "config.h" // Defines module configuration flags
# endif
#endif
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread() #include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
#include <stdlib.h> // Required for: malloc(), free() #include <stdlib.h> // Required for: malloc(), free()
@ -57,6 +50,7 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module defines // Module defines
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define NET_SOCKET_BACKLOG_SIZE (20) #define NET_SOCKET_BACKLOG_SIZE (20)
#define NET_MAXHOST (1025) // Max size of a fully-qualified domain name #define NET_MAXHOST (1025) // Max size of a fully-qualified domain name
#define NET_MAXSERV (32) // Max size of a service name #define NET_MAXSERV (32) // Max size of a service name
@ -66,35 +60,21 @@
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if PLATFORM == PLATFORM_WINDOWS typedef struct _SocketAddress {
typedef socklen_t _SocketLength; struct sockaddr address;
typedef SOCKADDR _SocketAddress; } _SocketAddress;
typedef SOCKADDR_IN _SocketAddressIPv4; typedef struct _SocketAddressIPv4 {
typedef SOCKADDR_IN6 _SocketAddressIPv6; struct sockaddr_in address;
typedef SOCKADDR_STORAGE _SocketAddressStorage; } _SocketAddressIPv4;
typedef struct _SocketAddressIPv6 {
struct sockaddr_in6 address;
} _SocketAddressIPv6;
typedef struct _SocketAddressStorage {
struct sockaddr_storage address;
} _SocketAddressStorage;
typedef struct _AddressInformation { typedef struct _AddressInformation {
int ai_flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST struct addrinfo addr;
int ai_family; // PF_xxx
int ai_socktype; // SOCK_xxx
int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
size_t ai_addrlen; // Length of ai_addr
struct sockaddr_storage ai_addr; // Binary address
} _AddressInformation; } _AddressInformation;
#else
#endif
#if defined(RNET_STANDALONE)
typedef enum {
LOG_ALL,
LOG_TRACE,
LOG_DEBUG,
LOG_INFO,
LOG_WARNING,
LOG_ERROR,
LOG_FATAL,
LOG_NONE
} TraceLogType;
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global module forward declarations // Global module forward declarations
@ -120,11 +100,18 @@ static char *SocketAddressToString(struct sockaddr_storage *sockaddr, char buffe
static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol); static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol);
static bool FillIPv4SockAddress(struct sockaddr_in *sa, const char *host, unsigned short port); static bool FillIPv4SockAddress(struct sockaddr_in *sa, const char *host, unsigned short port);
static bool FillIPv6SockAddress(struct sockaddr_in6 *sa, const char *host, unsigned short port); static bool FillIPv6SockAddress(struct sockaddr_in6 *sa, const char *host, unsigned short port);
static void PrintSocket(AddressInformation addr);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global module implementationd // Global module implementationd
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static void PrintAddressInfo(AddressInformation addr)
{
PrintSocket(&addr->addr.ai_addr, addr->addr.ai_family, addr->addr.ai_socktype,
addr->addr.ai_protocol);
}
// //
static bool FillIPv4SockAddress(struct sockaddr_in *sa, const char *host, unsigned short port) static bool FillIPv4SockAddress(struct sockaddr_in *sa, const char *host, unsigned short port)
{ {
@ -226,7 +213,7 @@ static char *SocketAddressToString(struct sockaddr_storage *sockaddr)
} }
} }
// // Check if the null terminated string ip is a valid IPv4 address
static bool IsIPv4Address(const char *ip) static bool IsIPv4Address(const char *ip)
{ {
struct sockaddr_in sa; struct sockaddr_in sa;
@ -234,7 +221,7 @@ static bool IsIPv4Address(const char *ip)
return result != 0; return result != 0;
} }
// // Check if the null terminated string ip is a valid IPv6 address
static bool IsIPv6Address(const char *ip) static bool IsIPv6Address(const char *ip)
{ {
struct sockaddr_in6 sa; struct sockaddr_in6 sa;
@ -328,7 +315,7 @@ static bool InitSocket(Socket *sock, struct addrinfo *addr)
return IsSocketValid(sock); return IsSocketValid(sock);
} }
// CreateSocket() - Interally called by OpenSocket() // CreateSocket() - Interally called by CreateSocket()
// //
// This here is the bread and butter of the socket API, This function will // 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 // attempt to open a socket, bind and listen to it based on the config passed in
@ -446,7 +433,7 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
return success; return success;
} }
// // Set the state of the Socket sock to blocking
static bool SocketSetBlocking(Socket *sock) static bool SocketSetBlocking(Socket *sock)
{ {
bool ret = true; bool ret = true;
@ -465,7 +452,7 @@ static bool SocketSetBlocking(Socket *sock)
return ret; return ret;
} }
// // Set the state of the Socket sock to non-blocking
static bool SocketSetNonBlocking(Socket *sock) static bool SocketSetNonBlocking(Socket *sock)
{ {
bool ret = true; bool ret = true;
@ -483,7 +470,7 @@ static bool SocketSetNonBlocking(Socket *sock)
return ret; return ret;
} }
// // Set options specified in SocketConfig to Socket sock
static bool SocketSetOptions(SocketConfig *config, Socket *sock) static bool SocketSetOptions(SocketConfig *config, Socket *sock)
{ {
for (int i = 0; i < SOCKET_MAX_SOCK_OPTS; i++) { for (int i = 0; i < SOCKET_MAX_SOCK_OPTS; i++) {
@ -654,7 +641,7 @@ void ResolveIP(const char *ip, const char *port, int flags, char *host, char *se
// returns: // returns:
// the total amount of addresses found // the total amount of addresses found
// //
int ResolveHost(const char *address, const char *port, AddressInformation *outAddrList) int ResolveHost(const char *address, const char *port, AddressInformation *addrlist)
{ {
// Variables // Variables
int status; // Status value to return (0) is success int status; // Status value to return (0) is success
@ -698,14 +685,14 @@ int ResolveHost(const char *address, const char *port, AddressInformation *outAd
} }
// Dynamically allocate an array of address information structs // Dynamically allocate an array of address information structs
if (outAddrList != NULL) { if (addrlist != NULL) {
int i; int i;
for (i = 0; i < size; ++i) { for (i = 0; i < size; ++i) {
outAddrList[i] = AllocAddress(); addrlist[i] = AllocAddress();
if (outAddrList[i] == NULL) { break; } if (addrlist[i] == NULL) { break; }
} }
outAddrList[i] = NULL; addrlist[i] = NULL;
if (i != size) { outAddrList = NULL; } if (i != size) { addrlist = NULL; }
} else { } else {
TraceLog(LOG_WARNING, TraceLog(LOG_WARNING,
"Error, failed to dynamically allocate memory for the address list"); "Error, failed to dynamically allocate memory for the address list");
@ -715,20 +702,20 @@ int ResolveHost(const char *address, const char *port, AddressInformation *outAd
int i = 0; int i = 0;
for (iterator = res; iterator != NULL; iterator = iterator->ai_next) { for (iterator = res; iterator != NULL; iterator = iterator->ai_next) {
if (i < size) { if (i < size) {
outAddrList[i]->ai_flags = iterator->ai_flags; addrlist[i]->addr.ai_flags = iterator->ai_flags;
outAddrList[i]->ai_family = iterator->ai_family; addrlist[i]->addr.ai_family = iterator->ai_family;
outAddrList[i]->ai_socktype = iterator->ai_socktype; addrlist[i]->addr.ai_socktype = iterator->ai_socktype;
outAddrList[i]->ai_protocol = iterator->ai_protocol; addrlist[i]->addr.ai_protocol = iterator->ai_protocol;
outAddrList[i]->ai_addrlen = iterator->ai_addrlen; addrlist[i]->addr.ai_addrlen = iterator->ai_addrlen;
memcpy(&outAddrList[i]->ai_addr, iterator->ai_addr, iterator->ai_addrlen); memcpy(&addrlist[i]->addr.ai_addr, iterator->ai_addr, iterator->ai_addrlen);
#if NET_DEBUG_ENABLED #if NET_DEBUG_ENABLED
TraceLog(LOG_DEBUG, "GetAddressInformation"); TraceLog(LOG_DEBUG, "GetAddressInformation");
TraceLog(LOG_DEBUG, "\tFlags: 0x%x", iterator->ai_flags); TraceLog(LOG_DEBUG, "\tFlags: 0x%x", iterator->ai_flags);
PrintSocket(&outAddrList[i]->ai_addr, PrintSocket(&addrlist[i]->addr.ai_addr,
outAddrList[i]->ai_family, addrlist[i]->addr.ai_family,
outAddrList[i]->ai_socktype, addrlist[i]->addr.ai_socktype,
outAddrList[i]->ai_protocol); addrlist[i]->addr.ai_protocol);
TraceLog(LOG_DEBUG, "Length of this sockaddr: %d", outAddrList[i]->ai_addrlen); TraceLog(LOG_DEBUG, "Length of this sockaddr: %d", addrlist[i]->addr.ai_addrlen);
TraceLog(LOG_DEBUG, "Canonical name: %s", iterator->ai_canonname); TraceLog(LOG_DEBUG, "Canonical name: %s", iterator->ai_canonname);
#endif #endif
i++; i++;
@ -783,54 +770,91 @@ bool SocketCreate(SocketConfig *config, SocketResult *result)
return success; return success;
} }
// // Bind a socket to a local address
bool SocketListen(SocketConfig *config, SocketResult *result) // Note: The bind function is required on an unconnected socket before subsequent calls to the listen function.
bool SocketBind(SocketConfig *config, SocketResult *result)
{ {
bool success = true; bool success = false;
result->status = RESULT_FAILURE; result->status = RESULT_FAILURE;
// Only bind to sockets marked as server // Don't bind to a socket that isn't configured as a server
if (config->server) { if (!IsSocketValid(result->socket) || !config->server) {
// The sockaddr_in structure specifies the address family, TraceLog(LOG_WARNING,
// IP address, and port of the server to be connected to. "Cannot bind to socket marked as \"Client\" in SocketConfig.");
struct sockaddr_in clientService; success = false;
clientService.sin_family = AF_INET; } else {
clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); if (IsIPv4Address(config->host)) {
clientService.sin_port = htons(8080); struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
// Attempt to bind the socket ip4addr.sin_port = config->port;
if (bind(result->socket->channel, (SOCKADDR *) &clientService, sizeof(clientService)) != SOCKET_ERROR) { inet_pton(AF_INET, config->host, &ip4addr.sin_addr);
TraceLog(LOG_INFO, "Successfully bound socket."); if (bind(result->socket->channel, (struct sockaddr *) &ip4addr, sizeof(ip4addr)) != SOCKET_ERROR) {
} else { TraceLog(LOG_INFO, "Successfully bound socket.");
result->socket->status = SocketGetLastError();
TraceLog(LOG_WARNING, "Socket Error: %s",
SocketErrorCodeToString(result->socket->status));
SocketSetLastError(0);
success = false;
}
// Don't listen on UDP sockets
if (!config->datagram) {
if (listen(result->socket->channel, config->backlog_size) != 0) {
success = false;
} else {
TraceLog(LOG_INFO, "Started listening on socket...");
success = true; success = true;
} else {
result->socket->status = SocketGetLastError();
TraceLog(LOG_WARNING, "Socket Error: %s",
SocketErrorCodeToString(result->socket->status));
SocketSetLastError(0);
success = false;
}
} else {
if (IsIPv6Address(config->host)) {
struct sockaddr_in6 ip6addr;
ip6addr.sin6_family = AF_INET6;
ip6addr.sin6_port = config->port;
inet_pton(AF_INET6, config->host, &ip6addr.sin6_addr);
if (bind(result->socket->channel, (struct sockaddr *) &ip6addr, sizeof(ip6addr)) != SOCKET_ERROR) {
TraceLog(LOG_INFO, "Successfully bound socket.");
success = true;
} else {
result->socket->status = SocketGetLastError();
TraceLog(LOG_WARNING, "Socket Error: %s",
SocketErrorCodeToString(result->socket->status));
SocketSetLastError(0);
success = false;
}
} }
} }
} else {
TraceLog(LOG_WARNING,
"Cannot listen on socket marked as \"Client\" in SocketConfig.");
success = false;
} }
// Was the bind a success?
if (success) { if (success) {
result->status = RESULT_SUCCESS; result->status = RESULT_SUCCESS;
result->socket->ready = 0; result->socket->ready = 0;
result->socket->status = 0; result->socket->status = 0;
} }
return success;
}
// Listens (and queues) incoming connections requests for a bound port.
bool SocketListen(SocketConfig *config, SocketResult *result)
{
bool success = false;
result->status = RESULT_FAILURE;
// Don't bind to a socket that isn't configured as a server
if (!IsSocketValid(result->socket) || !config->server) {
TraceLog(LOG_WARNING,
"Cannot listen on socket marked as \"Client\" in SocketConfig.");
success = false;
} else {
// Don't listen on UDP sockets
if (!config->datagram) {
if (listen(result->socket->channel, config->backlog_size) != SOCKET_ERROR) {
TraceLog(LOG_INFO, "Started listening on socket...");
success = true;
} else {
success = false;
}
}
}
// Was the listen a success?
if (success) {
result->status = RESULT_SUCCESS;
result->socket->ready = 0;
result->socket->status = 0;
}
return success; return success;
} }
@ -846,23 +870,58 @@ bool SocketConnect(SocketConfig *config, SocketResult *result)
"Cannot connect to socket marked as \"Server\" in SocketConfig."); "Cannot connect to socket marked as \"Server\" in SocketConfig.");
success = false; success = false;
} else { } else {
// The sockaddr_in structure specifies the address family, if (IsIPv4Address(config->host)) {
// IP address, and port of the server to be connected to. struct sockaddr_in ip4addr;
struct sockaddr_in clientService; ip4addr.sin_family = AF_INET;
clientService.sin_family = AF_INET; ip4addr.sin_port = config->port;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); inet_pton(AF_INET, config->host, &ip4addr.sin_addr);
clientService.sin_port = htons(8080); int connect_result = connect(result->socket->channel, (struct sockaddr *) &ip4addr, sizeof(ip4addr));
if (connect_result == SOCKET_ERROR) {
// Did we connect successfully? result->socket->status = SocketGetLastError();
if (connect(result->socket->channel, (SOCKADDR *) &clientService, sizeof(clientService)) != SOCKET_ERROR) { SocketSetLastError(0);
TraceLog(LOG_INFO, "Successfully connected to socket."); switch (result->socket->status) {
case WSAEWOULDBLOCK: {
success = true;
break;
}
default: {
TraceLog(LOG_WARNING, "Socket Error: %s",
SocketErrorCodeToString(result->socket->status));
success = false;
break;
}
}
} else {
TraceLog(LOG_INFO, "Successfully connected to socket.");
success = true;
}
} else { } else {
result->socket->status = SocketGetLastError(); if (IsIPv6Address(config->host)) {
TraceLog(LOG_WARNING, struct sockaddr_in6 ip6addr;
"Socket Error: %s", ip6addr.sin6_family = AF_INET6;
SocketErrorCodeToString(result->socket->status)); ip6addr.sin6_port = config->port;
SocketSetLastError(0); inet_pton(AF_INET6, config->host, &ip6addr.sin6_addr);
success = false; int connect_result = connect(result->socket->channel, (struct sockaddr *) &ip6addr, sizeof(ip6addr));
if (connect_result == SOCKET_ERROR) {
result->socket->status = SocketGetLastError();
SocketSetLastError(0);
switch (result->socket->status) {
case WSAEWOULDBLOCK: {
success = true;
break;
}
default: {
TraceLog(LOG_WARNING, "Socket Error: %s",
SocketErrorCodeToString(result->socket->status));
success = false;
break;
}
}
} else {
TraceLog(LOG_INFO, "Successfully connected to socket.");
success = true;
}
}
} }
} }
@ -1082,7 +1141,32 @@ bool IsSocketReady(Socket *sock)
return (sock != NULL) && (sock->ready); return (sock != NULL) && (sock->ready);
} }
// bool IsSocketConnected(Socket *sock)
{
#if PLATFORM_WINDOWS
FD_SET writefds;
FD_ZERO(&writefds);
FD_SET(sock->channel, &writefds);
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 1000000000UL;
int total = select(0, NULL, &writefds, NULL, &timeout);
if (total == -1) { // Error
sock->status = SocketGetLastError();
TraceLog(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status));
SocketSetLastError(0);
} else if (total == 0) { // Timeout
return false;
} else {
if (FD_ISSET(sock->channel, &writefds)) { return true; }
}
return false;
#else
return true;
#endif
}
// Allocate and return a SocketResult struct
SocketResult *AllocSocketResult() SocketResult *AllocSocketResult()
{ {
struct SocketResult *res; struct SocketResult *res;
@ -1097,7 +1181,7 @@ SocketResult *AllocSocketResult()
return res; return res;
} }
// // Free an allocated SocketResult
void FreeSocketResult(SocketResult **result) void FreeSocketResult(SocketResult **result)
{ {
if (*result != NULL) { if (*result != NULL) {
@ -1107,13 +1191,13 @@ void FreeSocketResult(SocketResult **result)
} }
} }
// // Allocate a Socket
Socket *AllocSocket() Socket *AllocSocket()
{ {
// Allocate a socket if one already hasn't been // Allocate a socket if one already hasn't been
struct Socket *sock; struct Socket *sock;
sock = (Socket *) malloc(sizeof(*sock)); sock = (Socket *) malloc(sizeof(*sock));
if (socket != NULL) { if (sock != NULL) {
memset(sock, 0, sizeof(*sock)); memset(sock, 0, sizeof(*sock));
} else { } else {
TraceLog( TraceLog(
@ -1125,7 +1209,7 @@ Socket *AllocSocket()
return sock; return sock;
} }
// // Free an allocated Socket
void FreeSocket(Socket **sock) void FreeSocket(Socket **sock)
{ {
if (*sock != NULL) { if (*sock != NULL) {
@ -1134,7 +1218,7 @@ void FreeSocket(Socket **sock)
} }
} }
// // Allocate a SocketSet
SocketSet *AllocSocketSet(int max) SocketSet *AllocSocketSet(int max)
{ {
struct SocketSet *set; struct SocketSet *set;
@ -1155,7 +1239,7 @@ SocketSet *AllocSocketSet(int max)
return (set); return (set);
} }
// // Free an allocated SocketSet
void FreeSocketSet(SocketSet *set) void FreeSocketSet(SocketSet *set)
{ {
if (set) { if (set) {
@ -1164,7 +1248,7 @@ void FreeSocketSet(SocketSet *set)
} }
} }
// // Add a Socket "sock" to the SocketSet "set"
int AddSocket(SocketSet *set, Socket *sock) int AddSocket(SocketSet *set, Socket *sock)
{ {
if (sock != NULL) { if (sock != NULL) {
@ -1182,7 +1266,7 @@ int AddSocket(SocketSet *set, Socket *sock)
return (set->numsockets); return (set->numsockets);
} }
// // Remove a Socket "sock" to the SocketSet "set"
int RemoveSocket(SocketSet *set, Socket *sock) int RemoveSocket(SocketSet *set, Socket *sock)
{ {
int i; int i;
@ -1204,7 +1288,7 @@ int RemoveSocket(SocketSet *set, Socket *sock)
return (set->numsockets); return (set->numsockets);
} }
// // Check the sockets in the socket set for pending information
int CheckSockets(SocketSet *set, unsigned int timeout) int CheckSockets(SocketSet *set, unsigned int timeout)
{ {
int i; int i;
@ -1248,7 +1332,7 @@ int CheckSockets(SocketSet *set, unsigned int timeout)
return (retval); return (retval);
} }
// // Allocate a Packet
Packet *AllocPacket(int size) Packet *AllocPacket(int size)
{ {
struct Packet *packet; struct Packet *packet;
@ -1271,7 +1355,7 @@ Packet *AllocPacket(int size)
return packet; return packet;
} }
// // Free an allocated Packet
void FreePacket(Packet *packet) void FreePacket(Packet *packet)
{ {
if (packet != NULL) { if (packet != NULL) {
@ -1284,7 +1368,7 @@ void FreePacket(Packet *packet)
} }
} }
// // Allocate an AddressInformation
AddressInformation AllocAddress() AddressInformation AllocAddress()
{ {
AddressInformation addr; AddressInformation addr;
@ -1292,7 +1376,7 @@ AddressInformation AllocAddress()
return addr; return addr;
} }
// // Allocate a list of AddressInformation
AddressInformation *AllocAddressList(int size) AddressInformation *AllocAddressList(int size)
{ {
AddressInformation *addr; AddressInformation *addr;
@ -1300,25 +1384,22 @@ AddressInformation *AllocAddressList(int size)
return addr; return addr;
} }
// Opaque datatype accessor addrinfo->ai_socktype
int GetAddressSocketType(AddressInformation address) int GetAddressSocketType(AddressInformation address)
{ {
return address->ai_socktype; return address->addr.ai_socktype;
} }
// Opaque datatype accessor addrinfo->ai_protocol
int GetAddressProtocol(AddressInformation address) int GetAddressProtocol(AddressInformation address)
{ {
return address->ai_protocol; return address->addr.ai_protocol;
} }
// Opaque datatype accessor addrinfo->ai_family
int GetAddressFamily(AddressInformation address) int GetAddressFamily(AddressInformation address)
{ {
return address->ai_family; return address->addr.ai_family;
}
//
void PrintAddressInfo(AddressInformation addr)
{
PrintSocket(&addr->ai_addr, addr->ai_family, addr->ai_socktype, addr->ai_protocol);
} }
// //

View File

@ -88,7 +88,6 @@
#define NOPROFILER // Profiler interface. #define NOPROFILER // Profiler interface.
#define NODEFERWINDOWPOS // DeferWindowPos routines #define NODEFERWINDOWPOS // DeferWindowPos routines
#define NOMCX // Modem Configuration Extensions #define NOMCX // Modem Configuration Extensions
#define MMNOSOUND #define MMNOSOUND
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -170,14 +169,6 @@ typedef long int int64;
# define ssize_t size_t # define ssize_t size_t
#endif // WIN32 #endif // WIN32
#ifndef TRUE
# define TRUE 1
#endif // TRUE
#ifndef FALSE
# define FALSE 0
#endif // FALSE
#ifndef RESULT_SUCCESS #ifndef RESULT_SUCCESS
# define RESULT_SUCCESS 0 # define RESULT_SUCCESS 0
#endif // RESULT_SUCCESS #endif // RESULT_SUCCESS
@ -186,19 +177,6 @@ typedef long int int64;
# define RESULT_FAILURE 1 # define RESULT_FAILURE 1
#endif // RESULT_FAILURE #endif // RESULT_FAILURE
#ifndef INADDR_ANY
# define INADDR_ANY 0x00000000
#endif // INADDR_ANY
#ifndef INADDR_NONE
# define INADDR_NONE 0xFFFFFFFF
#endif // INADDR_NONE
#ifndef INADDR_LOOPBACK
# define INADDR_LOOPBACK 0x7f000001
#endif // INADDR_LOOPBACK
#ifndef INADDR_BROADCAST
# define INADDR_BROADCAST 0xFFFFFFFF
#endif // INADDR_BROADCAST
#ifndef htonll #ifndef htonll
# ifdef _BIG_ENDIAN # ifdef _BIG_ENDIAN
# define htonll(x) (x) # define htonll(x) (x)