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: 2025-05-19
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(sa_family_t a_pf_family, 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_pf_family != PF_INET6 && a_pf_family != PF_INET)
88 throw std::invalid_argument(
89 UPnPsdk_LOGEXCEPT(
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(
94 UPnPsdk_LOGEXCEPT(
95 "MSG1016") "Failed to create socket: invalid socket type " +
96 std::to_string(a_socktype));
97
98 CSocketErr serrObj;
99
100 // Syscall socket(): get new socket file descriptor.
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
104 << '\n';
105 if (sfd == INVALID_SOCKET) {
106 serrObj.catch_error();
107 throw std::runtime_error(
108 UPnPsdk_LOGEXCEPT("MSG1017") "Failed to create socket: " +
109 serrObj.error_str() + '\n');
110 }
111 int so_option{0};
112 constexpr socklen_t optlen{sizeof(so_option)};
113
114 // Reset SO_REUSEADDR on all platforms if it should be set by default. This
115 // is unclear on WIN32. See note below.
116 // Type cast (char*)&so_option is needed for Microsoft Windows.
117 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
118 reinterpret_cast<char*>(&so_option),
119 optlen) != 0) {
120 serrObj.catch_error();
121 CLOSE_SOCKET_P(sfd);
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: " +
126 serrObj.error_str() + '\n');
127 }
128
129 // With protocol family PF_INET6 I always set IPV6_V6ONLY to false. See
130 // also note to bind() in the header file.
131 if (a_pf_family == AF_INET6) {
132 so_option = 0; // false
133 // Type cast (char*)&so_option is needed for Microsoft Windows.
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) {
138 serrObj.catch_error();
139 CLOSE_SOCKET_P(sfd);
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: " +
144 serrObj.error_str() + '\n');
145 }
146 }
147
148#ifdef _MSC_VER
149 // Set socket option SO_EXCLUSIVEADDRUSE on Microsoft Windows. THIS IS AN
150 // IMPORTANT SECURITY ISSUE! But it needs special handling with binding a
151 // socket fd to an ip address because it may be possible that even a new
152 // unbound socket fd is blocked by the operating system. Lock at
153 // REF:_[Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE]
154 // (https://learn.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse#application-strategies)
155 so_option = 1; // Set SO_EXCLUSIVEADDRUSE
156 // Type cast (char*)&so_option is needed for Microsoft Windows.
157 if (umock::sys_socket_h.setsockopt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
158 reinterpret_cast<char*>(&so_option),
159 optlen) != 0) {
160 serrObj.catch_error();
161 CLOSE_SOCKET_P(sfd);
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: " +
166 serrObj.error_str() + '\n');
167 }
168#endif
169 return sfd;
170}
171
172} // anonymous namespace
173
174
175// CSocket_basic class
176// ===================
177// Default constructor for an empty socket object
179 TRACE2(this, " Construct default CSocket_basic()")}
180
181// Constructor for the socket file descriptor. Before use, it must be load().
183 : m_sfd_hint(a_sfd) { //
184 TRACE2(this, " Construct CSocket_basic(SOCKET)")
185}
186
187// Destructor
188CSocket_basic::~CSocket_basic() {
189 TRACE2(this, " Destruct CSocket_basic()")
190 if (::pthread_mutex_destroy(&m_socket_mutex) != 0)
191 UPnPsdk_LOGCRIT(
192 "MSG1151") "fails with EBUSY. The mutex is currently locked.\n";
193}
194
195// Setter with given file desciptor
197 TRACE2(this, " Executing CSocket_basic::load()")
198
199 CSocketErr serrObj;
200 // Check if we have a valid socket file descriptor
201 int so_option{-1};
202 socklen_t optlen{sizeof(so_option)}; // May be modified
203 // Type cast (char*)&so_option is needed for Microsoft Windows.
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),
208 &optlen) != 0) {
209 serrObj.catch_error();
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');
214 }
215 m_sfd = m_sfd_hint;
216 ::pthread_mutex_unlock(&m_socket_mutex);
217}
218
219// Get the raw socket file descriptor
220CSocket_basic::operator SOCKET() const {
221 TRACE2(this, " Executing CSocket_basic::operator SOCKET() (get "
222 "raw socket fd)")
223 ::pthread_mutex_lock(&m_socket_mutex);
224 const auto sfd{m_sfd};
225 ::pthread_mutex_unlock(&m_socket_mutex);
226 return sfd;
227}
228
229// Getter
230// ------
232 TRACE2(this, " Executing CSocket_basic::local_saddr()")
233 CPthread_scoped_lock lock(m_socket_mutex);
234 return this->local_saddr_protected(a_saddr);
235}
236
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) {
241 if (a_saddr)
242 *a_saddr = "";
243 return false;
244 }
245
246 // Get local address from socket file descriptor.
247 SSockaddr saObj;
248 socklen_t addrlen = sizeof(saObj.ss); // May be modified
249 CSocketErr serrObj;
250 // syscall
251 int ret = UPnPsdk::getsockname(m_sfd, &saObj.sa, &addrlen);
252 if (ret != 0) {
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());
257 }
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));
263
264 // Check if there is a complete address structure returned from
265 // UPnPsdk::getsockname(). On macOS the function returns only part of the
266 // address structure if the socket file descriptor isn't bound to an
267 // address of a local network adapter. It trunkates the address part.
268 if (!(af == AF_INET6 && addrlen == sizeof(saObj.sin6)) &&
269 !(af == AF_INET && addrlen == sizeof(saObj.sin))) {
270 // If there is no complete address structure returned from
271 // UPnPsdk::getsockname() but no error reported, it is considered to be
272 // unbound. I return here an empty socket address with preserved
273 // address family.
274 if (a_saddr) {
275 *a_saddr = "";
276 a_saddr->ss.ss_family = af;
277 }
278 return false;
279 }
280
281 if (a_saddr)
282 *a_saddr = saObj;
283 return true;
284}
286
288 TRACE2(this, " Executing CSocket_basic::remote_saddr()")
289
290 CPthread_scoped_lock lock(m_socket_mutex);
291
292 if (m_sfd == INVALID_SOCKET) {
293 if (a_saddr)
294 *a_saddr = "";
295 return false;
296 }
297
298 // Get remote address from socket file descriptor.
299 SSockaddr saObj;
300 socklen_t addrlen = sizeof(saObj.ss); // May be modified
301 CSocketErr serrObj;
302 // syscall
303 int ret = umock::sys_socket_h.getpeername(m_sfd, &saObj.sa, &addrlen);
304 if (ret != 0) {
305 serrObj.catch_error();
306 if (serrObj == ENOTCONNP) {
307 // Return with empty socket address if not connected.
308 if (a_saddr)
309 *a_saddr = "";
310 return false;
311 }
312 throw std::runtime_error(
313 UPnPsdk_LOGEXCEPT("MSG1044") "Failed to get address from socket(" +
314 std::to_string(m_sfd) + "): " + serrObj.error_str());
315 }
316
317 // Check if there is a complete address structure returned from
318 // ::getpeername(). On macOS the function returns only part of the address
319 // structure if the socket file descriptor isn't connected to an address.
320 // It trunkates the address part.
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))) {
324 if (a_saddr)
325 *a_saddr = saObj;
326 return true;
327 }
328 // If there is no complete address structure returned from ::getpeername()
329 // I do not modify the result object *a_saddr.
330 throw std::invalid_argument(
331 UPnPsdk_LOGEXCEPT(
332 "MSG1088") "Unknown socket address detected with address family " +
333 std::to_string(saObj.ss.ss_family));
334}
335
336
338 TRACE2(this, " Executing CSocket_basic::socktype()")
339 int so_option{-1};
340 socklen_t len{sizeof(so_option)}; // May be modified
341 CSocketErr serrObj;
342 ::pthread_mutex_lock(&m_socket_mutex);
343 // Type cast (char*)&so_option is needed for Microsoft Windows.
344 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_TYPE,
345 reinterpret_cast<char*>(&so_option),
346 &len) != 0) {
347 serrObj.catch_error();
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.): " +
352 serrObj.error_str() + '\n');
353 }
354 ::pthread_mutex_unlock(&m_socket_mutex);
355 return so_option;
356}
357
359 TRACE2(this, " Executing CSocket_basic::sockerr()")
360 int so_option{-1};
361 socklen_t len{sizeof(so_option)}; // May be modified
362 CSocketErr serrObj;
363 ::pthread_mutex_lock(&m_socket_mutex);
364 // Type cast (char*)&so_option is needed for Microsoft Windows.
365 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_ERROR,
366 reinterpret_cast<char*>(&so_option),
367 &len) != 0) {
368 serrObj.catch_error();
369 ::pthread_mutex_unlock(&m_socket_mutex);
370 throw std::runtime_error(
371 UPnPsdk_LOGEXCEPT(
372 "MSG1011") "Failed to get socket option SO_ERROR: " +
373 serrObj.error_str() + '\n');
374 }
375 ::pthread_mutex_unlock(&m_socket_mutex);
376 return so_option;
377}
378
380 TRACE2(this, " Executing CSocket_basic::is_reuse_addr()")
381 int so_option{-1};
382 socklen_t len{sizeof(so_option)}; // May be modified
383 CSocketErr serrObj;
384 ::pthread_mutex_lock(&m_socket_mutex);
385 // Type cast (char*)&so_option is needed for Microsoft Windows.
386 if (umock::sys_socket_h.getsockopt(m_sfd, SOL_SOCKET, SO_REUSEADDR,
387 reinterpret_cast<char*>(&so_option),
388 &len) != 0) {
389 serrObj.catch_error();
390 ::pthread_mutex_unlock(&m_socket_mutex);
391 throw std::runtime_error(
392 UPnPsdk_LOGEXCEPT(
393 "MSG1013") "Failed to get socket option SO_REUSEADDR: " +
394 serrObj.error_str() + '\n');
395 }
396 ::pthread_mutex_unlock(&m_socket_mutex);
397 return so_option;
398}
399
400
401// CSocket class
402// =============
403// Default constructor for an empty socket object
404CSocket::CSocket(){TRACE2(this, " Construct default CSocket()")}
405
406// Move constructor
408 TRACE2(this, " Construct move CSocket()")
409 ::pthread_mutex_lock(&m_socket_mutex);
410 m_sfd = that.m_sfd;
411 that.m_sfd = INVALID_SOCKET;
412
413 m_listen = that.m_listen;
414 that.m_listen = false;
415 ::pthread_mutex_unlock(&m_socket_mutex);
416}
417
418// Assignment operator (parameter as value)
420 TRACE2(this, " Executing CSocket::operator=()")
421 // This is thread safe because the swap is from the stack.
422 std::swap(m_sfd, that.m_sfd);
423 std::swap(m_listen, that.m_listen);
424
425 return *this;
426}
427
428// Destructor
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
434 << ".\n";
435 ::shutdown(m_sfd, SHUT_RDWR);
436 CLOSE_SOCKET_P(m_sfd);
437 ::pthread_mutex_unlock(&m_socket_mutex);
438
439 // Don't destroy pthread mutex here. It will be done with inherited
440 // CSocket_basic::~CSocket_basic.
441 // if (::pthread_mutex_destroy(&m_socket_mutex) != 0)
442 // UPnPsdk_LOGCRIT(
443 // "MSGnnnn") "fails with EBUSY. The mutex is currently locked.\n";
444}
445
446// Setter
447// ------
448#if 0
449void CSocket::set_reuse_addr(bool a_reuse) {
450 // Set socket option SO_REUSEADDR on other platforms.
451 // --------------------------------------------------
452 // REF: [How do SO_REUSEADDR and SO_REUSEPORT differ?]
453 // (https://stackoverflow.com/a/14388707/5014688)
454 so_option = a_reuse_addr ? 1 : 0;
455 // Type cast (char*)&so_reuseaddr is needed for Microsoft Windows.
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:");
459}
460#endif
461
462// Bind socket to an ip address
463// ----------------------------
464void CSocket::bind(const int a_socktype, const SSockaddr* const a_saddr,
465 const int a_flags) {
466 TRACE2(this, " Executing CSocket::bind()")
467
468 // Protect binding.
469 CPthread_scoped_lock lock(m_socket_mutex);
470
471 // Check if socket is already bound.
472 if (m_sfd != INVALID_SOCKET) {
473 SSockaddr saObj;
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 \"" +
479 saObj.netaddrp() + '\"');
480 }
481
482 // If no socket address is given then get a valid one, either the
483 // unspecified address when a passive address is requested, or the best
484 // choise from the operating system.
485 SSockaddr saddr; // Unspecified
486 if (a_saddr == nullptr) {
487 if (!(a_flags & AI_PASSIVE)) {
488 // Get best choise sockaddr from operating system.
489 CNetadapter nadapObj;
490 nadapObj.get_first(); // May throw exception.
491 if (!nadapObj.find_first())
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");
496 nadapObj.sockaddr(saddr);
497 }
498
499 } else {
500 saddr = *a_saddr;
501 }
502
503 // Get the address info for binding.
504 CAddrinfo ai(saddr.netaddrp(), AI_NUMERICHOST | AI_NUMERICSERV | a_flags,
505 a_socktype);
506 if (!ai.get_first())
507 throw std::runtime_error(
508 UPnPsdk_LOGEXCEPT("MSG1092") "detect error next line ...\n" +
509 ai.what());
510
511
512 // Get a socket file descriptor from operating system and try to bind it.
513 // ----------------------------------------------------------------------
514 // Get a socket file descriptor.
515 SOCKET sockfd =
516 get_sockfd(static_cast<sa_family_t>(ai->ai_family), ai->ai_socktype);
517
518 // Try to bind the socket.
519 int ret_code{SOCKET_ERROR};
520 int count{1};
521 ret_code = umock::sys_socket_h.bind(sockfd, ai->ai_addr,
522 static_cast<socklen_t>(ai->ai_addrlen));
523 CSocketErr serrObj;
524 if (ret_code == 0)
525 // Store valid socket file descriptor.
526 m_sfd = sockfd;
527 else
528 serrObj.catch_error();
529
530 if (g_dbug) {
531 SSockaddr saObj;
532 this->local_saddr_protected(&saObj); // Get new bound socket address.
533 UPnPsdk_LOGINFO("MSG1115") "syscall ::bind("
534 << sockfd << ", " << &saObj.sa << ", " << saObj.sizeof_saddr()
535 << ") Tried " << count << " times \"" << saddr.netaddrp()
536 << (ret_code != 0 ? "\". Get ERROR"
537 : "\". Bound to \"" + saObj.netaddrp())
538 << "\".\n";
539 }
540
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) + ") " +
547 serrObj.error_str());
548 }
549}
550
551// Set socket to listen
553 TRACE2(this, " Executing CSocket::listen()")
554
555 // Protect set listen and storing its state (m_listen).
556 ::pthread_mutex_lock(&m_socket_mutex);
557
558 if (m_listen) {
559 ::pthread_mutex_unlock(&m_socket_mutex);
560 return;
561 }
562
563 CSocketErr serrObj;
564 // Second argument backlog (maximum length of the queue for pending
565 // connections) is hard coded for now.
566 if (umock::sys_socket_h.listen(m_sfd, SOMAXCONN) != 0) {
567 serrObj.catch_error();
568 ::pthread_mutex_unlock(&m_socket_mutex);
569 throw std::runtime_error(
570 UPnPsdk_LOGEXCEPT("MSG1034") "Failed to set socket to listen: " +
571 serrObj.error_str() + '\n');
572 }
573 UPnPsdk_LOGINFO("MSG1032") "syscall ::listen(" << m_sfd << ", " << SOMAXCONN
574 << ").\n";
575 m_listen = true;
576 ::pthread_mutex_unlock(&m_socket_mutex);
577}
578
579// Getter
580// ------
581bool CSocket::is_listen() const {
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");
589 }
590 const auto listen{m_listen};
591 ::pthread_mutex_unlock(&m_socket_mutex);
592 return listen;
593}
594
595
596// Portable handling of socket errors
597// ==================================
598CSocketErr::CSocketErr() = default;
599
600CSocketErr::~CSocketErr() = default;
601
602CSocketErr::operator const int&() {
603 // TRACE not usable with chained output.
604 // TRACE2(this, " Executing CSocketErr::operator int&() (get socket error
605 // number)")
606 return m_errno;
607}
608
610#ifdef _MSC_VER
611 m_errno = umock::winsock2_h.WSAGetLastError();
612#else
613 m_errno = errno;
614#endif
615 TRACE2(this, " Executing CSocketErr::catch_error()")
616}
617
618std::string CSocketErr::error_str() const {
619 // TRACE not usable with chained output, e.g.
620 // std::cerr << "Error: " << sockerrObj.error_str();
621 // TRACE2(this, " Executing CSocketErr::error_str()")
622
623 // Portable C++ statement
624 return std::system_category().message(m_errno);
625 // return std::generic_category().message(m_errno);
626 // return std::strerror(m_errno); // Alternative for Unix platforms
627}
628
629} // 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:89
const std::string & what() const
Get cached error message.
Definition addrinfo.cpp:226
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:609
std::string error_str() const
Get human readable error description of the catched error.
Definition socket.cpp:618
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:358
CSocket_basic()
Default constructor for an empty basic socket object with invalid socket file descriptor.
Definition socket.cpp:178
bool local_saddr(SSockaddr *a_saddr=nullptr) const
Get the local socket address the socket is bound to.
Definition socket.cpp:231
void load()
Load the raw socket file descriptor specified with the constructor into the object.
Definition socket.cpp:196
bool remote_saddr(SSockaddr *a_saddr=nullptr) const
Get the remote socket address the socket is connected to.
Definition socket.cpp:287
bool is_reuse_addr() const
Get status if reusing address is enabled.
Definition socket.cpp:379
int socktype() const
Get the socket type.
Definition socket.cpp:337
Manage all aspects of a network socket.
Definition socket.hpp:320
void listen()
Set socket to listen.
Definition socket.cpp:552
CSocket()
Default constructor for an empty socket object.
Definition socket.cpp:404
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:464
virtual ~CSocket()
Destructor.
Definition socket.cpp:429
bool is_listen() const
Get status if the socket is listen to incomming network packets.
Definition socket.cpp:581
CSocket & operator=(CSocket)
Assignment operator.
Definition socket.cpp:419
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(sa_family_t a_pf_family, 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:94
sockaddr_in & sin
Reference to sockaddr_in struct.
Definition sockaddr.hpp:102
const std::string netaddrp() noexcept
Get the assosiated netaddress with port.
Definition sockaddr.cpp:519
sockaddr_in6 & sin6
Reference to sockaddr_in6 struct.
Definition sockaddr.hpp:100
sockaddr & sa
Reference to sockaddr struct.
Definition sockaddr.hpp:104
sockaddr_storage & ss
Reference to sockaddr_storage struct.
Definition sockaddr.hpp:96
socklen_t sizeof_saddr() const
Get sizeof the current filled (sin6 or sin) Sockaddr Structure.
Definition sockaddr.cpp:555