fixed tcp_client
fixed tcp_server fixed ping_pong udp support still broken >:(
This commit is contained in:
parent
38b77c7cc0
commit
0ea6d1543d
|
|
@ -36,8 +36,8 @@ bool client_connected = false;
|
||||||
const char * pingmsg = "Ping!";
|
const char * pingmsg = "Ping!";
|
||||||
const char * pongmsg = "Pong!";
|
const char * pongmsg = "Pong!";
|
||||||
int msglen = 0;
|
int msglen = 0;
|
||||||
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .datagram = true, .server = true, .nonblocking = true};
|
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", .datagram = true, .nonblocking = true};
|
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .type = SOCKET_TCP, .nonblocking = true};
|
||||||
SocketConfig connection_cfg = {.nonblocking = true};
|
SocketConfig connection_cfg = {.nonblocking = true};
|
||||||
SocketResult *server_res = NULL;
|
SocketResult *server_res = NULL;
|
||||||
SocketResult *client_res = NULL;
|
SocketResult *client_res = NULL;
|
||||||
|
|
@ -49,7 +49,7 @@ char recvBuffer[512];
|
||||||
void NetworkConnect()
|
void NetworkConnect()
|
||||||
{
|
{
|
||||||
// If the server is configured as UDP, ignore connection requests
|
// 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;
|
ping = true;
|
||||||
connected = true;
|
connected = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -84,15 +84,25 @@ void NetworkConnect()
|
||||||
// and when information is ready, send either a Ping or a Pong.
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
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);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"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;
|
int bytesRecv = 0;
|
||||||
if (server_cfg.datagram) {
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
if (IsSocketReady(client_res->socket)) {
|
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);
|
bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -100,19 +110,30 @@ void NetworkUpdate()
|
||||||
bytesRecv = SocketReceive(connection, recvBuffer, msglen, 0);
|
bytesRecv = SocketReceive(connection, recvBuffer, msglen, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we received data, was that data a "Ping!" or a "Pong!"
|
||||||
if (bytesRecv > 0) {
|
if (bytesRecv > 0) {
|
||||||
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
||||||
if (strcmp(recvBuffer, pongmsg) == 0) { ping = 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();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (ping) {
|
if (ping) {
|
||||||
ping = false;
|
ping = false;
|
||||||
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
SocketSend(client_res->socket, pingmsg, msglen);
|
SocketSend(client_res->socket, pingmsg, msglen);
|
||||||
|
} else {
|
||||||
|
SocketSend(client_res->socket, pingmsg, msglen);
|
||||||
|
}
|
||||||
} else if (pong) {
|
} else if (pong) {
|
||||||
pong = false;
|
pong = false;
|
||||||
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
SocketSend(client_res->socket, pongmsg, msglen);
|
SocketSend(client_res->socket, pongmsg, msglen);
|
||||||
|
} else {
|
||||||
|
SocketSend(client_res->socket, pongmsg, msglen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
@ -148,6 +169,7 @@ int main()
|
||||||
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
|
if (!(server_cfg.type == SOCKET_UDP)) {
|
||||||
if (!SocketListen(&server_cfg, server_res)) {
|
if (!SocketListen(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to start listen server: status %d, errno %d",
|
"Failed to start listen server: status %d, errno %d",
|
||||||
|
|
@ -155,6 +177,7 @@ int main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the client
|
// Create the client
|
||||||
//
|
//
|
||||||
|
|
@ -162,18 +185,20 @@ int main()
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// connect
|
// connect (TCP only)
|
||||||
client_res = AllocSocketResult();
|
client_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&client_cfg, client_res)) {
|
if (!SocketCreate(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
client_res->status, client_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
|
if (!(client_cfg.type == SOCKET_UDP)) {
|
||||||
if (!SocketConnect(&client_cfg, client_res)) {
|
if (!SocketConnect(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to connect to server: status %d, errno %d",
|
"Failed to connect to server: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
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);
|
socket_set = AllocSocketSet(3);
|
||||||
|
|
|
||||||
|
|
@ -1,87 +1,115 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* raylib [core] example - Basic window
|
|
||||||
*
|
|
||||||
* Welcome to raylib!
|
|
||||||
*
|
|
||||||
* To test examples, just press F6 and execute raylib_compile_execute script
|
|
||||||
* Note that compiled executable is placed in the same folder as .c file
|
|
||||||
*
|
|
||||||
* You can find all basic examples on C:\raylib\raylib\examples folder or
|
|
||||||
* raylib official webpage: www.raylib.com
|
|
||||||
*
|
|
||||||
* Enjoy using raylib. :)
|
|
||||||
*
|
|
||||||
* This example has been created using raylib 1.0 (www.raylib.com)
|
|
||||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
|
|
||||||
*
|
|
||||||
********************************************************************************************/
|
|
||||||
|
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
#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 elapsed = 0.0f;
|
||||||
float delay = 1.0f;
|
float delay = 1.0f;
|
||||||
|
bool ping = false;
|
||||||
|
bool pong = false;
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
|
const char * pingmsg = "Ping!";
|
||||||
|
const char * pongmsg = "Pong!";
|
||||||
|
int msglen = 0;
|
||||||
|
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .type = SOCKET_TCP, .nonblocking = true};
|
||||||
SocketResult *client_res = NULL;
|
SocketResult *client_res = NULL;
|
||||||
SocketSet * socket_set = NULL;
|
SocketSet * socket_set = NULL;
|
||||||
SocketConfig client_cfg = {.host = "127.0.0.1", .port = "8080", .nonblocking = true};
|
char recvBuffer[512];
|
||||||
|
|
||||||
|
// Attempt to connect to the network (Either TCP, or UDP)
|
||||||
void NetworkConnect()
|
void NetworkConnect()
|
||||||
{
|
{
|
||||||
if (!SocketConnect(&client_cfg, client_res)) {
|
// Check if we're connected every _delay_ seconds
|
||||||
TraceLog(LOG_WARNING,
|
elapsed += GetFrameTime();
|
||||||
"Failed to connect socket to server: status %d, errno %d",
|
if (elapsed > delay) {
|
||||||
client_res->status, client_res->socket->status);
|
if (IsSocketConnected(client_res->socket)) { connected = true; }
|
||||||
} else {
|
elapsed = 0.0f;
|
||||||
connected = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Once connected to the network, check the sockets for pending information
|
||||||
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
void NetworkUpdate()
|
||||||
{
|
{
|
||||||
|
// 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);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active > 0) {
|
// IsSocketReady
|
||||||
|
//
|
||||||
|
// If the socket is ready, attempt to receive data from the socket
|
||||||
int bytesRecv = 0;
|
int bytesRecv = 0;
|
||||||
if (IsSocketReady(client_res->socket)) {
|
if (IsSocketReady(client_res->socket)) {
|
||||||
bytesRecv = SocketReceive(client_res->socket, buffer, MAX_BUFFER_SIZE, 0);
|
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen, 0);
|
||||||
}
|
}
|
||||||
if (bytesRecv > 0) { TraceLog(LOG_INFO, "%s", buffer); }
|
|
||||||
|
// 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()
|
int main()
|
||||||
{
|
{
|
||||||
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [core] example - basic window");
|
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
// Set log type
|
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Init the network layer
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the server
|
// Create the client
|
||||||
|
//
|
||||||
|
// Performs
|
||||||
|
// getaddrinfo
|
||||||
|
// socket
|
||||||
|
// setsockopt
|
||||||
|
// connect (TCP only)
|
||||||
client_res = AllocSocketResult();
|
client_res = AllocSocketResult();
|
||||||
socket_set = AllocSocketSet(1);
|
|
||||||
if (!SocketCreate(&client_cfg, client_res)) {
|
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);
|
client_res->status, client_res->socket->status);
|
||||||
} else {
|
} 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
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
|
|
@ -90,15 +118,12 @@ int main()
|
||||||
if (connected) {
|
if (connected) {
|
||||||
NetworkUpdate();
|
NetworkUpdate();
|
||||||
} else {
|
} else {
|
||||||
elapsed += GetFrameTime();
|
|
||||||
if (elapsed > delay) {
|
|
||||||
NetworkConnect();
|
NetworkConnect();
|
||||||
elapsed = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
CloseWindow();
|
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
CloseWindow();
|
||||||
return 0;
|
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 "raylib.h"
|
||||||
|
#include "rnet.c"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
bool connected = false;
|
|
||||||
bool sent = false;
|
|
||||||
float elapsed = 0.0f;
|
float elapsed = 0.0f;
|
||||||
float delay = 1.0f;
|
float delay = 1.0f;
|
||||||
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true};
|
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};
|
SocketConfig connection_cfg = {.nonblocking = true};
|
||||||
SocketResult *server_res = NULL;
|
SocketResult *server_res = NULL;
|
||||||
Socket* connection = NULL;
|
|
||||||
SocketSet * socket_set = NULL;
|
SocketSet * socket_set = NULL;
|
||||||
|
Socket * connection = NULL;
|
||||||
|
char recvBuffer[512];
|
||||||
|
|
||||||
void NetworkSend()
|
// Attempt to connect to the network (Either TCP, or UDP)
|
||||||
{
|
void NetworkConnect()
|
||||||
if (!sent) {
|
|
||||||
sent = true;
|
|
||||||
SocketSend(connection, "Hello, world!", 13);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkListen()
|
|
||||||
{
|
{
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active > 0) {
|
if (active > 0) {
|
||||||
connection = SocketAccept(server_res->socket, &connection_cfg);
|
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
|
||||||
if (connection != NULL) {
|
|
||||||
AddSocket(socket_set, connection);
|
AddSocket(socket_set, connection);
|
||||||
|
ping = true;
|
||||||
connected = 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()
|
int main()
|
||||||
{
|
{
|
||||||
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [core] example - basic window");
|
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
// Set log type
|
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Init the network layer
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the server
|
// Create the server
|
||||||
|
//
|
||||||
|
// Performs
|
||||||
|
// getaddrinfo
|
||||||
|
// socket
|
||||||
|
// setsockopt
|
||||||
|
// bind
|
||||||
|
// listen
|
||||||
server_res = AllocSocketResult();
|
server_res = AllocSocketResult();
|
||||||
socket_set = AllocSocketSet(2);
|
|
||||||
if (!SocketCreate(&server_cfg, server_res)) {
|
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);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
AddSocket(socket_set, server_res->socket);
|
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)) {
|
if (!SocketListen(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to listen on socket: status %d, errno %d",
|
"Failed to start listen server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
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
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
NetworkSend();
|
NetworkUpdate();
|
||||||
} else {
|
} else {
|
||||||
elapsed += GetFrameTime();
|
NetworkConnect();
|
||||||
if (elapsed > delay) {
|
|
||||||
NetworkListen();
|
|
||||||
elapsed = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
CloseWindow();
|
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,22 +1,111 @@
|
||||||
#include "raylib.h"
|
#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()
|
int main()
|
||||||
{
|
{
|
||||||
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [core] example - basic window");
|
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
||||||
SetTargetFPS(60);
|
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
|
// Main game loop
|
||||||
while (!WindowShouldClose())
|
while (!WindowShouldClose()) {
|
||||||
{
|
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
NetworkUpdate();
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
CloseWindow();
|
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,26 +1,110 @@
|
||||||
#include "raylib.h"
|
#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()
|
int main()
|
||||||
{
|
{
|
||||||
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [core] example - basic window");
|
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Initialise networking
|
// Networking
|
||||||
InitNetwork();
|
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
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
NetworkUpdate();
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
CloseWindow();
|
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
69
src/raylib.h
69
src/raylib.h
|
|
@ -173,9 +173,6 @@
|
||||||
typedef enum { false, true } bool;
|
typedef enum { false, true } bool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Network typedefs
|
|
||||||
typedef int32_t SocketChannel;
|
|
||||||
|
|
||||||
// Vector2 type
|
// Vector2 type
|
||||||
typedef struct Vector2 {
|
typedef struct Vector2 {
|
||||||
float x;
|
float x;
|
||||||
|
|
@ -452,20 +449,19 @@ typedef struct VrStereoConfig {
|
||||||
int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h]
|
int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h]
|
||||||
} VrStereoConfig;
|
} 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)
|
// IPAddress definition (in network byte order)
|
||||||
typedef struct IPv4Address {
|
typedef struct IPAddress {
|
||||||
unsigned long host; /* 32-bit IPv4 host address */
|
unsigned long host; /* 32-bit IPv4 host address */
|
||||||
unsigned short port; /* 16-bit protocol port */
|
unsigned short port; /* 16-bit protocol port */
|
||||||
} IPv4Address;
|
} IPAddress;
|
||||||
|
|
||||||
typedef struct IPv6Address {
|
|
||||||
union {
|
|
||||||
uint8_t byte[16];
|
|
||||||
uint16_t word[8];
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
// An option ID, value, sizeof(value) tuple for setsockopt(2).
|
// An option ID, value, sizeof(value) tuple for setsockopt(2).
|
||||||
typedef struct SocketOpt {
|
typedef struct SocketOpt {
|
||||||
|
|
@ -481,17 +477,20 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct UDPChannel {
|
typedef struct UDPChannel {
|
||||||
int numbound; // The total number of addresses this channel is bound to
|
int numbound; // The total number of addresses this channel is bound to
|
||||||
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;
|
} UDPChannel;
|
||||||
|
|
||||||
typedef struct Socket {
|
typedef struct Socket {
|
||||||
int ready; // Is the socket ready? i.e. has information
|
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 isServer; // Is this socket a server socket (i.e. TCP/UDP Listen Server)
|
||||||
|
bool isIPv6;
|
||||||
SocketChannel channel; // The socket handle id
|
SocketChannel channel; // The socket handle id
|
||||||
SocketType type; // Is this socket a TCP or UDP socket?
|
SocketType type; // Is this socket a TCP or UDP socket?
|
||||||
IPv4Address address; // The host/target ip for this socket (in network byte order)
|
IPAddress address; // The host/target IPv4 for this socket (in network byte order)
|
||||||
struct UDPChannel bindings[SOCKET_MAX_UDPCHANNELS]; // The amount of channels (if UDP) this socket is bound to
|
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;
|
} Socket;
|
||||||
|
|
||||||
typedef struct SocketSet {
|
typedef struct SocketSet {
|
||||||
|
|
@ -506,7 +505,7 @@ typedef struct SocketDataPacket {
|
||||||
int len; /* The length of the packet data */
|
int len; /* The length of the packet data */
|
||||||
int maxlen; /* The size of the data buffer */
|
int maxlen; /* The size of the data buffer */
|
||||||
int status; /* packet status after sending */
|
int status; /* packet status after sending */
|
||||||
IPv4Address address; /* The source/dest address of an incoming/outgoing packet */
|
IPAddress address; /* The source/dest address of an incoming/outgoing packet */
|
||||||
} SocketDataPacket;
|
} SocketDataPacket;
|
||||||
|
|
||||||
// Configuration for a socket. Not all of these fields need to
|
// Configuration for a socket. Not all of these fields need to
|
||||||
|
|
@ -514,9 +513,9 @@ typedef struct SocketDataPacket {
|
||||||
// struct literal will be zeroed out and replaced with defaults.
|
// struct literal will be zeroed out and replaced with defaults.
|
||||||
typedef struct SocketConfig {
|
typedef struct SocketConfig {
|
||||||
char * host; // The host address in xxx.xxx.xxx.xxx form
|
char * host; // The host address in xxx.xxx.xxx.xxx form
|
||||||
char * port; // The target port/server in the form "http" or "25565"
|
char * port; // The target port/service in the form "http" or "25565"
|
||||||
bool server; // Listen for incoming clients?
|
bool server; // Listen for incoming clients?
|
||||||
bool datagram; // TCP or UDP?
|
SocketType type;
|
||||||
bool nonblocking; // non-blocking operation?
|
bool nonblocking; // non-blocking operation?
|
||||||
int backlog_size; // set a custom backlog size
|
int backlog_size; // set a custom backlog size
|
||||||
SocketOpt sockopts[SOCKET_MAX_SOCK_OPTS];
|
SocketOpt sockopts[SOCKET_MAX_SOCK_OPTS];
|
||||||
|
|
@ -536,13 +535,6 @@ typedef struct Packet {
|
||||||
uint8_t* data; // Data stored in network byte order
|
uint8_t* data; // Data stored in network byte order
|
||||||
} Packet;
|
} Packet;
|
||||||
|
|
||||||
//
|
|
||||||
typedef struct _AddressInformation * AddressInformation;
|
|
||||||
typedef struct _SocketAddress * SocketAddress;
|
|
||||||
typedef struct _SocketAddressIPv4 * SocketAddressIPv4;
|
|
||||||
typedef struct _SocketAddressIPv6 * SocketAddressIPv6;
|
|
||||||
typedef struct _SocketAddressStorage *SocketAddressStorage;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Enumerators Definition
|
// Enumerators Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -1520,14 +1512,23 @@ RLAPI AddressInformation AllocAddress();
|
||||||
RLAPI AddressInformation* AllocAddressList(int size);
|
RLAPI AddressInformation* AllocAddressList(int size);
|
||||||
|
|
||||||
// Socket API
|
// Socket API
|
||||||
RLAPI bool SocketCreate(SocketConfig *cfg, SocketResult *res);
|
RLAPI bool SocketCreate(SocketConfig *config, SocketResult* result);
|
||||||
RLAPI bool SocketBind(SocketConfig *cfg, SocketResult *res);
|
RLAPI bool SocketBind(SocketConfig *config, SocketResult* result);
|
||||||
RLAPI bool SocketListen(SocketConfig *cfg, SocketResult *res);
|
RLAPI bool SocketListen(SocketConfig *config, SocketResult* result);
|
||||||
RLAPI bool SocketConnect(SocketConfig *cfg, SocketResult *res);
|
RLAPI bool SocketConnect(SocketConfig *config, SocketResult* result);
|
||||||
RLAPI Socket *SocketAccept(Socket *server, SocketConfig *cfg);
|
RLAPI Socket *SocketAccept(Socket *server, SocketConfig *config);
|
||||||
RLAPI int SocketSend(Socket *socket, const void *datap, int len);
|
|
||||||
RLAPI int SocketReceive(Socket *socket, void *data, int maxlen, int timeout);
|
// UDP Socket API
|
||||||
RLAPI void SocketClose(SocketChannel socket);
|
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 Socket *AllocSocket();
|
||||||
RLAPI void FreeSocket(Socket **sock);
|
RLAPI void FreeSocket(Socket **sock);
|
||||||
RLAPI SocketResult *AllocSocketResult();
|
RLAPI SocketResult *AllocSocketResult();
|
||||||
|
|
|
||||||
297
src/rnet.c
297
src/rnet.c
|
|
@ -3,7 +3,7 @@
|
||||||
* rnet - A simple and easy-to-use network module for raylib
|
* rnet - A simple and easy-to-use network module for raylib
|
||||||
*
|
*
|
||||||
* FEATURES:
|
* FEATURES:
|
||||||
* - Manage network stuff
|
* - Provides a simple and (hopefully) easy to use wrapper around the Berkeley socket API
|
||||||
*
|
*
|
||||||
* DEPENDENCIES:
|
* DEPENDENCIES:
|
||||||
* raylib.h - TraceLog
|
* raylib.h - TraceLog
|
||||||
|
|
@ -93,72 +93,30 @@ static bool SocketSetNonBlocking(Socket *out);
|
||||||
static bool SocketSetOptions(SocketConfig *config, Socket *channel);
|
static bool SocketSetOptions(SocketConfig *config, Socket *channel);
|
||||||
static void *GetSocketAddressPtr(struct sockaddr *sa);
|
static void *GetSocketAddressPtr(struct sockaddr *sa);
|
||||||
static void *GetSocketPortPtr(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 IsIPv4Address(const char *ip);
|
||||||
static bool IsIPv6Address(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 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
|
// Print socket information
|
||||||
static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol)
|
static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol)
|
||||||
{
|
{
|
||||||
struct sockaddr *sockaddr_ip;
|
|
||||||
char ip[INET6_ADDRSTRLEN]; // Enough pace to hold a IPv6 string
|
|
||||||
int port;
|
|
||||||
switch (family) {
|
switch (family) {
|
||||||
case AF_UNSPEC: {
|
case AF_UNSPEC: {
|
||||||
TraceLog(LOG_DEBUG, "\tFamily: Unspecified");
|
TraceLog(LOG_DEBUG, "\tFamily: Unspecified");
|
||||||
} break;
|
} break;
|
||||||
case AF_INET: {
|
case AF_INET: {
|
||||||
TraceLog(LOG_DEBUG, "\tFamily: AF_INET (IPv4)");
|
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;
|
} break;
|
||||||
case AF_INET6: {
|
case AF_INET6: {
|
||||||
TraceLog(LOG_DEBUG, "\tFamily: AF_INET6 (IPv6)");
|
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;
|
} break;
|
||||||
case AF_NETBIOS: {
|
case AF_NETBIOS: {
|
||||||
TraceLog(LOG_DEBUG, "\tFamily: AF_NETBIOS (NetBIOS)");
|
TraceLog(LOG_DEBUG, "\tFamily: AF_NETBIOS (NetBIOS)");
|
||||||
|
|
@ -229,7 +187,7 @@ static bool IsIPv6Address(const char *ip)
|
||||||
return result != 0;
|
return result != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Return a pointer to the port from the correct address family (IPv4, or IPv6)
|
||||||
void *GetSocketPortPtr(struct sockaddr *sa)
|
void *GetSocketPortPtr(struct sockaddr *sa)
|
||||||
{
|
{
|
||||||
if (sa->sa_family == AF_INET) {
|
if (sa->sa_family == AF_INET) {
|
||||||
|
|
@ -239,7 +197,7 @@ void *GetSocketPortPtr(struct sockaddr *sa)
|
||||||
return &(((struct sockaddr_in6 *) sa)->sin6_port);
|
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)
|
void *GetSocketAddressPtr(struct sockaddr *sa)
|
||||||
{
|
{
|
||||||
if (sa->sa_family == AF_INET) {
|
if (sa->sa_family == AF_INET) {
|
||||||
|
|
@ -249,7 +207,7 @@ void *GetSocketAddressPtr(struct sockaddr *sa)
|
||||||
return &(((struct sockaddr_in6 *) sa)->sin6_addr);
|
return &(((struct sockaddr_in6 *) sa)->sin6_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Is the socket in a valid state?
|
||||||
static bool IsSocketValid(Socket *sock)
|
static bool IsSocketValid(Socket *sock)
|
||||||
{
|
{
|
||||||
if (sock != NULL) { return (sock->channel != INVALID_SOCKET); }
|
if (sock != NULL) { return (sock->channel != INVALID_SOCKET); }
|
||||||
|
|
@ -294,7 +252,7 @@ static char *SocketErrorCodeToString(int err)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Set the defaults in the supplied SocketConfig if they're not already set
|
||||||
static bool SocketSetDefaults(SocketConfig *config)
|
static bool SocketSetDefaults(SocketConfig *config)
|
||||||
{
|
{
|
||||||
if (config->backlog_size == 0) {
|
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)
|
// SocketResult* result - The results of this function (if any, including errors)
|
||||||
//
|
//
|
||||||
// e.g.
|
// e.g.
|
||||||
// SocketConfig server_cfg = { SocketConfig client_cfg = {
|
// SocketConfig server_config = { SocketConfig client_config = {
|
||||||
// .host = "127.0.0.1", .host = "127.0.0.1",
|
// .host = "127.0.0.1", .host = "127.0.0.1",
|
||||||
// .port = 8080, .port = 8080,
|
// .port = 8080, .port = 8080,
|
||||||
// .server = true, };
|
// .server = true, };
|
||||||
|
|
@ -341,7 +299,7 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
|
||||||
outresult->status = RESULT_FAILURE;
|
outresult->status = RESULT_FAILURE;
|
||||||
|
|
||||||
// Set the socket type
|
// 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
|
// Set the hints based on information in the config
|
||||||
//
|
//
|
||||||
|
|
@ -415,17 +373,31 @@ static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
|
||||||
outresult->status = RESULT_SUCCESS;
|
outresult->status = RESULT_SUCCESS;
|
||||||
outresult->socket->ready = 0;
|
outresult->socket->ready = 0;
|
||||||
outresult->socket->status = 0;
|
outresult->socket->status = 0;
|
||||||
|
if (!(config->type == SOCKET_UDP)) {
|
||||||
outresult->socket->isServer = config->server;
|
outresult->socket->isServer = config->server;
|
||||||
|
}
|
||||||
switch (res->ai_addr->sa_family) {
|
switch (res->ai_addr->sa_family) {
|
||||||
case AF_INET: {
|
case AF_INET: {
|
||||||
struct sockaddr_in *s = ((struct sockaddr_in *) res->ai_addr);
|
outresult->socket->addripv4 = (struct _SocketAddressIPv4 *) malloc(
|
||||||
outresult->socket->address.host = s->sin_addr.s_addr;
|
sizeof(*outresult->socket->addripv4));
|
||||||
outresult->socket->address.port = s->sin_port;
|
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;
|
} break;
|
||||||
case AF_INET6: {
|
case AF_INET6: {
|
||||||
struct sockaddr_in6 *s = ((struct sockaddr_in6 *) res->ai_addr);
|
outresult->socket->addripv6 = (struct _SocketAddressIPv6 *) malloc(
|
||||||
outresult->socket->address.host = s->sin6_addr.s6_addr;
|
sizeof(*outresult->socket->addripv6));
|
||||||
outresult->socket->address.port = s->sin6_port;
|
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;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -486,17 +458,17 @@ static bool SocketSetOptions(SocketConfig *config, Socket *sock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set "hints" in an addrinfo struct, to be passed to getaddrinfo.
|
// 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));
|
memset(hints, 0, sizeof(*hints));
|
||||||
|
|
||||||
// Check if the ip supplied in the config is a valid ipv4 ip ipv6 address
|
// 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_family = AF_INET;
|
||||||
hints->ai_flags |= AI_NUMERICHOST;
|
hints->ai_flags |= AI_NUMERICHOST;
|
||||||
} else {
|
} else {
|
||||||
if (IsIPv6Address(cfg->host)) {
|
if (IsIPv6Address(config->host)) {
|
||||||
hints->ai_family = AF_INET6;
|
hints->ai_family = AF_INET6;
|
||||||
hints->ai_flags |= AI_NUMERICHOST;
|
hints->ai_flags |= AI_NUMERICHOST;
|
||||||
} else {
|
} 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;
|
hints->ai_socktype = SOCK_DGRAM;
|
||||||
} else {
|
} else {
|
||||||
hints->ai_socktype = SOCK_STREAM;
|
hints->ai_socktype = SOCK_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set passive unless UDP client
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -638,8 +612,8 @@ void ResolveIP(const char *ip, const char *port, int flags, char *host, char *se
|
||||||
// const char* address = "127.0.0.1" (local address)
|
// const char* address = "127.0.0.1" (local address)
|
||||||
// const char* port = "80"
|
// const char* port = "80"
|
||||||
//
|
//
|
||||||
// returns:
|
// Returns:
|
||||||
// the total amount of addresses found
|
// The total amount of addresses found, -1 on error
|
||||||
//
|
//
|
||||||
int ResolveHost(const char *address, const char *port, AddressInformation *addrlist)
|
int ResolveHost(const char *address, const char *port, AddressInformation *addrlist)
|
||||||
{
|
{
|
||||||
|
|
@ -681,7 +655,7 @@ int ResolveHost(const char *address, const char *port, AddressInformation *addrl
|
||||||
// Validate the size is > 0, otherwise return
|
// Validate the size is > 0, otherwise return
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
TraceLog(LOG_WARNING, "Error, no addresses found.");
|
TraceLog(LOG_WARNING, "Error, no addresses found.");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamically allocate an array of address information structs
|
// Dynamically allocate an array of address information structs
|
||||||
|
|
@ -736,7 +710,7 @@ int ResolveHost(const char *address, const char *port, AddressInformation *addrl
|
||||||
// SocketResult* result - The results of this function (if any, including errors)
|
// SocketResult* result - The results of this function (if any, including errors)
|
||||||
//
|
//
|
||||||
// e.g.
|
// e.g.
|
||||||
// SocketConfig server_cfg = { SocketConfig client_cfg = {
|
// SocketConfig server_config = { SocketConfig client_config = {
|
||||||
// .host = "127.0.0.1", .host = "127.0.0.1",
|
// .host = "127.0.0.1", .host = "127.0.0.1",
|
||||||
// .port = 8080, .port = 8080,
|
// .port = 8080, .port = 8080,
|
||||||
// .server = true, };
|
// .server = true, };
|
||||||
|
|
@ -776,6 +750,7 @@ bool SocketBind(SocketConfig *config, SocketResult *result)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
result->status = RESULT_FAILURE;
|
result->status = RESULT_FAILURE;
|
||||||
|
struct sockaddr_storage *sock_addr = NULL;
|
||||||
|
|
||||||
// Don't bind to a socket that isn't configured as a server
|
// Don't bind to a socket that isn't configured as a server
|
||||||
if (!IsSocketValid(result->socket) || !config->server) {
|
if (!IsSocketValid(result->socket) || !config->server) {
|
||||||
|
|
@ -784,27 +759,21 @@ bool SocketBind(SocketConfig *config, SocketResult *result)
|
||||||
success = false;
|
success = false;
|
||||||
} else {
|
} else {
|
||||||
if (IsIPv4Address(config->host)) {
|
if (IsIPv4Address(config->host)) {
|
||||||
struct sockaddr_in ip4addr;
|
struct sockaddr_in ipv4addr;
|
||||||
ip4addr.sin_family = AF_INET;
|
ipv4addr.sin_family = AF_INET;
|
||||||
ip4addr.sin_port = config->port;
|
ipv4addr.sin_port = config->port;
|
||||||
inet_pton(AF_INET, config->host, &ip4addr.sin_addr);
|
inet_pton(AF_INET, config->host, &ipv4addr.sin_addr);
|
||||||
if (bind(result->socket->channel, (struct sockaddr *) &ip4addr, sizeof(ip4addr)) != SOCKET_ERROR) {
|
sock_addr = (struct sockaddr_storage *) &ipv4addr;
|
||||||
TraceLog(LOG_INFO, "Successfully bound socket.");
|
|
||||||
success = true;
|
|
||||||
} else {
|
|
||||||
result->socket->status = SocketGetLastError();
|
|
||||||
TraceLog(LOG_WARNING, "Socket Error: %s",
|
|
||||||
SocketErrorCodeToString(result->socket->status));
|
|
||||||
SocketSetLastError(0);
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (IsIPv6Address(config->host)) {
|
if (IsIPv6Address(config->host)) {
|
||||||
struct sockaddr_in6 ip6addr;
|
struct sockaddr_in6 ipv6addr;
|
||||||
ip6addr.sin6_family = AF_INET6;
|
ipv6addr.sin6_family = AF_INET6;
|
||||||
ip6addr.sin6_port = config->port;
|
ipv6addr.sin6_port = config->port;
|
||||||
inet_pton(AF_INET6, config->host, &ip6addr.sin6_addr);
|
inet_pton(AF_INET6, config->host, &ipv6addr.sin6_addr);
|
||||||
if (bind(result->socket->channel, (struct sockaddr *) &ip6addr, sizeof(ip6addr)) != SOCKET_ERROR) {
|
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.");
|
TraceLog(LOG_INFO, "Successfully bound socket.");
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -815,13 +784,19 @@ bool SocketBind(SocketConfig *config, SocketResult *result)
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
// Was the bind a success?
|
// Was the bind a success?
|
||||||
if (success) {
|
if (success) {
|
||||||
result->status = RESULT_SUCCESS;
|
result->status = RESULT_SUCCESS;
|
||||||
result->socket->ready = 0;
|
result->socket->ready = 0;
|
||||||
result->socket->status = 0;
|
result->socket->status = 0;
|
||||||
|
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;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
@ -839,13 +814,17 @@ bool SocketListen(SocketConfig *config, SocketResult *result)
|
||||||
success = false;
|
success = false;
|
||||||
} else {
|
} else {
|
||||||
// Don't listen on UDP sockets
|
// Don't listen on UDP sockets
|
||||||
if (!config->datagram) {
|
if (!(config->type == SOCKET_UDP)) {
|
||||||
if (listen(result->socket->channel, config->backlog_size) != SOCKET_ERROR) {
|
if (listen(result->socket->channel, config->backlog_size) != SOCKET_ERROR) {
|
||||||
TraceLog(LOG_INFO, "Started listening on socket...");
|
TraceLog(LOG_INFO, "Started listening on socket...");
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
success = false;
|
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;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Connect the socket to the destination specified by "host" and "port" in SocketConfig
|
||||||
bool SocketConnect(SocketConfig *config, SocketResult *result)
|
bool SocketConnect(SocketConfig *config, SocketResult *result)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
@ -966,7 +945,6 @@ Socket *SocketAccept(Socket *server, SocketConfig *config)
|
||||||
struct sockaddr_storage sock_addr;
|
struct sockaddr_storage sock_addr;
|
||||||
socklen_t sock_alen;
|
socklen_t sock_alen;
|
||||||
Socket * sock;
|
Socket * sock;
|
||||||
int sock_port;
|
|
||||||
sock = AllocSocket();
|
sock = AllocSocket();
|
||||||
server->ready = 0;
|
server->ready = 0;
|
||||||
sock_alen = sizeof(sock_addr);
|
sock_alen = sizeof(sock_addr);
|
||||||
|
|
@ -985,22 +963,92 @@ Socket *SocketAccept(Socket *server, SocketConfig *config)
|
||||||
switch (sock_addr.ss_family) {
|
switch (sock_addr.ss_family) {
|
||||||
case AF_INET: {
|
case AF_INET: {
|
||||||
struct sockaddr_in *s = ((struct sockaddr_in *) &sock_addr);
|
struct sockaddr_in *s = ((struct sockaddr_in *) &sock_addr);
|
||||||
sock->address.host = s->sin_addr.s_addr;
|
sock->addripv4 = (struct _SocketAddressIPv4 *) malloc(sizeof(*sock->addripv4));
|
||||||
sock->address.port = s->sin_port;
|
if (sock->addripv4 != NULL) {
|
||||||
TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString(s),
|
memset(sock->addripv4, 0, sizeof(*sock->addripv4));
|
||||||
ntohs(sock->address.port));
|
}
|
||||||
|
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;
|
} break;
|
||||||
case AF_INET6: {
|
case AF_INET6: {
|
||||||
struct sockaddr_in6 *s = ((struct sockaddr_in6 *) &sock_addr);
|
struct sockaddr_in6 *s = ((struct sockaddr_in6 *) &sock_addr);
|
||||||
sock->address.host = s->sin6_addr.s6_addr;
|
sock->addripv6 = (struct _SocketAddressIPv6 *) malloc(sizeof(*sock->addripv6));
|
||||||
sock->address.port = s->sin6_port;
|
if (sock->addripv6 != NULL) {
|
||||||
TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString(s),
|
memset(sock->addripv6, 0, sizeof(*sock->addripv6));
|
||||||
ntohs(sock->address.port));
|
}
|
||||||
|
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;
|
} break;
|
||||||
}
|
}
|
||||||
return sock;
|
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'
|
// Send 'len' bytes of 'data' over the non-server socket 'sock'
|
||||||
//
|
//
|
||||||
// Example
|
// Example
|
||||||
|
|
@ -1045,12 +1093,16 @@ int SocketSend(Socket *sock, const void *datap, int length)
|
||||||
return sent;
|
return sent;
|
||||||
} break;
|
} break;
|
||||||
case SOCKET_UDP: {
|
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);
|
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) {
|
if (sent >= 0) {
|
||||||
sock->status = status;
|
sock->status = status;
|
||||||
++numsent;
|
++numsent;
|
||||||
|
|
@ -1135,12 +1187,33 @@ int SocketReceive(Socket *sock, void *data, int maxlen, int timeout)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Does the socket have it's 'ready' flag set?
|
||||||
bool IsSocketReady(Socket *sock)
|
bool IsSocketReady(Socket *sock)
|
||||||
{
|
{
|
||||||
return (sock != NULL) && (sock->ready);
|
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)
|
bool IsSocketConnected(Socket *sock)
|
||||||
{
|
{
|
||||||
#if PLATFORM_WINDOWS
|
#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 {
|
do {
|
||||||
SocketSetLastError(0);
|
SocketSetLastError(0);
|
||||||
|
|
||||||
/* Set up the mask of file descriptors */
|
// Set up the mask of file descriptors
|
||||||
FD_ZERO(&mask);
|
FD_ZERO(&mask);
|
||||||
for (i = set->numsockets - 1; i >= 0; --i) {
|
for (i = set->numsockets - 1; i >= 0; --i) {
|
||||||
FD_SET(set->sockets[i]->channel, &mask);
|
FD_SET(set->sockets[i]->channel, &mask);
|
||||||
} /* Set up the timeout */
|
} // Set up the timeout
|
||||||
tv.tv_sec = timeout / 1000;
|
tv.tv_sec = timeout / 1000;
|
||||||
tv.tv_usec = (timeout % 1000) * 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);
|
retval = select(maxfd + 1, &mask, NULL, NULL, &tv);
|
||||||
} while (SocketGetLastError() == WSAEINTR);
|
} while (SocketGetLastError() == WSAEINTR);
|
||||||
|
|
||||||
/* Mark all file descriptors ready that have data available */
|
// Mark all file descriptors ready that have data available
|
||||||
if (retval > 0) {
|
if (retval > 0) {
|
||||||
for (i = set->numsockets - 1; i >= 0; --i) {
|
for (i = set->numsockets - 1; i >= 0; --i) {
|
||||||
if (FD_ISSET(set->sockets[i]->channel, &mask)) {
|
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
|
// 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
|
#ifdef WIN32
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
#endif
|
#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
|
#ifndef RESULT_SUCCESS
|
||||||
# define RESULT_SUCCESS 0
|
# define RESULT_SUCCESS 0
|
||||||
#endif // RESULT_SUCCESS
|
#endif // RESULT_SUCCESS
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user