fixed tcp_client
fixed tcp_server fixed ping_pong udp support still broken >:(
This commit is contained in:
parent
38b77c7cc0
commit
0ea6d1543d
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
71
src/raylib.h
71
src/raylib.h
|
|
@ -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();
|
||||
|
|
|
|||
329
src/rnet.c
329
src/rnet.c
|
|
@ -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)) {
|
||||
|
|
|
|||
57
src/rnet.h
57
src/rnet.h
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user