KD SOAP API Documentation  2.2
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 
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"), 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 
174 void KDSoapServer::setLogFileName(const QString &fileName)
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 
186 void 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
266  Q_UNUSED(sockets);
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 
297 void 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 
304 QString KDSoapServer::wsdlFile() const
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 
316 void KDSoapServer::setPath(const QString &path)
317 {
318  QMutexLocker lock(&d->m_serverDataMutex);
319  d->m_path = path;
320 }
321 
322 QString KDSoapServer::path() const
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 
340 void KDSoapServer::setFeatures(Features features)
341 {
342  QMutexLocker lock(&d->m_serverDataMutex);
343  d->m_features = features;
344 }
345 
346 KDSoapServer::Features KDSoapServer::features() const
347 {
348  QMutexLocker lock(&d->m_serverDataMutex);
349  return d->m_features;
350 }
351 
352 #ifndef QT_NO_SSL
353 QSslConfiguration KDSoapServer::sslConfiguration() const
354 {
355  return d->m_sslConfiguration;
356 }
357 
358 void KDSoapServer::setSslConfiguration(const QSslConfiguration &config)
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)
@ 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-2024 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 by doxygen 1.9.1