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)) {
98 address.
protocol() == QHostAddress::AnyIPProtocol;
99 const bool ipv6 = address.
protocol() == QHostAddress::IPv6Protocol || dualStackAny;
102 WSASocketW(ipv6 ? AF_INET6 : AF_INET,
107 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
108 if (socket == INVALID_SOCKET) {
110 *errorOut = windowsSocketErrorString(WSAGetLastError());
115 BOOL exclusive = TRUE;
116 if (setsockopt(socket,
119 reinterpret_cast<const char *
>(&exclusive),
120 sizeof(exclusive)) != 0) {
122 *errorOut = windowsSocketErrorString(WSAGetLastError());
130 sa.sin6_family = AF_INET6;
131 sa.sin6_port = htons(port);
133 sa.sin6_addr = in6addr_any;
134 const int v6only = 0;
138 reinterpret_cast<const char *
>(&v6only),
142 memcpy(&sa.sin6_addr, &tmp,
sizeof(tmp));
144 if (bind(socket,
reinterpret_cast<sockaddr *
>(&sa),
sizeof(sa)) != 0) {
146 *errorOut = windowsSocketErrorString(WSAGetLastError());
153 sa.sin_family = AF_INET;
154 sa.sin_port = htons(port);
156 sa.sin_addr.s_addr = INADDR_ANY;
160 if (bind(socket,
reinterpret_cast<sockaddr *
>(&sa),
sizeof(sa)) != 0) {
162 *errorOut = windowsSocketErrorString(WSAGetLastError());
169 if (::listen(socket, listenQueue) != 0) {
171 *errorOut = windowsSocketErrorString(WSAGetLastError());
177 return static_cast<int>(socket);
182TcpServerBalancer::TcpServerBalancer(
Server *server)
188TcpServerBalancer::~TcpServerBalancer()
191 delete m_sslConfiguration;
195bool TcpServerBalancer::listen(
const QString &line,
Protocol *protocol,
bool secure)
197 m_protocol = protocol;
199 int commaPos = line.
indexOf(u
',');
200 const QString addressPortString = line.
mid(0, commaPos);
203 int closeBracketPos = addressPortString.
indexOf(u
']');
204 if (closeBracketPos != -1) {
206 std::cerr <<
"Failed to parse address: " << qPrintable(addressPortString) <<
'\n';
209 addressString = addressPortString.
mid(1, closeBracketPos - 1);
211 addressString = addressPortString.
section(u
':', 0, -2);
223 quint16 port = portString.
toUInt(&ok);
224 if (!ok || (port < 1 || port > 35554)) {
230 if (commaPos == -1) {
231 std::cerr <<
"No SSL certificate specified" <<
'\n';
235 const QString sslString = line.
mid(commaPos + 1);
237 QFile certFile(certPath);
239 std::cerr <<
"Failed to open SSL certificate" << qPrintable(certPath)
240 << qPrintable(certFile.errorString()) <<
'\n';
245 std::cerr <<
"Failed to parse SSL certificate" <<
'\n';
250 QFile keyFile(keyPath);
252 std::cerr <<
"Failed to open SSL private key" << qPrintable(keyPath)
253 << qPrintable(keyFile.errorString()) <<
'\n';
265 std::cerr <<
"Failed to select SSL Key Algorithm" << qPrintable(keyAlgorithm)
271 QSslKey key(&keyFile, algorithm);
273 std::cerr <<
"Failed to parse SSL private key" <<
'\n';
282 if (m_server->httpsH2()) {
284 {QByteArrayLiteral(
"h2"), QSslConfiguration::NextProtocolHttp1_1});
294 int socket = listenReuse(
295 address, m_server->listenQueue(), port, m_server->reusePort(), !m_server->reusePort());
302 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
306 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
310#elif defined(Q_OS_WIN)
311 int socket = listenExclusive(address, m_server->listenQueue(), port, &m_bindError);
320 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
324 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
334 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
335 << qPrintable(m_bindError) <<
'\n';
347inline int qt_safe_socket(
int domain,
int type,
int protocol,
int flags = 0)
349 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
352# ifdef QT_THREADSAFE_CLOEXEC
353 int newtype = type | SOCK_CLOEXEC;
354 if (flags & O_NONBLOCK) {
355 newtype |= SOCK_NONBLOCK;
357 fd = ::socket(domain, newtype, protocol);
360 fd = ::socket(domain, type, protocol);
365 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
368 if (flags & O_NONBLOCK) {
369 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
384 int type = SOCK_STREAM;
386 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
389 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
396 case EPROTONOSUPPORT:
399 qCDebug(C_SERVER_BALANCER)
400 <<
"setError(QAbstractSocket::UnsupportedSocketOperationError, "
401 "ProtocolUnsupportedErrorString)";
407 qCDebug(C_SERVER_BALANCER)
408 <<
"setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
411 qCDebug(C_SERVER_BALANCER)
412 <<
"setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
418# if defined(QNATIVESOCKETENGINE_DEBUG)
419 qCDebug(C_SERVER_BALANCER,
420 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
429# if defined(QNATIVESOCKETENGINE_DEBUG)
430 qCDebug(C_SERVER_BALANCER,
431 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
445# define QT_SOCKLEN_T int
446# define QT_SOCKET_BIND ::bind
450void set(T *sa,
typename std::enable_if<(&T::sa_len,
true), QT_SOCKLEN_T>::type len)
455void set(T *sin6,
typename std::enable_if<(&T::sin6_len,
true), QT_SOCKLEN_T>::type len)
457 sin6->sin6_len = len;
465void setPortAndAddress(quint16 port,
475 memset(&aa->a6, 0,
sizeof(sockaddr_in6));
476 aa->a6.sin6_family = AF_INET6;
480 aa->a6.sin6_port = htons(port);
482 memcpy(&aa->a6.sin6_addr, &tmp,
sizeof(tmp));
483 *sockAddrSize =
sizeof(sockaddr_in6);
484 SetSALen::set(&aa->a,
sizeof(sockaddr_in6));
486 memset(&aa->a, 0,
sizeof(sockaddr_in));
487 aa->a4.sin_family = AF_INET;
488 aa->a4.sin_port = htons(port);
490 *sockAddrSize =
sizeof(sockaddr_in);
491 SetSALen::set(&aa->a,
sizeof(sockaddr_in));
495bool nativeBind(
int socketDescriptor,
const QHostAddress &address, quint16 port)
499 setPortAndAddress(port, address, address.
protocol(), &aa, &sockAddrSize);
502 if (aa.a.sa_family == AF_INET6) {
510 socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (
char *) &ipv6only,
sizeof(ipv6only));
514 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
515 if (bindResult < 0 && errno == EAFNOSUPPORT &&
518 aa.a4.sin_family = AF_INET;
519 aa.a4.sin_port = htons(port);
521 sockAddrSize =
sizeof(aa.a4);
522 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
525 if (bindResult < 0) {
526# if defined(QNATIVESOCKETENGINE_DEBUG)
546# if defined(QNATIVESOCKETENGINE_DEBUG)
547 qCDebug(C_SERVER_BALANCER,
548 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
557# if defined(QNATIVESOCKETENGINE_DEBUG)
558 qCDebug(C_SERVER_BALANCER,
559 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
575 int socket = createNewSocket(proto);
577 qCCritical(C_SERVER_BALANCER) <<
"Failed to create new socket";
584 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval))) {
585 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEADDR on socket" << socket;
590 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval,
sizeof(optval))) {
591 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEPORT on socket" << socket;
596 if (!nativeBind(socket, address, port)) {
597 qCCritical(C_SERVER_BALANCER) <<
"Failed to bind to socket" << socket;
601 if (startListening && ::listen(socket, listenQueue) < 0) {
602 qCCritical(C_SERVER_BALANCER) <<
"Failed to listen to socket" << socket;
611void TcpServerBalancer::setBalancer(
bool enable)
616void TcpServerBalancer::incomingConnection(qintptr handle)
618 TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());
620 Q_EMIT serverIdle->createConnection(handle);
626 if (m_sslConfiguration) {
628 auto sslServer =
new TcpSslServer(m_serverName, m_protocol, m_server, engine);
629 sslServer->setSslConfiguration(*m_sslConfiguration);
633 server =
new TcpServer(m_serverName, m_protocol, m_server, engine);
635 connect(engine, &ServerEngine::shutdown, server, &TcpServer::shutdown);
638 connect(engine, &ServerEngine::started,
this, [
this, server]() {
639 m_servers.push_back(server);
643 &TcpServer::createConnection,
645 &TcpServer::incomingConnection,
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);
655 qFatal(
"Failed to set server socket descriptor, reuse-port");
665 &ServerEngine::started,
670 qFatal(
"Failed to set server socket descriptor");
677#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