added Socket::getIfceIndex(), Socket::getIfceAddress(), etc
This commit is contained in:
parent
4a10c5d7cd
commit
5b529ad535
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
/////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user