7# define _WIN32_WINNT 0x0601
9# ifndef WIN32_LEAN_AND_MEAN
10# define WIN32_LEAN_AND_MEAN
17#include "serverengine.h"
19#include "tcpserverbalancer.h"
20#include "tcpsslserver.h"
26#include <QLoggingCategory>
30# include <arpa/inet.h>
32# include <sys/socket.h>
33# include <sys/types.h>
37Q_LOGGING_CATEGORY(C_SERVER_BALANCER,
"cutelyst.server.tcpbalancer", QtWarningMsg)
53bool ensureWinsockInitialized(
QString *errorOut)
55 static std::once_flag once;
56 static int wsaInitError = 0;
57 std::call_once(once, [] {
59 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
60 wsaInitError = WSAGetLastError();
63 if (wsaInitError != 0) {
66 QStringLiteral(
"WSAStartup failed (Windows socket error %1)").
arg(wsaInitError);
73QString windowsSocketErrorString(
int error)
77 return QStringLiteral(
"The bound address is already in use");
79 return QStringLiteral(
"The requested address is a protected address and requires "
80 "appropriate privileges");
81 case WSAEADDRNOTAVAIL:
82 return QStringLiteral(
"The requested address is not valid in this context");
83 case WSANOTINITIALISED:
84 return QStringLiteral(
"Winsock has not been initialized");
86 return QStringLiteral(
"Windows socket error %1").arg(error);
90int listenExclusive(
const QHostAddress &address,
int listenQueue, quint16 port,
QString *errorOut)
92 if (!ensureWinsockInitialized(errorOut)) {
96 const bool dualStackAny =
98 const bool ipv6 = address.
protocol() == QHostAddress::IPv6Protocol || dualStackAny;
100 SOCKET socket = WSASocketW(ipv6 ? AF_INET6 : AF_INET,
105 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
106 if (socket == INVALID_SOCKET) {
108 *errorOut = windowsSocketErrorString(WSAGetLastError());
113 BOOL exclusive = TRUE;
114 if (setsockopt(socket,
117 reinterpret_cast<const char *
>(&exclusive),
118 sizeof(exclusive)) != 0) {
120 *errorOut = windowsSocketErrorString(WSAGetLastError());
128 sa.sin6_family = AF_INET6;
129 sa.sin6_port = htons(port);
131 sa.sin6_addr = in6addr_any;
132 const int v6only = 0;
136 reinterpret_cast<const char *
>(&v6only),
140 memcpy(&sa.sin6_addr, &tmp,
sizeof(tmp));
142 if (bind(socket,
reinterpret_cast<sockaddr *
>(&sa),
sizeof(sa)) != 0) {
144 *errorOut = windowsSocketErrorString(WSAGetLastError());
151 sa.sin_family = AF_INET;
152 sa.sin_port = htons(port);
154 sa.sin_addr.s_addr = INADDR_ANY;
158 if (bind(socket,
reinterpret_cast<sockaddr *
>(&sa),
sizeof(sa)) != 0) {
160 *errorOut = windowsSocketErrorString(WSAGetLastError());
167 if (::listen(socket, listenQueue) != 0) {
169 *errorOut = windowsSocketErrorString(WSAGetLastError());
175 return static_cast<int>(socket);
180TcpServerBalancer::TcpServerBalancer(
Server *server)
186TcpServerBalancer::~TcpServerBalancer()
189 delete m_sslConfiguration;
193bool TcpServerBalancer::listen(
const QString &line,
Protocol *protocol,
bool secure)
195 m_protocol = protocol;
197 int commaPos = line.
indexOf(u
',');
198 const QString addressPortString = line.
mid(0, commaPos);
200 QString addressString;
201 int closeBracketPos = addressPortString.
indexOf(u
']');
202 if (closeBracketPos != -1) {
204 std::cerr <<
"Failed to parse address: " << qPrintable(addressPortString) <<
'\n';
207 addressString = addressPortString.
mid(1, closeBracketPos - 1);
209 addressString = addressPortString.
section(u
':', 0, -2);
211 const QString portString = addressPortString.
section(u
':', -1);
213 QHostAddress address;
221 quint16 port = portString.
toUInt(&ok);
222 if (!ok || (port < 1 || port > 35554)) {
228 if (commaPos == -1) {
229 std::cerr <<
"No SSL certificate specified" <<
'\n';
233 const QString sslString = line.
mid(commaPos + 1);
234 const QString certPath = sslString.
section(u
',', 0, 0);
235 QFile certFile(certPath);
237 std::cerr <<
"Failed to open SSL certificate" << qPrintable(certPath)
238 << qPrintable(certFile.errorString()) <<
'\n';
241 QSslCertificate cert(&certFile);
243 std::cerr <<
"Failed to parse SSL certificate" <<
'\n';
247 const QString keyPath = sslString.
section(u
',', 1, 1);
248 QFile keyFile(keyPath);
250 std::cerr <<
"Failed to open SSL private key" << qPrintable(keyPath)
251 << qPrintable(keyFile.errorString()) <<
'\n';
256 const QString keyAlgorithm = sslString.
section(u
',', 2, 2);
263 std::cerr <<
"Failed to select SSL Key Algorithm" << qPrintable(keyAlgorithm)
269 QSslKey key(&keyFile, algorithm);
271 std::cerr <<
"Failed to parse SSL private key" <<
'\n';
275 m_sslConfiguration =
new QSslConfiguration;
276 m_sslConfiguration->setLocalCertificate(cert);
277 m_sslConfiguration->setPrivateKey(key);
278 m_sslConfiguration->setPeerVerifyMode(
280 if (m_server->httpsH2()) {
281 m_sslConfiguration->setAllowedNextProtocols(
282 {QByteArrayLiteral(
"h2"), QSslConfiguration::NextProtocolHttp1_1});
292 int socket = listenReuse(
293 address, m_server->listenQueue(), port, m_server->reusePort(), !m_server->reusePort());
300 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
304 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
308#elif defined(Q_OS_WIN)
309 int socket = listenExclusive(address, m_server->listenQueue(), port, &m_bindError);
314 if (m_bindError.isEmpty()) {
318 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
322 qCWarning(C_SERVER_BALANCER) <<
"Failed to listen on TCP:" << line << m_bindError;
332 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
333 << qPrintable(m_bindError) <<
'\n';
345inline int qt_safe_socket(
int domain,
int type,
int protocol,
int flags = 0)
347 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
350# ifdef QT_THREADSAFE_CLOEXEC
351 int newtype = type | SOCK_CLOEXEC;
352 if (flags & O_NONBLOCK) {
353 newtype |= SOCK_NONBLOCK;
355 fd = ::socket(domain, newtype, protocol);
358 fd = ::socket(domain, type, protocol);
363 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
366 if (flags & O_NONBLOCK) {
367 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
382 int type = SOCK_STREAM;
384 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
387 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
394 case EPROTONOSUPPORT:
397 qCDebug(C_SERVER_BALANCER)
398 <<
"setError(QAbstractSocket::UnsupportedSocketOperationError, "
399 "ProtocolUnsupportedErrorString)";
405 qCDebug(C_SERVER_BALANCER)
406 <<
"setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
409 qCDebug(C_SERVER_BALANCER)
410 <<
"setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
416# if defined(QNATIVESOCKETENGINE_DEBUG)
417 qCDebug(C_SERVER_BALANCER,
418 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
427# if defined(QNATIVESOCKETENGINE_DEBUG)
428 qCDebug(C_SERVER_BALANCER,
429 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
443# define QT_SOCKLEN_T int
444# define QT_SOCKET_BIND ::bind
448void set(T *sa,
typename std::enable_if<(&T::sa_len,
true), QT_SOCKLEN_T>::type len)
453void set(T *sin6,
typename std::enable_if<(&T::sin6_len,
true), QT_SOCKLEN_T>::type len)
455 sin6->sin6_len = len;
463void setPortAndAddress(quint16 port,
464 const QHostAddress &address,
473 memset(&aa->a6, 0,
sizeof(sockaddr_in6));
474 aa->a6.sin6_family = AF_INET6;
478 aa->a6.sin6_port = htons(port);
480 memcpy(&aa->a6.sin6_addr, &tmp,
sizeof(tmp));
481 *sockAddrSize =
sizeof(sockaddr_in6);
482 SetSALen::set(&aa->a,
sizeof(sockaddr_in6));
484 memset(&aa->a, 0,
sizeof(sockaddr_in));
485 aa->a4.sin_family = AF_INET;
486 aa->a4.sin_port = htons(port);
488 *sockAddrSize =
sizeof(sockaddr_in);
489 SetSALen::set(&aa->a,
sizeof(sockaddr_in));
493bool nativeBind(
int socketDescriptor,
const QHostAddress &address, quint16 port)
497 setPortAndAddress(port, address, address.
protocol(), &aa, &sockAddrSize);
500 if (aa.a.sa_family == AF_INET6) {
508 socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (
char *) &ipv6only,
sizeof(ipv6only));
512 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
513 if (bindResult < 0 && errno == EAFNOSUPPORT &&
516 aa.a4.sin_family = AF_INET;
517 aa.a4.sin_port = htons(port);
519 sockAddrSize =
sizeof(aa.a4);
520 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
523 if (bindResult < 0) {
524# if defined(QNATIVESOCKETENGINE_DEBUG)
544# if defined(QNATIVESOCKETENGINE_DEBUG)
545 qCDebug(C_SERVER_BALANCER,
546 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
555# if defined(QNATIVESOCKETENGINE_DEBUG)
556 qCDebug(C_SERVER_BALANCER,
557 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
565int listenReuse(
const QHostAddress &address,
573 int socket = createNewSocket(proto);
575 qCCritical(C_SERVER_BALANCER) <<
"Failed to create new socket";
582 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval))) {
583 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEADDR on socket" << socket;
588 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval,
sizeof(optval))) {
589 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEPORT on socket" << socket;
594 if (!nativeBind(socket, address, port)) {
595 qCCritical(C_SERVER_BALANCER) <<
"Failed to bind to socket" << socket;
599 if (startListening && ::listen(socket, listenQueue) < 0) {
600 qCCritical(C_SERVER_BALANCER) <<
"Failed to listen to socket" << socket;
609void TcpServerBalancer::setBalancer(
bool enable)
614void TcpServerBalancer::incomingConnection(qintptr handle)
616 TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());
618 Q_EMIT serverIdle->createConnection(handle);
624 if (m_sslConfiguration) {
626 auto sslServer =
new TcpSslServer(m_serverName, m_protocol, m_server, engine);
627 sslServer->setSslConfiguration(*m_sslConfiguration);
631 server =
new TcpServer(m_serverName, m_protocol, m_server, engine);
633 connect(engine, &ServerEngine::shutdown, server, &TcpServer::shutdown);
636 connect(engine, &ServerEngine::started,
this, [
this, server]() {
637 m_servers.push_back(server);
641 &TcpServer::createConnection,
643 &TcpServer::incomingConnection,
648 if (m_server->reusePort()) {
649 connect(engine, &ServerEngine::started,
this, [
this, server]() {
650 int socket = listenReuse(
651 m_address, m_server->listenQueue(), m_port, m_server->reusePort(),
true);
653 qFatal(
"Failed to set server socket descriptor, reuse-port");
663 &ServerEngine::started,
668 qFatal(
"Failed to set server socket descriptor");
675#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)
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) &&
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