More socket API changes
This commit is contained in:
parent
4c9057cec2
commit
97d01fe36d
|
|
@ -1,62 +1,72 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* 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) 2014 Ramon Santamaria (@raysan5)
|
|
||||||
*
|
|
||||||
********************************************************************************************/
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
using namespace std;
|
||||||
|
|
||||||
|
typedef struct room
|
||||||
{
|
{
|
||||||
// Initialization
|
int x = 0;
|
||||||
//--------------------------------------------------------------------------------------
|
int y = 0;
|
||||||
|
int width = 10;
|
||||||
|
int height = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
room Temp_Rect_Creat()
|
||||||
|
{
|
||||||
|
room in_creation;
|
||||||
|
|
||||||
|
in_creation.x = int(rand() % 700);
|
||||||
|
in_creation.y = int(rand() % 400);
|
||||||
|
|
||||||
|
in_creation.width = int(rand() % 50);
|
||||||
|
if (in_creation.width < 10) in_creation.width = 10;
|
||||||
|
in_creation.height = int(rand() % 70);
|
||||||
|
if (in_creation.height < 10) in_creation.height = 10;
|
||||||
|
|
||||||
|
return in_creation;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
|
vector<room> rooms;
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input");
|
||||||
|
|
||||||
|
Vector2 ballPosition = { (float)screenWidth / 2, (float)screenHeight / 2 };
|
||||||
|
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Main game loop
|
int i = 0;
|
||||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
while (i < 20)
|
||||||
{
|
{
|
||||||
// Update
|
room temp = Temp_Rect_Creat();
|
||||||
//----------------------------------------------------------------------------------
|
rooms.push_back(temp);
|
||||||
// TODO: Update your variables here
|
i++;
|
||||||
//----------------------------------------------------------------------------------
|
}
|
||||||
|
|
||||||
// Draw
|
while (!WindowShouldClose())
|
||||||
//----------------------------------------------------------------------------------
|
{
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
for (int i = 0; i < rooms.size(); i++)
|
||||||
|
{
|
||||||
EndDrawing();
|
DrawRectangle(rooms[i].x, rooms[i].y, rooms[i].width, rooms[i].height, BLACK);
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-Initialization
|
EndDrawing();
|
||||||
//--------------------------------------------------------------------------------------
|
}
|
||||||
CloseWindow(); // Close window and OpenGL context
|
|
||||||
//--------------------------------------------------------------------------------------
|
CloseWindow();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
|
#define MYPORT "4950"
|
||||||
|
#define MAXBUFLEN 100
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
|
|
@ -37,25 +36,41 @@ int main()
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Server socket and address
|
// Create the server
|
||||||
AddressInformation serveraddr;
|
SocketConfig server_cfg = {
|
||||||
Socket server;
|
.host = "127.0.0.1",
|
||||||
server.blocking = false;
|
.port = 8080,
|
||||||
ResolveHost(&serveraddr, "localhost", "3490", SOCKET_TCP);
|
.server = true,
|
||||||
|
.nonblocking = true,
|
||||||
|
};
|
||||||
|
|
||||||
CreateSocket(&server, serveraddr);
|
SocketResult server_res;
|
||||||
BindSocket(server, serveraddr);
|
memset(&server_res, 0, sizeof(SocketResult));
|
||||||
ListenSocket(server);
|
{
|
||||||
|
bool ok = SocketOpen(&server_cfg, &server_res);
|
||||||
|
if (!ok) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
// Client socket and address
|
// Create the client
|
||||||
AddressInformation clientaddr;
|
SocketConfig client_cfg = {
|
||||||
Socket client;
|
.host = "127.0.0.1",
|
||||||
client.blocking = false;
|
.port = 8080,
|
||||||
ResolveHost(&clientaddr, "localhost", "3490", SOCKET_TCP);
|
};
|
||||||
CreateSocket(&client, clientaddr);
|
|
||||||
ConnectSocket(client, clientaddr);
|
|
||||||
|
|
||||||
Socket connection; // The socket connection between server->client
|
SocketResult client_res;
|
||||||
|
memset(&client_res, 0, sizeof(SocketResult));
|
||||||
|
{
|
||||||
|
bool ok = SocketOpen(&client_cfg, &client_res);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
printf("failed to open: status %d, errno %d\n",
|
||||||
|
client_res.status, client_res.saved_errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketResult connection;
|
||||||
|
memset(&connection, 0, sizeof(SocketResult));
|
||||||
float elapsed = 0.0f, delay = 1.0f; // ms
|
float elapsed = 0.0f, delay = 1.0f; // ms
|
||||||
bool ping = false, pong = false;
|
bool ping = false, pong = false;
|
||||||
char recvBuffer[512];
|
char recvBuffer[512];
|
||||||
|
|
@ -74,15 +89,17 @@ int main()
|
||||||
// A valid connection will != -1
|
// A valid connection will != -1
|
||||||
if (!connected)
|
if (!connected)
|
||||||
{
|
{
|
||||||
AcceptSocket(server, &connection);
|
if (SocketAccept(server_res.socket.handle, &connection))
|
||||||
|
{
|
||||||
ping = true;
|
ping = true;
|
||||||
connected = true;
|
connected = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Connected
|
// Connected
|
||||||
if (connected)
|
if (connected)
|
||||||
{
|
{
|
||||||
int bytesRecv = ReceiveTCP(connection.handle, recvBuffer, 5);
|
int bytesRecv = SocketReceive(&connection.socket, recvBuffer, 5);
|
||||||
if (bytesRecv > 0)
|
if (bytesRecv > 0)
|
||||||
{
|
{
|
||||||
if (strcmp(recvBuffer, "Ping!") == 0)
|
if (strcmp(recvBuffer, "Ping!") == 0)
|
||||||
|
|
@ -103,12 +120,12 @@ int main()
|
||||||
if (ping)
|
if (ping)
|
||||||
{
|
{
|
||||||
ping = false;
|
ping = false;
|
||||||
SendTCP(client.handle, "Ping!", 5);
|
SocketSend(&client_res.socket, "Ping!", 5);
|
||||||
}
|
}
|
||||||
else if (pong)
|
else if (pong)
|
||||||
{
|
{
|
||||||
pong = false;
|
pong = false;
|
||||||
SendTCP(client.handle, "Pong!", 5);
|
SocketSend(&client_res.socket, "Pong!", 5);
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,67 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* 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 <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef struct room {
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int width = 10;
|
||||||
|
int height = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
room Temp_Rect_Creat() {
|
||||||
|
room in_creation;
|
||||||
|
|
||||||
|
in_creation.x = int (rand() % 700);
|
||||||
|
in_creation.y = int (rand() % 400);
|
||||||
|
|
||||||
|
in_creation.width = int(rand() % 50);
|
||||||
|
if (in_creation.width < 10) in_creation.width = 10;
|
||||||
|
in_creation.height = int(rand() % 70);
|
||||||
|
if (in_creation.height < 10) in_creation.height = 10;
|
||||||
|
|
||||||
|
return in_creation;
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Initialization
|
srand(time(NULL));
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
|
vector<room> rooms;
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input");
|
||||||
|
|
||||||
|
Vector2 ballPosition = { (float)screenWidth / 2, (float)screenHeight / 2 };
|
||||||
|
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Main game loop
|
int i = 0;
|
||||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
while (i < 20) {
|
||||||
|
room temp = Temp_Rect_Creat();
|
||||||
|
rooms.push_back(temp);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!WindowShouldClose())
|
||||||
{
|
{
|
||||||
// Update
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// TODO: Update your variables here
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Draw
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
for (int i = 0; i < rooms.size(); i++) {
|
||||||
|
DrawRectangle(rooms[i].x, rooms[i].y, rooms[i].width, rooms[i].height, BLACK);
|
||||||
EndDrawing();
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-Initialization
|
EndDrawing();
|
||||||
//--------------------------------------------------------------------------------------
|
}
|
||||||
CloseWindow(); // Close window and OpenGL context
|
|
||||||
//--------------------------------------------------------------------------------------
|
CloseWindow();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
200
src/raylib.h
200
src/raylib.h
|
|
@ -100,10 +100,12 @@
|
||||||
// Network limits
|
// Network limits
|
||||||
#define MAX_SOCKET_SET_SIZE 32
|
#define MAX_SOCKET_SET_SIZE 32
|
||||||
#define MAX_SOCKET_QUEUE_SIZE 16
|
#define MAX_SOCKET_QUEUE_SIZE 16
|
||||||
#define MAX_HOST_NAME_SIZE NI_MAXHOST
|
#define MAX_HOST_NAME_SIZE 1025
|
||||||
#define MAX_SERV_NAME_SIZE NI_MAXSERV
|
#define MAX_SERV_NAME_SIZE 32
|
||||||
#define MAX_IPV4_NAME_SIZE INET6_ADDRSTRLEN
|
#define MAX_IPV4_NAME_SIZE 22
|
||||||
#define MAX_IPV6_NAME_SIZE INET_ADDRSTRLEN
|
#define MAX_IPV6_NAME_SIZE 65
|
||||||
|
|
||||||
|
#define MAX_SOCK_OPTS 4
|
||||||
|
|
||||||
// NOTE: MSC C++ compiler does not support compound literals (C99 feature)
|
// NOTE: MSC C++ compiler does not support compound literals (C99 feature)
|
||||||
// Plain structures in C++ (without constructors) can be initialized from { } initializers.
|
// Plain structures in C++ (without constructors) can be initialized from { } initializers.
|
||||||
|
|
@ -431,31 +433,10 @@ typedef struct VrStereoConfig {
|
||||||
|
|
||||||
typedef struct IPAddress
|
typedef struct IPAddress
|
||||||
{
|
{
|
||||||
int family;
|
unsigned char* host; /* 32-bit IPv4 host address */
|
||||||
union {
|
unsigned char* port; /* 16-bit protocol port */
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned int host; /* 32-bit IPv4 host address */
|
|
||||||
unsigned short port; /* 16-bit protocol port */
|
|
||||||
} ip4;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned char host[16]; /* 128-bit IPv6 host address */
|
|
||||||
} ip6;
|
|
||||||
} data;
|
|
||||||
} IPAddress;
|
} IPAddress;
|
||||||
|
|
||||||
typedef struct IPv4address
|
|
||||||
{
|
|
||||||
unsigned int host; /* 32-bit IPv4 host address */
|
|
||||||
unsigned short port; /* 16-bit protocol port */
|
|
||||||
} IPv4address;
|
|
||||||
|
|
||||||
typedef struct IPv6address
|
|
||||||
{
|
|
||||||
unsigned char bytes[16]; /* 128-bit IPv6 host address */
|
|
||||||
} IPv6address;
|
|
||||||
|
|
||||||
typedef struct AddressInformation
|
typedef struct AddressInformation
|
||||||
{
|
{
|
||||||
int flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
|
int flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
|
||||||
|
|
@ -474,60 +455,93 @@ typedef struct SocketAddress
|
||||||
char data[14]; // Up to 14 bytes of direct address.
|
char data[14]; // Up to 14 bytes of direct address.
|
||||||
} SocketAddress;
|
} SocketAddress;
|
||||||
|
|
||||||
// Socket
|
/* An option ID, value, sizeof(value) tuple for setsockopt(2). */
|
||||||
|
typedef struct SocketOpt {
|
||||||
|
int option_id;
|
||||||
|
void *value;
|
||||||
|
int value_len;
|
||||||
|
} SocketOpt;
|
||||||
|
|
||||||
typedef struct Socket
|
typedef struct Socket
|
||||||
{
|
{
|
||||||
int ready;
|
int ready;
|
||||||
SocketHandle handle;
|
SocketHandle handle;
|
||||||
IPv4address address;
|
IPAddress remoteAddress;
|
||||||
bool blocking;
|
IPAddress localAddress;
|
||||||
// int ready;
|
int sflag;
|
||||||
// SocketHandle handle;
|
|
||||||
// IPAddress address;
|
|
||||||
// bool blocking;
|
|
||||||
} Socket;
|
} Socket;
|
||||||
|
|
||||||
|
/* Configuration for a socket. Not all of these fields need to
|
||||||
|
* be set, and ones omitted from a C99-style "designated initializer"
|
||||||
|
* struct literal will be zeroed out and replaced with defaults. */
|
||||||
|
typedef struct SocketConfig {
|
||||||
|
/* Hostname and port, for TCP or UDP sockets. */
|
||||||
|
char *host;
|
||||||
|
int port;
|
||||||
|
|
||||||
//typedef struct UDPSocket
|
/* Path, for Unix domain socket. */
|
||||||
//{
|
char *path;
|
||||||
// int ready;
|
|
||||||
// SocketHandle handle;
|
|
||||||
// IPAddress address;
|
|
||||||
// bool blocking;
|
|
||||||
//} UDPSocket;
|
|
||||||
//
|
|
||||||
//typedef struct UDPPacket
|
|
||||||
//{
|
|
||||||
// int channel; /* The src/dst channel of the packet */
|
|
||||||
// char * data; /* The packet data */
|
|
||||||
// int len; /* The length of the packet data */
|
|
||||||
// int maxlen; /* The size of the data buffer */
|
|
||||||
// int status; /* packet status after sending */
|
|
||||||
// IPAddress address; /* The source/dest address of an incoming/outgoing packet */
|
|
||||||
//} UDPPacket;
|
|
||||||
//
|
|
||||||
//typedef struct TCPSocket
|
|
||||||
//{
|
|
||||||
// int ready;
|
|
||||||
// SocketHandle channel;
|
|
||||||
// IPAddress remoteAddress;
|
|
||||||
// IPAddress localAddress;
|
|
||||||
// bool isServer;
|
|
||||||
// bool blocking;
|
|
||||||
//} TCPSocket;
|
|
||||||
//
|
|
||||||
//typedef struct TCPPacket
|
|
||||||
//{
|
|
||||||
// const void *data; /* The packet data */
|
|
||||||
// int len; /* The length of the packet data */
|
|
||||||
// int maxlen; /* The size of the data buffer */
|
|
||||||
//} TCPPacket;
|
|
||||||
|
|
||||||
typedef struct SocketSet
|
/* IPv4 or IPv6 address; if neither is specified, let OS decide.
|
||||||
{
|
* These fields should be used in place of 'host' above. */
|
||||||
Socket *sockets[MAX_SOCKET_SET_SIZE];
|
char *IPv4;
|
||||||
} SocketSet;
|
char *IPv6;
|
||||||
|
|
||||||
|
bool server; /* Listen for incoming clients? */
|
||||||
|
bool datagram; /* UDP or datagram Unix domain? */
|
||||||
|
bool nonblocking; /* non-blocking operation? */
|
||||||
|
|
||||||
|
int backlog_size; /* set a custom backlog size */
|
||||||
|
|
||||||
|
SocketOpt sockopts[MAX_SOCK_OPTS];
|
||||||
|
} SocketConfig;
|
||||||
|
|
||||||
|
enum SocketStatus {
|
||||||
|
|
||||||
|
/* Socket created. */
|
||||||
|
SOCKET_OK = 0,
|
||||||
|
|
||||||
|
/* Failures from socket API functions; most also save errno. */
|
||||||
|
SOCKET_ERROR_GETADDRINFO = -1,
|
||||||
|
SOCKET_ERROR_SOCKET = -2,
|
||||||
|
SOCKET_ERROR_BIND = -3,
|
||||||
|
SOCKET_ERROR_LISTEN = -4,
|
||||||
|
SOCKET_ERROR_CONNECT = -5,
|
||||||
|
SOCKET_ERROR_FCNTL = -6,
|
||||||
|
SOCKET_ERROR_ACCEPT = -7,
|
||||||
|
SOCKET_ERROR_SEND = -8,
|
||||||
|
|
||||||
|
/* Failure from snprintf: name too long. */
|
||||||
|
SOCKET_ERROR_SNPRINTF = -100,
|
||||||
|
|
||||||
|
/* Invalid combination of options in configuration. */
|
||||||
|
SOCKET_ERROR_CONFIGURATION = -200,
|
||||||
|
|
||||||
|
/* Error in setsockopt(2). */
|
||||||
|
SOCKET_ERROR_SETSOCKOPT = -300,
|
||||||
|
|
||||||
|
/* Other unknown error. */
|
||||||
|
SOCKET_ERROR_UNKNOWN = -400,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Result from calling open with a given config. */
|
||||||
|
typedef struct SocketResult {
|
||||||
|
/* Result code and errno value from failure (if any). */
|
||||||
|
enum SocketStatus status;
|
||||||
|
|
||||||
|
/* File descriptor, set if status is SOCKET99_OK (success). */
|
||||||
|
Socket socket;
|
||||||
|
|
||||||
|
/* Address information populated from getaddrinfo() */
|
||||||
|
AddressInformation addrinfo;
|
||||||
|
|
||||||
|
/* Error code from socket(2), bind(2), etc. */
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
/* Error code from getaddrinfo, only set if status is
|
||||||
|
* SOCKET99_ERROR_GETADDRINFO. See: gai_strerror(3). */
|
||||||
|
int getaddrinfo_error;
|
||||||
|
} SocketResult;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Enumerators Definition
|
// Enumerators Definition
|
||||||
|
|
@ -539,12 +553,6 @@ typedef enum
|
||||||
SOCKET_UDP = 2 // SOCK_DGRAM
|
SOCKET_UDP = 2 // SOCK_DGRAM
|
||||||
} SocketType;
|
} SocketType;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
FAMILY_IPv4 = 1,
|
|
||||||
FAMILY_IPv6 = 2
|
|
||||||
} AddressFamily;
|
|
||||||
|
|
||||||
// System config flags
|
// System config flags
|
||||||
// NOTE: Used for bit masks
|
// NOTE: Used for bit masks
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
@ -1498,24 +1506,35 @@ RLAPI void StopAudioStream(AudioStream stream); // Stop au
|
||||||
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
||||||
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
||||||
|
|
||||||
// Network functions
|
//------------------------------------------------------------------------------------
|
||||||
|
// Network (Module: network)
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
|
||||||
RLAPI bool InitNetwork(void);
|
RLAPI bool InitNetwork(void);
|
||||||
RLAPI void CloseNetwork(void);
|
RLAPI void CloseNetwork(void);
|
||||||
|
|
||||||
|
// Resolution
|
||||||
RLAPI void ResolveHost(AddressInformation *outaddr, const char *address, const char *port, SocketType socketType);
|
RLAPI void ResolveHost(AddressInformation *outaddr, const char *address, const char *port, SocketType socketType);
|
||||||
RLAPI char *ResolveIP(const char *host, const char *port);
|
RLAPI char *ResolveIP(const char *host, const char *port);
|
||||||
RLAPI bool IsIPv4Address(const char *host);
|
|
||||||
RLAPI bool IsIPv6Address(const char *host);
|
// IP
|
||||||
RLAPI int GetIPFamily(const char *host);
|
|
||||||
RLAPI void GetLocalAddresses();
|
RLAPI void GetLocalAddresses();
|
||||||
RLAPI bool CreateSocket(Socket *socket, AddressInformation outaddr);
|
|
||||||
RLAPI bool BindSocket(Socket socket, const AddressInformation addr);
|
// Socket API
|
||||||
RLAPI bool ConnectSocket(Socket socket, const AddressInformation addr);
|
RLAPI bool SocketOpen(SocketConfig *cfg, SocketResult *res);
|
||||||
RLAPI bool ListenSocket(Socket socket);
|
RLAPI void SocketClose(SocketHandle socket);
|
||||||
RLAPI void CloseSocket(Socket *socket);
|
RLAPI bool SocketAccept(SocketHandle listener, SocketResult* res);
|
||||||
RLAPI void AcceptSocket(Socket listenSock, Socket *newSock);
|
RLAPI int SocketSend(Socket* socket, const void *datap, int len);
|
||||||
|
RLAPI int SocketReceive(Socket* socket, void *data, int maxlen);
|
||||||
|
RLAPI int SocketGetError(char *buf, int buf_size, SocketResult *res);
|
||||||
|
RLAPI void SocketPrintError(SocketResult *res);
|
||||||
|
RLAPI void SocketSetHints(SocketConfig *cfg, AddressInformation *hints);
|
||||||
|
|
||||||
|
// Print methods
|
||||||
RLAPI char *SocketAddressToString(SocketAddress *sockaddr, char buffer[]);
|
RLAPI char *SocketAddressToString(SocketAddress *sockaddr, char buffer[]);
|
||||||
RLAPI void PrintSocket(SocketAddress *addr, const int family, const int socktype, const int protocol);
|
RLAPI void PrintSocket(SocketAddress *addr, const int family, const int socktype, const int protocol);
|
||||||
|
|
||||||
|
// Network conversion methods
|
||||||
RLAPI unsigned int PackData(unsigned char *buf, char *format, ...);
|
RLAPI unsigned int PackData(unsigned char *buf, char *format, ...);
|
||||||
RLAPI void UnpackData(unsigned char *buf, char *format, ...);
|
RLAPI void UnpackData(unsigned char *buf, char *format, ...);
|
||||||
RLAPI unsigned short HostToNetworkShort(unsigned short value); // 2 bytes - 0 to 65,535
|
RLAPI unsigned short HostToNetworkShort(unsigned short value); // 2 bytes - 0 to 65,535
|
||||||
|
|
@ -1528,11 +1547,6 @@ RLAPI unsigned long NetworkToHostLong(unsigned long value); // 4 byte - 0 to 4,2
|
||||||
RLAPI float NetworkToHostFloat(unsigned int value); // 4 byte - 1.2E-38 to 3.4E+38
|
RLAPI float NetworkToHostFloat(unsigned int value); // 4 byte - 1.2E-38 to 3.4E+38
|
||||||
RLAPI double NetworkToHostDouble(unsigned long long value); // 8 byte - 2.3E-308 to 1.7E+308
|
RLAPI double NetworkToHostDouble(unsigned long long value); // 8 byte - 2.3E-308 to 1.7E+308
|
||||||
RLAPI unsigned long long NetworkToHostLongLong(unsigned long long value); // 8 byte - 0 to 1.8446744073709551615 × 10^19
|
RLAPI unsigned long long NetworkToHostLongLong(unsigned long long value); // 8 byte - 0 to 1.8446744073709551615 × 10^19
|
||||||
RLAPI void CreateListenServer(Socket *socket, const char *address, const int port, SocketType socketType);
|
|
||||||
RLAPI void CreateClient(Socket *socket, const char *address, const char *port, SocketType socketType);
|
|
||||||
RLAPI int Send(SocketHandle sockfd, const char *data, int len);
|
|
||||||
RLAPI int Receive(SocketHandle sockfd, const char *data, int len);
|
|
||||||
RLAPI void ResetSocket(Socket *socket);
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
805
src/rnet.c
805
src/rnet.c
|
|
@ -38,6 +38,7 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Check if config flags have been externally provided on compilation line
|
// Check if config flags have been externally provided on compilation line
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
||||||
# include "config.h" // Defines module configuration flags
|
# include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -47,8 +48,8 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
#include "sysnet.h"
|
|
||||||
#include "rpack.h"
|
#include "rpack.h"
|
||||||
|
#include "sysnet.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module defines
|
// Module defines
|
||||||
|
|
@ -58,6 +59,234 @@
|
||||||
# define errno WSAGetLastError() // Support UNIX socket error codes
|
# define errno WSAGetLastError() // Support UNIX socket error codes
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DEF_BACKLOG_SIZE SOMAXCONN
|
||||||
|
#define PORT_STR_BUFSZ 6
|
||||||
|
|
||||||
|
static bool SocketSetDefaults(SocketConfig *cfg);
|
||||||
|
static bool CreateSocket(SocketConfig *cfg, SocketResult *out);
|
||||||
|
static bool SocketSetNonBlocking(SocketResult *out);
|
||||||
|
static bool SocketSetOptions(SocketConfig *cfg,
|
||||||
|
SocketResult *out, int fd);
|
||||||
|
static const char *SocketStatusToString(enum SocketStatus s);
|
||||||
|
|
||||||
|
/* Static network API methods */
|
||||||
|
|
||||||
|
static void SocketSetError(int err)
|
||||||
|
{
|
||||||
|
#if PLATFORM == PLATFORM_WINDOWS
|
||||||
|
WSASetLastError(err);
|
||||||
|
#else
|
||||||
|
errno = err;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SocketGetLastError()
|
||||||
|
{
|
||||||
|
#if PLATFORM == PLATFORM_WINDOWS
|
||||||
|
return WSAGetLastError();
|
||||||
|
#else
|
||||||
|
return errno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SocketSetDefaults(SocketConfig *cfg)
|
||||||
|
{
|
||||||
|
if (cfg->backlog_size == 0) { cfg->backlog_size = DEF_BACKLOG_SIZE; }
|
||||||
|
|
||||||
|
/* Screen out contradictory settings */
|
||||||
|
if (cfg->IPv6 && cfg->IPv4) { return false; }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SocketStatusToError(SocketResult *out, enum SocketStatus status)
|
||||||
|
{
|
||||||
|
out->status = status;
|
||||||
|
out->saved_errno = SocketGetLastError();
|
||||||
|
SocketSetError(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CreateSocket(SocketConfig *cfg, SocketResult *out)
|
||||||
|
{
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *res = NULL;
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
char port_str[PORT_STR_BUFSZ];
|
||||||
|
memset(port_str, 0, PORT_STR_BUFSZ);
|
||||||
|
|
||||||
|
SocketSetHints(cfg, &hints);
|
||||||
|
|
||||||
|
if (PORT_STR_BUFSZ < snprintf(port_str, PORT_STR_BUFSZ,
|
||||||
|
"%u", cfg->port))
|
||||||
|
{
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_SNPRINTF);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct addrinfo *ai = NULL;
|
||||||
|
int addr_res = getaddrinfo(cfg->host, port_str, &hints, &res);
|
||||||
|
if (addr_res != 0)
|
||||||
|
{
|
||||||
|
out->getaddrinfo_error = addr_res;
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_GETADDRINFO);
|
||||||
|
}
|
||||||
|
memcpy(&out->addrinfo, res, sizeof(struct addrinfo));
|
||||||
|
|
||||||
|
for (ai = res; ai != NULL; ai = ai->ai_next)
|
||||||
|
{
|
||||||
|
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
/* Save errno, but will be clobbered if others succeed. */
|
||||||
|
out->status = SOCKET_ERROR_SOCKET;
|
||||||
|
out->saved_errno = SocketGetLastError();
|
||||||
|
SocketSetError(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SocketSetOptions(cfg, out, fd))
|
||||||
|
{
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->server)
|
||||||
|
{
|
||||||
|
int bind_res = bind(fd, res->ai_addr, res->ai_addrlen);
|
||||||
|
if (bind_res == -1)
|
||||||
|
{
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_BIND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cfg->datagram)
|
||||||
|
{
|
||||||
|
int listen_res = listen(fd, cfg->backlog_size);
|
||||||
|
if (listen_res == -1)
|
||||||
|
{
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_LISTEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else /* client */
|
||||||
|
{
|
||||||
|
if (cfg->datagram) { break; }
|
||||||
|
|
||||||
|
int connect_res = connect(fd, ai->ai_addr, ai->ai_addrlen);
|
||||||
|
if (connect_res == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
out->status = SOCKET_ERROR_CONNECT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
if (out->status == SOCKET_OK)
|
||||||
|
{
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_UNKNOWN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->saved_errno = SocketGetLastError();
|
||||||
|
SocketSetError(0);
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out->status = SOCKET_OK;
|
||||||
|
freeaddrinfo(res);
|
||||||
|
out->saved_errno = 0;
|
||||||
|
out->socket.handle = fd;
|
||||||
|
out->socket.ready = 0;
|
||||||
|
out->socket.remoteAddress.host = ((struct sockaddr_in*)res->ai_addr)->sin_addr.s_addr;
|
||||||
|
out->socket.remoteAddress.port = ((struct sockaddr_in*)res->ai_addr)->sin_port;
|
||||||
|
out->socket.sflag = cfg->server;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SocketSetNonBlocking(SocketResult *out)
|
||||||
|
{
|
||||||
|
#if PLATFORM == PLATFORM_WINDOWS
|
||||||
|
unsigned long mode = 1;
|
||||||
|
if (ioctlsocket(out->socket.handle, FIONBIO, &mode) != 0)
|
||||||
|
{
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_FCNTL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int flags = fcntl(out->socket.handle, F_GETFL, 0);
|
||||||
|
if (flags == -1)
|
||||||
|
{
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_FCNTL);
|
||||||
|
}
|
||||||
|
if (fcntl(out->socket, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||||
|
{
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_FCNTL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SocketSetOptions(SocketConfig *cfg,
|
||||||
|
SocketResult *out, int fd)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_SOCK_OPTS; i++)
|
||||||
|
{
|
||||||
|
SocketOpt *opt = &cfg->sockopts[i];
|
||||||
|
if (opt->option_id == 0) { break; }
|
||||||
|
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, opt->option_id,
|
||||||
|
opt->value, opt->value_len) < 0)
|
||||||
|
{
|
||||||
|
return SocketStatusToError(out, SOCKET_ERROR_SETSOCKOPT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *SocketStatusToString(enum SocketStatus s)
|
||||||
|
{
|
||||||
|
switch (s)
|
||||||
|
{
|
||||||
|
case SOCKET_OK:
|
||||||
|
return "ok";
|
||||||
|
case SOCKET_ERROR_GETADDRINFO:
|
||||||
|
return "getaddrinfo";
|
||||||
|
case SOCKET_ERROR_SOCKET:
|
||||||
|
return "socket";
|
||||||
|
case SOCKET_ERROR_BIND:
|
||||||
|
return "bind";
|
||||||
|
case SOCKET_ERROR_LISTEN:
|
||||||
|
return "listen";
|
||||||
|
case SOCKET_ERROR_CONNECT:
|
||||||
|
return "connect";
|
||||||
|
case SOCKET_ERROR_FCNTL:
|
||||||
|
return "fcntl";
|
||||||
|
case SOCKET_ERROR_SNPRINTF:
|
||||||
|
return "snprintf";
|
||||||
|
case SOCKET_ERROR_CONFIGURATION:
|
||||||
|
return "configuration";
|
||||||
|
case SOCKET_ERROR_SETSOCKOPT:
|
||||||
|
return "setsockopt";
|
||||||
|
case SOCKET_ERROR_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module implementation
|
// Module implementation
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -65,7 +294,6 @@
|
||||||
// Initialise the network (requires for windows platforms only)
|
// Initialise the network (requires for windows platforms only)
|
||||||
bool InitNetwork()
|
bool InitNetwork()
|
||||||
{
|
{
|
||||||
#if PLATFORM == PLATFORM_WINDOWS
|
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR)
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR)
|
||||||
{
|
{
|
||||||
|
|
@ -77,17 +305,19 @@ bool InitNetwork()
|
||||||
TraceLog(LOG_WARNING, "WinSock failed to initialise.");
|
TraceLog(LOG_WARNING, "WinSock failed to initialise.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup, and close the network
|
// Cleanup, and close the network
|
||||||
void CloseNetwork()
|
void CloseNetwork()
|
||||||
{
|
{
|
||||||
#if PLATFORM == PLATFORM_WINDOWS
|
if (WSACleanup() == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (WSAGetLastError() == WSAEINPROGRESS)
|
||||||
|
{
|
||||||
|
WSACancelBlockingCall();
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the hostname
|
// Resolve the hostname
|
||||||
|
|
@ -224,323 +454,201 @@ void ResolveHost(AddressInformation* outaddr, const char* address, const char* p
|
||||||
freeaddrinfo(results);
|
freeaddrinfo(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IP helper method, checks if an address is a valid IPv4 address
|
/* Attempt to open a socket, according to the configuration stored in
|
||||||
bool IsIPv4Address(const char* address)
|
* CFG. Returns whether the the socket opened; further details will be
|
||||||
|
* stored in RES. */
|
||||||
|
bool SocketOpen(SocketConfig *cfg, SocketResult *res)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sa;
|
if (cfg == NULL || res == NULL) { return false; }
|
||||||
return inet_pton(AF_INET, address, &(sa.sin_addr)) != 0;
|
memset(res, 0, sizeof(*res));
|
||||||
}
|
|
||||||
|
|
||||||
// IP helper method, checks if an address is a valid IPv6 address
|
if (!SocketSetDefaults(cfg))
|
||||||
bool IsIPv6Address(const char* address)
|
|
||||||
{
|
{
|
||||||
struct sockaddr_in6 sa;
|
res->status = SOCKET_ERROR_CONFIGURATION;
|
||||||
return inet_pton(AF_INET6, address, &(sa.sin6_addr)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a socket from information provided by the filled Address information struct
|
|
||||||
bool CreateSocket(Socket* sock, const AddressInformation addr)
|
|
||||||
{
|
|
||||||
// Create a socket from provided address data
|
|
||||||
sock->handle = socket(addr.family, addr.socktype, addr.protocol);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (sock->handle == INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to get create socket: %ls", gai_strerror(errno));
|
|
||||||
CloseSocket(sock->handle);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (!CreateSocket(cfg, res)) { return false; }
|
||||||
|
|
||||||
|
if (cfg->nonblocking)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_INFO, "Successfully created socket");
|
if (!SocketSetNonBlocking(res)) { return false; }
|
||||||
PrintSocket(addr.sockaddr, addr.family, addr.socktype, addr.protocol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if we've successfully created the socket
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind the socket to a specific port, this is usually used if you're going to listen for incoming connections on a specific port
|
/* Close a network socket */
|
||||||
bool BindSocket(Socket sock, const AddressInformation addr)
|
void SocketClose(SocketHandle socket)
|
||||||
{
|
{
|
||||||
// Bind the socket handle to the socket address defined in sockaddr
|
if (socket)
|
||||||
int status = bind(sock.handle, addr.sockaddr, addr.addrlen);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status == SOCKET_ERROR)
|
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING, "Failed to get bind socket: %ls", gai_strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char buff[INET6_ADDRSTRLEN];
|
|
||||||
TraceLog(LOG_INFO, "Successfully bound socket to address: %s", SocketAddressToString(addr.sockaddr, buff));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if we've successfully bound the socket
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect the socket to an address
|
|
||||||
bool ConnectSocket(Socket socket, AddressInformation addr)
|
|
||||||
{
|
|
||||||
int status = connect(socket.handle, addr.sockaddr, addr.addrlen);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status == SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to connect socket: %ls", gai_strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char buff[INET6_ADDRSTRLEN];
|
|
||||||
TraceLog(LOG_INFO, "Successfully connected socket to address: %s", SocketAddressToString(addr.sockaddr, buff));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if we've successfully connected the socket
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen on a socket
|
|
||||||
bool ListenSocket(Socket socket)
|
|
||||||
{
|
|
||||||
int status = listen(socket.handle, MAX_SOCKET_QUEUE_SIZE);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status == SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to listen to socket: %ls", gai_strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Success, socket now listening");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the socket i/o mode to blocking, or non-blocking
|
|
||||||
unsigned long blocking = socket.blocking ? 0 : 1;
|
|
||||||
status = ioctlsocket(socket.handle, FIONBIO, &blocking);
|
|
||||||
|
|
||||||
if (status != NO_ERROR)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to set socket io mode to: %s", (blocking ? "non-blocking" : "blocking"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Successfully set socket io mode to: %s", (blocking ? "non-blocking" : "blocking"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if we've successfully connected the socket
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close a socket
|
|
||||||
void CloseSocket(Socket* socket)
|
|
||||||
{
|
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
closesocket(socket);
|
closesocket(socket);
|
||||||
#elif PLATFORM == PLATFORM_UNIX
|
}
|
||||||
close(socket);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a listen server, this combines Create/Bind/Listen into 1 function
|
/* Accept an incoming connection on the given server socket.
|
||||||
void CreateListenServer(Socket* tcpsock, const char* address, const char* port, SocketType socketType)
|
The newly created socket is returned, or NULL if there was an error.
|
||||||
|
*/
|
||||||
|
bool SocketAccept(SocketHandle listener, SocketResult* out)
|
||||||
{
|
{
|
||||||
// Variables
|
struct sockaddr_in sock_addr;
|
||||||
int status; // Status value to return (0) is success
|
socklen_t sock_alen;
|
||||||
struct addrinfo hints; // Address flags (IPV4, IPV6, UDP?)
|
sock_alen = sizeof(sock_addr);
|
||||||
struct addrinfo* results; // A pointer to the resulting address list
|
out->socket.handle = accept(listener, (struct sockaddr *)&sock_addr,
|
||||||
|
&sock_alen);
|
||||||
// Set the hints
|
if (out->socket.handle == INVALID_SOCKET)
|
||||||
memset(&hints, 0, sizeof hints);
|
|
||||||
hints.ai_family = AF_UNSPEC; // Either IPv4 or IPv6 (AF_INET, AF_INET6)
|
|
||||||
hints.ai_socktype = socketType; // TCP (SOCK_STREAM), UDP (SOCK_DGRAM)
|
|
||||||
|
|
||||||
// Populate address information
|
|
||||||
status = getaddrinfo(address, // e.g. "www.example.com" or IP
|
|
||||||
port, // e.g. "http" or port number
|
|
||||||
&hints, // e.g. SOCK_STREAM/SOCK_DGRAM
|
|
||||||
&results // The struct to populate
|
|
||||||
);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status == -1)
|
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %ls", address, port, gai_strerror(errno));
|
/* Save errno, but will be clobbered if others succeed. */
|
||||||
|
out->status = SOCKET_ERROR_ACCEPT;
|
||||||
|
out->saved_errno = SocketGetLastError();
|
||||||
|
SocketSetError(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(&out->addrinfo, &sock_addr, sizeof(struct sockaddr));
|
||||||
|
out->socket.remoteAddress.host = sock_addr.sin_addr.s_addr;
|
||||||
|
out->socket.remoteAddress.port = sock_addr.sin_port;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send 'len' bytes of 'data' over the non-server socket 'sock'
|
||||||
|
This function returns the actual amount of data sent. If the return value
|
||||||
|
is less than the amount of data sent, then either the remote connection was
|
||||||
|
closed, or an unknown socket error occurred.
|
||||||
|
*/
|
||||||
|
int SocketSend(Socket* socket, const void *datap, int len)
|
||||||
|
{
|
||||||
|
const unsigned char *data = (const unsigned char *)datap; /* For pointer arithmetic */
|
||||||
|
int sent, left;
|
||||||
|
|
||||||
|
// /* Server sockets are for accepting connections only */
|
||||||
|
if (socket->sflag)
|
||||||
|
{
|
||||||
|
// out->status = SOCKET_ERROR_SEND;
|
||||||
|
// out->saved_errno = SocketGetLastError();
|
||||||
|
// SocketSetError(0);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep sending data until it's sent or an error occurs */
|
||||||
|
left = len;
|
||||||
|
sent = 0;
|
||||||
|
SocketSetError(0);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
len = send(socket->handle, (const char *)data, left, 0);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
sent += len;
|
||||||
|
left -= len;
|
||||||
|
data += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ((left > 0) && ((len > 0) || (SocketGetLastError() == EINTR)));
|
||||||
|
|
||||||
|
return(sent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
|
||||||
|
and store them in the buffer pointed to by 'data'.
|
||||||
|
This function returns the actual amount of data received. If the return
|
||||||
|
value is less than or equal to zero, then either the remote connection was
|
||||||
|
closed, or an unknown socket error occurred.
|
||||||
|
*/
|
||||||
|
int SocketReceive(Socket* socket, void *data, int maxlen)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/* Server sockets are for accepting connections only */
|
||||||
|
if (socket->sflag)
|
||||||
|
{
|
||||||
|
// out->status = SOCKET_ERROR_RECEIVE;
|
||||||
|
// out->saved_errno = SocketGetLastError();
|
||||||
|
// SocketSetError(0);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketSetError(0);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
len = recv(socket->handle, (char *)data, maxlen, 0);
|
||||||
|
}
|
||||||
|
while (SocketGetLastError() == EINTR);
|
||||||
|
|
||||||
|
// sock->ready = 0;
|
||||||
|
return(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct an error message in BUF, based on the status codes
|
||||||
|
* in *RES. This has the same return value and general behavior
|
||||||
|
* as snprintf -- if the return value is >= buf_size, the string
|
||||||
|
* has been truncated. Returns -1 if either BUF or RES are NULL. */
|
||||||
|
int SocketGetError(char *buf, size_t buf_size, SocketResult *res)
|
||||||
|
{
|
||||||
|
if (buf == NULL || res == NULL) { return 0; }
|
||||||
|
return snprintf(buf, buf_size, "%s: %ls",
|
||||||
|
SocketStatusToString(res->status),
|
||||||
|
(res->status == SOCKET_ERROR_GETADDRINFO
|
||||||
|
? gai_strerror(res->getaddrinfo_error)
|
||||||
|
: strerror(res->saved_errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print an error message based on the status contained in *RES. */
|
||||||
|
void SocketPrintError(SocketResult *res)
|
||||||
|
{
|
||||||
|
if (res == NULL) { return; }
|
||||||
|
printf("%s: %ls\n", SocketStatusToString(res->status),
|
||||||
|
(res->status == SOCKET_ERROR_GETADDRINFO
|
||||||
|
? gai_strerror(res->getaddrinfo_error)
|
||||||
|
: strerror(res->saved_errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set "hints" in an addrinfo struct, to be passed to getaddrinfo. */
|
||||||
|
void SocketSetHints(SocketConfig *cfg, struct addrinfo *hints)
|
||||||
|
{
|
||||||
|
if (cfg == NULL || hints == NULL) { return; }
|
||||||
|
memset(hints, 0, sizeof(*hints));
|
||||||
|
|
||||||
|
/* if .IPv4 or .IPv6 are used, set and use that instead of *host */
|
||||||
|
if (cfg->path)
|
||||||
|
{
|
||||||
|
hints->ai_family = AF_UNIX;
|
||||||
|
}
|
||||||
|
else if (cfg->IPv6)
|
||||||
|
{
|
||||||
|
hints->ai_family = AF_INET6;
|
||||||
|
}
|
||||||
|
else if (cfg->IPv4)
|
||||||
|
{
|
||||||
|
hints->ai_family = AF_INET;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, port);
|
hints->ai_family = AF_UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create our server socket
|
if (cfg->datagram)
|
||||||
int handle = socket(results->ai_family, results->ai_socktype, results->ai_protocol);
|
|
||||||
|
|
||||||
// Bind it to the port we passed in to getaddrinfo():
|
|
||||||
status = bind(handle, results->ai_addr, results->ai_addrlen);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status == -1)
|
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING, "Failed to get bind socket to port (%s): %ls", port, gai_strerror(errno));
|
hints->ai_socktype = SOCK_DGRAM;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TraceLog(LOG_INFO, "Successfully bound %s to port (%s)", address, port);
|
hints->ai_socktype = SOCK_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen on the bound port
|
/* Set passive unless UDP client */
|
||||||
status = listen(handle, 5);
|
if (!cfg->datagram || cfg->server)
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status == -1)
|
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING, "Failed to listen to socket: %ls", gai_strerror(errno));
|
hints->ai_flags = AI_PASSIVE;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Successfully started listen server.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD nonBlocking = 1;
|
if (cfg->IPv6 || cfg->IPv4)
|
||||||
if (ioctlsocket(handle, FIONBIO, &nonBlocking) == -1)
|
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING, "Failed to set socket to non-blocking.");
|
hints->ai_flags |= AI_NUMERICHOST;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Successfully set socket to non-blocking.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the linked-list, we're not using it anymore
|
|
||||||
freeaddrinfo(results);
|
|
||||||
|
|
||||||
// Finally, return our socket descriptor
|
|
||||||
tcpsock->handle = handle;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a simple client, this combines Create/Bind/Connect into 1 function
|
|
||||||
void CreateClient(Socket* tcpsock, char* address, char* port, SocketType socketType)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
int handle;
|
|
||||||
struct addrinfo hints;
|
|
||||||
struct addrinfo* results; // Will point to the results
|
|
||||||
|
|
||||||
memset(&hints, 0, sizeof hints); // Make sure the struct is empty
|
|
||||||
hints.ai_family = AF_UNSPEC; // Don't care IPv4 or IPv6
|
|
||||||
hints.ai_socktype = socketType; // TCP stream sockets
|
|
||||||
|
|
||||||
// Get ready to connect
|
|
||||||
status = getaddrinfo(address, port, &hints, &results);
|
|
||||||
|
|
||||||
// Did we succeed?
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to get address information: %ls", gai_strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Successfully created TCP client on port (%s)", port);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create our socket
|
|
||||||
handle = socket(results->ai_family, results->ai_socktype, results->ai_protocol);
|
|
||||||
|
|
||||||
// Did it succeed?
|
|
||||||
if (handle == -1)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to create socket: %ls", gai_strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Successfully created socket");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to the server
|
|
||||||
status = connect(handle, results->ai_addr, results->ai_addrlen);
|
|
||||||
|
|
||||||
if (status == -1)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to connect to server %s:%s", address, port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Successfully connected to %s:%s", address, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(results);
|
|
||||||
|
|
||||||
// Finally, return our socket descriptor
|
|
||||||
tcpsock->handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to accept connections on ListenSock and store them in NewSock
|
|
||||||
void AcceptSocket(Socket listenSock, Socket* newSock)
|
|
||||||
{
|
|
||||||
struct sockaddr_storage their_addr;
|
|
||||||
socklen_t addrSize;
|
|
||||||
int newHandle;
|
|
||||||
addrSize = sizeof their_addr;
|
|
||||||
newHandle = accept(listenSock.handle, (struct sockaddr*) &their_addr, &addrSize);
|
|
||||||
|
|
||||||
if (newHandle == INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_DEBUG, "Failed to accept incoming connection: %ls", gai_strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newSock->handle = newHandle;
|
|
||||||
TraceLog(LOG_INFO, "Successfully accepted a new connection.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send data over TCP
|
|
||||||
int SendTCP(SocketHandle handle, const char* data, int len)
|
|
||||||
{
|
|
||||||
int sentBytes = send(handle, data, len, 0);
|
|
||||||
if (sentBytes == SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Failed to send data: %ls", gai_strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_DEBUG, "Successfully sent %d bytes.", sentBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receiive data over TCP
|
|
||||||
int ReceiveTCP(SocketHandle handle, const char* data, int len)
|
|
||||||
{
|
|
||||||
int status = recv(handle, data, len, 0);
|
|
||||||
if (status == SOCKET_ERROR && errno == EWOULDBLOCK)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_DEBUG, "Failed to receive data: %ls", gai_strerror(errno));
|
|
||||||
}
|
|
||||||
else if (status > 0)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_DEBUG, "Successfully received %d bytes.", status);
|
|
||||||
}
|
|
||||||
else if (status == 0)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_INFO, "Connection closed.");
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset a socket
|
|
||||||
void ResetSocket(Socket* socket)
|
|
||||||
{
|
|
||||||
socket->handle = -1;
|
|
||||||
socket->blocking = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Print socket information
|
// Print socket information
|
||||||
void PrintSocket(struct SocketAddress* addr, const int family, const int socktype, const int protocol)
|
void PrintSocket(struct SocketAddress* addr, const int family, const int socktype, const int protocol)
|
||||||
{
|
{
|
||||||
|
|
@ -642,61 +750,6 @@ char* SocketAddressToString(struct SocketAddress* sockaddr, char buffer[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short HostToNetworkShort(unsigned short value)
|
|
||||||
{
|
|
||||||
return htons(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long HostToNetworkLong(unsigned long value)
|
|
||||||
{
|
|
||||||
return htonl(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int HostToNetworkFloat(float value)
|
|
||||||
{
|
|
||||||
return htonf(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long HostToNetworkDouble(double value)
|
|
||||||
{
|
|
||||||
return htond(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long HostToNetworkLongLong(unsigned long long value)
|
|
||||||
{
|
|
||||||
return htonll(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short NetworkToHostShort(unsigned short value)
|
|
||||||
{
|
|
||||||
return ntohs(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long NetworkToHostLong(unsigned long value)
|
|
||||||
{
|
|
||||||
return ntohl(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
float NetworkToHostFloat(unsigned int value)
|
|
||||||
{
|
|
||||||
return ntohf(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
double NetworkToHostDouble(unsigned long long value)
|
|
||||||
{
|
|
||||||
return ntohd(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
double NetworkToHostLongDouble(unsigned long long value)
|
|
||||||
{
|
|
||||||
return ntohd(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long NetworkToHostLongLong(unsigned long long value)
|
|
||||||
{
|
|
||||||
return ntohll(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** PackData() -- store data dictated by the format string in the buffer
|
** PackData() -- store data dictated by the format string in the buffer
|
||||||
**
|
**
|
||||||
|
|
@ -982,3 +1035,69 @@ void UnpackData(unsigned char* buf, char* format, ...)
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned short HostToNetworkShort(unsigned short value)
|
||||||
|
{
|
||||||
|
return htons(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned long HostToNetworkLong(unsigned long value)
|
||||||
|
{
|
||||||
|
return htonl(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned int HostToNetworkFloat(float value)
|
||||||
|
{
|
||||||
|
return htonf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned long long HostToNetworkDouble(double value)
|
||||||
|
{
|
||||||
|
return htond(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned long long HostToNetworkLongLong(unsigned long long value)
|
||||||
|
{
|
||||||
|
return htonll(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned short NetworkToHostShort(unsigned short value)
|
||||||
|
{
|
||||||
|
return ntohs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned long NetworkToHostLong(unsigned long value)
|
||||||
|
{
|
||||||
|
return ntohl(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float NetworkToHostFloat(unsigned int value)
|
||||||
|
{
|
||||||
|
return ntohf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
double NetworkToHostDouble(unsigned long long value)
|
||||||
|
{
|
||||||
|
return ntohd(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
double NetworkToHostLongDouble(unsigned long long value)
|
||||||
|
{
|
||||||
|
return ntohd(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned long long NetworkToHostLongLong(unsigned long long value)
|
||||||
|
{
|
||||||
|
return ntohll(value);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user