]> www.infradead.org Git - users/dhowells/kafs-utils.git/commitdiff
Add server resolution argument handling
authorDavid Howells <dhowells@redhat.com>
Tue, 4 May 2021 14:32:48 +0000 (15:32 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 5 May 2023 10:53:26 +0000 (11:53 +0100)
Add functions to resolve server specifier arguments to server records,
looking up the host addresses.

Signed-off-by: David Howells <dhowells@redhat.com>
kafs/Makefile
kafs/arg_parse.H
kafs/arg_resolve.C [new file with mode: 0644]

index c794fbd243b48d80b2ed0e6ff69732c2b36e3f8d..ff2ba2271501ac3d33dcbf5e661c3bbf0c87f3aa 100644 (file)
@@ -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 \
index 3c7bb0366bb16bc11f5d2a7c1ee08108f05be274..ef6619243e246dffce9dc01a7d1740910206cc27 100644 (file)
@@ -86,6 +86,12 @@ struct Nocombine {
 class Gave_help : std::exception {
 };
 
+/*
+ * arg_resolve.C
+ */
+extern rxrpc::ref<FS_site> 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 (file)
index 0000000..4a28d05
--- /dev/null
@@ -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 <ctype.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fmt/format.h>
+#include <kafs/cellserv.h>
+#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::FS_site> kafs::resolve_server_spec(Context *ctx,
+                                            const FVserver_spec &spec)
+{
+       ref<FS_site> 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<sockaddr_rxrpc> &vs_addrs = site->vs_addrs;
+               std::vector<sockaddr_rxrpc> &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;
+       }
+}