ArnLib  4.0.x
Active Registry Network
ArnServer.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2022 Michael Wiklund.
2 // All rights reserved.
3 // Contact: arnlib@wiklunden.se
4 //
5 // This file is part of the ArnLib - Active Registry Network.
6 // Parts of ArnLib depend on Qt and/or other libraries that have their own
7 // licenses. Usage of these other libraries is subject to their respective
8 // license agreements.
9 //
10 // GNU Lesser General Public License Usage
11 // This file may be used under the terms of the GNU Lesser General Public
12 // License version 2.1 as published by the Free Software Foundation and
13 // appearing in the file LICENSE_LGPL.txt included in the packaging of this
14 // file. In addition, as a special exception, you may use the rights described
15 // in the Nokia Qt LGPL Exception version 1.1, included in the file
16 // LGPL_EXCEPTION.txt in this package.
17 //
18 // GNU General Public License Usage
19 // Alternatively, this file may be used under the terms of the GNU General Public
20 // License version 3.0 as published by the Free Software Foundation and appearing
21 // in the file LICENSE_GPL.txt included in the packaging of this file.
22 //
23 // Other Usage
24 // Alternatively, this file may be used in accordance with the terms and conditions
25 // contained in a signed written agreement between you and Michael Wiklund.
26 //
27 // This program is distributed in the hope that it will be useful, but WITHOUT ANY
28 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
29 // PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
30 //
31 
32 #include "ArnInc/ArnServer.hpp"
33 #include "private/ArnServer_p.hpp"
34 #include "ArnInc/ArnError.hpp"
35 #include "ArnInc/ArnM.hpp"
36 #include "ArnInc/ArnLib.hpp"
37 #include "ArnSync.hpp"
38 #include "ArnSyncLogin.hpp"
39 #include "ArnItemNet.hpp"
40 #include <QTcpServer>
41 #include <QTcpSocket>
42 #include <QHostInfo>
43 #include <QNetworkInterface>
44 #include <QHostAddress>
45 #include <QPair>
46 #include <QDebug>
47 
48 using Arn::XStringMap;
49 
50 
51 ArnServerSession::ArnServerSession( QTcpSocket* socket, ArnServer* arnServer)
52  : QObject( arnServer)
53 {
54  QHostAddress remoteAddr = socket->peerAddress();
55  // QHostAddress localAddr = socket->localAddress();
56  // qDebug() << "ArnServerNetSync: remoteAddr=" << remoteAddr.toString()
57  // << " localAddr=" << localAddr.toString();
58 
59  _socket = socket;
60  _arnServer = arnServer;
61  _socket->setParent( this); // Session takes ownership of socket
62  _arnNetSync = new ArnSync( _socket, false, this);
63  _arnNetSync->setSessionHandler( this);
64  _arnNetSync->setArnLogin( _arnServer->arnLogin());
65  _arnNetSync->setDemandLogin( _arnServer->isDemandLogin()
66  && _arnServer->isDemandLoginNet( remoteAddr));
67  // qDebug() << "ArnServerNetSync new session: remoteAddr=" << remoteAddr.toString()
68  // << "isDemandLoginNet=" << _arnServer->isDemandLoginNet( remoteAddr);
69  _arnNetSync->start();
70 
71  foreach (const QString& path, _arnServer->freePaths()) {
72  _arnNetSync->addFreePath( path);
73  }
74  _arnNetSync->setWhoIAm( _arnServer->whoIAm());
75 
76  _arnNetEar = new ArnItemNetEar( this);
77  _arnNetEar->open("/"); // MW: Optimize to only mountPoint:s ?
78 
79  connect( _arnNetSync, SIGNAL(stateChanged(int)), this, SLOT(doSyncStateChanged(int)));
80  connect( _arnNetSync, SIGNAL(destroyed(QObject*)), this, SLOT(shutdown()));
81  connect( _arnNetSync, SIGNAL(xcomDelete(QString)), this, SLOT(onCommandDelete(QString)));
82  connect( _arnNetSync, SIGNAL(infoReceived(int)), this, SIGNAL(infoReceived(int)));
83  connect( _arnNetSync, SIGNAL(loginCompleted()), this, SIGNAL(loginCompleted()));
84  connect( _arnNetSync, SIGNAL(messageReceived(int,QByteArray)),
85  this, SIGNAL(messageReceived(int,QByteArray)));
86  connect( _arnNetEar, SIGNAL(arnTreeDestroyed(QString,bool)),
87  this, SLOT(doDestroyArnTree(QString,bool)));
88 }
89 
90 
91 void ArnServerSession::shutdown()
92 {
93  _arnNetSync = arnNullptr; // Mark retired
94  _arnNetEar->close();
95  deleteLater();
96 }
97 
98 
99 void ArnServerSession::doDestroyArnTree( const QString& path, bool isGlobal)
100 {
101  Q_UNUSED(isGlobal) // Destruction of tree on server will allways be global
102 
103  if (!_arnNetSync) return; // Retired
104 
105  _arnNetSync->sendDelete( path);
106 }
107 
108 
109 void ArnServerSession::onCommandDelete( const QString& path)
110 {
111  if (!_arnNetSync) return; // Retired
112 
113  // qDebug() << "ArnServerNetSync-delete: path=" << path;
114  ArnM::destroyLink( path);
115 }
116 
117 
118 void ArnServerSession::doSyncStateChanged( int state)
119 {
120  if (!_arnNetSync) return; // Retired
121 
122  // qDebug() << "ArnServer sync state changed: state=" << state;
123  ArnSync::State syncState = ArnSync::State::fromInt( state);
124  if (syncState == syncState.Normal) {
125  // qDebug() << "ArnServer connected: remVer="
126  // << _arnNetSync->remoteVer(0) << _arnNetSync->remoteVer(1);
127  }
128 }
129 
130 
131 QTcpSocket* ArnServerSession::socket() const
132 {
133  return _socket;
134 }
135 
136 
138 {
139  if (!_arnNetSync) return XStringMap(); // Retired
140 
141  return XStringMap( _arnNetSync->remoteWhoIAm());
142 }
143 
144 
146 {
147  if (!_arnNetSync) return QString(); // Retired
148 
149  return _arnNetSync->loginUserName();
150 }
151 
152 
154 {
155  if (!_arnNetSync) return Arn::Allow(); // Retired
156 
157  return _arnNetSync->getAllow();
158 }
159 
160 
161 void ArnServerSession::sendMessage( int type, const QByteArray& data)
162 {
163  if (!_arnNetSync) return; // Retired
164 
165  _arnNetSync->sendMessage( type, data);
166 }
167 
168 
169 bool ArnServerSession::getTraffic( quint64& in, quint64& out) const
170 {
171  if (!_arnNetSync) return false; // Retired
172 
173  _arnNetSync->getTraffic( in, out);
174  return true;
175 }
176 
177 
178 
179 ArnServerPrivate::ArnServerPrivate( ArnServer::Type serverType)
180 {
181  _tcpServerActive = false;
182  _isDemandLogin = false;
183  _tcpServer = new QTcpServer;
184  _arnLogin = new ArnSyncLogin;
185  _newSession = arnNullptr;
186  _serverType = serverType;
187  _freePathTab += Arn::fullPath( Arn::pathLocalSys + "Legal/");
188 }
189 
190 
191 ArnServerPrivate::~ArnServerPrivate()
192 {
193  delete _tcpServer;
194  delete _arnLogin;
195 }
196 
197 
198 ArnServer::ArnServer( Type serverType, QObject *parent)
199  : QObject( parent)
200  , d_ptr( new ArnServerPrivate( serverType))
201 {
202 }
203 
204 
205 ArnServer::ArnServer( ArnServerPrivate& dd, QObject* parent)
206  : QObject( parent)
207  , d_ptr( &dd)
208 {
209 }
210 
211 
213 {
214  delete d_ptr;
215 }
216 
217 
218 void ArnServer::start( int port, QHostAddress listenAddr)
219 {
220  Q_D(ArnServer);
221 
222  if (port < 0) {
223  switch (d->_serverType) {
224  case Type::NetSync:
226  break;
227  default:
228  ArnM::errorLog( QString(tr("Unknown Arn server Type: ")) + QString::number( d->_serverType),
230  return;
231  }
232  }
233 
234  if (d->_tcpServer->listen( listenAddr, port)) {
235  d->_tcpServerActive = true;
236 
237  connect( d->_tcpServer, SIGNAL(newConnection()), this, SLOT(tcpConnection()));
238  }
239  else {
240  ArnM::errorLog( QString(tr("Failed start Arn Server Port: ")) + QString::number( port),
242  }
243 }
244 
245 
247 {
248  Q_D(ArnServer);
249 
250  return d->_tcpServer->serverPort();
251 }
252 
253 
255 {
256  Q_D(ArnServer);
257 
258  QHostAddress addr = d->_tcpServer->serverAddress();
259  return addr;
260 }
261 
262 
263 void ArnServer::addAccess(const QString& userName, const QString& password, Arn::Allow allow)
264 {
265  Q_D(ArnServer);
266 
267  d->_arnLogin->addAccess( userName, password, allow);
268 }
269 
270 
272 {
273  Q_D(const ArnServer);
274 
275  return d->_isDemandLogin;
276 }
277 
278 
279 void ArnServer::setDemandLogin( bool isDemandLogin)
280 {
281  Q_D(ArnServer);
282 
283  d->_isDemandLogin = isDemandLogin;
284 }
285 
286 
287 void ArnServer::setNoLoginNets( const QStringList& noLoginNets)
288 {
289  Q_D(ArnServer);
290 
291  d->_noLoginNets = noLoginNets;
292 }
293 
294 
295 QStringList ArnServer::noLoginNets() const
296 {
297  Q_D(const ArnServer);
298 
299  return d->_noLoginNets;
300 }
301 
302 
303 bool ArnServer::isDemandLoginNet( const QHostAddress& remoteAddr) const
304 {
305  Q_D(const ArnServer);
306 
307  QHostAddress remoteAddrV6 = QHostAddress( remoteAddr.toIPv6Address());
308 
309  foreach (const QString& noLoginNet, d->_noLoginNets) {
310  bool chkLocalHost = noLoginNet == "localhost";
311  if (chkLocalHost || (noLoginNet == "localnet")) {
312  if (remoteAddrV6 == QHostAddress( QHostAddress::LocalHostIPv6))
313  return false; // Localhost, ok for both localhost & localnet
314 
315  foreach (QNetworkInterface interface, QNetworkInterface::allInterfaces()) {
316  QNetworkInterface::InterfaceFlags flags = interface.flags();
317  if (flags.testFlag( QNetworkInterface::IsPointToPoint)
318  || flags.testFlag( QNetworkInterface::IsLoopBack))
319  continue;
320 
321  foreach (QNetworkAddressEntry entry, interface.addressEntries()) {
322  QHostAddress entryIp = entry.ip();
323  QAbstractSocket::NetworkLayerProtocol prot = entryIp.protocol();
324  if ((prot != QAbstractSocket::IPv4Protocol) && (prot != QAbstractSocket::IPv6Protocol))
325  continue;
326 
327  QHostAddress entryIpV6 = QHostAddress( entryIp.toIPv6Address());
328  int prefixOffs = (prot == QAbstractSocket::IPv4Protocol) ? 96 : 0;
329  int prefixV6 = entry.prefixLength() + prefixOffs;
330 
331  if (entry.prefixLength() < 0) {
332  // This is a bug in some Qt for android, windows ... (Not linux)
333  prefixV6 = 24 + prefixOffs;
334  qWarning() << "Bad netmask: nif=" << interface.humanReadableName()
335  << ", asume prefixV6Len(=" << prefixV6;
336  }
337 
338  if (entryIpV6 == remoteAddrV6) // Address to this host ip, ok for both localhost & localnet
339  return false;
340 
341  if (!chkLocalHost && remoteAddrV6.isInSubnet( entryIpV6, prefixV6))
342  return false;
343  }
344  }
345  }
346  else if (noLoginNet == "any") {
347  return false;
348  }
349  else {
350  QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet( noLoginNet);
351  QHostAddress subnetIpV6 = QHostAddress( subnet.first.toIPv6Address());
352  int prefixOffs = (subnet.first.protocol() == QAbstractSocket::IPv4Protocol) ? 96 : 0;
353  int prefixV6 = subnet.second + prefixOffs;
354  if (remoteAddrV6.isInSubnet( subnetIpV6, prefixV6))
355  return false;
356  }
357  }
358 
359  return true;
360 }
361 
362 
363 void ArnServer::addFreePath(const QString& path)
364 {
365  Q_D(ArnServer);
366 
367  if (!d->_freePathTab.contains( path))
368  d->_freePathTab += path;
369 }
370 
371 
372 QStringList ArnServer::freePaths() const
373 {
374  Q_D(const ArnServer);
375 
376  return d->_freePathTab;
377 }
378 
379 
380 ArnSyncLogin* ArnServer::arnLogin() const
381 {
382  Q_D(const ArnServer);
383 
384  return d->_arnLogin;
385 }
386 
387 
388 ArnServerSession* ArnServer::getSession() const
389 {
390  Q_D(const ArnServer);
391 
392  return d->_newSession;
393 }
394 
395 
396 QByteArray ArnServer::whoIAm() const
397 {
398  Q_D(const ArnServer);
399 
400  return d->_whoIAm;
401 }
402 
403 
404 void ArnServer::setWhoIAm( const Arn::XStringMap& whoIAmXsm)
405 {
406  Q_D(ArnServer);
407 
408  d->_whoIAm = whoIAmXsm.toXString();
409 }
410 
411 
412 void ArnServer::tcpConnection()
413 {
414  Q_D(ArnServer);
415 
416  QTcpSocket* socket = d->_tcpServer->nextPendingConnection();
417  if (socket->peerPort() == 0) { // Socket not connected ok
418  socket->deleteLater();
419  return;
420  }
421 
422  switch (d->_serverType) {
423  case Type::NetSync:
424  d->_newSession = new ArnServerSession( socket, this);
425  emit newSession();
426  d->_newSession = arnNullptr;
427  break;
428  }
429 }
QStringList noLoginNets() const
Get the nets not demanding login.
Definition: ArnServer.cpp:295
Arn::XStringMap remoteWhoIAm() const
Definition: ArnServer.cpp:137
QTcpSocket * socket() const
Definition: ArnServer.cpp:131
void start(int port=-1, QHostAddress listenAddr=QHostAddress::Any)
Start the Arn server
Definition: ArnServer.cpp:218
void setWhoIAm(const Arn::XStringMap &whoIAmXsm)
Set servers human readable identification information.
Definition: ArnServer.cpp:404
Class for making an Arn Server.
Definition: ArnServer.hpp:98
Container class with string representation for serialized data.
Definition: XStringMap.hpp:107
QString fullPath(const QString &path)
Convert a path to a full absolute path.
Definition: Arn.cpp:82
bool getTraffic(quint64 &in, quint64 &out) const
Definition: ArnServer.cpp:169
const QString pathLocalSys
Definition: Arn.cpp:46
void setNoLoginNets(const QStringList &noLoginNets)
Set the nets not demanding login.
Definition: ArnServer.cpp:287
const quint16 defaultTcpPort
Definition: Arn.hpp:50
ArnServer(Type serverType, QObject *parent=arnNullptr)
Create an Arn server object.
Definition: ArnServer.cpp:198
bool isDemandLoginNet(const QHostAddress &remoteAddr) const
Return if a host address demands login.
Definition: ArnServer.cpp:303
QStringList freePaths() const
Returns current list of freePaths.
Definition: ArnServer.cpp:372
ArnServerSession(QTcpSocket *socket, ArnServer *arnServer)
Definition: ArnServer.cpp:51
void addFreePath(const QString &path)
Add a new "freePath".
Definition: ArnServer.cpp:363
void messageReceived(int type, const QByteArray &data)
QByteArray toXString() const
QHostAddress listenAddress()
Address of the interface used to listening for connections to the Arn server
Definition: ArnServer.cpp:254
void addAccess(const QString &userName, const QString &password, Arn::Allow allow)
Add an access entry.
Definition: ArnServer.cpp:263
void infoReceived(int type)
bool isDemandLogin() const
Get servers demand for login.
Definition: ArnServer.cpp:271
int port()
Port number of the Arn server
Definition: ArnServer.cpp:246
QString loginUserName() const
Definition: ArnServer.cpp:145
static void errorLog(QString errText, ArnError err=ArnError::Undef, void *reference=arnNullptr)
Definition: ArnM.cpp:1025
static void destroyLink(const QString &path, bool isGlobal=true)
Destroy the Arn Data Object at path
Definition: ArnM.cpp:853
void sendMessage(int type, const QByteArray &data=QByteArray())
Definition: ArnServer.cpp:161
void setDemandLogin(bool isDemandLogin)
Set servers demand for login.
Definition: ArnServer.cpp:279
Arn::Allow getAllow() const
Definition: ArnServer.cpp:153