Fix Windows support

This commit is contained in:
Stephen Seo 2019-09-19 12:23:15 +09:00
parent 0e22357d55
commit 71f7bc4977
4 changed files with 145 additions and 65 deletions

View file

@ -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")

View file

@ -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;

View file

@ -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;
} }

View file

@ -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
} }