KD SOAP API Documentation 2.2
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 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"), addressStr)
148 .arg(serverPort())
149 .arg(d->m_path);
150}
151
153{
154 d->m_use = use;
155}
156
158{
159 return d->m_use;
160}
161
163{
164 QMutexLocker lock(&d->m_logMutex);
165 d->m_logLevel = level;
166}
167
169{
170 QMutexLocker lock(&d->m_logMutex);
171 return d->m_logLevel;
172}
173
175{
176 QMutexLocker lock(&d->m_logMutex);
177 d->m_logFileName = fileName;
178}
179
181{
182 QMutexLocker lock(&d->m_logMutex);
183 return d->m_logFileName;
184}
185
186void KDSoapServer::log(const QByteArray &text)
187{
188 if (d->m_logLevel == KDSoapServer::LogNothing) {
189 return;
190 }
191
192 QMutexLocker lock(&d->m_logMutex);
193 if (d->m_logFileName.isEmpty()) {
194 return;
195 }
196 if (!d->m_logFile.isOpen()) {
197 d->m_logFile.setFileName(d->m_logFileName);
198 if (!d->m_logFile.open(QIODevice::Append)) {
199 qCritical("Could not open log file for writing: %s", qPrintable(d->m_logFileName));
200 d->m_logFileName.clear(); // don't retry every time log() is called
201 return;
202 }
203 }
204 d->m_logFile.write(text);
205}
206
208{
209 if (d->m_logFile.isOpen()) {
210 d->m_logFile.flush();
211 }
212}
213
215{
216 if (d->m_logFile.isOpen()) {
217 d->m_logFile.close();
218 }
219}
220
222{
223 // I hit a system limit when trying to connect more than 1024 sockets in the same process.
224 // strace said: socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = -1 EMFILE (Too many open files)
225 // Solution: ulimit -n 4096
226 // Or in C code, below.
227
228#ifdef Q_OS_UNIX
229 struct rlimit lim;
230 if (getrlimit(RLIMIT_NOFILE, &lim) != 0) {
231 qDebug() << "error calling getrlimit:" << strerror(errno);
232 return false;
233 }
234 bool changingHardLimit = false;
235 if (sockets > -1) {
236 qDebug() << "Current limit" << lim.rlim_cur << lim.rlim_max;
237 sockets += 20; // we need some file descriptors too
238 if (rlim_t(sockets) <= lim.rlim_cur) {
239 return true; // nothing to do
240 }
241
242 if (rlim_t(sockets) > lim.rlim_max) {
243 // Seems we need to run as root then
244 lim.rlim_max = sockets;
245 qDebug() << "Setting rlim_max to" << sockets;
246 changingHardLimit = true;
247 }
248 }
249#ifdef OPEN_MAX
250 // Mac OSX: setrlimit() no longer accepts "rlim_cur = RLIM_INFINITY" for RLIM_NOFILE. Use "rlim_cur = min(OPEN_MAX, rlim_max)".
251 lim.rlim_cur = qMin(rlim_t(OPEN_MAX), lim.rlim_max);
252#else
253 // Linux: does not define OPEN_MAX anymore, since it's "configurable at runtime".
254 lim.rlim_cur = lim.rlim_max;
255#endif
256 if (setrlimit(RLIMIT_NOFILE, &lim) == 0) {
257 qDebug() << "limit set to" << lim.rlim_cur;
258 } else {
259 if (changingHardLimit) {
260 qDebug() << "WARNING: hard limit is not high enough";
261 }
262 qDebug() << "error calling setrlimit(" << lim.rlim_cur << "," << lim.rlim_max << ") :" << strerror(errno);
263 return false;
264 }
265#else
267#endif
268 return true;
269}
270
272{
273 d->m_portBeforeSuspend = serverPort();
274 d->m_addressBeforeSuspend = serverAddress();
275 close();
276
277 // Disconnect connected sockets, otherwise they could still make calls
278 if (d->m_threadPool) {
279 d->m_threadPool->disconnectSockets(this);
280 } else if (d->m_mainThreadSocketList) {
281 d->m_mainThreadSocketList->disconnectAll();
282 }
283}
284
286{
287 if (d->m_portBeforeSuspend == 0) {
288 qWarning("KDSoapServer: resume() called without calling suspend() first");
289 } else {
290 if (!listen(d->m_addressBeforeSuspend, d->m_portBeforeSuspend)) {
291 qWarning("KDSoapServer: failed to listen on %s port %d", qPrintable(d->m_addressBeforeSuspend.toString()), d->m_portBeforeSuspend);
292 }
293 d->m_portBeforeSuspend = 0;
294 }
295}
296
297void KDSoapServer::setWsdlFile(const QString &file, const QString &pathInUrl)
298{
299 QMutexLocker lock(&d->m_serverDataMutex);
300 d->m_wsdlFile = file;
301 d->m_wsdlPathInUrl = pathInUrl;
302}
303
305{
306 QMutexLocker lock(&d->m_serverDataMutex);
307 return d->m_wsdlFile;
308}
309
311{
312 QMutexLocker lock(&d->m_serverDataMutex);
313 return d->m_wsdlPathInUrl;
314}
315
317{
318 QMutexLocker lock(&d->m_serverDataMutex);
319 d->m_path = path;
320}
321
323{
324 QMutexLocker lock(&d->m_serverDataMutex);
325 return d->m_path;
326}
327
329{
330 QMutexLocker lock(&d->m_serverDataMutex);
331 d->m_maxConnections = sockets;
332}
333
335{
336 QMutexLocker lock(&d->m_serverDataMutex);
337 return d->m_maxConnections;
338}
339
340void KDSoapServer::setFeatures(Features features)
341{
342 QMutexLocker lock(&d->m_serverDataMutex);
343 d->m_features = features;
344}
345
346KDSoapServer::Features KDSoapServer::features() const
347{
348 QMutexLocker lock(&d->m_serverDataMutex);
349 return d->m_features;
350}
351
352#ifndef QT_NO_SSL
354{
355 return d->m_sslConfiguration;
356}
357
359{
360 d->m_sslConfiguration = config;
361}
362#endif
363
364#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

© 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 Sat Apr 20 2024 00:04:25 for KD SOAP API Documentation by doxygen 1.9.8