fixed tcp_client

fixed tcp_server
fixed ping_pong
udp support still broken >:(
This commit is contained in:
Jak Barnes 2019-03-16 16:48:15 +00:00
parent 38b77c7cc0
commit 0ea6d1543d
8 changed files with 785 additions and 511 deletions

View File

@ -27,29 +27,29 @@
#include <stdio.h>
#include <string.h>
float elapsed = 0.0f;
float delay = 1.0f;
bool ping = false;
bool pong = false;
bool connected = false;
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", .datagram = true, .server = true, .nonblocking = true};
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .datagram = true, .nonblocking = true};
SocketConfig connection_cfg = {.nonblocking = true};
SocketResult *server_res = NULL;
SocketResult *client_res = NULL;
SocketSet * socket_set = NULL;
Socket * connection = NULL;
float elapsed = 0.0f;
float delay = 1.0f;
bool ping = false;
bool pong = false;
bool connected = false;
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 connection_cfg = {.nonblocking = true};
SocketResult *server_res = NULL;
SocketResult *client_res = NULL;
SocketSet * socket_set = NULL;
Socket * connection = NULL;
char recvBuffer[512];
// Attempt to connect to the network (Either TCP, or UDP)
void NetworkConnect()
{
// If the server is configured as UDP, ignore connection requests
if (server_cfg.datagram == true && client_cfg.datagram == true) {
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
ping = true;
connected = true;
} else {
@ -84,15 +84,25 @@ void NetworkConnect()
// and when information is ready, send either a Ping or a Pong.
void NetworkUpdate()
{
// CheckSockets
//
// If any of the sockets in the socket_set are pending (received data, or requests)
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
int active = CheckSockets(socket_set, 0);
if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
// IsSocketReady
//
// If the socket is ready, attempt to receive data from the socket
int bytesRecv = 0;
if (server_cfg.datagram) {
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
if (IsSocketReady(client_res->socket)) {
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen, 0);
}
if (IsSocketReady(server_res->socket)) {
bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0);
}
} else {
@ -100,19 +110,30 @@ void NetworkUpdate()
bytesRecv = SocketReceive(connection, recvBuffer, msglen, 0);
}
}
// If we received data, was that data a "Ping!" or a "Pong!"
if (bytesRecv > 0) {
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
}
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
elapsed += GetFrameTime();
if (elapsed > delay) {
if (ping) {
ping = false;
SocketSend(client_res->socket, pingmsg, msglen);
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
SocketSend(client_res->socket, pingmsg, msglen);
} else {
SocketSend(client_res->socket, pingmsg, msglen);
}
} else if (pong) {
pong = false;
SocketSend(client_res->socket, pongmsg, msglen);
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
SocketSend(client_res->socket, pongmsg, msglen);
} else {
SocketSend(client_res->socket, pongmsg, msglen);
}
}
elapsed = 0.0f;
}
@ -148,10 +169,12 @@ int main()
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);
if (!(server_cfg.type == SOCKET_UDP)) {
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);
}
}
}
}
@ -162,20 +185,22 @@ int main()
// getaddrinfo
// socket
// setsockopt
// connect
// connect (TCP only)
client_res = AllocSocketResult();
if (!SocketCreate(&client_cfg, client_res)) {
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
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);
if (!(client_cfg.type == SOCKET_UDP)) {
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);
}
}
}
// Create & Add sockets to the socket set
// Create & Add sockets to the socket set
socket_set = AllocSocketSet(3);
msglen = strlen(pingmsg) + 1;
memset(recvBuffer, '\0', sizeof(recvBuffer));

View File

@ -1,88 +1,116 @@
/*******************************************************************************************
*
* 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 "rnet.c"
#define MAX_BUFFER_SIZE 512
#include <assert.h>
#include <stdio.h>
#include <string.h>
char buffer[MAX_BUFFER_SIZE];
float elapsed = 0.0f;
float delay = 1.0f;
bool ping = false;
bool pong = false;
bool connected = false;
SocketResult* client_res = NULL;
SocketSet* socket_set = NULL;
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .nonblocking = true};
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};
SocketResult *client_res = NULL;
SocketSet * socket_set = NULL;
char recvBuffer[512];
// Attempt to connect to the network (Either TCP, or UDP)
void NetworkConnect()
{
if (!SocketConnect(&client_cfg, client_res)) {
TraceLog(LOG_WARNING,
"Failed to connect socket to server: status %d, errno %d",
client_res->status, client_res->socket->status);
} else {
connected = true;
// Check if we're connected every _delay_ seconds
elapsed += GetFrameTime();
if (elapsed > delay) {
if (IsSocketConnected(client_res->socket)) { 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()
{
// CheckSockets
//
// If any of the sockets in the socket_set are pending (received data, or requests)
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
int active = CheckSockets(socket_set, 0);
if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
if (active > 0) {
int bytesRecv = 0;
if (IsSocketReady(client_res->socket)) {
bytesRecv = SocketReceive(client_res->socket, buffer, MAX_BUFFER_SIZE, 0);
// IsSocketReady
//
// 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);
}
// If we received data, was that data a "Ping!" or a "Pong!"
if (bytesRecv > 0) {
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
}
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
elapsed += GetFrameTime();
if (elapsed > delay) {
if (ping) {
ping = false;
SocketSend(client_res->socket, pingmsg, msglen);
} else if (pong) {
pong = false;
SocketSend(client_res->socket, pongmsg, msglen);
}
if (bytesRecv > 0) { TraceLog(LOG_INFO, "%s", buffer); }
elapsed = 0.0f;
}
}
int main()
{
// Setup
int screenWidth = 800;
int screenHeight = 450;
InitWindow(
screenWidth, screenHeight, "raylib [core] example - basic window");
screenWidth, screenHeight, "raylib [network] example - ping pong");
SetTargetFPS(60);
// Set log type
SetTraceLogLevel(LOG_DEBUG);
// Init the network layer
// Networking
InitNetwork();
// Create the server
// Create the client
//
// Performs
// getaddrinfo
// socket
// setsockopt
// connect (TCP only)
client_res = AllocSocketResult();
socket_set = AllocSocketSet(1);
if (!SocketCreate(&client_cfg, client_res)) {
TraceLog(LOG_WARNING, "Failed to create socket: status %d, errno %d",
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
client_res->status, client_res->socket->status);
} else {
AddSocket(socket_set, client_res->socket);
if (!(client_cfg.type == SOCKET_UDP)) {
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);
}
}
}
// Create & Add sockets to the socket set
socket_set = AllocSocketSet(1);
msglen = strlen(pingmsg) + 1;
memset(recvBuffer, '\0', sizeof(recvBuffer));
AddSocket(socket_set, client_res->socket);
// Main game loop
while (!WindowShouldClose()) {
BeginDrawing();
@ -90,15 +118,12 @@ int main()
if (connected) {
NetworkUpdate();
} else {
elapsed += GetFrameTime();
if (elapsed > delay) {
NetworkConnect();
elapsed = 0.0f;
}
NetworkConnect();
}
EndDrawing();
}
CloseWindow();
// Cleanup
CloseWindow();
return 0;
}

View File

@ -1,109 +1,143 @@
/*******************************************************************************************
*
* 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 "rnet.c"
bool connected = false;
bool sent = false;
float elapsed = 0.0f;
float delay = 1.0f;
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true};
#include <assert.h>
#include <stdio.h>
#include <string.h>
float elapsed = 0.0f;
float delay = 1.0f;
bool ping = false;
bool pong = false;
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 connection_cfg = {.nonblocking = true};
SocketResult* server_res = NULL;
Socket* connection = NULL;
SocketSet* socket_set = NULL;
SocketResult *server_res = NULL;
SocketSet * socket_set = NULL;
Socket * connection = NULL;
char recvBuffer[512];
void NetworkSend()
{
if (!sent) {
sent = true;
SocketSend(connection, "Hello, world!", 13);
}
}
void NetworkListen()
// Attempt to connect to the network (Either TCP, or UDP)
void NetworkConnect()
{
int active = CheckSockets(socket_set, 0);
if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
if (active > 0) {
connection = SocketAccept(server_res->socket, &connection_cfg);
if (connection != NULL) {
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
AddSocket(socket_set, connection);
ping = true;
connected = true;
} else {
TraceLog(LOG_WARNING, "Failed to accept socket: status %d, errno %d",
server_res->status, server_res->socket->status);
}
}
}
// 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()
{
// CheckSockets
//
// If any of the sockets in the socket_set are pending (received data, or requests)
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
int active = CheckSockets(socket_set, 0);
if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
// IsSocketReady
//
// If the socket is ready, attempt to receive data from the socket
int bytesRecv = 0;
if (IsSocketReady(connection)) {
bytesRecv = SocketReceive(connection, recvBuffer, msglen, 0);
}
// If we received data, was that data a "Ping!" or a "Pong!"
if (bytesRecv > 0) {
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
}
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
elapsed += GetFrameTime();
if (elapsed > delay) {
if (ping) {
ping = false;
SocketSend(connection, pingmsg, msglen);
} else if (pong) {
pong = false;
SocketSend(connection, pongmsg, msglen);
}
elapsed = 0.0f;
}
}
int main()
{
// Setup
int screenWidth = 800;
int screenHeight = 450;
InitWindow(
screenWidth, screenHeight, "raylib [core] example - basic window");
screenWidth, screenHeight, "raylib [network] example - ping pong");
SetTargetFPS(60);
// Set log type
SetTraceLogLevel(LOG_DEBUG);
// Init the network layer
// Networking
InitNetwork();
// Create the server
// Create the server
//
// Performs
// getaddrinfo
// socket
// setsockopt
// bind
// listen
server_res = AllocSocketResult();
socket_set = AllocSocketSet(2);
if (!SocketCreate(&server_cfg, server_res)) {
TraceLog(LOG_WARNING, "Failed to create socket: status %d, errno %d",
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
server_res->status, server_res->socket->status);
} else {
AddSocket(socket_set, server_res->socket);
if (!SocketListen(&server_cfg, server_res)) {
TraceLog(LOG_WARNING,
"Failed to listen on socket: status %d, errno %d",
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 (!(server_cfg.type == SOCKET_UDP)) {
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 & Add sockets to the socket set
socket_set = AllocSocketSet(2);
msglen = strlen(pingmsg) + 1;
memset(recvBuffer, '\0', sizeof(recvBuffer));
AddSocket(socket_set, server_res->socket);
// Main game loop
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(RAYWHITE);
if (connected) {
NetworkSend();
NetworkUpdate();
} else {
elapsed += GetFrameTime();
if (elapsed > delay) {
NetworkListen();
elapsed = 0.0f;
}
NetworkConnect();
}
EndDrawing();
}
CloseWindow();
// Cleanup
CloseWindow();
return 0;
}

View File

@ -1,22 +1,111 @@
#include "raylib.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
float elapsed = 0.0f;
float delay = 1.0f;
bool ping = false;
bool pong = false;
const char * pingmsg = "Ping!";
const char * pongmsg = "Pong!";
int msglen = 0;
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_UDP, .nonblocking = true};
SocketResult *client_res = NULL;
SocketSet * socket_set = NULL;
char recvBuffer[512];
// 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()
{
// CheckSockets
//
// If any of the sockets in the socket_set are pending (received data, or requests)
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
int active = CheckSockets(socket_set, 0);
if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
// IsSocketReady
//
// 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);
}
// If we received data, was that data a "Ping!" or a "Pong!"
if (bytesRecv > 0) {
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
}
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
elapsed += GetFrameTime();
if (elapsed > delay) {
if (ping) {
ping = false;
SocketSend(client_res->socket, pingmsg, msglen);
} else if (pong) {
pong = false;
SocketSend(client_res->socket, pongmsg, msglen);
}
elapsed = 0.0f;
}
}
int main()
{
// Setup
int screenWidth = 800;
int screenHeight = 450;
InitWindow(
screenWidth, screenHeight, "raylib [core] example - basic window");
screenWidth, screenHeight, "raylib [network] example - ping pong");
SetTargetFPS(60);
SetTraceLogLevel(LOG_DEBUG);
// Networking
InitNetwork();
// Create the client
//
// Performs
// getaddrinfo
// socket
// setsockopt
// connect (TCP only)
client_res = AllocSocketResult();
if (!SocketCreate(&client_cfg, client_res)) {
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
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);
}
}
// Create & Add sockets to the socket set
socket_set = AllocSocketSet(1);
msglen = strlen(pingmsg) + 1;
ping = true;
memset(recvBuffer, '\0', sizeof(recvBuffer));
AddSocket(socket_set, client_res->socket);
// Main game loop
while (!WindowShouldClose())
{
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
NetworkUpdate();
EndDrawing();
}
CloseWindow();
// Cleanup
CloseWindow();
return 0;
}

View File

@ -1,26 +1,110 @@
#include "raylib.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
float elapsed = 0.0f;
float delay = 1.0f;
bool ping = false;
bool pong = false;
const char * pingmsg = "Ping!";
const char * pongmsg = "Pong!";
int msglen = 0;
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "4950", .server = true, .type = SOCKET_UDP, .nonblocking = true};
SocketResult *server_res = NULL;
SocketSet * socket_set = NULL;
char recvBuffer[512];
// 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()
{
// CheckSockets
//
// If any of the sockets in the socket_set are pending (received data, or requests)
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
int active = CheckSockets(socket_set, 0);
if (active != 0) {
TraceLog(LOG_DEBUG,
"There are currently %d socket(s) with data to be processed.", active);
}
// IsSocketReady
//
// 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);
}
// If we received data, was that data a "Ping!" or a "Pong!"
if (bytesRecv > 0) {
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
}
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
elapsed += GetFrameTime();
if (elapsed > delay) {
if (ping) {
ping = false;
SocketSend(server_res->socket, pingmsg, msglen);
} else if (pong) {
pong = false;
SocketSend(server_res->socket, pongmsg, msglen);
}
elapsed = 0.0f;
}
}
int main()
{
// Setup
int screenWidth = 800;
int screenHeight = 450;
InitWindow(
screenWidth, screenHeight, "raylib [core] example - basic window");
screenWidth, screenHeight, "raylib [network] example - ping pong");
SetTargetFPS(60);
SetTraceLogLevel(LOG_DEBUG);
// Initialise networking
// Networking
InitNetwork();
//
// Create the server
//
// Performs
// getaddrinfo
// socket
// setsockopt
// bind
// listen
server_res = AllocSocketResult();
if (!SocketCreate(&server_cfg, server_res)) {
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
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);
}
}
// Create & Add sockets to the socket set
socket_set = AllocSocketSet(1);
msglen = strlen(pingmsg) + 1;
memset(recvBuffer, '\0', sizeof(recvBuffer));
AddSocket(socket_set, server_res->socket);
// Main game loop
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
NetworkUpdate();
EndDrawing();
}
CloseWindow();
// Cleanup
CloseWindow();
return 0;
}

View File

@ -173,9 +173,6 @@
typedef enum { false, true } bool;
#endif
// Network typedefs
typedef int32_t SocketChannel;
// Vector2 type
typedef struct Vector2 {
float x;
@ -452,20 +449,19 @@ typedef struct VrStereoConfig {
int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h]
} VrStereoConfig;
// Network typedefs
typedef uint32_t SocketChannel;
typedef struct _AddressInformation * AddressInformation;
typedef struct _SocketAddress * SocketAddress;
typedef struct _SocketAddressIPv4 * SocketAddressIPv4;
typedef struct _SocketAddressIPv6 * SocketAddressIPv6;
typedef struct _SocketAddressStorage *SocketAddressStorage;
// IPAddress definition (in network byte order)
typedef struct IPv4Address {
typedef struct IPAddress {
unsigned long host; /* 32-bit IPv4 host address */
unsigned short port; /* 16-bit protocol port */
} IPv4Address;
typedef struct IPv6Address {
union {
uint8_t byte[16];
uint16_t word[8];
} u;
};
} IPAddress;
// An option ID, value, sizeof(value) tuple for setsockopt(2).
typedef struct SocketOpt {
@ -481,17 +477,20 @@ typedef enum {
typedef struct UDPChannel {
int numbound; // The total number of addresses this channel is bound to
IPv4Address address[SOCKET_MAX_UDPADDRESSES]; // The list of remote addresses this channel is bound to
IPAddress address[SOCKET_MAX_UDPADDRESSES]; // The list of remote addresses this channel is bound to
} UDPChannel;
typedef struct Socket {
int ready; // Is the socket ready? i.e. has information
int status; // The last status code to have occured using this socket
int status; // The last status code to have occured using this socket
bool isServer; // Is this socket a server socket (i.e. TCP/UDP Listen Server)
bool isIPv6;
SocketChannel channel; // The socket handle id
SocketType type; // Is this socket a TCP or UDP socket?
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
IPAddress address; // The host/target IPv4 for this socket (in network byte order)
SocketAddressIPv4 addripv4; // The host/target IPv4 for this socket (in network byte order)
SocketAddressIPv6 addripv6; // The host/target IPv6 for this socket (in network byte order)
struct UDPChannel binding[SOCKET_MAX_UDPCHANNELS]; // The amount of channels (if UDP) this socket is bound to
} Socket;
typedef struct SocketSet {
@ -506,7 +505,7 @@ typedef struct SocketDataPacket {
int len; /* The length of the packet data */
int maxlen; /* The size of the data buffer */
int status; /* packet status after sending */
IPv4Address address; /* The source/dest address of an incoming/outgoing packet */
IPAddress address; /* The source/dest address of an incoming/outgoing packet */
} SocketDataPacket;
// Configuration for a socket. Not all of these fields need to
@ -514,9 +513,9 @@ typedef struct SocketDataPacket {
// struct literal will be zeroed out and replaced with defaults.
typedef struct SocketConfig {
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/service in the form "http" or "25565"
bool server; // Listen for incoming clients?
bool datagram; // TCP or UDP?
SocketType type;
bool nonblocking; // non-blocking operation?
int backlog_size; // set a custom backlog size
SocketOpt sockopts[SOCKET_MAX_SOCK_OPTS];
@ -536,13 +535,6 @@ typedef struct Packet {
uint8_t* data; // Data stored in network byte order
} Packet;
//
typedef struct _AddressInformation * AddressInformation;
typedef struct _SocketAddress * SocketAddress;
typedef struct _SocketAddressIPv4 * SocketAddressIPv4;
typedef struct _SocketAddressIPv6 * SocketAddressIPv6;
typedef struct _SocketAddressStorage *SocketAddressStorage;
//----------------------------------------------------------------------------------
// Enumerators Definition
//----------------------------------------------------------------------------------
@ -1520,14 +1512,23 @@ RLAPI AddressInformation AllocAddress();
RLAPI AddressInformation* AllocAddressList(int size);
// Socket API
RLAPI bool SocketCreate(SocketConfig *cfg, SocketResult *res);
RLAPI bool SocketBind(SocketConfig *cfg, SocketResult *res);
RLAPI bool SocketListen(SocketConfig *cfg, SocketResult *res);
RLAPI bool SocketConnect(SocketConfig *cfg, SocketResult *res);
RLAPI Socket *SocketAccept(Socket *server, SocketConfig *cfg);
RLAPI int SocketSend(Socket *socket, const void *datap, int len);
RLAPI int SocketReceive(Socket *socket, void *data, int maxlen, int timeout);
RLAPI void SocketClose(SocketChannel socket);
RLAPI bool SocketCreate(SocketConfig *config, SocketResult* result);
RLAPI bool SocketBind(SocketConfig *config, SocketResult* result);
RLAPI bool SocketListen(SocketConfig *config, SocketResult* result);
RLAPI bool SocketConnect(SocketConfig *config, SocketResult* result);
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 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 void SocketClose(Socket* sock);
RLAPI int SocketReady(Socket* sock);
RLAPI Socket *AllocSocket();
RLAPI void FreeSocket(Socket **sock);
RLAPI SocketResult *AllocSocketResult();

View File

@ -3,7 +3,7 @@
* rnet - A simple and easy-to-use network module for raylib
*
* FEATURES:
* - Manage network stuff
* - Provides a simple and (hopefully) easy to use wrapper around the Berkeley socket API
*
* DEPENDENCIES:
* raylib.h - TraceLog
@ -93,72 +93,30 @@ 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 *cfg, struct addrinfo *hints);
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, char buffer[], int *port);
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 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 void PrintSocket(AddressInformation addr);
//----------------------------------------------------------------------------------
// Global module implementationd
// Global module implementation
//----------------------------------------------------------------------------------
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)
{
sa->sin_family = AF_INET;
sa->sin_port = htons(port);
int result = inet_pton(AF_INET, host, &(sa->sin_addr));
if (result <= 0) {
if (result == 0) {
TraceLog(LOG_WARNING, "Input not provided in presentation format.");
return false;
}
}
return true;
}
//
static bool FillIPv6SockAddress(struct sockaddr_in6 *sa, const char *host, unsigned short port)
{
sa->sin6_family = AF_INET6;
sa->sin6_port = htons(port);
int result = inet_pton(AF_INET6, host, &(sa->sin6_addr));
if (result <= 0) {
if (result == 0) {
TraceLog(LOG_WARNING, "Input not provided in presentation format.");
return false;
}
}
return true;
}
// Print socket information
static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol)
{
struct sockaddr *sockaddr_ip;
char ip[INET6_ADDRSTRLEN]; // Enough pace to hold a IPv6 string
int port;
switch (family) {
case AF_UNSPEC: {
TraceLog(LOG_DEBUG, "\tFamily: Unspecified");
} break;
case AF_INET: {
TraceLog(LOG_DEBUG, "\tFamily: AF_INET (IPv4)");
TraceLog(LOG_INFO, "\t- IPv4 address %s", SocketAddressToString(addr, ip, &port));
TraceLog(LOG_INFO, "\t- IPv4 address %s", SocketAddressToString(addr));
} break;
case AF_INET6: {
TraceLog(LOG_DEBUG, "\tFamily: AF_INET6 (IPv6)");
TraceLog(LOG_INFO, "\t- IPv6 address %s", SocketAddressToString(addr, ip, &port));
TraceLog(LOG_INFO, "\t- IPv6 address %s", SocketAddressToString(addr));
} break;
case AF_NETBIOS: {
TraceLog(LOG_DEBUG, "\tFamily: AF_NETBIOS (NetBIOS)");
@ -229,7 +187,7 @@ static bool IsIPv6Address(const char *ip)
return result != 0;
}
//
// Return a pointer to the port from the correct address family (IPv4, or IPv6)
void *GetSocketPortPtr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
@ -239,7 +197,7 @@ void *GetSocketPortPtr(struct sockaddr *sa)
return &(((struct sockaddr_in6 *) sa)->sin6_port);
}
//
// Return a pointer to the address from the correct address family (IPv4, or IPv6)
void *GetSocketAddressPtr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
@ -249,7 +207,7 @@ void *GetSocketAddressPtr(struct sockaddr *sa)
return &(((struct sockaddr_in6 *) sa)->sin6_addr);
}
//
// Is the socket in a valid state?
static bool IsSocketValid(Socket *sock)
{
if (sock != NULL) { return (sock->channel != INVALID_SOCKET); }
@ -294,7 +252,7 @@ static char *SocketErrorCodeToString(int err)
#endif
}
//
// Set the defaults in the supplied SocketConfig if they're not already set
static bool SocketSetDefaults(SocketConfig *config)
{
if (config->backlog_size == 0) {
@ -324,7 +282,7 @@ static bool InitSocket(Socket *sock, struct addrinfo *addr)
// SocketResult* result - The results of this function (if any, including errors)
//
// e.g.
// SocketConfig server_cfg = { SocketConfig client_cfg = {
// SocketConfig server_config = { SocketConfig client_config = {
// .host = "127.0.0.1", .host = "127.0.0.1",
// .port = 8080, .port = 8080,
// .server = true, };
@ -341,7 +299,7 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
outresult->status = RESULT_FAILURE;
// Set the socket type
outresult->socket->type = (config->datagram) ? SOCKET_UDP : SOCKET_TCP;
outresult->socket->type = config->type;
// Set the hints based on information in the config
//
@ -412,20 +370,34 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
}
if (success) {
outresult->status = RESULT_SUCCESS;
outresult->socket->ready = 0;
outresult->socket->status = 0;
outresult->socket->isServer = config->server;
outresult->status = RESULT_SUCCESS;
outresult->socket->ready = 0;
outresult->socket->status = 0;
if (!(config->type == SOCKET_UDP)) {
outresult->socket->isServer = config->server;
}
switch (res->ai_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *s = ((struct sockaddr_in *) res->ai_addr);
outresult->socket->address.host = s->sin_addr.s_addr;
outresult->socket->address.port = s->sin_port;
outresult->socket->addripv4 = (struct _SocketAddressIPv4 *) malloc(
sizeof(*outresult->socket->addripv4));
if (outresult->socket->addripv4 != NULL) {
memset(outresult->socket->addripv4, 0,
sizeof(*outresult->socket->addripv4));
}
memcpy(&outresult->socket->addripv4->address,
(struct sockaddr_in *) res->ai_addr, sizeof(struct sockaddr_in));
outresult->socket->isIPv6 = false;
} break;
case AF_INET6: {
struct sockaddr_in6 *s = ((struct sockaddr_in6 *) res->ai_addr);
outresult->socket->address.host = s->sin6_addr.s6_addr;
outresult->socket->address.port = s->sin6_port;
outresult->socket->addripv6 = (struct _SocketAddressIPv6 *) malloc(
sizeof(*outresult->socket->addripv6));
if (outresult->socket->addripv6 != NULL) {
memset(outresult->socket->addripv6, 0,
sizeof(*outresult->socket->addripv6));
}
memcpy(&outresult->socket->addripv6->address,
(struct sockaddr_in6 *) res->ai_addr, sizeof(struct sockaddr_in6));
outresult->socket->isIPv6 = true;
} break;
}
}
@ -486,17 +458,17 @@ static bool SocketSetOptions(SocketConfig *config, Socket *sock)
}
// Set "hints" in an addrinfo struct, to be passed to getaddrinfo.
static void SocketSetHints(SocketConfig *cfg, struct addrinfo *hints)
static void SocketSetHints(SocketConfig *config, struct addrinfo *hints)
{
if (cfg == 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
if (IsIPv4Address(cfg->host)) {
if (IsIPv4Address(config->host)) {
hints->ai_family = AF_INET;
hints->ai_flags |= AI_NUMERICHOST;
} else {
if (IsIPv6Address(cfg->host)) {
if (IsIPv6Address(config->host)) {
hints->ai_family = AF_INET6;
hints->ai_flags |= AI_NUMERICHOST;
} else {
@ -504,14 +476,16 @@ static void SocketSetHints(SocketConfig *cfg, struct addrinfo *hints)
}
}
if (cfg->datagram) {
if (config->type == SOCKET_UDP) {
hints->ai_socktype = SOCK_DGRAM;
} else {
hints->ai_socktype = SOCK_STREAM;
}
// Set passive unless UDP client
if (!cfg->datagram || cfg->server) { hints->ai_flags = AI_PASSIVE; }
if (!(config->type == SOCKET_UDP) || config->server) {
hints->ai_flags = AI_PASSIVE;
}
}
//----------------------------------------------------------------------------------
@ -636,10 +610,10 @@ void ResolveIP(const char *ip, const char *port, int flags, char *host, char *se
//
// e.g.
// const char* address = "127.0.0.1" (local address)
// const char* port = "80"
// const char* port = "80"
//
// returns:
// the total amount of addresses found
// Returns:
// The total amount of addresses found, -1 on error
//
int ResolveHost(const char *address, const char *port, AddressInformation *addrlist)
{
@ -681,7 +655,7 @@ int ResolveHost(const char *address, const char *port, AddressInformation *addrl
// Validate the size is > 0, otherwise return
if (size <= 0) {
TraceLog(LOG_WARNING, "Error, no addresses found.");
return;
return -1;
}
// Dynamically allocate an array of address information structs
@ -736,9 +710,9 @@ int ResolveHost(const char *address, const char *port, AddressInformation *addrl
// SocketResult* result - The results of this function (if any, including errors)
//
// e.g.
// SocketConfig server_cfg = { SocketConfig client_cfg = {
// .host = "127.0.0.1", .host = "127.0.0.1",
// .port = 8080, .port = 8080,
// SocketConfig server_config = { SocketConfig client_config = {
// .host = "127.0.0.1", .host = "127.0.0.1",
// .port = 8080, .port = 8080,
// .server = true, };
// .nonblocking = true,
// };
@ -774,8 +748,9 @@ bool SocketCreate(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 = false;
result->status = RESULT_FAILURE;
bool success = false;
result->status = RESULT_FAILURE;
struct sockaddr_storage *sock_addr = NULL;
// Don't bind to a socket that isn't configured as a server
if (!IsSocketValid(result->socket) || !config->server) {
@ -784,44 +759,44 @@ bool SocketBind(SocketConfig *config, SocketResult *result)
success = false;
} else {
if (IsIPv4Address(config->host)) {
struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
ip4addr.sin_port = config->port;
inet_pton(AF_INET, config->host, &ip4addr.sin_addr);
if (bind(result->socket->channel, (struct sockaddr *) &ip4addr, sizeof(ip4addr)) != 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;
}
struct sockaddr_in ipv4addr;
ipv4addr.sin_family = AF_INET;
ipv4addr.sin_port = config->port;
inet_pton(AF_INET, config->host, &ipv4addr.sin_addr);
sock_addr = (struct sockaddr_storage *) &ipv4addr;
} 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;
}
struct sockaddr_in6 ipv6addr;
ipv6addr.sin6_family = AF_INET6;
ipv6addr.sin6_port = config->port;
inet_pton(AF_INET6, config->host, &ipv6addr.sin6_addr);
sock_addr = (struct sockaddr_storage *) &ipv6addr;
}
}
if (bind(result->socket->channel, (struct sockaddr *) sock_addr, sizeof(*sock_addr)) != 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;
}
}
// Was the bind a success?
if (success) {
result->status = RESULT_SUCCESS;
result->socket->ready = 0;
result->socket->status = 0;
socklen_t sock_len = sizeof(*sock_addr);
if (getsockname(result->socket->channel, (struct sockaddr *) sock_addr, &sock_len) < 0) {
TraceLog(LOG_WARNING, "Couldn't get socket address");
} else {
struct sockaddr_in *s = (struct sockaddr_in *) sock_addr;
result->socket->address.host = s->sin_addr.s_addr;
result->socket->address.port = s->sin_port;
}
}
return success;
}
@ -839,13 +814,17 @@ bool SocketListen(SocketConfig *config, SocketResult *result)
success = false;
} else {
// Don't listen on UDP sockets
if (!config->datagram) {
if (!(config->type == SOCKET_UDP)) {
if (listen(result->socket->channel, config->backlog_size) != SOCKET_ERROR) {
TraceLog(LOG_INFO, "Started listening on socket...");
success = true;
} else {
success = false;
}
} else {
TraceLog(LOG_WARNING,
"Cannot listen on socket marked as \"UDP\" (datagram) in SocketConfig.");
success = false;
}
}
@ -858,7 +837,7 @@ bool SocketListen(SocketConfig *config, SocketResult *result)
return success;
}
//
// Connect the socket to the destination specified by "host" and "port" in SocketConfig
bool SocketConnect(SocketConfig *config, SocketResult *result)
{
bool success = true;
@ -966,7 +945,6 @@ Socket *SocketAccept(Socket *server, SocketConfig *config)
struct sockaddr_storage sock_addr;
socklen_t sock_alen;
Socket * sock;
int sock_port;
sock = AllocSocket();
server->ready = 0;
sock_alen = sizeof(sock_addr);
@ -985,22 +963,92 @@ Socket *SocketAccept(Socket *server, SocketConfig *config)
switch (sock_addr.ss_family) {
case AF_INET: {
struct sockaddr_in *s = ((struct sockaddr_in *) &sock_addr);
sock->address.host = s->sin_addr.s_addr;
sock->address.port = s->sin_port;
TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString(s),
ntohs(sock->address.port));
sock->addripv4 = (struct _SocketAddressIPv4 *) malloc(sizeof(*sock->addripv4));
if (sock->addripv4 != NULL) {
memset(sock->addripv4, 0, sizeof(*sock->addripv4));
}
memcpy(&sock->addripv4->address, (struct sockaddr_in *) &s->sin_addr, sizeof(struct sockaddr_in));
TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString((struct sockaddr_storage *) s),
ntohs(sock->addripv4->address.sin_port));
} break;
case AF_INET6: {
struct sockaddr_in6 *s = ((struct sockaddr_in6 *) &sock_addr);
sock->address.host = s->sin6_addr.s6_addr;
sock->address.port = s->sin6_port;
TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString(s),
ntohs(sock->address.port));
sock->addripv6 = (struct _SocketAddressIPv6 *) malloc(sizeof(*sock->addripv6));
if (sock->addripv6 != NULL) {
memset(sock->addripv6, 0, sizeof(*sock->addripv6));
}
memcpy(&sock->addripv6->address, (struct sockaddr_in6 *) &s->sin6_addr, sizeof(struct sockaddr_in6));
TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString((struct sockaddr_storage *) s),
ntohs(sock->addripv4->address.sin_port));
} break;
}
return sock;
}
// Verify that the channel is in the valid range
static int ValidChannel(int channel)
{
if ((channel < 0) || (channel >= SOCKET_MAX_UDPCHANNELS)) {
TraceLog(LOG_WARNING, "Invalid channel");
return 0;
}
return 1;
}
// Set the socket channel
int SocketSetChannel(Socket *socket, int channel, const IPAddress *address)
{
struct UDPChannel *binding;
if (socket == NULL) {
TraceLog(LOG_WARNING, "Passed a NULL socket");
return (-1);
}
if (channel == -1) {
for (channel = 0; channel < SOCKET_MAX_UDPCHANNELS; ++channel) {
binding = &socket->binding[channel];
if (binding->numbound < SOCKET_MAX_UDPADDRESSES) { break; }
}
} else {
if (!ValidChannel(channel)) { return (-1); }
binding = &socket->binding[channel];
}
if (binding->numbound == SOCKET_MAX_UDPADDRESSES) {
TraceLog(LOG_WARNING, "No room for new addresses");
return (-1);
}
binding->address[binding->numbound++] = *address;
return (channel);
}
// Remove the socket channel
int SocketUnsetChannel(Socket *socket, int channel)
{
if ((channel >= 0) && (channel < SOCKET_MAX_UDPCHANNELS)) {
socket->binding[channel].numbound = 0;
}
}
// Get the primary IP address of the remote system associated with the socket and channel.
// If the channel is not bound, this function returns NULL.
IPAddress *SocketGetPeerAddress(Socket *socket, int channel)
{
IPAddress *address;
address = NULL;
switch (channel) {
case -1:
/* Return the actual address of the socket */
address = &socket->address;
break;
default:
/* Return the address of the bound channel */
if (ValidChannel(channel) && (socket->binding[channel].numbound > 0)) {
address = &socket->binding[channel].address[0];
}
break;
}
return (address);
}
// Send 'len' bytes of 'data' over the non-server socket 'sock'
//
// Example
@ -1045,12 +1093,16 @@ int SocketSend(Socket *sock, const void *datap, int length)
return sent;
} break;
case SOCKET_UDP: {
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = sock->address.port;
dest.sin_addr.s_addr = sock->address.host;
SocketSetLastError(0);
status = sendto(sock->channel, (const char *) data, left, 0, (struct sockaddr *) &dest, sizeof(dest));
if (sock->isIPv6) {
status = sendto(sock->channel, (const char *) data, left, 0,
(struct sockaddr *) &sock->addripv6->address,
sizeof(sock->addripv6->address));
} else {
status = sendto(sock->channel, (const char *) data, left, 0,
(struct sockaddr *) &sock->addripv4->address,
sizeof(sock->addripv4->address));
}
if (sent >= 0) {
sock->status = status;
++numsent;
@ -1135,12 +1187,33 @@ int SocketReceive(Socket *sock, void *data, int maxlen, int timeout)
return -1;
}
//
// Does the socket have it's 'ready' flag set?
bool IsSocketReady(Socket *sock)
{
return (sock != NULL) && (sock->ready);
}
// Returns true if a socket is has data available for reading right now
bool SocketReady(Socket *sock)
{
int retval = 0;
struct timeval tv;
fd_set mask;
// Check the file descriptors for available data
do {
SocketSetLastError(0);
FD_ZERO(&mask);
FD_SET(sock->channel, &mask);
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(sock->channel + 1, &mask, NULL, NULL, &tv);
} while (SocketGetLastError() == WSAEINTR);
return (retval == 1);
}
// Check if the socket is considered connected
bool IsSocketConnected(Socket *sock)
{
#if PLATFORM_WINDOWS
@ -1305,15 +1378,15 @@ int CheckSockets(SocketSet *set, unsigned int timeout)
}
}
/* Check the file descriptors for available data */
// Check the file descriptors for available data
do {
SocketSetLastError(0);
/* Set up the mask of file descriptors */
// Set up the mask of file descriptors
FD_ZERO(&mask);
for (i = set->numsockets - 1; i >= 0; --i) {
FD_SET(set->sockets[i]->channel, &mask);
} /* Set up the timeout */
} // Set up the timeout
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
@ -1321,7 +1394,7 @@ int CheckSockets(SocketSet *set, unsigned int timeout)
retval = select(maxfd + 1, &mask, NULL, NULL, &tv);
} while (SocketGetLastError() == WSAEINTR);
/* Mark all file descriptors ready that have data available */
// Mark all file descriptors ready that have data available
if (retval > 0) {
for (i = set->numsockets - 1; i >= 0; --i) {
if (FD_ISSET(set->sockets[i]->channel, &mask)) {

View File

@ -108,67 +108,10 @@
// From: https://github.com/DFHack/clsocket/blob/master/src/Host.h
//----------------------------------------------------------------------------------
#ifndef __WORDSIZE
# define __WORDSIZE 32
#endif
#if defined(_LINUX) || defined(_DARWIN)
typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
typedef int SOCKET;
#endif
#ifdef WIN32
typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
#endif
#ifdef WIN32
typedef int socklen_t;
#endif
#if defined(WIN32)
typedef unsigned long long int uint64;
typedef long long int int64;
#elif (__WORDSIZE == 32)
__extension__ typedef long long int int64;
__extension__ typedef unsigned long long int uint64;
#elif (__WORDSIZE == 64)
typedef unsigned long int uint64;
typedef long int int64;
#endif
#ifdef WIN32
# ifndef UINT8_MAX
# define UINT8_MAX (UCHAR_MAX)
# endif // UINT8_MAX
# ifndef UINT16_MAX
# define UINT16_MAX (USHRT_MAX)
# endif // UINT16_MAX
# ifndef UINT32_MAX
# define UINT32_MAX (ULONG_MAX)
# endif // UINT32_MAX
# if __WORDSIZE == 64
# define SIZE_MAX (18446744073709551615UL)
# else
# ifndef SIZE_MAX
# define SIZE_MAX (4294967295U)
# endif // SIZE_MAX
# endif // __WORDSIZE == 64
#endif // WIN32
#if defined(WIN32)
# define ssize_t size_t
#endif // WIN32
#ifndef RESULT_SUCCESS
# define RESULT_SUCCESS 0
#endif // RESULT_SUCCESS