Fix Windows support
This commit is contained in:
parent
0e22357d55
commit
71f7bc4977
4 changed files with 145 additions and 65 deletions
|
@ -29,6 +29,10 @@ set_target_properties(UDPConnection PROPERTIES VERSION ${UDPConnection_VERSION})
|
||||||
|
|
||||||
target_compile_features(UDPConnection PUBLIC cxx_std_17)
|
target_compile_features(UDPConnection PUBLIC cxx_std_17)
|
||||||
target_link_libraries(UDPConnection PUBLIC pthread)
|
target_link_libraries(UDPConnection PUBLIC pthread)
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(UDPConnection PUBLIC Ws2_32)
|
||||||
|
target_link_libraries(UDPConnection PUBLIC Iphlpapi)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(UDPConnection PUBLIC
|
target_include_directories(UDPConnection PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/RingBuffer/src")
|
"${CMAKE_CURRENT_SOURCE_DIR}/RingBuffer/src")
|
||||||
|
|
|
@ -243,7 +243,7 @@ public:
|
||||||
std::atomic_uint32_t atostrBufIndex;
|
std::atomic_uint32_t atostrBufIndex;
|
||||||
char atostrBuf[UDPC_ATOSTR_SIZE];
|
char atostrBuf[UDPC_ATOSTR_SIZE];
|
||||||
|
|
||||||
int socketHandle;
|
UDPC_SOCKETTYPE socketHandle;
|
||||||
struct sockaddr_in6 socketInfo;
|
struct sockaddr_in6 socketInfo;
|
||||||
|
|
||||||
std::chrono::steady_clock::time_point lastUpdated;
|
std::chrono::steady_clock::time_point lastUpdated;
|
||||||
|
|
|
@ -16,6 +16,23 @@
|
||||||
|
|
||||||
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
#include <netioapi.h>
|
#include <netioapi.h>
|
||||||
|
|
||||||
|
static const UDPC_IPV6_ADDR_TYPE in6addr_any = UDPC_IPV6_ADDR_TYPE{{
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0
|
||||||
|
}};
|
||||||
|
static const UDPC_IPV6_ADDR_TYPE in6addr_loopback = UDPC_IPV6_ADDR_TYPE{{
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 1
|
||||||
|
}};
|
||||||
|
|
||||||
|
typedef int socklen_t;
|
||||||
|
|
||||||
|
static const std::regex regex_numeric = std::regex("[0-9]+");
|
||||||
#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
@ -32,7 +49,7 @@ sentTime(std::chrono::steady_clock::now())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::size_t UDPC::ConnectionIdHasher::operator()(const UDPC_ConnectionId& key) const {
|
std::size_t UDPC::ConnectionIdHasher::operator()(const UDPC_ConnectionId& key) const {
|
||||||
std::string value((const char*)key.addr.s6_addr, 16);
|
std::string value((const char*)UDPC_IPV6_ADDR_SUB(key.addr), 16);
|
||||||
value.push_back((char)((key.scope_id >> 24) & 0xFF));
|
value.push_back((char)((key.scope_id >> 24) & 0xFF));
|
||||||
value.push_back((char)((key.scope_id >> 16) & 0xFF));
|
value.push_back((char)((key.scope_id >> 16) & 0xFF));
|
||||||
value.push_back((char)((key.scope_id >> 8) & 0xFF));
|
value.push_back((char)((key.scope_id >> 8) & 0xFF));
|
||||||
|
@ -42,17 +59,17 @@ std::size_t UDPC::ConnectionIdHasher::operator()(const UDPC_ConnectionId& key) c
|
||||||
return std::hash<std::string>()(value);
|
return std::hash<std::string>()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t UDPC::IPV6_Hasher::operator()(const struct in6_addr& addr) const {
|
std::size_t UDPC::IPV6_Hasher::operator()(const UDPC_IPV6_ADDR_TYPE& addr) const {
|
||||||
return std::hash<std::string>()(std::string((const char*)addr.s6_addr, 16));
|
return std::hash<std::string>()(std::string((const char*)UDPC_IPV6_ADDR_SUB(addr), 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator ==(const UDPC_ConnectionId& a, const UDPC_ConnectionId& b) {
|
bool operator ==(const UDPC_ConnectionId& a, const UDPC_ConnectionId& b) {
|
||||||
return a.addr == b.addr && a.scope_id == b.scope_id && a.port == b.port;
|
return a.addr == b.addr && a.scope_id == b.scope_id && a.port == b.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator ==(const struct in6_addr& a, const struct in6_addr& b) {
|
bool operator ==(const UDPC_IPV6_ADDR_TYPE& a, const UDPC_IPV6_ADDR_TYPE& b) {
|
||||||
for(unsigned int i = 0; i < 16; ++i) {
|
for(unsigned int i = 0; i < 16; ++i) {
|
||||||
if(a.s6_addr[i] != b.s6_addr[i]) {
|
if(UDPC_IPV6_ADDR_SUB(a)[i] != UDPC_IPV6_ADDR_SUB(b)[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +103,7 @@ rtt(std::chrono::steady_clock::duration::zero())
|
||||||
UDPC::ConnectionData::ConnectionData(
|
UDPC::ConnectionData::ConnectionData(
|
||||||
bool isServer,
|
bool isServer,
|
||||||
Context *ctx,
|
Context *ctx,
|
||||||
struct in6_addr addr,
|
UDPC_IPV6_ADDR_TYPE addr,
|
||||||
uint32_t scope_id,
|
uint32_t scope_id,
|
||||||
uint16_t port) :
|
uint16_t port) :
|
||||||
flags(),
|
flags(),
|
||||||
|
@ -285,9 +302,9 @@ void UDPC::Context::update_impl() {
|
||||||
nullptr,
|
nullptr,
|
||||||
0x1);
|
0x1);
|
||||||
|
|
||||||
struct sockaddr_in6 destinationInfo;
|
UDPC_IPV6_SOCKADDR_TYPE destinationInfo;
|
||||||
destinationInfo.sin6_family = AF_INET6;
|
destinationInfo.sin6_family = AF_INET6;
|
||||||
std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
|
std::memcpy(UDPC_IPV6_ADDR_SUB(destinationInfo.sin6_addr), UDPC_IPV6_ADDR_SUB(iter->first.addr), 16);
|
||||||
destinationInfo.sin6_port = htons(iter->second.port);
|
destinationInfo.sin6_port = htons(iter->second.port);
|
||||||
destinationInfo.sin6_flowinfo = 0;
|
destinationInfo.sin6_flowinfo = 0;
|
||||||
destinationInfo.sin6_scope_id = iter->first.scope_id;
|
destinationInfo.sin6_scope_id = iter->first.scope_id;
|
||||||
|
@ -297,7 +314,7 @@ void UDPC::Context::update_impl() {
|
||||||
20,
|
20,
|
||||||
0,
|
0,
|
||||||
(struct sockaddr*) &destinationInfo,
|
(struct sockaddr*) &destinationInfo,
|
||||||
sizeof(struct sockaddr_in6));
|
sizeof(UDPC_IPV6_SOCKADDR_TYPE));
|
||||||
if(sentBytes != 20) {
|
if(sentBytes != 20) {
|
||||||
log(
|
log(
|
||||||
UDPC_LoggingType::UDPC_ERROR,
|
UDPC_LoggingType::UDPC_ERROR,
|
||||||
|
@ -327,9 +344,9 @@ void UDPC::Context::update_impl() {
|
||||||
&iter->second.lseq,
|
&iter->second.lseq,
|
||||||
0x1);
|
0x1);
|
||||||
|
|
||||||
struct sockaddr_in6 destinationInfo;
|
UDPC_IPV6_SOCKADDR_TYPE destinationInfo;
|
||||||
destinationInfo.sin6_family = AF_INET6;
|
destinationInfo.sin6_family = AF_INET6;
|
||||||
std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
|
std::memcpy(UDPC_IPV6_ADDR_SUB(destinationInfo.sin6_addr), UDPC_IPV6_ADDR_SUB(iter->first.addr), 16);
|
||||||
destinationInfo.sin6_port = htons(iter->second.port);
|
destinationInfo.sin6_port = htons(iter->second.port);
|
||||||
destinationInfo.sin6_flowinfo = 0;
|
destinationInfo.sin6_flowinfo = 0;
|
||||||
destinationInfo.sin6_scope_id = iter->first.scope_id;
|
destinationInfo.sin6_scope_id = iter->first.scope_id;
|
||||||
|
@ -339,7 +356,7 @@ void UDPC::Context::update_impl() {
|
||||||
20,
|
20,
|
||||||
0,
|
0,
|
||||||
(struct sockaddr*) &destinationInfo,
|
(struct sockaddr*) &destinationInfo,
|
||||||
sizeof(struct sockaddr_in6));
|
sizeof(UDPC_IPV6_SOCKADDR_TYPE));
|
||||||
if(sentBytes != 20) {
|
if(sentBytes != 20) {
|
||||||
log(
|
log(
|
||||||
UDPC_LoggingType::UDPC_ERROR,
|
UDPC_LoggingType::UDPC_ERROR,
|
||||||
|
@ -371,9 +388,9 @@ void UDPC::Context::update_impl() {
|
||||||
&iter->second.lseq,
|
&iter->second.lseq,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
struct sockaddr_in6 destinationInfo;
|
UDPC_IPV6_SOCKADDR_TYPE destinationInfo;
|
||||||
destinationInfo.sin6_family = AF_INET6;
|
destinationInfo.sin6_family = AF_INET6;
|
||||||
std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
|
std::memcpy(UDPC_IPV6_ADDR_SUB(destinationInfo.sin6_addr), UDPC_IPV6_ADDR_SUB(iter->first.addr), 16);
|
||||||
destinationInfo.sin6_port = htons(iter->second.port);
|
destinationInfo.sin6_port = htons(iter->second.port);
|
||||||
destinationInfo.sin6_flowinfo = 0;
|
destinationInfo.sin6_flowinfo = 0;
|
||||||
destinationInfo.sin6_scope_id = iter->first.scope_id;
|
destinationInfo.sin6_scope_id = iter->first.scope_id;
|
||||||
|
@ -383,7 +400,7 @@ void UDPC::Context::update_impl() {
|
||||||
20,
|
20,
|
||||||
0,
|
0,
|
||||||
(struct sockaddr*) &destinationInfo,
|
(struct sockaddr*) &destinationInfo,
|
||||||
sizeof(struct sockaddr_in6));
|
sizeof(UDPC_IPV6_SOCKADDR_TYPE));
|
||||||
if(sentBytes != 20) {
|
if(sentBytes != 20) {
|
||||||
log(
|
log(
|
||||||
UDPC_LoggingType::UDPC_ERROR,
|
UDPC_LoggingType::UDPC_ERROR,
|
||||||
|
@ -432,9 +449,9 @@ void UDPC::Context::update_impl() {
|
||||||
(pInfo.flags & 0x4) | (isResending ? 0x8 : 0));
|
(pInfo.flags & 0x4) | (isResending ? 0x8 : 0));
|
||||||
std::memcpy(buf.get() + 20, pInfo.data, pInfo.dataSize);
|
std::memcpy(buf.get() + 20, pInfo.data, pInfo.dataSize);
|
||||||
|
|
||||||
struct sockaddr_in6 destinationInfo;
|
UDPC_IPV6_SOCKADDR_TYPE destinationInfo;
|
||||||
destinationInfo.sin6_family = AF_INET6;
|
destinationInfo.sin6_family = AF_INET6;
|
||||||
std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
|
std::memcpy(UDPC_IPV6_ADDR_SUB(destinationInfo.sin6_addr), UDPC_IPV6_ADDR_SUB(iter->first.addr), 16);
|
||||||
destinationInfo.sin6_port = htons(iter->second.port);
|
destinationInfo.sin6_port = htons(iter->second.port);
|
||||||
long int sentBytes = sendto(
|
long int sentBytes = sendto(
|
||||||
socketHandle,
|
socketHandle,
|
||||||
|
@ -442,7 +459,7 @@ void UDPC::Context::update_impl() {
|
||||||
pInfo.dataSize + 20,
|
pInfo.dataSize + 20,
|
||||||
0,
|
0,
|
||||||
(struct sockaddr*) &destinationInfo,
|
(struct sockaddr*) &destinationInfo,
|
||||||
sizeof(struct sockaddr_in6));
|
sizeof(UDPC_IPV6_SOCKADDR_TYPE));
|
||||||
if(sentBytes != 20 + pInfo.dataSize) {
|
if(sentBytes != 20 + pInfo.dataSize) {
|
||||||
log(
|
log(
|
||||||
UDPC_LoggingType::UDPC_ERROR,
|
UDPC_LoggingType::UDPC_ERROR,
|
||||||
|
@ -489,10 +506,7 @@ void UDPC::Context::update_impl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// receive packet
|
// receive packet
|
||||||
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
UDPC_IPV6_SOCKADDR_TYPE receivedData;
|
||||||
typedef int socklen_t;
|
|
||||||
#endif
|
|
||||||
struct sockaddr_in6 receivedData;
|
|
||||||
socklen_t receivedDataSize = sizeof(receivedData);
|
socklen_t receivedDataSize = sizeof(receivedData);
|
||||||
int bytes = recvfrom(
|
int bytes = recvfrom(
|
||||||
socketHandle,
|
socketHandle,
|
||||||
|
@ -502,6 +516,28 @@ void UDPC::Context::update_impl() {
|
||||||
(struct sockaddr*) &receivedData,
|
(struct sockaddr*) &receivedData,
|
||||||
&receivedDataSize);
|
&receivedDataSize);
|
||||||
|
|
||||||
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
|
if(bytes == 0) {
|
||||||
|
// connection closed
|
||||||
|
return;
|
||||||
|
} else if(bytes == SOCKET_ERROR) {
|
||||||
|
int error = WSAGetLastError();
|
||||||
|
if(error != WSAEWOULDBLOCK) {
|
||||||
|
log(UDPC_LoggingType::UDPC_ERROR,
|
||||||
|
"Error receiving packet, ", error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if(bytes < 20) {
|
||||||
|
// packet size is too small, invalid packet
|
||||||
|
log(
|
||||||
|
UDPC_LoggingType::UDPC_INFO,
|
||||||
|
"Received packet is smaller than header, ignoring packet from ",
|
||||||
|
UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
|
||||||
|
", port = ",
|
||||||
|
receivedData.sin6_port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if(bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
if(bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||||
// no packet was received
|
// no packet was received
|
||||||
return;
|
return;
|
||||||
|
@ -515,6 +551,7 @@ void UDPC::Context::update_impl() {
|
||||||
receivedData.sin6_port);
|
receivedData.sin6_port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t temp = ntohl(*((uint32_t*)recvBuf));
|
uint32_t temp = ntohl(*((uint32_t*)recvBuf));
|
||||||
if(temp != protocolID) {
|
if(temp != protocolID) {
|
||||||
|
@ -871,11 +908,11 @@ void UDPC::threadedUpdate(Context *ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPC_ConnectionId UDPC_create_id(struct in6_addr addr, uint16_t port) {
|
UDPC_ConnectionId UDPC_create_id(UDPC_IPV6_ADDR_TYPE addr, uint16_t port) {
|
||||||
return UDPC_ConnectionId{addr, 0, port};
|
return UDPC_ConnectionId{addr, 0, port};
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPC_ConnectionId UDPC_create_id_full(struct in6_addr addr, uint32_t scope_id, uint16_t port) {
|
UDPC_ConnectionId UDPC_create_id_full(UDPC_IPV6_ADDR_TYPE addr, uint32_t scope_id, uint16_t port) {
|
||||||
return UDPC_ConnectionId{addr, scope_id, port};
|
return UDPC_ConnectionId{addr, scope_id, port};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,18 +927,38 @@ UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient) {
|
||||||
ctx->log(UDPC_LoggingType::UDPC_INFO, "Got listen addr ",
|
ctx->log(UDPC_LoggingType::UDPC_INFO, "Got listen addr ",
|
||||||
UDPC_atostr((UDPC_HContext)ctx, listenId.addr));
|
UDPC_atostr((UDPC_HContext)ctx, listenId.addr));
|
||||||
|
|
||||||
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
|
// Initialize Winsock
|
||||||
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
WSADATA wsaData;
|
||||||
|
if(WSAStartup(wVersionRequested, &wsaData) != 0) {
|
||||||
|
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to initialize Winsock");
|
||||||
|
delete ctx;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// create socket
|
// create socket
|
||||||
ctx->socketHandle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
ctx->socketHandle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if(ctx->socketHandle <= 0) {
|
if(UDPC_SOCKET_RETURN_ERROR(ctx->socketHandle)) {
|
||||||
// TODO maybe different way of handling init fail
|
// TODO maybe different way of handling init fail
|
||||||
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
|
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to create socket, ",
|
||||||
|
WSAGetLastError());
|
||||||
|
#else
|
||||||
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to create socket");
|
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to create socket");
|
||||||
|
#endif
|
||||||
delete ctx;
|
delete ctx;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow ipv4 connections on ipv6 socket
|
// allow ipv4 connections on ipv6 socket
|
||||||
{
|
{
|
||||||
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
|
char no = 0;
|
||||||
|
#else
|
||||||
int no = 0;
|
int no = 0;
|
||||||
|
#endif
|
||||||
setsockopt(ctx->socketHandle, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
|
setsockopt(ctx->socketHandle, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,18 +969,18 @@ UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient) {
|
||||||
ctx->socketInfo.sin6_flowinfo = 0;
|
ctx->socketInfo.sin6_flowinfo = 0;
|
||||||
ctx->socketInfo.sin6_scope_id = listenId.scope_id;
|
ctx->socketInfo.sin6_scope_id = listenId.scope_id;
|
||||||
if(bind(ctx->socketHandle, (const struct sockaddr *)&ctx->socketInfo,
|
if(bind(ctx->socketHandle, (const struct sockaddr *)&ctx->socketInfo,
|
||||||
sizeof(struct sockaddr_in6)) < 0) {
|
sizeof(UDPC_IPV6_SOCKADDR_TYPE)) < 0) {
|
||||||
// TODO maybe different way of handling init fail
|
// TODO maybe different way of handling init fail
|
||||||
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to bind socket");
|
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to bind socket");
|
||||||
CleanupSocket(ctx->socketHandle);
|
UDPC_CLEANUPSOCKET(ctx->socketHandle);
|
||||||
delete ctx;
|
delete ctx;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO verify this is necessary to get the listen port
|
// TODO verify this is necessary to get the listen port
|
||||||
if(ctx->socketInfo.sin6_port == 0) {
|
if(ctx->socketInfo.sin6_port == 0) {
|
||||||
struct sockaddr_in6 getInfo;
|
UDPC_IPV6_SOCKADDR_TYPE getInfo;
|
||||||
socklen_t size = sizeof(struct sockaddr_in6);
|
socklen_t size = sizeof(UDPC_IPV6_SOCKADDR_TYPE);
|
||||||
if(getsockname(ctx->socketHandle, (struct sockaddr *)&getInfo, &size) == 0) {
|
if(getsockname(ctx->socketHandle, (struct sockaddr *)&getInfo, &size) == 0) {
|
||||||
ctx->socketInfo.sin6_port = getInfo.sin6_port;
|
ctx->socketInfo.sin6_port = getInfo.sin6_port;
|
||||||
}
|
}
|
||||||
|
@ -941,7 +998,7 @@ UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient) {
|
||||||
#endif
|
#endif
|
||||||
// TODO maybe different way of handling init fail
|
// TODO maybe different way of handling init fail
|
||||||
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to set nonblocking on socket");
|
ctx->log(UDPC_LoggingType::UDPC_ERROR, "Failed to set nonblocking on socket");
|
||||||
CleanupSocket(ctx->socketHandle);
|
UDPC_CLEANUPSOCKET(ctx->socketHandle);
|
||||||
delete ctx;
|
delete ctx;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -972,6 +1029,9 @@ void UDPC_destroy(UDPC_HContext ctx) {
|
||||||
UDPC_ctx->threadRunning.store(false);
|
UDPC_ctx->threadRunning.store(false);
|
||||||
UDPC_ctx->thread.join();
|
UDPC_ctx->thread.join();
|
||||||
}
|
}
|
||||||
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
delete UDPC_ctx;
|
delete UDPC_ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1167,7 +1227,7 @@ const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId) {
|
||||||
return UDPC_atostr(ctx, connectionId.addr);
|
return UDPC_atostr(ctx, connectionId.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *UDPC_atostr(UDPC_HContext ctx, struct in6_addr addr) {
|
const char *UDPC_atostr(UDPC_HContext ctx, UDPC_IPV6_ADDR_TYPE addr) {
|
||||||
UDPC::Context *c = UDPC::verifyContext(ctx);
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
||||||
if(!c) {
|
if(!c) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1196,12 +1256,12 @@ const char *UDPC_atostr(UDPC_HContext ctx, struct in6_addr addr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr.s6_addr[i] == 0 && (headIndex - index <= 1 || c->atostrBuf[index] == ':')) {
|
if(UDPC_IPV6_ADDR_SUB(addr)[i] == 0 && (headIndex - index <= 1 || c->atostrBuf[index] == ':')) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
std::stringstream sstream;
|
std::stringstream sstream;
|
||||||
sstream << std::setw(2) << std::setfill('0')
|
sstream << std::setw(2) << std::setfill('0')
|
||||||
<< std::hex << (unsigned int) addr.s6_addr[i];
|
<< std::hex << (unsigned int) UDPC_IPV6_ADDR_SUB(addr)[i];
|
||||||
std::string out(sstream.str());
|
std::string out(sstream.str());
|
||||||
unsigned int outOffset = 0;
|
unsigned int outOffset = 0;
|
||||||
if(headIndex - index <= 1 || c->atostrBuf[index - 1] == ':') {
|
if(headIndex - index <= 1 || c->atostrBuf[index - 1] == ':') {
|
||||||
|
@ -1236,8 +1296,8 @@ const char *UDPC_atostr(UDPC_HContext ctx, struct in6_addr addr) {
|
||||||
return c->atostrBuf + headIndex;
|
return c->atostrBuf + headIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct in6_addr UDPC_strtoa(const char *addrStr) {
|
UDPC_IPV6_ADDR_TYPE UDPC_strtoa(const char *addrStr) {
|
||||||
struct in6_addr result = in6addr_loopback;
|
UDPC_IPV6_ADDR_TYPE result = in6addr_loopback;
|
||||||
std::cmatch matchResults;
|
std::cmatch matchResults;
|
||||||
if(std::regex_match(addrStr, matchResults, ipv6_regex_nolink)) {
|
if(std::regex_match(addrStr, matchResults, ipv6_regex_nolink)) {
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
|
@ -1249,8 +1309,8 @@ struct in6_addr UDPC_strtoa(const char *addrStr) {
|
||||||
|
|
||||||
const auto checkInc = [&result, &index, &bytes] () -> bool {
|
const auto checkInc = [&result, &index, &bytes] () -> bool {
|
||||||
if(index < 15) {
|
if(index < 15) {
|
||||||
result.s6_addr[index++] = bytes[0];
|
UDPC_IPV6_ADDR_SUB(result)[index++] = bytes[0];
|
||||||
result.s6_addr[index++] = bytes[1];
|
UDPC_IPV6_ADDR_SUB(result)[index++] = bytes[1];
|
||||||
bytes[0] = 0;
|
bytes[0] = 0;
|
||||||
bytes[1] = 0;
|
bytes[1] = 0;
|
||||||
return false;
|
return false;
|
||||||
|
@ -1400,31 +1460,31 @@ struct in6_addr UDPC_strtoa(const char *addrStr) {
|
||||||
return in6addr_loopback;
|
return in6addr_loopback;
|
||||||
}
|
}
|
||||||
for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
|
for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
|
||||||
result.s6_addr[i] = result.s6_addr[i - strIndex];
|
UDPC_IPV6_ADDR_SUB(result)[i] = UDPC_IPV6_ADDR_SUB(result)[i - strIndex];
|
||||||
result.s6_addr[i - strIndex] = 0;
|
UDPC_IPV6_ADDR_SUB(result)[i - strIndex] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(std::regex_match(addrStr, matchResults, ipv4_regex)) {
|
} else if(std::regex_match(addrStr, matchResults, ipv4_regex)) {
|
||||||
for(unsigned int i = 0; i < 10; ++i) {
|
for(unsigned int i = 0; i < 10; ++i) {
|
||||||
result.s6_addr[i] = 0;
|
UDPC_IPV6_ADDR_SUB(result)[i] = 0;
|
||||||
}
|
}
|
||||||
result.s6_addr[10] = 0xFF;
|
UDPC_IPV6_ADDR_SUB(result)[10] = 0xFF;
|
||||||
result.s6_addr[11] = 0xFF;
|
UDPC_IPV6_ADDR_SUB(result)[11] = 0xFF;
|
||||||
for(unsigned int i = 0; i < 4; ++i) {
|
for(unsigned int i = 0; i < 4; ++i) {
|
||||||
result.s6_addr[12 + i] = std::stoi(matchResults[i + 1].str());
|
UDPC_IPV6_ADDR_SUB(result)[12 + i] = std::stoi(matchResults[i + 1].str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct in6_addr UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out) {
|
UDPC_IPV6_ADDR_TYPE UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out) {
|
||||||
const auto checkSetOut = [&linkId_out] (uint32_t val) {
|
const auto checkSetOut = [&linkId_out] (uint32_t val) {
|
||||||
if(linkId_out) {
|
if(linkId_out) {
|
||||||
*linkId_out = val;
|
*linkId_out = val;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct in6_addr result({0});
|
UDPC_IPV6_ADDR_TYPE result({0});
|
||||||
std::cmatch matchResults;
|
std::cmatch matchResults;
|
||||||
const char *linkName = nullptr;
|
const char *linkName = nullptr;
|
||||||
|
|
||||||
|
@ -1438,8 +1498,8 @@ struct in6_addr UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out) {
|
||||||
|
|
||||||
const auto checkInc = [&result, &index, &bytes] () -> bool {
|
const auto checkInc = [&result, &index, &bytes] () -> bool {
|
||||||
if(index < 15) {
|
if(index < 15) {
|
||||||
result.s6_addr[index++] = bytes[0];
|
UDPC_IPV6_ADDR_SUB(result)[index++] = bytes[0];
|
||||||
result.s6_addr[index++] = bytes[1];
|
UDPC_IPV6_ADDR_SUB(result)[index++] = bytes[1];
|
||||||
bytes[0] = 0;
|
bytes[0] = 0;
|
||||||
bytes[1] = 0;
|
bytes[1] = 0;
|
||||||
return false;
|
return false;
|
||||||
|
@ -1605,32 +1665,36 @@ struct in6_addr UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out) {
|
||||||
return in6addr_loopback;
|
return in6addr_loopback;
|
||||||
}
|
}
|
||||||
for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
|
for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
|
||||||
result.s6_addr[i] = result.s6_addr[i - strIndex];
|
UDPC_IPV6_ADDR_SUB(result)[i] = UDPC_IPV6_ADDR_SUB(result)[i - strIndex];
|
||||||
result.s6_addr[i - strIndex] = 0;
|
UDPC_IPV6_ADDR_SUB(result)[i - strIndex] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t scope_id;
|
uint32_t scope_id;
|
||||||
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
scope_id = if_nametoindex(linkName);
|
if(std::regex_match(linkName, regex_numeric)) {
|
||||||
if(scope_id == 0) {
|
scope_id = std::atoi(linkName);
|
||||||
checkSetOut(0);
|
} else {
|
||||||
return in6addr_loopback;
|
scope_id = if_nametoindex(linkName);
|
||||||
|
if(scope_id == 0) {
|
||||||
|
checkSetOut(0);
|
||||||
|
return in6addr_loopback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
||||||
struct ifreq req{{0}, 0, 0};
|
struct ifreq req{{0}, 0, 0};
|
||||||
std::strncpy(req.ifr_name, linkName, IFNAMSIZ);
|
std::strncpy(req.ifr_name, linkName, IFNAMSIZ);
|
||||||
int socketHandle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
int socketHandle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if(ioctl(socketHandle, SIOCGIFINDEX, &req) < 0) {
|
if(ioctl(socketHandle, SIOCGIFINDEX, &req) < 0) {
|
||||||
CleanupSocket(socketHandle);
|
UDPC_CLEANUPSOCKET(socketHandle);
|
||||||
checkSetOut(0);
|
checkSetOut(0);
|
||||||
return in6addr_loopback;
|
return in6addr_loopback;
|
||||||
}
|
}
|
||||||
scope_id = req.ifr_ifindex;
|
scope_id = req.ifr_ifindex;
|
||||||
|
UDPC_CLEANUPSOCKET(socketHandle);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CleanupSocket(socketHandle);
|
|
||||||
checkSetOut(scope_id);
|
checkSetOut(scope_id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,17 +20,29 @@
|
||||||
// OS-based networking macros
|
// OS-based networking macros
|
||||||
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <Ws2ipdef.h>
|
||||||
|
#include <In6addr.h>
|
||||||
|
|
||||||
#define CleanupSocket(x) closesocket(x)
|
#define UDPC_CLEANUPSOCKET(x) closesocket(x)
|
||||||
|
#define UDPC_SOCKETTYPE SOCKET
|
||||||
|
#define UDPC_IPV6_SOCKADDR_TYPE SOCKADDR_IN6
|
||||||
|
#define UDPC_IPV6_ADDR_TYPE IN6_ADDR
|
||||||
|
#define UDPC_IPV6_ADDR_SUB(addr) addr.u.Byte
|
||||||
|
#define UDPC_SOCKET_RETURN_ERROR(socket) (socket == INVALID_SOCKET)
|
||||||
#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define CleanupSocket(x) close(x)
|
#define UDPC_CLEANUPSOCKET(x) close(x)
|
||||||
|
#define UDPC_SOCKETTYPE int
|
||||||
|
#define UDPC_IPV6_SOCKADDR_TYPE struct sockaddr_in6
|
||||||
|
#define UDPC_IPV6_ADDR_TYPE struct in6_addr
|
||||||
|
#define UDPC_IPV6_ADDR_SUB(addr) addr.s6_addr
|
||||||
|
#define UDPC_SOCKET_RETURN_ERROR(socket) (socket <= 0)
|
||||||
#else
|
#else
|
||||||
#define CleanupSocket(x) ((void)0)
|
#define UDPC_CLEANUPSOCKET(x) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// other defines
|
// other defines
|
||||||
|
@ -51,7 +63,7 @@ typedef struct UDPC_Context *UDPC_HContext;
|
||||||
typedef enum { UDPC_SILENT, UDPC_ERROR, UDPC_WARNING, UDPC_VERBOSE, UDPC_INFO } UDPC_LoggingType;
|
typedef enum { UDPC_SILENT, UDPC_ERROR, UDPC_WARNING, UDPC_VERBOSE, UDPC_INFO } UDPC_LoggingType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct in6_addr addr;
|
UDPC_IPV6_ADDR_TYPE addr;
|
||||||
uint32_t scope_id;
|
uint32_t scope_id;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} UDPC_ConnectionId;
|
} UDPC_ConnectionId;
|
||||||
|
@ -72,9 +84,9 @@ typedef struct {
|
||||||
} UDPC_PacketInfo;
|
} UDPC_PacketInfo;
|
||||||
|
|
||||||
/// port should be in native byte order (not network/big-endian)
|
/// port should be in native byte order (not network/big-endian)
|
||||||
UDPC_ConnectionId UDPC_create_id(struct in6_addr addr, uint16_t port);
|
UDPC_ConnectionId UDPC_create_id(UDPC_IPV6_ADDR_TYPE addr, uint16_t port);
|
||||||
|
|
||||||
UDPC_ConnectionId UDPC_create_id_full(struct in6_addr addr, uint32_t scope_id, uint16_t port);
|
UDPC_ConnectionId UDPC_create_id_full(UDPC_IPV6_ADDR_TYPE addr, uint32_t scope_id, uint16_t port);
|
||||||
|
|
||||||
UDPC_ConnectionId UDPC_create_id_anyaddr(uint16_t port);
|
UDPC_ConnectionId UDPC_create_id_anyaddr(uint16_t port);
|
||||||
|
|
||||||
|
@ -107,12 +119,12 @@ UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx);
|
||||||
|
|
||||||
const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
|
const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
|
||||||
|
|
||||||
const char *UDPC_atostr(UDPC_HContext ctx, struct in6_addr addr);
|
const char *UDPC_atostr(UDPC_HContext ctx, UDPC_IPV6_ADDR_TYPE addr);
|
||||||
|
|
||||||
/// addrStr must be a valid ipv6 address or a valid ipv4 address
|
/// addrStr must be a valid ipv6 address or a valid ipv4 address
|
||||||
struct in6_addr UDPC_strtoa(const char *addrStr);
|
UDPC_IPV6_ADDR_TYPE UDPC_strtoa(const char *addrStr);
|
||||||
|
|
||||||
struct in6_addr UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out);
|
UDPC_IPV6_ADDR_TYPE UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue