Child: [8a6060] (diff)

Download this file

helloctl.cpp    145 lines (122 with data), 4.6 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// This libupnpp sample is the control side for the hellodevice sample
// device implementation
#include <string>
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <functional>
#include "libupnpp/upnpplib.hxx"
#include "libupnpp/soaphelp.hxx"
#include "libupnpp/control/discovery.hxx"
#include "libupnpp/control/device.hxx"
#include "libupnpp/control/service.hxx"
using namespace std;
using namespace std::placeholders;
// Locally defined control class for the Rendering Control
// service. We're just copying code from the libupnpp actually, this is
// just to show that it can be done outside the library.
class HelloCTL : public UPnPClient::Service {
public:
/* Construct by copying data from device and service objects.*/
HelloCTL(const UPnPClient::UPnPDeviceDesc& device,
const UPnPClient::UPnPServiceDesc& service)
: UPnPClient::Service(device, service) {
// No event handling. Look at, e.g. rdcvolume.cpp for an example
}
virtual ~HelloCTL() { }
/* Test that a service type matches ours. This can be used
with the directory traversal routine */
static bool isHelloService(const std::string& st) {
// Note that we do not care about the version
return st.find("urn:upnpp-schemas:service:HelloService") == 0;
}
int hello();
};
int HelloCTL::hello()
{
// Outgoing parameters. The object is constructed with the service
// type (comes from the description we were built on), and the
// action name. This is sufficient for some actions (ie stop())
UPnPP::SoapOutgoing args(getServiceType(), "Hello");
// This call does not need further outgoing arguments (see
// rdcvolume for an example of these.
// We have to declare a return parameter, even if we don't care
// about the contents.
UPnPP::SoapIncoming data;
int ret = runAction(args, data);
if (ret != UPNP_E_SUCCESS) {
return ret;
}
string value;
if (!data.get("MyValue", &value)) {
cerr << "HelloCTL:getVolume: missing MyValue in response\n";
return UPNP_E_BAD_RESPONSE;
}
cout << "Hello : " << value << endl;
return 0;
}
// Device discovery part. We do it the easy way here: use a blocking
// call which will wait for the initial window to complete. We could
// traverse the device directory in search, for example of a device of
// a specific kind instead of using a device name like we do here (there is
// an example of UPnPDeviceDirectory::traverse() usage in uplistdir.cpp).
//
// See rdcvolume.cpp for a version using callbacks to get the device asap
shared_ptr<HelloCTL> getService(const string& name)
{
// Initialize and get a discovery directory handle.
auto *superdir = UPnPClient::UPnPDeviceDirectory::getTheDir(1);
if (nullptr == superdir) {
cerr << "Discovery init failed\n";
return shared_ptr<HelloCTL>();
}
UPnPClient::UPnPDeviceDesc devicedesc;
// We look-up the device by either friendlyname or udn as the 2
// namespaces are unlikely to overlap, no need to complicate things
if (!superdir->getDevByUDN(name, devicedesc) &&
!superdir->getDevByFName(name, devicedesc)) {
cerr << "Can't connect to " << name << endl;
return shared_ptr<HelloCTL>();
}
// Walk the device description service list, looking for ours
for (const auto& ent : devicedesc.services) {
// cout << ent.dump() << endl;
if (HelloCTL::isHelloService(ent.serviceType)) {
return make_shared<HelloCTL>(devicedesc, ent);
}
}
cerr << name << " has no hello service\n";
return shared_ptr<HelloCTL>();
}
int main(int argc, char **argv)
{
// Initialize libupnpp logging
Logger::getTheLog("")->setLogLevel(Logger::LLERR);
argv++;argc--;
if (argc != 1) {
cerr << "Usage: rdcvolume rendererNameOrUid\n";
return 1;
}
string devname(*argv++);
argc--;
// Explicitely initialize libupnpp so that we can display a
// possible error
UPnPP::LibUPnP *mylib = UPnPP::LibUPnP::getLibUPnP();
if (!mylib) {
cerr << "Can't get LibUPnP" << endl;
return 1;
}
if (!mylib->ok()) {
cerr << "Lib init failed: " <<
mylib->errAsString("main", mylib->getInitError()) << endl;
return 1;
}
shared_ptr<HelloCTL> hlo = getService(devname);
if (!hlo) {
cerr << "Device " << devname <<
" has no Hello service" << endl;
return 1;
}
hlo->hello();
return 0;
}