1
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
<title>Writing a UPnP Service</title>
6
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2">
7
<link rel="start" href="index.html" title="GUPnP Reference Manual">
8
<link rel="up" href="tutorial.html" title="Part I. Tutorial">
9
<link rel="prev" href="client-tutorial.html" title="Writing a UPnP Client">
10
<link rel="next" href="api.html" title="Part II. Reference">
11
<meta name="generator" content="GTK-Doc V1.10 (XML mode)">
12
<link rel="stylesheet" href="style.css" type="text/css">
13
<link rel="part" href="tutorial.html" title="Part I. Tutorial">
14
<link rel="chapter" href="overview.html" title="Overview">
15
<link rel="chapter" href="client-tutorial.html" title="Writing a UPnP Client">
16
<link rel="chapter" href="server-tutorial.html" title="Writing a UPnP Service">
17
<link rel="part" href="api.html" title="Part II. Reference">
18
<link rel="chapter" href="api-device-info.html" title="Device Information">
19
<link rel="chapter" href="api-device-control.html" title="Device Control">
20
<link rel="chapter" href="api-device-impl.html" title="Device Implementation">
21
<link rel="chapter" href="api-utility.html" title="Utility Functions">
22
<link rel="chapter" href="api-tools.html" title="Tools">
23
<link rel="part" href="schemas.html" title="Part III. XML Schemas">
24
<link rel="chapter" href="schemas-device.html" title="Device Description">
25
<link rel="chapter" href="schemas-service.html" title="Service Description">
26
<link rel="glossary" href="glossary.html" title="Glossary">
27
<link rel="index" href="ix01.html" title="Index">
29
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
30
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"><tr valign="middle">
31
<td><a accesskey="p" href="client-tutorial.html"><img src="left.png" width="24" height="24" border="0" alt="Prev"></a></td>
32
<td><a accesskey="u" href="tutorial.html"><img src="up.png" width="24" height="24" border="0" alt="Up"></a></td>
33
<td><a accesskey="h" href="index.html"><img src="home.png" width="24" height="24" border="0" alt="Home"></a></td>
34
<th width="100%" align="center">GUPnP Reference Manual</th>
35
<td><a accesskey="n" href="api.html"><img src="right.png" width="24" height="24" border="0" alt="Next"></a></td>
37
<div class="chapter" lang="en">
38
<div class="titlepage"><div><div><h2 class="title">
39
<a name="server-tutorial"></a>Writing a UPnP Service</h2></div></div></div>
40
<div class="simplesect" lang="en">
41
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
42
<a name="id2582304"></a>Introduction</h2></div></div></div>
44
This chapter explains how to implement a UPnP service using GUPnP. For
45
this example we will create a virtual UPnP-enabled light bulb.
48
Before any code can be written, the device and services that it implement
49
need to be described in XML. Although this can be frustrating, if you are
50
implementing a standardised service (see <a class="ulink" href="http://upnp.org/standardizeddcps/" target="_top">http://upnp.org/standardizeddcps/</a> for the list of standard devices
51
and services) then the service description is already written for you and
52
the device description is trivial. UPnP has standardised <a class="ulink" href="http://upnp.org/standardizeddcps/lighting.asp" target="_top">Lighting
53
Controls</a>, so we'll be using the device and service types defined
57
<div class="simplesect" lang="en">
58
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
59
<a name="id2605390"></a>Defining the Device</h2></div></div></div>
61
The first step is to write the <em class="firstterm">device description</em>
62
file. This is a short XML document which describes the device and what
63
services it provides (for more details see the <a class="ulink" href="http://upnp.org/specs/arch/UPnP-DeviceArchitecture-v1.0.pdf" target="_top">UPnP
64
Device Architecture</a> specification, section 2.1). We'll be using
65
the <code class="literal">BinaryLight1</code> device type, but if none of the
66
existing device types are suitable a custom device type can be created.
68
<pre class="programlisting"><?xml version="1.0" encoding="utf-8"?>
69
<root xmlns="urn:schemas-upnp-org:device-1-0">
71
<major>1</major>
72
<minor>0</minor>
76
<deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType>
77
<friendlyName>Kitchen Lights</friendlyName>
78
<manufacturer>OpenedHand</manufacturer>
79
<modelName>Virtual Light</modelName>
80
<UDN>uuid:cc93d8e6-6b8b-4f60-87ca-228c36b5b0e8</UDN>
84
<serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>
85
<serviceId>urn:upnp-org:serviceId:SwitchPower:1</serviceId>
86
<SCPDURL>/SwitchPower1.xml</SCPDURL>
87
<controlURL>/SwitchPower/Control</controlURL>
88
<eventSubURL>/SwitchPower/Event</eventSubURL>
95
The <code class="sgmltag-element">specVersion</code> tag defines what version of the UPnP
96
Device Architecture the document conforms to. At the time of writing the
100
Next there is the root <code class="sgmltag-element">device</code> tag. This contains
101
metadata about the device, lists the services it provides and any
102
sub-devices present (there are none in this example). The
103
<code class="sgmltag-element">deviceType</code> tag specifies the type of the device.
106
Next we have <code class="sgmltag-element">friendlyName</code>,
107
<code class="sgmltag-element">manufacturer</code> and <code class="sgmltag-element">modelName</code>. The
108
friendly name is a human-readable name for the device, the manufacturer
109
and model name are self-explanatory.
112
Next there is the UDN, or <em class="firstterm">Unique Device Name</em>. This
113
is an identifier which is unique for each device but persistent for each
114
particular device. Although it has to start with <code class="literal">uuid:</code>
115
note that it doesn't have to be an UUID. There are several alternatives
116
here: for example it could be computed at built-time if the software will
117
only be used on a single machine, or it could be calculated using the
118
device's serial number or MAC address.
121
Finally we have the <code class="sgmltag-element">serviceList</code> which describes the
122
services this device provides. Each service has a service type (again
123
there are types defined for standardised services or you can create your
124
own), service identifier, and three URLs. As a service type we're using
125
the standard <code class="literal">SwitchPower1</code> service. The
126
<code class="sgmltag-element">SCPDURL</code> field specifies where the <em class="firstterm">Service
127
Control Protocol Document</em> can be found, this describes the
128
service in more detail and will be covered next. Finally there are the
129
control and event URLs, which need to be unique on the device and will be
133
<div class="simplesect" lang="en">
134
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
135
<a name="id2626610"></a>Defining Services</h2></div></div></div>
137
Becase we are using a standard service we can use the service description
138
from the specification. This is the <code class="literal">SwitchPower1</code>
139
service description file:
141
<pre class="programlisting"><?xml version="1.0" encoding="utf-8"?>
142
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
144
<major>1</major>
145
<minor>0</minor>
149
<name>SetTarget</name>
152
<name>NewTargetValue</name>
153
<relatedStateVariable>Target</relatedStateVariable>
154
<direction>in</direction>
156
</argumentList>
159
<name>GetTarget</name>
162
<name>RetTargetValue</name>
163
<relatedStateVariable>Target</relatedStateVariable>
164
<direction>out</direction>
166
</argumentList>
169
<name>GetStatus</name>
172
<name>ResultStatus</name>
173
<relatedStateVariable>Status</relatedStateVariable>
174
<direction>out</direction>
176
</argumentList>
179
<serviceStateTable>
180
<stateVariable sendEvents="no">
181
<name>Target</name>
182
<dataType>boolean</dataType>
183
<defaultValue>0</defaultValue>
184
</stateVariable>
185
<stateVariable sendEvents="yes">
186
<name>Status</name>
187
<dataType>boolean</dataType>
188
<defaultValue>0</defaultValue>
189
</stateVariable>
190
</serviceStateTable>
194
Again, the <code class="sgmltag-element">specVersion</code> tag defines the UPnP version
195
that is being used. The rest of the document consists of an
196
<code class="sgmltag-element">actionList</code> defining the <a class="glossterm" href="glossary.html#action"><em class="glossterm">actions</em></a> available and a
197
<code class="sgmltag-element">serviceStateTable</code> defining the <a class="glossterm" href="glossary.html#state-variable"><em class="glossterm">state variables</em></a>.
200
Every <code class="sgmltag-element">action</code> has a <code class="sgmltag-element">name</code> and a list
201
of <code class="sgmltag-element">argument</code>s. Arguments also have a name, a direction
202
(<code class="literal">in</code> or <code class="literal">out</code> for input or output
203
arguments) and a related state variable. The state variable is used to
204
determine the type of the argument, and as such is a required element.
205
This can lead to the creation of otherwise unused state variables to
206
define the type for an argument (the <code class="literal">WANIPConnection</code>
207
service is a good example of this), thanks to the legacy behind UPnP.
210
<code class="sgmltag-element">stateVariable</code>s need to specify their
211
<code class="sgmltag-element">name</code> and <code class="sgmltag-element">dataType</code>. State variables
212
by default send notifications when they change, to specify that a variable
213
doesn't do this set the <code class="sgmltag-element">sendEvents</code> attribute to
214
<code class="literal">no</code>. Finally there are optional
215
<code class="sgmltag-element">defaultValue</code>, <code class="sgmltag-element">allowedValueList</code> and
216
<code class="sgmltag-element">allowedValueRange</code> elements which specify what the
217
default and valid values for the variable.
220
For the full specification of the service definition file, including a
221
complete list of valid <code class="sgmltag-element">dataType</code>s, see section 2.3 of
222
the <a class="ulink" href="http://upnp.org/specs/arch/UPnP-DeviceArchitecture-v1.0.pdf" target="_top">UPnP
223
Device Architecture</a>.
226
<div class="simplesect" lang="en">
227
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
228
<a name="id2623799"></a>Implementing the Device</h2></div></div></div>
230
Before starting to implement the device, some boilerplate code is needed
231
to initialise GUPnP. GLib types and threading needs to be initialised,
232
and then a GUPnP context can be created using <a class="link" href="GUPnPContext.html#gupnp-context-new" title="gupnp_context_new ()"><code class="function">gupnp_context_new()</code></a>.
234
<pre class="programlisting">GUPnPContext *context;
235
/* Initialize required subsystems */
236
g_thread_init (NULL);
238
/* Create the GUPnP context with default host and port */
239
context = gupnp_context_new (NULL, NULL, 0, NULL);</pre>
241
UPnP uses HTTP to provide the device and service description files, so
242
next we tell GUPnP to publish them. This is done with
243
<a class="link" href="GUPnPContext.html#gupnp-context-host-path" title="gupnp_context_host_path ()"><code class="function">gupnp_context_host_path()</code></a> which takes a local filename to send when a
244
certain server path is requested.
246
<pre class="programlisting">gupnp_context_host_path (context, "BinaryLight1.xml", "/BinaryLight1.xml");
247
gupnp_context_host_path (context, "SwitchPower1.xml", "/SwitchPower1.xml");</pre>
249
Next the root device can be created.
251
<pre class="programlisting">GUPnPRootDevice *dev;
252
/* Create the root device object */
253
dev = gupnp_root_device_new (context, "/BinaryLight1.xml");
254
/* Activate the root device, so that it announces itself */
255
gupnp_root_device_set_available (dev, TRUE);</pre>
257
GUPnP scans the device description and any service description files it
258
refers to, so if the main loop was entered now the device and service
259
would be available on the network, albeit with no functionality. The
260
remaining task is to implement the services.
263
<div class="simplesect" lang="en">
264
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
265
<a name="id2586848"></a>Implementing a Service</h2></div></div></div>
267
To implement a service we first fetch the <a class="link" href="GUPnPService.html" title="GUPnPService"><span class="type">GUPnPService</span></a> from the root
268
device using <a class="link" href="GUPnPDeviceInfo.html#gupnp-device-info-get-service" title="gupnp_device_info_get_service ()"><code class="function">gupnp_device_info_get_service()</code></a> (<a class="link" href="GUPnPRootDevice.html" title="GUPnPRootDevice"><span class="type">GUPnPRootDevice</span></a> is a
269
subclass of <a class="link" href="GUPnPDevice.html" title="GUPnPDevice"><span class="type">GUPnPDevice</span></a>, which implements <a class="link" href="GUPnPDeviceInfo.html" title="GUPnPDeviceInfo"><span class="type">GUPnPDeviceInfo</span></a>). This
270
returns a <a class="link" href="GUPnPServiceInfo.html" title="GUPnPServiceInfo"><span class="type">GUPnPServiceInfo</span></a> which again is an interface, implemented by
271
<a class="link" href="GUPnPService.html" title="GUPnPService"><span class="type">GUPnPService</span></a> (on the server) and <a class="link" href="GUPnPServiceProxy.html" title="GUPnPServiceProxy"><span class="type">GUPnPServiceProxy</span></a> (on the client).
273
<pre class="programlisting">GUPnPServiceInfo *service;
274
service = gupnp_device_info_get_service
275
(GUPNP_DEVICE_INFO (dev), "urn:schemas-upnp-org:service:SwitchPower:1");</pre>
277
<a class="link" href="GUPnPService.html" title="GUPnPService"><span class="type">GUPnPService</span></a> handles interacting with the network itself, leaving the
278
implementation of the service itself to signal handlers that we need to
279
connect. There are two signals: <a class="link" href="GUPnPService.html#GUPnPService-action-invoked" title='The "action-invoked" signal'><span class="type">"action-invoked"</span></a> and
280
<a class="link" href="GUPnPService.html#GUPnPService-query-variable" title='The "query-variable" signal'><span class="type">"query-variable"</span></a>. <a class="link" href="GUPnPService.html#GUPnPService-action-invoked" title='The "action-invoked" signal'><span class="type">"action-invoked"</span></a> is emitted
281
when a client invokes an action: the handler is passed a
282
<a class="link" href="GUPnPService.html#GUPnPServiceAction" title="GUPnPServiceAction"><span class="type">GUPnPServiceAction</span></a> object that identifies which action was invoked, and
283
is used to return values using <a class="link" href="GUPnPService.html#gupnp-service-action-set" title="gupnp_service_action_set ()"><code class="function">gupnp_service_action_set()</code></a>.
284
<a class="link" href="GUPnPService.html#GUPnPService-query-variable" title='The "query-variable" signal'><span class="type">"query-variable"</span></a> is emitted for evented variables when a
285
control point subscribes to the service (to announce the initial value),
286
or whenever a client queries the value of a state variable (note that this
287
is now deprecated behaviour for UPnP control points): the handler is
288
passed the variable name and a <span class="type">GValue</span> which should be set to the current
289
value of the variable.
292
There are two approaches that clients can take to handle these signals.
293
They can either connect a single handler to <a class="link" href="GUPnPService.html#GUPnPService-action-invoked" title='The "action-invoked" signal'><span class="type">"action-invoked"</span></a>
294
or <a class="link" href="GUPnPService.html#GUPnPService-query-variable" title='The "query-variable" signal'><span class="type">"query-variable"</span></a> and examine the arguments to decide what
295
action to take. Alternatively, handlers can be targetted at specific
296
actions or variables by using the <em class="firstterm">signal detail</em>
297
when connecting. For example, this causes
298
<code class="function">on_get_status_action</code> to be called when the
299
<code class="function">GetStatus</code> action is invoked:
301
<pre class="programlisting">static void on_get_status_action (GUPnPService *service, GUPnPServiceAction *action, gpointer user_data);
303
g_signal_connect (service, "action-invoked::GetStatus", G_CALLBACK (on_get_status_action), NULL);</pre>
305
The implementation of action handlers is quite simple. The handler is
306
passed a <a class="link" href="GUPnPService.html#GUPnPServiceAction" title="GUPnPServiceAction"><span class="type">GUPnPServiceAction</span></a> object which represents the in-progress
307
action. If required it can be queried using
308
<a class="link" href="GUPnPService.html#gupnp-service-action-get-name" title="gupnp_service_action_get_name ()"><code class="function">gupnp_service_action_get_name()</code></a> to identify the action (this isn't
309
required if detailed signals were connected). Any
310
<em class="firstterm">in</em> arguments can be retrieving using
311
<a class="link" href="GUPnPService.html#gupnp-service-action-get" title="gupnp_service_action_get ()"><code class="function">gupnp_service_action_get()</code></a>, and then return values can be set using
312
<a class="link" href="GUPnPService.html#gupnp-service-action-set" title="gupnp_service_action_set ()"><code class="function">gupnp_service_action_set()</code></a>. Once the action has been performed, either
313
<a class="link" href="GUPnPService.html#gupnp-service-action-return" title="gupnp_service_action_return ()"><code class="function">gupnp_service_action_return()</code></a> or <a class="link" href="GUPnPService.html#gupnp-service-action-return-error" title="gupnp_service_action_return_error ()"><code class="function">gupnp_service_action_return_error()</code></a>
314
should be called to either return successfully or return an error code.
315
If any evented state variables were modified during the action then a
316
notification should be emitted using <a class="link" href="GUPnPService.html#gupnp-service-notify" title="gupnp_service_notify ()"><code class="function">gupnp_service_notify()</code></a>. This is an
317
example implementation of <code class="function">GetStatus</code> and
318
<code class="function">SetTarget</code>:
320
<pre class="programlisting">static gboolean status;
323
get_status_cb (GUPnPService *service, GUPnPServiceAction *action, gpointer user_data)
325
gupnp_service_action_set (action,
326
"ResultStatus", G_TYPE_BOOLEAN, status,
328
gupnp_service_action_return (action);
332
set_target_cb (GUPnPService *service, GUPnPServiceAction *action, gpointer user_data)
334
gupnp_service_action_get (action,
335
"NewTargetValue", G_TYPE_BOOLEAN, &status,
337
gupnp_service_action_return (action);
338
gupnp_service_notify (service, "Status", G_TYPE_STRING, status, NULL);
341
g_signal_connect (service, "action-invoked::GetStatus", G_CALLBACK (get_status_cb), NULL);
342
g_signal_connect (service, "action-invoked::SetTarget", G_CALLBACK (set_target_cb), NULL);</pre>
344
State variable query handlers are called with the name of the variable and
345
a <span class="type">GValue</span>. This value should be initialized with the relevant type and
346
then set to the current value. Again signal detail can be used to connect
347
handlers to specific state variable callbacks.
349
<pre class="programlisting">static gboolean status;
352
query_status_cb (GUPnPService *service, char *variable, GValue *value, gpointer user_data)
354
g_value_init (value, G_TYPE_BOOLEAN);
355
g_value_set_boolean (value, status);
358
g_signal_connect (service, "query-variable::Status", G_CALLBACK (query_status_cb), NULL);</pre>
360
For services which have many actions and variables there is a convenience
361
method <a class="link" href="GUPnPService.html#gupnp-service-signals-autoconnect" title="gupnp_service_signals_autoconnect ()"><code class="function">gupnp_service_signals_autoconnect()</code></a> which will automatically
362
connect specially named handlers to signals. See the documentation for
363
full details on how it works.
366
The service is now fully implemented. To complete it, enter a GLib main
367
loop and wait for a client to connect. The complete source code for this
368
example is available as <code class="filename">examples/light-server.c</code> in
375
Generated by GTK-Doc V1.10</div>