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