7# define _WIN32_WINNT 0x0601
9# ifndef WIN32_LEAN_AND_MEAN
10# define WIN32_LEAN_AND_MEAN
16#include "tcpserverbalancer.h"
19#include "serverengine.h"
21#include "tcpsslserver.h"
27#include <QLoggingCategory>
31# include <arpa/inet.h>
33# include <sys/socket.h>
34# include <sys/types.h>
38Q_LOGGING_CATEGORY(C_SERVER_BALANCER,
"cutelyst.server.tcpbalancer", QtWarningMsg)
54bool ensureWinsockInitialized(
QString *errorOut)
56 static std::once_flag once;
57 static int wsaInitError = 0;
58 std::call_once(once, [] {
60 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
61 wsaInitError = WSAGetLastError();
64 if (wsaInitError != 0) {
66 *errorOut = QStringLiteral(
"WSAStartup failed (Windows socket error %1)")
74QString windowsSocketErrorString(
int error)
78 return QStringLiteral(
"The bound address is already in use");
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");
87 return QStringLiteral(
"Windows socket error %1").arg(error);
91int listenExclusive(
const QHostAddress &address,
int listenQueue, quint16 port,
QString *errorOut)
93 if (!ensureWinsockInitialized(errorOut)) {
97 const bool ipv6 = address.
protocol() == QHostAddress::IPv6Protocol ||
98 address.
protocol() == QHostAddress::AnyIPProtocol;
101 WSASocketW(ipv6 ? AF_INET6 : AF_INET,
106 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
107 if (socket == INVALID_SOCKET) {
109 *errorOut = windowsSocketErrorString(WSAGetLastError());
114 BOOL exclusive = TRUE;
115 if (setsockopt(socket,
118 reinterpret_cast<const char *
>(&exclusive),
119 sizeof(exclusive)) != 0) {
121 *errorOut = windowsSocketErrorString(WSAGetLastError());
129 sa.sin6_family = AF_INET6;
130 sa.sin6_port = htons(port);
131 if (address.
protocol() == QHostAddress::AnyIPProtocol) {
132 sa.sin6_addr = in6addr_any;
135 memcpy(&sa.sin6_addr, &tmp,
sizeof(tmp));
137 if (bind(socket,
reinterpret_cast<sockaddr *
>(&sa),
sizeof(sa)) != 0) {
139 *errorOut = windowsSocketErrorString(WSAGetLastError());
146 sa.sin_family = AF_INET;
147 sa.sin_port = htons(port);
149 sa.sin_addr.s_addr = INADDR_ANY;
153 if (bind(socket,
reinterpret_cast<sockaddr *
>(&sa),
sizeof(sa)) != 0) {
155 *errorOut = windowsSocketErrorString(WSAGetLastError());
162 if (::listen(socket, listenQueue) != 0) {
164 *errorOut = windowsSocketErrorString(WSAGetLastError());
170 return static_cast<int>(socket);
175TcpServerBalancer::TcpServerBalancer(
Server *server)
181TcpServerBalancer::~TcpServerBalancer()
184 delete m_sslConfiguration;
188bool TcpServerBalancer::listen(
const QString &line,
Protocol *protocol,
bool secure)
190 m_protocol = protocol;
192 int commaPos = line.
indexOf(u
',');
193 const QString addressPortString = line.
mid(0, commaPos);
196 int closeBracketPos = addressPortString.
indexOf(u
']');
197 if (closeBracketPos != -1) {
199 std::cerr <<
"Failed to parse address: " << qPrintable(addressPortString) <<
'\n';
202 addressString = addressPortString.
mid(1, closeBracketPos - 1);
204 addressString = addressPortString.
section(u
':', 0, -2);
216 quint16 port = portString.
toUInt(&ok);
217 if (!ok || (port < 1 || port > 35554)) {
223 if (commaPos == -1) {
224 std::cerr <<
"No SSL certificate specified" <<
'\n';
228 const QString sslString = line.
mid(commaPos + 1);
230 QFile certFile(certPath);
232 std::cerr <<
"Failed to open SSL certificate" << qPrintable(certPath)
233 << qPrintable(certFile.errorString()) <<
'\n';
238 std::cerr <<
"Failed to parse SSL certificate" <<
'\n';
243 QFile keyFile(keyPath);
245 std::cerr <<
"Failed to open SSL private key" << qPrintable(keyPath)
246 << qPrintable(keyFile.errorString()) <<
'\n';
258 std::cerr <<
"Failed to select SSL Key Algorithm" << qPrintable(keyAlgorithm)
264 QSslKey key(&keyFile, algorithm);
266 std::cerr <<
"Failed to parse SSL private key" <<
'\n';
275 if (m_server->httpsH2()) {
277 {QByteArrayLiteral(
"h2"), QSslConfiguration::NextProtocolHttp1_1});
287 int socket = listenReuse(
288 address, m_server->listenQueue(), port, m_server->reusePort(), !m_server->reusePort());
295 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
299 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
303#elif defined(Q_OS_WIN)
304 int socket = listenExclusive(address, m_server->listenQueue(), port, &m_bindError);
313 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
317 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
327 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
328 << qPrintable(m_bindError) <<
'\n';
340inline int qt_safe_socket(
int domain,
int type,
int protocol,
int flags = 0)
342 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
345# ifdef QT_THREADSAFE_CLOEXEC
346 int newtype = type | SOCK_CLOEXEC;
347 if (flags & O_NONBLOCK) {
348 newtype |= SOCK_NONBLOCK;
350 fd = ::socket(domain, newtype, protocol);
353 fd = ::socket(domain, type, protocol);
358 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
361 if (flags & O_NONBLOCK) {
362 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
377 int type = SOCK_STREAM;
379 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
382 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
389 case EPROTONOSUPPORT:
392 qCDebug(C_SERVER_BALANCER)
393 <<
"setError(QAbstractSocket::UnsupportedSocketOperationError, "
394 "ProtocolUnsupportedErrorString)";
400 qCDebug(C_SERVER_BALANCER)
401 <<
"setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
404 qCDebug(C_SERVER_BALANCER)
405 <<
"setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
411# if defined(QNATIVESOCKETENGINE_DEBUG)
412 qCDebug(C_SERVER_BALANCER,
413 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
422# if defined(QNATIVESOCKETENGINE_DEBUG)
423 qCDebug(C_SERVER_BALANCER,
424 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
438# define QT_SOCKLEN_T int
439# define QT_SOCKET_BIND ::bind
443void set(T *sa,
typename std::enable_if<(&T::sa_len,
true), QT_SOCKLEN_T>::type len)
448void set(T *sin6,
typename std::enable_if<(&T::sin6_len,
true), QT_SOCKLEN_T>::type len)
450 sin6->sin6_len = len;
458void setPortAndAddress(quint16 port,
468 memset(&aa->a6, 0,
sizeof(sockaddr_in6));
469 aa->a6.sin6_family = AF_INET6;
473 aa->a6.sin6_port = htons(port);
475 memcpy(&aa->a6.sin6_addr, &tmp,
sizeof(tmp));
476 *sockAddrSize =
sizeof(sockaddr_in6);
477 SetSALen::set(&aa->a,
sizeof(sockaddr_in6));
479 memset(&aa->a, 0,
sizeof(sockaddr_in));
480 aa->a4.sin_family = AF_INET;
481 aa->a4.sin_port = htons(port);
483 *sockAddrSize =
sizeof(sockaddr_in);
484 SetSALen::set(&aa->a,
sizeof(sockaddr_in));
488bool nativeBind(
int socketDescriptor,
const QHostAddress &address, quint16 port)
492 setPortAndAddress(port, address, address.
protocol(), &aa, &sockAddrSize);
495 if (aa.a.sa_family == AF_INET6) {
503 socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (
char *) &ipv6only,
sizeof(ipv6only));
507 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
508 if (bindResult < 0 && errno == EAFNOSUPPORT &&
511 aa.a4.sin_family = AF_INET;
512 aa.a4.sin_port = htons(port);
514 sockAddrSize =
sizeof(aa.a4);
515 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
518 if (bindResult < 0) {
519# if defined(QNATIVESOCKETENGINE_DEBUG)
539# if defined(QNATIVESOCKETENGINE_DEBUG)
540 qCDebug(C_SERVER_BALANCER,
541 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
550# if defined(QNATIVESOCKETENGINE_DEBUG)
551 qCDebug(C_SERVER_BALANCER,
552 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
568 int socket = createNewSocket(proto);
570 qCCritical(C_SERVER_BALANCER) <<
"Failed to create new socket";
577 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval))) {
578 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEADDR on socket" << socket;
583 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval,
sizeof(optval))) {
584 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEPORT on socket" << socket;
589 if (!nativeBind(socket, address, port)) {
590 qCCritical(C_SERVER_BALANCER) <<
"Failed to bind to socket" << socket;
594 if (startListening && ::listen(socket, listenQueue) < 0) {
595 qCCritical(C_SERVER_BALANCER) <<
"Failed to listen to socket" << socket;
604void TcpServerBalancer::setBalancer(
bool enable)
609void TcpServerBalancer::incomingConnection(qintptr handle)
611 TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());
613 Q_EMIT serverIdle->createConnection(handle);
619 if (m_sslConfiguration) {
621 auto sslServer =
new TcpSslServer(m_serverName, m_protocol, m_server, engine);
622 sslServer->setSslConfiguration(*m_sslConfiguration);
626 server =
new TcpServer(m_serverName, m_protocol, m_server, engine);
628 connect(engine, &ServerEngine::shutdown, server, &TcpServer::shutdown);
631 connect(engine, &ServerEngine::started,
this, [
this, server]() {
632 m_servers.push_back(server);
636 &TcpServer::createConnection,
638 &TcpServer::incomingConnection,
643 if (m_server->reusePort()) {
644 connect(engine, &ServerEngine::started,
this, [
this, server]() {
645 int socket = listenReuse(
646 m_address, m_server->listenQueue(), m_port, m_server->reusePort(),
true);
648 qFatal(
"Failed to set server socket descriptor, reuse-port");
658 &ServerEngine::started,
663 qFatal(
"Failed to set server socket descriptor");
670#include "moc_tcpserverbalancer.cpp"
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
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
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
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
QString errorString() const const
bool listen(const QHostAddress &address, quint16 port)
QHostAddress serverAddress() const const
void setListenBacklogSize(int size)
bool setSocketDescriptor(qintptr socketDescriptor)
qintptr socketDescriptor() const const