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 Client</title>
6 <meta name="generator" content="DocBook XSL Stylesheets V1.76.1">
7 <link rel="home" href="index.html" title="GUPnP Reference Manual">
8 <link rel="up" href="tutorial.html" title="Part I. Tutorial">
9 <link rel="prev" href="overview.html" title="Overview">
10 <link rel="next" href="server-tutorial.html" title="Writing a UPnP Service">
11 <meta name="generator" content="GTK-Doc V1.18 (XML mode)">
12 <link rel="stylesheet" href="style.css" type="text/css">
14 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
15 <table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"><tr valign="middle">
16 <td><a accesskey="p" href="overview.html"><img src="left.png" width="24" height="24" border="0" alt="Prev"></a></td>
17 <td><a accesskey="u" href="tutorial.html"><img src="up.png" width="24" height="24" border="0" alt="Up"></a></td>
18 <td><a accesskey="h" href="index.html"><img src="home.png" width="24" height="24" border="0" alt="Home"></a></td>
19 <th width="100%" align="center">GUPnP Reference Manual</th>
20 <td><a accesskey="n" href="server-tutorial.html"><img src="right.png" width="24" height="24" border="0" alt="Next"></a></td>
23 <div class="titlepage"><div><div><h2 class="title">
24 <a name="client-tutorial"></a>Writing a UPnP Client</h2></div></div></div>
25 <div class="simplesect">
26 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
27 <a name="idp5344880"></a>Introduction</h2></div></div></div>
29 This chapter explains how to write an application which fetches the
30 external IP address from an UPnP-compliant modem. To do this a
31 <em class="glossterm">Control Point</em> is created, which searches for
33 <code class="literal">urn:schemas-upnp-org:service:WANIPConnection:1</code> (part of
34 the <a class="ulink" href="http://upnp.org/standardizeddcps/igd.asp" target="_top">Internet Gateway
35 Device</a> specification). As services are discovered
36 <em class="firstterm">Service Proxy</em> objects are created by GUPnP to allow
37 interaction with the service, on which we can invoke the action
38 <code class="function">GetExternalIPAddress</code> to fetch the external IP
42 <div class="simplesect">
43 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
44 <a name="idp6417544"></a>Finding Services</h2></div></div></div>
46 First, we initialize GUPnP and create a control point targeting the
47 service type. Then we connect a signal handler so that we are notified
48 when services we are interested in are found.
50 <pre class="programlisting">#include <libgupnp/gupnp-control-point.h>
52 static GMainLoop *main_loop;
55 service_proxy_available_cb (GUPnPControlPoint *cp,
56 GUPnPServiceProxy *proxy,
63 main (int argc, char **argv)
65 GUPnPContext *context;
66 GUPnPControlPoint *cp;
68 /* Required initialisation */
71 /* Create a new GUPnP Context. By here we are using the default GLib main
72 context, and connecting to the current machine's default IP on an
73 automatically generated port. */
74 context = gupnp_context_new (NULL, NULL, 0, NULL);
76 /* Create a Control Point targeting WAN IP Connection services */
77 cp = gupnp_control_point_new
78 (context, "urn:schemas-upnp-org:service:WANIPConnection:1");
80 /* The service-proxy-available signal is emitted when any services which match
81 our target are found, so connect to it */
83 "service-proxy-available",
84 G_CALLBACK (service_proxy_available_cb),
87 /* Tell the Control Point to start searching */
88 gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
90 /* Enter the main loop. This will start the search and result in callbacks to
91 service_proxy_available_cb. */
92 main_loop = g_main_loop_new (NULL, FALSE);
93 g_main_loop_run (main_loop);
96 g_main_loop_unref (main_loop);
98 g_object_unref (context);
103 <div class="simplesect">
104 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
105 <a name="idp5733152"></a>Invoking Actions</h2></div></div></div>
107 Now we have an application which searches for the service we specified and
108 calls <code class="function">service_proxy_available_cb</code> for each one it
109 found. To get the external IP address we need to invoke the
110 <code class="literal">GetExternalIPAddress</code> action. This action takes no in
111 arguments, and has a single out argument called "NewExternalIPAddress".
112 GUPnP has a set of methods to invoke actions (which will be very familiar
113 to anyone who has used <code class="literal">dbus-glib</code>) where you pass a
114 <code class="constant">NULL</code>-terminated varargs list of (name, GType, value)
115 tuples for the in arguments, then a <code class="constant">NULL</code>-terminated
116 varargs list of (name, GType, return location) tuples for the out
119 <pre class="programlisting">static void
120 service_proxy_available_cb (GUPnPControlPoint *cp,
121 GUPnPServiceProxy *proxy,
124 GError *error = NULL;
127 gupnp_service_proxy_send_action (proxy,
128 /* Action name and error location */
129 "GetExternalIPAddress", &error,
133 "NewExternalIPAddress",
134 G_TYPE_STRING, &ip,
138 g_print ("External IP address is %s\n", ip);
141 g_printerr ("Error: %s\n", error->message);
142 g_error_free (error);
144 g_main_loop_quit (main_loop);
147 Note that gupnp_service_proxy_send_action() blocks until the service has
148 replied. If you need to make non-blocking calls then use
149 gupnp_service_proxy_begin_action(), which takes a callback that will be
150 called from the mainloop when the reply is received.
153 <div class="simplesect">
154 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
155 <a name="idp4316208"></a>Subscribing to state variable change notifications</h2></div></div></div>
157 It is possible to get change notifications for the service state variables
158 that have attribute <code class="literal">sendEvents="yes"</code>. We'll demonstrate
159 this by modifying <code class="function">service_proxy_available_cb()</code> and using
160 gupnp_service_proxy_add_notify() to setup a notification callback:
162 <pre class="programlisting">static void
163 external_ip_address_changed (GUPnPServiceProxy *proxy,
164 const char *variable,
168 g_print ("External IP address changed: %s\n", g_value_get_string (value));
172 service_proxy_available_cb (GUPnPControlPoint *cp,
173 GUPnPServiceProxy *proxy,
176 g_print ("Found a WAN IP Connection service\n");
178 gupnp_service_proxy_set_subscribed (proxy, TRUE);
179 if (!gupnp_service_proxy_add_notify (proxy,
182 external_ip_address_changed,
184 g_printerr ("Failed to add notify");
188 <div class="simplesect">
189 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
190 <a name="idp5918864"></a>Generating Wrappers</h2></div></div></div>
192 Using gupnp_service_proxy_send_action() and gupnp_service_proxy_add_notify ()
193 can become tedious, because of the requirement to specify the types and deal
195 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
196 generates wrappers that hide the boilerplate code from you. Using a
197 wrapper generated with prefix 'ipconn' would replace
198 gupnp_service_proxy_send_action() with this code:
200 <pre class="programlisting">ipconn_get_external_ip_address (proxy, &ip, &error);</pre>
202 State variable change notifications are friendlier with wrappers as well:
204 <pre class="programlisting">static void
205 external_ip_address_changed (GUPnPServiceProxy *proxy,
206 const gchar *external_ip_address,
209 g_print ("External IP address changed: '%s'\n", external_ip_address);
213 service_proxy_available_cb (GUPnPControlPoint *cp,
214 GUPnPServiceProxy *proxy
217 g_print ("Found a WAN IP Connection service\n");
219 gupnp_service_proxy_set_subscribed (proxy, TRUE);
220 if (!ipconn_external_ip_address_add_notify (proxy,
221 external_ip_address_changed,
223 g_printerr ("Failed to add notify");
230 Generated by GTK-Doc V1.18</div>