added Socket::getIfceIndex(), Socket::getIfceAddress(), etc
This commit is contained in:
		| @ -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); | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user