UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
socket.cpp
Go to the documentation of this file.
1// Copyright (C) 2021+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
2// Redistribution only with this Copyright remark. Last modified: 2026-04-02
8#include <UPnPsdk/socket.hpp>
9
10#include <UPnPsdk/addrinfo.hpp>
12#include <umock/sys_socket.hpp>
13#include <umock/stringh.hpp>
14#ifdef _MSC_VER
15#include <umock/winsock2.hpp>
17#include <array>
19#endif
20
21namespace UPnPsdk {
22
23namespace {
24
25// Free helper functions
26// =====================
37int getsockname(SOCKET a_sockfd, sockaddr* a_addr, socklen_t* a_addrlen) {
38 TRACE("Executing getsockname()");
39
40 int ret = umock::sys_socket_h.getsockname(a_sockfd, a_addr, a_addrlen);
41
42 if (ret == 0) {
43 return 0;
44 }
45#ifndef _MSC_VER
46 return ret;
47
48#else
49 if (umock::winsock2_h.WSAGetLastError() != WSAEINVAL) // Error 10022 not set
50 return ret;
51
52 // WSAEINVAL indicates that the socket is unbound. We will return an
53 // empty sockaddr with address family set. This is what we get on Unix
54 // platforms. On Microsoft Windows we cannot use ::getsockname() like
55 // on unix platforms because it returns an error indicating an unbound
56 // socket and an untouched socket address storage. Here we have to use
57 // an alternative ::getsockopt() that provides additional info with a
58 // non-standard option SO_PROTOCOL_INFO.
59 ::WSAPROTOCOL_INFO protocol_info{};
60 int len{sizeof(protocol_info)}; // May be modified?
61 if (umock::sys_socket_h.getsockopt(a_sockfd, SOL_SOCKET, SO_PROTOCOL_INFO,
62 &protocol_info, &len) != 0)
63 return WSAENOBUFS; // Insufficient resources were available in the
64 // system to perform the operation.
65
66 memset(a_addr, 0, *a_addrlen);
67 // Microsoft itself defines sockaddr.sa_family as ushort, so the typecast
68 // from int should not do any harm.
69 a_addr->sa_family =
70 static_cast<unsigned short>(protocol_info.iAddressFamily);
71 return 0;
72#endif
73}
74
82SOCKET get_sockfd(int a_socktype) {
83 TRACE(" Executing get_sockfd()")
84
85 // Do some general checks that must always be done according to the
86 // specification.
87 if (a_socktype != SOCK_STREAM && a_socktype != SOCK_DGRAM)
88 throw std::invalid_argument(
89 UPnPsdk_LOGEXCEPT(
90 "MSG1016") "Failed to create socket: invalid socket type " +
91 std::to_string(a_socktype));
92
93 CSocketErr serrObj;
94
95 // Syscall socket(): get new socket file descriptor.
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) {
100 serrObj.catch_error();
101 throw std::runtime_error(
102 UPnPsdk_LOGEXCEPT("MSG1017") "Failed to create socket: " +
103 serrObj.error_str() + '\n');
104 }
105 int so_option{0};
106 constexpr socklen_t optlen{sizeof(so_option)};
107
108 // Reset SO_REUSEADDR on all platforms if it should be set by default. This
109 // is unclear on WIN32. See note below.
110 // Type cast (char*)&so_option is needed for Microsoft Windows.
111 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
112 reinterpret_cast<char*>(&so_option),
113 optlen) != 0) {
114 serrObj.catch_error();
115 CLOSE_SOCKET_P(sfd);
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: " +
120 serrObj.error_str() + '\n');
121 }
122
123 // We have only address family AF_INET6. Always set IPV6_V6ONLY to false.
124 // We need that for IPv4 mapped IPv6 addresses. See also note to bind() in
125 // the header file.
126 so_option = 0; // false
127 // Type cast (char*)&so_option is needed for Microsoft Windows.
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) {
132 serrObj.catch_error();
133 CLOSE_SOCKET_P(sfd);
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: " +
138 serrObj.error_str() + '\n');
139 }
140
141#ifdef _MSC_VER
142 // Set socket option SO_EXCLUSIVEADDRUSE on Microsoft Windows. THIS IS AN
143 // IMPORTANT SECURITY ISSUE! But it needs special handling with binding a
144 // socket fd to an ip address because it may be possible that even a new
145 // unbound socket fd is blocked by the operating system. Lock at
146 // REF:_[Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE]
147 // (https://learn.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse#application-strategies)
148 so_option = 1; // Set SO_EXCLUSIVEADDRUSE
149 // Type cast (char*)&so_option is needed for Microsoft Windows.
150 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
151 reinterpret_cast<char*>(&so_option),
152 optlen) != 0) {
153 serrObj.catch_error();
154 CLOSE_SOCKET_P(sfd);
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: " +
159 serrObj.error_str() + '\n');
160 }
161#endif
162 return sfd;
163}
164
165} // anonymous namespace
166
167
168// CSocket_basic class
169// ===================
170// Default constructor for an empty socket object
172 TRACE2(this, " Construct default CSocket_basic()")}
173
174// Constructor for the socket file descriptor. Before use, it must be load().
176 : m_sfd_hint(a_sfd) { //
177 TRACE2(this, " Construct CSocket_basic(SOCKET)")
178}
179
180// Destructor
181CSocket_basic::~CSocket_basic() {
182 TRACE2(this, " Destruct CSocket_basic()")
183 if (::pthread_mutex_destroy(&m_socket_mutex) != 0)
184 UPnPsdk_LOGCRIT(
185 "MSG1151") "fails with EBUSY. The mutex is currently locked.\n";
186}
187
188// Setter with given file desciptor
190 TRACE2(this, " Executing CSocket_basic::load()")
191
192 CSocketErr serrObj;
193 // Check if we have a valid socket file descriptor
194 int so_option{-1};
195 socklen_t optlen{sizeof(so_option)}; // May be modified
196 // Type cast (char*)&so_option is needed for Microsoft Windows.
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),
201 &optlen) != 0) {
202 serrObj.catch_error();
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');
207 }
208 m_sfd = m_sfd_hint;
209 ::pthread_mutex_unlock(&m_socket_mutex);
210}
211
212// Get the raw socket file descriptor
213CSocket_basic::operator SOCKET() const {
214 TRACE2(this, " Executing CSocket_basic::operator SOCKET() (get "
215 "raw socket fd)")
216 ::pthread_mutex_lock(&m_socket_mutex);
217 const auto sfd{m_sfd};
218 ::pthread_mutex_unlock(&m_socket_mutex);
219 return sfd;
220}
221
222// Getter
223// ------
225 TRACE2(this, " Executing CSocket_basic::local_saddr()")
226 CPthread_scoped_lock lock(m_socket_mutex);
227 return this->local_saddr_protected(a_saddr);
228}
229
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) {
234 if (a_saddr)
235 *a_saddr = "";
236 return false;
237 }
238
239 // Get local address from socket file descriptor.
240 SSockaddr saObj;
241 socklen_t addrlen = sizeof(saObj.ss); // May be modified
242 CSocketErr serrObj;
243 // syscall
244 int ret = UPnPsdk::getsockname(m_sfd, &saObj.sa, &addrlen);
245 if (ret != 0) {
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());
250 }
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));
256
257 // Check if there is a complete address structure returned from
258 // UPnPsdk::getsockname(). On macOS the function returns only part of the
259 // address structure if the socket file descriptor isn't bound to an
260 // address of a local network adapter. It trunkates the address part.
261 if (!(af == AF_INET6 && addrlen == sizeof(saObj.sin6)) &&
262 !(af == AF_INET && addrlen == sizeof(saObj.sin))) {
263 // If there is no complete address structure returned from
264 // UPnPsdk::getsockname() but no error reported, it is considered to be
265 // unbound. I return here an empty socket address with preserved
266 // address family.
267 if (a_saddr) {
268 *a_saddr = "";
269 a_saddr->ss.ss_family = af;
270 }
271 return false;
272 }
273
274 if (a_saddr)
275 *a_saddr = saObj;
276 return true;
277}
279
281 TRACE2(this, " Executing CSocket_basic::remote_saddr()")
282
283 CPthread_scoped_lock lock(m_socket_mutex);
284
285 if (m_sfd == INVALID_SOCKET) {
286 if (a_saddr)
287 *a_saddr = "";
288 return false;
289 }
290
291 // Get remote address from socket file descriptor.
292 SSockaddr saObj;
293 socklen_t addrlen = sizeof(saObj.ss); // May be modified
294 CSocketErr serrObj;
295 // syscall
296 int ret = umock::sys_socket_h.getpeername(m_sfd, &saObj.sa, &addrlen);
297 if (ret != 0) {
298 serrObj.catch_error();
299 if (serrObj == ENOTCONNP) {
300 // Return with empty socket address if not connected.
301 if (a_saddr)
302 *a_saddr = "";
303 return false;
304 }
305 throw std::runtime_error(
306 UPnPsdk_LOGEXCEPT("MSG1044") "Failed to get address from socket(" +
307 std::to_string(m_sfd) + "): " + serrObj.error_str());
308 }
309
310 // Check if there is a complete address structure returned from
311 // ::getpeername(). On macOS the function returns only part of the address
312 // structure if the socket file descriptor isn't connected to an address.
313 // It trunkates the address part.
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))) {
317 if (a_saddr)
318 *a_saddr = saObj;
319 return true;
320 }
321 // If there is no complete address structure returned from ::getpeername()
322 // I do not modify the result object *a_saddr.
323 throw std::invalid_argument(
324 UPnPsdk_LOGEXCEPT(
325 "MSG1088") "Unknown socket address detected with address family " +
326 std::to_string(saObj.ss.ss_family));
327}
328
329
331 TRACE2(this, " Executing CSocket_basic::socktype()")
332 int so_option{-1};
333 socklen_t len{sizeof(so_option)}; // May be modified
334 CSocketErr serrObj;
335 ::pthread_mutex_lock(&m_socket_mutex);
336 // Type cast (char*)&so_option is needed for Microsoft Windows.
337 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_TYPE,
338 reinterpret_cast<char*>(&so_option),
339 &len) != 0) {
340 serrObj.catch_error();
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.): " +
345 serrObj.error_str() + '\n');
346 }
347 ::pthread_mutex_unlock(&m_socket_mutex);
348 return so_option;
349}
350
352 TRACE2(this, " Executing CSocket_basic::sockerr()")
353 int so_option{-1};
354 socklen_t len{sizeof(so_option)}; // May be modified
355 CSocketErr serrObj;
356 ::pthread_mutex_lock(&m_socket_mutex);
357 // Type cast (char*)&so_option is needed for Microsoft Windows.
358 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_ERROR,
359 reinterpret_cast<char*>(&so_option),
360 &len) != 0) {
361 serrObj.catch_error();
362 ::pthread_mutex_unlock(&m_socket_mutex);
363 throw std::runtime_error(
364 UPnPsdk_LOGEXCEPT(
365 "MSG1011") "Failed to get socket option SO_ERROR: " +
366 serrObj.error_str() + '\n');
367 }
368 ::pthread_mutex_unlock(&m_socket_mutex);
369 return so_option;
370}
371
373 TRACE2(this, " Executing CSocket_basic::is_reuse_addr()")
374 int so_option{-1};
375 socklen_t len{sizeof(so_option)}; // May be modified
376 CSocketErr serrObj;
377 ::pthread_mutex_lock(&m_socket_mutex);
378 // Type cast (char*)&so_option is needed for Microsoft Windows.
379 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_REUSEADDR,
380 reinterpret_cast<char*>(&so_option),
381 &len) != 0) {
382 serrObj.catch_error();
383 ::pthread_mutex_unlock(&m_socket_mutex);
384 throw std::runtime_error(
385 UPnPsdk_LOGEXCEPT(
386 "MSG1013") "Failed to get socket option SO_REUSEADDR: " +
387 serrObj.error_str() + '\n');
388 }
389 ::pthread_mutex_unlock(&m_socket_mutex);
390 return so_option;
391}
392
393
394// CSocket class
395// =============
396// Default constructor for an empty socket object
397CSocket::CSocket(){TRACE2(this, " Construct default CSocket()")}
398
399// Move constructor
401 TRACE2(this, " Construct move CSocket()")
402 ::pthread_mutex_lock(&m_socket_mutex);
403 m_sfd = that.m_sfd;
404 that.m_sfd = INVALID_SOCKET;
405
406 m_listen = that.m_listen;
407 that.m_listen = false;
408 ::pthread_mutex_unlock(&m_socket_mutex);
409}
410
411// Assignment operator (parameter as value)
413 TRACE2(this, " Executing CSocket::operator=()")
414 // This is thread safe because the swap is from the stack.
415 std::swap(m_sfd, that.m_sfd);
416 std::swap(m_listen, that.m_listen);
417
418 return *this;
419}
420
421// Destructor
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
427 << ".\n";
428 ::shutdown(m_sfd, SHUT_RDWR);
429 CLOSE_SOCKET_P(m_sfd);
430 ::pthread_mutex_unlock(&m_socket_mutex);
431
432 // Don't destroy pthread mutex here. It will be done with inherited
433 // CSocket_basic::~CSocket_basic.
434 // if (::pthread_mutex_destroy(&m_socket_mutex) != 0)
435 // UPnPsdk_LOGCRIT(
436 // "MSGnnnn") "fails with EBUSY. The mutex is currently locked.\n";
437}
438
439// Setter
440// ------
441#if 0
442void CSocket::set_reuse_addr(bool a_reuse) {
443 // Set socket option SO_REUSEADDR on other platforms.
444 // --------------------------------------------------
445 // REF: [How do SO_REUSEADDR and SO_REUSEPORT differ?]
446 // (https://stackoverflow.com/a/14388707/5014688)
447 so_option = a_reuse_addr ? 1 : 0;
448 // Type cast (char*)&so_reuseaddr is needed for Microsoft Windows.
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:");
452}
453#endif
454
455// Bind socket to an ip address
456// ----------------------------
457void CSocket::bind(const int a_socktype, const SSockaddr* const a_saddr,
458 const int a_flags) {
459 TRACE2(this, " Executing CSocket::bind()")
460
461 // Protect binding.
462 CPthread_scoped_lock lock(m_socket_mutex);
463
464 SSockaddr saddrObj; // Unspecified
465
466 // Check if socket is already bound.
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 \"" +
473 saddrObj.netaddrp() + '\"');
474 }
475
476 // If no socket address is given then get a valid one, either the
477 // unspecified address when a passive address is requested, or the best
478 // choise from the operating system.
479 if (a_saddr == nullptr) {
480 if (!(a_flags & AI_PASSIVE)) {
481 // Get best choise sockaddr from operating system.
482 CNetadapter nadapObj;
483 nadapObj.get_first(); // May throw exception.
484 if (!nadapObj.find_first())
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");
489 nadapObj.sockaddr(saddrObj);
490 }
491 // Here is AI_PASSIVE given, and saddrObj unspecified. That gives the
492 // "wildcard address" IN6ADDR_ANY_INIT ([::]).
493
494 } else {
495 saddrObj = *a_saddr;
496 }
497
498 // Get the address info for binding.
499 CAddrinfo ai(saddrObj.netaddrp(), AI_NUMERICHOST | AI_NUMERICSERV | a_flags,
500 a_socktype);
501 if (!ai.get_first())
502 throw std::runtime_error(
503 UPnPsdk_LOGEXCEPT("MSG1092") "detect error next line ...\n" +
504 ai.what());
505
506 // Get a socket file descriptor from operating system and try to bind it.
507 // ----------------------------------------------------------------------
508 // Get a socket file descriptor.
509 SOCKET sockfd = get_sockfd(ai->ai_socktype);
510
511 // Try to bind the socket.
512 int ret_code{SOCKET_ERROR};
513 int count;
514#ifdef _MSC_VER
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));
518 if (ret_code == 0)
519 break;
520 else
521 // Try with a random port number // DEBUG!
522 reinterpret_cast<sockaddr_in6*>(ai->ai_addr)->sin6_port = 0;
523 }
524#else
525 count = 1;
526 ret_code = umock::sys_socket_h.bind(sockfd, ai->ai_addr,
527 static_cast<socklen_t>(ai->ai_addrlen));
528#endif
529 CSocketErr serrObj;
530 if (ret_code == 0)
531 // Store valid socket file descriptor.
532 m_sfd = sockfd;
533 else
534 serrObj.catch_error();
535
536 if (g_dbug) {
537 ai.sockaddr(saddrObj);
538 SSockaddr saObj;
539 this->local_saddr_protected(&saObj); // Get new bound socket address.
540 UPnPsdk_LOGINFO("MSG1115") "syscall ::bind("
541 << sockfd << ", " << &saObj.sa << ", " << saObj.sizeof_saddr()
542 << ") Tried " << count << " times \"" << saddrObj.netaddrp()
543 << (ret_code != 0 ? "\". Get ERROR"
544 : "\". Bound to \"" + saObj.netaddrp())
545 << "\".\n";
546 }
547
548 if (ret_code == SOCKET_ERROR) {
549 CLOSE_SOCKET_P(sockfd);
550 ai.sockaddr(saddrObj);
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) +
556 ") " + serrObj.error_str());
557 }
558}
559
560// Set socket to listen
562 TRACE2(this, " Executing CSocket::listen()")
563
564 // Protect set listen and storing its state (m_listen).
565 ::pthread_mutex_lock(&m_socket_mutex);
566
567 if (m_listen) {
568 ::pthread_mutex_unlock(&m_socket_mutex);
569 return;
570 }
571
572 CSocketErr serrObj;
573 // Second argument backlog (maximum length of the queue for pending
574 // connections) is hard coded for now.
575 if (umock::sys_socket_h.listen(m_sfd, SOMAXCONN) != 0) {
576 serrObj.catch_error();
577 ::pthread_mutex_unlock(&m_socket_mutex);
578 throw std::runtime_error(
579 UPnPsdk_LOGEXCEPT("MSG1034") "Failed to set socket to listen: " +
580 serrObj.error_str() + '\n');
581 }
582 UPnPsdk_LOGINFO("MSG1032") "syscall ::listen(" << m_sfd << ", " << SOMAXCONN
583 << ").\n";
584 m_listen = true;
585 ::pthread_mutex_unlock(&m_socket_mutex);
586}
587
588// Getter
589// ------
590bool CSocket::is_listen() const {
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");
598 }
599 const auto listen{m_listen};
600 ::pthread_mutex_unlock(&m_socket_mutex);
601 return listen;
602}
603
604
605// Portable handling of socket errors
606// ==================================
607CSocketErr::CSocketErr() = default;
608
609CSocketErr::~CSocketErr() = default;
610
611CSocketErr::operator const int&() {
612 // TRACE not usable with chained output.
613 // TRACE2(this, " Executing CSocketErr::operator int&() (get socket error
614 // number)")
615 return m_errno;
616}
617
619#ifdef _MSC_VER
620 m_errno = umock::winsock2_h.WSAGetLastError();
621#else
622 m_errno = errno;
623#endif
624 TRACE2(this, " Executing CSocketErr::catch_error()")
625}
626
627std::string CSocketErr::error_str() const {
628 // TRACE not usable with chained output, e.g.
629 // std::cerr << "Error: " << sockerrObj.error_str();
630 // TRACE2(this, " Executing CSocketErr::error_str()")
631
632 // Portable C++ statement
633 return std::system_category().message(m_errno);
634 // return std::generic_category().message(m_errno);
635 // return std::strerror(m_errno); // Alternative for Unix platforms
636}
637
638} // namespace UPnPsdk
Declaration of the Addrinfo class.
Get information from the operating system about an internet address.
Definition addrinfo.hpp:55
bool get_first()
Get the first entry of an address info from the operating system.
Definition addrinfo.cpp:156
const std::string & what() const
Get cached error message.
Definition addrinfo.cpp:292
void sockaddr(SSockaddr &a_saddr)
Get the socket address from current selcted address information.
Definition addrinfo.cpp:282
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.
Definition pthread.hpp:103
Class for portable handling of network socket errors.
Definition socket.hpp:537
void catch_error()
Catch error for later use.
Definition socket.cpp:618
std::string error_str() const
Get human readable error description of the catched error.
Definition socket.cpp:627
Get information from a raw network socket file descriptor.
Definition socket.hpp:129
int sockerr() const
Get the error that is given from the socket as option.
Definition socket.cpp:351
CSocket_basic()
Default constructor for an empty basic socket object with invalid socket file descriptor.
Definition socket.cpp:171
bool local_saddr(SSockaddr *a_saddr=nullptr) const
Get the local socket address the socket is bound to.
Definition socket.cpp:224
void load()
Load the raw socket file descriptor specified with the constructor into the object.
Definition socket.cpp:189
bool remote_saddr(SSockaddr *a_saddr=nullptr) const
Get the remote socket address the socket is connected to.
Definition socket.cpp:280
bool is_reuse_addr() const
Get status if reusing address is enabled.
Definition socket.cpp:372
int socktype() const
Get the socket type.
Definition socket.cpp:330
Manage all aspects of a network socket.
Definition socket.hpp:320
void listen()
Set socket to listen.
Definition socket.cpp:561
CSocket()
Default constructor for an empty socket object.
Definition socket.cpp:397
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.
Definition socket.cpp:457
virtual ~CSocket()
Destructor.
Definition socket.cpp:422
bool is_listen() const
Get status if the socket is listen to incomming network packets.
Definition socket.cpp:590
CSocket & operator=(CSocket)
Assignment operator.
Definition socket.cpp:412
int getsockname(SOCKET a_sockfd, sockaddr *a_addr, socklen_t *a_addrlen)
Wrapper for the ::getsockname() system function.
Definition socket.cpp:37
SOCKET get_sockfd(int a_socktype)
Get a socket file descriptor from the operating system.
Definition socket.cpp:82
Reengineered Object Oriented UPnP+ program code.
UPnPsdk_EXTERN bool g_dbug
Switch to enable verbose (debug) output.
Definition global.hpp:26
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.
Definition sockaddr.hpp:133
sockaddr_in & sin
Reference to sockaddr_in struct.
Definition sockaddr.hpp:141
const std::string netaddrp() noexcept
Get the assosiated netaddress with port.
Definition sockaddr.cpp:484
sockaddr_in6 & sin6
Reference to sockaddr_in6 struct.
Definition sockaddr.hpp:139
sockaddr & sa
Reference to sockaddr struct.
Definition sockaddr.hpp:143
sockaddr_storage & ss
Reference to sockaddr_storage struct.
Definition sockaddr.hpp:135
socklen_t sizeof_saddr() const
Get sizeof the current filled (sin6 or sin) Sockaddr Structure.
Definition sockaddr.cpp:520