--- a/src/Socket.cpp Fri Aug 05 23:45:48 2022 +0200
+++ b/src/Socket.cpp Sat Aug 06 00:27:22 2022 +0200
@@ -69,44 +69,41 @@
else return nullptr;
}
-static std::string ip2string(const addrinfo* ai) {
- //char buffer[INET_ADDRSTRLEN] = {0};
- char buffer[INET6_ADDRSTRLEN] = {0};
- //return inet_ntop(ai->ai_family, &ai->ai_addr, buffer, sizeof (buffer));
- //return inet_ntop(ai->ai_family, &ai->ai_addr->sa_data, buffer, sizeof (buffer));
- if (ai->ai_family == AF_INET) return inet_ntop(ai->ai_family, &((sockaddr_in const *) ai->ai_addr)->sin_addr, buffer, sizeof (buffer)); // TODO: check 0 result
- else if (ai->ai_family == AF_INET6) return inet_ntop(ai->ai_family, &((sockaddr_in6 const *) ai->ai_addr)->sin6_addr, buffer, sizeof (buffer)); // TODO: check 0 result
- else throw std::logic_error("Invalid address family: " + std::to_string(ai->ai_family));
-}
-
class AddressInfos {
private:
- struct addrinfo* addrInfo;
+ std::shared_ptr<addrinfo> addrInfo;
- AddressInfos(addrinfo* addrInfo) : addrInfo(addrInfo) {
- std::cerr << " AddressInfo()" << std::endl;
+ AddressInfos(addrinfo* addrInfo) : addrInfo(std::shared_ptr<addrinfo>(addrInfo, freeaddrinfo)) {
}
public:
virtual ~AddressInfos() {
- std::cerr << " ~AddressInfo()" << std::endl;
- freeaddrinfo(addrInfo);
}
-
+
class AddressInfo {
+ private:
+ std::shared_ptr<addrinfo> parent; // to avoid premature deletion of the whole structure
public:
- const addrinfo* const ai;
-
- AddressInfo(const addrinfo* const ai) : ai(ai) {}
+ const addrinfo * const ai;
+
+ AddressInfo(const addrinfo * const ai, std::shared_ptr<addrinfo> parent) : ai(ai), parent(parent) {
+ }
+
+ const std::string toString() const {
+ char buffer[INET6_ADDRSTRLEN] = {0};
+ if (ai->ai_family == AF_INET) return inet_ntop(ai->ai_family, &((sockaddr_in const *) ai->ai_addr)->sin_addr, buffer, sizeof (buffer)); // TODO: check 0 result
+ else if (ai->ai_family == AF_INET6) return inet_ntop(ai->ai_family, &((sockaddr_in6 const *) ai->ai_addr)->sin6_addr, buffer, sizeof (buffer)); // TODO: check 0 result
+ else return "unknown address family: " + std::to_string(ai->ai_family);
+ }
};
- static AddressInfos getAddressInfo(const std::string& host, const std::string& port) {
+ static AddressInfos getAddressInfos(const std::string& host, const std::string& port, int socketType = SOCK_STREAM, int protocol = IPPROTO_TCP) {
struct addrinfo query;
memset(&query, sizeof (query), 0);
query.ai_family = AF_UNSPEC;
- query.ai_socktype = SOCK_STREAM;
- query.ai_protocol = IPPROTO_TCP;
+ query.ai_socktype = socketType;
+ query.ai_protocol = protocol;
query.ai_flags = AI_ALL;
struct addrinfo* addrInfo;
@@ -121,34 +118,24 @@
const std::size_t size() const {
std::size_t size = 0;
- for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) size++;
+ for (addrinfo* ai = addrInfo.get(); ai; ai = ai->ai_next) size++;
return size;
}
- const addrinfo& operator[](std::size_t index) const {
- for (addrinfo* ai = addrInfo; ai; index--) {
- if (index == 0) return *ai;
+ const AddressInfo operator[](std::size_t index) const {
+ for (addrinfo* ai = addrInfo.get(); ai; index--) {
+ if (index == 0) return AddressInfo(ai, addrInfo);
else ai = ai->ai_next;
}
-
+
throw std::out_of_range("invalid index for AddressInfo: " + std::to_string(index));
}
-
+
};
+// TODO: delete getAddress()
+
static in_addr_t getAddress(const std::string& host) {
-
- {
- AddressInfos ai = AddressInfos::getAddressInfo("::0ff2", "smtp");
- std::cerr << "AddressInfo size = " << ai.size() << std::endl;
- for (size_t i = 0, limit = ai.size(); i < limit; i++) {
- std::cerr << "AddressInfo: " << ip2string(&ai[i]) << std::endl;
- }
- }
-
-
-
-
struct addrinfo query;
memset(&query, sizeof (query), 0);
query.ai_family = AF_UNSPEC;
@@ -159,16 +146,6 @@
struct addrinfo* addrInfo;
check(getaddrinfo(host.c_str(), "", &query, &addrInfo), "getaddrinfo");
- std::cerr << "found: " << addrInfo << std::endl;
- if (addrInfo) {
- for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
- std::cerr << "address info: family=" << std::to_string(ai->ai_addr->sa_family) << " socktype=" << std::to_string(ai->ai_socktype) << " protocol=" << std::to_string(ai->ai_protocol);
- if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) std::cerr << " IPv4=" << ip2string(ai);
- else if (sockaddr_in6 * sa = castAddress<sockaddr_in6>(ai, AF_INET6)) std::cerr << " IPv6=" << ip2string(ai);
- std::cerr << std::endl;
- }
- }
-
if (addrInfo) {
for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) {
@@ -188,30 +165,29 @@
class UDPClientSocket : public Socket {
private:
- struct sockaddr_in remoteAddress;
- int protocol = IPPROTO_UDP;
- int type = SOCK_DGRAM;
+ AddressInfos remoteAddresses;
+
+ UDPClientSocket(AddressInfos remoteAddresses) : remoteAddresses(remoteAddresses) {
+ }
+
public:
static std::shared_ptr<Socket> open(const SocketOptions& options) {
- std::shared_ptr<UDPClientSocket> s = std::make_shared<UDPClientSocket>();
- memset((char *) &s->remoteAddress, 0, sizeof (s->remoteAddress));
- s->remoteAddress.sin_family = AF_INET;
- s->remoteAddress.sin_addr.s_addr = getAddress(findOption(options, OPTION_HOST, true)); // TODO: use getaddrinfo() instead (because of error -1 = 255.255.255.255)
- s->remoteAddress.sin_port = htons(std::stoi(findOption(options, OPTION_PORT, true)));
+ auto protocol = findOption(options, OPTION_PROTOCOL);
- auto protocol = findOption(options, OPTION_PROTOCOL);
- if (protocol == PROTOCOL_SCTP) {
- s->protocol = IPPROTO_SCTP;
- s->type = SOCK_SEQPACKET;
- }
+ AddressInfos remoteAddresses = AddressInfos::getAddressInfos(
+ findOption(options, OPTION_HOST, true),
+ findOption(options, OPTION_PORT, true),
+ protocol == PROTOCOL_SCTP ? SOCK_SEQPACKET : SOCK_DGRAM,
+ protocol == PROTOCOL_SCTP ? IPPROTO_SCTP : IPPROTO_UDP);
- return s;
+ return std::shared_ptr<UDPClientSocket>(new UDPClientSocket(remoteAddresses));
}
void send(const std::string& message) override {
- FD s(::socket(AF_INET, type, protocol));
- sendto(s.getFD(), message.c_str(), message.size(), 0, (sockaddr*) & remoteAddress, sizeof (remoteAddress));
+ auto ai = remoteAddresses[0].ai;
+ FD s(::socket(AF_INET, ai->ai_socktype, ai->ai_protocol));
+ sendto(s.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen);
}
const std::string receive() override {