cutelyst  4.8.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
tcpserver.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2016-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "tcpserver.h"
6 
7 #include "protocol.h"
8 #include "protocolhttp.h"
9 #include "server.h"
10 #include "socket.h"
11 
12 #include <Cutelyst/Engine>
13 
14 #include <QDateTime>
15 #include <QLoggingCategory>
16 
17 Q_LOGGING_CATEGORY(C_SERVER_TCP, "cutelyst.server.tcp", QtWarningMsg)
18 
19 using namespace Cutelyst;
20 
21 TcpServer::TcpServer(const QByteArray &serverAddress,
22  Protocol *protocol,
23  Server *wsgi,
24  QObject *parent)
25  : QTcpServer(parent)
26  , m_serverAddress(serverAddress)
27  , m_wsgi(wsgi)
28  , m_protocol(protocol)
29 {
30  m_engine = qobject_cast<ServerEngine *>(parent);
31 
32  if (m_wsgi->tcpNodelay()) {
33  m_socketOptions.push_back({QAbstractSocket::LowDelayOption, 1});
34  }
35  if (m_wsgi->soKeepalive()) {
36  m_socketOptions.push_back({QAbstractSocket::KeepAliveOption, 1});
37  }
38  if (m_wsgi->socketSndbuf() != -1) {
39  m_socketOptions.push_back(
40  {QAbstractSocket::SendBufferSizeSocketOption, m_wsgi->socketSndbuf()});
41  }
42  if (m_wsgi->socketRcvbuf() != -1) {
43  m_socketOptions.push_back(
44  {QAbstractSocket::ReceiveBufferSizeSocketOption, m_wsgi->socketRcvbuf()});
45  }
46 }
47 
48 void TcpServer::incomingConnection(qintptr handle)
49 {
50  auto sock = new TcpSocket(m_engine, this);
51  sock->serverAddress = m_serverAddress;
52  sock->protoData = m_protocol->createData(sock);
53 
54  connect(sock, &QIODevice::readyRead, [sock] {
55  sock->timeout = false;
56  sock->proto->parse(sock, sock);
57  });
58  connect(sock, &TcpSocket::finished, this, [this, sock] {
59  sock->deleteLater();
60  if (--m_processing == 0) {
61  m_engine->stopSocketTimeout();
62  }
63  });
64 
65  if (Q_LIKELY(sock->setSocketDescriptor(
67  sock->proto = m_protocol;
68 
69  sock->remoteAddress = sock->peerAddress();
70  sock->remotePort = sock->peerPort();
71  sock->protoData->setupNewConnection(sock);
72 
73  for (const auto &opt : m_socketOptions) {
74  sock->setSocketOption(opt.first, opt.second);
75  }
76 
77  if (++m_processing) {
78  m_engine->startSocketTimeout();
79  }
80  } else {
81  delete sock;
82  }
83 }
84 
85 void TcpServer::shutdown()
86 {
87  close();
88 
89  if (m_processing == 0) {
90  m_engine->serverShutdown();
91  } else {
92  const auto childrenL = children();
93  for (auto child : childrenL) {
94  auto socket = qobject_cast<TcpSocket *>(child);
95  if (socket) {
96  connect(socket, &TcpSocket::finished, this, [this]() {
97  if (m_processing == 0) {
98  m_engine->serverShutdown();
99  }
100  });
101  m_engine->handleSocketShutdown(socket);
102  }
103  }
104  }
105 }
106 
107 void TcpServer::timeoutConnections()
108 {
109  if (m_processing) {
110  const auto childrenL = children();
111  for (auto child : childrenL) {
112  auto socket = qobject_cast<TcpSocket *>(child);
113  if (socket && !socket->processing &&
114  socket->state() == QAbstractSocket::ConnectedState) {
115  if (socket->timeout) {
116  qCInfo(C_SERVER_TCP) << "timing out connection"
117  << socket->peerAddress().toString() << socket->peerPort();
118  socket->connectionClose();
119  } else {
120  socket->timeout = true;
121  }
122  }
123  }
124  }
125 }
126 
127 Protocol *TcpServer::protocol() const
128 {
129  return m_protocol;
130 }
131 
132 void TcpServer::setProtocol(Protocol *protocol)
133 {
134  m_protocol = protocol;
135 }
136 
137 #include "moc_tcpserver.cpp"
QHostAddress peerAddress() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
const QObjectList & children() const const
Implements a web server.
Definition: server.h:59
QString toString() const const
The Cutelyst namespace holds all public Cutelyst API.
void readyRead()
T qobject_cast(QObject *object)
QObject * parent() const const
void close()