ArnLib  4.0.x
Active Registry Network
ArnClient.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/ArnClient.hpp"
33 #include "private/ArnClient_p.hpp"
34 #include "ArnInc/Arn.hpp"
35 #include "ArnInc/ArnLib.hpp"
36 #include "ArnSync.hpp"
37 #include "ArnSyncLogin.hpp"
38 #include <QTcpSocket>
39 #include <QStringList>
40 #include <QTimer>
41 #include <QMap>
42 #include <QMutexLocker>
43 #include <QDebug>
44 
45 using Arn::XStringMap;
46 
47 
49 {
50 public:
51  bool store( ArnClient* client, const QString& id);
52  ArnClient* get( const QString& id);
53  int remove( const QString& id);
54  int remove( const ArnClient* client);
55 
56  static ArnClientReg& instance();
57 
58 private:
59  ArnClientReg() {}
60 
61  QMap<QString, ArnClient*> _clientTab;
62  QMutex _mutex;
63 };
64 
65 
66 bool ArnClientReg::store( ArnClient* client, const QString& id)
67 {
68  if (id.isEmpty()) return false;
69 
70  QMutexLocker locker( &_mutex);
71 
72  if (_clientTab.contains( id)) return false;
73 
74  _clientTab.insert( id, client);
75  return true;
76 }
77 
78 
79 ArnClient* ArnClientReg::get( const QString& id)
80 {
81  QMutexLocker locker( &_mutex);
82 
83  return _clientTab.value( id, arnNullptr);
84 }
85 
86 
87 int ArnClientReg::remove( const QString& id)
88 {
89  QMutexLocker locker( &_mutex);
90 
91  return _clientTab.remove( id);
92 }
93 
94 
95 int ArnClientReg::remove( const ArnClient* client)
96 {
97  QMutexLocker locker( &_mutex);
98 
99  int eraseCount = 0;
100 
101  QMap<QString, ArnClient*>::iterator i = _clientTab.begin();
102  while (i != _clientTab.end()) {
103  if (i.value() == client) {
104  i = _clientTab.erase(i);
105  ++eraseCount;
106  }
107  else
108  ++i;
109  }
110  return eraseCount;
111 }
112 
113 
115 {
116  static ArnClientReg in;
117 
118  return in;
119 }
120 
121 
122 
123 ArnClientPrivate::ArnClientPrivate()
124 {
125  _arnMountPoint = arnNullptr;
126  _isAutoConnect = false;
127  _isValidCredent = false;
128  _isClosed = true;
129  _receiveTimeout = 10;
130  _recTimeoutCount = 0;
131  _retryTime = 2;
132  _port = 0;
133  _nextHost = -1;
134  _curPrio = -1;
136  resetConnectionFlags();
137 
138  _socket = new QTcpSocket;
139  _arnNetSync = new ArnSync( _socket, true, arnNullptr);
140  _arnNetSync->setClientSyncMode( _syncMode);
141  _arnNetSync->start();
142  _connectTimer = new QTimer;
143  _recTimer = new QTimer;
144 }
145 
146 
147 ArnClientPrivate::~ArnClientPrivate()
148 {
149  delete _socket;
150  delete _arnNetSync;
151  delete _connectTimer;
152  delete _recTimer;
153 }
154 
155 
156 void ArnClientPrivate::resetConnectionFlags()
157 {
158  _isReContact = false;
159  _isReConnect = false;
160  _wasContact = false;
161  _wasConnect = false;
162 }
163 
164 
165 void ArnClientPrivate::clearArnList( int prioFilter)
166 {
167  if (_nextHost > 0)
168  _nextHost = 0;
169 
170  if ((prioFilter < 0) || _hostTab.isEmpty()) {
171  _hostTab.clear();
172  _hostPrioTab.clear();
173  return;
174  }
175 
176  int index = -1;
177  forever {
178  index = _hostPrioTab.indexOf( prioFilter, index + 1);
179  if (index < 0) break;
180  _hostTab.removeAt( index);
181  _hostPrioTab.removeAt( index);
182  }
183 }
184 
185 
186 ArnClient::HostList ArnClientPrivate::arnList( int prioFilter) const
187 {
188  if ((prioFilter < 0) || _hostTab.isEmpty())
189  return _hostTab;
190 
191  ArnClient::HostList retVal;
192  int index = -1;
193  forever {
194  index = _hostPrioTab.indexOf( prioFilter, index + 1);
195  if (index < 0) break;
196  retVal += _hostTab.at( index);
197  }
198  return retVal;
199 }
200 
201 
202 void ArnClientPrivate::addToArnList( const QString& arnHost, quint16 port, int prio)
203 {
204  if (arnHost.isEmpty()) return; // Invalid
205 
207  slot.addr = arnHost;
208  slot.port = port ? port : Arn::defaultTcpPort;
209 
210  int index;
211  for (index = 0; index < _hostPrioTab.size(); ++index) {
212  if (prio < _hostPrioTab.at( index)) break; // Found place
213  }
214  _hostTab.insert( index, slot);
215  _hostPrioTab.insert( index, prio);
216 }
217 
218 
219 void ArnClient::init()
220 {
221  Q_D(ArnClient);
222 
223  QString stdId = "std";
224  if (ArnClientReg::instance().store( this, stdId)) // Only use std-id once
225  d->_id = stdId;
226 
227  ArnSync* arnSync = d->_arnNetSync;
228  QTcpSocket* socket = d->_socket;
229  arnSync->setSessionHandler( this);
230  arnSync->setToRemotePathCB( &toRemotePathCB);
231  connect( socket, SIGNAL(connected()), this, SLOT(doTcpConnected()));
232  connect( socket, SIGNAL(disconnected()), this, SLOT(doTcpDisconnected()));
233  connect( arnSync, SIGNAL(loginRequired(int)), this, SLOT(doLoginRequired(int)));
234  connect( arnSync, SIGNAL(stateChanged(int)), this, SLOT(doSyncStateChanged(int)));
235  connect( arnSync, SIGNAL(replyRecord(Arn::XStringMap&)), this, SLOT(doReplyRecord(Arn::XStringMap&)));
236  connect( arnSync, SIGNAL(replyRecord(Arn::XStringMap&)), this, SIGNAL(replyRecord(Arn::XStringMap&)));
237  connect( arnSync, SIGNAL(xcomDelete(QString)), this, SLOT(onCommandDelete(QString)));
238  connect( arnSync, SIGNAL(messageReceived(int,QByteArray)),
239  this, SLOT(onMessageReceived(int,QByteArray)));
240  connect( d->_recTimer, SIGNAL(timeout()), this, SLOT(doRecTimeout()));
241  connect( socket, SIGNAL(readyRead()), this, SLOT(doRecNotified()));
242 #if (QT_VERSION >= QT_VERSION_CHECK( 5, 15, 0))
243  connect( socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
244  this, SLOT(doTcpError(QAbstractSocket::SocketError)));
245 #else
246  connect( socket, SIGNAL(error(QAbstractSocket::SocketError)),
247  this, SLOT(doTcpError(QAbstractSocket::SocketError)));
248 #endif
249  connect( d->_connectTimer, SIGNAL(timeout()), this, SLOT(onConnectWaitDone()));
250 }
251 
252 
253 ArnClient::ArnClient( QObject* parent)
254  : QObject( parent)
255  , d_ptr( new ArnClientPrivate)
256 {
257  init();
258 }
259 
260 
261 ArnClient::ArnClient( ArnClientPrivate& dd, QObject* parent)
262  : QObject( parent)
263  , d_ptr( &dd)
264 {
265  init();
266 }
267 
268 
270 {
271  ArnClientReg::instance().remove( this); // If registered, remove it
272 
273  delete d_ptr;
274 }
275 
276 
277 void ArnClient::clearArnList( int prioFilter)
278 {
279  Q_D(ArnClient);
280 
281  d->clearArnList( prioFilter);
282 }
283 
284 
286 {
287  Q_D(const ArnClient);
288 
289  return d->arnList( prioFilter);
290 }
291 
292 
293 void ArnClient::addToArnList( const QString &arnHost, quint16 port, int prio)
294 {
295  Q_D(ArnClient);
296 
297  d->addToArnList( arnHost, port, prio);
298 }
299 
300 
302 {
303  Q_D(ArnClient);
304 
305  if (d->_hostTab.isEmpty()) return;
306 
307  d->_isValidCredent = false;
308  d->_nextHost = 0;
309  d->resetConnectionFlags();
310  startConnectArn();
311 }
312 
313 
314 void ArnClient::connectToArn( const QString& arnHost, quint16 port)
315 {
316  Q_D(ArnClient);
317 
318  d->_isValidCredent = false;
319  d->_nextHost = -1;
320  d->_arnHost = arnHost;
321  d->_port = port ? port : Arn::defaultTcpPort;
322  d->resetConnectionFlags();
323  startConnectArn();
324 }
325 
326 
328 {
329  Q_D(ArnClient);
330 
331  d->_arnNetSync->sendExit();
332  setAutoConnect( false);
333  d->_socket->disconnectFromHost();
334  d->_isClosed = true;
335 }
336 
337 
338 void ArnClient::loginToArn( const QString& userName, const QString& password, Arn::Allow allow)
339 {
340  QString pwHash = passwordHash( password);
341  loginToArnHashed( userName, pwHash, allow);
342 }
343 
344 
345 void ArnClient::loginToArnHashed( const QString& userName, const QString& passwordHashed, Arn::Allow allow)
346 {
347  Q_D(ArnClient);
348 
349  d->_isValidCredent = !userName.isEmpty();
350  d->_arnNetSync->loginToArn( userName, passwordHashed, allow);
351 }
352 
353 
355 {
356  Q_D(ArnClient);
357 
358  setAutoConnect( false);
359  d->_arnNetSync->close();
360  d->_isClosed = true;
361 }
362 
363 
365 {
366  Q_D(const ArnClient);
367 
368  return d->_connectStat;
369 }
370 
371 
372 bool ArnClient::setMountPoint( const QString& path)
373 {
374  Q_D(ArnClient);
375 
376  QMutexLocker locker( &d->_mutex);
377 
378  if (d->_mountPoints.size() == 1)
379  removeMountPointNL( d->_mountPoints.at(0).localPath);
380 
381  return addMountPointNL( path, QString());
382 }
383 
384 
385 bool ArnClient::addMountPoint( const QString& localPath, const QString& remotePath)
386 {
387  Q_D(ArnClient);
388 
389  d->_mutex.lock();
390  bool retVal = addMountPointNL( localPath, remotePath);
391  d->_mutex.unlock();
392 
393  return retVal;
394 }
395 
396 
397 bool ArnClient::addMountPointNL( const QString& localPath, const QString& remotePath)
398 {
399  Q_D(ArnClient);
400 
401  if (Arn::debugShareObj) qDebug() << "Adding mount point: localPath=" << localPath
402  << " remotePath=" << remotePath;
403  if (localPath.isEmpty()) {
404  return false;
405  }
406  QString localPath_ = Arn::fullPath( localPath);
407 
409  foreach (const MountPointSlot& mpSlot, d->_mountPoints) {
410  QString mplPath = mpSlot.localPath;
411  if (localPath_.startsWith( mplPath) || mplPath.startsWith( localPath_)) {
412  ArnM::errorLog( QString(tr("Mount points not exclusive: new=")) +
413  localPath + " existing=" + mplPath,
415  return false;
416  }
417  }
418 
419  MountPointSlot mpSlot;
420  mpSlot.arnMountPoint = new ArnItemNetEar( this);
421  bool isOk = mpSlot.arnMountPoint->openFolder( localPath_);
422  if (isOk) {
423  mpSlot.localPath = localPath_;
424  mpSlot.remotePath = remotePath.isEmpty() ? localPath_ : Arn::fullPath( remotePath);
425  connect( mpSlot.arnMountPoint, SIGNAL(arnItemCreated(QString)), this, SLOT(createNewItem(QString)));
426  connect( mpSlot.arnMountPoint, SIGNAL(arnTreeCreated(QString)),
427  this, SLOT(doCreateArnTree(QString)));
428  connect( mpSlot.arnMountPoint, SIGNAL(arnTreeDestroyed(QString,bool)),
429  this, SLOT(doDestroyArnTree(QString,bool)));
430  d->_mountPoints += mpSlot;
431  mpSlot.arnMountPoint->setReference( &d->_mountPoints.last()); // Give a ref to this added slot
432  }
433  else
434  delete mpSlot.arnMountPoint;
435 
436  return isOk;
437 }
438 
439 
440 bool ArnClient::removeMountPoint( const QString& localPath)
441 {
442  Q_D(ArnClient);
443 
444  d->_mutex.lock();
445  bool retVal = removeMountPointNL( localPath);
446  d->_mutex.unlock();
447 
448  return retVal;
449 }
450 
451 
452 bool ArnClient::removeMountPointNL( const QString& localPath)
453 {
454  Q_D(ArnClient);
455 
456  QString localPath_ = Arn::fullPath( localPath);
457 
458  int mpSize = d->_mountPoints.size();
459  for (int i = 0; i < mpSize; ++ i) {
460  const MountPointSlot& mountPoint = d->_mountPoints.at(i);
461  if (mountPoint.localPath == localPath_) {
462  if (mountPoint.arnMountPoint)
463  delete mountPoint.arnMountPoint;
464  d->_mountPoints.removeAt(i);
465  return true;
466  }
467  }
468  return false;
469 }
470 
471 
472 void ArnClient::setAutoConnect( bool isAuto, int retryTime)
473 {
474  Q_D(ArnClient);
475 
476  d->_isAutoConnect = isAuto;
477  d->_retryTime = retryTime > 1 ? retryTime : 1;
478 }
479 
480 
481 void ArnClient::registerClient( const QString& id)
482 {
483  Q_D(ArnClient);
484 
485  d->_id = id;
488  ArnClientReg::instance().store( this, id);
489 }
490 
491 
492 ArnClient* ArnClient::getClient( const QString& id)
493 {
494  return ArnClientReg::instance().get( id);
495 }
496 
497 
498 QString ArnClient::id() const
499 {
500  Q_D(const ArnClient);
501 
502  return d->_id;
503 }
504 
505 
507 {
508  Q_D(const ArnClient);
509 
510  return d->_receiveTimeout;
511 }
512 
513 
514 void ArnClient::setReceiveTimeout( int receiveTimeout)
515 {
516  Q_D(ArnClient);
517 
518  d->_receiveTimeout = receiveTimeout;
519 }
520 
521 
523 {
524  Q_D(const ArnClient);
525 
526  return d->_arnNetSync->isDemandLogin();
527 }
528 
529 
530 void ArnClient::setDemandLogin( bool isDemandLogin)
531 {
532  Q_D(ArnClient);
533 
534  d->_arnNetSync->setDemandLogin( isDemandLogin);
535 }
536 
537 
539 {
540  Q_D(const ArnClient);
541 
542  return d->_syncMode;
543 }
544 
545 
547 {
548  Q_D(ArnClient);
549 
550  if (syncMode != SyncMode::Invalid) {
551  d->_syncMode = syncMode;
552  d->_arnNetSync->setClientSyncMode( syncMode);
553  }
554 }
555 
556 
557 QString ArnClient::passwordHash( const QString& password)
558 {
559  return ArnSyncLogin::passwordHash( password);
560 }
561 
562 
563 QStringList ArnClient::freePaths() const
564 {
565  Q_D(const ArnClient);
566 
567  return d->_arnNetSync->freePaths();
568 }
569 
570 
571 void ArnClient::setWhoIAm( const Arn::XStringMap& whoIAmXsm)
572 {
573  Q_D(ArnClient);
574 
575  d->_arnNetSync->setWhoIAm( whoIAmXsm.toXString());
576 }
577 
578 
580 {
581  Q_D(const ArnClient);
582 
583  return XStringMap( d->_arnNetSync->remoteWhoIAm());
584 }
585 
586 
588 {
589  Q_D(const ArnClient);
590 
591  return d->_isReContact;
592 }
593 
594 
596 {
597  Q_D(const ArnClient);
598 
599  return d->_isReConnect;
600 }
601 
602 
603 int ArnClient::curPrio() const
604 {
605  Q_D(const ArnClient);
606 
607  return d->_curPrio;
608 }
609 
610 
611 void ArnClient::chatSend( const QString& text, int prioType)
612 {
613  Q_D(ArnClient);
614 
615  d->_arnNetSync->sendMessage( prioType == 1 ? ArnSync::MessageType::ChatPrio
616  : ArnSync::MessageType::ChatNormal,
617  text.toUtf8());
618 }
619 
620 
622 {
623  Q_D(ArnClient);
624 
625  d->_arnNetSync->sendMessage( ArnSync::MessageType::AbortKillRequest);
626 }
627 
628 
629 bool ArnClient::getTraffic( quint64& in, quint64& out) const
630 {
631  Q_D(const ArnClient);
632 
633  d->_arnNetSync->getTraffic( in, out);
634  return true;
635 }
636 
637 
638 void ArnClient::commandGet( const QString& path)
639 {
640  Q_D(ArnClient);
641 
642  d->_commandMap.clear();
643  d->_commandMap.add(ARNRECNAME, "get").add("path", path);
644 
645  d->_arnNetSync->sendXSMap( d->_commandMap);
646 }
647 
648 
649 void ArnClient::commandSet( const QString& path, const QString& data)
650 {
651  Q_D(ArnClient);
652 
653  d->_commandMap.clear();
654  d->_commandMap.add(ARNRECNAME, "set").add("path", path).add("data", data);
655 
656  d->_arnNetSync->sendXSMap( d->_commandMap);
657 }
658 
659 
660 void ArnClient::commandLs( const QString& path)
661 {
662  Q_D(ArnClient);
663 
664  d->_commandMap.clear();
665  d->_commandMap.add(ARNRECNAME, "ls").add("path", path);
666 
667  // qDebug() << "client-ls: path=" << path;
668  d->_arnNetSync->sendXSMap( d->_commandMap);
669 }
670 
671 
672 void ArnClient::commandInfo( int type, const QByteArray& data)
673 {
674  Q_D(ArnClient);
675 
676  if (type < Arn::InfoType::N)
677  d->_arnNetSync->sendInfo( type, data);
678 }
679 
680 
681 void ArnClient::commandVersion()
682 {
683  Q_D(ArnClient);
684 
685  d->_commandMap.clear();
686  d->_commandMap.add(ARNRECNAME, "ver");
687 
688  d->_arnNetSync->sendXSMap( d->_commandMap);
689 }
690 
691 
692 void ArnClient::newNetItemProxy( ArnThreadCom *threadCom,
693  const QString &path, int syncMode, void* isNewPtr)
694 {
695  ArnThreadComProxyLock proxyLock( threadCom);
696 
697  if (Arn::debugThreading) qDebug() << "newNetItemProxy: path=" << path;
698  threadCom->_retObj = newNetItem( path, Arn::ObjectSyncMode::fromInt( syncMode), (bool*) isNewPtr);
699  if (Arn::debugThreading) qDebug() << "newNetItemProxy: waking thread";
700 }
701 
702 
703 bool ArnClient::getLocalRemotePath( const QString& path,
704  QString& localMountPath, QString& remoteMountPath)
705 {
706  Q_D(ArnClient);
707 
708  QMutexLocker locker( &d->_mutex);
709 
710  bool retVal = false;
711  QString path_ = Arn::fullPath( path);
712  MountPointSlot mpSlot;
713  foreach (const MountPointSlot& mountPoint, d->_mountPoints) {
714  if (path_.startsWith( mountPoint.localPath)) {
715  mpSlot = mountPoint;
716  retVal = true;
717  break;
718  }
719  }
720  localMountPath = mpSlot.localPath;
721  remoteMountPath = mpSlot.remotePath;
722 
723  return retVal;
724 }
725 
726 
727 QString ArnClient::toRemotePathCB( void* context, const QString& path)
728 {
729  ArnClient* that = static_cast<ArnClient*>( context);
730  Q_ASSERT(that);
731 
732  QString localMountPath;
733  QString remoteMountPath;
734  that->getLocalRemotePath( path, localMountPath, remoteMountPath);
735 
736  return Arn::changeBasePath( localMountPath,remoteMountPath, path);
737 }
738 
739 
740 ArnItemNet* ArnClient::newNetItem( const QString& path, Arn::ObjectSyncMode syncMode, bool* isNewPtr)
741 {
742  Q_D(ArnClient);
743 
744  if (ArnM::isMainThread()) {
745  QString path_ = Arn::fullPath( path);
746  return d->_arnNetSync->newNetItem( path_, syncMode, isNewPtr);
747  }
748  else { // Threaded - must be threadsafe
749  ArnThreadComCaller threadCom;
750 
751  threadCom.p()->_retObj = arnNullptr; // Just in case ...
752  if (Arn::debugThreading) qDebug() << "newNetItem-thread: start path=" << path;
753  QMetaObject::invokeMethod( this,
754  "newNetItemProxy",
755  Qt::QueuedConnection,
756  Q_ARG( ArnThreadCom*, threadCom.p()),
757  Q_ARG( QString, path),
758  Q_ARG( int, syncMode.toInt()),
759  Q_ARG( void*, isNewPtr));
760  threadCom.waitCommandEnd(); // Wait main-thread gives retObj
761  ArnItemNet* retItemNet = static_cast<ArnItemNet*>( threadCom.p()->_retObj);
762  if (retItemNet) if (Arn::debugThreading) qDebug() << "newNetItem-thread: end path=" << retItemNet->path();
763 
764  return retItemNet;
765  }
766 }
767 
768 
769 void ArnClient::createNewItem( const QString& path)
770 {
771  Q_D(ArnClient);
772 
773  // qDebug() << "ArnClient,ArnItem-created: path=" << path;
774 
775  d->_arnNetSync->newNetItem( path);
776 }
777 
778 
779 void ArnClient::doCreateArnTree( const QString& path)
780 {
781  Q_D(ArnClient);
782 
783  // qDebug() << "ArnClient,CreateArnTree: path=" << path;
784  ArnItemNetEar* item = qobject_cast<ArnItemNetEar*>( sender());
785  Q_ASSERT(item);
786  MountPointSlot* mpSlot = static_cast<MountPointSlot*>( item->reference());
787  Q_ASSERT(mpSlot);
788 
789  QString remotePath = Arn::changeBasePath( mpSlot->localPath, mpSlot->remotePath, path);
790  d->_arnNetSync->sendSetTree( remotePath);
791 }
792 
793 
794 void ArnClient::doDestroyArnTree( const QString& path, bool isGlobal)
795 {
796  Q_D(ArnClient);
797 
798  // qDebug() << "ArnClient,DestroyArnTree: path=" << path;
799  ArnItemNetEar* item = qobject_cast<ArnItemNetEar*>( sender());
800  Q_ASSERT(item);
801  MountPointSlot* mpSlot = static_cast<MountPointSlot*>( item->reference());
802  Q_ASSERT(mpSlot);
803 
804  QString remotePath = Arn::changeBasePath( mpSlot->localPath, mpSlot->remotePath, path);
805  if (isGlobal)
806  d->_arnNetSync->sendDelete( remotePath);
807  else
808  d->_arnNetSync->sendNoSync( remotePath);
809 }
810 
811 
812 void ArnClient::doTcpError( QAbstractSocket::SocketError socketError)
813 {
814  Q_D(ArnClient);
815 
816  d->_recTimer->stop();
817 
818  QMetaObject::invokeMethod( this,
819  "doTcpError",
820  Qt::QueuedConnection,
821  Q_ARG( int, socketError));
822 }
823 
824 
825 void ArnClient::doTcpError( int socketError)
826 {
827  Q_D(ArnClient);
828 
829  // qDebug() << "ArnClient TcpError: hostAddr=" << _curConnectAP.addr;
830  QString errTextSum = QString(tr("TCP Client Msg:")) + d->_socket->errorString();
832 
833  if (d->_connectStat != ConnectStat::Disconnected) {
834  d->_connectStat = ( (d->_connectStat == ConnectStat::Connected)
835  || (d->_connectStat == ConnectStat::Stopped)
836  || (d->_connectStat == ConnectStat::Negotiating))
839  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
840 
841  if (d->_connectStat == ConnectStat::Error)
842  emit tcpError( d->_socket->errorString(), QAbstractSocket::SocketError( socketError));
843  else if (d->_connectStat == ConnectStat::Disconnected)
844  emit tcpDisConnected();
845 
846  reConnectArn();
847  }
848 }
849 
850 
851 void ArnClient::doTcpDisconnected()
852 {
853  Q_D(ArnClient);
854 
855  // qDebug() << "ArnClient TcpDisconnected: hostAddr=" << _curConnectAP.addr;
856  d->_recTimer->stop();
857 
858  if ((d->_connectStat == ConnectStat::Connected)
859  || (d->_connectStat == ConnectStat::Stopped)
860  || (d->_connectStat == ConnectStat::Negotiating))
861  {
862  d->_connectStat = ConnectStat::Disconnected;
863  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
864  emit tcpDisConnected();
865 
866  reConnectArn();
867  }
868 }
869 
870 
871 void ArnClient::startConnectArn()
872 {
873  Q_D(ArnClient);
874 
875  d->_isClosed = false;
876  doConnectArnLogic();
877 }
878 
879 
880 void ArnClient::reConnectArn()
881 {
882  Q_D(ArnClient);
883 
884  // qDebug() << " reConnectArn";
885  bool wantDelayConnect = true;
886  if (d->_nextHost >= 0) { // Using connection list
887  doConnectArnLogic();
888  wantDelayConnect = d->_nextHost == 0; // WantDelay when tried all in connection list
889  }
890 
891  if (wantDelayConnect && d->_isAutoConnect) {
892  d->_connectTimer->start( d->_retryTime * 1000);
893  }
894 }
895 
896 
897 void ArnClient::onConnectWaitDone()
898 {
899  Q_D(ArnClient);
900 
901  d->_connectTimer->stop();
902  doConnectArnLogic();
903 }
904 
905 
906 void ArnClient::doTcpConnected()
907 {
908  Q_D(ArnClient);
909 
910  if (d->_isClosed) { // Unexpected tcp connection, not wanted
911  d->_socket->abort();
912  return;
913  }
914 
915  d->_isReContact = d->_wasContact;
916  d->_wasContact = true;
917 
918  if ((d->_receiveTimeout > 0) && !Arn::offHeartbeat)
919  d->_recTimer->start( d->_receiveTimeout * 1000 / 2);
920  d->_recTimeoutCount = 0;
921 
922  d->_arnNetSync->connected();
923 
924  emit tcpConnected( d->_curConnectAP.addr, d->_curConnectAP.port);
925  d->_connectStat = ConnectStat::Negotiating;
926  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
927 }
928 
929 
930 void ArnClient::doSyncStateChanged( int state)
931 {
932  Q_D(ArnClient);
933 
934  // qDebug() << "ArnClient sync state changed: state=" << state;
935  ArnSync::State syncState = ArnSync::State::fromInt( state);
936  if (syncState == syncState.Normal) {
937  // qDebug() << "ArnClient connected: remVer="
938  // << _arnNetSync->remoteVer(0) << _arnNetSync->remoteVer(1);
939  d->_isReConnect = d->_wasConnect;
940  d->_wasConnect = true;
941  d->_connectStat = ConnectStat::Connected;
942  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
943  }
944 }
945 
946 
947 void ArnClient::doRecNotified()
948 {
949  Q_D(ArnClient);
950 
951  if (d->_recTimer->isActive())
952  d->_recTimer->start();
953  d->_recTimeoutCount = 0;
954 
955  if (d->_connectStat == ConnectStat::Stopped) {
956  d->_connectStat = ConnectStat::Connected;
957  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
958  }
959 }
960 
961 
962 void ArnClient::doRecTimeout()
963 {
964  Q_D(ArnClient);
965 
966  ++d->_recTimeoutCount;
967 
968  if (d->_recTimeoutCount == 1) {
969  commandVersion(); // Use version command as a flow requester
970  }
971  else if (d->_recTimeoutCount == 6) {
972  d->_socket->abort();
973  }
974 
975  if (d->_recTimeoutCount > 1) {
976  if (d->_connectStat == ConnectStat::Connected) {
977  d->_connectStat = ConnectStat::Stopped;
978  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
979  }
980  }
981 }
982 
983 
984 void ArnClient::onCommandDelete( const QString& remotePath)
985 {
986  Q_D(ArnClient);
987 
988  QMutexLocker locker( &d->_mutex);
989 
990  // qDebug() << "ArnClient-delete: remotePath=" << remotePath;
991  QString localPath;
992  foreach (const MountPointSlot& mountPoint, d->_mountPoints) {
993  if (remotePath.startsWith( mountPoint.remotePath)) {
994  localPath = Arn::changeBasePath( mountPoint.remotePath, mountPoint.localPath, remotePath);
995  break;
996  }
997  }
998  if (!localPath.isEmpty())
999  ArnM::destroyLink( localPath);
1000 }
1001 
1002 
1003 void ArnClient::onMessageReceived( int type, const QByteArray& data)
1004 {
1005  // XStringMap xmIn( data);
1006 
1007  switch (type) {
1009  case ArnSync::MessageType::KillRequest:
1010  emit killRequested();
1011  close();
1012  break;
1013  case ArnSync::MessageType::AbortKillRequest:
1014  // Not valid for client
1015  break;
1016  case ArnSync::MessageType::ChatPrio:
1017  emit chatReceived( QString::fromUtf8( data.constData(), data.size()), 1);
1018  break;
1019  case ArnSync::MessageType::ChatNormal:
1020  emit chatReceived( QString::fromUtf8( data.constData(), data.size()), 2);
1021  break;
1022  default:;
1023  // Not supported message-type.
1024  }
1025 }
1026 
1027 
1028 void ArnClient::doConnectArnLogic()
1029 {
1030  Q_D(ArnClient);
1031 
1032  QString arnHost;
1033  quint16 port = 0;
1034  int curPrio = -1;
1035  d->_curPrio = curPrio;
1036 
1037  if (d->_nextHost < 0) { // Normal single host connect
1038  arnHost = d->_arnHost;
1039  port = d->_port;
1040  }
1041  else if (!d->_hostTab.isEmpty()) { // Arn connection list
1042  if (d->_nextHost >= d->_hostTab.size()) { // Past end of list, restart
1043  d->_nextHost = 0;
1045  return;
1046  }
1047 
1048  const HostAddrPort& slot = d->_hostTab.at( d->_nextHost);
1049  arnHost = slot.addr;
1050  port = slot.port;
1051  curPrio = d->_hostPrioTab.at( d->_nextHost);
1052  // qDebug() << "ArnClient connectlogic: hostTabSize=" << _hostTab.size() << " index=" << _nextHost
1053  // << " prio=" << _hostPrioTab.at( _nextHost);
1054  ++d->_nextHost;
1055  }
1056 
1057  if (arnHost.isEmpty()) return;
1058 
1059  if (port == 0)
1060  port = Arn::defaultTcpPort;
1061 
1062  d->_socket->abort();
1063  d->_socket->connectToHost( Arn::hostFromHostWithInfo( arnHost), port);
1064  d->_curConnectAP.addr = arnHost;
1065  d->_curConnectAP.port = port;
1066  d->_curPrio = curPrio;
1067  d->_connectStat = ConnectStat::Connecting;
1068 
1069  d->_arnNetSync->connectStarted();
1070  emit connectionStatusChanged( d->_connectStat, d->_curPrio);
1071 }
1072 
1073 
1074 void ArnClient::doReplyRecord( XStringMap& replyMap)
1075 {
1076  QByteArray reply = replyMap.value(0);
1077 
1078  if (reply == "Rget") {
1079  emit replyGet( replyMap.valueString("data"), replyMap.valueString("path"));
1080  }
1081  else if (reply == "Rls") {
1082  emit replyLs( makeItemList( replyMap), replyMap.valueString("path"));
1083  }
1084  else if (reply == "Rinfo") {
1085  int type = replyMap.value("type", "-1").toInt();
1086  QByteArray data = replyMap.value("data");
1087  emit replyInfo( type, data);
1088  }
1089  else if (reply == "Rver") {
1090  QString ver = replyMap.valueString("ver", "1.0"); // ver key only after version 1.0
1091  QString type = replyMap.valueString("type", "ArnNetSync");
1092  emit replyVer( type + " ver " + ver);
1093  }
1094 }
1095 
1096 
1097 void ArnClient::doLoginRequired( int contextCode)
1098 {
1099  Q_D(ArnClient);
1100 
1101  if (d->_isValidCredent && (contextCode == 0)) // First login for this TCP session
1102  d->_arnNetSync->loginToArn(); // Try to use last credentials
1103  else {
1104  d->_isValidCredent = false;
1105  emit loginRequired( contextCode);
1106  }
1107 }
1108 
1109 
1110 QStringList ArnClient::makeItemList( XStringMap& xsMap)
1111 {
1112  QStringList items;
1113  int n = xsMap.maxEnumOf("item");
1114 
1115  for (int i = 1; i <= n; ++i) {
1116  items << xsMap.valueString( "item", uint(i));
1117  }
1118 
1119  return items;
1120 }
bool debugThreading
Definition: ArnLib.cpp:38
int maxEnumOf(const char *keyPrefix) const
QString hostFromHostWithInfo(const QString &hostWithInfo)
Get the host from the HostWithInfo string.
Definition: Arn.cpp:242
HostList arnList(int prioFilter=-1) const
Return the Arn connection list.
Definition: ArnClient.cpp:285
bool getTraffic(quint64 &in, quint64 &out) const
Get traffic metrics.
Definition: ArnClient.cpp:629
static bool isMainThread()
Definition: ArnM.cpp:379
void tcpDisConnected()
Signal emitted when the tcp connection is broken (has been successfull).
void loginToArn(const QString &userName, const QString &password, Arn::Allow allow=Arn::Allow::All)
Login to an Arn Server
Definition: ArnClient.cpp:338
void killRequested()
Signal emitted when the server request this client to kill its connection.
No data flow within set timeout (still connected)
Definition: ArnClient.hpp:63
bool offHeartbeat
Definition: ArnLib.cpp:52
Unsuccessfull when trying to connect to an Arn host.
Definition: ArnClient.hpp:65
void tcpConnected(const QString &arnHost, quint16 port)
Signal emitted when the tcp connection is successfull.
int remove(const QString &id)
Definition: ArnClient.cpp:87
Successfully connected to an Arn host.
Definition: ArnClient.hpp:61
bool isDemandLogin() const
Get clients demand for login.
Definition: ArnClient.cpp:522
void connectionStatusChanged(int status, int curPrio)
Signal emitted when the connection status is changed.
Arn::XStringMap remoteWhoIAm() const
Returns remote side (server) readable identification information.
Definition: ArnClient.cpp:579
void close()
Close sharing with an Arn Server
Definition: ArnClient.cpp:354
ConnectStat connectStatus() const
Return the Arn connection status.
Definition: ArnClient.cpp:364
#define ARNRECNAME
Definition: ArnSync.hpp:45
QList< HostAddrPort > HostList
Definition: ArnClient.hpp:121
Unsuccessfully tried to connect to all hosts in the Arn connection List.
Definition: ArnClient.hpp:69
QStringList freePaths() const
Returns current list of freePaths.
Definition: ArnClient.cpp:563
Container class with string representation for serialized data.
Definition: XStringMap.hpp:107
void setReceiveTimeout(int receiveTimeout)
Set receive data timeout (base time)
Definition: ArnClient.cpp:514
void setDemandLogin(bool isDemandLogin)
Set clients demand for login.
Definition: ArnClient.cpp:530
bool addMountPoint(const QString &localPath, const QString &remotePath=QString())
Add a sharing tree path.
Definition: ArnClient.cpp:385
QString fullPath(const QString &path)
Convert a path to a full absolute path.
Definition: Arn.cpp:82
TCP connection is broken (has been successfull)
Definition: ArnClient.hpp:67
bool isReConnect() const
Is last Arn Connection a reConnect.
Definition: ArnClient.cpp:595
bool isReContact() const
Is last TCP connection a reContact.
Definition: ArnClient.cpp:587
Value for Server, can not be set in Client.
Definition: Arn.hpp:158
void setAutoConnect(bool isAuto, int retryTime=2)
Set automatic reconnect.
Definition: ArnClient.cpp:472
The Client session Sync mode at connect & reconnect.
Definition: Arn.hpp:155
const quint16 defaultTcpPort
Definition: Arn.hpp:50
Negotiating terms and compatibility with an Arn host.
Definition: ArnClient.hpp:59
static ArnClientReg & instance()
Definition: ArnClient.cpp:114
void connectToArn(const QString &arnHost, quint16 port=0)
Connect to an Arn Server
Definition: ArnClient.cpp:314
void clearArnList(int prioFilter=-1)
Clear the Arn connection list.
Definition: ArnClient.cpp:277
void chatReceived(const QString &text, int prioType)
Signal emitted when a chat message is received from the server.
QByteArray value(int i, const char *def=arnNullptr) const
void connectToArnList()
Connect to an Arn Server in the Arn connection list.
Definition: ArnClient.cpp:301
void addToArnList(const QString &arnHost, quint16 port=0, int prio=0)
Add an Arn Server to the Arn connection list.
Definition: ArnClient.cpp:293
bool store(ArnClient *client, const QString &id)
Definition: ArnClient.cpp:66
QString changeBasePath(const QString &oldBasePath, const QString &newBasePath, const QString &path)
Change the base (start) of a path.
Definition: Arn.cpp:114
Class for connecting to an Arn Server.
Definition: ArnClient.hpp:104
QByteArray toXString() const
Trying to connect to an Arn host.
Definition: ArnClient.hpp:57
void disconnectFromArn()
Disconnect from an Arn Server
Definition: ArnClient.cpp:327
bool removeMountPoint(const QString &localPath)
Remove a sharing tree path.
Definition: ArnClient.cpp:440
static QString passwordHash(const QString &password)
Generate a hashed password from clear text password.
Definition: ArnClient.cpp:557
void loginToArnHashed(const QString &userName, const QString &passwordHashed, Arn::Allow allow=Arn::Allow::All)
Login to an Arn Server using hashed password.
Definition: ArnClient.cpp:345
QString id() const
Get the id of this client.
Definition: ArnClient.cpp:498
QString valueString(int i, const QString &def=QString()) const
ArnClient * get(const QString &id)
Definition: ArnClient.cpp:79
void setWhoIAm(const Arn::XStringMap &whoIAmXsm)
Set clients human readable identification information.
Definition: ArnClient.cpp:571
void tcpError(const QString &errorText, QAbstractSocket::SocketError socketError)
Signal emitted when a connection tcp error occur.
SyncMode syncMode() const
Get ClientSyncMode.
Definition: ArnClient.cpp:538
void chatSend(const QString &text, int prioType)
Send chat message to server.
Definition: ArnClient.cpp:611
bool debugShareObj
Definition: ArnLib.cpp:42
static void errorLog(QString errText, ArnError err=ArnError::Undef, void *reference=arnNullptr)
Definition: ArnM.cpp:1025
void abortKillRequest()
Send abort kill requst to server.
Definition: ArnClient.cpp:621
static void destroyLink(const QString &path, bool isGlobal=true)
Destroy the Arn Data Object at path
Definition: ArnM.cpp:853
int receiveTimeout() const
Get receive data timeout (base time)
Definition: ArnClient.cpp:506
bool setMountPoint(const QString &path)
Set the sharing tree path.
Definition: ArnClient.cpp:372
Default dynamic auto master mode, general purpose, prohibit Null value sync.
Definition: Arn.hpp:160
void loginRequired(int contextCode)
Signal emitted when the remote ArnServer demands a login.
void setSyncMode(SyncMode syncMode)
Set ClientSyncMode.
Definition: ArnClient.cpp:546
ArnClient(QObject *parent=arnNullptr)
Definition: ArnClient.cpp:253
static ArnClient * getClient(const QString &id)
Get a client by its id.
Definition: ArnClient.cpp:492
void registerClient(const QString &id)
Register this client to be avaiable with id.
Definition: ArnClient.cpp:481