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);
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;
#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()),
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) {
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,
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,
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,
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);
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,
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;
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);
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;
}
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;
}
}
-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 {
}
}
-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;
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;
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;
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);
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);
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