This file is indexed.

/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 &lt;libgupnp/gupnp-control-point.h&gt;

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", &amp;error,
				   /* IN args */
				   NULL,
				   /* OUT args */
				   "NewExternalIPAddress",
				   G_TYPE_STRING, &amp;ip,
				   NULL);
  
  if (error == NULL) {
    g_print ("External IP address is %s\n", ip);
    g_free (ip);
  } else {
    g_printerr ("Error: %s\n", error-&gt;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, &amp;ip, &amp;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>