From 4d62590116c983e7a7a42c51f1c36e8e7dc7c370 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 4 May 2021 15:32:48 +0100 Subject: [PATCH] Add server resolution argument handling Add functions to resolve server specifier arguments to server records, looking up the host addresses. Signed-off-by: David Howells --- kafs/Makefile | 1 + kafs/arg_parse.H | 6 ++ kafs/arg_resolve.C | 150 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 kafs/arg_resolve.C diff --git a/kafs/Makefile b/kafs/Makefile index c794fbd..ff2ba22 100644 --- a/kafs/Makefile +++ b/kafs/Makefile @@ -7,6 +7,7 @@ CORE_SRCS := \ kafs.C \ arg_completion.C \ arg_parse.C \ + arg_resolve.C \ display.C \ display_error.C \ display_vol.C \ diff --git a/kafs/arg_parse.H b/kafs/arg_parse.H index 3c7bb03..ef66192 100644 --- a/kafs/arg_parse.H +++ b/kafs/arg_parse.H @@ -86,6 +86,12 @@ struct Nocombine { class Gave_help : std::exception { }; +/* + * arg_resolve.C + */ +extern rxrpc::ref resolve_server_spec(Context *ctx, + const FVserver_spec &spec); + /* * arg_parse.C */ diff --git a/kafs/arg_resolve.C b/kafs/arg_resolve.C new file mode 100644 index 0000000..4a28d05 --- /dev/null +++ b/kafs/arg_resolve.C @@ -0,0 +1,150 @@ +/* Argument resolver + * + * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include "rxrpc.H" +#include "afs_xg.H" +#include "arg_parse.H" + +using rxrpc::ref; + +bool kafs::Fileserver_spec::is_volser_spec() const { return false; } +bool kafs::Volserver_spec::is_volser_spec() const { return true; } + +/** + * kafs::resolve_server_spec - Resolve a volume or fileserver server spec + * @ctx: The cell and authentication context + * @vs: The server specifier + * + * Resolve a volume server or fileserver specified as a name or address into a + * set of addresses that can be used to contact it. The addresses are attached + * to a server record, which is returned. + */ +ref kafs::resolve_server_spec(Context *ctx, + const FVserver_spec &spec) +{ + ref site; + struct addrinfo *ai = NULL, *p; + struct servent fs_serv, vs_serv, *serv_result; + const char *service = spec.is_volser_spec() ? "afs3-volser" : "afs3-fileserver"; + char *canon = NULL, buf[1024]; + int err, n; + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, + }; + + _enter("%s", spec.name.c_str()); + + if (getservbyname_r("afs3-fileserver", "udp", + &fs_serv, buf, sizeof(buf), &serv_result) < 0) + throw std::system_error( + std::error_code(errno, std::generic_category()), + "Failed to look up 'afs3-fileserver' service"); + if (!serv_result) + throw std::runtime_error("Service 'afs3-fileserver' not found"); + + if (getservbyname_r("afs3-volser", "udp", + &vs_serv, buf, sizeof(buf), &serv_result) < 0) + throw std::system_error( + std::error_code(errno, std::generic_category()), + "Failed to look up 'afs3-volser' service"); + if (!serv_result) + throw std::runtime_error("Service 'afs3-volser' not found"); + + site = new FS_site; + + try { + err = getaddrinfo(spec.name.c_str(), service, &hints, &ai); + if (err != 0) + throw std::runtime_error( + fmt::format("{}: {}", spec.name, gai_strerror(err))); + + /* Count the number of usable addresses */ + n = 0; + for (p = ai; p; p = p->ai_next) { + switch (p->ai_family) { + case AF_INET: + case AF_INET6: + n++; + break; + default: + break; + } + } + + std::vector &vs_addrs = site->vs_addrs; + std::vector &fs_addrs = site->fs_addrs; + + n = 0; + for (p = ai; p; p = p->ai_next) { + switch (p->ai_family) { + case AF_INET: + case AF_INET6: + n++; + break; + } + } + vs_addrs.resize(n); + fs_addrs.resize(n); + + n = 0; + for (p = ai; p; p = p->ai_next) { + struct sockaddr_rxrpc &vs_srx = vs_addrs[n]; + struct sockaddr_rxrpc &fs_srx = fs_addrs[n]; + + if (p->ai_canonname && !canon) + canon = p->ai_canonname; + + fs_srx.srx_family = AF_RXRPC; + fs_srx.srx_service = afs::FS_SERVICE; + fs_srx.transport_type = p->ai_socktype; + fs_srx.transport_len = p->ai_addrlen; + + vs_srx.srx_family = AF_RXRPC; + vs_srx.srx_service = afs::VOLSERVICE_ID; + vs_srx.transport_type = p->ai_socktype; + vs_srx.transport_len = p->ai_addrlen; + + switch (p->ai_family) { + case AF_INET: + memcpy(&fs_srx.transport, p->ai_addr, p->ai_addrlen); + memcpy(&vs_srx.transport, p->ai_addr, p->ai_addrlen); + fs_srx.transport.sin.sin_port = fs_serv.s_port; + vs_srx.transport.sin.sin_port = vs_serv.s_port; + n++; + break; + case AF_INET6: + memcpy(&fs_srx.transport, p->ai_addr, p->ai_addrlen); + memcpy(&vs_srx.transport, p->ai_addr, p->ai_addrlen); + fs_srx.transport.sin6.sin6_port = fs_serv.s_port; + vs_srx.transport.sin6.sin6_port = vs_serv.s_port; + n++; + break; + } + } + + site->name = canon ?: spec.name; + + freeaddrinfo(ai); + _leave(" = t [%zu,%zu]", site->vs_addrs.size(), site->fs_addrs.size()); + return site; + } catch (...) { + freeaddrinfo(ai); + throw; + } +} -- 2.49.0