2
* Copyright (C) 2010, 2011 Tuomo Penttinen, all rights reserved.
4
* Author: Tuomo Penttinen <tp@herqq.org>
6
* This file is part of Herqq UPnP (HUPnP) library.
8
* Herqq UPnP is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU Lesser General Public License as published by
10
* the Free Software Foundation, either version 3 of the License, or
11
* (at your option) any later version.
13
* Herqq UPnP is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with Herqq UPnP. If not, see <http://www.gnu.org/licenses/>.
22
#include "hdevicehost_ssdp_handler_p.h"
23
#include "hserverdevicecontroller_p.h"
25
#include "../../general/hupnp_global_p.h"
27
#include "../../dataelements/hudn.h"
28
#include "../../dataelements/hdeviceinfo.h"
29
#include "../../dataelements/hserviceinfo.h"
30
#include "../../dataelements/hdiscoverytype.h"
31
#include "../../dataelements/hproduct_tokens.h"
33
#include "../../devicemodel/hdevicestatus.h"
34
#include "../../devicemodel/server/hserverdevice.h"
35
#include "../../devicemodel/server/hserverservice.h"
37
#include "../../general/hlogger_p.h"
38
#include "../../utils/hsysutils_p.h"
40
#include <QtCore/QUuid>
41
#include <QtCore/QDateTime>
49
/*******************************************************************************
51
******************************************************************************/
52
HDelayedWriter::HDelayedWriter(
53
HDeviceHostSsdpHandler& ssdp,
54
const QList<HDiscoveryResponse>& responses,
55
const HEndpoint& source,
58
m_ssdp(ssdp), m_responses(responses), m_source(source), m_msecs(msecs)
62
void HDelayedWriter::timerEvent(QTimerEvent*)
64
HLOG2(H_AT, H_FUN, m_ssdp.loggingIdentifier());
65
foreach(const HDiscoveryResponse& resp, m_responses)
67
qint32 count = m_ssdp.sendDiscoveryResponse(resp, m_source);
70
HLOG_WARN(QString("Failed to send discovery response [%1] to: [%2].").arg(
71
resp.usn().toString(), m_source.toString()));
78
void HDelayedWriter::run()
83
/*******************************************************************************
84
* HDeviceHostSsdpHandler
85
******************************************************************************/
86
HDeviceHostSsdpHandler::HDeviceHostSsdpHandler(
87
const QByteArray& loggingIdentifier,
88
HDeviceStorage<HServerDevice, HServerService, HServerDeviceController>& ds,
90
HSsdp(loggingIdentifier, parent), m_deviceStorage(ds)
93
setFilter(DiscoveryRequest);
96
HDeviceHostSsdpHandler::~HDeviceHostSsdpHandler()
100
bool HDeviceHostSsdpHandler::processSearchRequest_specificDevice(
101
const HDiscoveryRequest& req, const HEndpoint& source,
102
QList<HDiscoveryResponse>* responses)
104
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
106
HDiscoveryType st = req.searchTarget();
107
QUuid uuid = st.udn().value();
110
HLOG_DBG(QString("Invalid device-UUID: [%1]").arg(st.udn().toString()));
114
const HServerDevice* device =
115
m_deviceStorage.searchDeviceByUdn(HUdn(uuid), AllDevices);
119
HLOG_DBG(QString("No device with the specified UUID: [%1]").arg(
126
if (!m_deviceStorage.searchValidLocation(device, source, &location))
129
"Found a device with uuid: [%1], but it is not "
130
"available on the interface that has address: [%2]").arg(
131
uuid.toString(), source.toString()));
136
const HServerDeviceController* controller =
137
m_deviceStorage.getController(device);
139
Q_ASSERT(controller);
141
responses->push_back(
143
controller->deviceTimeoutInSecs() * 2,
144
QDateTime::currentDateTime(),
146
HSysInfo::instance().herqqProductTokens(),
147
st, // the searched usn
148
device->deviceStatus().bootId(),
149
device->deviceStatus().configId()
155
bool HDeviceHostSsdpHandler::processSearchRequest_deviceType(
156
const HDiscoveryRequest& req, const HEndpoint& source,
157
QList<HDiscoveryResponse>* responses)
159
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
161
HDiscoveryType st = req.searchTarget();
163
QList<HServerDevice*> foundDevices =
164
m_deviceStorage.searchDevicesByDeviceType(
166
HResourceType::EqualOrGreater,
169
if (!foundDevices.size())
171
HLOG_DBG(QString("No devices match the specified type: [%1]").arg(
172
st.resourceType().toString()));
177
qint32 prevSize = responses->size();
178
foreach(const HServerDevice* device, foundDevices)
181
if (!m_deviceStorage.searchValidLocation(device, source, &location))
184
"Found a matching device, but it is not "
185
"available on the interface that has address: [%1]").arg(
191
st.setUdn(device->info().udn());
193
const HServerDeviceController* controller =
194
m_deviceStorage.getController(device);
196
Q_ASSERT(controller);
198
responses->push_back(
200
controller->deviceTimeoutInSecs() * 2,
201
QDateTime::currentDateTime(),
203
HSysInfo::instance().herqqProductTokens(),
205
device->deviceStatus().bootId(),
206
device->deviceStatus().configId()
210
return responses->size() > prevSize;
213
bool HDeviceHostSsdpHandler::processSearchRequest_serviceType(
214
const HDiscoveryRequest& req, const HEndpoint& source,
215
QList<HDiscoveryResponse>* responses)
217
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
219
HDiscoveryType st = req.searchTarget();
221
QList<HServerService*> foundServices =
222
m_deviceStorage.searchServicesByServiceType(
224
HResourceType::EqualOrGreater);
226
if (!foundServices.size())
229
"No services match the specified type: [%1]").arg(
230
st.resourceType().toString()));
235
qint32 prevSize = responses->size();
236
foreach(const HServerService* service, foundServices)
238
const HServerDevice* device = service->parentDevice();
242
if (!m_deviceStorage.searchValidLocation(device, source, &location))
245
"Found a matching device, but it is not "
246
"available on the interface that has address: [%1]").arg(
252
HDeviceInfo deviceInfo = device->info();
254
const HServerDevice* dc =
255
m_deviceStorage.searchDeviceByUdn(deviceInfo.udn(), AllDevices);
259
st.setUdn(deviceInfo.udn());
261
const HServerDeviceController* controller =
262
m_deviceStorage.getController(device);
264
Q_ASSERT(controller);
266
responses->push_back(
268
controller->deviceTimeoutInSecs() * 2,
269
QDateTime::currentDateTime(),
271
HSysInfo::instance().herqqProductTokens(),
273
dc->deviceStatus().bootId(),
274
dc->deviceStatus().configId()
278
return responses->size() > prevSize;
281
void HDeviceHostSsdpHandler::processSearchRequest(
282
const HServerDevice* device, const QUrl& location,
283
QList<HDiscoveryResponse>* responses)
285
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
288
HDeviceInfo deviceInfo = device->info();
289
HProductTokens pt = HSysInfo::instance().herqqProductTokens();
290
HDiscoveryType usn(deviceInfo.udn());
292
const HServerDeviceController* controller =
293
m_deviceStorage.getController(device);
295
Q_ASSERT(controller);
297
const HDeviceStatus& deviceStatus = device->deviceStatus();
300
responses->push_back(
302
controller->deviceTimeoutInSecs() * 2,
303
QDateTime::currentDateTime(), location, pt, usn,
304
deviceStatus.bootId(),
305
deviceStatus.configId()));
307
usn.setResourceType(deviceInfo.deviceType());
310
responses->push_back(
312
controller->deviceTimeoutInSecs() * 2,
313
QDateTime::currentDateTime(), location, pt, usn,
314
deviceStatus.bootId(),
315
deviceStatus.configId()));
317
const HServerServices& services = device->services();
318
foreach(const HServerService* service, services)
320
usn.setResourceType(service->info().serviceType());
322
responses->push_back(
324
controller->deviceTimeoutInSecs() * 2,
325
QDateTime::currentDateTime(), location, pt, usn,
326
deviceStatus.bootId(),
327
deviceStatus.configId()
331
const HServerDevices& devices = device->embeddedDevices();
332
foreach(const HServerDevice* embeddedDevice, devices)
334
processSearchRequest(embeddedDevice, location, responses);
338
bool HDeviceHostSsdpHandler::processSearchRequest_AllDevices(
339
const HDiscoveryRequest& /*req*/, const HEndpoint& source,
340
QList<HDiscoveryResponse>* responses)
342
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
345
const HProductTokens& pt = HSysInfo::instance().herqqProductTokens();
347
const HServerDevices& rootDevices = m_deviceStorage.rootDevices();
349
qint32 prevSize = responses->size();
350
foreach(const HServerDevice* rootDevice, rootDevices)
353
if (!m_deviceStorage.searchValidLocation(rootDevice, source, &location))
356
"Found a device, but it is not "
357
"available on the interface that has address: [%1]").arg(
363
HDiscoveryType usn(rootDevice->info().udn(), true);
365
const HServerDeviceController* controller =
366
m_deviceStorage.getController(rootDevice);
368
Q_ASSERT(controller);
370
responses->push_back(
372
controller->deviceTimeoutInSecs() * 2,
373
QDateTime::currentDateTime(),
377
rootDevice->deviceStatus().bootId(),
378
rootDevice->deviceStatus().configId()
381
processSearchRequest(rootDevice, location, responses);
383
const HServerDevices& devices = rootDevice->embeddedDevices();
384
foreach(const HServerDevice* embeddedDevice, devices)
386
if (!m_deviceStorage.searchValidLocation(
387
embeddedDevice, source, &location))
389
// highly uncommon, but possible; the root device is "active"
390
// on the network interface to which the request came,
391
// but at least one of its embedded devices is not.
394
"Skipping an embedded device that is not "
395
"available on the interface that has address: [%1]").arg(
401
processSearchRequest(embeddedDevice, location, responses);
405
return responses->size() > prevSize;
408
bool HDeviceHostSsdpHandler::processSearchRequest_RootDevice(
409
const HDiscoveryRequest& /*req*/, const HEndpoint& source,
410
QList<HDiscoveryResponse>* responses)
412
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
415
const HServerDevices& rootDevices = m_deviceStorage.rootDevices();
417
qint32 prevSize = responses->size();
418
foreach(const HServerDevice* rootDevice, rootDevices)
421
if (!m_deviceStorage.searchValidLocation(rootDevice, source, &location))
424
"Found a root device, but it is not "
425
"available on the interface that has address: [%1]").arg(
426
source.hostAddress().toString()));
431
HDiscoveryType usn(rootDevice->info().udn(), true);
433
const HServerDeviceController* controller =
434
m_deviceStorage.getController(rootDevice);
436
Q_ASSERT(controller);
438
responses->push_back(
440
controller->deviceTimeoutInSecs() * 2,
441
QDateTime::currentDateTime(),
443
HSysInfo::instance().herqqProductTokens(),
445
rootDevice->deviceStatus().bootId(),
446
rootDevice->deviceStatus().configId()));
449
return responses->size() > prevSize;
452
bool HDeviceHostSsdpHandler::incomingDiscoveryRequest(
453
const HDiscoveryRequest& msg, const HEndpoint& source,
454
DiscoveryRequestMethod requestType)
456
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
458
HLOG_DBG(QString("Received discovery request for [%1] from [%2]").arg(
459
msg.searchTarget().toString(), source.toString()));
462
QList<HDiscoveryResponse> responses;
463
switch (msg.searchTarget().type())
465
case HDiscoveryType::All:
466
ok = processSearchRequest_AllDevices(msg, source, &responses);
469
case HDiscoveryType::RootDevices:
470
ok = processSearchRequest_RootDevice(msg, source, &responses);
473
case HDiscoveryType::SpecificDevice:
474
ok = processSearchRequest_specificDevice(msg, source, &responses);
477
case HDiscoveryType::DeviceType:
478
ok = processSearchRequest_deviceType(msg, source, &responses);
481
case HDiscoveryType::ServiceType:
482
ok = processSearchRequest_serviceType(msg, source, &responses);
491
if (requestType == MulticastDiscovery)
493
HDelayedWriter* writer =
495
*this, responses, source, (qrand() % msg.mx()) * 1000);
498
connect(writer, SIGNAL(sent()), writer, SLOT(deleteLater()));
500
Q_ASSERT(ok); Q_UNUSED(ok)
506
foreach (const HDiscoveryResponse& resp, responses)
508
qint32 count = sendDiscoveryResponse(resp, source);
509
Q_ASSERT(count >= 0); Q_UNUSED(count)
516
"No resources found for discovery request [%1] from [%2]").arg(
517
msg.searchTarget().toString(), source.toString()));