1 /****************************************************************************
2 ** Copyright (C) 2010-2020 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com.
3 ** All rights reserved.
4 **
5 ** This file is part of the KD Soap library.
6 **
7 ** Licensees holding valid commercial KD Soap licenses may use this file in
8 ** accordance with the KD Soap Commercial License Agreement provided with
9 ** the Software.
10 **
11 **
12 ** This file may be distributed and/or modified under the terms of the
13 ** GNU Lesser General Public License version 2.1 and version 3 as published by the
14 ** Free Software Foundation and appearing in the file LICENSE.LGPL.txt included.
15 **
16 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
17 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 **
19 ** Contact info@kdab.com if any conditions of this licensing are not
20 ** clear to you.
21 **
22 **********************************************************************/
23 #include "KDSoapServerThread_p.h"
24 #include "KDSoapSocketList_p.h"
25 #include "KDSoapServerSocket_p.h"
26 #include "KDSoapServer.h"
27
28 #include <QMetaType>
29
KDSoapServerThread(QObject * parent)30 KDSoapServerThread::KDSoapServerThread(QObject *parent)
31 : QThread(parent), d(nullptr)
32 {
33 qRegisterMetaType<KDSoapServer *>("KDSoapServer*");
34 qRegisterMetaType<QSemaphore *>("QSemaphore*");
35 }
36
~KDSoapServerThread()37 KDSoapServerThread::~KDSoapServerThread()
38 {
39 }
40
run()41 void KDSoapServerThread::run()
42 {
43 KDSoapServerThreadImpl impl;
44 d = &impl;
45 m_semaphore.release();
46 exec();
47 d = nullptr;
48 }
49
socketCount() const50 int KDSoapServerThread::socketCount() const
51 {
52 if (d) {
53 return d->socketCount();
54 }
55 return 0;
56 }
57
socketCountForServer(const KDSoapServer * server) const58 int KDSoapServerThread::socketCountForServer(const KDSoapServer *server) const
59 {
60 if (d) {
61 return d->socketCountForServer(server);
62 }
63 return 0;
64 }
65
totalConnectionCountForServer(const KDSoapServer * server) const66 int KDSoapServerThread::totalConnectionCountForServer(const KDSoapServer *server) const
67 {
68 if (d) {
69 return d->totalConnectionCountForServer(server);
70 }
71 return 0;
72 }
73
resetTotalConnectionCountForServer(const KDSoapServer * server)74 void KDSoapServerThread::resetTotalConnectionCountForServer(const KDSoapServer *server)
75 {
76 if (d) {
77 d->resetTotalConnectionCountForServer(server);
78 }
79 }
80
disconnectSocketsForServer(KDSoapServer * server,QSemaphore & semaphore)81 void KDSoapServerThread::disconnectSocketsForServer(KDSoapServer *server, QSemaphore &semaphore)
82 {
83 if (d) {
84 QMetaObject::invokeMethod(d, "disconnectSocketsForServer", Q_ARG(KDSoapServer *, server), Q_ARG(QSemaphore *, &semaphore));
85 }
86 }
87
startThread()88 void KDSoapServerThread::startThread()
89 {
90 QThread::start();
91 m_semaphore.acquire(); // wait for init to be done
92 }
93
quitThread()94 void KDSoapServerThread::quitThread()
95 {
96 QMetaObject::invokeMethod(d, "quit");
97 }
98
handleIncomingConnection(int socketDescriptor,KDSoapServer * server)99 void KDSoapServerThread::handleIncomingConnection(int socketDescriptor, KDSoapServer *server)
100 {
101 d->addIncomingConnection();
102 QMetaObject::invokeMethod(d, "handleIncomingConnection", Q_ARG(int, socketDescriptor), Q_ARG(KDSoapServer *, server));
103 }
104
105 ////
106
KDSoapServerThreadImpl()107 KDSoapServerThreadImpl::KDSoapServerThreadImpl()
108 : QObject(nullptr), m_incomingConnectionCount(0)
109 {
110 }
111
~KDSoapServerThreadImpl()112 KDSoapServerThreadImpl::~KDSoapServerThreadImpl()
113 {
114 qDeleteAll(m_socketLists.values());
115 }
116
117 // Called from main thread!
socketCount()118 int KDSoapServerThreadImpl::socketCount()
119 {
120 QMutexLocker lock(&m_socketListMutex);
121 int sc = 0;
122 SocketLists::const_iterator it = m_socketLists.constBegin();
123 for (; it != m_socketLists.constEnd(); ++it) {
124 sc += it.value()->socketCount();
125 }
126 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
127 sc += m_incomingConnectionCount.loadAcquire();
128 #else
129 sc += m_incomingConnectionCount;
130 #endif
131 return sc;
132 }
133
socketListForServer(KDSoapServer * server)134 KDSoapSocketList *KDSoapServerThreadImpl::socketListForServer(KDSoapServer *server)
135 {
136 KDSoapSocketList *sockets = m_socketLists.value(server);
137 if (sockets) {
138 return sockets;
139 }
140
141 sockets = new KDSoapSocketList(server); // creates the server object
142 m_socketLists.insert(server, sockets);
143 return sockets;
144 }
145
addIncomingConnection()146 void KDSoapServerThreadImpl::addIncomingConnection()
147 {
148 m_incomingConnectionCount.fetchAndAddAcquire(1);
149 }
150
151 // Called in the thread itself so that the socket list and server object
152 // are created in the thread.
handleIncomingConnection(int socketDescriptor,KDSoapServer * server)153 void KDSoapServerThreadImpl::handleIncomingConnection(int socketDescriptor, KDSoapServer *server)
154 {
155 QMutexLocker lock(&m_socketListMutex);
156 KDSoapSocketList *sockets = socketListForServer(server);
157 KDSoapServerSocket *socket = sockets->handleIncomingConnection(socketDescriptor);
158 Q_UNUSED(socket);
159 m_incomingConnectionCount.fetchAndAddAcquire(-1);
160 }
161
quit()162 void KDSoapServerThreadImpl::quit()
163 {
164 thread()->quit();
165 }
166
socketCountForServer(const KDSoapServer * server)167 int KDSoapServerThreadImpl::socketCountForServer(const KDSoapServer *server)
168 {
169 QMutexLocker lock(&m_socketListMutex);
170 KDSoapSocketList *sockets = m_socketLists.value(const_cast<KDSoapServer *>(server));
171 return sockets ? sockets->socketCount() : 0;
172 }
173
disconnectSocketsForServer(KDSoapServer * server,QSemaphore * semaphore)174 void KDSoapServerThreadImpl::disconnectSocketsForServer(KDSoapServer *server, QSemaphore *semaphore)
175 {
176 QMutexLocker lock(&m_socketListMutex);
177 KDSoapSocketList *sockets = m_socketLists.value(server);
178 if (sockets) {
179 sockets->disconnectAll();
180 }
181 semaphore->release();
182 }
183
totalConnectionCountForServer(const KDSoapServer * server)184 int KDSoapServerThreadImpl::totalConnectionCountForServer(const KDSoapServer *server)
185 {
186 QMutexLocker lock(&m_socketListMutex);
187 KDSoapSocketList *sockets = m_socketLists.value(const_cast<KDSoapServer *>(server));
188 return sockets ? sockets->totalConnectionCount() : 0;
189 }
190
resetTotalConnectionCountForServer(const KDSoapServer * server)191 void KDSoapServerThreadImpl::resetTotalConnectionCountForServer(const KDSoapServer *server)
192 {
193 QMutexLocker lock(&m_socketListMutex);
194 KDSoapSocketList *sockets = m_socketLists.value(const_cast<KDSoapServer *>(server));
195 if (sockets) {
196 sockets->resetTotalConnectionCount();
197 }
198 }
199