12#include <umock/sys_socket.hpp>
13#include <umock/stringh.hpp>
15#include <umock/winsock2.hpp>
37int getsockname(SOCKET a_sockfd, sockaddr* a_addr, socklen_t* a_addrlen) {
38 TRACE(
"Executing getsockname()");
40 int ret = umock::sys_socket_h.getsockname(a_sockfd, a_addr, a_addrlen);
49 if (umock::winsock2_h.WSAGetLastError() != WSAEINVAL)
59 ::WSAPROTOCOL_INFO protocol_info{};
60 int len{
sizeof(protocol_info)};
61 if (umock::sys_socket_h.getsockopt(a_sockfd, SOL_SOCKET, SO_PROTOCOL_INFO,
62 &protocol_info, &len) != 0)
66 memset(a_addr, 0, *a_addrlen);
70 static_cast<unsigned short>(protocol_info.iAddressFamily);
82SOCKET
get_sockfd(sa_family_t a_pf_family,
int a_socktype) {
83 TRACE(
" Executing get_sockfd()")
87 if (a_pf_family != PF_INET6 && a_pf_family != PF_INET)
88 throw std::invalid_argument(
90 "MSG1015")
"Failed to create socket: invalid protocol family " +
91 std::to_string(a_pf_family));
92 if (a_socktype != SOCK_STREAM && a_socktype != SOCK_DGRAM)
93 throw std::invalid_argument(
95 "MSG1016")
"Failed to create socket: invalid socket type " +
96 std::to_string(a_socktype));
101 SOCKET sfd = umock::sys_socket_h.socket(a_pf_family, a_socktype, 0);
102 UPnPsdk_LOGINFO(
"MSG1135")
"syscall ::socket("
103 << a_pf_family <<
", " << a_socktype <<
", 0). Get socket fd " << sfd
105 if (sfd == INVALID_SOCKET) {
107 throw std::runtime_error(
108 UPnPsdk_LOGEXCEPT(
"MSG1017")
"Failed to create socket: " +
112 constexpr socklen_t optlen{
sizeof(so_option)};
117 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
118 reinterpret_cast<char*
>(&so_option),
122 throw std::runtime_error(
123 UPnPsdk_LOGEXCEPT(
"MSG1018")
"Close socket fd " +
124 std::to_string(sfd) +
125 ". Failed to set socket option SO_REUSEADDR: " +
131 if (a_pf_family == AF_INET6) {
134 if (umock::sys_socket_h.setsockopt(
135 sfd, IPPROTO_IPV6, IPV6_V6ONLY,
136 reinterpret_cast<const char*
>(&so_option),
137 sizeof(so_option)) != 0) {
140 throw std::runtime_error(
141 UPnPsdk_LOGEXCEPT(
"MSG1007")
"Close socket fd " +
142 std::to_string(sfd) +
143 ". Failed to set socket option IPV6_V6ONLY: " +
157 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
158 reinterpret_cast<char*
>(&so_option),
162 throw std::runtime_error(
163 UPnPsdk_LOGEXCEPT(
"MSG1019")
"Close socket fd " +
164 std::to_string(sfd) +
165 ". Failed to set socket option SO_EXCLUSIVEADDRUSE: " +
179 TRACE2(
this,
" Construct default CSocket_basic()")}
183 : m_sfd_hint(a_sfd) {
184 TRACE2(
this,
" Construct CSocket_basic(SOCKET)")
188CSocket_basic::~CSocket_basic() {
189 TRACE2(
this,
" Destruct CSocket_basic()")
190 if (::pthread_mutex_destroy(&m_socket_mutex) != 0)
192 "MSG1151") "fails with EBUSY. The mutex is currently locked.\n";
197 TRACE2(
this,
" Executing CSocket_basic::load()")
202 socklen_t optlen{
sizeof(so_option)};
204 TRACE2(
this,
" Calling system function ::getsockopt().")
205 ::pthread_mutex_lock(&m_socket_mutex);
206 if (umock::sys_socket_h.getsockopt(m_sfd_hint, SOL_SOCKET, SO_ERROR,
207 reinterpret_cast<char*
>(&so_option),
210 ::pthread_mutex_unlock(&m_socket_mutex);
211 throw std::runtime_error(
212 UPnPsdk_LOGEXCEPT(
"MSG1014")
"Failed to create socket=" +
213 std::to_string(m_sfd_hint) +
": " + serrObj.
error_str() +
'\n');
216 ::pthread_mutex_unlock(&m_socket_mutex);
220CSocket_basic::operator SOCKET()
const {
221 TRACE2(
this,
" Executing CSocket_basic::operator SOCKET() (get "
223 ::pthread_mutex_lock(&m_socket_mutex);
224 const auto sfd{m_sfd};
225 ::pthread_mutex_unlock(&m_socket_mutex);
232 TRACE2(
this,
" Executing CSocket_basic::local_saddr()")
234 return this->local_saddr_protected(a_saddr);
238bool CSocket_basic::local_saddr_protected(
SSockaddr* a_saddr)
const {
239 TRACE2(
this,
" Executing CSocket_basic::local_saddr_protected()")
240 if (m_sfd == INVALID_SOCKET) {
248 socklen_t addrlen =
sizeof(saObj.ss);
251 int ret = UPnPsdk::getsockname(m_sfd, &saObj.sa, &addrlen);
253 serrObj.catch_error();
254 throw std::runtime_error(
255 UPnPsdk_LOGEXCEPT(
"MSG1001")
"Failed to get address from socket(" +
256 std::to_string(m_sfd) +
"): " + serrObj.error_str());
258 sa_family_t af = saObj.ss.ss_family;
259 if (af != AF_INET6 && af != AF_INET)
260 throw std::runtime_error(
261 UPnPsdk_LOGEXCEPT(
"MSG1091")
"Unsupported address family " +
262 std::to_string(saObj.ss.ss_family));
268 if (!(af == AF_INET6 && addrlen ==
sizeof(saObj.sin6)) &&
269 !(af == AF_INET && addrlen ==
sizeof(saObj.sin))) {
276 a_saddr->
ss.ss_family = af;
288 TRACE2(
this,
" Executing CSocket_basic::remote_saddr()")
292 if (m_sfd == INVALID_SOCKET) {
300 socklen_t addrlen =
sizeof(saObj.
ss);
303 int ret = umock::sys_socket_h.getpeername(m_sfd, &saObj.
sa, &addrlen);
306 if (serrObj == ENOTCONNP) {
312 throw std::runtime_error(
313 UPnPsdk_LOGEXCEPT(
"MSG1044")
"Failed to get address from socket(" +
314 std::to_string(m_sfd) +
"): " + serrObj.
error_str());
321 sa_family_t af = saObj.
ss.ss_family;
322 if ((af == AF_INET6 && addrlen ==
sizeof(saObj.
sin6)) ||
323 (af == AF_INET && addrlen ==
sizeof(saObj.
sin))) {
330 throw std::invalid_argument(
332 "MSG1088")
"Unknown socket address detected with address family " +
333 std::to_string(saObj.
ss.ss_family));
338 TRACE2(
this,
" Executing CSocket_basic::socktype()")
340 socklen_t len{
sizeof(so_option)};
342 ::pthread_mutex_lock(&m_socket_mutex);
344 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_TYPE,
345 reinterpret_cast<char*
>(&so_option),
348 ::pthread_mutex_unlock(&m_socket_mutex);
349 throw std::runtime_error(
350 UPnPsdk_LOGEXCEPT(
"MSG1030")
"Failed to get socket option SO_TYPE "
351 "(SOCK_STREAM, SOCK_DGRAM, etc.): " +
354 ::pthread_mutex_unlock(&m_socket_mutex);
359 TRACE2(
this,
" Executing CSocket_basic::sockerr()")
361 socklen_t len{
sizeof(so_option)};
363 ::pthread_mutex_lock(&m_socket_mutex);
365 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_ERROR,
366 reinterpret_cast<char*
>(&so_option),
369 ::pthread_mutex_unlock(&m_socket_mutex);
370 throw std::runtime_error(
372 "MSG1011")
"Failed to get socket option SO_ERROR: " +
375 ::pthread_mutex_unlock(&m_socket_mutex);
380 TRACE2(
this,
" Executing CSocket_basic::is_reuse_addr()")
382 socklen_t len{
sizeof(so_option)};
384 ::pthread_mutex_lock(&m_socket_mutex);
386 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_REUSEADDR,
387 reinterpret_cast<char*
>(&so_option),
390 ::pthread_mutex_unlock(&m_socket_mutex);
391 throw std::runtime_error(
393 "MSG1013")
"Failed to get socket option SO_REUSEADDR: " +
396 ::pthread_mutex_unlock(&m_socket_mutex);
408 TRACE2(
this,
" Construct move CSocket()")
409 ::pthread_mutex_lock(&m_socket_mutex);
411 that.m_sfd = INVALID_SOCKET;
413 m_listen = that.m_listen;
414 that.m_listen =
false;
415 ::pthread_mutex_unlock(&m_socket_mutex);
420 TRACE2(
this,
" Executing CSocket::operator=()")
422 std::swap(m_sfd, that.m_sfd);
423 std::swap(m_listen, that.m_listen);
430 TRACE2(
this,
" Destruct CSocket()")
431 ::pthread_mutex_lock(&m_socket_mutex);
432 if (m_sfd != INVALID_SOCKET)
433 UPnPsdk_LOGINFO(
"MSG1136")
"shutdown and close socket fd " << m_sfd
435 ::shutdown(m_sfd, SHUT_RDWR);
436 CLOSE_SOCKET_P(m_sfd);
437 ::pthread_mutex_unlock(&m_socket_mutex);
449void CSocket::set_reuse_addr(
bool a_reuse) {
454 so_option = a_reuse_addr ? 1 : 0;
456 if (umock::sys_socket_h.setsockopt(m_listen_sfd, SOL_SOCKET, SO_REUSEADDR,
457 reinterpret_cast<char*
>(&so_option), optlen) != 0)
458 throw_error(
"MSG1004: Failed to set socket option SO_REUSEADDR:");
466 TRACE2(
this,
" Executing CSocket::bind()")
472 if (m_sfd != INVALID_SOCKET) {
474 this->local_saddr_protected(&saObj);
475 throw std::runtime_error(
476 UPnPsdk_LOGEXCEPT(
"MSG1137")
"Failed to bind socket to an "
477 "address. Socket fd " +
478 std::to_string(m_sfd) +
" already bound to netaddress \"" +
486 if (a_saddr ==
nullptr) {
487 if (!(a_flags & AI_PASSIVE)) {
492 throw std::runtime_error(
493 UPnPsdk_LOGEXCEPT(
"MSG1037")
"No usable link local or "
494 "global ip address found. Try "
495 "to use \"loopback\".\n");
507 throw std::runtime_error(
508 UPnPsdk_LOGEXCEPT(
"MSG1092")
"detect error next line ...\n" +
516 get_sockfd(
static_cast<sa_family_t
>(ai->ai_family), ai->ai_socktype);
519 int ret_code{SOCKET_ERROR};
521 ret_code = umock::sys_socket_h.bind(sockfd, ai->ai_addr,
522 static_cast<socklen_t
>(ai->ai_addrlen));
532 this->local_saddr_protected(&saObj);
533 UPnPsdk_LOGINFO(
"MSG1115")
"syscall ::bind("
535 <<
") Tried " << count <<
" times \"" << saddr.
netaddrp()
536 << (ret_code != 0 ?
"\". Get ERROR"
537 :
"\". Bound to \"" + saObj.
netaddrp())
541 if (ret_code == SOCKET_ERROR) {
542 CLOSE_SOCKET_P(sockfd);
543 throw std::runtime_error(
544 UPnPsdk_LOGEXCEPT(
"MSG1008")
"Close socket fd " +
545 std::to_string(sockfd) +
". Failed to bind socket to address=\"" +
546 saddr.
netaddrp() +
"\": (errid " + std::to_string(serrObj) +
") " +
553 TRACE2(
this,
" Executing CSocket::listen()")
556 ::pthread_mutex_lock(&m_socket_mutex);
559 ::pthread_mutex_unlock(&m_socket_mutex);
566 if (umock::sys_socket_h.listen(m_sfd, SOMAXCONN) != 0) {
568 ::pthread_mutex_unlock(&m_socket_mutex);
569 throw std::runtime_error(
570 UPnPsdk_LOGEXCEPT(
"MSG1034")
"Failed to set socket to listen: " +
573 UPnPsdk_LOGINFO(
"MSG1032")
"syscall ::listen(" << m_sfd <<
", " << SOMAXCONN
576 ::pthread_mutex_unlock(&m_socket_mutex);
582 TRACE2(
this,
" Executing CSocket::is_listen()")
583 ::pthread_mutex_lock(&m_socket_mutex);
584 if (m_sfd == INVALID_SOCKET) {
585 ::pthread_mutex_unlock(&m_socket_mutex);
586 throw std::runtime_error(
587 UPnPsdk_LOGEXCEPT(
"MSG1035")
"Failed to get socket option "
588 "'is_Listen': Bad file descriptor.\n");
590 const auto listen{m_listen};
591 ::pthread_mutex_unlock(&m_socket_mutex);
598CSocketErr::CSocketErr() =
default;
600CSocketErr::~CSocketErr() =
default;
602CSocketErr::operator
const int&() {
611 m_errno = umock::winsock2_h.WSAGetLastError();
615 TRACE2(
this,
" Executing CSocketErr::catch_error()")
624 return std::system_category().message(m_errno);
Declaration of the Addrinfo class.
Get information from the operating system about an internet address.
bool get_first()
Get the first entry of an address info from the operating system.
const std::string & what() const
Get cached error message.
Get information from local network adapters.
UPnPsdk_API void get_first()
Load a list of network adapters from the operating system and select its first entry.
UPnPsdk_API void sockaddr(SSockaddr &a_saddr) const
Get socket address from current selected list entry.
UPnPsdk_API bool find_first(std::string_view a_name_or_addr="")
Find local network adapter with given name or ip address.
Scoped POSIX thread mutex lock is valid for the current scope of the object.
Class for portable handling of network socket errors.
void catch_error()
Catch error for later use.
std::string error_str() const
Get human readable error description of the catched error.
Get information from a raw network socket file descriptor.
int sockerr() const
Get the error that is given from the socket as option.
CSocket_basic()
Default constructor for an empty basic socket object with invalid socket file descriptor.
bool local_saddr(SSockaddr *a_saddr=nullptr) const
Get the local socket address the socket is bound to.
void load()
Load the raw socket file descriptor specified with the constructor into the object.
bool remote_saddr(SSockaddr *a_saddr=nullptr) const
Get the remote socket address the socket is connected to.
bool is_reuse_addr() const
Get status if reusing address is enabled.
int socktype() const
Get the socket type.
Manage all aspects of a network socket.
void listen()
Set socket to listen.
CSocket()
Default constructor for an empty socket object.
void bind(const int a_socktype, const SSockaddr *const a_saddr=nullptr, const int a_flags=0)
Bind socket to an ip address of a local network adapter.
virtual ~CSocket()
Destructor.
bool is_listen() const
Get status if the socket is listen to incomming network packets.
CSocket & operator=(CSocket)
Assignment operator.
int getsockname(SOCKET a_sockfd, sockaddr *a_addr, socklen_t *a_addrlen)
Wrapper for the ::getsockname() system function.
SOCKET get_sockfd(sa_family_t a_pf_family, int a_socktype)
Get a socket file descriptor from the operating system.
Reengineered Object Oriented UPnP+ program code.
UPnPsdk_EXTERN bool g_dbug
Switch to enable verbose (debug) output.
Manage information about network adapters.
Socket Module: manage properties and methods but not connections of ONE network socket to handle IPv4...
Trivial ::sockaddr structures enhanced with methods.
sockaddr_in & sin
Reference to sockaddr_in struct.
const std::string netaddrp() noexcept
Get the assosiated netaddress with port.
sockaddr_in6 & sin6
Reference to sockaddr_in6 struct.
sockaddr & sa
Reference to sockaddr struct.
sockaddr_storage & ss
Reference to sockaddr_storage struct.
socklen_t sizeof_saddr() const
Get sizeof the current filled (sin6 or sin) Sockaddr Structure.