X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=testing%2Flib%2FServer.cpp;h=b3d0118baf9a51f14dbab99101e8f85355ef79f5;hb=42f32d1f7926663821f7a76a34584484f7a4b412;hp=bc5de99fe7a0aeee997535b71bafe6b44e863ff7;hpb=5e54d17fc535a901f384fcbf2cfd420f3a2e7a81;p=m6w6%2Flibmemcached diff --git a/testing/lib/Server.cpp b/testing/lib/Server.cpp index bc5de99f..b3d0118b 100644 --- a/testing/lib/Server.cpp +++ b/testing/lib/Server.cpp @@ -1,100 +1,90 @@ #include "Server.hpp" -#include "WaitForExec.hpp" -#include "WaitForConn.hpp" +#include "Connection.hpp" +#include "ForkAndExec.hpp" -#include -#include -#include -#include #include #include -#include -#include - -using namespace std; - -[[nodiscard]] -auto Server::createArgv() { - auto i = 0, port = -1, socket = -1; - auto arr = new char *[str_args.size() + dyn_args.size()*2 + 2] { - strdup(binary.c_str()) - }; - - for (auto &arg : str_args) { - arr[++i] = strdup(arg.c_str()); - if (arg == "-p") { - port = i + 1; - } else if (arg == "-s") { - socket = i + 1; - } - } - for (auto &arg : dyn_args) { - arr[++i] = strdup(arg.first.c_str()); - arr[++i] = strdup(arg.second(arg.first).c_str()); - if (arg.first == "-p") { - port = i; - } else if (arg.first == "-s") { - socket = i; - } +Server::Server(string &&binary_, Server::argv_t &&args_) + : binary{forward(binary_)} + , args{forward(args_)} +{} +Server::~Server() { + stop(); + wait(); + if (holds_alternative(socket_or_port)) { + unlink(get(socket_or_port).c_str()); } - arr[i+1] = nullptr; +} - if (socket > -1) { - socket_or_port = arr[socket]; - } else if (port > -1) { - socket_or_port = stoi(arr[port]); +static inline string extractArg(const Server::arg_t &arg_cont, const string &func_arg) { + if (holds_alternative(arg_cont)) { + return get(arg_cont); } else { - socket_or_port = 11211; + return get(arg_cont)(func_arg); } - - return arr; } -[[nodiscard]] -optional Server::createSocket() { - sockaddr_storage addr; - unsigned size = 0; - int sock; - - if (holds_alternative(socket_or_port)) { - const auto path = get(socket_or_port); - const auto safe = path.c_str(); - const auto zlen = path.length() + 1; - const auto ulen = sizeof(sockaddr_un) - sizeof(sa_family_t); - - if (zlen >= ulen) { - cerr << "Server::isListening socket(): path too long '" << path << "'\n"; - return {}; - } - - if (0 > (sock = socket(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0))) { - perror("Server::isListening socket()"); - return {}; - } +static inline void pushArg(vector &arr, const string &arg) { + auto len = arg.size(); + auto str = arg.data(), end = str + len + 1; + auto ptr = new char[len + 1]; + copy(str, end, ptr); + arr.push_back(ptr); +} - auto sa = reinterpret_cast(&addr); - sa->sun_family = AF_UNIX; - strncpy(sa->sun_path, safe, zlen); +optional Server::handleArg(vector &arr, const string &arg, const arg_func_t &next_arg) { + pushArg(arr, arg); + if (arg == "-p" || arg == "--port") { + auto port = next_arg(arg); + pushArg(arr, port); + pushArg(arr, "-U"); + pushArg(arr, port); + socket_or_port = stoi(port); + return port; + } else if (arg == "-s" || arg == "--unix-socket") { + auto sock = next_arg(arg); + pushArg(arr, sock); + socket_or_port = sock; + return sock; + } + return {}; +} - size = sizeof(*sa); - } else { - if (0 > (sock = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0))) { - perror("Server::isListening socket()"); - return {}; +[[nodiscard]] +vector Server::createArgv() { + vector arr; + + pushArg(arr, binary); + pushArg(arr, "-v"); + + for (auto it = args.cbegin(); it != args.cend(); ++it) { + if (holds_alternative(*it)) { + // a single argument + auto arg = extractArg(get(*it), binary); + handleArg(arr, arg, [&it](const string &arg_) { + return extractArg(get(*++it), arg_); + }); + } else { + // an argument pair + auto &[one, two] = get(*it); + auto arg_one = extractArg(one, binary); + auto arg_two = extractArg(two, arg_one); + + auto next = handleArg(arr, arg_one, [&arg_two](const string &) { + return arg_two; + }); + + if (!next.has_value()) { + pushArg(arr, arg_two); + } } - - const auto port = get(socket_or_port); - auto sa = reinterpret_cast(&addr); - sa->sin_family = AF_INET; - sa->sin_port = htons(static_cast(port)), - sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - size = sizeof(*sa); } - return optional{make_tuple(sock, addr, size)}; + arr.push_back(nullptr); + + return arr; } optional Server::start() { @@ -102,36 +92,27 @@ optional Server::start() { return pid; } - WaitForExec wait_for_exec; + auto argv = createArgv(); + auto child = ForkAndExec{binary.c_str(), argv.data()}(); - switch (pid = fork()) { - case 0: - execvp(binary.c_str(), createArgv()); - [[fallthrough]]; - case -1: - perror("Server::start fork() & exec()"); - return {}; + for (auto argp : argv) { + delete [] argp; + } - default: - if (!wait_for_exec()) { - cerr << "Server::start exec(): incomplete\n"; - } - return pid; + if (child.has_value()) { + pid = child.value(); } + + return child; } -bool Server::isListening(int max_timeout) { - auto conn = createSocket(); +bool Server::isListening() { + Connection conn(socket_or_port); - if (!conn) { + if (!conn.open()) { return false; } - - WaitForConn wait_for_conn{ - {conn.value()}, - Poll{POLLOUT, 2, max_timeout} - }; - return wait_for_conn(); + return conn.isOpen(); } bool Server::stop() { @@ -168,3 +149,33 @@ bool Server::wait(int flags) { bool Server::tryWait() { return wait(WNOHANG); } + +Server::Server(const Server &s) { + binary = s.binary; + args = s.args; + socket_or_port = s.socket_or_port; +} + +Server &Server::operator=(const Server &s) { + binary = s.binary; + args = s.args; + socket_or_port = s.socket_or_port; + return *this; +} + +pid_t Server::getPid() const { + return pid; +} + +const string &Server::getBinary() const { + return binary; +} + +const Server::argv_t &Server::getArgs() const { + return args; +} + +const socket_or_port_t &Server::getSocketOrPort() const { + return socket_or_port; +} +