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 <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 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);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
int i = 0;
|
||||
while (i < 20)
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
room temp = Temp_Rect_Creat();
|
||||
rooms.push_back(temp);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
for (int i = 0; i < rooms.size(); i++)
|
||||
{
|
||||
DrawRectangle(rooms[i].x, rooms[i].y, rooms[i].width, rooms[i].height, BLACK);
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -22,6 +22,9 @@
|
|||
|
||||
#include "raylib.h"
|
||||
|
||||
#define MYPORT "4950"
|
||||
#define MAXBUFLEN 100
|
||||
|
||||
int main()
|
||||
{
|
||||
// Setup
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
int main()
|
||||
{
|
||||
|
||||
// Setup
|
||||
int screenWidth = 800;
|
||||
int screenHeight = 450;
|
||||
|
|
@ -37,25 +36,41 @@ int main()
|
|||
// Networking
|
||||
InitNetwork();
|
||||
|
||||
// Server socket and address
|
||||
AddressInformation serveraddr;
|
||||
Socket server;
|
||||
server.blocking = false;
|
||||
ResolveHost(&serveraddr, "localhost", "3490", SOCKET_TCP);
|
||||
// Create the server
|
||||
SocketConfig server_cfg = {
|
||||
.host = "127.0.0.1",
|
||||
.port = 8080,
|
||||
.server = true,
|
||||
.nonblocking = true,
|
||||
};
|
||||
|
||||
CreateSocket(&server, serveraddr);
|
||||
BindSocket(server, serveraddr);
|
||||
ListenSocket(server);
|
||||
SocketResult server_res;
|
||||
memset(&server_res, 0, sizeof(SocketResult));
|
||||
{
|
||||
bool ok = SocketOpen(&server_cfg, &server_res);
|
||||
if (!ok) { return false; }
|
||||
}
|
||||
|
||||
// Client socket and address
|
||||
AddressInformation clientaddr;
|
||||
Socket client;
|
||||
client.blocking = false;
|
||||
ResolveHost(&clientaddr, "localhost", "3490", SOCKET_TCP);
|
||||
CreateSocket(&client, clientaddr);
|
||||
ConnectSocket(client, clientaddr);
|
||||
// Create the client
|
||||
SocketConfig client_cfg = {
|
||||
.host = "127.0.0.1",
|
||||
.port = 8080,
|
||||
};
|
||||
|
||||
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
|
||||
bool ping = false, pong = false;
|
||||
char recvBuffer[512];
|
||||
|
|
@ -74,15 +89,17 @@ int main()
|
|||
// A valid connection will != -1
|
||||
if (!connected)
|
||||
{
|
||||
AcceptSocket(server, &connection);
|
||||
if (SocketAccept(server_res.socket.handle, &connection))
|
||||
{
|
||||
ping = true;
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Connected
|
||||
if (connected)
|
||||
{
|
||||
int bytesRecv = ReceiveTCP(connection.handle, recvBuffer, 5);
|
||||
int bytesRecv = SocketReceive(&connection.socket, recvBuffer, 5);
|
||||
if (bytesRecv > 0)
|
||||
{
|
||||
if (strcmp(recvBuffer, "Ping!") == 0)
|
||||
|
|
@ -103,12 +120,12 @@ int main()
|
|||
if (ping)
|
||||
{
|
||||
ping = false;
|
||||
SendTCP(client.handle, "Ping!", 5);
|
||||
SocketSend(&client_res.socket, "Ping!", 5);
|
||||
}
|
||||
else if (pong)
|
||||
{
|
||||
pong = false;
|
||||
SendTCP(client.handle, "Pong!", 5);
|
||||
SocketSend(&client_res.socket, "Pong!", 5);
|
||||
}
|
||||
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 <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()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
srand(time(NULL));
|
||||
|
||||
int screenWidth = 800;
|
||||
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);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
int i = 0;
|
||||
while (i < 20) {
|
||||
room temp = Temp_Rect_Creat();
|
||||
rooms.push_back(temp);
|
||||
i++;
|
||||
}
|
||||
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
for (int i = 0; i < rooms.size(); i++) {
|
||||
DrawRectangle(rooms[i].x, rooms[i].y, rooms[i].width, rooms[i].height, BLACK);
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
|
||||
return 0;
|
||||
}
|
||||
200
src/raylib.h
200
src/raylib.h
|
|
@ -100,10 +100,12 @@
|
|||
// Network limits
|
||||
#define MAX_SOCKET_SET_SIZE 32
|
||||
#define MAX_SOCKET_QUEUE_SIZE 16
|
||||
#define MAX_HOST_NAME_SIZE NI_MAXHOST
|
||||
#define MAX_SERV_NAME_SIZE NI_MAXSERV
|
||||
#define MAX_IPV4_NAME_SIZE INET6_ADDRSTRLEN
|
||||
#define MAX_IPV6_NAME_SIZE INET_ADDRSTRLEN
|
||||
#define MAX_HOST_NAME_SIZE 1025
|
||||
#define MAX_SERV_NAME_SIZE 32
|
||||
#define MAX_IPV4_NAME_SIZE 22
|
||||
#define MAX_IPV6_NAME_SIZE 65
|
||||
|
||||
#define MAX_SOCK_OPTS 4
|
||||
|
||||
// NOTE: MSC C++ compiler does not support compound literals (C99 feature)
|
||||
// Plain structures in C++ (without constructors) can be initialized from { } initializers.
|
||||
|
|
@ -431,31 +433,10 @@ typedef struct VrStereoConfig {
|
|||
|
||||
typedef struct IPAddress
|
||||
{
|
||||
int family;
|
||||
union {
|
||||
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;
|
||||
unsigned char* host; /* 32-bit IPv4 host address */
|
||||
unsigned char* port; /* 16-bit protocol port */
|
||||
} 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
|
||||
{
|
||||
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.
|
||||
} 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
|
||||
{
|
||||
int ready;
|
||||
SocketHandle handle;
|
||||
IPv4address address;
|
||||
bool blocking;
|
||||
// int ready;
|
||||
// SocketHandle handle;
|
||||
// IPAddress address;
|
||||
// bool blocking;
|
||||
IPAddress remoteAddress;
|
||||
IPAddress localAddress;
|
||||
int sflag;
|
||||
} 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
|
||||
//{
|
||||
// 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;
|
||||
/* Path, for Unix domain socket. */
|
||||
char *path;
|
||||
|
||||
typedef struct SocketSet
|
||||
{
|
||||
Socket *sockets[MAX_SOCKET_SET_SIZE];
|
||||
} SocketSet;
|
||||
/* IPv4 or IPv6 address; if neither is specified, let OS decide.
|
||||
* These fields should be used in place of 'host' above. */
|
||||
char *IPv4;
|
||||
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
|
||||
|
|
@ -539,12 +553,6 @@ typedef enum
|
|||
SOCKET_UDP = 2 // SOCK_DGRAM
|
||||
} SocketType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FAMILY_IPv4 = 1,
|
||||
FAMILY_IPv6 = 2
|
||||
} AddressFamily;
|
||||
|
||||
// System config flags
|
||||
// NOTE: Used for bit masks
|
||||
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 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 void CloseNetwork(void);
|
||||
|
||||
// Resolution
|
||||
RLAPI void ResolveHost(AddressInformation *outaddr, const char *address, const char *port, SocketType socketType);
|
||||
RLAPI char *ResolveIP(const char *host, const char *port);
|
||||
RLAPI bool IsIPv4Address(const char *host);
|
||||
RLAPI bool IsIPv6Address(const char *host);
|
||||
RLAPI int GetIPFamily(const char *host);
|
||||
|
||||
// IP
|
||||
RLAPI void GetLocalAddresses();
|
||||
RLAPI bool CreateSocket(Socket *socket, AddressInformation outaddr);
|
||||
RLAPI bool BindSocket(Socket socket, const AddressInformation addr);
|
||||
RLAPI bool ConnectSocket(Socket socket, const AddressInformation addr);
|
||||
RLAPI bool ListenSocket(Socket socket);
|
||||
RLAPI void CloseSocket(Socket *socket);
|
||||
RLAPI void AcceptSocket(Socket listenSock, Socket *newSock);
|
||||
|
||||
// Socket API
|
||||
RLAPI bool SocketOpen(SocketConfig *cfg, SocketResult *res);
|
||||
RLAPI void SocketClose(SocketHandle socket);
|
||||
RLAPI bool SocketAccept(SocketHandle listener, SocketResult* res);
|
||||
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 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 void UnpackData(unsigned char *buf, char *format, ...);
|
||||
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 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 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)
|
||||
}
|
||||
|
|
|
|||
835
src/rnet.c
835
src/rnet.c
|
|
@ -38,6 +38,7 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
// Check if config flags have been externally provided on compilation line
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
||||
# include "config.h" // Defines module configuration flags
|
||||
#endif
|
||||
|
|
@ -47,8 +48,8 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "raylib.h"
|
||||
#include "sysnet.h"
|
||||
#include "rpack.h"
|
||||
#include "sysnet.h"
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module defines
|
||||
|
|
@ -58,6 +59,234 @@
|
|||
# define errno WSAGetLastError() // Support UNIX socket error codes
|
||||
#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
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -65,7 +294,6 @@
|
|||
// Initialise the network (requires for windows platforms only)
|
||||
bool InitNetwork()
|
||||
{
|
||||
#if PLATFORM == PLATFORM_WINDOWS
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR)
|
||||
{
|
||||
|
|
@ -77,17 +305,19 @@ bool InitNetwork()
|
|||
TraceLog(LOG_WARNING, "WinSock failed to initialise.");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Cleanup, and close the network
|
||||
void CloseNetwork()
|
||||
{
|
||||
#if PLATFORM == PLATFORM_WINDOWS
|
||||
if (WSACleanup() == SOCKET_ERROR)
|
||||
{
|
||||
if (WSAGetLastError() == WSAEINPROGRESS)
|
||||
{
|
||||
WSACancelBlockingCall();
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the hostname
|
||||
|
|
@ -224,323 +454,201 @@ void ResolveHost(AddressInformation* outaddr, const char* address, const char* p
|
|||
freeaddrinfo(results);
|
||||
}
|
||||
|
||||
// IP helper method, checks if an address is a valid IPv4 address
|
||||
bool IsIPv4Address(const char* address)
|
||||
/* Attempt to open a socket, according to the configuration stored in
|
||||
* CFG. Returns whether the the socket opened; further details will be
|
||||
* stored in RES. */
|
||||
bool SocketOpen(SocketConfig *cfg, SocketResult *res)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
return inet_pton(AF_INET, address, &(sa.sin_addr)) != 0;
|
||||
}
|
||||
if (cfg == NULL || res == NULL) { return false; }
|
||||
memset(res, 0, sizeof(*res));
|
||||
|
||||
// IP helper method, checks if an address is a valid IPv6 address
|
||||
bool IsIPv6Address(const char* address)
|
||||
{
|
||||
struct sockaddr_in6 sa;
|
||||
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)
|
||||
if (!SocketSetDefaults(cfg))
|
||||
{
|
||||
TraceLog(LOG_WARNING, "Failed to get create socket: %ls", gai_strerror(errno));
|
||||
CloseSocket(sock->handle);
|
||||
res->status = SOCKET_ERROR_CONFIGURATION;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
if (!CreateSocket(cfg, res)) { return false; }
|
||||
|
||||
if (cfg->nonblocking)
|
||||
{
|
||||
TraceLog(LOG_INFO, "Successfully created socket");
|
||||
PrintSocket(addr.sockaddr, addr.family, addr.socktype, addr.protocol);
|
||||
if (!SocketSetNonBlocking(res)) { return false; }
|
||||
}
|
||||
|
||||
// Return true if we've successfully created the socket
|
||||
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
|
||||
bool BindSocket(Socket sock, const AddressInformation addr)
|
||||
/* Close a network socket */
|
||||
void SocketClose(SocketHandle socket)
|
||||
{
|
||||
// Bind the socket handle to the socket address defined in sockaddr
|
||||
int status = bind(sock.handle, addr.sockaddr, addr.addrlen);
|
||||
|
||||
// Did we succeed?
|
||||
if (status == SOCKET_ERROR)
|
||||
if (socket)
|
||||
{
|
||||
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);
|
||||
#elif PLATFORM == PLATFORM_UNIX
|
||||
close(socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a listen server, this combines Create/Bind/Listen into 1 function
|
||||
void CreateListenServer(Socket* tcpsock, const char* address, const char* port, SocketType socketType)
|
||||
{
|
||||
// Variables
|
||||
int status; // Status value to return (0) is success
|
||||
struct addrinfo hints; // Address flags (IPV4, IPV6, UDP?)
|
||||
struct addrinfo* results; // A pointer to the resulting address list
|
||||
|
||||
// Set the hints
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, port);
|
||||
}
|
||||
|
||||
// Create our server socket
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLog(LOG_INFO, "Successfully bound %s to port (%s)", address, port);
|
||||
}
|
||||
|
||||
// Listen on the bound port
|
||||
status = listen(handle, 5);
|
||||
|
||||
// Did we succeed?
|
||||
if (status == -1)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "Failed to listen to socket: %ls", gai_strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLog(LOG_INFO, "Successfully started listen server.");
|
||||
}
|
||||
|
||||
DWORD nonBlocking = 1;
|
||||
if (ioctlsocket(handle, FIONBIO, &nonBlocking) == -1)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "Failed to set socket to non-blocking.");
|
||||
}
|
||||
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)
|
||||
/* Accept an incoming connection on the given server socket.
|
||||
The newly created socket is returned, or NULL if there was an error.
|
||||
*/
|
||||
bool SocketAccept(SocketHandle listener, SocketResult* out)
|
||||
{
|
||||
int sentBytes = send(handle, data, len, 0);
|
||||
if (sentBytes == SOCKET_ERROR)
|
||||
struct sockaddr_in sock_addr;
|
||||
socklen_t sock_alen;
|
||||
sock_alen = sizeof(sock_addr);
|
||||
out->socket.handle = accept(listener, (struct sockaddr *)&sock_addr,
|
||||
&sock_alen);
|
||||
if (out->socket.handle == INVALID_SOCKET)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "Failed to send data: %ls", 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
|
||||
{
|
||||
TraceLog(LOG_DEBUG, "Successfully sent %d bytes.", sentBytes);
|
||||
hints->ai_family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
if (cfg->datagram)
|
||||
{
|
||||
hints->ai_socktype = SOCK_DGRAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
hints->ai_socktype = SOCK_STREAM;
|
||||
}
|
||||
|
||||
/* Set passive unless UDP client */
|
||||
if (!cfg->datagram || cfg->server)
|
||||
{
|
||||
hints->ai_flags = AI_PASSIVE;
|
||||
}
|
||||
|
||||
if (cfg->IPv6 || cfg->IPv4)
|
||||
{
|
||||
hints->ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
**
|
||||
|
|
@ -744,13 +797,13 @@ unsigned int PackData(unsigned char* buf, char* format, ...)
|
|||
{
|
||||
case 'c': // 8-bit
|
||||
size += 1;
|
||||
c = (signed char) va_arg(ap, int); // promoted
|
||||
c = (signed char)va_arg(ap, int); // promoted
|
||||
*buf++ = c;
|
||||
break;
|
||||
|
||||
case 'C': // 8-bit unsigned
|
||||
size += 1;
|
||||
C = (unsigned char) va_arg(ap, unsigned int); // promoted
|
||||
C = (unsigned char)va_arg(ap, unsigned int); // promoted
|
||||
*buf++ = C;
|
||||
break;
|
||||
|
||||
|
|
@ -798,7 +851,7 @@ unsigned int PackData(unsigned char* buf, char* format, ...)
|
|||
|
||||
case 'f': // float-16
|
||||
size += 2;
|
||||
f = (float) va_arg(ap, double); // promoted
|
||||
f = (float)va_arg(ap, double); // promoted
|
||||
fhold = pack754_16(f); // convert to IEEE 754
|
||||
packi16(buf, fhold);
|
||||
buf += 2;
|
||||
|
|
@ -889,7 +942,7 @@ void UnpackData(unsigned char* buf, char* format, ...)
|
|||
} // re-sign
|
||||
else
|
||||
{
|
||||
*c = -1 - (unsigned char) (0xffu - *buf);
|
||||
*c = -1 - (unsigned char)(0xffu - *buf);
|
||||
}
|
||||
buf++;
|
||||
break;
|
||||
|
|
@ -982,3 +1035,69 @@ void UnpackData(unsigned char* buf, char* format, ...)
|
|||
|
||||
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