added Socket::getIfceIndex(), Socket::getIfceAddress(), etc

This commit is contained in:
hyung-hwan 2018-10-17 14:20:32 +00:00
parent 4a10c5d7cd
commit 5b529ad535
5 changed files with 316 additions and 9 deletions

View File

@ -96,11 +96,29 @@ public:
/* TODO: sendmsg, recvmsg */
// utility functions to retrieve network configuration information.
int getIfceIndex (const qse_mchar_t* name);
int getIfceIndex (const qse_wchar_t* name);
// the following 6 functions are provided for backward compatibility.
// it is limited to a single address and they may suffer race condition.
// for example, you call getIfceAddress() followed by getIfceNetmask().
// the network configuration information may change in between.
// the address/netmask pair may not be the valid fixed combination.
int getIfceAddress (const qse_mchar_t* name, SocketAddress* addr);
int getIfceAddress (const qse_wchar_t* name, SocketAddress* addr);
int getIfceNetmask (const qse_mchar_t* name, SocketAddress* addr);
int getIfceNetmask (const qse_wchar_t* name, SocketAddress* addr);
int getIfceBroadcast (const qse_mchar_t* name, SocketAddress* addr);
int getIfceBroadcast (const qse_wchar_t* name, SocketAddress* addr);
protected:
qse_sck_hnd_t handle;
int domain;
ErrorCode errcode;
void set_errcode_with_syserr (int syserr);
int get_ifce_address (int cmd, const void* name, bool wchar, SocketAddress* addr);
};

View File

@ -70,6 +70,9 @@ public:
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
void setScopeId (qse_uint32_t scope_id) QSE_CPP_NOEXCEPT; // in network-byte order
int set (const qse_skad_t* skad) QSE_CPP_NOEXCEPT;
int set (const qse_nwad_t* nwad) QSE_CPP_NOEXCEPT;
int set (const qse_mchar_t* str) QSE_CPP_NOEXCEPT;
@ -77,7 +80,6 @@ public:
int set (const qse_mchar_t* str, qse_size_t len) QSE_CPP_NOEXCEPT;
int set (const qse_wchar_t* str, qse_size_t len) QSE_CPP_NOEXCEPT;
qse_mchar_t* toStrBuf (qse_mchar_t* buf, qse_size_t len) const QSE_CPP_NOEXCEPT;
qse_wchar_t* toStrBuf (qse_wchar_t* buf, qse_size_t len) const QSE_CPP_NOEXCEPT;

View File

@ -26,6 +26,7 @@
#include <qse/si/Socket.hpp>
#include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include "../cmn/mem-prv.h"
#include <sys/types.h>
@ -35,6 +36,19 @@
#include <fcntl.h>
#include <unistd.h>
#if defined(HAVE_NET_IF_H)
# include <net/if.h>
#endif
#if defined(HAVE_SYS_IOCTL_H)
# include <sys/ioctl.h>
#endif
#if defined(HAVE_IFADDRS_H)
# include <ifaddrs.h>
#endif
#include <stdio.h>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
@ -42,7 +56,7 @@ QSE_BEGIN_NAMESPACE(QSE)
#include "../cmn/syserr.h"
IMPLEMENT_SYSERR_TO_ERRNUM (Socket::ErrorCode, Socket::)
Socket::Socket () QSE_CPP_NOEXCEPT: handle(QSE_INVALID_SCKHND), errcode(E_ENOERR)
Socket::Socket () QSE_CPP_NOEXCEPT: handle(QSE_INVALID_SCKHND), domain(-1), errcode(E_ENOERR)
{
}
@ -68,7 +82,7 @@ int Socket::open (int domain, int type, int protocol, int traits) QSE_CPP_NOEXCE
if (traits & Socket::T_CLOEXEC) type |= SOCK_CLOEXEC;
open_socket:
#endif
x = ::socket (domain, type, protocol);
x = ::socket(domain, type, protocol);
if (x == -1)
{
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
@ -113,6 +127,18 @@ open_socket:
done:
this->close (); // close the existing handle if open.
this->handle = x;
// while it seems to be possible to get the domain value from a socket
// descriptor with getsockopt(SO_DOMAIN), the method doesn't seem universal.
//
// SO_DOMAIN (since Linux 2.6.32)
// Retrieves the socket domain as an integer, returning a value
// such as AF_INET6. See socket(2) for details. This socket
// option is read-only.
//
// let me just store the information in the class
this->domain = domain;
return 0;
}
@ -122,6 +148,7 @@ void Socket::close () QSE_CPP_NOEXCEPT
{
qse_closesckhnd (this->handle);
this->handle = QSE_INVALID_SCKHND;
this->domain = -1;
}
}
@ -564,6 +591,199 @@ qse_ssize_t Socket::receive (void* buf, qse_size_t len, SocketAddress& srcaddr)
return n;
}
int Socket::getIfceIndex (const qse_mchar_t* name)
{
#if defined(SIOCGIFINDEX)
struct ifreq ifr;
QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr));
qse_mbsxcpy (ifr.ifr_name, QSE_COUNTOF(ifr.ifr_name), name);
if (::ioctl(this->handle, SIOCGIFINDEX, &ifr) == -1)
{
this->setErrorCode (syserr_to_errnum(errno));
return -1;
}
#if defined(ifr_ifindex)
return ifr.ifr_ifindex;
#else
return ifr.ifr_index;
#endif
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceIndex (const qse_wchar_t* name)
{
#if defined(SIOCGIFINDEX)
struct ifreq ifr;
QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr));
qse_size_t wlen, mlen = QSE_COUNTOF(ifr.ifr_name);
if (qse_wcstombs(name, &wlen, ifr.ifr_name, &mlen) <= -1 || wlen < qse_wcslen(name))
{
this->setErrorCode (E_EINVAL);
return -1;
}
if (::ioctl(this->handle, SIOCGIFINDEX, &ifr) == -1)
{
this->setErrorCode (syserr_to_errnum(errno));
return -1;
}
#if defined(ifr_ifindex)
return ifr.ifr_ifindex;
#else
return ifr.ifr_index;
#endif
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceAddress (const qse_mchar_t* name, SocketAddress* addr)
{
#if defined(SIOCGIFADDR)
return this->get_ifce_address(SIOCGIFADDR, name, false, addr);
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceAddress (const qse_wchar_t* name, SocketAddress* addr)
{
#if defined(SIOCGIFADDR)
return this->get_ifce_address(SIOCGIFADDR, name, true, addr);
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceNetmask(const qse_mchar_t* name, SocketAddress* addr)
{
#if defined(SIOCGIFADDR)
return this->get_ifce_address(SIOCGIFNETMASK, name, false, addr);
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceNetmask (const qse_wchar_t* name, SocketAddress* addr)
{
#if defined(SIOCGIFADDR)
return this->get_ifce_address(SIOCGIFNETMASK, name, true, addr);
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceBroadcast(const qse_mchar_t* name, SocketAddress* addr)
{
#if defined(SIOCGIFADDR)
return this->get_ifce_address(SIOCGIFBRDADDR, name, false, addr);
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::getIfceBroadcast (const qse_wchar_t* name, SocketAddress* addr)
{
#if defined(SIOCGIFADDR)
return this->get_ifce_address(SIOCGIFBRDADDR, name, true, addr);
#else
this->setErrorCode (E_ENOIMPL);
return -1;
#endif
}
int Socket::get_ifce_address (int cmd, const void* name, bool wchar, SocketAddress* addr)
{
struct ifreq ifr;
QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr));
if (wchar)
{
qse_size_t wlen, mlen = QSE_COUNTOF(ifr.ifr_name);
if (qse_wcstombs((const qse_wchar_t*)name, &wlen, ifr.ifr_name, &mlen) <= -1 || wlen < qse_wcslen((const qse_wchar_t*)name))
{
this->setErrorCode (E_EINVAL);
return -1;
}
}
else
{
qse_mbsxcpy (ifr.ifr_name, QSE_COUNTOF(ifr.ifr_name), (const qse_mchar_t*)name);
}
#if defined(HAVE_GETIFADDRS)
struct ifaddrs* ifa;
if (::getifaddrs(&ifa) == 0)
{
for (struct ifaddrs* ife = ifa; ife; ife = ife->ifa_next)
{
if (qse_mbscmp (ifr.ifr_name, ife->ifa_name) != 0) continue;
struct sockaddr* sa = QSE_NULL;
switch (cmd)
{
case SIOCGIFADDR:
sa = ife->ifa_addr;
break;
case SIOCGIFNETMASK:
sa = ife->ifa_netmask;
break;
case SIOCGIFBRDADDR:
sa = ife->ifa_broadaddr;
break;
default:
break;
}
if (!sa || !sa->sa_data) continue;
if (sa->sa_family != this->domain) continue; /* skip an address that doesn't match the socket's domain */
*addr = SocketAddress((const qse_skad_t*)sa);
freeifaddrs (ifa);
return 0;
}
freeifaddrs (ifa);
}
#endif
if (::ioctl (this->handle, cmd, &ifr) == -1)
{
this->setErrorCode (syserr_to_errnum(errno));
return -1;
}
struct sockaddr* sa = (struct sockaddr*)&ifr.ifr_addr;
if (sa->sa_family != this->domain)
{
this->setErrorCode (E_ENOENT);
return -1;
}
*addr = SocketAddress((const qse_skad_t*)&ifr.ifr_addr);
return 0;
}
/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////

View File

@ -143,21 +143,21 @@ qse_uint16_t SocketAddress::getPort () const QSE_CPP_NOEXCEPT
{
switch (FAMILY(&this->skad))
{
#if defined(AF_INET)
#if defined(AF_INET)
case AF_INET:
{
struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad;
return v4->sin_port;
}
#endif
#endif
#if defined(AF_INET6)
#if defined(AF_INET6)
case AF_INET6:
{
struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad;
return v6->sin6_port;
}
#endif
#endif
}
return 0;
@ -167,14 +167,14 @@ void SocketAddress::setPort (qse_uint16_t port) QSE_CPP_NOEXCEPT
{
switch (FAMILY(&this->skad))
{
#if defined(AF_INET)
#if defined(AF_INET)
case AF_INET:
{
struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad;
v4->sin_port = port;
break;
}
#endif
#endif
#if defined(AF_INET6)
case AF_INET6:
@ -187,6 +187,37 @@ void SocketAddress::setPort (qse_uint16_t port) QSE_CPP_NOEXCEPT
}
}
qse_uint32_t SocketAddress::getScopeId () QSE_CPP_NOEXCEPT
{
switch (FAMILY(&this->skad))
{
#if defined(AF_INET6)
case AF_INET6:
{
struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad;
return v6->sin6_scope_id;
}
#endif
}
return 0;
}
void SocketAddress::setScopeId (qse_uint32_t scope_id) QSE_CPP_NOEXCEPT
{
switch (FAMILY(&this->skad))
{
#if defined(AF_INET6)
case AF_INET6:
{
struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad;
v6->sin6_scope_id = scope_id;
break;
}
#endif
}
}
int SocketAddress::set (const qse_skad_t* skad) QSE_CPP_NOEXCEPT
{
this->skad = *skad;

View File

@ -24,6 +24,42 @@ static int test1 ()
return -1;
}
qse_printf (QSE_T("lo ifindex ===> %d\n"), s.getIfceIndex(QSE_WT("lo")));
if (s.getIfceAddress(QSE_WT("lo"), &addr) >= 0)
{
qse_char_t buf[256];
qse_printf (QSE_T("lo ifaddr ===> [%s]\n"), addr.toStrBuf(buf, QSE_COUNTOF(buf)));
}
if (s.getIfceNetmask(QSE_WT("lo"), &addr) >= 0)
{
qse_char_t buf[256];
qse_printf (QSE_T("lo netmask ===> [%s]\n"), addr.toStrBuf(buf, QSE_COUNTOF(buf)));
}
if (s.getIfceBroadcast(QSE_WT("lo"), &addr) >= 0)
{
qse_char_t buf[256];
qse_printf (QSE_T("lo broadcast ===> [%s]\n"), addr.toStrBuf(buf, QSE_COUNTOF(buf)));
}
qse_printf (QSE_T("eth0 ifindex ===> %d\n"), s.getIfceIndex(QSE_WT("eth0")));
if (s.getIfceAddress(QSE_WT("eth0"), &addr) >= 0)
{
qse_char_t buf[256];
qse_printf (QSE_T("eth0 ifaddr ===> [%s]\n"), addr.toStrBuf(buf, QSE_COUNTOF(buf)));
}
if (s.getIfceNetmask(QSE_WT("eth0"), &addr) >= 0)
{
qse_char_t buf[256];
qse_printf (QSE_T("eth0 netmask ===> [%s]\n"), addr.toStrBuf(buf, QSE_COUNTOF(buf)));
}
if (s.getIfceBroadcast(QSE_WT("eth0"), &addr) >= 0)
{
qse_char_t buf[256];
qse_printf (QSE_T("eth0 broadcast ===> [%s]\n"), addr.toStrBuf(buf, QSE_COUNTOF(buf)));
}
addr.set ("[::1]:9999");
s.connect (addr);