KD SOAP API Documentation 2.1
Loading...
Searching...
No Matches
KDSoapServer.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** This file is part of the KD Soap project.
4**
5** SPDX-FileCopyrightText: 2010-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6**
7** SPDX-License-Identifier: MIT
8**
9****************************************************************************/
10#include "KDSoapServer.h"
11#include "KDSoapSocketList_p.h"
12#include "KDSoapThreadPool.h"
13#include <QFile>
14#include <QMutex>
15#ifdef Q_OS_UNIX
16#include <errno.h>
17#include <limits.h>
18#include <sys/resource.h>
19#include <sys/time.h>
20#endif
21
22class KDSoapServer::Private
23{
24public:
25 Private()
26 : m_threadPool(nullptr)
27 , m_mainThreadSocketList(nullptr)
28 , m_use(KDSoapMessage::LiteralUse)
29 , m_logLevel(KDSoapServer::LogNothing)
30 , m_path(QString::fromLatin1("/"))
31 , m_maxConnections(-1)
32 , m_portBeforeSuspend(0)
33 {
34 }
35
36 ~Private()
37 {
38 delete m_mainThreadSocketList;
39 }
40
41 KDSoapThreadPool *m_threadPool;
42 KDSoapSocketList *m_mainThreadSocketList;
44 KDSoapServer::Features m_features;
45
46 QMutex m_logMutex;
47 KDSoapServer::LogLevel m_logLevel;
48 QString m_logFileName;
49 QFile m_logFile;
50
51 QMutex m_serverDataMutex;
52 QString m_wsdlFile;
53 QString m_wsdlPathInUrl;
54 QString m_path;
55 int m_maxConnections;
56
57 QHostAddress m_addressBeforeSuspend;
58 quint16 m_portBeforeSuspend;
59
60#ifndef QT_NO_SSL
61 QSslConfiguration m_sslConfiguration;
62#endif
63};
64
66 : QTcpServer(parent)
67 , d(new KDSoapServer::Private)
68{
69 // Probably not very useful since we handle them immediately, but cannot hurt.
71}
72
74{
75 delete d;
76}
77
78void KDSoapServer::incomingConnection(qintptr socketDescriptor)
79{
80 const int max = maxConnections();
81 const int numSockets = numConnectedSockets();
82 if (max > -1 && numSockets >= max) {
84 log(QByteArray("ERROR Too many connections (") + QByteArray::number(numSockets) + "), incoming connection rejected\n");
85 } else if (d->m_threadPool) {
86 // qDebug() << "incomingConnection: using thread pool";
87 d->m_threadPool->handleIncomingConnection(socketDescriptor, this);
88 } else {
89 // qDebug() << "incomingConnection: using main-thread socketlist";
90 if (!d->m_mainThreadSocketList) {
91 d->m_mainThreadSocketList = new KDSoapSocketList(this /*server*/);
92 }
93 d->m_mainThreadSocketList->handleIncomingConnection(socketDescriptor);
94 }
95}
96
98{
99 if (d->m_threadPool) {
100 return d->m_threadPool->numConnectedSockets(this);
101 } else if (d->m_mainThreadSocketList) {
102 return d->m_mainThreadSocketList->socketCount();
103 } else {
104 return 0;
105 }
106}
107
109{
110 if (d->m_threadPool) {
111 return d->m_threadPool->totalConnectionCount(this);
112 } else if (d->m_mainThreadSocketList) {
113 return d->m_mainThreadSocketList->totalConnectionCount();
114 } else {
115 return 0;
116 }
117}
118
120{
121 if (d->m_threadPool) {
122 d->m_threadPool->resetTotalConnectionCount(this);
123 } else if (d->m_mainThreadSocketList) {
124 d->m_mainThreadSocketList->resetTotalConnectionCount();
125 }
126}
127
129{
130 d->m_threadPool = threadPool;
131}
132
134{
135 return d->m_threadPool;
136}
137
139{
140 QMutexLocker lock(&d->m_serverDataMutex);
141 const QHostAddress address = serverAddress();
142 if (address == QHostAddress::Null) {
143 return QString();
144 }
145 const QString addressStr = address == QHostAddress::Any ? QString::fromLatin1("127.0.0.1") : address.toString();
146 return QString::fromLatin1("%1://%2:%3%4")
147 .arg(QString::fromLatin1((d->m_features & Ssl) ? "https" : "http"))
149 .arg(serverPort())
150 .arg(d->m_path);
151}
152
154{
155 d->m_use = use;
156}
157
159{
160 return d->m_use;
161}
162
164{
165 QMutexLocker lock(&d->m_logMutex);
166 d->m_logLevel = level;
167}
168
170{
171 QMutexLocker lock(&d->m_logMutex);
172 return d->m_logLevel;
173}
174
176{
177 QMutexLocker lock(&d->m_logMutex);
178 d->m_logFileName = fileName;
179}
180
182{
183 QMutexLocker lock(&d->m_logMutex);
184 return d->m_logFileName;
185}
186
187void KDSoapServer::log(const QByteArray &text)
188{
189 if (d->m_logLevel == KDSoapServer::LogNothing) {
190 return;
191 }
192
193 QMutexLocker lock(&d->m_logMutex);
194 if (d->m_logFileName.isEmpty()) {
195 return;
196 }
197 if (!d->m_logFile.isOpen()) {
198 d->m_logFile.setFileName(d->m_logFileName);
199 if (!d->m_logFile.open(QIODevice::Append)) {
200 qCritical("Could not open log file for writing: %s", qPrintable(d->m_logFileName));
201 d->m_logFileName.clear(); // don't retry every time log() is called
202 return;
203 }
204 }
205 d->m_logFile.write(text);
206}
207
209{
210 if (d->m_logFile.isOpen()) {
211 d->m_logFile.flush();
212 }
213}
214
216{
217 if (d->m_logFile.isOpen()) {
218 d->m_logFile.close();
219 }
220}
221
223{
224 // I hit a system limit when trying to connect more than 1024 sockets in the same process.
225 // strace said: socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = -1 EMFILE (Too many open files)
226 // Solution: ulimit -n 4096
227 // Or in C code, below.
228
229#ifdef Q_OS_UNIX
230 struct rlimit lim;
231 if (getrlimit(RLIMIT_NOFILE, &lim) != 0) {
232 qDebug() << "error calling getrlimit:" << strerror(errno);
233 return false;
234 }
235 bool changingHardLimit = false;
236 if (sockets > -1) {
237 qDebug() << "Current limit" << lim.rlim_cur << lim.rlim_max;
238 sockets += 20; // we need some file descriptors too
239 if (rlim_t(sockets) <= lim.rlim_cur) {
240 return true; // nothing to do
241 }
242
243 if (rlim_t(sockets) > lim.rlim_max) {
244 // Seems we need to run as root then
245 lim.rlim_max = sockets;
246 qDebug() << "Setting rlim_max to" << sockets;
247 changingHardLimit = true;
248 }
249 }
250#ifdef OPEN_MAX
251 // Mac OSX: setrlimit() no longer accepts "rlim_cur = RLIM_INFINITY" for RLIM_NOFILE. Use "rlim_cur = min(OPEN_MAX, rlim_max)".
252 lim.rlim_cur = qMin(rlim_t(OPEN_MAX), lim.rlim_max);
253#else
254 // Linux: does not define OPEN_MAX anymore, since it's "configurable at runtime".
255 lim.rlim_cur = lim.rlim_max;
256#endif
257 if (setrlimit(RLIMIT_NOFILE, &lim) == 0) {
258 qDebug() << "limit set to" << lim.rlim_cur;
259 } else {
260 if (changingHardLimit) {
261 qDebug() << "WARNING: hard limit is not high enough";
262 }
263 qDebug() << "error calling setrlimit(" << lim.rlim_cur << "," << lim.rlim_max << ") :" << strerror(errno);
264 return false;
265 }
266#else
268#endif
269 return true;
270}
271
273{
274 d->m_portBeforeSuspend = serverPort();
275 d->m_addressBeforeSuspend = serverAddress();
276 close();
277
278 // Disconnect connected sockets, otherwise they could still make calls
279 if (d->m_threadPool) {
280 d->m_threadPool->disconnectSockets(this);
281 } else if (d->m_mainThreadSocketList) {
282 d->m_mainThreadSocketList->disconnectAll();
283 }
284}
285
287{
288 if (d->m_portBeforeSuspend == 0) {
289 qWarning("KDSoapServer: resume() called without calling suspend() first");
290 } else {
291 if (!listen(d->m_addressBeforeSuspend, d->m_portBeforeSuspend)) {
292 qWarning("KDSoapServer: failed to listen on %s port %d", qPrintable(d->m_addressBeforeSuspend.toString()), d->m_portBeforeSuspend);
293 }
294 d->m_portBeforeSuspend = 0;
295 }
296}
297
298void KDSoapServer::setWsdlFile(const QString &file, const QString &pathInUrl)
299{
300 QMutexLocker lock(&d->m_serverDataMutex);
301 d->m_wsdlFile = file;
302 d->m_wsdlPathInUrl = pathInUrl;
303}
304
306{
307 QMutexLocker lock(&d->m_serverDataMutex);
308 return d->m_wsdlFile;
309}
310
312{
313 QMutexLocker lock(&d->m_serverDataMutex);
314 return d->m_wsdlPathInUrl;
315}
316
318{
319 QMutexLocker lock(&d->m_serverDataMutex);
320 d->m_path = path;
321}
322
324{
325 QMutexLocker lock(&d->m_serverDataMutex);
326 return d->m_path;
327}
328
330{
331 QMutexLocker lock(&d->m_serverDataMutex);
332 d->m_maxConnections = sockets;
333}
334
336{
337 QMutexLocker lock(&d->m_serverDataMutex);
338 return d->m_maxConnections;
339}
340
341void KDSoapServer::setFeatures(Features features)
342{
343 QMutexLocker lock(&d->m_serverDataMutex);
344 d->m_features = features;
345}
346
347KDSoapServer::Features KDSoapServer::features() const
348{
349 QMutexLocker lock(&d->m_serverDataMutex);
350 return d->m_features;
351}
352
353#ifndef QT_NO_SSL
355{
356 return d->m_sslConfiguration;
357}
358
360{
361 d->m_sslConfiguration = config;
362}
363#endif
364
365#include "moc_KDSoapServer.cpp"
int numConnectedSockets() const
KDSoapThreadPool * threadPool() const
void setPath(const QString &path)
void setLogFileName(const QString &fileName)
int maxConnections() const
void connectionRejected()
static bool setExpectedSocketCount(int sockets)
void setSslConfiguration(const QSslConfiguration &config)
void setUse(KDSoapMessage::Use use)
KDSoapServer(QObject *parent=0)
KDSoapMessage::Use use() const
void setWsdlFile(const QString &file, const QString &pathInUrl)
void incomingConnection(qintptr socketDescriptor) override
QSslConfiguration sslConfiguration() const
void setMaxConnections(int sockets)
QString wsdlFile() const
void setThreadPool(KDSoapThreadPool *threadPool)
QString logFileName() const
void resetTotalConnectionCount()
QString wsdlPathInUrl() const
void setFeatures(Features features)
QString endPoint() const
LogLevel logLevel() const
QString path() const
Features features() const
int totalConnectionCount() const
void setLogLevel(LogLevel level)
QByteArray number(int n, int base)
QString toString() const const
T qobject_cast(QObject *object)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
void close()
bool listen(const QHostAddress &address, quint16 port)
QHostAddress serverAddress() const const
quint16 serverPort() const const
void setMaxPendingConnections(int numConnections)
qintptr socketDescriptor() const const

© 2010-2023 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-soap/
Generated on Tue Dec 26 2023 00:00:25 for KD SOAP API Documentation by doxygen 1.9.8