5#include "tcpserverbalancer.h"
8#include "serverengine.h"
10#include "tcpsslserver.h"
15#include <QLoggingCategory>
19# include <arpa/inet.h>
21# include <sys/socket.h>
22# include <sys/types.h>
25Q_LOGGING_CATEGORY(C_SERVER_BALANCER,
"cutelyst.server.tcpbalancer", QtWarningMsg)
37TcpServerBalancer::TcpServerBalancer(
Server *wsgi)
43TcpServerBalancer::~TcpServerBalancer()
46 delete m_sslConfiguration;
50bool TcpServerBalancer::listen(
const QString &line,
Protocol *protocol,
bool secure)
52 m_protocol = protocol;
55 const QString addressPortString = line.
mid(0, commaPos);
59 if (closeBracketPos != -1) {
61 std::cerr <<
"Failed to parse address: " << qPrintable(addressPortString) << std::endl;
64 addressString = addressPortString.
mid(1, closeBracketPos - 1);
78 quint16 port = portString.
toUInt(&ok);
79 if (!ok || (port < 1 || port > 35554)) {
86 std::cerr <<
"No SSL certificate specified" << std::endl;
90 const QString sslString = line.
mid(commaPos + 1);
92 QFile certFile(certPath);
94 std::cerr <<
"Failed to open SSL certificate" << qPrintable(certPath)
95 << qPrintable(certFile.errorString()) << std::endl;
100 std::cerr <<
"Failed to parse SSL certificate" << std::endl;
105 QFile keyFile(keyPath);
107 std::cerr <<
"Failed to open SSL private key" << qPrintable(keyPath)
108 << qPrintable(keyFile.errorString()) << std::endl;
120 std::cerr <<
"Failed to select SSL Key Algorithm" << qPrintable(keyAlgorithm)
126 QSslKey key(&keyFile, algorithm);
128 std::cerr <<
"Failed to parse SSL private key" << std::endl;
137 if (m_wsgi->httpsH2()) {
139 {QByteArrayLiteral(
"h2"), QSslConfiguration::NextProtocolHttp1_1});
148 int socket = listenReuse(
149 address, m_wsgi->listenQueue(), port, m_wsgi->reusePort(), !m_wsgi->reusePort());
153 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
162 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
174static inline int qt_safe_socket(
int domain,
int type,
int protocol,
int flags = 0)
176 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
179# ifdef QT_THREADSAFE_CLOEXEC
180 int newtype = type | SOCK_CLOEXEC;
181 if (flags & O_NONBLOCK)
182 newtype |= SOCK_NONBLOCK;
183 fd = ::socket(domain, newtype, protocol);
186 fd = ::socket(domain, type, protocol);
190 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
193 if (flags & O_NONBLOCK)
194 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
208 int type = SOCK_STREAM;
210 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
213 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
220 case EPROTONOSUPPORT:
223 qCDebug(C_SERVER_BALANCER)
224 <<
"setError(QAbstractSocket::UnsupportedSocketOperationError, "
225 "ProtocolUnsupportedErrorString)";
231 qCDebug(C_SERVER_BALANCER)
232 <<
"setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
235 qCDebug(C_SERVER_BALANCER)
236 <<
"setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
242# if defined(QNATIVESOCKETENGINE_DEBUG)
243 qCDebug(C_SERVER_BALANCER,
244 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
253# if defined(QNATIVESOCKETENGINE_DEBUG)
254 qCDebug(C_SERVER_BALANCER,
255 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
269# define QT_SOCKLEN_T int
270# define QT_SOCKET_BIND ::bind
275void set(T *sa,
typename std::enable_if<(&T::sa_len,
true), QT_SOCKLEN_T>::type len)
280void set(T *sin6,
typename std::enable_if<(&T::sin6_len,
true), QT_SOCKLEN_T>::type len)
282 sin6->sin6_len = len;
291void setPortAndAddress(quint16 port,
301 memset(&aa->a6, 0,
sizeof(sockaddr_in6));
302 aa->a6.sin6_family = AF_INET6;
306 aa->a6.sin6_port = htons(port);
308 memcpy(&aa->a6.sin6_addr, &tmp,
sizeof(tmp));
309 *sockAddrSize =
sizeof(sockaddr_in6);
310 SetSALen::set(&aa->a,
sizeof(sockaddr_in6));
312 memset(&aa->a, 0,
sizeof(sockaddr_in));
313 aa->a4.sin_family = AF_INET;
314 aa->a4.sin_port = htons(port);
316 *sockAddrSize =
sizeof(sockaddr_in);
317 SetSALen::set(&aa->a,
sizeof(sockaddr_in));
321bool nativeBind(
int socketDescriptor,
const QHostAddress &address, quint16 port)
325 setPortAndAddress(port, address, address.
protocol(), &aa, &sockAddrSize);
328 if (aa.a.sa_family == AF_INET6) {
335 socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (
char *) &ipv6only,
sizeof(ipv6only));
339 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
340 if (bindResult < 0 && errno == EAFNOSUPPORT &&
343 aa.a4.sin_family = AF_INET;
344 aa.a4.sin_port = htons(port);
346 sockAddrSize =
sizeof(aa.a4);
347 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
350 if (bindResult < 0) {
351# if defined(QNATIVESOCKETENGINE_DEBUG)
371# if defined(QNATIVESOCKETENGINE_DEBUG)
372 qCDebug(C_SERVER_BALANCER,
373 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
382# if defined(QNATIVESOCKETENGINE_DEBUG)
383 qCDebug(C_SERVER_BALANCER,
384 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
400 int socket = createNewSocket(proto);
402 qCCritical(C_SERVER_BALANCER) <<
"Failed to create new socket";
409 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval))) {
410 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEADDR on socket" << socket;
415 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval,
sizeof(optval))) {
416 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEPORT on socket" << socket;
421 if (!nativeBind(socket, address, port)) {
422 qCCritical(C_SERVER_BALANCER) <<
"Failed to bind to socket" << socket;
426 if (startListening && ::listen(socket, listenQueue) < 0) {
427 qCCritical(C_SERVER_BALANCER) <<
"Failed to listen to socket" << socket;
435void TcpServerBalancer::setBalancer(
bool enable)
440void TcpServerBalancer::incomingConnection(qintptr handle)
442 TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());
444 Q_EMIT serverIdle->createConnection(handle);
450 if (m_sslConfiguration) {
452 auto sslServer =
new TcpSslServer(m_serverName, m_protocol, m_wsgi, engine);
453 sslServer->setSslConfiguration(*m_sslConfiguration);
457 server =
new TcpServer(m_serverName, m_protocol, m_wsgi, engine);
459 connect(engine, &ServerEngine::shutdown, server, &TcpServer::shutdown);
462 connect(engine, &ServerEngine::started,
this, [
this, server]() {
463 m_servers.push_back(server);
467 &TcpServer::createConnection,
469 &TcpServer::incomingConnection,
474 if (m_wsgi->reusePort()) {
475 connect(engine, &ServerEngine::started,
this, [
this, server]() {
476 int socket = listenReuse(
477 m_address, m_wsgi->listenQueue(), m_port, m_wsgi->reusePort(),
true);
479 qFatal(
"Failed to set server socket descriptor, reuse-port");
489 &ServerEngine::started,
494 qFatal(
"Failed to set server socket descriptor");
501#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)
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
bool setSocketDescriptor(qintptr socketDescriptor)
qintptr socketDescriptor() const const