Store connections based on both addr and port

Previous implementation only stored based on addr only, preventing
connections from/to the same address but different ports.
This commit is contained in:
Stephen Seo 2019-08-27 17:00:29 +09:00
parent 57e270eb15
commit 1382cc6b7c
3 changed files with 108 additions and 25 deletions

View file

@ -50,6 +50,37 @@ struct SentPktInfo {
std::chrono::steady_clock::time_point sentTime;
};
struct ConnectionIdentifier {
ConnectionIdentifier();
ConnectionIdentifier(uint32_t addr, uint16_t port);
// copy
ConnectionIdentifier(const ConnectionIdentifier& other) = default;
ConnectionIdentifier& operator =(const ConnectionIdentifier& other) = default;
// move
ConnectionIdentifier(ConnectionIdentifier&& other) = default;
ConnectionIdentifier& operator =(ConnectionIdentifier&& other) = default;
uint64_t id;
/// expects address to be in network byte order (big-endian)
void setAddr(uint32_t addr);
/// expects port to be in native order (not network byte order)
void setPort(uint16_t port);
/// returns address as a 4 byte unsigned int in network byte order (big-endian)
uint32_t getAddr() const;
/// returns port as a 2 byte unsigned int in native order (not network byte order)
uint16_t getPort() const;
bool operator ==(const ConnectionIdentifier& other) const;
struct Hasher {
std::size_t operator()(const ConnectionIdentifier& key) const;
};
};
struct ConnectionData {
ConnectionData();
ConnectionData(bool isServer, Context *ctx);
@ -114,10 +145,10 @@ struct Context {
struct sockaddr_in socketInfo;
std::chrono::steady_clock::time_point lastUpdated;
// ipv4 address to ConnectionData
std::unordered_map<uint32_t, ConnectionData> conMap;
// ipv4 address and port to ConnectionData
std::unordered_map<ConnectionIdentifier, ConnectionData, ConnectionIdentifier::Hasher> conMap;
// id to ipv4 address
std::unordered_map<uint32_t, uint32_t> idMap;
std::unordered_map<uint32_t, ConnectionIdentifier> idMap;
std::default_random_engine rng_engine;

View file

@ -6,12 +6,48 @@
#include <cstring>
#include <optional>
#include <vector>
#include <functional>
UDPC::SentPktInfo::SentPktInfo() :
id(0),
sentTime(std::chrono::steady_clock::now())
{}
UDPC::ConnectionIdentifier::ConnectionIdentifier() :
id(0)
{}
UDPC::ConnectionIdentifier::ConnectionIdentifier(uint32_t addr, uint16_t port) :
UDPC::ConnectionIdentifier::ConnectionIdentifier()
{
*((uint32_t*)&id) = addr;
*((uint16_t*)(((unsigned char*)&id) + 4)) = port;
}
void UDPC::ConnectionIdentifier::setAddr(uint32_t addr) {
*((uint32_t*)&id) = addr;
}
void UDPC::ConnectionIdentifier::setPort(uint16_t port) {
*((uint16_t*)(((unsigned char*)&id) + 4)) = port;
}
uint32_t UDPC::ConnectionIdentifier::getAddr() const {
return *((uint32_t*)&id);
}
uint16_t UDPC::ConnectionIdentifier::getPort() const {
return *((uint16_t*)(((unsigned char*)&id) + 4));
}
bool UDPC::ConnectionIdentifier::operator==(const ConnectionIdentifier& other) const {
return id == other.id;
}
std::size_t UDPC::ConnectionIdentifier::Hasher::operator()(const ConnectionIdentifier& key) const {
return std::hash<uint64_t>()(key.id);
}
UDPC::ConnectionData::ConnectionData() :
flags(),
timer(std::chrono::steady_clock::duration::zero()),
@ -230,7 +266,7 @@ void UDPC_update(void *ctx) {
std::chrono::steady_clock::duration temp_dt_fs;
{
// check timed out, check good/bad mode with rtt, remove timed out
std::vector<uint32_t> removed;
std::vector<UDPC::ConnectionIdentifier> removed;
for(auto iter = c->conMap.begin(); iter != c->conMap.end(); ++iter) {
temp_dt_fs = now - iter->second.received;
if(temp_dt_fs >= UDPC::CONNECTION_TIMEOUT) {
@ -319,7 +355,7 @@ void UDPC_update(void *ctx) {
struct sockaddr_in destinationInfo;
destinationInfo.sin_family = AF_INET;
destinationInfo.sin_addr.s_addr = iter->first;
destinationInfo.sin_addr.s_addr = iter->first.getAddr();
destinationInfo.sin_port = htons(iter->second.port);
long int sentBytes = sendto(
c->socketHandle,
@ -348,7 +384,7 @@ void UDPC_update(void *ctx) {
struct sockaddr_in destinationInfo;
destinationInfo.sin_family = AF_INET;
destinationInfo.sin_addr.s_addr = iter->first;
destinationInfo.sin_addr.s_addr = iter->first.getAddr();
destinationInfo.sin_port = htons(iter->second.port);
long int sentBytes = sendto(
c->socketHandle,
@ -384,7 +420,7 @@ void UDPC_update(void *ctx) {
struct sockaddr_in destinationInfo;
destinationInfo.sin_family = AF_INET;
destinationInfo.sin_addr.s_addr = iter->first;
destinationInfo.sin_addr.s_addr = iter->first.getAddr();
destinationInfo.sin_port = htons(iter->second.port);
long int sentBytes = sendto(
c->socketHandle,
@ -399,7 +435,7 @@ void UDPC_update(void *ctx) {
UDPC_PacketInfo pInfo{{0}, 0, 0, 0, 0, 0, 0};
pInfo.sender = UDPC::LOCAL_ADDR;
pInfo.receiver = iter->first;
pInfo.receiver = iter->first.getAddr();
pInfo.senderPort = c->socketInfo.sin_port;
pInfo.receiverPort = iter->second.port;
*((uint32_t*)(pInfo.data + 8)) = htonl(iter->second.lseq - 1);
@ -437,7 +473,7 @@ void UDPC_update(void *ctx) {
struct sockaddr_in destinationInfo;
destinationInfo.sin_family = AF_INET;
destinationInfo.sin_addr.s_addr = iter->first;
destinationInfo.sin_addr.s_addr = iter->first.getAddr();
destinationInfo.sin_port = htons(iter->second.port);
long int sentBytes = sendto(
c->socketHandle,
@ -457,7 +493,7 @@ void UDPC_update(void *ctx) {
sentPInfo.flags = 0;
sentPInfo.dataSize = 20 + pInfo.dataSize;
sentPInfo.sender = UDPC::LOCAL_ADDR;
sentPInfo.receiver = iter->first;
sentPInfo.receiver = iter->first.getAddr();
sentPInfo.senderPort = c->socketInfo.sin_port;
sentPInfo.receiverPort = iter->second.port;
@ -469,7 +505,7 @@ void UDPC_update(void *ctx) {
sentPInfo.flags = 0x4;
sentPInfo.dataSize = 0;
sentPInfo.sender = UDPC::LOCAL_ADDR;
sentPInfo.receiver = iter->first;
sentPInfo.receiver = iter->first.getAddr();
sentPInfo.senderPort = c->socketInfo.sin_port;
sentPInfo.receiverPort = iter->second.port;
*((uint32_t*)(sentPInfo.data + 8)) = htonl(iter->second.lseq - 1);
@ -526,22 +562,24 @@ void UDPC_update(void *ctx) {
bool isResending = conID & UDPC_ID_RESENDING;
conID &= 0x0FFFFFFF;
UDPC::ConnectionIdentifier identifier(receivedData.sin_addr.s_addr, ntohs(receivedData.sin_port));
if(isConnect && c->flags.test(2)) {
// is connect packet and is accepting new connections
if(!c->flags.test(1)
&& c->conMap.find(receivedData.sin_addr.s_addr) == c->conMap.end()) {
&& c->conMap.find(identifier) == c->conMap.end()) {
// is receiving as server, connection did not already exist
// TODO log establishing connection with client peer
UDPC::ConnectionData newConnection(true, c);
newConnection.addr = receivedData.sin_addr.s_addr;
newConnection.port = ntohs(receivedData.sin_port);
c->idMap.insert(std::make_pair(newConnection.id, newConnection.addr));
c->conMap.insert(std::make_pair(newConnection.addr, std::move(newConnection)));
c->idMap.insert(std::make_pair(newConnection.id, identifier));
c->conMap.insert(std::make_pair(identifier, std::move(newConnection)));
// TODO trigger event server established connection with client
} else if (c->flags.test(1)) {
// is client
auto iter = c->conMap.find(receivedData.sin_addr.s_addr);
auto iter = c->conMap.find(identifier);
if(iter == c->conMap.end() || !iter->second.flags.test(3)) {
return;
}
@ -553,7 +591,7 @@ void UDPC_update(void *ctx) {
return;
}
auto iter = c->conMap.find(receivedData.sin_addr.s_addr);
auto iter = c->conMap.find(identifier);
if(iter == c->conMap.end() || iter->second.flags.test(3)
|| !iter->second.flags.test(4) || iter->second.id != conID) {
return;
@ -698,13 +736,15 @@ void UDPC_update(void *ctx) {
}
}
int UDPC_get_queue_send_available(void *ctx, uint32_t addr) {
int UDPC_get_queue_send_available(void *ctx, uint32_t addr, uint16_t port) {
UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) {
return 0;
}
auto iter = c->conMap.find(addr);
UDPC::ConnectionIdentifier identifier(addr, port);
auto iter = c->conMap.find(identifier);
if(iter != c->conMap.end()) {
return iter->second.sendPkts.capacity() - iter->second.sendPkts.size();
} else {
@ -712,7 +752,7 @@ int UDPC_get_queue_send_available(void *ctx, uint32_t addr) {
}
}
void UDPC_queue_send(void *ctx, uint32_t destAddr,
void UDPC_queue_send(void *ctx, uint32_t destAddr, uint16_t destPort,
uint32_t isChecked, void *data, uint32_t size) {
if(size == 0 || !data) {
return;
@ -723,7 +763,9 @@ void UDPC_queue_send(void *ctx, uint32_t destAddr,
return;
}
auto iter = c->conMap.find(destAddr);
UDPC::ConnectionIdentifier identifier(destAddr, destPort);
auto iter = c->conMap.find(identifier);
if(iter == c->conMap.end()) {
// TODO log failed to add packet to queue; unknown recipient
return;
@ -749,13 +791,15 @@ int UDPC_set_accept_new_connections(void *ctx, int isAccepting) {
return c->isAcceptNewConnections.exchange(isAccepting == 0 ? false : true);
}
int UDPC_drop_connection(void *ctx, uint32_t addr) {
int UDPC_drop_connection(void *ctx, uint32_t addr, uint16_t port) {
UDPC::Context *c = UDPC::verifyContext(ctx);
if(!c) {
return 0;
}
auto iter = c->conMap.find(addr);
UDPC::ConnectionIdentifier identifier(addr, port);
auto iter = c->conMap.find(identifier);
if(iter != c->conMap.end()) {
c->conMap.erase(iter);
return 1;

View file

@ -63,7 +63,9 @@ typedef struct {
uint16_t receiverPort;
} UDPC_PacketInfo;
/// listenPort must be in native byte order, listenAddr must be in network byte order (big-endian)
void *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)
void *UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr,
int isClient);
@ -71,14 +73,18 @@ void UDPC_destroy(void *ctx);
void UDPC_update(void *ctx);
int UDPC_get_queue_send_available(void *ctx, uint32_t addr);
/// port must be in native byte order, addr must be in network byte order (big-endian)
int UDPC_get_queue_send_available(void *ctx, uint32_t addr, uint16_t port);
void UDPC_queue_send(void *ctx, uint32_t destAddr,
/// destPort must be in native byte order, destAddr must be in network byte order (big-endian)
void UDPC_queue_send(void *ctx, uint32_t destAddr, uint16_t destPort,
uint32_t isChecked, void *data, uint32_t size);
int UDPC_set_accept_new_connections(void *ctx, int isAccepting);
int UDPC_drop_connection(void *ctx, uint32_t addr);
// TODO implement drop_connection for all connections on an address and any port
/// addr must be in network byte order (big-endian), port must be in native byte order
int UDPC_drop_connection(void *ctx, uint32_t addr, uint16_t port);
uint32_t UDPC_set_protocol_id(void *ctx, uint32_t id);
@ -86,8 +92,10 @@ UDPC_LoggingType set_logging_type(void *ctx, UDPC_LoggingType loggingType);
UDPC_PacketInfo UDPC_get_received(void *ctx);
/// addr must be in network byte order
const char *UDPC_atostr(void *ctx, uint32_t addr);
/// returns a 4 byte unsigned integer address in network byte order
uint32_t UDPC_strtoa(const char *addrStr);
#ifdef __cplusplus