/usr/share/gtk-doc/html/gupnp/client-tutorial.html is in libgupnp-doc 0.20.10-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>GUPnP Reference Manual: Writing a UPnP Client</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="index.html" title="GUPnP Reference Manual">
<link rel="up" href="tutorial.html" title="Part I. Tutorial">
<link rel="prev" href="overview.html" title="Overview">
<link rel="next" href="server-tutorial.html" title="Writing a UPnP Service">
<meta name="generator" content="GTK-Doc V1.20 (XML mode)">
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="10"><tr valign="middle">
<td width="100%" align="left" class="shortcuts"></td>
<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
<td><a accesskey="u" href="tutorial.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
<td><a accesskey="p" href="overview.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
<td><a accesskey="n" href="server-tutorial.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
</tr></table>
<div class="chapter">
<div class="titlepage"><div><div><h2 class="title">
<a name="client-tutorial"></a>Writing a UPnP Client</h2></div></div></div>
<div class="simplesect">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="id-1.2.3.2"></a>Introduction</h2></div></div></div>
<p>
This chapter explains how to write an application which fetches the
external IP address from an UPnP-compliant modem. To do this a
<em class="glossterm">Control Point</em> is created, which searches for
services of the type
<code class="literal">urn:schemas-upnp-org:service:WANIPConnection:1</code> (part of
the <a class="ulink" href="http://upnp.org/standardizeddcps/igd.asp" target="_top">Internet Gateway
Device</a> specification). As services are discovered
<em class="firstterm">Service Proxy</em> objects are created by GUPnP to allow
interaction with the service, on which we can invoke the action
<code class="function">GetExternalIPAddress</code> to fetch the external IP
address.
</p>
</div>
<div class="simplesect">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="id-1.2.3.3"></a>Finding Services</h2></div></div></div>
<p>
First, we initialize GUPnP and create a control point targeting the
service type. Then we connect a signal handler so that we are notified
when services we are interested in are found.
</p>
<pre class="programlisting">#include <libgupnp/gupnp-control-point.h>
static GMainLoop *main_loop;
static void
service_proxy_available_cb (GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy,
gpointer userdata)
{
/* … */
}
int
main (int argc, char **argv)
{
GUPnPContext *context;
GUPnPControlPoint *cp;
/* Required initialisation */
#if !GLIB_CHECK_VERSION(2,35,0)
g_type_init ();
#endif
/* Create a new GUPnP Context. By here we are using the default GLib main
context, and connecting to the current machine's default IP on an
automatically generated port. */
context = gupnp_context_new (NULL, NULL, 0, NULL);
/* Create a Control Point targeting WAN IP Connection services */
cp = gupnp_control_point_new
(context, "urn:schemas-upnp-org:service:WANIPConnection:1");
/* The service-proxy-available signal is emitted when any services which match
our target are found, so connect to it */
g_signal_connect (cp,
"service-proxy-available",
G_CALLBACK (service_proxy_available_cb),
NULL);
/* Tell the Control Point to start searching */
gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
/* Enter the main loop. This will start the search and result in callbacks to
service_proxy_available_cb. */
main_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (main_loop);
/* Clean up */
g_main_loop_unref (main_loop);
g_object_unref (cp);
g_object_unref (context);
return 0;
}</pre>
</div>
<div class="simplesect">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="id-1.2.3.4"></a>Invoking Actions</h2></div></div></div>
<p>
Now we have an application which searches for the service we specified and
calls <code class="function">service_proxy_available_cb</code> for each one it
found. To get the external IP address we need to invoke the
<code class="literal">GetExternalIPAddress</code> action. This action takes no in
arguments, and has a single out argument called "NewExternalIPAddress".
GUPnP has a set of methods to invoke actions (which will be very familiar
to anyone who has used <code class="literal">dbus-glib</code>) where you pass a
<code class="constant">NULL</code>-terminated varargs list of (name, GType, value)
tuples for the in arguments, then a <code class="constant">NULL</code>-terminated
varargs list of (name, GType, return location) tuples for the out
arguments.
</p>
<pre class="programlisting">static void
service_proxy_available_cb (GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy,
gpointer userdata)
{
GError *error = NULL;
char *ip = NULL;
gupnp_service_proxy_send_action (proxy,
/* Action name and error location */
"GetExternalIPAddress", &error,
/* IN args */
NULL,
/* OUT args */
"NewExternalIPAddress",
G_TYPE_STRING, &ip,
NULL);
if (error == NULL) {
g_print ("External IP address is %s\n", ip);
g_free (ip);
} else {
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
}
g_main_loop_quit (main_loop);
}</pre>
<p>
Note that <a class="link" href="GUPnPServiceProxy.html#gupnp-service-proxy-send-action" title="gupnp_service_proxy_send_action ()"><code class="function">gupnp_service_proxy_send_action()</code></a> blocks until the service has
replied. If you need to make non-blocking calls then use
<a class="link" href="GUPnPServiceProxy.html#gupnp-service-proxy-begin-action" title="gupnp_service_proxy_begin_action ()"><code class="function">gupnp_service_proxy_begin_action()</code></a>, which takes a callback that will be
called from the mainloop when the reply is received.
</p>
</div>
<div class="simplesect">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="id-1.2.3.5"></a>Subscribing to state variable change notifications</h2></div></div></div>
<p>
It is possible to get change notifications for the service state variables
that have attribute <code class="literal">sendEvents="yes"</code>. We'll demonstrate
this by modifying <code class="function">service_proxy_available_cb</code> and using
<a class="link" href="GUPnPServiceProxy.html#gupnp-service-proxy-add-notify" title="gupnp_service_proxy_add_notify ()"><code class="function">gupnp_service_proxy_add_notify()</code></a> to setup a notification callback:
</p>
<pre class="programlisting">static void
external_ip_address_changed (GUPnPServiceProxy *proxy,
const char *variable,
GValue *value,
gpointer userdata)
{
g_print ("External IP address changed: %s\n", g_value_get_string (value));
}
static void
service_proxy_available_cb (GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy,
gpointer userdata)
{
g_print ("Found a WAN IP Connection service\n");
gupnp_service_proxy_set_subscribed (proxy, TRUE);
if (!gupnp_service_proxy_add_notify (proxy,
"ExternalIPAddress",
G_TYPE_STRING,
external_ip_address_changed,
NULL)) {
g_printerr ("Failed to add notify");
}
}</pre>
</div>
<div class="simplesect">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="id-1.2.3.6"></a>Generating Wrappers</h2></div></div></div>
<p>
Using <a class="link" href="GUPnPServiceProxy.html#gupnp-service-proxy-send-action" title="gupnp_service_proxy_send_action ()"><code class="function">gupnp_service_proxy_send_action()</code></a> and <a class="link" href="GUPnPServiceProxy.html#gupnp-service-proxy-add-notify" title="gupnp_service_proxy_add_notify ()"><code class="function">gupnp_service_proxy_add_notify()</code></a>
can become tedious, because of the requirement to specify the types and deal
with GValues. An
alternative is to use <a class="xref" href="gupnp-binding-tool.html" title="gupnp-binding-tool"><span class="refentrytitle">gupnp-binding-tool</span>(1)</a>, which
generates wrappers that hide the boilerplate code from you. Using a
wrapper generated with prefix 'ipconn' would replace
<a class="link" href="GUPnPServiceProxy.html#gupnp-service-proxy-send-action" title="gupnp_service_proxy_send_action ()"><code class="function">gupnp_service_proxy_send_action()</code></a> with this code:
</p>
<pre class="programlisting">ipconn_get_external_ip_address (proxy, &ip, &error);</pre>
<p>
State variable change notifications are friendlier with wrappers as well:
</p>
<pre class="programlisting">static void
external_ip_address_changed (GUPnPServiceProxy *proxy,
const gchar *external_ip_address,
gpointer userdata)
{
g_print ("External IP address changed: '%s'\n", external_ip_address);
}
static void
service_proxy_available_cb (GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy
gpointer userdata)
{
g_print ("Found a WAN IP Connection service\n");
gupnp_service_proxy_set_subscribed (proxy, TRUE);
if (!ipconn_external_ip_address_add_notify (proxy,
external_ip_address_changed,
NULL)) {
g_printerr ("Failed to add notify");
}
}</pre>
</div>
</div>
<div class="footer">
<hr>
Generated by GTK-Doc V1.20</div>
</body>
</html>
|