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);
83 TRACE(
" Executing get_sockfd()")
87 if (a_socktype != SOCK_STREAM && a_socktype != SOCK_DGRAM)
88 throw std::invalid_argument(
90 "MSG1016")
"Failed to create socket: invalid socket type " +
91 std::to_string(a_socktype));
96 SOCKET sfd = umock::sys_socket_h.socket(AF_INET6, a_socktype, 0);
97 UPnPsdk_LOGINFO(
"MSG1135")
"syscall ::socket(AF_INET6, "
98 << a_socktype <<
", 0). Get socket fd " << sfd <<
'\n';
99 if (sfd == INVALID_SOCKET) {
101 throw std::runtime_error(
102 UPnPsdk_LOGEXCEPT(
"MSG1017")
"Failed to create socket: " +
106 constexpr socklen_t optlen{
sizeof(so_option)};
111 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
112 reinterpret_cast<char*
>(&so_option),
116 throw std::runtime_error(
117 UPnPsdk_LOGEXCEPT(
"MSG1018")
"Close socket fd " +
118 std::to_string(sfd) +
119 ". Failed to set socket option SO_REUSEADDR: " +
128 if (umock::sys_socket_h.setsockopt(
129 sfd, IPPROTO_IPV6, IPV6_V6ONLY,
130 reinterpret_cast<const char*
>(&so_option),
131 sizeof(so_option)) != 0) {
134 throw std::runtime_error(
135 UPnPsdk_LOGEXCEPT(
"MSG1007")
"Close socket fd " +
136 std::to_string(sfd) +
137 ". Failed to set socket option IPV6_V6ONLY: " +
150 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
151 reinterpret_cast<char*
>(&so_option),
155 throw std::runtime_error(
156 UPnPsdk_LOGEXCEPT(
"MSG1019")
"Close socket fd " +
157 std::to_string(sfd) +
158 ". Failed to set socket option SO_EXCLUSIVEADDRUSE: " +
172 TRACE2(
this,
" Construct default CSocket_basic()")}
176 : m_sfd_hint(a_sfd) {
177 TRACE2(
this,
" Construct CSocket_basic(SOCKET)")
181CSocket_basic::~CSocket_basic() {
182 TRACE2(
this,
" Destruct CSocket_basic()")
183 if (::pthread_mutex_destroy(&m_socket_mutex) != 0)
185 "MSG1151") "fails with EBUSY. The mutex is currently locked.\n";
190 TRACE2(
this,
" Executing CSocket_basic::load()")
195 socklen_t optlen{
sizeof(so_option)};
197 TRACE2(
this,
" Calling system function ::getsockopt().")
198 ::pthread_mutex_lock(&m_socket_mutex);
199 if (umock::sys_socket_h.getsockopt(m_sfd_hint, SOL_SOCKET, SO_ERROR,
200 reinterpret_cast<char*
>(&so_option),
203 ::pthread_mutex_unlock(&m_socket_mutex);
204 throw std::runtime_error(
205 UPnPsdk_LOGEXCEPT(
"MSG1014")
"Failed to create socket=" +
206 std::to_string(m_sfd_hint) +
": " + serrObj.
error_str() +
'\n');
209 ::pthread_mutex_unlock(&m_socket_mutex);
213CSocket_basic::operator SOCKET()
const {
214 TRACE2(
this,
" Executing CSocket_basic::operator SOCKET() (get "
216 ::pthread_mutex_lock(&m_socket_mutex);
217 const auto sfd{m_sfd};
218 ::pthread_mutex_unlock(&m_socket_mutex);
225 TRACE2(
this,
" Executing CSocket_basic::local_saddr()")
227 return this->local_saddr_protected(a_saddr);
231bool CSocket_basic::local_saddr_protected(
SSockaddr* a_saddr)
const {
232 TRACE2(
this,
" Executing CSocket_basic::local_saddr_protected()")
233 if (m_sfd == INVALID_SOCKET) {
241 socklen_t addrlen =
sizeof(saObj.ss);
244 int ret = UPnPsdk::getsockname(m_sfd, &saObj.sa, &addrlen);
246 serrObj.catch_error();
247 throw std::runtime_error(
248 UPnPsdk_LOGEXCEPT(
"MSG1001")
"Failed to get address from socket(" +
249 std::to_string(m_sfd) +
"): " + serrObj.error_str());
251 sa_family_t af = saObj.ss.ss_family;
252 if (af != AF_INET6 && af != AF_INET)
253 throw std::runtime_error(
254 UPnPsdk_LOGEXCEPT(
"MSG1091")
"Unsupported address family " +
255 std::to_string(saObj.ss.ss_family));
261 if (!(af == AF_INET6 && addrlen ==
sizeof(saObj.sin6)) &&
262 !(af == AF_INET && addrlen ==
sizeof(saObj.sin))) {
269 a_saddr->
ss.ss_family = af;
281 TRACE2(
this,
" Executing CSocket_basic::remote_saddr()")
285 if (m_sfd == INVALID_SOCKET) {
293 socklen_t addrlen =
sizeof(saObj.
ss);
296 int ret = umock::sys_socket_h.getpeername(m_sfd, &saObj.
sa, &addrlen);
299 if (serrObj == ENOTCONNP) {
305 throw std::runtime_error(
306 UPnPsdk_LOGEXCEPT(
"MSG1044")
"Failed to get address from socket(" +
307 std::to_string(m_sfd) +
"): " + serrObj.
error_str());
314 sa_family_t af = saObj.
ss.ss_family;
315 if ((af == AF_INET6 && addrlen ==
sizeof(saObj.
sin6)) ||
316 (af == AF_INET && addrlen ==
sizeof(saObj.
sin))) {
323 throw std::invalid_argument(
325 "MSG1088")
"Unknown socket address detected with address family " +
326 std::to_string(saObj.
ss.ss_family));
331 TRACE2(
this,
" Executing CSocket_basic::socktype()")
333 socklen_t len{
sizeof(so_option)};
335 ::pthread_mutex_lock(&m_socket_mutex);
337 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_TYPE,
338 reinterpret_cast<char*
>(&so_option),
341 ::pthread_mutex_unlock(&m_socket_mutex);
342 throw std::runtime_error(
343 UPnPsdk_LOGEXCEPT(
"MSG1030")
"Failed to get socket option SO_TYPE "
344 "(SOCK_STREAM, SOCK_DGRAM, etc.): " +
347 ::pthread_mutex_unlock(&m_socket_mutex);
352 TRACE2(
this,
" Executing CSocket_basic::sockerr()")
354 socklen_t len{
sizeof(so_option)};
356 ::pthread_mutex_lock(&m_socket_mutex);
358 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_ERROR,
359 reinterpret_cast<char*
>(&so_option),
362 ::pthread_mutex_unlock(&m_socket_mutex);
363 throw std::runtime_error(
365 "MSG1011")
"Failed to get socket option SO_ERROR: " +
368 ::pthread_mutex_unlock(&m_socket_mutex);
373 TRACE2(
this,
" Executing CSocket_basic::is_reuse_addr()")
375 socklen_t len{
sizeof(so_option)};
377 ::pthread_mutex_lock(&m_socket_mutex);
379 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_REUSEADDR,
380 reinterpret_cast<char*
>(&so_option),
383 ::pthread_mutex_unlock(&m_socket_mutex);
384 throw std::runtime_error(
386 "MSG1013")
"Failed to get socket option SO_REUSEADDR: " +
389 ::pthread_mutex_unlock(&m_socket_mutex);
401 TRACE2(
this,
" Construct move CSocket()")
402 ::pthread_mutex_lock(&m_socket_mutex);
404 that.m_sfd = INVALID_SOCKET;
406 m_listen = that.m_listen;
407 that.m_listen =
false;
408 ::pthread_mutex_unlock(&m_socket_mutex);
413 TRACE2(
this,
" Executing CSocket::operator=()")
415 std::swap(m_sfd, that.m_sfd);
416 std::swap(m_listen, that.m_listen);
423 TRACE2(
this,
" Destruct CSocket()")
424 ::pthread_mutex_lock(&m_socket_mutex);
425 if (m_sfd != INVALID_SOCKET)
426 UPnPsdk_LOGINFO(
"MSG1136")
"shutdown and close socket fd " << m_sfd
428 ::shutdown(m_sfd, SHUT_RDWR);
429 CLOSE_SOCKET_P(m_sfd);
430 ::pthread_mutex_unlock(&m_socket_mutex);
442void CSocket::set_reuse_addr(
bool a_reuse) {
447 so_option = a_reuse_addr ? 1 : 0;
449 if (umock::sys_socket_h.setsockopt(m_listen_sfd, SOL_SOCKET, SO_REUSEADDR,
450 reinterpret_cast<char*
>(&so_option), optlen) != 0)
451 throw_error(
"MSG1004: Failed to set socket option SO_REUSEADDR:");
459 TRACE2(
this,
" Executing CSocket::bind()")
467 if (m_sfd != INVALID_SOCKET) {
468 this->local_saddr_protected(&saddrObj);
469 throw std::runtime_error(
470 UPnPsdk_LOGEXCEPT(
"MSG1137")
"Failed to bind socket to an "
471 "address. Socket fd " +
472 std::to_string(m_sfd) +
" already bound to netaddress \"" +
479 if (a_saddr ==
nullptr) {
480 if (!(a_flags & AI_PASSIVE)) {
485 throw std::runtime_error(
486 UPnPsdk_LOGEXCEPT(
"MSG1037")
"No usable link local or "
487 "global ip address found. Try "
488 "to use \"loopback\".\n");
502 throw std::runtime_error(
503 UPnPsdk_LOGEXCEPT(
"MSG1092")
"detect error next line ...\n" +
509 SOCKET sockfd = get_sockfd(ai->ai_socktype);
512 int ret_code{SOCKET_ERROR};
515 for (count = 0; count < 5; count++) {
516 ret_code = umock::sys_socket_h.bind(
517 sockfd, ai->ai_addr,
static_cast<socklen_t
>(ai->ai_addrlen));
522 reinterpret_cast<sockaddr_in6*
>(ai->ai_addr)->sin6_port = 0;
526 ret_code = umock::sys_socket_h.bind(sockfd, ai->ai_addr,
527 static_cast<socklen_t
>(ai->ai_addrlen));
539 this->local_saddr_protected(&saObj);
540 UPnPsdk_LOGINFO(
"MSG1115")
"syscall ::bind("
542 <<
") Tried " << count <<
" times \"" << saddrObj.
netaddrp()
543 << (ret_code != 0 ?
"\". Get ERROR"
544 :
"\". Bound to \"" + saObj.
netaddrp())
548 if (ret_code == SOCKET_ERROR) {
549 CLOSE_SOCKET_P(sockfd);
551 throw std::runtime_error(
552 UPnPsdk_LOGEXCEPT(
"MSG1008")
"Close socket fd " +
553 std::to_string(sockfd) +
". Failed to bind socket " +
554 std::to_string(count) +
" times to address=\"" +
555 saddrObj.
netaddrp() +
"\": (errid " + std::to_string(serrObj) +
562 TRACE2(
this,
" Executing CSocket::listen()")
565 ::pthread_mutex_lock(&m_socket_mutex);
568 ::pthread_mutex_unlock(&m_socket_mutex);
575 if (umock::sys_socket_h.listen(m_sfd, SOMAXCONN) != 0) {
577 ::pthread_mutex_unlock(&m_socket_mutex);
578 throw std::runtime_error(
579 UPnPsdk_LOGEXCEPT(
"MSG1034")
"Failed to set socket to listen: " +
582 UPnPsdk_LOGINFO(
"MSG1032")
"syscall ::listen(" << m_sfd <<
", " << SOMAXCONN
585 ::pthread_mutex_unlock(&m_socket_mutex);
591 TRACE2(
this,
" Executing CSocket::is_listen()")
592 ::pthread_mutex_lock(&m_socket_mutex);
593 if (m_sfd == INVALID_SOCKET) {
594 ::pthread_mutex_unlock(&m_socket_mutex);
595 throw std::runtime_error(
596 UPnPsdk_LOGEXCEPT(
"MSG1035")
"Failed to get socket option "
597 "'is_Listen': Bad file descriptor.\n");
599 const auto listen{m_listen};
600 ::pthread_mutex_unlock(&m_socket_mutex);
607CSocketErr::CSocketErr() =
default;
609CSocketErr::~CSocketErr() =
default;
611CSocketErr::operator
const int&() {
620 m_errno = umock::winsock2_h.WSAGetLastError();
624 TRACE2(
this,
" Executing CSocketErr::catch_error()")
633 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.
void sockaddr(SSockaddr &a_saddr)
Get the socket address from current selcted address information.
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(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.