diff options
Diffstat (limited to 'qemu/roms/ipxe/src/usr/nslookup.c')
-rw-r--r-- | qemu/roms/ipxe/src/usr/nslookup.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/usr/nslookup.c b/qemu/roms/ipxe/src/usr/nslookup.c new file mode 100644 index 000000000..eb2b08b42 --- /dev/null +++ b/qemu/roms/ipxe/src/usr/nslookup.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2012 Patrick Plenefisch <phplenefisch@wpi.edu>. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ipxe/resolv.h> +#include <ipxe/tcpip.h> +#include <ipxe/monojob.h> +#include <ipxe/settings.h> +#include <usr/nslookup.h> + +/** @file + * + * Standalone name resolution + * + */ + +/** A name resolution request */ +struct nslookup { + /** Reference count for this object */ + struct refcnt refcnt; + + /** Job control interface */ + struct interface job; + /** Data transfer interface */ + struct interface resolver; + + /** Setting name */ + char *setting_name; +}; + +/** + * Terminate name resolution + * + * @v nslookup Name resolution request + * @v rc Reason for termination + */ +static void nslookup_close ( struct nslookup *nslookup, int rc ) { + + /* Shut down interfaces */ + intf_shutdown ( &nslookup->resolver, rc ); + intf_shutdown ( &nslookup->job, rc ); +} + +/** + * Handle resolved name + * + * @v nslookup Name resolution request + * @v sa Completed socket address + */ +static void nslookup_resolv_done ( struct nslookup *nslookup, + struct sockaddr *sa ) { + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + const struct setting_type *default_type; + struct settings *settings; + struct setting setting; + void *data; + size_t len; + int rc; + + /* Extract address */ + switch ( sa->sa_family ) { + case AF_INET: + sin = ( ( struct sockaddr_in * ) sa ); + data = &sin->sin_addr; + len = sizeof ( sin->sin_addr ); + default_type = &setting_type_ipv4; + break; + case AF_INET6: + sin6 = ( ( struct sockaddr_in6 * ) sa ); + data = &sin6->sin6_addr; + len = sizeof ( sin6->sin6_addr ); + default_type = &setting_type_ipv6; + break; + default: + rc = -ENOTSUP; + goto err; + } + + /* Parse specified setting name */ + if ( ( rc = parse_setting_name ( nslookup->setting_name, + autovivify_child_settings, &settings, + &setting ) ) != 0 ) + goto err; + + /* Apply default type if necessary */ + if ( ! setting.type ) + setting.type = default_type; + + /* Store in specified setting */ + if ( ( rc = store_setting ( settings, &setting, data, len ) ) != 0 ) + goto err; + + err: + /* Terminate name resolution */ + nslookup_close ( nslookup, rc ); +} + +/** Name resolution resolver interface operations */ +static struct interface_operation nslookup_resolver_operations[] = { + INTF_OP ( resolv_done, struct nslookup *, nslookup_resolv_done ), + INTF_OP ( intf_close, struct nslookup *, nslookup_close ), +}; + +/** Name resolution resolver interface descriptor */ +static struct interface_descriptor nslookup_resolver_desc = + INTF_DESC_PASSTHRU ( struct nslookup, resolver, + nslookup_resolver_operations, job ); + +/** Name resolution job control interface operations */ +static struct interface_operation nslookup_job_operations[] = { + INTF_OP ( intf_close, struct nslookup *, nslookup_close ), +}; + +/** Name resolution job control interface descriptor */ +static struct interface_descriptor nslookup_job_desc = + INTF_DESC_PASSTHRU ( struct nslookup, job, + nslookup_job_operations, resolver ); + +/** + * Initiate standalone name resolution + * + * @v job Parent interface + * @v name Name to resolve + * @v setting_name Setting name + * @ret rc Return status code + */ +static int resolv_setting ( struct interface *job, const char *name, + const char *setting_name ) { + struct nslookup *nslookup; + struct sockaddr sa; + char *setting_name_copy; + int rc; + + /* Allocate and initialise structure */ + nslookup = zalloc ( sizeof ( *nslookup ) + strlen ( setting_name ) + + 1 /* NUL */ ); + if ( ! nslookup ) + return -ENOMEM; + ref_init ( &nslookup->refcnt, NULL ); + intf_init ( &nslookup->job, &nslookup_job_desc, &nslookup->refcnt ); + intf_init ( &nslookup->resolver, &nslookup_resolver_desc, + &nslookup->refcnt ); + setting_name_copy = ( ( void * ) ( nslookup + 1 ) ); + strcpy ( setting_name_copy, setting_name ); + nslookup->setting_name = setting_name_copy; + + /* Start name resolution */ + memset ( &sa, 0, sizeof ( sa ) ); + if ( ( rc = resolv ( &nslookup->resolver, name, &sa ) ) != 0 ) + goto err_resolv; + + /* Attach parent interface, mortalise self, and return */ + intf_plug_plug ( &nslookup->job, job ); + ref_put ( &nslookup->refcnt ); + return 0; + + err_resolv: + ref_put ( &nslookup->refcnt ); + return rc; +} + +/** + * Perform (blocking) standalone name resolution + * + * @v name Name to resolve + * @v setting_name Setting name + * @ret rc Return status code + */ +int nslookup ( const char *name, const char *setting_name ) { + int rc; + + /* Perform name resolution */ + if ( ( rc = resolv_setting ( &monojob, name, setting_name ) ) == 0 ) + rc = monojob_wait ( NULL, 0 ); + if ( rc != 0 ) { + printf ( "Could not resolve %s: %s\n", name, strerror ( rc ) ); + return rc; + } + + return 0; +} |