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> 25 Q_LOGGING_CATEGORY(C_SERVER_BALANCER,
"cutelyst.server.tcpbalancer", QtWarningMsg)
39 TcpServerBalancer::TcpServerBalancer(
Server *server)
45 TcpServerBalancer::~TcpServerBalancer()
48 delete m_sslConfiguration;
52 bool TcpServerBalancer::listen(
const QString &line,
Protocol *protocol,
bool secure)
54 m_protocol = protocol;
56 int commaPos = line.
indexOf(u
',');
57 const QString addressPortString = line.
mid(0, commaPos);
60 int closeBracketPos = addressPortString.
indexOf(u
']');
61 if (closeBracketPos != -1) {
63 std::cerr <<
"Failed to parse address: " << qPrintable(addressPortString) <<
'\n';
66 addressString = addressPortString.
mid(1, closeBracketPos - 1);
68 addressString = addressPortString.
section(u
':', 0, -2);
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) <<
" : " 178 inline 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 280 template <
typename T>
281 void set(T *sa,
typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len)
285 template <
typename T>
286 void set(T *sin6,
typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len)
288 sin6->sin6_len = len;
290 template <
typename T>
296 void 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));
326 bool 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;
442 void TcpServerBalancer::setBalancer(
bool enable)
447 void 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" void setLocalCertificate(const QSslCertificate &certificate)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool setSocketDescriptor(qintptr socketDescriptor)
QString toString() const const
qintptr socketDescriptor() const const
bool setAddress(const QString &address)
void setPrivateKey(const QSslKey &key)
QHostAddress serverAddress() const const
QByteArray number(double n, char format, int precision)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool listen(const QHostAddress &address, quint16 port)
bool isEmpty() const const
const char * constData() const const
The Cutelyst namespace holds all public Cutelyst API.
void setAllowedNextProtocols(const QList< QByteArray > &protocols)
QString errorString() const const
quint32 toIPv4Address(bool *ok) const const
Q_IPV6ADDR toIPv6Address() const const
QByteArray toLatin1() const const
QString mid(qsizetype position, qsizetype n) const const
void setPeerVerifyMode(QSslSocket::PeerVerifyMode mode)
int protocol() const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
uint toUInt(bool *ok, int base) const const
void setListenBacklogSize(int size)