<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:admin="http://webns.net/mvcb/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:html="http://www.w3.org/1999/html" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>Ross Burton</title><link>http://www.burtonini.com/blog</link><description>A potted account of Ross' life</description><language>en</language><ttl>60</ttl><dc:creator>Ross Burton</dc:creator><admin:generatorAgent rdf:resource="http://pyblosxom.sourceforge.net/"/><admin:errorReportsTo rdf:resource="mailto:ross@burtonini.com"/><item><title>Fire Eagle Invitation?</title><guid isPermaLink="false">computers/fireeagle-2008-05-12-21-50</guid><link>http://www.burtonini.com/blog/computers/fireeagle-2008-05-12-21-50</link><description>Does anyone out there on the Intarwebs work for Yahoo, or have a friend who works at Yahoo? I'd really ...</description><content:encoded><![CDATA[    <p>
      Does anyone out there on the Intarwebs work for Yahoo, or have a friend
      who works at Yahoo?  I'd really like to give
      this <a href="http://fireeagle.yahoo.net/">Fire Eagle</a> thing a go,
      specifically integrating <a href="http://gypsy.freedesktop.org/">Gypsy</a>
      and <a href="http://geoclue.freedesktop.org/">GeoClue</a> with Fire Eagle,
      but it's invitation only at the moment...
    </p>
    <p>
      <strong>Update: </strong> I now have an account!
    </p>
]]></content:encoded><category domain="http://www.burtonini.com">/computers</category><dc:date>2008-05-12T20:50:00Z</dc:date></item><item><title>GUPnP Basics, Part 1</title><guid isPermaLink="false">computers/gupnp-basics-2008-05-12-12-50</guid><link>http://www.burtonini.com/blog/computers/gupnp-basics-2008-05-12-12-50</link><description>For the last few days I've been learning more about UPnP and testing it with the few devices I have ...</description><content:encoded><![CDATA[    <!-- -*- Mode: html -*- -->
    <p>
      For the last few days I've been learning more about UPnP and testing it
      with the few devices I have around the house.  One of these is a cheap
      ADSL router, which apparently has the lamest UPnP stack on in existence.
      It does however support the <cite>WAN IP Connection</cite> interface, so
      you can use UPnP to get the external IP address and manipulate the port
      mapping.  I'll skip over the horrific security violations this involves,
      because it's a useful demonstration that the majority of people will be
      able to test.
    </p>
    <p>
      Today we'll start simple and get our external IP address using GUPnP.  The
      first thing to be done is to create a <cite>Control Point</cite>, which in
      the UPnP model handles discovery of resources, be them devices or services
      (a device can have multiple services).  When creating a control point you
      can specify the URN of the resource you want to target.  In this case we
      want all services providing <cite>WANIPConnection</cite> so we'd
      use <tt>urn:schemas-upnp-org:service:WANIPConnection:1</tt>.  If you want
      to browse for all services then use <tt>ssdp:all</tt> (SSDP being the
      <cite>Simple Service Discovery Protocol</cite>).
    </p>
    <pre>static GMainLoop *main_loop;

int
main (int argc, char **argv)
{
  GError *error = NULL;
  GUPnPContext *context;
  GUPnPControlPoint *cp;
  
  /* libsoup requires threading, so we have to initialise it */
  g_thread_init (NULL);
  g_type_init ();

  /* Default GLib context, default host IP, default port */
  context = gupnp_context_new (NULL, NULL, 0, &amp;error);
  if (error) g_error (error->message);

  /* 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 */
  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 */
  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;
}

static void
service_proxy_available_cb (GUPnPControlPoint *cp,
                            GUPnPServiceProxy *proxy)
{
  /* ... */
}</pre>
    <p>
      Now we have an application which searches for the service we specified and
      calls <tt>service_proxy_available_cb</tt> for each one it found.  Now, to
      get the external IP address we need to invoke
      the <tt>GetExternalIPAddress</tt> action.  This action takes no in
      arguments, and has a single out argument called "NewExternalIPAddress".
      Yes, the naming scheme is <em>stupid</em>.  GUPnP has a set of methods to
      invoke actions -- which will be very familiar to anyone who has
      used <tt>dbus-glib</tt> -- where you pass a <tt>NULL</tt>-terminated varargs list
      of (name, type, value) tuples for the in arguments, then
      a <tt>NULL</tt>-terminated varargs list of (name, value, return location) tuples
      for the out arguments.  A simple implementation would be as follows.
    </p>
    <pre>static void
service_proxy_available_cb (GUPnPControlPoint *cp,
                            GUPnPServiceProxy *proxy)
{
  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 <tt>_send_action</tt> blocks until the service has replied.  If you
      need to make non-blocking calls then
      use <tt>gupnp_service_proxy_begin_action</tt> which takes a callback.
    </p>
    <p>
      So, that is searching for services and invoking actions in GUPnP.  Next
      time I'll cover subscribing to state variables, and routers which can't
      count.
    </p>
    <p>
      <small>NP: <cite>Folk But Not Folk</cite>, Various</small>
    </p>
]]></content:encoded><category domain="http://www.burtonini.com">/computers</category><dc:date>2008-05-12T11:50:00Z</dc:date></item></channel></rss>