Files
CgeNet/win32/Socket.c
Mikhail Romanko f8f90f94dc
All checks were successful
CI / build-and-analyze (push) Successful in 1m12s
Use consistent naming for OOM
2026-08-09 08:55:08 +03:00

431 lines
12 KiB
C

#include "Internal.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int CgeNetInit(void) {
WSADATA wsaData;
return (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0) ? 1 : 0;
}
void CgeNetCleanup(void) {
WSACleanup();
}
static int wsaToErrorCode(int value) {
switch (value) {
case 0:
return CGE_NET_EOK;
case WSAEHOSTUNREACH:
return CGE_NET_EHOSTUNREACH;
case WSAENETUNREACH:
return CGE_NET_ENETUNREACH;
case WSAEINVAL:
return CGE_NET_EINVAL;
case WSAENOBUFS:
case WSA_NOT_ENOUGH_MEMORY:
return CGE_NET_EOOM;
case WSAEADDRINUSE:
return CGE_NET_EADDRINUSE;
case WSAEADDRNOTAVAIL:
return CGE_NET_EADDRNOTAVAIL;
case WSAECONNREFUSED:
return CGE_NET_ECONNREFUSED;
case WSAECONNRESET:
return CGE_NET_ECONNRESET;
case WSAECONNABORTED:
return CGE_NET_ECONNABORTED;
case WSAETIMEDOUT:
return CGE_NET_ETIMEDOUT;
case WSAEWOULDBLOCK:
return CGE_NET_EWOULDBLOCK;
default:
return CGE_NET_EUNKNOWN;
}
}
static int socketInit(CgeNetSocket *s, int domain, int type) {
int protocol;
assert(s != NULL);
s->domain = domain;
s->type = type;
s->pollObject = NULL;
s->pollIndex = 0;
switch (domain) {
case CGE_NET_IPV4: domain = AF_INET; break;
case CGE_NET_IPV6: domain = AF_INET6; break;
default: return CGE_NET_EINVAL;
}
switch (type) {
case CGE_NET_TCP: type = SOCK_STREAM; protocol = IPPROTO_TCP; break;
case CGE_NET_UDP: type = SOCK_DGRAM; protocol = IPPROTO_UDP; break;
default: return CGE_NET_EINVAL;
}
s->handle = socket(domain, type, protocol);
if (s->handle == INVALID_SOCKET)
return wsaToErrorCode(WSAGetLastError());
return CGE_NET_EOK;
}
CgeNetSocket *CgeNetOpen(int domain, int type, int *result) {
CgeNetSocket *socket = NULL;
int code = CGE_NET_EOOM;
if ((socket = malloc(sizeof(*socket)))) {
if ((code = socketInit(socket, domain, type))) {
free(socket);
socket = NULL;
}
}
if (result)
*result = code;
return socket;
}
void CgeNetClose(CgeNetSocket *socket) {
if (!socket)
return;
if (socket->pollObject)
CgeNetPollRemove(socket->pollObject, socket);
closesocket(socket->handle);
free(socket);
}
int CgeNetErrorCode(CgeNetSocket *socket) {
assert(socket != NULL);
return socket->lastError;
}
int CgeNetFetchError(CgeNetSocket *socket) {
int result = 0;
int len = sizeof(result);
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
if (getsockopt(socket->handle, SOL_SOCKET, SO_ERROR, (char *)&result, &len)) {
socket->lastError = wsaToErrorCode(WSAGetLastError());
return 0;
}
socket->lastError = wsaToErrorCode(result);
return result != 0;
}
int CgeNetSetBlocking(CgeNetSocket *socket, int value) {
u_long mode;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
mode = value ? 0 : 1;
if (ioctlsocket(socket->handle, FIONBIO, &mode) == SOCKET_ERROR) {
socket->lastError = wsaToErrorCode(WSAGetLastError());
return 0;
}
return 1;
}
int CgeNetBind(CgeNetSocket *socket, const CgeNetAddr *addr) {
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
const struct sockaddr *sa;
socklen_t salen;
int result;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(addr != NULL);
assert(addr->type == CGE_NET_IPV4 || addr->type == CGE_NET_IPV6);
if (addr->type == CGE_NET_IPV4) {
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
sa4.sin_port = htons(addr->ipv4.port);
memcpy(&sa4.sin_addr, addr->ipv4.addr, 4);
sa = (struct sockaddr *)&sa4;
salen = sizeof(sa4);
} else {
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(addr->ipv6.port);
memcpy(&sa6.sin6_addr, addr->ipv6.addr, 16);
sa = (struct sockaddr *)&sa6;
salen = sizeof(sa6);
}
result = bind(socket->handle, sa, (int)salen);
if (result == SOCKET_ERROR)
socket->lastError = wsaToErrorCode(WSAGetLastError());
return result != SOCKET_ERROR;
}
int CgeNetListen(CgeNetSocket *socket, unsigned int backlog) {
int result;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
result = listen(socket->handle, backlog);
if (result == SOCKET_ERROR)
socket->lastError = wsaToErrorCode(WSAGetLastError());
return result != SOCKET_ERROR;
}
CgeNetSocket *CgeNetAccept(CgeNetSocket *socket, CgeNetAddr *addr) {
SOCKET fd;
CgeNetSocket *client;
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
fd = accept(socket->handle, (struct sockaddr*)&ss, &slen);
if (fd == INVALID_SOCKET) {
socket->lastError = wsaToErrorCode(WSAGetLastError());
return NULL;
}
if (!(client = malloc(sizeof(*client)))) {
closesocket(fd);
socket->lastError = CGE_NET_EOOM;
return NULL;
}
client->handle = fd;
client->domain = socket->domain;
client->type = socket->type;
client->lastError = CGE_NET_EOK;
client->pollObject = NULL;
client->pollIndex = 0;
client->context = NULL;
if (addr) {
if (ss.ss_family == AF_INET) {
struct sockaddr_in *sa4 = (struct sockaddr_in *)&ss;
addr->ipv4.type = CGE_NET_IPV4;
memcpy(addr->ipv4.addr, &sa4->sin_addr, 4);
addr->ipv4.port = ntohs(sa4->sin_port);
} else if (ss.ss_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&ss;
addr->ipv6.type = CGE_NET_IPV6;
memcpy(addr->ipv6.addr, &sa6->sin6_addr, 16);
addr->ipv6.port = ntohs(sa6->sin6_port);
}
}
return client;
}
int CgeNetConnect(CgeNetSocket *socket, const CgeNetAddr *addr) {
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
const struct sockaddr *sa;
socklen_t salen;
int result;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(addr != NULL);
assert(addr->type == CGE_NET_IPV4 || addr->type == CGE_NET_IPV6);
if (addr->type == CGE_NET_IPV4) {
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
sa4.sin_port = htons(addr->ipv4.port);
memcpy(&sa4.sin_addr, addr->ipv4.addr, 4);
sa = (struct sockaddr *)&sa4;
salen = sizeof(sa4);
} else {
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(addr->ipv6.port);
memcpy(&sa6.sin6_addr, addr->ipv6.addr, 16);
sa = (struct sockaddr *)&sa6;
salen = sizeof(sa6);
}
result = connect(socket->handle, sa, (int)salen);
if (result == SOCKET_ERROR)
socket->lastError = wsaToErrorCode(WSAGetLastError());
return result != SOCKET_ERROR;
}
int CgeNetWrite(CgeNetSocket *socket, const void *buffer, size_t size,
size_t *actual) {
int result;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(buffer != NULL);
result = send(socket->handle, (const char *)buffer, (int)size, 0);
if (actual)
*actual = (size_t)result;
socket->lastError = (result == SOCKET_ERROR) ? wsaToErrorCode(WSAGetLastError()) : CGE_NET_EOK;
return result != SOCKET_ERROR;
}
int CgeNetRead(CgeNetSocket *socket, void *buffer, size_t size,
size_t *actual) {
int result;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(buffer != NULL);
result = recv(socket->handle, (char *)buffer, (int)size, 0);
if (actual)
*actual = (size_t)result;
if (result == 0 && socket->type == CGE_NET_TCP) {
socket->lastError = CGE_NET_EDISCONNECT;
return 0;
}
socket->lastError = (result == SOCKET_ERROR) ? wsaToErrorCode(WSAGetLastError()) : CGE_NET_EOK;
return result != SOCKET_ERROR;
}
int CgeNetPeek(CgeNetSocket *socket, void *buffer, size_t size, size_t *actual) {
int result;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(buffer != NULL);
result = recv(socket->handle, (char *)buffer, (int)size, MSG_PEEK);
if (actual)
*actual = (size_t)result;
if (result == 0 && socket->type == CGE_NET_TCP) {
socket->lastError = CGE_NET_EDISCONNECT;
return 0;
}
socket->lastError = (result == SOCKET_ERROR) ? wsaToErrorCode(WSAGetLastError()) : CGE_NET_EOK;
return result != SOCKET_ERROR;
}
int CgeNetWriteTo(CgeNetSocket *socket, const CgeNetAddr *addr,
const void *buffer, size_t size, size_t *actual) {
int result;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
const struct sockaddr *sa;
socklen_t salen;
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(addr != NULL);
assert(addr->type == CGE_NET_IPV4 || addr->type == CGE_NET_IPV6);
assert(buffer != NULL);
if (socket->type != CGE_NET_UDP) {
socket->lastError = CGE_NET_EINVAL;
return -1;
}
if (addr->type == CGE_NET_IPV4) {
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
sa4.sin_port = htons(addr->ipv4.port);
memcpy(&sa4.sin_addr, addr->ipv4.addr, 4);
sa = (struct sockaddr *)&sa4;
salen = sizeof(sa4);
} else {
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(addr->ipv6.port);
memcpy(&sa6.sin6_addr, addr->ipv6.addr, 16);
sa = (struct sockaddr *)&sa6;
salen = sizeof(sa6);
}
result = sendto(socket->handle, (const char *)buffer, (int)size, 0, sa, (int)salen);
if (actual)
*actual = (size_t)result;
socket->lastError = (result == SOCKET_ERROR) ? wsaToErrorCode(WSAGetLastError()) : CGE_NET_EOK;
return result != SOCKET_ERROR;
}
int CgeNetReadFrom(CgeNetSocket *socket, CgeNetAddr* addr, void *buffer,
size_t size, size_t *actual) {
int result;
struct sockaddr_storage ss;
int sslen = sizeof(ss);
assert(socket != NULL);
assert(socket->handle != INVALID_SOCKET);
assert(addr != NULL);
assert(addr->type == CGE_NET_IPV4 || addr->type == CGE_NET_IPV6);
assert(buffer != NULL);
if (socket->type != CGE_NET_UDP) {
socket->lastError = CGE_NET_EINVAL;
return -1;
}
result = recvfrom(socket->handle, (char *)buffer, (int)size, 0, (struct sockaddr *)&ss, &sslen);
if (result == SOCKET_ERROR) {
socket->lastError = wsaToErrorCode(WSAGetLastError());
return 0;
}
if (actual)
*actual = (size_t)result;
if (ss.ss_family == AF_INET) {
struct sockaddr_in *sa4 = (struct sockaddr_in *)&ss;
addr->ipv4.type = CGE_NET_IPV4;
memcpy(addr->ipv4.addr, &sa4->sin_addr, 4);
addr->ipv4.port = ntohs(sa4->sin_port);
} else {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&ss;
addr->ipv6.type = CGE_NET_IPV6;
memcpy(addr->ipv6.addr, &sa6->sin6_addr, 16);
addr->ipv6.port = ntohs(sa6->sin6_port);
}
socket->lastError = CGE_NET_EOK;
return 1;
}
void *CgeNetContext(CgeNetSocket *socket) {
assert(socket != NULL);
return socket->context;
}
void CgeNetSetContext(CgeNetSocket *socket, void *data) {
assert(socket != NULL);
socket->context = data;
}