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)
39TcpServerBalancer::TcpServerBalancer(
Server *server)
45TcpServerBalancer::~TcpServerBalancer()
48 delete m_sslConfiguration;
52bool TcpServerBalancer::listen(
const QString &line,
Protocol *protocol,
bool secure)
54 m_protocol = protocol;
57 const QString addressPortString = line.
mid(0, commaPos);
61 if (closeBracketPos != -1) {
63 std::cerr <<
"Failed to parse address: " << qPrintable(addressPortString) <<
'\n';
66 addressString = addressPortString.
mid(1, closeBracketPos - 1);
80 quint16 port = portString.
toUInt(&ok);
81 if (!ok || (port < 1 || port > 35554)) {
88 std::cerr <<
"No SSL certificate specified" <<
'\n';
92 const QString sslString = line.
mid(commaPos + 1);
94 QFile certFile(certPath);
96 std::cerr <<
"Failed to open SSL certificate" << qPrintable(certPath)
97 << qPrintable(certFile.errorString()) <<
'\n';
102 std::cerr <<
"Failed to parse SSL certificate" <<
'\n';
107 QFile keyFile(keyPath);
109 std::cerr <<
"Failed to open SSL private key" << qPrintable(keyPath)
110 << qPrintable(keyFile.errorString()) <<
'\n';
122 std::cerr <<
"Failed to select SSL Key Algorithm" << qPrintable(keyAlgorithm)
128 QSslKey key(&keyFile, algorithm);
130 std::cerr <<
"Failed to parse SSL private key" <<
'\n';
139 if (m_server->httpsH2()) {
141 {QByteArrayLiteral(
"h2"), QSslConfiguration::NextProtocolHttp1_1});
150 int socket = listenReuse(
151 address, m_server->listenQueue(), port, m_server->reusePort(), !m_server->reusePort());
155 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
165 std::cerr <<
"Failed to listen on TCP: " << qPrintable(line) <<
" : "
178inline int qt_safe_socket(
int domain,
int type,
int protocol,
int flags = 0)
180 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
183# ifdef QT_THREADSAFE_CLOEXEC
184 int newtype = type | SOCK_CLOEXEC;
185 if (flags & O_NONBLOCK) {
186 newtype |= SOCK_NONBLOCK;
188 fd = ::socket(domain, newtype, protocol);
191 fd = ::socket(domain, type, protocol);
196 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
199 if (flags & O_NONBLOCK) {
200 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
215 int type = SOCK_STREAM;
217 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
220 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
227 case EPROTONOSUPPORT:
230 qCDebug(C_SERVER_BALANCER)
231 <<
"setError(QAbstractSocket::UnsupportedSocketOperationError, "
232 "ProtocolUnsupportedErrorString)";
238 qCDebug(C_SERVER_BALANCER)
239 <<
"setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
242 qCDebug(C_SERVER_BALANCER)
243 <<
"setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
249# if defined(QNATIVESOCKETENGINE_DEBUG)
250 qCDebug(C_SERVER_BALANCER,
251 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
260# if defined(QNATIVESOCKETENGINE_DEBUG)
261 qCDebug(C_SERVER_BALANCER,
262 "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
276# define QT_SOCKLEN_T int
277# define QT_SOCKET_BIND ::bind
281void set(T *sa,
typename std::enable_if<(&T::sa_len,
true), QT_SOCKLEN_T>::type len)
286void set(T *sin6,
typename std::enable_if<(&T::sin6_len,
true), QT_SOCKLEN_T>::type len)
288 sin6->sin6_len = len;
296void setPortAndAddress(quint16 port,
306 memset(&aa->a6, 0,
sizeof(sockaddr_in6));
307 aa->a6.sin6_family = AF_INET6;
311 aa->a6.sin6_port = htons(port);
313 memcpy(&aa->a6.sin6_addr, &tmp,
sizeof(tmp));
314 *sockAddrSize =
sizeof(sockaddr_in6);
315 SetSALen::set(&aa->a,
sizeof(sockaddr_in6));
317 memset(&aa->a, 0,
sizeof(sockaddr_in));
318 aa->a4.sin_family = AF_INET;
319 aa->a4.sin_port = htons(port);
321 *sockAddrSize =
sizeof(sockaddr_in);
322 SetSALen::set(&aa->a,
sizeof(sockaddr_in));
326bool nativeBind(
int socketDescriptor,
const QHostAddress &address, quint16 port)
330 setPortAndAddress(port, address, address.
protocol(), &aa, &sockAddrSize);
333 if (aa.a.sa_family == AF_INET6) {
341 socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (
char *) &ipv6only,
sizeof(ipv6only));
345 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
346 if (bindResult < 0 && errno == EAFNOSUPPORT &&
349 aa.a4.sin_family = AF_INET;
350 aa.a4.sin_port = htons(port);
352 sockAddrSize =
sizeof(aa.a4);
353 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
356 if (bindResult < 0) {
357# if defined(QNATIVESOCKETENGINE_DEBUG)
377# if defined(QNATIVESOCKETENGINE_DEBUG)
378 qCDebug(C_SERVER_BALANCER,
379 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
388# if defined(QNATIVESOCKETENGINE_DEBUG)
389 qCDebug(C_SERVER_BALANCER,
390 "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
406 int socket = createNewSocket(proto);
408 qCCritical(C_SERVER_BALANCER) <<
"Failed to create new socket";
415 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval))) {
416 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEADDR on socket" << socket;
421 if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval,
sizeof(optval))) {
422 qCCritical(C_SERVER_BALANCER) <<
"Failed to set SO_REUSEPORT on socket" << socket;
427 if (!nativeBind(socket, address, port)) {
428 qCCritical(C_SERVER_BALANCER) <<
"Failed to bind to socket" << socket;
432 if (startListening && ::listen(socket, listenQueue) < 0) {
433 qCCritical(C_SERVER_BALANCER) <<
"Failed to listen to socket" << socket;
442void TcpServerBalancer::setBalancer(
bool enable)
447void TcpServerBalancer::incomingConnection(qintptr handle)
449 TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());
451 Q_EMIT serverIdle->createConnection(handle);
457 if (m_sslConfiguration) {
459 auto sslServer =
new TcpSslServer(m_serverName, m_protocol, m_server, engine);
460 sslServer->setSslConfiguration(*m_sslConfiguration);
464 server =
new TcpServer(m_serverName, m_protocol, m_server, engine);
466 connect(engine, &ServerEngine::shutdown, server, &TcpServer::shutdown);
469 connect(engine, &ServerEngine::started,
this, [
this, server]() {
470 m_servers.push_back(server);
474 &TcpServer::createConnection,
476 &TcpServer::incomingConnection,
481 if (m_server->reusePort()) {
482 connect(engine, &ServerEngine::started,
this, [
this, server]() {
483 int socket = listenReuse(
484 m_address, m_server->listenQueue(), m_port, m_server->reusePort(),
true);
486 qFatal(
"Failed to set server socket descriptor, reuse-port");
496 &ServerEngine::started,
501 qFatal(
"Failed to set server socket descriptor");
508#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
void setListenBacklogSize(int size)
bool setSocketDescriptor(qintptr socketDescriptor)
qintptr socketDescriptor() const const