GNetworkService: fall back when there is no valid SRV record
authorDan Winship <danw@gnome.org>
Wed, 15 Sep 2010 14:05:03 +0000 (10:05 -0400)
committerDan Winship <danw@gnome.org>
Fri, 22 Oct 2010 18:59:35 +0000 (14:59 -0400)
RFC 2782 says that if there is no SRV record for
_SERVICE._PROTOCOL.DOMAIN, you should fall back to trying just DOMAIN,
with the default port for SERVICE. Do that.

https://bugzilla.gnome.org/show_bug.cgi?id=629274

gio/gnetworkservice.c

index 78e1ab5..58671a4 100644 (file)
@@ -361,6 +361,25 @@ g_network_service_set_scheme (GNetworkService *srv,
   g_object_notify (G_OBJECT (srv), "scheme");
 }
 
+static GList *
+g_network_service_fallback_targets (GNetworkService *srv)
+{
+  GSrvTarget *target;
+  struct servent *entry;
+  guint16 port;
+
+  entry = getservbyname (srv->priv->service, "tcp");
+  port = entry ? g_ntohs (entry->s_port) : 0;
+#ifdef HAVE_ENDSERVENT
+  endservent ();
+#endif
+
+  if (entry == NULL)
+      return NULL;
+
+  target = g_srv_target_new (srv->priv->domain, port, 0, 0);
+  return g_list_append (NULL, target);
+}
 
 #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
 #define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
@@ -401,14 +420,26 @@ g_network_service_address_enumerator_next (GSocketAddressEnumerator  *enumerator
   if (!srv_enum->srv->priv->targets)
     {
       GList *targets;
+      GError *my_error = NULL;
 
       targets = g_resolver_lookup_service (srv_enum->resolver,
                                            srv_enum->srv->priv->service,
                                            srv_enum->srv->priv->protocol,
                                            srv_enum->srv->priv->domain,
-                                           cancellable, error);
+                                           cancellable, &my_error);
+      if (!targets && g_error_matches (my_error, G_RESOLVER_ERROR,
+                                       G_RESOLVER_ERROR_NOT_FOUND))
+        {
+          targets = g_network_service_fallback_targets (srv_enum->srv);
+          if (targets)
+            g_clear_error (&my_error);
+        }
+
       if (!targets)
-        return NULL;
+        {
+          g_propagate_error (error, my_error);
+          return NULL;
+        }
 
       srv_enum->srv->priv->targets = targets;
       srv_enum->t = srv_enum->srv->priv->targets;
@@ -546,9 +577,18 @@ next_async_resolved_targets (GObject      *source_object,
 {
   GNetworkServiceAddressEnumerator *srv_enum = user_data;
   GError *error = NULL;
+  GList *targets;
 
-  srv_enum->srv->priv->targets =
-    g_resolver_lookup_service_finish (srv_enum->resolver, result, &error);
+  targets = g_resolver_lookup_service_finish (srv_enum->resolver,
+                                              result, &error);
+
+  if (!targets && g_error_matches (error, G_RESOLVER_ERROR,
+                                   G_RESOLVER_ERROR_NOT_FOUND))
+    {
+      targets = g_network_service_fallback_targets (srv_enum->srv);
+      if (targets)
+        g_clear_error (&error);
+    }
 
   if (error)
     {
@@ -562,7 +602,7 @@ next_async_resolved_targets (GObject      *source_object,
     }
   else
     {
-      srv_enum->t = srv_enum->srv->priv->targets;
+      srv_enum->t = srv_enum->srv->priv->targets = targets;
       next_async_have_targets (srv_enum);
     }
 }