Unverified Commit 495de8bf authored by Ali Güngör's avatar Ali Güngör Committed by GitHub

Merge pull request #454 from aligungr/ipv6-rls

Ipv6 rls
parents 59c13021 1ce11d50
......@@ -48,7 +48,7 @@ static nr::gnb::GnbConfig *ReadConfigYaml()
result->gnbIdLength = yaml::GetInt32(config, "idLength", 22, 32);
result->tac = yaml::GetInt32(config, "tac", 0, 0xFFFFFF);
result->portalIp = yaml::GetIp4(config, "linkIp");
result->portalIp = yaml::GetIp(config, "linkIp");
result->ngapIp = yaml::GetIp4(config, "ngapIp");
result->gtpIp = yaml::GetIp4(config, "gtpIp");
......
......@@ -11,6 +11,8 @@
#include <atomic>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <vector>
......@@ -37,6 +39,8 @@ void Initialize()
if (g_instanceCount++ != 0)
std::terminate();
srand(time(nullptr));
std::signal(SIGTERM, BaseSignalHandler);
std::signal(SIGINT, BaseSignalHandler);
}
......
......@@ -9,31 +9,49 @@
#include "server.hpp"
#include <cstring>
#include <utils/common.hpp>
namespace udp
{
UdpServer::UdpServer() : socket{Socket::CreateUdp4()}
UdpServer::UdpServer() : sockets{Socket::CreateUdp4(), Socket::CreateUdp6()}
{
}
UdpServer::UdpServer(const std::string &address, uint16_t port) : socket{Socket::CreateAndBindUdp({address, port})}
UdpServer::UdpServer(const std::string &address, uint16_t port) : sockets{Socket::CreateAndBindUdp({address, port})}
{
}
int UdpServer::Receive(uint8_t *buffer, size_t bufferSize, int timeoutMs, InetAddress &outPeerAddress) const
{
auto socket = Socket::Select(sockets, {}, timeoutMs);
if (!socket.hasFd())
return 0;
return socket.receive(buffer, bufferSize, timeoutMs, outPeerAddress);
}
void UdpServer::Send(const InetAddress &address, const uint8_t *buffer, size_t bufferSize) const
{
socket.send(address, buffer, bufferSize);
int version = address.getIpVersion();
if (version != 4 && version != 6)
throw std::runtime_error{"UdpServer::Send failure: Invalid IP version"};
for (const Socket &s : sockets)
{
if (s.hasFd() && s.getIpVersion() == version)
{
s.send(address, buffer, bufferSize);
return;
}
}
throw std::runtime_error{"UdpServer::Send failure: No IP socket found"};
}
UdpServer::~UdpServer()
{
socket.close();
for (auto &s : sockets)
s.close();
}
} // namespace udp
\ No newline at end of file
} // namespace udp
......@@ -9,6 +9,7 @@
#pragma once
#include <string>
#include <unistd.h>
#include <utils/network.hpp>
......@@ -18,7 +19,7 @@ namespace udp
class UdpServer
{
private:
Socket socket;
std::vector<Socket> sockets;
public:
UdpServer();
......
......@@ -219,6 +219,36 @@ std::string GetIp4OfInterface(const std::string &ifName)
return std::string{str};
}
std::string GetIp6OfInterface(const std::string &ifName)
{
std::string res;
struct ifreq ifr = {};
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd <= 0)
return "";
ifr.ifr_addr.sa_family = AF_INET6;
strncpy(ifr.ifr_name, ifName.c_str(), IFNAMSIZ - 1);
if (ioctl(fd, SIOCGIFADDR, &ifr))
{
close(fd);
return "";
}
close(fd);
auto address = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
char str[INET6_ADDRSTRLEN] = {0};
if (inet_ntop(AF_INET6, &address, str, INET6_ADDRSTRLEN) == nullptr)
return "";
return std::string{str};
}
std::string GetHostByName(const std::string &name)
{
struct addrinfo hints = {};
......
......@@ -42,6 +42,8 @@ void AppendPath(std::string &source, const std::string &target);
std::string GetIp4OfInterface(const std::string &ifName);
std::string GetIp6OfInterface(const std::string &ifName);
std::string GetHostByName(const std::string& name);
} // namespace io
......@@ -13,6 +13,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <random>
#include <stdexcept>
#include <sys/socket.h>
#include <sys/types.h>
......@@ -31,15 +32,9 @@ static std::string OctetStringToIpString(const OctetString &address)
char str[INET6_ADDRSTRLEN] = {0};
if (domain == AF_INET)
{
auto *p = reinterpret_cast<in_addr *>(buf);
p->s_addr = (in_addr_t)octet4{address.data()[0], address.data()[1], address.data()[2], address.data()[3]};
}
std::memcpy(buf, address.data(), 4);
else
{
auto *p = reinterpret_cast<in6_addr *>(buf);
std::memcpy(p, address.data(), 16);
}
std::memcpy(buf, address.data(), 16);
if (inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == nullptr)
throw LibError("Bad Inet address, inet_ntop failure:", errno);
......@@ -78,7 +73,7 @@ InetAddress::InetAddress(const std::string &address, uint16_t port) : storage{},
if (s != 0)
throw LibError("Bad Inet address: " + address, errno);
if (result->ai_family != AF_INET && result->ai_family == AF_INET6)
if (result->ai_family != AF_INET && result->ai_family != AF_INET6)
{
freeaddrinfo(result);
throw std::runtime_error("Bad Inet address: " + address);
......@@ -89,6 +84,15 @@ InetAddress::InetAddress(const std::string &address, uint16_t port) : storage{},
freeaddrinfo(result);
}
int InetAddress::getIpVersion() const
{
if (storage.ss_family == AF_INET)
return 4;
if (storage.ss_family == AF_INET6)
return 6;
return 0;
}
InetAddress::InetAddress(const OctetString &address, uint16_t port) : InetAddress(OctetStringToIpString(address), port)
{
}
......@@ -114,6 +118,7 @@ Socket::Socket(int domain, int type, int protocol)
if (sd < 0)
throw LibError("Socket could not be created:", errno);
this->fd = sd;
this->domain = domain;
}
Socket Socket::CreateUdp4()
......@@ -126,17 +131,7 @@ Socket Socket::CreateUdp6()
return {AF_INET6, SOCK_DGRAM, IPPROTO_UDP};
}
Socket Socket::CreateTcp4()
{
return {AF_INET, SOCK_STREAM, IPPROTO_TCP};
}
Socket Socket::CreateTcp6()
{
return {AF_INET6, SOCK_STREAM, IPPROTO_TCP};
}
Socket::Socket() : fd(-1)
Socket::Socket() : fd(-1), domain(0)
{
}
......@@ -261,10 +256,12 @@ Socket Socket::Select(const std::vector<Socket> &readSockets, const std::vector<
std::vector<Socket> rs, ws;
Select(readSockets, writeSockets, rs, ws, timeout);
// Return a socket chosen at random from selection to avoid starvation
auto r = static_cast<size_t>(rand());
if (!rs.empty())
return rs[0];
return rs[r % rs.size()];
if (!ws.empty())
return rs[0];
return ws[r % ws.size()];
return {};
}
......@@ -297,3 +294,12 @@ InetAddress Socket::getAddress() const
return {storage, len};
}
int Socket::getIpVersion() const
{
if (domain == AF_INET6)
return 6;
if (domain == AF_INET)
return 4;
return 0;
}
......@@ -38,6 +38,7 @@ struct InetAddress
return len;
}
[[nodiscard]] int getIpVersion() const;
[[nodiscard]] uint16_t getPort() const;
};
......@@ -45,6 +46,7 @@ class Socket
{
private:
int fd;
int domain;
public:
Socket();
......@@ -57,6 +59,7 @@ class Socket
void close();
[[nodiscard]] bool hasFd() const;
[[nodiscard]] InetAddress getAddress() const;
[[nodiscard]] int getIpVersion() const;
/* Socket options */
void setReuseAddress() const;
......@@ -66,8 +69,6 @@ class Socket
static Socket CreateAndBindTcp(const InetAddress &address);
static Socket CreateUdp4();
static Socket CreateUdp6();
static Socket CreateTcp4();
static Socket CreateTcp6();
static bool Select(const std::vector<Socket> &inReadSockets, const std::vector<Socket> &inWriteSockets,
std::vector<Socket> &outReadSockets, std::vector<Socket> &outWriteSockets, int timeout = 0);
......@@ -76,4 +77,4 @@ class Socket
int timeout = 0);
static bool Select(const Socket &socket, int timeout = 0);
};
\ No newline at end of file
};
......@@ -158,6 +158,38 @@ std::string GetIp4(const YAML::Node &node, const std::string &name)
return ipFromIf;
}
std::string GetIp6(const YAML::Node &node, const std::string &name)
{
std::string s = GetString(node, name);
int version = utils::GetIpVersion(s);
if (version == 4)
FieldError(name, "must be a valid IPv6 address or a valid network interface with a IPv6 address");
if (version == 6)
return s;
auto ipFromIf = io::GetIp6OfInterface(s);
if (ipFromIf.empty())
FieldError(name, "must be a valid IPv6 address or a valid network interface with a IPv6 address");
return ipFromIf;
}
std::string GetIp(const YAML::Node &node, const std::string & name)
{
std::string s = GetString(node, name);
int version = utils::GetIpVersion(s);
if (version == 6 || version == 4)
return s;
auto ip4FromIf = io::GetIp4OfInterface(s);
if (!ip4FromIf.empty())
return ip4FromIf;
auto ip6FromIf = io::GetIp6OfInterface(s);
if (!ip6FromIf.empty())
return ip6FromIf;
FieldError(name, "must be a valid IP address or a valid network interface with an IP address");
}
void AssertHasBool(const YAML::Node &node, const std::string &name)
{
AssertHasField(node, name);
......
......@@ -42,6 +42,8 @@ std::string GetString(const YAML::Node &node, const std::string &name, std::opti
std::optional<int> maxLength);
std::string GetIp4(const YAML::Node &node, const std::string &name);
std::string GetIp6(const YAML::Node &node, const std::string &name);
std::string GetIp(const YAML::Node &node, const std::string &name);
bool GetBool(const YAML::Node &node, const std::string &name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment