KD SOAP API Documentation  2.1
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-2022 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 
22 class KDSoapServer::Private
23 {
24 public:
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;
43  KDSoapMessage::Use m_use;
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.
70  setMaxPendingConnections(1000);
71 }
72 
74 {
75  delete d;
76 }
77 
78 void KDSoapServer::incomingConnection(qintptr socketDescriptor)
79 {
80  const int max = maxConnections();
81  const int numSockets = numConnectedSockets();
82  if (max > -1 && numSockets >= max) {
83  emit connectionRejected();
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 
138 QString KDSoapServer::endPoint() const
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"))
148  .arg(addressStr)
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 
175 void KDSoapServer::setLogFileName(const QString &fileName)
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 
187 void 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
267  Q_UNUSED(sockets);
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 
298 void 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 
305 QString KDSoapServer::wsdlFile() const
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 
317 void KDSoapServer::setPath(const QString &path)
318 {
319  QMutexLocker lock(&d->m_serverDataMutex);
320  d->m_path = path;
321 }
322 
323 QString KDSoapServer::path() const
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 
341 void KDSoapServer::setFeatures(Features features)
342 {
343  QMutexLocker lock(&d->m_serverDataMutex);
344  d->m_features = features;
345 }
346 
347 KDSoapServer::Features KDSoapServer::features() const
348 {
349  QMutexLocker lock(&d->m_serverDataMutex);
350  return d->m_features;
351 }
352 
353 #ifndef QT_NO_SSL
354 QSslConfiguration KDSoapServer::sslConfiguration() const
355 {
356  return d->m_sslConfiguration;
357 }
358 
359 void KDSoapServer::setSslConfiguration(const QSslConfiguration &config)
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)
@ Ssl
HTTPS.
Definition: KDSoapServer.h:49
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)
void flushLogFile()
QString endPoint() const
LogLevel logLevel() const
QString path() const
Features features() const
int totalConnectionCount() const
void closeLogFile()
void setLogLevel(LogLevel level)

© 2010-2022 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 Jun 13 2023 12:18:34 for KD SOAP API Documentation by doxygen 1.9.1