Download this file

hellodevice.cpp    165 lines (139 with data), 5.4 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// A barebones example of device implementation.
//
// The skeleton code for the Service part could have been
// automatically generated by the scripts/sdeftoc.py (libupnpp source
// tree), from the xml description, but we did it by hand instead.
//
// This is a minimal example. Refer to, e.g. the upmpdcli code for a
// more complete exercise of the library.
#include <iostream>
#include <libupnpp/device/device.hxx>
#include <libupnpp/soaphelp.hxx>
#include <libupnpp/log.hxx>
using namespace std;
using namespace std::placeholders;
using namespace UPnPProvider;
using namespace UPnPP;
// Beware: these must match the values for serviceType and serviceId in the
// device description document
const string sTpHello("urn:upnpp-schemas:service:HelloService:1");
const string sIdHello("urn:upnpp-org:serviceId:HelloService");
// Device description document. This has some identifying data and a
// list of services.
// Beware: the UDN value must match the uuid parameter for the device
// constructor, and the SCDPURL paths must match the vdircontent paths
// (see below)
const string devicedesc(R"raw(<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion><major>1</major><minor>0</minor></specVersion>
<device>
<deviceType>urn:upnpp-schemas:device:HelloDevice:1</deviceType>
<friendlyName>HelloDeviceName</friendlyName>
<manufacturer>HelloDevices</manufacturer>
<modelName>SimpleHelloDevice</modelName>
<modelNumber>1.0</modelNumber>
<UDN>uuid:you-should-find-something-better</UDN>
<serviceList>
<service>
<serviceType>urn:upnpp-schemas:service:HelloService:1</serviceType>
<serviceId>urn:upnpp-org:serviceId:HelloService</serviceId>
<SCPDURL>/hello/Hello.xml</SCPDURL>
<controlURL>/ctl/Hello</controlURL>
<eventSubURL>/evt/Hello</eventSubURL>
</service>
</serviceList>
</device>
<devicelist>
</devicelist>
</root>
)raw");
// Service description document. The variables and actions. Action
// names must match the name parameter to the addActionMapping calls
const string helloservicedesc(R"raw(<?xml version="1.0" encoding="utf-8"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
<specVersion><major>1</major><minor>1</minor></specVersion>
<actionList>
<action>
<name>Hello</name>
<argumentList>
<argument>
<name>MyValue</name>
<direction>out</direction>
<relatedStateVariable>Hello</relatedStateVariable>
</argument>
</argumentList>
</action>
</actionList>
<serviceStateTable>
<stateVariable sendEvents="no">
<name>Hello</name>
<dataType>string</dataType>
</stateVariable>
</serviceStateTable>
</scpd>
)raw");
// The files which will be served by the HTTP server. Refer to the
// comments in device.hxx for more details.
unordered_map<string, VDirContent> myfiles {
{"/hello/description.xml", {devicedesc, "text/xml"}},
{"/hello/Hello.xml", {helloservicedesc, "text/xml"}},
};
// The service class defines the methods which will be called for each
// UPnP action (and the event handling, which is not shown here).
class HelloService : public UPnPProvider::UpnpService {
public:
// The constructor initializes the base class (which links to the
// device and lib), and sets our action callbacks.
HelloService(UpnpDevice *dev)
: UpnpService(sTpHello, sIdHello, dev), m_dev(dev) {
m_dev->addActionMapping(this, "Hello",
bind(&HelloService::hello, this, _1, _2));
}
// Event retrieval routine. This gets polled (the service can
// trigger an immediate poll). We're not really doing this, look
// at how upmpdcli openhome services do it
virtual bool getEventData(bool all, std::vector<std::string>& names,
std::vector<std::string>& values) {
return true;
}
private:
// An action method. This takes no argument, just returns a value.
// Look at upmpdcli code to see how to handle incoming parameters.
int hello(const SoapIncoming& sc, SoapOutgoing& data) {
data.addarg("MyValue", "World");
return UPNP_E_SUCCESS;
}
UpnpDevice *m_dev;
};
// The device initializes the parent class and creates its services
class HelloDevice : public UpnpDevice {
public:
HelloDevice(const string& deviceid,
const std::unordered_map<std::string, VDirContent>& files)
: UpnpDevice(deviceid, files) {
m_services.push_back(new HelloService(this));
}
~HelloDevice() {
for (auto& ent : m_services) {
delete ent;
}
}
vector<UpnpService*> m_services;
};
int main(int argc, char *argv[])
{
// Initialize libupnpp logging
Logger::getTheLog("")->setLogLevel(Logger::LLERR);
//cout << "DEVICE: " << devicedesc << endl;
//cout << "SERVICE: " << helloservicedesc << endl;
// uuid must match the one in the description document
HelloDevice dev("uuid:you-should-find-something-better", myfiles);
string host;
unsigned short port;
dev.ipv4(&host, &port);
// fname should match what we set in the desc above ! A real
// program would do it differently...
string fname("HelloDeviceName");
cout << fname << " running on host " << host << " port " << port << endl;
dev.eventloop();
}