diff --git a/qse/include/qse/si/Socket.hpp b/qse/include/qse/si/Socket.hpp index 51d0070b..7bf13a08 100644 --- a/qse/include/qse/si/Socket.hpp +++ b/qse/include/qse/si/Socket.hpp @@ -95,6 +95,8 @@ public: qse_ssize_t receive (void* buf, qse_size_t len, SocketAddress& srcaddr) QSE_CPP_NOEXCEPT; /* TODO: sendmsg, recvmsg */ + int joinMulticastGroup (const SocketAddress& mcaddr, const SocketAddress& ifaddr); + int leaveMulticastGroup (const SocketAddress& mcaddr, const SocketAddress& ifaddr); // utility functions to retrieve network configuration information. int getIfceIndex (const qse_mchar_t* name); diff --git a/qse/include/qse/si/SocketAddress.hpp b/qse/include/qse/si/SocketAddress.hpp index fef92c28..29be0e68 100644 --- a/qse/include/qse/si/SocketAddress.hpp +++ b/qse/include/qse/si/SocketAddress.hpp @@ -67,10 +67,13 @@ public: void setIpaddr (const qse_ip4ad_t* ipaddr) QSE_CPP_NOEXCEPT; void setIpaddr (const qse_ip6ad_t* ipaddr) QSE_CPP_NOEXCEPT; + const qse_ip4ad_t* getIp4addr () const QSE_CPP_NOEXCEPT; + const qse_ip6ad_t* getIp6addr () const QSE_CPP_NOEXCEPT; + qse_uint16_t getPort() const QSE_CPP_NOEXCEPT; // in network-byte order void setPort (qse_uint16_t port) QSE_CPP_NOEXCEPT; // in network-byte order - qse_uint32_t getScopeId () QSE_CPP_NOEXCEPT; // in network-byte order + qse_uint32_t getScopeId () const QSE_CPP_NOEXCEPT; // in network-byte order void setScopeId (qse_uint32_t scope_id) QSE_CPP_NOEXCEPT; // in network-byte order int set (const qse_skad_t* skad) QSE_CPP_NOEXCEPT; diff --git a/qse/lib/si/Socket.cpp b/qse/lib/si/Socket.cpp index 581bb775..fc76f13e 100644 --- a/qse/lib/si/Socket.cpp +++ b/qse/lib/si/Socket.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #if defined(HAVE_NET_IF_H) # include @@ -590,6 +591,88 @@ qse_ssize_t Socket::receive (void* buf, qse_size_t len, SocketAddress& srcaddr) return n; } +int Socket::joinMulticastGroup (const SocketAddress& mcaddr, const SocketAddress& ifaddr) +{ + int family = mcaddr.getFamily(); // ((struct sockaddr*)mcaddr.getAddrPtr())->sa_family + + if (family != ifaddr.getFamily()) + { + this->setErrorCode (E_EINVAL); + return -1; + } + + switch (family) + { + #if defined(AF_INET) + case AF_INET: + { + + struct ip_mreq mreq; + QSE_MEMSET (&mreq, 0, QSE_SIZEOF(mreq)); + + mreq.imr_multiaddr = *(struct in_addr*)mcaddr.getIp4addr(); + mreq.imr_interface = *(struct in_addr*)ifaddr.getIp4addr(); + return ::setsockopt(this->handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, QSE_SIZEOF(mreq)); + } + #endif + + #if defined(AF_INET6) + case AF_INET6: + { + struct ipv6_mreq mreq; + QSE_MEMSET (&mreq, 0, QSE_SIZEOF(mreq)); + + mreq.ipv6mr_multiaddr = *(struct in6_addr*)mcaddr.getIp6addr(); + mreq.ipv6mr_interface = ifaddr.getScopeId(); + return ::setsockopt(this->handle, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, QSE_SIZEOF(mreq)); + } + #endif + } + + this->setErrorCode (E_ENOIMPL); + return -1; +} + +int Socket::leaveMulticastGroup (const SocketAddress& mcaddr, const SocketAddress& ifaddr) +{ + int family = mcaddr.getFamily(); // ((struct sockaddr*)mcaddr.getAddrPtr())->sa_family + + if (family != ifaddr.getFamily()) + { + this->setErrorCode (E_EINVAL); + return -1; + } + + switch (family) + { + #if defined(AF_INET) + case AF_INET: + { + struct ip_mreq mreq; + QSE_MEMSET (&mreq, 0, QSE_SIZEOF(mreq)); + + mreq.imr_multiaddr = *(struct in_addr*)mcaddr.getIp4addr(); + mreq.imr_interface = *(struct in_addr*)ifaddr.getIp4addr(); + return ::setsockopt(this->handle, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, QSE_SIZEOF(mreq)); + } + #endif + + #if defined(AF_INET6) + case AF_INET6: + { + struct ipv6_mreq mreq; + QSE_MEMSET (&mreq, 0, QSE_SIZEOF(mreq)); + + mreq.ipv6mr_multiaddr = *(struct in6_addr*)mcaddr.getIp6addr(); + mreq.ipv6mr_interface = ifaddr.getScopeId(); + return ::setsockopt(this->handle, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, QSE_SIZEOF(mreq)); + } + #endif + } + + this->setErrorCode (E_ENOIMPL); + return -1; +} int Socket::getIfceIndex (const qse_mchar_t* name) { @@ -674,7 +757,7 @@ int Socket::getIfceAddress (const qse_wchar_t* name, SocketAddress* addr) int Socket::getIfceNetmask(const qse_mchar_t* name, SocketAddress* addr) { -#if defined(SIOCGIFADDR) +#if defined(SIOCGIFNETMASK) return this->get_ifce_address(SIOCGIFNETMASK, name, false, addr); #else this->setErrorCode (E_ENOIMPL); @@ -684,7 +767,7 @@ int Socket::getIfceNetmask(const qse_mchar_t* name, SocketAddress* addr) int Socket::getIfceNetmask (const qse_wchar_t* name, SocketAddress* addr) { -#if defined(SIOCGIFADDR) +#if defined(SIOCGIFNETMASK) return this->get_ifce_address(SIOCGIFNETMASK, name, true, addr); #else this->setErrorCode (E_ENOIMPL); @@ -694,7 +777,7 @@ int Socket::getIfceNetmask (const qse_wchar_t* name, SocketAddress* addr) int Socket::getIfceBroadcast(const qse_mchar_t* name, SocketAddress* addr) { -#if defined(SIOCGIFADDR) +#if defined(SIOCGIFBRDADDR) return this->get_ifce_address(SIOCGIFBRDADDR, name, false, addr); #else this->setErrorCode (E_ENOIMPL); @@ -704,7 +787,7 @@ int Socket::getIfceBroadcast(const qse_mchar_t* name, SocketAddress* addr) int Socket::getIfceBroadcast (const qse_wchar_t* name, SocketAddress* addr) { -#if defined(SIOCGIFADDR) +#if defined(SIOCGIFBRDADDR) return this->get_ifce_address(SIOCGIFBRDADDR, name, true, addr); #else this->setErrorCode (E_ENOIMPL); diff --git a/qse/lib/si/SocketAddress.cpp b/qse/lib/si/SocketAddress.cpp index 2901d177..caa1ae6a 100644 --- a/qse/lib/si/SocketAddress.cpp +++ b/qse/lib/si/SocketAddress.cpp @@ -139,6 +139,30 @@ void SocketAddress::setIpaddr (const qse_ip6ad_t* ipaddr) QSE_CPP_NOEXCEPT #endif } +const qse_ip4ad_t* SocketAddress::getIp4addr () const QSE_CPP_NOEXCEPT +{ +#if defined(AF_INET) + if (FAMILY(&this->skad) == AF_INET) + { + struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad; + return (const qse_ip4ad_t*)&v4->sin_addr; + } +#endif + return QSE_NULL; +} + +const qse_ip6ad_t* SocketAddress::getIp6addr () const QSE_CPP_NOEXCEPT +{ +#if defined(AF_INET6) + if (FAMILY(&this->skad) == AF_INET6) + { + struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad; + return (const qse_ip6ad_t*)&v6->sin6_addr; + } +#endif + return QSE_NULL; +} + qse_uint16_t SocketAddress::getPort () const QSE_CPP_NOEXCEPT { switch (FAMILY(&this->skad)) @@ -187,7 +211,7 @@ void SocketAddress::setPort (qse_uint16_t port) QSE_CPP_NOEXCEPT } } -qse_uint32_t SocketAddress::getScopeId () QSE_CPP_NOEXCEPT +qse_uint32_t SocketAddress::getScopeId () const QSE_CPP_NOEXCEPT { switch (FAMILY(&this->skad)) {