Skip to content

Commit

Permalink
Added an interface check. If the interface is auto, the first found i…
Browse files Browse the repository at this point in the history
…pv6 interface will be selected. If no prober interface is provided, the tbd_controller throws an exception. The port from the sdp server is now reusable. The sdp socket binds now to the interface and joins multicast group

Signed-off-by: Sebastian Lukas <[email protected]>
  • Loading branch information
SebaLukas committed Nov 19, 2024
1 parent 1bd7bf4 commit df50777
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 8 deletions.
3 changes: 3 additions & 0 deletions include/iso15118/detail/io/socket_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include <netinet/in.h>

namespace iso15118::io {

bool check_and_udapte_interface(std::string& interface_name);

bool get_first_sockaddr_in6_for_interface(const std::string& interface_name, sockaddr_in6& address);

std::unique_ptr<char[]> sockaddr_in6_to_name(const sockaddr_in6&);
Expand Down
2 changes: 1 addition & 1 deletion include/iso15118/io/sdp_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct PeerRequestContext {

class SdpServer {
public:
SdpServer();
explicit SdpServer(std::string interface_name);
~SdpServer();
PeerRequestContext get_peer_request();
void send_response(const PeerRequestContext&, const Ipv6EndPoint&);
Expand Down
2 changes: 2 additions & 0 deletions include/iso15118/tbd_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class TbdController {
const session::feedback::Callbacks callbacks;

d20::EvseSetupConfig evse_setup;

std::string interface_name;
};

} // namespace iso15118
3 changes: 3 additions & 0 deletions src/iso15118/io/connection_mbedtls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <iso15118/io/connection_ssl.hpp>

#include <cassert>
#include <cinttypes>
#include <cstring>
#include <filesystem>

Expand Down Expand Up @@ -156,6 +157,8 @@ ConnectionSSL::ConnectionSSL(PollManager& poll_manager_, const std::string& inte
log_and_throw(msg.c_str());
}

logf_info("Incoming connection from [%s]:%" PRIu16, address_name.get(), ntohs(address.sin6_port));

end_point.port = 50000;
memcpy(&end_point.address, &address.sin6_addr, sizeof(address.sin6_addr));

Expand Down
3 changes: 3 additions & 0 deletions src/iso15118/io/connection_openssl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <iso15118/io/connection_ssl.hpp>

#include <cassert>
#include <cinttypes>
#include <cstring>
#include <filesystem>
#include <unistd.h>
Expand Down Expand Up @@ -142,6 +143,8 @@ ConnectionSSL::ConnectionSSL(PollManager& poll_manager_, const std::string& inte
log_and_throw(msg.c_str());
}

logf_info("Incoming connection from [%s]:%" PRIu16, address_name.get(), ntohs(address.sin6_port));

// Todo(sl): Define constexpr -> 50000 is fixed?
end_point.port = 50000;
memcpy(&end_point.address, &address.sin6_addr, sizeof(address.sin6_addr));
Expand Down
4 changes: 4 additions & 0 deletions src/iso15118/io/connection_plain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ void ConnectionPlain::handle_connect() {

const auto address_name = sockaddr_in6_to_name(address);

if (not address_name) {
log_and_throw("Failed to determine string representation of ipv6 socket address");
}

logf_info("Incoming connection from [%s]:%" PRIu16, address_name.get(), ntohs(address.sin6_port));

poll_manager.unregister_fd(fd);
Expand Down
31 changes: 30 additions & 1 deletion src/iso15118/io/sdp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@

#include <iso15118/detail/helper.hpp>

// FIXME(Sl): Not sure with define
/* link-local multicast address ff02::1 aka ip6-allnodes */
#define IN6ADDR_ALLNODES {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}

namespace iso15118 {

static void log_peer_hostname(const struct sockaddr_in6& address) {
Expand All @@ -33,7 +37,7 @@ static void log_peer_hostname(const struct sockaddr_in6& address) {

namespace io {

SdpServer::SdpServer() {
SdpServer::SdpServer(std::string interface_name) {
fd = socket(AF_INET6, SOCK_DGRAM, 0);

if (fd == -1) {
Expand All @@ -47,11 +51,36 @@ SdpServer::SdpServer() {
socket_address.sin6_port = htobe16(v2gtp::SDP_SERVER_PORT);
memcpy(&socket_address.sin6_addr, &in6addr_any, sizeof(socket_address.sin6_addr));

int enable = 1;
auto result = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
if (result == -1) {
const auto error_msg = adding_err_msg("Setsockopt(SO_REUSEPORT) failed");
log_and_throw(error_msg.c_str());
}

const auto bind_result =
bind(fd, reinterpret_cast<const struct sockaddr*>(&socket_address), sizeof(socket_address));
if (bind_result == -1) {
log_and_throw("Failed to bind to socket");
}

// Bind only to specified device
result = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name.c_str(), interface_name.length());
if (result == -1) {
const auto error_msg = adding_err_msg("Setsockopt(SO_BINDTODEVICE) failed");
log_and_throw(error_msg.c_str());
}

// Join multicast group
struct ipv6_mreq mreq{};
mreq.ipv6mr_multiaddr = IN6ADDR_ALLNODES;
mreq.ipv6mr_interface = if_nametoindex(interface_name.c_str());

result = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
if (result == -1) {
const auto error_msg = adding_err_msg("Setsockopt(IPV6_JOIN_GROUP) failed");
log_and_throw(error_msg.c_str());
}
}

SdpServer::~SdpServer() {
Expand Down
49 changes: 49 additions & 0 deletions src/iso15118/io/socket_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,55 @@
#include <iso15118/detail/helper.hpp>

namespace iso15118::io {

namespace {

auto choose_first_ipv6_interface() {
std::string interface_name{""};
struct ifaddrs* if_list_head;
const auto get_if_addrs_result = getifaddrs(&if_list_head);

if (get_if_addrs_result == -1) {
logf_error("Failed to call getifaddrs");
return std::string("");
}

for (auto current_if = if_list_head; current_if != nullptr; current_if = current_if->ifa_next) {
if (current_if->ifa_addr == nullptr or current_if->ifa_addr->sa_family != AF_INET6) {
continue;
}

// NOTE (aw): because we did the check for AF_INET6, we can assume that ifa_addr is indeed an sockaddr_in6
const auto current_addr = reinterpret_cast<const sockaddr_in6*>(current_if->ifa_addr);
if (not IN6_IS_ADDR_LINKLOCAL(&(current_addr->sin6_addr))) {
continue;
}
interface_name = current_if->ifa_name;
break; // Stop the loop if a interface is found
}
freeifaddrs(if_list_head);

return interface_name;
}

} // namespace

bool check_and_udapte_interface(std::string& interface_name) {

if (interface_name == "auto") {
logf_info("Search for the first available ipv6 interface");
interface_name = choose_first_ipv6_interface();
}

struct ipv6_mreq mreq {};
mreq.ipv6mr_interface = if_nametoindex(interface_name.c_str());
if (!mreq.ipv6mr_interface) {
logf_error("No such interface: %s", interface_name.c_str());
return false;
}
return not interface_name.empty();
}

bool get_first_sockaddr_in6_for_interface(const std::string& interface_name, sockaddr_in6& address) {
struct ifaddrs* if_list_head;
const auto get_if_addrs_result = getifaddrs(&if_list_head);
Expand Down
23 changes: 17 additions & 6 deletions src/iso15118/tbd_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,25 @@
#include <iso15118/session/iso.hpp>

#include <iso15118/detail/helper.hpp>
#include <iso15118/detail/io/socket_helper.hpp>

namespace iso15118 {

TbdController::TbdController(TbdConfig config_, session::feedback::Callbacks callbacks_, d20::EvseSetupConfig setup_) :
config(std::move(config_)), callbacks(std::move(callbacks_)), evse_setup(std::move(setup_)) {
config(std::move(config_)),
callbacks(std::move(callbacks_)),
evse_setup(std::move(setup_)),
interface_name(config.interface_name) {

const auto result_interface_check = io::check_and_udapte_interface(interface_name);
if (result_interface_check) {
logf_info("Using ethernet interface: %s", interface_name.c_str());
} else {
throw std::runtime_error("Ethernet interface was not found!");
}

if (config.enable_sdp_server) {
sdp_server = std::make_unique<io::SdpServer>();
sdp_server = std::make_unique<io::SdpServer>(interface_name);
poll_manager.register_fd(sdp_server->get_fd(), [this]() { handle_sdp_server_input(); });
}
}
Expand All @@ -27,7 +38,7 @@ void TbdController::loop() {
static constexpr auto POLL_MANAGER_TIMEOUT_MS = 50;

if (not config.enable_sdp_server) {
auto connection = std::make_unique<io::ConnectionPlain>(poll_manager, config.interface_name);
auto connection = std::make_unique<io::ConnectionPlain>(poll_manager, interface_name);
session =
std::make_unique<Session>(std::move(connection), std::move(d20::SessionConfig(evse_setup)), callbacks);
}
Expand All @@ -47,7 +58,7 @@ void TbdController::loop() {
session.reset();

if (not config.enable_sdp_server) {
auto connection = std::make_unique<io::ConnectionPlain>(poll_manager, config.interface_name);
auto connection = std::make_unique<io::ConnectionPlain>(poll_manager, interface_name);
session = std::make_unique<Session>(std::move(connection),
std::move(d20::SessionConfig(evse_setup)), callbacks);
}
Expand Down Expand Up @@ -104,9 +115,9 @@ void TbdController::handle_sdp_server_input() {

auto connection = [this](bool secure_connection) -> std::unique_ptr<io::IConnection> {
if (secure_connection) {
return std::make_unique<io::ConnectionSSL>(poll_manager, config.interface_name, config.ssl);
return std::make_unique<io::ConnectionSSL>(poll_manager, interface_name, config.ssl);
} else {
return std::make_unique<io::ConnectionPlain>(poll_manager, config.interface_name);
return std::make_unique<io::ConnectionPlain>(poll_manager, interface_name);
}
}(request.security == io::v2gtp::Security::TLS);

Expand Down

0 comments on commit df50777

Please sign in to comment.