Skip to content
This repository has been archived by the owner on Feb 7, 2023. It is now read-only.

Commit

Permalink
udp_socket: Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
lhmouse committed Feb 7, 2023
1 parent 1ff5b4c commit 52ede8e
Showing 1 changed file with 28 additions and 67 deletions.
95 changes: 28 additions & 67 deletions poseidon/socket/udp_socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "../static/async_logger.hpp"
#include "../utils.hpp"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>

namespace poseidon {
Expand Down Expand Up @@ -175,36 +174,25 @@ void
UDP_Socket::
join_multicast_group(const Socket_Address& maddr, uint8_t ttl, bool loopback, const char* ifname_opt)
{
// Get the local address of the interface to use.
struct ::ifreq ifreq;
::memset(&ifreq, 0, sizeof(ifreq));

if(ifname_opt) {
size_t ifname_len = ::strlen(ifname_opt);
if(ifname_len + 1 > IF_NAMESIZE)
POSEIDON_THROW((
"Network interface name too long: ifname = `$3`",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), ifname_opt);

::memcpy(ifreq.ifr_name, ifname_opt, ifname_len);
}
// Get the index of the interface to use. If no interface name is given,
// the second one is used, as the first one is typically the loopback
// interface `lo`.
int ifindex = ifname_opt ? (int) ::if_nametoindex(ifname_opt) : 2;
if(ifindex <= 0)
POSEIDON_THROW((
"Failed to get index of interface `$4`",
"[`ioctl()` failed: $3]",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), format_errno(), ifname_opt);

// IPv6 doesn't take IPv4-mapped multicast addresses, so there has to be
// special treatement. `sendto()` is not affected.
if(::memcmp(maddr.data(), "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF", 12) == 0) {
// IPv4
if(ifreq.ifr_name[0] && (::ioctl(this->fd(), SIOCGIFADDR, &ifreq) != 0))
POSEIDON_THROW((
"Failed to get address of interface `$4`",
"[`ioctl()` failed: $3]",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), format_errno(), ifreq.ifr_name);

// Join the multicast group.
struct ::ip_mreq mreq;
struct ::ip_mreqn mreq;
::memcpy(&(mreq.imr_multiaddr.s_addr), maddr.data() + 12, 4);
::memcpy(&(mreq.imr_interface.s_addr), &(ifreq.ifr_addr), 4);
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = ifindex;
if(::setsockopt(this->fd(), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0)
POSEIDON_THROW((
"Failed to join IPv4 multicast group `$4`",
Expand All @@ -230,18 +218,10 @@ join_multicast_group(const Socket_Address& maddr, uint8_t ttl, bool loopback, co
this, typeid(*this), format_errno());
}
else {
// IPv6
if(ifreq.ifr_name[0] && (::ioctl(this->fd(), SIOCGIFINDEX, &ifreq) != 0))
POSEIDON_THROW((
"Failed to get index of interface `$4`",
"[`ioctl()` failed: $3]",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), format_errno(), ifreq.ifr_name);

// Join the multicast group.
struct ::ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = maddr.addr();
mreq.ipv6mr_interface = (unsigned) ifreq.ifr_ifindex;
mreq.ipv6mr_interface = (uint32_t) ifindex;
if(::setsockopt(this->fd(), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0)
POSEIDON_THROW((
"Failed to join IPv6 multicast group `$4`",
Expand Down Expand Up @@ -277,36 +257,25 @@ void
UDP_Socket::
leave_multicast_group(const Socket_Address& maddr, const char* ifname_opt)
{
// Get the local address of the interface to use.
struct ::ifreq ifreq;
::memset(&ifreq, 0, sizeof(ifreq));

if(ifname_opt) {
size_t ifname_len = ::strlen(ifname_opt);
if(ifname_len + 1 > IF_NAMESIZE)
POSEIDON_THROW((
"Network interface name too long: ifname = `$3`",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), ifname_opt);

::memcpy(ifreq.ifr_name, ifname_opt, ifname_len);
}
// Get the index of the interface to use. If no interface name is given,
// the second one is used, as the first one is typically the loopback
// interface `lo`.
int ifindex = ifname_opt ? (int) ::if_nametoindex(ifname_opt) : 2;
if(ifindex <= 0)
POSEIDON_THROW((
"Failed to get index of interface `$4`",
"[`ioctl()` failed: $3]",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), format_errno(), ifname_opt);

// IPv6 doesn't take IPv4-mapped multicast addresses, so there has to be
// special treatement. `sendto()` is not affected.
if(::memcmp(maddr.data(), "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF", 12) == 0) {
// IPv4
if(ifreq.ifr_name[0] && (::ioctl(this->fd(), SIOCGIFADDR, &ifreq) != 0))
POSEIDON_THROW((
"Failed to get address of interface `$4`",
"[`ioctl()` failed: $3]",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), format_errno(), ifreq.ifr_name);

// Leave the multicast group.
struct ::ip_mreq mreq;
struct ::ip_mreqn mreq;
::memcpy(&(mreq.imr_multiaddr.s_addr), maddr.data() + 12, 4);
::memcpy(&(mreq.imr_interface.s_addr), &(ifreq.ifr_addr), 4);
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = ifindex;
if(::setsockopt(this->fd(), IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) != 0)
POSEIDON_THROW((
"Failed to leave IPv4 multicast group `$4`",
Expand All @@ -315,18 +284,10 @@ leave_multicast_group(const Socket_Address& maddr, const char* ifname_opt)
this, typeid(*this), format_errno(), maddr);
}
else {
// IPv6
if(ifreq.ifr_name[0] && (::ioctl(this->fd(), SIOCGIFINDEX, &ifreq) != 0))
POSEIDON_THROW((
"Failed to get index of interface `$4`",
"[`ioctl()` failed: $3]",
"[UDP socket `$1` (class `$2`)]"),
this, typeid(*this), format_errno(), ifreq.ifr_name);

// Leave the multicast group.
struct ::ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = maddr.addr();
mreq.ipv6mr_interface = (unsigned) ifreq.ifr_ifindex;
mreq.ipv6mr_interface = (uint32_t) ifindex;
if(::setsockopt(this->fd(), IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) != 0)
POSEIDON_THROW((
"Failed to leave IPv6 multicast group `$4`",
Expand Down

0 comments on commit 52ede8e

Please sign in to comment.