ArnLib  4.0.x
Active Registry Network
ArnDiscoverRemote.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 
33 #include "private/ArnDiscoverRemote_p.hpp"
34 #include "ArnInc/ArnZeroConf.hpp"
35 #include "ArnInc/ArnServer.hpp"
36 #include "ArnInc/ArnM.hpp"
37 #include "ArnInc/ArnLib.hpp"
38 #include <QTimer>
39 #include <QMetaObject>
40 #include <QHostInfo>
41 #include <QNetworkInterface>
42 #include <QDir>
43 
44 
46 
47 ArnDiscoverRemotePrivate::ArnDiscoverRemotePrivate()
48 {
49  _servTimer = new QTimer;
50  _arnInternalServer = arnNullptr;
51  _arnDResolver = arnNullptr;
52  _defaultService = "Arn Default Service";
53  _initialServiceTimeout = 0;
54 }
55 
56 
57 ArnDiscoverRemotePrivate::~ArnDiscoverRemotePrivate()
58 {
59  delete _servTimer;
60 }
61 
62 
64  : ArnDiscoverAdvertise( *new ArnDiscoverRemotePrivate, parent)
65 {
66 }
67 
68 
69 ArnDiscoverRemote::ArnDiscoverRemote( ArnDiscoverRemotePrivate& dd, QObject* parent)
70  : ArnDiscoverAdvertise( dd, parent)
71 {
72 }
73 
74 
76 {
77 }
78 
79 
81 {
82  QHostAddress addr = arnServer->listenAddress();
83  QString listenAddr = ((addr == QHostAddress::Any) || (addr == QHostAddress::AnyIPv6))
84  ? QString("Any") : addr.toString();
85  int hostPort = arnServer->port();
86  ArnM::setValue( Arn::pathDiscoverThis + "Interfaces/Listen/value", listenAddr);
87  ArnM::setValue( Arn::pathDiscoverThis + "Host/value", QHostInfo::localHostName());
88  ArnM::setValue( Arn::pathDiscoverThis + "Host/Port/value", hostPort);
90 
92  QStringList hostIpList;
93  int i = 0;
94  foreach (QNetworkInterface interface, QNetworkInterface::allInterfaces()) {
95  QNetworkInterface::InterfaceFlags flags = interface.flags();
96  if (!flags.testFlag( QNetworkInterface::IsUp)
97  || flags.testFlag( QNetworkInterface::IsPointToPoint)
98  || flags.testFlag( QNetworkInterface::IsLoopBack))
99  continue;
100 
101  foreach (QNetworkAddressEntry entry, interface.addressEntries()) {
102  QAbstractSocket::NetworkLayerProtocol prot = entry.ip().protocol();
103  if ((prot != QAbstractSocket::IPv4Protocol) && (prot != QAbstractSocket::IPv6Protocol))
104  continue;
105 
106  QString path = (Arn::pathDiscoverThis + "Interfaces/Interf-%1/").arg(i);
107  QString addr = entry.ip().toString();
108  QString mask = entry.netmask().toString();
109  QString sysName = interface.humanReadableName();
110  ArnM::setValue( path + "addr", addr);
111  ArnM::setValue( path + "mask", mask);
112  ArnM::setValue( path + "sysName", sysName);
113  ArnM::setValue( path + "name", addr + " [" + sysName + "]");
114 
115  if (prot == QAbstractSocket::IPv4Protocol) {
116  hostIpList += addr;
117  }
118  ++i;
119  }
120  }
121 
122  // Setup advertise, but don't start yet, can be waiting for service name
123  ArnDiscoverAdvertise::setHostIpList( hostIpList);
124  ArnDiscoverAdvertise::advertiseService( discoverType, service(), hostPort);
125 }
126 
127 
129 {
130  Q_D(ArnDiscoverRemote);
131 
132  if (!d->_arnInternalServer)
133  delete d->_arnInternalServer;
134  d->_arnInternalServer = new ArnServer( ArnServer::Type::NetSync, this);
135  d->_arnInternalServer->start( port);
136 
137  startUseServer( d->_arnInternalServer, discoverType);
138 }
139 
140 
142 {
143  ArnDiscoverConnector* connector = new ArnDiscoverConnector( client, id);
144  connect( connector, SIGNAL(clientReadyToConnect(ArnClient*,QString)),
145  this, SIGNAL(clientReadyToConnect(ArnClient*,QString)));
146 
147  return connector;
148 }
149 
150 
151 void ArnDiscoverRemote::postSetupThis()
152 {
153  Q_D(ArnDiscoverRemote);
154 
155  d->_servTimer->start( d->_initialServiceTimeout * 1000); // If no service name set, give time for external setting ...
156  connect( d->_servTimer, SIGNAL(timeout()), this, SLOT(serviceTimeout()));
157 
158  connect( &d->_arnService, SIGNAL(changed(QString)), this, SLOT(firstServiceSetup(QString)));
159  connect( &d->_arnServicePv, SIGNAL(changed(QString)), this, SLOT(firstServiceSetup(QString)));
160  QString servicePath = Arn::pathDiscoverThis + "Service/value";
161  d->_arnServicePv.open( Arn::twinPath( servicePath));
162  d->_arnService.addMode( Arn::ObjectMode::Save);
163  d->_arnService.open( servicePath);
164  // Any loaded persistent service name has now been sent to firstServiceSetup()
165 
166  ArnDiscoverAdvertise::postSetupThis();
167 }
168 
169 
170 void ArnDiscoverRemote::serviceTimeout()
171 {
172  Q_D(ArnDiscoverRemote);
173 
174  if (Arn::debugDiscover) qDebug() << "First service setup timeout, using default.";
175 
176  firstServiceSetup( d->_defaultService, true);
177 }
178 
179 
180 void ArnDiscoverRemote::firstServiceSetup( const QString& serviceName, bool forceSetup)
181 {
182  Q_D(ArnDiscoverRemote);
183 
184  QString useService = service(); // Priority for any previous set service name
185  if (useService.isEmpty())
186  useService = serviceName;
187  if (Arn::debugDiscover) qDebug() << "firstServiceSetup: service=" << serviceName
188  << " useService=" << useService << " forceSetup=" << forceSetup;
189 
190  if (!forceSetup && useService.isEmpty()) return; // Try later (at timeout)
191 
192  d->_servTimer->stop();
193  disconnect( &d->_arnService, SIGNAL(changed(QString)), this, SLOT(firstServiceSetup(QString)));
194  disconnect( &d->_arnServicePv, SIGNAL(changed(QString)), this, SLOT(firstServiceSetup(QString)));
195  connect( &d->_arnServicePv, SIGNAL(changed(QString)), this, SLOT(doServiceChanged(QString)));
196 
197  setService( useService);
198 }
199 
200 
201 void ArnDiscoverRemote::doServiceChanged( const QString& val)
202 {
203  Q_D(ArnDiscoverRemote);
204 
205  if (Arn::debugDiscover) qDebug() << "DiscoverRemote Service changed: servname=" << val;
206  d->_arnServicePv = val;
207  ArnDiscoverAdvertise::setService( val.isEmpty() ? d->_defaultService : val);
208 }
209 
210 
211 void ArnDiscoverRemote::serviceRegistered( const QString& serviceName)
212 {
213  if (Arn::debugDiscover) qDebug() << "DiscoverRemote Service registered: serviceName=" << serviceName;
214 
215  ArnM::setValue( Arn::pathDiscoverThis + "UsingService/value", serviceName);
216 
217  ArnDiscoverAdvertise::serviceRegistered( serviceName);
218 }
219 
220 
221 void ArnDiscoverRemote::setService( const QString& service)
222 {
223  Q_D(ArnDiscoverRemote);
224 
225  if (Arn::debugDiscover) qDebug() << "DiscoverRemote setService: serviceName=" << service;
226 
227  if (hasSetupAdvertise()) {
228  bool isAdvertise = state().isAny( State::Advertise);
229  d->_arnService.setValue( service, isAdvertise ? Arn::SameValue::Ignore
231  // If advertising not yet has started, any value must trigger the "service changed logic"
232  }
233  else
235 }
236 
237 
239 {
240  Q_D(const ArnDiscoverRemote);
241 
242  return d->_defaultService;
243 }
244 
245 
246 void ArnDiscoverRemote::setDefaultService( const QString& defaultService)
247 {
248  Q_D(ArnDiscoverRemote);
249 
250  if (!defaultService.isEmpty())
251  d->_defaultService = defaultService;
252 }
253 
254 
256 {
257  Q_D(const ArnDiscoverRemote);
258 
259  return d->_initialServiceTimeout;
260 }
261 
262 
263 void ArnDiscoverRemote::setInitialServiceTimeout( int initialServiceTimeout)
264 {
265  Q_D(ArnDiscoverRemote);
266 
267  d->_initialServiceTimeout = initialServiceTimeout;
268 }
const QString pathDiscover
Definition: Arn.cpp:47
static void setValue(const QString &path, int value)
Assign an integer to an Arn Data Object at path
Definition: ArnM.cpp:473
QString defaultService() const
Return the default service name.
bool debugDiscover
Definition: ArnLib.cpp:48
void advertiseService(ArnDiscover::Type discoverType, const QString &serviceName, int port=-1, const QString &hostName=QString())
Start advertising the service.
void clientReadyToConnect(ArnClient *arnClient, const QString &id)
Central signal for external client connection.
const QString resourceArnRoot
Definition: ArnLib.cpp:55
Class for making an Arn Server.
Definition: ArnServer.hpp:98
void setInitialServiceTimeout(int initialServiceTimeout)
Set the time for initial timeout processing.
Advertise an Arn service.
Assigning same value generates an update of the Arn Data Object
Definition: Arn.hpp:64
static bool loadFromDirRoot(const QString &path, const QDir &dirRoot, Arn::Coding coding)
Load relative a directory root to an Arn Data Object at path
Definition: ArnM.cpp:556
int initialServiceTimeout() const
Return the time for initial timeout processing.
QString service() const
Returns the requested service name for this Advertise.
void startUseNewServer(ArnDiscover::Type discoverType, int port=-1)
Start a new ArnServer and advertise as a service.
Text coding, can be any character set.
Definition: Arn.hpp:201
Types of Arn discover advertise.
Definition: ArnDiscover.hpp:52
ArnDiscoverRemote(QObject *parent=arnNullptr)
Class for connecting to an Arn Server.
Definition: ArnClient.hpp:104
An automatic client discover connector.
void startUseServer(ArnServer *arnServer, ArnDiscover::Type discoverType=ArnDiscover::Type::Server)
Start advertising the ArnServer as a service.
QString twinPath(const QString &path)
Get the bidirectional twin to a given path
Definition: Arn.cpp:195
QHostAddress listenAddress()
Address of the interface used to listening for connections to the Arn server
Definition: ArnServer.cpp:254
virtual void setService(const QString &service)
Set the service name.
const QString pathDiscoverThis
Definition: Arn.cpp:48
ArnDiscoverConnector * newConnector(ArnClient &client, const QString &id)
Create and return an ArnDiscoverConnector for handling remote client.
int port()
Port number of the Arn server
Definition: ArnServer.cpp:246
Discover with remote setting.
State state() const
Returns the state for this Advertise.
Assigning same value is ignored.
Definition: Arn.hpp:66
isAny(): Startup advertising in progress or has finished sucessfully.
Data is persistent and will be saved.
Definition: Arn.hpp:130
void setDefaultService(const QString &defaultService)
Set the default service name.
virtual void setService(const QString &service)
Set the service name.