@@ -125,5 +125,3 @@ private:
|
||||
};
|
||||
|
||||
std::string addr_to_string(const struct addrinfo* rp);
|
||||
|
||||
|
||||
|
||||
@@ -154,6 +154,25 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri
|
||||
#endif
|
||||
this->connection_date = std::chrono::system_clock::now();
|
||||
|
||||
// Get our local TCP port and store it
|
||||
this->local_port = static_cast<uint16_t>(-1);
|
||||
if (rp->ai_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 a;
|
||||
socklen_t l = sizeof(a);
|
||||
if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1)
|
||||
this->local_port = ::ntohs(a.sin6_port);
|
||||
}
|
||||
else if (rp->ai_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
socklen_t l = sizeof(a);
|
||||
if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1)
|
||||
this->local_port = ::ntohs(a.sin_port);
|
||||
}
|
||||
|
||||
log_debug("Local port: ", this->local_port, ", and remote port: ", this->port);
|
||||
|
||||
this->on_connected();
|
||||
return ;
|
||||
}
|
||||
@@ -231,3 +250,9 @@ std::string TCPClientSocketHandler::get_port() const
|
||||
{
|
||||
return this->port;
|
||||
}
|
||||
|
||||
bool TCPClientSocketHandler::match_port_pairt(const uint16_t local, const uint16_t remote) const
|
||||
{
|
||||
const uint16_t remote_port = static_cast<uint16_t>(std::stoi(this->port));
|
||||
return this->is_connected() && local == this->local_port && remote == remote_port;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ class TCPClientSocketHandler: public TCPSocketHandler
|
||||
void close() override final;
|
||||
std::chrono::system_clock::time_point connection_date;
|
||||
|
||||
/**
|
||||
* Whether or not this connection is using the two given TCP ports.
|
||||
*/
|
||||
bool match_port_pairt(const uint16_t local, const uint16_t remote) const;
|
||||
|
||||
protected:
|
||||
bool hostname_resolution_failed;
|
||||
/**
|
||||
@@ -70,6 +75,8 @@ class TCPClientSocketHandler: public TCPSocketHandler
|
||||
*/
|
||||
std::string port;
|
||||
|
||||
uint16_t local_port;
|
||||
|
||||
bool connected;
|
||||
bool connecting;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <network/socket_handler.hpp>
|
||||
#include <network/resolver.hpp>
|
||||
#include <network/poller.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include <logger/logger.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
template <typename RemoteSocketType>
|
||||
class TcpSocketServer: public SocketHandler
|
||||
{
|
||||
public:
|
||||
TcpSocketServer(std::shared_ptr<Poller> poller, const uint16_t port):
|
||||
SocketHandler(poller, -1)
|
||||
{
|
||||
if ((this->socket = ::socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||
throw std::runtime_error("Could not create socket: "s + std::strerror(errno));
|
||||
|
||||
int opt = 1;
|
||||
if (::setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
|
||||
throw std::runtime_error("Failed to set socket option: "s + std::strerror(errno));
|
||||
|
||||
struct sockaddr_in6 addr{};
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
addr.sin6_addr = IN6ADDR_ANY_INIT;
|
||||
if ((::bind(this->socket, (const struct sockaddr*)&addr, sizeof(addr))) == -1)
|
||||
{ // If we can’t listen on this port, we just give up, but this is not fatal.
|
||||
log_warning("Failed to bind on port ", std::to_string(port), ": ", std::strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((::listen(this->socket, 10)) == -1)
|
||||
throw std::runtime_error("listen() failed");
|
||||
|
||||
this->accept();
|
||||
}
|
||||
~TcpSocketServer() = default;
|
||||
|
||||
void on_recv() override
|
||||
{
|
||||
// Accept a RemoteSocketType
|
||||
int socket = ::accept(this->socket, nullptr, nullptr);
|
||||
|
||||
auto client = std::make_unique<RemoteSocketType>(poller, socket, *this);
|
||||
this->poller->add_socket_handler(client.get());
|
||||
this->sockets.push_back(std::move(client));
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<RemoteSocketType>> sockets;
|
||||
|
||||
private:
|
||||
void accept()
|
||||
{
|
||||
this->poller->add_socket_handler(this);
|
||||
}
|
||||
void on_send() override
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
void connect() override
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
bool is_connected() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool is_connecting() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user