cutelyst 5.1.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
tcpserverbalancer.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2017-2018 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#if defined(_WIN32)
6# ifndef _WIN32_WINNT
7# define _WIN32_WINNT 0x0601
8# endif
9# ifndef WIN32_LEAN_AND_MEAN
10# define WIN32_LEAN_AND_MEAN
11# endif
12# include <winsock2.h>
13# include <ws2tcpip.h>
14#endif
15
16#include "tcpserverbalancer.h"
17
18#include "server.h"
19#include "serverengine.h"
20#include "tcpserver.h"
21#include "tcpsslserver.h"
22
23#include <iostream>
24#include <mutex>
25
26#include <QFile>
27#include <QLoggingCategory>
28#include <QSslKey>
29
30#ifdef Q_OS_LINUX
31# include <arpa/inet.h>
32# include <fcntl.h>
33# include <sys/socket.h>
34# include <sys/types.h>
35# include <unistd.h>
36#endif
37
38Q_LOGGING_CATEGORY(C_SERVER_BALANCER, "cutelyst.server.tcpbalancer", QtWarningMsg)
39
40using namespace Cutelyst;
41
42#ifdef Q_OS_LINUX
43namespace {
44int listenReuse(const QHostAddress &address,
45 int listenQueue,
46 quint16 port,
47 bool reusePort,
48 bool startListening);
49}
50#endif
51
52#ifdef Q_OS_WIN
53namespace {
54bool ensureWinsockInitialized(QString *errorOut)
55{
56 static std::once_flag once;
57 static int wsaInitError = 0;
58 std::call_once(once, [] {
59 WSADATA wsaData;
60 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
61 wsaInitError = WSAGetLastError();
62 }
63 });
64 if (wsaInitError != 0) {
65 if (errorOut) {
66 *errorOut = QStringLiteral("WSAStartup failed (Windows socket error %1)")
67 .arg(wsaInitError);
68 }
69 return false;
70 }
71 return true;
72}
73
74QString windowsSocketErrorString(int error)
75{
76 switch (error) {
77 case WSAEADDRINUSE:
78 return QStringLiteral("The bound address is already in use");
79 case WSAEACCES:
80 return QStringLiteral("The requested address is a protected address and requires "
81 "appropriate privileges");
82 case WSAEADDRNOTAVAIL:
83 return QStringLiteral("The requested address is not valid in this context");
84 case WSANOTINITIALISED:
85 return QStringLiteral("Winsock has not been initialized");
86 default:
87 return QStringLiteral("Windows socket error %1").arg(error);
88 }
89}
90
91int listenExclusive(const QHostAddress &address, int listenQueue, quint16 port, QString *errorOut)
92{
93 if (!ensureWinsockInitialized(errorOut)) {
94 return -1;
95 }
96
97 const bool dualStackAny = address == QHostAddress::Any ||
98 address.protocol() == QHostAddress::AnyIPProtocol;
99 const bool ipv6 = address.protocol() == QHostAddress::IPv6Protocol || dualStackAny;
100
101 SOCKET socket =
102 WSASocketW(ipv6 ? AF_INET6 : AF_INET,
103 SOCK_STREAM,
104 IPPROTO_TCP,
105 nullptr,
106 0,
107 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
108 if (socket == INVALID_SOCKET) {
109 if (errorOut) {
110 *errorOut = windowsSocketErrorString(WSAGetLastError());
111 }
112 return -1;
113 }
114
115 BOOL exclusive = TRUE;
116 if (setsockopt(socket,
117 SOL_SOCKET,
118 SO_EXCLUSIVEADDRUSE,
119 reinterpret_cast<const char *>(&exclusive),
120 sizeof(exclusive)) != 0) {
121 if (errorOut) {
122 *errorOut = windowsSocketErrorString(WSAGetLastError());
123 }
124 closesocket(socket);
125 return -1;
126 }
127
128 if (ipv6) {
129 sockaddr_in6 sa{};
130 sa.sin6_family = AF_INET6;
131 sa.sin6_port = htons(port);
132 if (dualStackAny) {
133 sa.sin6_addr = in6addr_any;
134 const int v6only = 0;
135 setsockopt(socket,
136 IPPROTO_IPV6,
137 IPV6_V6ONLY,
138 reinterpret_cast<const char *>(&v6only),
139 sizeof(v6only));
140 } else {
141 const Q_IPV6ADDR tmp = address.toIPv6Address();
142 memcpy(&sa.sin6_addr, &tmp, sizeof(tmp));
143 }
144 if (bind(socket, reinterpret_cast<sockaddr *>(&sa), sizeof(sa)) != 0) {
145 if (errorOut) {
146 *errorOut = windowsSocketErrorString(WSAGetLastError());
147 }
148 closesocket(socket);
149 return -1;
150 }
151 } else {
152 sockaddr_in sa{};
153 sa.sin_family = AF_INET;
154 sa.sin_port = htons(port);
155 if (address.protocol() == QHostAddress::Any) {
156 sa.sin_addr.s_addr = INADDR_ANY;
157 } else {
158 sa.sin_addr.s_addr = htonl(address.toIPv4Address());
159 }
160 if (bind(socket, reinterpret_cast<sockaddr *>(&sa), sizeof(sa)) != 0) {
161 if (errorOut) {
162 *errorOut = windowsSocketErrorString(WSAGetLastError());
163 }
164 closesocket(socket);
165 return -1;
166 }
167 }
168
169 if (::listen(socket, listenQueue) != 0) {
170 if (errorOut) {
171 *errorOut = windowsSocketErrorString(WSAGetLastError());
172 }
173 closesocket(socket);
174 return -1;
175 }
176
177 return static_cast<int>(socket);
178}
179} // namespace
180#endif
181
182TcpServerBalancer::TcpServerBalancer(Server *server)
183 : QTcpServer(server)
184 , m_server(server)
185{
186}
187
188TcpServerBalancer::~TcpServerBalancer()
189{
190#ifndef QT_NO_SSL
191 delete m_sslConfiguration;
192#endif // QT_NO_SSL
193}
194
195bool TcpServerBalancer::listen(const QString &line, Protocol *protocol, bool secure)
196{
197 m_protocol = protocol;
198
199 int commaPos = line.indexOf(u',');
200 const QString addressPortString = line.mid(0, commaPos);
201
202 QString addressString;
203 int closeBracketPos = addressPortString.indexOf(u']');
204 if (closeBracketPos != -1) {
205 if (!line.startsWith(u'[')) {
206 std::cerr << "Failed to parse address: " << qPrintable(addressPortString) << '\n';
207 return false;
208 }
209 addressString = addressPortString.mid(1, closeBracketPos - 1);
210 } else {
211 addressString = addressPortString.section(u':', 0, -2);
212 }
213 const QString portString = addressPortString.section(u':', -1);
214
215 QHostAddress address;
216 if (addressString.isEmpty()) {
218 } else {
219 address.setAddress(addressString);
220 }
221
222 bool ok;
223 quint16 port = portString.toUInt(&ok);
224 if (!ok || (port < 1 || port > 35554)) {
225 port = 80;
226 }
227
228#ifndef QT_NO_SSL
229 if (secure) {
230 if (commaPos == -1) {
231 std::cerr << "No SSL certificate specified" << '\n';
232 return false;
233 }
234
235 const QString sslString = line.mid(commaPos + 1);
236 const QString certPath = sslString.section(u',', 0, 0);
237 QFile certFile(certPath);
238 if (!certFile.open(QFile::ReadOnly)) {
239 std::cerr << "Failed to open SSL certificate" << qPrintable(certPath)
240 << qPrintable(certFile.errorString()) << '\n';
241 return false;
242 }
243 QSslCertificate cert(&certFile);
244 if (cert.isNull()) {
245 std::cerr << "Failed to parse SSL certificate" << '\n';
246 return false;
247 }
248
249 const QString keyPath = sslString.section(u',', 1, 1);
250 QFile keyFile(keyPath);
251 if (!keyFile.open(QFile::ReadOnly)) {
252 std::cerr << "Failed to open SSL private key" << qPrintable(keyPath)
253 << qPrintable(keyFile.errorString()) << '\n';
254 return false;
255 }
256
257 QSsl::KeyAlgorithm algorithm = QSsl::Rsa;
258 const QString keyAlgorithm = sslString.section(u',', 2, 2);
259 if (!keyAlgorithm.isEmpty()) {
260 if (keyAlgorithm.compare(u"rsa", Qt::CaseInsensitive) == 0) {
261 algorithm = QSsl::Rsa;
262 } else if (keyAlgorithm.compare(u"ec", Qt::CaseInsensitive) == 0) {
263 algorithm = QSsl::Ec;
264 } else {
265 std::cerr << "Failed to select SSL Key Algorithm" << qPrintable(keyAlgorithm)
266 << '\n';
267 return false;
268 }
269 }
270
271 QSslKey key(&keyFile, algorithm);
272 if (key.isNull()) {
273 std::cerr << "Failed to parse SSL private key" << '\n';
274 return false;
275 }
276
277 m_sslConfiguration = new QSslConfiguration;
278 m_sslConfiguration->setLocalCertificate(cert);
279 m_sslConfiguration->setPrivateKey(key);
280 m_sslConfiguration->setPeerVerifyMode(
281 QSslSocket::VerifyNone); // prevent asking for client certificate
282 if (m_server->httpsH2()) {
283 m_sslConfiguration->setAllowedNextProtocols(
284 {QByteArrayLiteral("h2"), QSslConfiguration::NextProtocolHttp1_1});
285 }
286 }
287#endif // QT_NO_SSL
288
289 m_address = address;
290 m_port = port;
291 m_bindError.clear();
292
293#ifdef Q_OS_LINUX
294 int socket = listenReuse(
295 address, m_server->listenQueue(), port, m_server->reusePort(), !m_server->reusePort());
296 if (socket > 0) {
297 if (setSocketDescriptor(socket)) {
299 } else {
300 m_bindError = errorString();
301 ::close(socket);
302 qCWarning(C_SERVER_BALANCER) << "Failed to listen on TCP:" << line << m_bindError;
303 return false;
304 }
305 } else {
306 std::cerr << "Failed to listen on TCP: " << qPrintable(line) << " : "
307 << qPrintable(errorString()) << '\n';
308 return false;
309 }
310#elif defined(Q_OS_WIN)
311 int socket = listenExclusive(address, m_server->listenQueue(), port, &m_bindError);
312 if (socket > 0) {
313 if (setSocketDescriptor(socket)) {
315 } else {
316 if (m_bindError.isEmpty()) {
317 m_bindError = errorString();
318 }
319 closesocket(socket);
320 qCWarning(C_SERVER_BALANCER) << "Failed to listen on TCP:" << line << m_bindError;
321 return false;
322 }
323 } else {
324 qCWarning(C_SERVER_BALANCER) << "Failed to listen on TCP:" << line << m_bindError;
325 return false;
326 }
327#else
328 setListenBacklogSize(m_server->listenQueue());
329 bool ret = QTcpServer::listen(address, port);
330 if (ret) {
332 } else {
333 m_bindError = errorString();
334 std::cerr << "Failed to listen on TCP: " << qPrintable(line) << " : "
335 << qPrintable(m_bindError) << '\n';
336 return false;
337 }
338#endif
339
340 m_serverName = serverAddress().toString().toLatin1() + ':' + QByteArray::number(port);
341 return true;
342}
343
344namespace {
345#ifdef Q_OS_LINUX
346// UnixWare 7 redefines socket -> _socket
347inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
348{
349 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
350
351 int fd;
352# ifdef QT_THREADSAFE_CLOEXEC
353 int newtype = type | SOCK_CLOEXEC;
354 if (flags & O_NONBLOCK) {
355 newtype |= SOCK_NONBLOCK;
356 }
357 fd = ::socket(domain, newtype, protocol);
358 return fd;
359# else
360 fd = ::socket(domain, type, protocol);
361 if (fd == -1) {
362 return -1;
363 }
364
365 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
366
367 // set non-block too?
368 if (flags & O_NONBLOCK) {
369 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
370 }
371
372 return fd;
373# endif
374}
375
376int createNewSocket(QAbstractSocket::NetworkLayerProtocol &socketProtocol)
377{
378 int protocol = 0;
379
380 int domain = (socketProtocol == QAbstractSocket::IPv6Protocol ||
381 socketProtocol == QAbstractSocket::AnyIPProtocol)
382 ? AF_INET6
383 : AF_INET;
384 int type = SOCK_STREAM;
385
386 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
387 if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
388 domain = AF_INET;
389 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
390 socketProtocol = QAbstractSocket::IPv4Protocol;
391 }
392
393 if (socket < 0) {
394 int ecopy = errno;
395 switch (ecopy) {
396 case EPROTONOSUPPORT:
397 case EAFNOSUPPORT:
398 case EINVAL:
399 qCDebug(C_SERVER_BALANCER)
400 << "setError(QAbstractSocket::UnsupportedSocketOperationError, "
401 "ProtocolUnsupportedErrorString)";
402 break;
403 case ENFILE:
404 case EMFILE:
405 case ENOBUFS:
406 case ENOMEM:
407 qCDebug(C_SERVER_BALANCER)
408 << "setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
409 break;
410 case EACCES:
411 qCDebug(C_SERVER_BALANCER)
412 << "setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
413 break;
414 default:
415 break;
416 }
417
418# if defined(QNATIVESOCKETENGINE_DEBUG)
419 qCDebug(C_SERVER_BALANCER,
420 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
421 socketType,
422 socketProtocol,
423 strerror(ecopy));
424# endif
425
426 return false;
427 }
428
429# if defined(QNATIVESOCKETENGINE_DEBUG)
430 qCDebug(C_SERVER_BALANCER,
431 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
432 socketType,
433 socketProtocol);
434# endif
435
436 return socket;
437}
438
439union qt_sockaddr {
440 sockaddr a;
441 sockaddr_in a4;
442 sockaddr_in6 a6;
443};
444
445# define QT_SOCKLEN_T int
446# define QT_SOCKET_BIND ::bind
447
448namespace SetSALen {
449template <typename T>
450void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len)
451{
452 sa->sa_len = len;
453}
454template <typename T>
455void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len)
456{
457 sin6->sin6_len = len;
458}
459template <typename T>
460void set(T *, ...)
461{
462}
463} // namespace SetSALen
464
465void setPortAndAddress(quint16 port,
466 const QHostAddress &address,
468 qt_sockaddr *aa,
469 int *sockAddrSize)
470{
471 if (address.protocol() == QAbstractSocket::IPv6Protocol ||
473 socketProtocol == QAbstractSocket::IPv6Protocol ||
474 socketProtocol == QAbstractSocket::AnyIPProtocol) {
475 memset(&aa->a6, 0, sizeof(sockaddr_in6));
476 aa->a6.sin6_family = AF_INET6;
477 // #if QT_CONFIG(networkinterface)
478 // aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId());
479 // #endif
480 aa->a6.sin6_port = htons(port);
481 Q_IPV6ADDR tmp = address.toIPv6Address();
482 memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp));
483 *sockAddrSize = sizeof(sockaddr_in6);
484 SetSALen::set(&aa->a, sizeof(sockaddr_in6));
485 } else {
486 memset(&aa->a, 0, sizeof(sockaddr_in));
487 aa->a4.sin_family = AF_INET;
488 aa->a4.sin_port = htons(port);
489 aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address());
490 *sockAddrSize = sizeof(sockaddr_in);
491 SetSALen::set(&aa->a, sizeof(sockaddr_in));
492 }
493}
494
495bool nativeBind(int socketDescriptor, const QHostAddress &address, quint16 port)
496{
497 qt_sockaddr aa;
498 int sockAddrSize;
499 setPortAndAddress(port, address, address.protocol(), &aa, &sockAddrSize);
500
501# ifdef IPV6_V6ONLY
502 if (aa.a.sa_family == AF_INET6) {
503 int ipv6only = 0;
504 if (address.protocol() == QAbstractSocket::IPv6Protocol) {
505 ipv6only = 1;
506 }
507 // default value of this socket option varies depending on unix variant (or system
508 // configuration on BSD), so always set it explicitly
509 ::setsockopt(
510 socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &ipv6only, sizeof(ipv6only));
511 }
512# endif
513
514 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
515 if (bindResult < 0 && errno == EAFNOSUPPORT &&
517 // retry with v4
518 aa.a4.sin_family = AF_INET;
519 aa.a4.sin_port = htons(port);
520 aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
521 sockAddrSize = sizeof(aa.a4);
522 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
523 }
524
525 if (bindResult < 0) {
526# if defined(QNATIVESOCKETENGINE_DEBUG)
527 int ecopy = errno;
528# endif
529 // switch(errno) {
530 // case EADDRINUSE:
531 // setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
532 // break;
533 // case EACCES:
534 // setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
535 // break;
536 // case EINVAL:
537 // setError(QAbstractSocket::UnsupportedSocketOperationError,
538 // OperationUnsupportedErrorString); break;
539 // case EADDRNOTAVAIL:
540 // setError(QAbstractSocket::SocketAddressNotAvailableError,
541 // AddressNotAvailableErrorString); break;
542 // default:
543 // break;
544 // }
545
546# if defined(QNATIVESOCKETENGINE_DEBUG)
547 qCDebug(C_SERVER_BALANCER,
548 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
549 address.toString().toLatin1().constData(),
550 port,
551 strerror(ecopy));
552# endif
553
554 return false;
555 }
556
557# if defined(QNATIVESOCKETENGINE_DEBUG)
558 qCDebug(C_SERVER_BALANCER,
559 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
560 address.toString().toLatin1().constData(),
561 port);
562# endif
563 // socketState = QAbstractSocket::BoundState;
564 return true;
565}
566
567int listenReuse(const QHostAddress &address,
568 int listenQueue,
569 quint16 port,
570 bool reusePort,
571 bool startListening)
572{
574
575 int socket = createNewSocket(proto);
576 if (socket < 0) {
577 qCCritical(C_SERVER_BALANCER) << "Failed to create new socket";
578 return -1;
579 }
580
581 int optval = 1;
582 // SO_REUSEADDR is set by default on QTcpServer and allows to bind again
583 // without having to wait all previous connections to close
584 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) {
585 qCCritical(C_SERVER_BALANCER) << "Failed to set SO_REUSEADDR on socket" << socket;
586 return -1;
587 }
588
589 if (reusePort) {
590 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))) {
591 qCCritical(C_SERVER_BALANCER) << "Failed to set SO_REUSEPORT on socket" << socket;
592 return -1;
593 }
594 }
595
596 if (!nativeBind(socket, address, port)) {
597 qCCritical(C_SERVER_BALANCER) << "Failed to bind to socket" << socket;
598 return -1;
599 }
600
601 if (startListening && ::listen(socket, listenQueue) < 0) {
602 qCCritical(C_SERVER_BALANCER) << "Failed to listen to socket" << socket;
603 return -1;
604 }
605
606 return socket;
607}
608#endif // Q_OS_LINUX
609} // namespace
610
611void TcpServerBalancer::setBalancer(bool enable)
612{
613 m_balancer = enable;
614}
615
616void TcpServerBalancer::incomingConnection(qintptr handle)
617{
618 TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());
619
620 Q_EMIT serverIdle->createConnection(handle);
621}
622
623TcpServer *TcpServerBalancer::createServer(ServerEngine *engine)
624{
625 TcpServer *server;
626 if (m_sslConfiguration) {
627#ifndef QT_NO_SSL
628 auto sslServer = new TcpSslServer(m_serverName, m_protocol, m_server, engine);
629 sslServer->setSslConfiguration(*m_sslConfiguration);
630 server = sslServer;
631#endif // QT_NO_SSL
632 } else {
633 server = new TcpServer(m_serverName, m_protocol, m_server, engine);
634 }
635 connect(engine, &ServerEngine::shutdown, server, &TcpServer::shutdown);
636
637 if (m_balancer) {
638 connect(engine, &ServerEngine::started, this, [this, server]() {
639 m_servers.push_back(server);
642 connect(server,
643 &TcpServer::createConnection,
644 server,
645 &TcpServer::incomingConnection,
647 } else {
648
649#ifdef Q_OS_LINUX
650 if (m_server->reusePort()) {
651 connect(engine, &ServerEngine::started, this, [this, server]() {
652 int socket = listenReuse(
653 m_address, m_server->listenQueue(), m_port, m_server->reusePort(), true);
654 if (!server->setSocketDescriptor(socket)) {
655 qFatal("Failed to set server socket descriptor, reuse-port");
656 }
658 return server;
659 }
660#endif
661
662 if (server->setSocketDescriptor(socketDescriptor())) {
663 server->pauseAccepting();
664 connect(engine,
665 &ServerEngine::started,
666 server,
669 } else {
670 qFatal("Failed to set server socket descriptor");
671 }
672 }
673
674 return server;
675}
676
677#include "moc_tcpserverbalancer.cpp"
Implements a web server.
Definition server.h:60
The Cutelyst namespace holds all public Cutelyst API.
const char * constData() const const
QByteArray number(double n, char format, int precision)
int protocol() const const
bool setAddress(const QString &address)
quint32 toIPv4Address(bool *ok) const const
Q_IPV6ADDR toIPv6Address() const const
QString toString() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
KeyAlgorithm
void setAllowedNextProtocols(const QList< QByteArray > &protocols)
void setLocalCertificate(const QSslCertificate &certificate)
void setPeerVerifyMode(QSslSocket::PeerVerifyMode mode)
void setPrivateKey(const QSslKey &key)
QString arg(Args &&... args) const const
void clear()
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString section(QChar sep, qsizetype start, qsizetype end, QString::SectionFlags flags) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
uint toUInt(bool *ok, int base) const const
CaseInsensitive
QueuedConnection
void close()
QString errorString() const const
bool listen(const QHostAddress &address, quint16 port)
void pauseAccepting()
void resumeAccepting()
QHostAddress serverAddress() const const
void setListenBacklogSize(int size)
bool setSocketDescriptor(qintptr socketDescriptor)
qintptr socketDescriptor() const const