Replace ipv4 with ipv6

ipv6 also supports sending to ipv4.
This commit is contained in:
Stephen Seo 2019-09-07 16:36:11 +09:00
parent 38eb06f105
commit 255930db9a
4 changed files with 529 additions and 285 deletions

View file

@ -12,8 +12,8 @@
#define UDPC_ID_NO_REC_CHK 0x20000000 #define UDPC_ID_NO_REC_CHK 0x20000000
#define UDPC_ID_RESENDING 0x10000000 #define UDPC_ID_RESENDING 0x10000000
#define UDPC_ATOSTR_BUFCOUNT 64 #define UDPC_ATOSTR_BUFCOUNT 32
#define UDPC_ATOSTR_BUFSIZE 16 #define UDPC_ATOSTR_BUFSIZE 40
#define UDPC_ATOSTR_SIZE (UDPC_ATOSTR_BUFCOUNT * UDPC_ATOSTR_BUFSIZE) #define UDPC_ATOSTR_SIZE (UDPC_ATOSTR_BUFCOUNT * UDPC_ATOSTR_BUFSIZE)
#include <atomic> #include <atomic>
@ -38,7 +38,6 @@ static const auto ONE_SECOND = std::chrono::seconds(1);
static const auto TEN_SECONDS = std::chrono::seconds(10); static const auto TEN_SECONDS = std::chrono::seconds(10);
static const auto THIRTY_SECONDS = std::chrono::seconds(30); static const auto THIRTY_SECONDS = std::chrono::seconds(30);
static uint32_t LOCAL_ADDR = 0;
static const auto INIT_PKT_INTERVAL_DT = std::chrono::seconds(5); static const auto INIT_PKT_INTERVAL_DT = std::chrono::seconds(5);
static const auto HEARTBEAT_PKT_INTERVAL_DT = std::chrono::milliseconds(150); static const auto HEARTBEAT_PKT_INTERVAL_DT = std::chrono::milliseconds(150);
static const auto PACKET_TIMEOUT_TIME = ONE_SECOND; static const auto PACKET_TIMEOUT_TIME = ONE_SECOND;
@ -63,6 +62,10 @@ struct ConnectionIdHasher {
std::size_t operator()(const UDPC_ConnectionId& key) const; std::size_t operator()(const UDPC_ConnectionId& key) const;
}; };
struct IPV6_Hasher {
std::size_t operator()(const struct in6_addr& addr) const;
};
struct ConnectionData { struct ConnectionData {
ConnectionData(); ConnectionData();
ConnectionData(bool isServer, Context *ctx); ConnectionData(bool isServer, Context *ctx);
@ -93,7 +96,7 @@ struct ConnectionData {
std::chrono::steady_clock::duration toggleT; std::chrono::steady_clock::duration toggleT;
std::chrono::steady_clock::duration toggleTimer; std::chrono::steady_clock::duration toggleTimer;
std::chrono::steady_clock::duration toggledTimer; std::chrono::steady_clock::duration toggledTimer;
uint32_t addr; // in network order struct in6_addr addr; // in network order
uint16_t port; // in native order uint16_t port; // in native order
std::deque<UDPC_PacketInfo> sentPkts; std::deque<UDPC_PacketInfo> sentPkts;
TSQueue<UDPC_PacketInfo> sendPkts; TSQueue<UDPC_PacketInfo> sendPkts;
@ -237,14 +240,14 @@ public:
char atostrBuf[UDPC_ATOSTR_SIZE]; char atostrBuf[UDPC_ATOSTR_SIZE];
int socketHandle; int socketHandle;
struct sockaddr_in socketInfo; struct sockaddr_in6 socketInfo;
std::chrono::steady_clock::time_point lastUpdated; std::chrono::steady_clock::time_point lastUpdated;
// ipv4 address and port (as UDPC_ConnectionId) to ConnectionData // ipv6 address and port (as UDPC_ConnectionId) to ConnectionData
std::unordered_map<UDPC_ConnectionId, ConnectionData, ConnectionIdHasher> conMap; std::unordered_map<UDPC_ConnectionId, ConnectionData, ConnectionIdHasher> conMap;
// ipv4 address to all connected UDPC_ConnectionId // ipv6 address to all connected UDPC_ConnectionId
std::unordered_map<uint32_t, std::unordered_set<UDPC_ConnectionId, ConnectionIdHasher> > addrConMap; std::unordered_map<struct in6_addr, std::unordered_set<UDPC_ConnectionId, ConnectionIdHasher>, IPV6_Hasher> addrConMap;
// id to ipv4 address and port (as UDPC_ConnectionId) // id to ipv6 address and port (as UDPC_ConnectionId)
std::unordered_map<uint32_t, UDPC_ConnectionId> idMap; std::unordered_map<uint32_t, UDPC_ConnectionId> idMap;
std::default_random_engine rng_engine; std::default_random_engine rng_engine;
@ -273,8 +276,12 @@ float timePointsToFSec(
const std::chrono::steady_clock::time_point& older, const std::chrono::steady_clock::time_point& older,
const std::chrono::steady_clock::time_point& newer); const std::chrono::steady_clock::time_point& newer);
UDPC_PacketInfo get_empty_pinfo();
} // namespace UDPC } // namespace UDPC
bool operator ==(const UDPC_ConnectionId& a, const UDPC_ConnectionId& b); bool operator ==(const UDPC_ConnectionId& a, const UDPC_ConnectionId& b);
bool operator ==(const struct in6_addr& a, const struct in6_addr& b);
#endif #endif

View file

@ -8,6 +8,9 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include <string>
#include <sstream>
#include <ios>
UDPC::SentPktInfo::SentPktInfo() : UDPC::SentPktInfo::SentPktInfo() :
id(0), id(0),
@ -15,13 +18,29 @@ 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 {
return std::hash<uint32_t>()(key.addr) ^ (std::hash<uint16_t>()(key.port) << 1); std::string value((const char*)key.addr.s6_addr, 16);
value.push_back((char)((key.port >> 8) & 0xFF));
value.push_back((char)(key.port & 0xFF));
return std::hash<std::string>()(value);
}
std::size_t UDPC::IPV6_Hasher::operator()(const struct in6_addr& addr) const {
return std::hash<std::string>()(std::string((const char*)addr.s6_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.port == b.port; return a.addr == b.addr && a.port == b.port;
} }
bool operator ==(const struct in6_addr& a, const struct in6_addr& b) {
for(unsigned int i = 0; i < 16; ++i) {
if(a.s6_addr[i] != b.s6_addr[i]) {
return false;
}
}
return true;
}
UDPC::ConnectionData::ConnectionData() : UDPC::ConnectionData::ConnectionData() :
flags(), flags(),
id(0), id(0),
@ -86,14 +105,6 @@ rng_engine()
flags.reset(0); flags.reset(0);
} }
if(UDPC::LOCAL_ADDR == 0) {
if(UDPC::isBigEndian()) {
UDPC::LOCAL_ADDR = 0x7F000001;
} else {
UDPC::LOCAL_ADDR = 0x0100007F;
}
}
rng_engine.seed(std::chrono::system_clock::now().time_since_epoch().count()); rng_engine.seed(std::chrono::system_clock::now().time_since_epoch().count());
} }
@ -173,29 +184,54 @@ float UDPC::timePointsToFSec(
* (float)decltype(dt)::period::num / (float)decltype(dt)::period::den; * (float)decltype(dt)::period::num / (float)decltype(dt)::period::den;
} }
UDPC_ConnectionId UDPC_create_id(uint32_t addr, uint16_t port) { UDPC_PacketInfo UDPC::get_empty_pinfo() {
return UDPC_PacketInfo {
{0}, // data (array)
0, // flags
0, // dataSize
{ // sender
{0}, // ipv6 addr
0 // port
},
{ // receiver
{0}, // ipv6 addr
0 // port
},
};
}
UDPC_ConnectionId UDPC_create_id(struct in6_addr addr, uint16_t port) {
return UDPC_ConnectionId{addr, port}; return UDPC_ConnectionId{addr, port};
} }
UDPC_HContext UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient) { UDPC_ConnectionId UDPC_create_id_anyaddr(uint16_t port) {
return UDPC_ConnectionId{in6addr_any, port};
}
UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient) {
UDPC::Context *ctx = new UDPC::Context(false); UDPC::Context *ctx = new UDPC::Context(false);
ctx->flags.set(1, isClient); ctx->flags.set(1, isClient);
// create socket // create socket
ctx->socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ctx->socketHandle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if(ctx->socketHandle <= 0) { if(ctx->socketHandle <= 0) {
// TODO maybe different way of handling init fail // TODO maybe different way of handling init fail
delete ctx; delete ctx;
return nullptr; return nullptr;
} }
// allow ipv4 connections on ipv6 socket
{
int no = 0;
setsockopt(ctx->socketHandle, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
}
// bind socket // bind socket
ctx->socketInfo.sin_family = AF_INET; ctx->socketInfo.sin6_family = AF_INET6;
ctx->socketInfo.sin_addr.s_addr = ctx->socketInfo.sin6_addr = listenId.addr;
(listenAddr == 0 ? INADDR_ANY : listenAddr); ctx->socketInfo.sin6_port = htons(listenId.port);
ctx->socketInfo.sin_port = htons(listenPort);
if(bind(ctx->socketHandle, (const struct sockaddr *)&ctx->socketInfo, if(bind(ctx->socketHandle, (const struct sockaddr *)&ctx->socketInfo,
sizeof(struct sockaddr_in)) < 0) { sizeof(struct sockaddr_in6)) < 0) {
// TODO maybe different way of handling init fail // TODO maybe different way of handling init fail
CleanupSocket(ctx->socketHandle); CleanupSocket(ctx->socketHandle);
delete ctx; delete ctx;
@ -203,11 +239,11 @@ UDPC_HContext UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient)
} }
// TODO verify this is necessary to get the listen port // TODO verify this is necessary to get the listen port
if(ctx->socketInfo.sin_port == 0) { if(ctx->socketInfo.sin6_port == 0) {
struct sockaddr_in getInfo; struct sockaddr_in6 getInfo;
socklen_t size = sizeof(struct sockaddr_in); socklen_t size = sizeof(struct sockaddr_in6);
if(getsockname(ctx->socketHandle, (struct sockaddr *)&getInfo, &size) == 0) { if(getsockname(ctx->socketHandle, (struct sockaddr *)&getInfo, &size) == 0) {
ctx->socketInfo.sin_port = getInfo.sin_port; ctx->socketInfo.sin6_port = getInfo.sin6_port;
} }
} }
@ -230,10 +266,9 @@ UDPC_HContext UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient)
return (UDPC_HContext) ctx; return (UDPC_HContext) ctx;
} }
UDPC_HContext UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr, UDPC_HContext UDPC_init_threaded_update(UDPC_ConnectionId listenId,
int isClient) { int isClient) {
UDPC::Context *ctx = UDPC::Context *ctx = (UDPC::Context *)UDPC_init(listenId, isClient);
(UDPC::Context *)UDPC_init(listenPort, listenAddr, isClient);
if(!ctx) { if(!ctx) {
return nullptr; return nullptr;
} }
@ -270,7 +305,7 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::VERBOSE, UDPC_LoggingType::VERBOSE,
"Timed out connection with ", "Timed out connection with ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
continue; continue;
@ -284,7 +319,7 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::INFO, UDPC_LoggingType::INFO,
"Switching to bad mode in connection with ", "Switching to bad mode in connection with ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
iter->second.flags.reset(1); iter->second.flags.reset(1);
@ -310,7 +345,7 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::INFO, UDPC_LoggingType::INFO,
"Switching to good mode in connection with ", "Switching to good mode in connection with ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
iter->second.flags.set(1); iter->second.flags.set(1);
@ -379,22 +414,22 @@ void UDPC_update(UDPC_HContext ctx) {
nullptr, nullptr,
0x1); 0x1);
struct sockaddr_in destinationInfo; struct sockaddr_in6 destinationInfo;
destinationInfo.sin_family = AF_INET; destinationInfo.sin6_family = AF_INET6;
destinationInfo.sin_addr.s_addr = iter->second.addr; std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
destinationInfo.sin_port = htons(iter->second.port); destinationInfo.sin6_port = htons(iter->second.port);
long int sentBytes = sendto( long int sentBytes = sendto(
c->socketHandle, c->socketHandle,
buf.get(), buf.get(),
20, 20,
0, 0,
(struct sockaddr*) &destinationInfo, (struct sockaddr*) &destinationInfo,
sizeof(struct sockaddr_in)); sizeof(struct sockaddr_in6));
if(sentBytes != 20) { if(sentBytes != 20) {
c->log( c->log(
UDPC_LoggingType::ERROR, UDPC_LoggingType::ERROR,
"Failed to send packet to initiate connection to ", "Failed to send packet to initiate connection to ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
continue; continue;
@ -414,22 +449,22 @@ void UDPC_update(UDPC_HContext ctx) {
&iter->second.lseq, &iter->second.lseq,
0x1); 0x1);
struct sockaddr_in destinationInfo; struct sockaddr_in6 destinationInfo;
destinationInfo.sin_family = AF_INET; destinationInfo.sin6_family = AF_INET6;
destinationInfo.sin_addr.s_addr = iter->second.addr; std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
destinationInfo.sin_port = htons(iter->second.port); destinationInfo.sin6_port = htons(iter->second.port);
long int sentBytes = sendto( long int sentBytes = sendto(
c->socketHandle, c->socketHandle,
buf.get(), buf.get(),
20, 20,
0, 0,
(struct sockaddr*) &destinationInfo, (struct sockaddr*) &destinationInfo,
sizeof(struct sockaddr_in)); sizeof(struct sockaddr_in6));
if(sentBytes != 20) { if(sentBytes != 20) {
c->log( c->log(
UDPC_LoggingType::ERROR, UDPC_LoggingType::ERROR,
"Failed to send packet to initiate connection to ", "Failed to send packet to initiate connection to ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
continue; continue;
@ -456,31 +491,31 @@ void UDPC_update(UDPC_HContext ctx) {
&iter->second.lseq, &iter->second.lseq,
0); 0);
struct sockaddr_in destinationInfo; struct sockaddr_in6 destinationInfo;
destinationInfo.sin_family = AF_INET; destinationInfo.sin6_family = AF_INET6;
destinationInfo.sin_addr.s_addr = iter->second.addr; std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
destinationInfo.sin_port = htons(iter->second.port); destinationInfo.sin6_port = htons(iter->second.port);
long int sentBytes = sendto( long int sentBytes = sendto(
c->socketHandle, c->socketHandle,
buf.get(), buf.get(),
20, 20,
0, 0,
(struct sockaddr*) &destinationInfo, (struct sockaddr*) &destinationInfo,
sizeof(struct sockaddr_in)); sizeof(struct sockaddr_in6));
if(sentBytes != 20) { if(sentBytes != 20) {
c->log( c->log(
UDPC_LoggingType::ERROR, UDPC_LoggingType::ERROR,
"Failed to send heartbeat packet to ", "Failed to send heartbeat packet to ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
continue; continue;
} }
UDPC_PacketInfo pInfo{{0}, 0, 0, 0, 0, 0, 0}; UDPC_PacketInfo pInfo = UDPC::get_empty_pinfo();
pInfo.sender.addr = UDPC::LOCAL_ADDR; pInfo.sender.addr = in6addr_loopback;
pInfo.receiver.addr = iter->first.addr; pInfo.receiver.addr = iter->first.addr;
pInfo.sender.port = c->socketInfo.sin_port; pInfo.sender.port = c->socketInfo.sin6_port;
pInfo.receiver.port = iter->second.port; pInfo.receiver.port = iter->second.port;
*((uint32_t*)(pInfo.data + 8)) = iter->second.lseq - 1; *((uint32_t*)(pInfo.data + 8)) = iter->second.lseq - 1;
@ -493,7 +528,7 @@ void UDPC_update(UDPC_HContext ctx) {
iter->second.sentInfoMap.insert(std::make_pair(sentPktInfo->id, sentPktInfo)); iter->second.sentInfoMap.insert(std::make_pair(sentPktInfo->id, sentPktInfo));
} else { } else {
// sendPkts or priorityPkts not empty // sendPkts or priorityPkts not empty
UDPC_PacketInfo pInfo; UDPC_PacketInfo pInfo = UDPC::get_empty_pinfo();
bool isResending = false; bool isResending = false;
if(!iter->second.priorityPkts.empty()) { if(!iter->second.priorityPkts.empty()) {
// TODO verify getting struct copy is valid // TODO verify getting struct copy is valid
@ -515,22 +550,22 @@ void UDPC_update(UDPC_HContext ctx) {
(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_in destinationInfo; struct sockaddr_in6 destinationInfo;
destinationInfo.sin_family = AF_INET; destinationInfo.sin6_family = AF_INET6;
destinationInfo.sin_addr.s_addr = iter->second.addr; std::memcpy(destinationInfo.sin6_addr.s6_addr, iter->first.addr.s6_addr, 16);
destinationInfo.sin_port = htons(iter->second.port); destinationInfo.sin6_port = htons(iter->second.port);
long int sentBytes = sendto( long int sentBytes = sendto(
c->socketHandle, c->socketHandle,
buf.get(), buf.get(),
pInfo.dataSize + 20, pInfo.dataSize + 20,
0, 0,
(struct sockaddr*) &destinationInfo, (struct sockaddr*) &destinationInfo,
sizeof(struct sockaddr_in)); sizeof(struct sockaddr_in6));
if(sentBytes != 20 + pInfo.dataSize) { if(sentBytes != 20 + pInfo.dataSize) {
c->log( c->log(
UDPC_LoggingType::ERROR, UDPC_LoggingType::ERROR,
"Failed to send packet to ", "Failed to send packet to ",
UDPC_atostr(ctx, iter->second.addr), UDPC_atostr(ctx, iter->first),
":", ":",
iter->second.port); iter->second.port);
continue; continue;
@ -538,25 +573,25 @@ void UDPC_update(UDPC_HContext ctx) {
if((pInfo.flags & 0x4) == 0) { if((pInfo.flags & 0x4) == 0) {
// is check-received, store data in case packet gets lost // is check-received, store data in case packet gets lost
UDPC_PacketInfo sentPInfo; UDPC_PacketInfo sentPInfo = UDPC::get_empty_pinfo();
std::memcpy(sentPInfo.data, buf.get(), 20 + pInfo.dataSize); std::memcpy(sentPInfo.data, buf.get(), 20 + pInfo.dataSize);
sentPInfo.flags = 0; sentPInfo.flags = 0;
sentPInfo.dataSize = 20 + pInfo.dataSize; sentPInfo.dataSize = 20 + pInfo.dataSize;
sentPInfo.sender.addr = UDPC::LOCAL_ADDR; sentPInfo.sender.addr = in6addr_loopback;
sentPInfo.receiver.addr = iter->first.addr; sentPInfo.receiver.addr = iter->first.addr;
sentPInfo.sender.port = c->socketInfo.sin_port; sentPInfo.sender.port = c->socketInfo.sin6_port;
sentPInfo.receiver.port = iter->second.port; sentPInfo.receiver.port = iter->second.port;
iter->second.sentPkts.push_back(std::move(pInfo)); iter->second.sentPkts.push_back(std::move(pInfo));
iter->second.cleanupSentPkts(); iter->second.cleanupSentPkts();
} else { } else {
// is not check-received, only id stored in data array // is not check-received, only id stored in data array
UDPC_PacketInfo sentPInfo; UDPC_PacketInfo sentPInfo = UDPC::get_empty_pinfo();
sentPInfo.flags = 0x4; sentPInfo.flags = 0x4;
sentPInfo.dataSize = 0; sentPInfo.dataSize = 0;
sentPInfo.sender.addr = UDPC::LOCAL_ADDR; sentPInfo.sender.addr = in6addr_loopback;
sentPInfo.receiver.addr = iter->first.addr; sentPInfo.receiver.addr = iter->first.addr;
sentPInfo.sender.port = c->socketInfo.sin_port; sentPInfo.sender.port = c->socketInfo.sin6_port;
sentPInfo.receiver.port = iter->second.port; sentPInfo.receiver.port = iter->second.port;
*((uint32_t*)(sentPInfo.data + 8)) = iter->second.lseq - 1; *((uint32_t*)(sentPInfo.data + 8)) = iter->second.lseq - 1;
@ -575,7 +610,7 @@ void UDPC_update(UDPC_HContext ctx) {
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS #if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
typedef int socklen_t; typedef int socklen_t;
#endif #endif
struct sockaddr_in receivedData; struct sockaddr_in6 receivedData;
socklen_t receivedDataSize = sizeof(receivedData); socklen_t receivedDataSize = sizeof(receivedData);
int bytes = recvfrom( int bytes = recvfrom(
c->socketHandle, c->socketHandle,
@ -593,9 +628,9 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::INFO, UDPC_LoggingType::INFO,
"Received packet is smaller than header, ignoring packet from ", "Received packet is smaller than header, ignoring packet from ",
UDPC_atostr(ctx, receivedData.sin_addr.s_addr), UDPC_atostr(ctx, UDPC_ConnectionId{receivedData.sin6_addr, 0}),
":", ":",
receivedData.sin_port); receivedData.sin6_port);
return; return;
} }
@ -605,9 +640,9 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::INFO, UDPC_LoggingType::INFO,
"Received packet has invalid protocol id, ignoring packet from ", "Received packet has invalid protocol id, ignoring packet from ",
UDPC_atostr(ctx, receivedData.sin_addr.s_addr), UDPC_atostr(ctx, UDPC_ConnectionId{receivedData.sin6_addr, 0}),
":", ":",
receivedData.sin_port); receivedData.sin6_port);
return; return;
} }
@ -622,7 +657,7 @@ void UDPC_update(UDPC_HContext ctx) {
bool isResending = conID & UDPC_ID_RESENDING; bool isResending = conID & UDPC_ID_RESENDING;
conID &= 0x0FFFFFFF; conID &= 0x0FFFFFFF;
UDPC_ConnectionId identifier{receivedData.sin_addr.s_addr, ntohs(receivedData.sin_port)}; UDPC_ConnectionId identifier{receivedData.sin6_addr, ntohs(receivedData.sin6_port)};
if(isConnect && c->flags.test(2)) { if(isConnect && c->flags.test(2)) {
// is connect packet and is accepting new connections // is connect packet and is accepting new connections
@ -632,12 +667,12 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::VERBOSE, UDPC_LoggingType::VERBOSE,
"Establishing connection with client ", "Establishing connection with client ",
UDPC_atostr(ctx, receivedData.sin_addr.s_addr), UDPC_atostr(ctx, UDPC_ConnectionId{receivedData.sin6_addr, 0}),
":", ":",
receivedData.sin_port); receivedData.sin6_port);
UDPC::ConnectionData newConnection(true, c); UDPC::ConnectionData newConnection(true, c);
newConnection.addr = receivedData.sin_addr.s_addr; newConnection.addr = receivedData.sin6_addr;
newConnection.port = ntohs(receivedData.sin_port); newConnection.port = ntohs(receivedData.sin6_port);
c->idMap.insert(std::make_pair(newConnection.id, identifier)); c->idMap.insert(std::make_pair(newConnection.id, identifier));
c->conMap.insert(std::make_pair(identifier, std::move(newConnection))); c->conMap.insert(std::make_pair(identifier, std::move(newConnection)));
@ -666,9 +701,9 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::VERBOSE, UDPC_LoggingType::VERBOSE,
"Established connection with server ", "Established connection with server ",
UDPC_atostr(ctx, receivedData.sin_addr.s_addr), UDPC_atostr(ctx, UDPC_ConnectionId{receivedData.sin6_addr, 0}),
":", ":",
receivedData.sin_port); receivedData.sin6_port);
// TODO trigger event client established connection with server // TODO trigger event client established connection with server
} }
return; return;
@ -687,9 +722,9 @@ void UDPC_update(UDPC_HContext ctx) {
c->log( c->log(
UDPC_LoggingType::INFO, UDPC_LoggingType::INFO,
"Received valid packet from ", "Received valid packet from ",
UDPC_atostr(ctx, receivedData.sin_addr.s_addr), UDPC_atostr(ctx, UDPC_ConnectionId{receivedData.sin6_addr, 0}),
":", ":",
receivedData.sin_port); receivedData.sin6_port);
// update rtt // update rtt
for(auto sentIter = iter->second.sentPkts.rbegin(); sentIter != iter->second.sentPkts.rend(); ++sentIter) { for(auto sentIter = iter->second.sentPkts.rbegin(); sentIter != iter->second.sentPkts.rend(); ++sentIter) {
@ -747,7 +782,7 @@ void UDPC_update(UDPC_HContext ctx) {
break; break;
} }
UDPC_PacketInfo resendingData; UDPC_PacketInfo resendingData = UDPC::get_empty_pinfo();
resendingData.dataSize = sentIter->dataSize - 20; resendingData.dataSize = sentIter->dataSize - 20;
std::memcpy(resendingData.data, sentIter->data + 20, resendingData.dataSize); std::memcpy(resendingData.data, sentIter->data + 20, resendingData.dataSize);
resendingData.flags = 0; resendingData.flags = 0;
@ -816,7 +851,7 @@ void UDPC_update(UDPC_HContext ctx) {
} }
if(bytes > 20) { if(bytes > 20) {
UDPC_PacketInfo recPktInfo; UDPC_PacketInfo recPktInfo = UDPC::get_empty_pinfo();
std::memcpy(recPktInfo.data, c->recvBuf, bytes); std::memcpy(recPktInfo.data, c->recvBuf, bytes);
recPktInfo.dataSize = bytes; recPktInfo.dataSize = bytes;
recPktInfo.flags = recPktInfo.flags =
@ -824,10 +859,10 @@ void UDPC_update(UDPC_HContext ctx) {
| (isPing ? 0x2 : 0) | (isPing ? 0x2 : 0)
| (isNotRecChecked ? 0x4 : 0) | (isNotRecChecked ? 0x4 : 0)
| (isResending ? 0x8 : 0); | (isResending ? 0x8 : 0);
recPktInfo.sender.addr = receivedData.sin_addr.s_addr; recPktInfo.sender.addr = receivedData.sin6_addr;
recPktInfo.receiver.addr = UDPC::LOCAL_ADDR; recPktInfo.receiver.addr = in6addr_loopback;
recPktInfo.sender.port = receivedData.sin_port; recPktInfo.sender.port = receivedData.sin6_port;
recPktInfo.receiver.port = c->socketInfo.sin_port; recPktInfo.receiver.port = c->socketInfo.sin6_port;
if(iter->second.receivedPkts.size() == iter->second.receivedPkts.capacity()) { if(iter->second.receivedPkts.size() == iter->second.receivedPkts.capacity()) {
c->log( c->log(
@ -844,38 +879,35 @@ void UDPC_update(UDPC_HContext ctx) {
} }
} }
void UDPC_client_initiate_connection(UDPC_HContext ctx, uint32_t addr, uint16_t port) { void UDPC_client_initiate_connection(UDPC_HContext ctx, UDPC_ConnectionId connectionId) {
UDPC::Context *c = UDPC::verifyContext(ctx); UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c || !c->flags.test(1)) { if(!c || !c->flags.test(1)) {
return; return;
} }
UDPC::ConnectionData newCon(false, c); UDPC::ConnectionData newCon(false, c);
UDPC_ConnectionId identifier{addr, port};
// TODO make thread safe by using mutex // TODO make thread safe by using mutex
c->conMap.insert(std::make_pair(identifier, std::move(newCon))); c->conMap.insert(std::make_pair(connectionId, std::move(newCon)));
auto addrConIter = c->addrConMap.find(addr); auto addrConIter = c->addrConMap.find(connectionId.addr);
if(addrConIter == c->addrConMap.end()) { if(addrConIter == c->addrConMap.end()) {
auto insertResult = c->addrConMap.insert(std::make_pair( auto insertResult = c->addrConMap.insert(std::make_pair(
addr, connectionId.addr,
std::unordered_set<UDPC_ConnectionId, UDPC::ConnectionIdHasher>{} std::unordered_set<UDPC_ConnectionId, UDPC::ConnectionIdHasher>{}
)); ));
assert(insertResult.second); assert(insertResult.second);
addrConIter = insertResult.first; addrConIter = insertResult.first;
} }
addrConIter->second.insert(identifier); addrConIter->second.insert(connectionId);
} }
int UDPC_get_queue_send_available(UDPC_HContext ctx, uint32_t addr, uint16_t port) { int UDPC_get_queue_send_available(UDPC_HContext ctx, UDPC_ConnectionId connectionId) {
UDPC::Context *c = UDPC::verifyContext(ctx); UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) { if(!c) {
return 0; return 0;
} }
UDPC_ConnectionId identifier{addr, port}; auto iter = c->conMap.find(connectionId);
auto iter = c->conMap.find(identifier);
if(iter != c->conMap.end()) { if(iter != c->conMap.end()) {
return iter->second.sendPkts.capacity() - iter->second.sendPkts.size(); return iter->second.sendPkts.capacity() - iter->second.sendPkts.size();
} else { } else {
@ -883,7 +915,7 @@ int UDPC_get_queue_send_available(UDPC_HContext ctx, uint32_t addr, uint16_t por
} }
} }
void UDPC_queue_send(UDPC_HContext ctx, uint32_t destAddr, uint16_t destPort, void UDPC_queue_send(UDPC_HContext ctx, UDPC_ConnectionId destinationId,
uint32_t isChecked, void *data, uint32_t size) { uint32_t isChecked, void *data, uint32_t size) {
if(size == 0 || !data) { if(size == 0 || !data) {
return; return;
@ -894,9 +926,7 @@ void UDPC_queue_send(UDPC_HContext ctx, uint32_t destAddr, uint16_t destPort,
return; return;
} }
UDPC_ConnectionId identifier{destAddr, destPort}; auto iter = c->conMap.find(destinationId);
auto iter = c->conMap.find(identifier);
if(iter == c->conMap.end()) { if(iter == c->conMap.end()) {
c->log( c->log(
UDPC_LoggingType::ERROR, UDPC_LoggingType::ERROR,
@ -905,12 +935,12 @@ void UDPC_queue_send(UDPC_HContext ctx, uint32_t destAddr, uint16_t destPort,
return; return;
} }
UDPC_PacketInfo sendInfo; UDPC_PacketInfo sendInfo = UDPC::get_empty_pinfo();
std::memcpy(sendInfo.data, data, size); std::memcpy(sendInfo.data, data, size);
sendInfo.dataSize = size; sendInfo.dataSize = size;
sendInfo.sender.addr = UDPC::LOCAL_ADDR; sendInfo.sender.addr = in6addr_loopback;
sendInfo.sender.port = c->socketInfo.sin_port; sendInfo.sender.port = c->socketInfo.sin6_port;
sendInfo.receiver.addr = destAddr; sendInfo.receiver.addr = destinationId.addr;
sendInfo.receiver.port = iter->second.port; sendInfo.receiver.port = iter->second.port;
sendInfo.flags = (isChecked ? 0x0 : 0x4); sendInfo.flags = (isChecked ? 0x0 : 0x4);
@ -925,53 +955,44 @@ int UDPC_set_accept_new_connections(UDPC_HContext ctx, int isAccepting) {
return c->isAcceptNewConnections.exchange(isAccepting == 0 ? false : true); return c->isAcceptNewConnections.exchange(isAccepting == 0 ? false : true);
} }
int UDPC_drop_connection(UDPC_HContext ctx, uint32_t addr, uint16_t port) { int UDPC_drop_connection(UDPC_HContext ctx, UDPC_ConnectionId connectionId, bool dropAllWithAddr) {
UDPC::Context *c = UDPC::verifyContext(ctx); UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) { if(!c) {
return 0; return 0;
} }
UDPC_ConnectionId identifier{addr, port}; if(dropAllWithAddr) {
auto addrConIter = c->addrConMap.find(connectionId.addr);
auto iter = c->conMap.find(identifier);
if(iter != c->conMap.end()) {
if(iter->second.flags.test(4)) {
c->idMap.erase(iter->second.id);
}
auto addrConIter = c->addrConMap.find(addr);
if(addrConIter != c->addrConMap.end()) { if(addrConIter != c->addrConMap.end()) {
addrConIter->second.erase(identifier); for(auto identIter = addrConIter->second.begin();
if(addrConIter->second.empty()) { identIter != addrConIter->second.end();
c->addrConMap.erase(addrConIter); ++identIter) {
auto conIter = c->conMap.find(*identIter);
assert(conIter != c->conMap.end());
if(conIter->second.flags.test(4)) {
c->idMap.erase(conIter->second.id);
}
c->conMap.erase(conIter);
} }
c->addrConMap.erase(addrConIter);
return 1;
} }
c->conMap.erase(iter); } else {
return 1; auto iter = c->conMap.find(connectionId);
} if(iter != c->conMap.end()) {
if(iter->second.flags.test(4)) {
return 0; c->idMap.erase(iter->second.id);
}
int UDPC_drop_connection_addr(UDPC_HContext ctx, uint32_t addr) {
UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) {
return 0;
}
auto addrConIter = c->addrConMap.find(addr);
if(addrConIter != c->addrConMap.end()) {
for(auto identIter = addrConIter->second.begin();
identIter != addrConIter->second.end();
++identIter) {
auto conIter = c->conMap.find(*identIter);
assert(conIter != c->conMap.end());
if(conIter->second.flags.test(4)) {
c->idMap.erase(conIter->second.id);
} }
c->conMap.erase(conIter); auto addrConIter = c->addrConMap.find(connectionId.addr);
if(addrConIter != c->addrConMap.end()) {
addrConIter->second.erase(connectionId);
if(addrConIter->second.empty()) {
c->addrConMap.erase(addrConIter);
}
}
c->conMap.erase(iter);
return 1;
} }
c->addrConMap.erase(addrConIter);
return 1;
} }
return 0; return 0;
@ -996,13 +1017,13 @@ UDPC_LoggingType set_logging_type(UDPC_HContext ctx, UDPC_LoggingType loggingTyp
UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx) { UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx) {
UDPC::Context *c = UDPC::verifyContext(ctx); UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) { if(!c) {
return UDPC_PacketInfo{{0}, 0, 0, 0, 0, 0, 0}; return UDPC::get_empty_pinfo();
} }
// TODO impl // TODO impl
return UDPC_PacketInfo{{0}, 0, 0, 0, 0, 0, 0}; return UDPC::get_empty_pinfo();
} }
const char *UDPC_atostr(UDPC_HContext ctx, uint32_t addr) { const char *UDPC_atostr(UDPC_HContext ctx, UDPC_ConnectionId connectionId) {
UDPC::Context *c = UDPC::verifyContext(ctx); UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) { if(!c) {
return nullptr; return nullptr;
@ -1010,55 +1031,220 @@ const char *UDPC_atostr(UDPC_HContext ctx, uint32_t addr) {
const uint32_t headIndex = const uint32_t headIndex =
c->atostrBufIndex.fetch_add(UDPC_ATOSTR_BUFSIZE) % UDPC_ATOSTR_SIZE; c->atostrBufIndex.fetch_add(UDPC_ATOSTR_BUFSIZE) % UDPC_ATOSTR_SIZE;
uint32_t index = headIndex; uint32_t index = headIndex;
for(int x = 0; x < 4; ++x) { bool usedDouble = false;
unsigned char temp = (addr >> (x * 8)) & 0xFF;
if(temp >= 100) { for(unsigned int i = 0; i < 16; ++i) {
c->atostrBuf[index++] = '0' + temp / 100; if(i != 0 && i % 2 == 0) {
if(headIndex - index > 1 && c->atostrBuf[index - 1] == ':') {
if(usedDouble) {
if(c->atostrBuf[index - 2] != ':') {
c->atostrBuf[index++] = '0';
c->atostrBuf[index++] = ':';
} else {
// continue use of double :, do nothing here
}
} else {
usedDouble = true;
c->atostrBuf[index++] = ':';
}
} else {
c->atostrBuf[index++] = ':';
}
} }
if(temp >= 10) {
c->atostrBuf[index++] = '0' + ((temp / 10) % 10);
}
c->atostrBuf[index++] = '0' + temp % 10;
if(x < 3) { if(connectionId.addr.s6_addr[i] == 0) {
c->atostrBuf[index++] = '.'; continue;
} else {
std::stringstream sstream;
sstream << std::hex << (unsigned int) connectionId.addr.s6_addr[i];
std::string out(sstream.str());
if(out.size() == 1) {
if(out[0] != '0') {
std::memcpy(c->atostrBuf + index, out.c_str(), 1);
++index;
}
} else {
std::memcpy(c->atostrBuf + index, out.c_str(), 2);
index += 2;
}
} }
} }
if(c->atostrBuf[index - 1] == ':'
&& (headIndex - index <= 2 || c->atostrBuf[index - 2] != ':')) {
c->atostrBuf[index++] = '0';
}
c->atostrBuf[index] = 0; c->atostrBuf[index] = 0;
return c->atostrBuf + headIndex; return c->atostrBuf + headIndex;
} }
uint32_t UDPC_strtoa(const char *addrStr) { struct in6_addr UDPC_strtoa(const char *addrStr) {
uint32_t addr = 0; struct in6_addr result{{0}};
uint32_t temp = 0; unsigned int index = 0;
uint32_t index = 0; unsigned int strIndex = 0;
while(*addrStr != 0) { int doubleColonIndex = -1;
if(*addrStr >= '0' && *addrStr <= '9') { unsigned char bytes[2] = {0, 0};
temp *= 10; unsigned char bytesState = 0;
temp += *addrStr - '0'; bool prevColon = false;
} else if(*addrStr == '.' && temp <= 0xFF && index < 3) {
if(UDPC::isBigEndian()) { const auto checkInc = [&result, &index, &bytes] () -> bool {
addr |= (temp << (24 - 8 * index++)); if(index < 15) {
} else { result.s6_addr[index++] = bytes[0];
addr |= (temp << (8 * index++)); result.s6_addr[index++] = bytes[1];
} bytes[0] = 0;
temp = 0; bytes[1] = 0;
} else { return false;
return 0;
} }
++addrStr; return true;
};
while(addrStr[strIndex] != '\0') {
if(addrStr[strIndex] >= '0' && addrStr[strIndex] <= '9') {
switch(bytesState) {
case 0:
bytes[0] = (addrStr[strIndex] - '0');
bytesState = 1;
break;
case 1:
bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - '0');
bytesState = 2;
break;
case 2:
bytes[1] = (addrStr[strIndex] - '0');
bytesState = 3;
break;
case 3:
bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - '0');
bytesState = 0;
if(checkInc()) {
return in6addr_loopback;
}
break;
default:
return in6addr_loopback;
}
prevColon = false;
} else if(addrStr[strIndex] >= 'a' && addrStr[strIndex] <= 'f') {
switch(bytesState) {
case 0:
bytes[0] = (addrStr[strIndex] - 'a' + 10);
bytesState = 1;
break;
case 1:
bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - 'a' + 10);
bytesState = 2;
break;
case 2:
bytes[1] = (addrStr[strIndex] - 'a' + 10);
bytesState = 3;
break;
case 3:
bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - 'a' + 10);
bytesState = 0;
if(checkInc()) {
return in6addr_loopback;
}
break;
default:
return in6addr_loopback;
}
prevColon = false;
} else if(addrStr[strIndex] >= 'A' && addrStr[strIndex] <= 'F') {
switch(bytesState) {
case 0:
bytes[0] = (addrStr[strIndex] - 'A' + 10);
bytesState = 1;
break;
case 1:
bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - 'A' + 10);
bytesState = 2;
break;
case 2:
bytes[1] = (addrStr[strIndex] - 'A' + 10);
bytesState = 3;
break;
case 3:
bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - 'A' + 10);
bytesState = 0;
if(checkInc()) {
return in6addr_loopback;
}
break;
default:
return in6addr_loopback;
}
prevColon = false;
} else if(addrStr[strIndex] == ':') {
switch(bytesState) {
case 1:
case 2:
bytes[1] = bytes[0];
bytes[0] = 0;
if(checkInc()) {
return in6addr_loopback;
}
break;
case 3:
bytes[1] |= (bytes[0] & 0xF) << 4;
bytes[0] = bytes[0] >> 4;
if(checkInc()) {
return in6addr_loopback;
}
break;
case 0:
break;
default:
return in6addr_loopback;
}
bytesState = 0;
if(prevColon) {
if(doubleColonIndex >= 0) {
return in6addr_loopback;
} else {
doubleColonIndex = index;
}
} else {
prevColon = true;
}
} else {
return in6addr_loopback;
}
++strIndex;
}
switch(bytesState) {
case 1:
case 2:
bytes[1] = bytes[0];
bytes[0] = 0;
if(checkInc()) {
return in6addr_loopback;
}
break;
case 3:
bytes[1] |= (bytes[0] & 0xF) << 4;
bytes[0] = bytes[0] >> 4;
if(checkInc()) {
return in6addr_loopback;
}
break;
case 0:
break;
default:
return in6addr_loopback;
} }
if(index == 3 && temp <= 0xFF) { if(doubleColonIndex >= 0) {
if(UDPC::isBigEndian()) { strIndex = 16 - index;
addr |= temp; if(strIndex < 2) {
} else { return in6addr_loopback;
addr |= temp << 24; }
for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
result.s6_addr[i] = result.s6_addr[i - strIndex];
result.s6_addr[i - strIndex] = 0;
} }
return addr;
} else {
return 0;
} }
return result;
} }

View file

@ -51,7 +51,7 @@ typedef struct UDPC_Context *UDPC_HContext;
typedef enum { SILENT, ERROR, WARNING, VERBOSE, INFO } UDPC_LoggingType; typedef enum { SILENT, ERROR, WARNING, VERBOSE, INFO } UDPC_LoggingType;
typedef struct { typedef struct {
uint32_t addr; struct in6_addr addr;
uint16_t port; uint16_t port;
} UDPC_ConnectionId; } UDPC_ConnectionId;
@ -70,35 +70,29 @@ typedef struct {
UDPC_ConnectionId receiver; UDPC_ConnectionId receiver;
} UDPC_PacketInfo; } UDPC_PacketInfo;
UDPC_ConnectionId UDPC_create_id(uint32_t addr, uint16_t port); /// port should be in native byte order (not network/big-endian)
UDPC_ConnectionId UDPC_create_id(struct in6_addr addr, uint16_t port);
/// listenPort must be in native byte order, listenAddr must be in network byte order (big-endian) UDPC_ConnectionId UDPC_create_id_anyaddr(uint16_t port);
UDPC_HContext UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient);
/// listenPort must be in native byte order, listenAddr must be in network byte order (big-endian) UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient);
UDPC_HContext UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr, UDPC_HContext UDPC_init_threaded_update(UDPC_ConnectionId listenId,
int isClient); int isClient);
void UDPC_destroy(UDPC_HContext ctx); void UDPC_destroy(UDPC_HContext ctx);
void UDPC_update(UDPC_HContext ctx); void UDPC_update(UDPC_HContext ctx);
/// addr must be in network byte order (big-endian), port must be in native byte order void UDPC_client_initiate_connection(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
void UDPC_client_initiate_connection(UDPC_HContext ctx, uint32_t addr, uint16_t port);
/// addr must be in network byte order (big-endian), port must be in native byte order int UDPC_get_queue_send_available(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
int UDPC_get_queue_send_available(UDPC_HContext ctx, uint32_t addr, uint16_t port);
/// destAddr must be in network byte order (big-endian), destPort must be in native byte order void UDPC_queue_send(UDPC_HContext ctx, UDPC_ConnectionId destinationId,
void UDPC_queue_send(UDPC_HContext ctx, uint32_t destAddr, uint16_t destPort,
uint32_t isChecked, void *data, uint32_t size); uint32_t isChecked, void *data, uint32_t size);
int UDPC_set_accept_new_connections(UDPC_HContext ctx, int isAccepting); int UDPC_set_accept_new_connections(UDPC_HContext ctx, int isAccepting);
/// addr must be in network byte order (big-endian), port must be in native byte order int UDPC_drop_connection(UDPC_HContext ctx, UDPC_ConnectionId connectionId, bool dropAllWithAddr);
int UDPC_drop_connection(UDPC_HContext ctx, uint32_t addr, uint16_t port);
/// addr must be in network byte order, drops all connections to specified addr
int UDPC_drop_connection_addr(UDPC_HContext ctx, uint32_t addr);
uint32_t UDPC_set_protocol_id(UDPC_HContext ctx, uint32_t id); uint32_t UDPC_set_protocol_id(UDPC_HContext ctx, uint32_t id);
@ -106,11 +100,9 @@ UDPC_LoggingType set_logging_type(UDPC_HContext ctx, UDPC_LoggingType loggingTyp
UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx); UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx);
/// addr must be in network byte order const char *UDPC_atostr(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
const char *UDPC_atostr(UDPC_HContext ctx, uint32_t addr);
/// returns a 4 byte unsigned integer address in network byte order struct in6_addr UDPC_strtoa(const char *addrStr);
uint32_t UDPC_strtoa(const char *addrStr);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -9,108 +9,167 @@
TEST(UDPC, atostr) { TEST(UDPC, atostr) {
UDPC::Context context(false); UDPC::Context context(false);
UDPC_ConnectionId conId;
const char* resultBuf; const char* resultBuf;
resultBuf = UDPC_atostr((UDPC_HContext)&context, 0x0100007F); for(unsigned int i = 0; i < 16; ++i) {
EXPECT_EQ(std::strcmp(resultBuf, "127.0.0.1"), 0); conId.addr.s6_addr[i] = (i % 3 == 0 ? 0xFF : (i % 3 == 1 ? 0x12 : 0x56));
}
resultBuf = UDPC_atostr((UDPC_HContext)&context, conId);
EXPECT_STREQ(resultBuf, "ff12:56ff:1256:ff12:56ff:1256:ff12:56ff");
resultBuf = UDPC_atostr((UDPC_HContext)&context, 0xFF08000A); for(unsigned int i = 0; i < 8; ++i) {
EXPECT_EQ(std::strcmp(resultBuf, "10.0.8.255"), 0); conId.addr.s6_addr[i] = 0;
}
resultBuf = UDPC_atostr((UDPC_HContext)&context, conId);
EXPECT_STREQ(resultBuf, "::56ff:1256:ff12:56ff");
resultBuf = UDPC_atostr((UDPC_HContext)&context, 0x0201A8C0); conId.addr.s6_addr[0] = 1;
EXPECT_EQ(std::strcmp(resultBuf, "192.168.1.2"), 0); conId.addr.s6_addr[1] = 2;
resultBuf = UDPC_atostr((UDPC_HContext)&context, conId);
EXPECT_STREQ(resultBuf, "12::56ff:1256:ff12:56ff");
conId.addr.s6_addr[14] = 0;
conId.addr.s6_addr[15] = 0;
resultBuf = UDPC_atostr((UDPC_HContext)&context, conId);
EXPECT_STREQ(resultBuf, "12::56ff:1256:ff12:0");
for(unsigned int i = 0; i < 15; ++i) {
conId.addr.s6_addr[i] = 0;
}
conId.addr.s6_addr[15] = 1;
resultBuf = UDPC_atostr((UDPC_HContext)&context, conId);
EXPECT_STREQ(resultBuf, "::1");
conId.addr.s6_addr[15] = 0;
resultBuf = UDPC_atostr((UDPC_HContext)&context, conId);
EXPECT_STREQ(resultBuf, "::");
} }
TEST(UDPC, atostr_concurrent) { TEST(UDPC, atostr_concurrent) {
UDPC::Context context(false); UDPC::Context context(false);
const char* results[64] = { const char* results[64] = {
"0.0.0.0", "::1111:1",
"1.1.1.1", "::1111:2",
"2.2.2.2", "::1111:3",
"3.3.3.3", "::1111:4",
"4.4.4.4", "::1111:5",
"5.5.5.5", "::1111:6",
"6.6.6.6", "::1111:7",
"7.7.7.7", "::1111:8",
"8.8.8.8", "::1111:9",
"9.9.9.9", "::1111:a",
"10.10.10.10", "::1111:b",
"11.11.11.11", "::1111:c",
"12.12.12.12", "::1111:d",
"13.13.13.13", "::1111:e",
"14.14.14.14", "::1111:f",
"15.15.15.15", "::1111:10",
"16.16.16.16", "::1111:11",
"17.17.17.17", "::1111:12",
"18.18.18.18", "::1111:13",
"19.19.19.19", "::1111:14",
"20.20.20.20", "::1111:15",
"21.21.21.21", "::1111:16",
"22.22.22.22", "::1111:17",
"23.23.23.23", "::1111:18",
"24.24.24.24", "::1111:19",
"25.25.25.25", "::1111:1a",
"26.26.26.26", "::1111:1b",
"27.27.27.27", "::1111:1c",
"28.28.28.28", "::1111:1d",
"29.29.29.29", "::1111:1e",
"30.30.30.30", "::1111:1f",
"31.31.31.31", "::1111:20",
"32.32.32.32", "::1111:21",
"33.33.33.33", "::1111:22",
"34.34.34.34", "::1111:23",
"35.35.35.35", "::1111:24",
"36.36.36.36", "::1111:25",
"37.37.37.37", "::1111:26",
"38.38.38.38", "::1111:27",
"39.39.39.39", "::1111:28",
"40.40.40.40", "::1111:29",
"41.41.41.41", "::1111:2a",
"42.42.42.42", "::1111:2b",
"43.43.43.43", "::1111:2c",
"44.44.44.44", "::1111:2d",
"45.45.45.45", "::1111:2e",
"46.46.46.46", "::1111:2f",
"47.47.47.47", "::1111:30",
"48.48.48.48", "::1111:31",
"49.49.49.49", "::1111:32",
"50.50.50.50", "::1111:33",
"51.51.51.51", "::1111:34",
"52.52.52.52", "::1111:35",
"53.53.53.53", "::1111:36",
"54.54.54.54", "::1111:37",
"55.55.55.55", "::1111:38",
"56.56.56.56", "::1111:39",
"57.57.57.57", "::1111:3a",
"58.58.58.58", "::1111:3b",
"59.59.59.59", "::1111:3c",
"60.60.60.60", "::1111:3d",
"61.61.61.61", "::1111:3e",
"62.62.62.62", "::1111:3f",
"63.63.63.63" "::1111:40"
}; };
std::future<void> futures[64]; std::future<void> futures[32];
const char* ptrs[64]; const char* ptrs[32];
for(unsigned int i = 0; i < 2; ++i) { for(unsigned int i = 0; i < 2; ++i) {
for(unsigned int j = 0; j < 64; ++j) { for(unsigned int j = 0; j < 32; ++j) {
futures[j] = std::async(std::launch::async, [] (unsigned int id, const char** ptr, UDPC::Context* c) { futures[j] = std::async(std::launch::async, [] (unsigned int id, const char** ptr, UDPC::Context* c) {
ptr[id] = UDPC_atostr((UDPC_HContext)c, id | (id << 8) | (id << 16) | (id << 24)); UDPC_ConnectionId conId = {
{0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0x11, 0x11, 0x0, (unsigned char)(id + 1)},
0
};
ptr[id] = UDPC_atostr((UDPC_HContext)c, conId);
}, j, ptrs, &context); }, j, ptrs, &context);
} }
for(unsigned int j = 0; j < 64; ++j) { for(unsigned int j = 0; j < 32; ++j) {
ASSERT_TRUE(futures[j].valid()); ASSERT_TRUE(futures[j].valid());
futures[j].wait(); futures[j].wait();
} }
for(unsigned int j = 0; j < 64; ++j) { for(unsigned int j = 0; j < 32; ++j) {
EXPECT_EQ(std::strcmp(ptrs[j], results[j]), 0); EXPECT_STREQ(ptrs[j], results[j]);
} }
} }
} }
TEST(UDPC, strtoa) { TEST(UDPC, strtoa) {
EXPECT_EQ(UDPC_strtoa("127.0.0.1"), 0x0100007F); struct in6_addr addr;
EXPECT_EQ(UDPC_strtoa("10.0.8.255"), 0xFF08000A);
EXPECT_EQ(UDPC_strtoa("192.168.1.2"), 0x0201A8C0); for(unsigned int i = 0; i < 16; ++i) {
addr.s6_addr[i] = 0;
}
addr.s6_addr[15] = 1;
EXPECT_EQ(UDPC_strtoa("::1"), addr);
// check invalid
EXPECT_EQ(UDPC_strtoa("1:1::1:1::1"), addr);
EXPECT_EQ(UDPC_strtoa("derpadoodle"), addr);
addr = {
0xF0, 0xF, 0x0, 0x1,
0x56, 0x78, 0x9A, 0xBC,
0xDE, 0xFF, 0x1, 0x2,
0x3, 0x4, 0x5, 0x6
};
EXPECT_EQ(UDPC_strtoa("F00F:1:5678:9abc:deff:102:304:506"), addr);
addr = {
0x0, 0xFF, 0x1, 0x0,
0x0, 0x1, 0x10, 0x0,
0x0, 0x0, 0x0, 0x0,
0x12, 0x34, 0xab, 0xcd
};
EXPECT_EQ(UDPC_strtoa("ff:100:1:1000::1234:abcd"), addr);
} }