A working name resolution framework
authorMichael Brown <mcb30@etherboot.org>
Thu, 18 Jan 2007 22:38:13 +0000 (22:38 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 18 Jan 2007 22:38:13 +0000 (22:38 +0000)
src/config.h
src/core/resolv.c
src/include/gpxe/resolv.h [new file with mode: 0644]
src/include/resolv.h [deleted file]
src/net/tcp/http.c
src/net/udp/dns.c
src/usr/dhcpmgmt.c

index 4c1af38..1e75f46 100644 (file)
@@ -72,7 +72,7 @@
 
 #define        DOWNLOAD_PROTO_TFTP     /* Trivial File Transfer Protocol */
 #undef DOWNLOAD_PROTO_NFS      /* Network File System */
 
 #define        DOWNLOAD_PROTO_TFTP     /* Trivial File Transfer Protocol */
 #undef DOWNLOAD_PROTO_NFS      /* Network File System */
-#undef DOWNLOAD_PROTO_HTTP     /* Hypertext Transfer Protocol */
+#define        DOWNLOAD_PROTO_HTTP     /* Hypertext Transfer Protocol */
 #undef DOWNLOAD_PROTO_TFTM     /* Multicast Trivial File Transfer Protocol */
 #undef DOWNLOAD_PROTO_SLAM     /* Scalable Local Area Multicast */
 #undef DOWNLOAD_PROTO_FSP      /* FSP? */
 #undef DOWNLOAD_PROTO_TFTM     /* Multicast Trivial File Transfer Protocol */
 #undef DOWNLOAD_PROTO_SLAM     /* Scalable Local Area Multicast */
 #undef DOWNLOAD_PROTO_FSP      /* FSP? */
@@ -85,7 +85,7 @@
  *
  */
 
  *
  */
 
-#undef DNS_RESOLVER            /* DNS resolver */
+#define        DNS_RESOLVER            /* DNS resolver */
 #undef NMB_RESOLVER            /* NMB resolver */
 
 /* @END general.h */
 #undef NMB_RESOLVER            /* NMB resolver */
 
 /* @END general.h */
index eb01a30..61bdfb0 100644 (file)
-#include "resolv.h"
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <gpxe/in.h>
+#include <gpxe/resolv.h>
 
 
+/** @file
+ *
+ * Name resolution
+ *
+ */
+
+static struct async_operations resolv_async_operations;
+
+/** Registered name resolvers */
 static struct resolver resolvers[0]
 static struct resolver resolvers[0]
-       __table_start ( struct resolver, resolver );
+       __table_start ( struct resolver, resolvers );
 static struct resolver resolvers_end[0]
 static struct resolver resolvers_end[0]
-       __table_end ( struct resolver, resolver );
+       __table_end ( struct resolver, resolvers );
 
 
-/*
- * Resolve a name (which may be just a dotted quad IP address) to an
- * IP address.
+/**
+ * Start name resolution
  *
  *
+ * @v name             Host name to resolve
+ * @v sa               Socket address to fill in
+ * @v parent           Parent asynchronous operation
+ * @ret rc             Return status code
  */
  */
-int resolv ( struct in_addr *address, const char *name ) {
+int resolv ( const char *name, struct sockaddr *sa, struct async *parent ) {
+       struct resolution *resolution;
        struct resolver *resolver;
        struct resolver *resolver;
+       struct sockaddr_in *sin = ( struct sockaddr_in * ) sa;
+       struct in_addr in;
+       int rc = -ENXIO;
+
+       /* Allocate and populate resolution structure */
+       resolution = malloc ( sizeof ( *resolution ) );
+       if ( ! resolution )
+               return -ENOMEM;
+       async_init ( &resolution->async, &resolv_async_operations, parent );
 
        /* Check for a dotted quad IP address first */
 
        /* Check for a dotted quad IP address first */
-       if ( inet_aton ( name, address ) ) {
-               DBG ( "RESOLV saw valid IP address %s\n", name );
-               return 1;
+       if ( inet_aton ( name, &in ) != 0 ) {
+               DBGC ( resolution, "RESOLV %p saw valid IP address %s\n",
+                      resolution, name );
+               sin->sin_family = AF_INET;
+               sin->sin_addr = in;
+               async_done ( &resolution->async, 0 );
+               return 0;
        }
 
        }
 
-       /* Try any compiled-in name resolution modules */
+       /* Start up all resolvers */
        for ( resolver = resolvers ; resolver < resolvers_end ; resolver++ ) {
        for ( resolver = resolvers ; resolver < resolvers_end ; resolver++ ) {
-               if ( resolver->resolv ( address, name ) ) {
-                       DBG ( "RESOLV resolved \"%s\" to %@ using %s\n",
-                             name, address->s_addr, resolver->name );
-                       return 1;
+               if ( ( rc = resolver->resolv ( name, sa,
+                                              &resolution->async ) ) != 0 ) {
+                       DBGC ( resolution, "RESOLV %p could not start %s: "
+                              "%s\n", resolution, resolver->name,
+                              strerror ( rc ) );
+                       /* Continue to try other resolvers */
+                       continue;
                }
                }
+               (resolution->pending)++;
        }
        }
+       if ( ! resolution->pending )
+               goto err;
 
 
-       DBG ( "RESOLV failed to resolve %s\n", name );
        return 0;
        return 0;
+
+ err:
+       async_uninit ( &resolution->async );
+       free ( resolution );
+       return rc;
 }
 }
+
+/**
+ * Handle child name resolution completion
+ *
+ * @v async            Name resolution asynchronous operation
+ * @v signal           SIGCHLD
+ */
+static void resolv_sigchld ( struct async *async,
+                            enum signal signal __unused ) {
+       struct resolution *resolution =
+               container_of ( async, struct resolution, async );
+       int rc;
+
+       /* If this child succeeded, kill all the others and return */
+       async_wait ( async, &rc, 1 );
+       if ( rc == 0 ) {
+               async_signal_children ( async, SIGKILL );
+               async_done ( async, 0 );
+               return;
+       }
+
+       /* If we have no children left, return failure */
+       if ( --(resolution->pending) == 0 )
+               async_done ( async, -ENXIO );
+}
+
+/**
+ * Free name resolution structure
+ *
+ * @v async            Asynchronous operation
+ */
+static void resolv_reap ( struct async *async ) {
+       free ( container_of ( async, struct resolution, async ) );
+}
+
+/** Name resolution asynchronous operations */
+static struct async_operations resolv_async_operations = {
+       .reap = resolv_reap,
+       .signal = {
+               [SIGCHLD] = resolv_sigchld,
+       },
+};
diff --git a/src/include/gpxe/resolv.h b/src/include/gpxe/resolv.h
new file mode 100644 (file)
index 0000000..7136401
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _GPXE_RESOLV_H
+#define _GPXE_RESOLV_H
+
+/** @file
+ *
+ * Name resolution
+ *
+ */
+
+struct sockaddr;
+
+#include <gpxe/async.h>
+#include <gpxe/tables.h>
+
+/** A name resolver */
+struct resolver {
+       /** Name of this resolver (e.g. "DNS") */
+       const char *name;
+       /** Start name resolution
+        *
+        * @v name              Host name to resolve
+        * @v sa                Socket address to fill in
+        * @v parent            Parent asynchronous operation
+        * @ret rc              Return status code
+        *
+        * The asynchronous process must be prepared to accept
+        * SIGKILL.
+        */
+       int ( * resolv ) ( const char *name, struct sockaddr *sa,
+                          struct async *parent );
+};
+
+/** A name resolution in progress */
+struct resolution {
+       /** Asynchronous operation */
+       struct async async;
+       /** Numner of active child resolvers */
+       unsigned int pending;
+};
+
+/** Register as a name resolver */
+#define __resolver __table ( struct resolver, resolvers, 01 )
+
+extern int resolv ( const char *name, struct sockaddr *sa,
+                   struct async *parent );
+
+#endif /* _GPXE_RESOLV_H */
diff --git a/src/include/resolv.h b/src/include/resolv.h
deleted file mode 100644 (file)
index 714d39e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef RESOLV_H
-#define RESOLV_H
-
-#include <gpxe/in.h>
-#include <gpxe/tables.h>
-
-struct resolver {
-       const char *name;
-       int ( * resolv ) ( struct in_addr *address, const char *name );
-};
-
-#define __resolver __table ( struct resolver, resolver, 01 )
-
-extern int resolv ( struct in_addr *address, const char *name );
-
-#endif /* RESOLV_H */
index 04e8f9a..87f6eee 100644 (file)
@@ -35,6 +35,7 @@
 #include <gpxe/uri.h>
 #include <gpxe/buffer.h>
 #include <gpxe/download.h>
 #include <gpxe/uri.h>
 #include <gpxe/buffer.h>
 #include <gpxe/download.h>
+#include <gpxe/resolv.h>
 #include <gpxe/http.h>
 
 static struct async_operations http_async_operations;
 #include <gpxe/http.h>
 
 static struct async_operations http_async_operations;
@@ -391,17 +392,12 @@ int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
        http->buffer = buffer;
        async_init ( &http->async, &http_async_operations, parent );
 
        http->buffer = buffer;
        async_init ( &http->async, &http_async_operations, parent );
 
-
-#warning "Quick name resolution hack"
-       extern int dns_resolv ( const char *name,
-                               struct sockaddr *sa,
-                               struct async *parent );
-               
-       if ( ( rc = dns_resolv ( uri->host, &http->server,
-                                &http->async ) ) != 0 )
+       /* Start name resolution.  The download proper will start when
+        * name resolution completes.
+        */
+       if ( ( rc = resolv ( uri->host, &http->server, &http->async ) ) != 0 )
                goto err;
 
                goto err;
 
-
        return 0;
 
  err:
        return 0;
 
  err:
index 872e3b2..a5b658c 100644 (file)
@@ -26,6 +26,7 @@
 #include <byteswap.h>
 #include <gpxe/async.h>
 #include <gpxe/udp.h>
 #include <byteswap.h>
 #include <gpxe/async.h>
 #include <gpxe/udp.h>
+#include <gpxe/resolv.h>
 #include <gpxe/dns.h>
 
 /** @file
 #include <gpxe/dns.h>
 
 /** @file
@@ -468,3 +469,9 @@ int dns_resolv ( const char *name, struct sockaddr *sa,
        free ( dns );
        return rc;
 }
        free ( dns );
        return rc;
 }
+
+/** DNS name resolver */
+struct resolver dns_resolver __resolver = {
+       .name = "DNS",
+       .resolv = dns_resolv,
+};
index 6f03027..42a0f2b 100644 (file)
@@ -24,6 +24,7 @@
 #include <gpxe/dhcp.h>
 #include <gpxe/async.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/dhcp.h>
 #include <gpxe/async.h>
 #include <gpxe/netdevice.h>
+#include <gpxe/dns.h>
 #include <usr/ifmgmt.h>
 #include <usr/dhcpmgmt.h>
 
 #include <usr/ifmgmt.h>
 #include <usr/dhcpmgmt.h>
 
@@ -33,6 +34,9 @@
  *
  */
 
  *
  */
 
+/* Avoid dragging in dns.o */
+struct in_addr nameserver;
+
 /**
  * Configure network device via DHCP
  *
 /**
  * Configure network device via DHCP
  *
@@ -42,8 +46,8 @@
 int dhcp ( struct net_device *netdev ) {
        static struct dhcp_option_block *dhcp_options = NULL;
        struct dhcp_session dhcp;
 int dhcp ( struct net_device *netdev ) {
        static struct dhcp_option_block *dhcp_options = NULL;
        struct dhcp_session dhcp;
-       struct in_addr address = { htonl ( 0 ) };
-       struct in_addr netmask = { htonl ( 0 ) };
+       struct in_addr address = { 0 };
+       struct in_addr netmask = { 0 };
        struct in_addr gateway = { INADDR_NONE };
        struct async async;
        int rc;
        struct in_addr gateway = { INADDR_NONE };
        struct async async;
        int rc;
@@ -90,5 +94,9 @@ int dhcp ( struct net_device *netdev ) {
                return rc;
        }
 
                return rc;
        }
 
+       /* Retrieve other DHCP options that we care about */
+       find_dhcp_ipv4_option ( dhcp_options, DHCP_DNS_SERVERS,
+                               &nameserver );
+
        return 0;
 }
        return 0;
 }