395ddcd40abac676cbccea833772425b9846e848
[profile/ivi/GUPnP.git] / doc / html / client-tutorial.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2 <html>
3 <head>
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">
13 </head>
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>
21 </tr></table>
22 <div class="chapter">
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="idp6270480"></a>Introduction</h2></div></div></div>
28 <p>
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
32       services of the type
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
39       address.
40     </p>
41 </div>
42 <div class="simplesect">
43 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
44 <a name="idp8317008"></a>Finding Services</h2></div></div></div>
45 <p>
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.
49     </p>
50 <pre class="programlisting">#include &lt;libgupnp/gupnp-control-point.h&gt;
51
52 static GMainLoop *main_loop;
53
54 static void
55 service_proxy_available_cb (GUPnPControlPoint *cp,
56                             GUPnPServiceProxy *proxy,
57                             gpointer           userdata)
58 {
59   /* … */
60 }
61
62 int
63 main (int argc, char **argv)
64 {
65   GUPnPContext *context;
66   GUPnPControlPoint *cp;
67   
68   /* Required initialisation */
69   #if !GLIB_CHECK_VERSION(2,35,0)
70     g_type_init ();
71   #endif
72
73   /* Create a new GUPnP Context.  By here we are using the default GLib main
74      context, and connecting to the current machine's default IP on an
75      automatically generated port. */
76   context = gupnp_context_new (NULL, NULL, 0, NULL);
77
78   /* Create a Control Point targeting WAN IP Connection services */
79   cp = gupnp_control_point_new
80     (context, "urn:schemas-upnp-org:service:WANIPConnection:1");
81
82   /* The service-proxy-available signal is emitted when any services which match
83      our target are found, so connect to it */
84   g_signal_connect (cp,
85                     "service-proxy-available",
86                     G_CALLBACK (service_proxy_available_cb),
87                     NULL);
88
89   /* Tell the Control Point to start searching */
90   gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
91   
92   /* Enter the main loop. This will start the search and result in callbacks to
93      service_proxy_available_cb. */
94   main_loop = g_main_loop_new (NULL, FALSE);
95   g_main_loop_run (main_loop);
96
97   /* Clean up */
98   g_main_loop_unref (main_loop);
99   g_object_unref (cp);
100   g_object_unref (context);
101   
102   return 0;
103 }</pre>
104 </div>
105 <div class="simplesect">
106 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
107 <a name="idp9039984"></a>Invoking Actions</h2></div></div></div>
108 <p>
109       Now we have an application which searches for the service we specified and
110       calls <code class="function">service_proxy_available_cb</code> for each one it
111       found.  To get the external IP address we need to invoke the
112       <code class="literal">GetExternalIPAddress</code> action.  This action takes no in
113       arguments, and has a single out argument called "NewExternalIPAddress".
114       GUPnP has a set of methods to invoke actions (which will be very familiar
115       to anyone who has used <code class="literal">dbus-glib</code>) where you pass a
116       <code class="constant">NULL</code>-terminated varargs list of (name, GType, value)
117       tuples for the in arguments, then a <code class="constant">NULL</code>-terminated
118       varargs list of (name, GType, return location) tuples for the out
119       arguments.
120     </p>
121 <pre class="programlisting">static void
122 service_proxy_available_cb (GUPnPControlPoint *cp,
123                             GUPnPServiceProxy *proxy,
124                             gpointer           userdata)
125 {
126   GError *error = NULL;
127   char *ip = NULL;
128   
129   gupnp_service_proxy_send_action (proxy,
130                                    /* Action name and error location */
131                                    "GetExternalIPAddress", &amp;error,
132                                    /* IN args */
133                                    NULL,
134                                    /* OUT args */
135                                    "NewExternalIPAddress",
136                                    G_TYPE_STRING, &amp;ip,
137                                    NULL);
138   
139   if (error == NULL) {
140     g_print ("External IP address is %s\n", ip);
141     g_free (ip);
142   } else {
143     g_printerr ("Error: %s\n", error-&gt;message);
144     g_error_free (error);
145   }
146   g_main_loop_quit (main_loop);
147 }</pre>
148 <p>
149       Note that gupnp_service_proxy_send_action() blocks until the service has
150       replied.  If you need to make non-blocking calls then use
151       gupnp_service_proxy_begin_action(), which takes a callback that will be
152       called from the mainloop when the reply is received.
153     </p>
154 </div>
155 <div class="simplesect">
156 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
157 <a name="idp9827344"></a>Subscribing to state variable change notifications</h2></div></div></div>
158 <p>
159       It is possible to get change notifications for the service state variables 
160       that have attribute <code class="literal">sendEvents="yes"</code>. We'll demonstrate
161       this by modifying <code class="function">service_proxy_available_cb</code> and using
162       gupnp_service_proxy_add_notify() to setup a notification callback:
163     </p>
164 <pre class="programlisting">static void
165 external_ip_address_changed (GUPnPServiceProxy *proxy,
166                              const char        *variable,
167                              GValue            *value,
168                              gpointer           userdata)
169 {
170   g_print ("External IP address changed: %s\n", g_value_get_string (value));
171 }
172
173 static void
174 service_proxy_available_cb (GUPnPControlPoint *cp,
175                             GUPnPServiceProxy *proxy,
176                             gpointer           userdata)
177 {
178   g_print ("Found a WAN IP Connection service\n");
179   
180   gupnp_service_proxy_set_subscribed (proxy, TRUE);
181   if (!gupnp_service_proxy_add_notify (proxy,
182                                        "ExternalIPAddress",
183                                        G_TYPE_STRING,
184                                        external_ip_address_changed,
185                                        NULL)) {
186     g_printerr ("Failed to add notify");
187   }
188 }</pre>
189 </div>
190 <div class="simplesect">
191 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
192 <a name="idp9597728"></a>Generating Wrappers</h2></div></div></div>
193 <p>
194       Using gupnp_service_proxy_send_action() and gupnp_service_proxy_add_notify ()
195       can become tedious, because of the requirement to specify the types and deal
196       with GValues.  An
197       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
198       generates wrappers that hide the boilerplate code from you.  Using a 
199       wrapper generated with prefix 'ipconn' would replace 
200       gupnp_service_proxy_send_action() with this code:
201     </p>
202 <pre class="programlisting">ipconn_get_external_ip_address (proxy, &amp;ip, &amp;error);</pre>
203 <p>
204       State variable change notifications are friendlier with wrappers as well:
205     </p>
206 <pre class="programlisting">static void
207 external_ip_address_changed (GUPnPServiceProxy *proxy,
208                              const gchar       *external_ip_address,
209                              gpointer           userdata)
210 {
211   g_print ("External IP address changed: '%s'\n", external_ip_address);
212 }
213
214 static void
215 service_proxy_available_cb (GUPnPControlPoint *cp,
216                             GUPnPServiceProxy *proxy
217                             gpointer           userdata)
218 {
219   g_print ("Found a WAN IP Connection service\n");
220   
221   gupnp_service_proxy_set_subscribed (proxy, TRUE);
222   if (!ipconn_external_ip_address_add_notify (proxy,
223                                               external_ip_address_changed,
224                                               NULL)) {
225     g_printerr ("Failed to add notify");
226   }
227 }</pre>
228 </div>
229 </div>
230 <div class="footer">
231 <hr>
232           Generated by GTK-Doc V1.18</div>
233 </body>
234 </html>