diff options
Diffstat (limited to '')
-rw-r--r-- | src/common/admin_socket_client.cc | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/common/admin_socket_client.cc b/src/common/admin_socket_client.cc new file mode 100644 index 000000000..aeddc100f --- /dev/null +++ b/src/common/admin_socket_client.cc @@ -0,0 +1,172 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2011 New Dream Network + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include <arpa/inet.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +#include "common/admin_socket.h" +#include "common/errno.h" +#include "common/safe_io.h" +#include "common/admin_socket_client.h" + +#include "include/compat.h" +#include "include/sock_compat.h" + +using std::ostringstream; + +const char* get_rand_socket_path() +{ + static char *g_socket_path = NULL; + + if (g_socket_path == NULL) { + char buf[512]; + const char *tdir = getenv("TMPDIR"); + #ifdef _WIN32 + if (tdir == NULL) { + tdir = getenv("TEMP"); + } + #endif /* _WIN32 */ + if (tdir == NULL) { + tdir = "/tmp"; + } + snprintf(buf, sizeof(((struct sockaddr_un*)0)->sun_path), + "%s/perfcounters_test_socket.%ld.%ld", + tdir, (long int)getpid(), time(NULL)); + g_socket_path = (char*)strdup(buf); + } + return g_socket_path; +} + +static std::string asok_connect(const std::string &path, int *fd) +{ + int socket_fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0); + if(socket_fd < 0) { + int err = ceph_sock_errno(); + ostringstream oss; + oss << "socket(PF_UNIX, SOCK_STREAM, 0) failed: " << cpp_strerror(err); + return oss.str(); + } + + struct sockaddr_un address; + // FIPS zeroization audit 20191115: this memset is fine. + memset(&address, 0, sizeof(struct sockaddr_un)); + address.sun_family = AF_UNIX; + snprintf(address.sun_path, sizeof(address.sun_path), "%s", path.c_str()); + + if (::connect(socket_fd, (struct sockaddr *) &address, + sizeof(struct sockaddr_un)) != 0) { + int err = ceph_sock_errno(); + ostringstream oss; + oss << "connect(" << socket_fd << ") failed: " << cpp_strerror(err); + compat_closesocket(socket_fd); + return oss.str(); + } + + struct timeval timer; + timer.tv_sec = 10; + timer.tv_usec = 0; + if (::setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (SOCKOPT_VAL_TYPE)&timer, sizeof(timer))) { + int err = ceph_sock_errno(); + ostringstream oss; + oss << "setsockopt(" << socket_fd << ", SO_RCVTIMEO) failed: " + << cpp_strerror(err); + compat_closesocket(socket_fd); + return oss.str(); + } + timer.tv_sec = 10; + timer.tv_usec = 0; + if (::setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, (SOCKOPT_VAL_TYPE)&timer, sizeof(timer))) { + int err = ceph_sock_errno(); + ostringstream oss; + oss << "setsockopt(" << socket_fd << ", SO_SNDTIMEO) failed: " + << cpp_strerror(err); + compat_closesocket(socket_fd); + return oss.str(); + } + + *fd = socket_fd; + return ""; +} + +static std::string asok_request(int socket_fd, std::string request) +{ + ssize_t res = safe_send(socket_fd, request.c_str(), request.length() + 1); + if (res < 0) { + int err = res; + ostringstream oss; + oss << "safe_write(" << socket_fd << ") failed to write request code: " + << cpp_strerror(err); + return oss.str(); + } + return ""; +} + +AdminSocketClient:: +AdminSocketClient(const std::string &path) + : m_path(path) +{ +} + +std::string AdminSocketClient::ping(bool *ok) +{ + std::string version; + std::string result = do_request("{\"prefix\":\"0\"}", &version); + *ok = result == "" && version.length() == 1; + return result; +} + +std::string AdminSocketClient::do_request(std::string request, std::string *result) +{ + int socket_fd = 0, res; + std::string buffer; + uint32_t message_size_raw, message_size; + + std::string err = asok_connect(m_path, &socket_fd); + if (!err.empty()) { + goto out; + } + err = asok_request(socket_fd, request); + if (!err.empty()) { + goto done; + } + res = safe_recv_exact(socket_fd, &message_size_raw, + sizeof(message_size_raw)); + if (res < 0) { + int e = res; + ostringstream oss; + oss << "safe_recv(" << socket_fd << ") failed to read message size: " + << cpp_strerror(e); + err = oss.str(); + goto done; + } + message_size = ntohl(message_size_raw); + buffer.resize(message_size, 0); + res = safe_recv_exact(socket_fd, &buffer[0], message_size); + if (res < 0) { + int e = res; + ostringstream oss; + oss << "safe_recv(" << socket_fd << ") failed: " << cpp_strerror(e); + err = oss.str(); + goto done; + } + //printf("MESSAGE FROM SERVER: %s\n", buffer.c_str()); + std::swap(*result, buffer); +done: + compat_closesocket(socket_fd); + out: + return err; +} |