diff options
author | Damian Hobson-Garcia <dhobsong@igel.co.jp> | 2021-02-19 03:52:55 +0000 |
---|---|---|
committer | Damian Hobson-Garcia <dhobsong@igel.co.jp> | 2021-04-06 15:58:47 +0900 |
commit | abb27e7774e3cd12bd3cfe3d4858bbe590e59be0 (patch) | |
tree | 2b676f85323f0297ffd187d3aef2c0b224e2ff99 | |
parent | d196375b8b130e119285fb19984870edc6941a90 (diff) |
Add lease request and release protocol
Explicitly request / release leases instead of implicitly
by opening and closing the connection. This will allow the
lease manager to take different action when a client
shuts down gracefully vs when it crashes, holding a lease.
Bug-AGL: SPEC-3862
Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
Change-Id: Ibc68bee855ce18e56eb6f57e5ad1743248320013
-rw-r--r-- | common/dlm-protocol.c | 66 | ||||
-rw-r--r-- | common/dlm-protocol.h | 32 | ||||
-rw-r--r-- | common/meson.build | 1 | ||||
-rw-r--r-- | drm-lease-manager/lease-server.c | 62 | ||||
-rw-r--r-- | drm-lease-manager/test/test-socket-client.c | 14 | ||||
-rw-r--r-- | libdlmclient/dlmclient.c | 35 | ||||
-rw-r--r-- | libdlmclient/test/test-socket-server.c | 13 |
7 files changed, 193 insertions, 30 deletions
diff --git a/common/dlm-protocol.c b/common/dlm-protocol.c new file mode 100644 index 0000000..4fc87b2 --- /dev/null +++ b/common/dlm-protocol.c @@ -0,0 +1,66 @@ +/* Copyright 2020-2021 IGEL Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dlm-protocol.h" + +#include <errno.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +bool receive_dlm_client_request(int socket, struct dlm_client_request *request) +{ + + ssize_t len; + struct iovec iov = { + .iov_base = request, + .iov_len = sizeof(*request), + }; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + while ((len = recvmsg(socket, &msg, 0)) < 0) { + if (errno != EINTR) + return false; + } + + if (len != sizeof(*request)) { + errno = EPROTO; + return false; + } + return true; +} + +bool send_dlm_client_request(int socket, struct dlm_client_request *request) +{ + struct iovec iov = { + .iov_base = request, + .iov_len = sizeof(*request), + }; + + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + while (sendmsg(socket, &msg, 0) < 1) { + if (errno != EINTR) + return false; + } + return true; +} diff --git a/common/dlm-protocol.h b/common/dlm-protocol.h new file mode 100644 index 0000000..44785e5 --- /dev/null +++ b/common/dlm-protocol.h @@ -0,0 +1,32 @@ +/* Copyright 2020-2021 IGEL Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DLM_PROTOCOL_H +#define DLM_PROTOCOL_H + +#include <stdbool.h> + +enum dlm_opcode { + DLM_GET_LEASE, + DLM_RELEASE_LEASE, +}; + +struct dlm_client_request { + enum dlm_opcode opcode; +}; + +bool receive_dlm_client_request(int socket, struct dlm_client_request *request); +bool send_dlm_client_request(int socket, struct dlm_client_request *request); +#endif diff --git a/common/meson.build b/common/meson.build index e465fa5..663c1ce 100644 --- a/common/meson.build +++ b/common/meson.build @@ -1,4 +1,5 @@ libdlmcommon_sources = [ + 'dlm-protocol.c', 'socket-path.c', 'log.c' ] diff --git a/drm-lease-manager/lease-server.c b/drm-lease-manager/lease-server.c index c57316e..ac4dd01 100644 --- a/drm-lease-manager/lease-server.c +++ b/drm-lease-manager/lease-server.c @@ -14,6 +14,8 @@ */ #include "lease-server.h" + +#include "dlm-protocol.h" #include "log.h" #include "socket-path.h" @@ -75,13 +77,13 @@ struct ls { int nservers; }; -static struct ls_client *client_connect(struct ls *ls, struct ls_server *serv) +static void client_connect(struct ls *ls, struct ls_server *serv) { int cfd = accept(serv->listen.fd, NULL, NULL); if (cfd < 0) { DEBUG_LOG("accept failed on %s: %s\n", serv->address.sun_path, strerror(errno)); - return NULL; + return; } struct ls_client *client = NULL; @@ -94,23 +96,44 @@ static struct ls_client *client_connect(struct ls *ls, struct ls_server *serv) } if (!client) { close(cfd); - return NULL; + return; } client->socket.fd = cfd; struct epoll_event ev = { - .events = POLLHUP, + .events = POLLIN, .data.ptr = &client->socket, }; if (epoll_ctl(ls->epoll_fd, EPOLL_CTL_ADD, cfd, &ev)) { DEBUG_LOG("epoll_ctl add failed: %s\n", strerror(errno)); close(cfd); - return NULL; + return; } client->is_connected = true; - return client; +} + +static int parse_client_request(struct ls_socket *client) +{ + int ret = -1; + struct dlm_client_request hdr; + if (!receive_dlm_client_request(client->fd, &hdr)) + return ret; + + switch (hdr.opcode) { + case DLM_GET_LEASE: + ret = LS_REQ_GET_LEASE; + break; + case DLM_RELEASE_LEASE: + ret = LS_REQ_RELEASE_LEASE; + break; + default: + ERROR_LOG("Unexpected client request received\n"); + break; + }; + + return ret; } static int create_socket_lock(struct sockaddr_un *addr) @@ -165,7 +188,7 @@ static bool server_setup(struct ls *ls, struct ls_server *serv, address->sun_family = AF_UNIX; - int server_socket = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); + int server_socket = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); if (server_socket < 0) { DEBUG_LOG("Socket creation failed: %s\n", strerror(errno)); return false; @@ -296,25 +319,20 @@ bool ls_get_request(struct ls *ls, struct ls_req *req) struct ls_socket *sock = ev.data.ptr; assert(sock); - struct ls_server *server; - struct ls_client *client; - if (sock->is_server) { - if (!(ev.events & POLLIN)) - continue; + if (ev.events & POLLIN) + client_connect(ls, sock->server); + continue; + } - server = sock->server; - client = client_connect(ls, server); - if (client) - request = LS_REQ_GET_LEASE; - } else { - if (!(ev.events & POLLHUP)) - continue; + if (ev.events & POLLIN) + request = parse_client_request(sock); - client = sock->client; - server = client->serv; + if (request < 0 && (ev.events & POLLHUP)) request = LS_REQ_RELEASE_LEASE; - } + + struct ls_client *client = sock->client; + struct ls_server *server = client->serv; req->lease_handle = server->lease_handle; req->client = client; diff --git a/drm-lease-manager/test/test-socket-client.c b/drm-lease-manager/test/test-socket-client.c index 260437a..9d191ff 100644 --- a/drm-lease-manager/test/test-socket-client.c +++ b/drm-lease-manager/test/test-socket-client.c @@ -28,6 +28,7 @@ #include <sys/un.h> #include <unistd.h> +#include "dlm-protocol.h" #include "socket-path.h" #define DEFAULT_RECV_TIMEOUT (100) // timeout in ms to receive data from server @@ -39,6 +40,14 @@ struct client_state { struct test_config *config; }; +static void send_lease_request(int socket, enum dlm_opcode opcode) +{ + struct dlm_client_request req = { + .opcode = opcode, + }; + send_dlm_client_request(socket, &req); +} + static void client_gst_socket_status(int socket_fd, struct test_config *config) { @@ -104,7 +113,7 @@ static void *test_client_thread(void *arg) sockaddr_set_lease_server_path(&address, config->lease->name), true); - int client = socket(PF_UNIX, SOCK_STREAM, 0); + int client = socket(PF_UNIX, SOCK_SEQPACKET, 0); ck_assert_int_ge(client, 0); int ret; @@ -115,6 +124,8 @@ static void *test_client_thread(void *arg) return NULL; } + send_lease_request(client, DLM_GET_LEASE); + if (!config->recv_timeout) config->recv_timeout = DEFAULT_RECV_TIMEOUT; @@ -125,6 +136,7 @@ static void *test_client_thread(void *arg) } cstate->socket_fd = client; + send_lease_request(client, DLM_RELEASE_LEASE); return NULL; } diff --git a/libdlmclient/dlmclient.c b/libdlmclient/dlmclient.c index 32493d3..03c08a8 100644 --- a/libdlmclient/dlmclient.c +++ b/libdlmclient/dlmclient.c @@ -14,6 +14,8 @@ */ #include "dlmclient.h" + +#include "dlm-protocol.h" #include "log.h" #include "socket-path.h" @@ -46,7 +48,7 @@ static bool lease_connect(struct dlm_lease *lease, const char *name) if (!sockaddr_set_lease_server_path(&sa, name)) return false; - int dlm_server_sock = socket(AF_UNIX, SOCK_STREAM, 0); + int dlm_server_sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (dlm_server_sock < 0) { DEBUG_LOG("Socket creation failed: %s\n", strerror(errno)); return false; @@ -65,6 +67,19 @@ static bool lease_connect(struct dlm_lease *lease, const char *name) return true; } +static bool lease_send_request(struct dlm_lease *lease, enum dlm_opcode opcode) +{ + struct dlm_client_request request = { + .opcode = opcode, + }; + + if (!send_dlm_client_request(lease->dlm_server_sock, &request)) { + DEBUG_LOG("Socket data send error: %s\n", strerror(errno)); + return false; + } + return true; +} + static bool lease_recv_fd(struct dlm_lease *lease) { char ctrl_buf[CMSG_SPACE(sizeof(int))] = {0}; @@ -131,6 +146,7 @@ static bool lease_recv_fd(struct dlm_lease *lease) struct dlm_lease *dlm_get_lease(const char *name) { + int saved_errno; struct dlm_lease *lease = calloc(1, sizeof(struct dlm_lease)); if (!lease) { DEBUG_LOG("can't allocate memory : %s\n", strerror(errno)); @@ -142,13 +158,19 @@ struct dlm_lease *dlm_get_lease(const char *name) return NULL; } - if (!lease_recv_fd(lease)) { - close(lease->dlm_server_sock); - free(lease); - return NULL; - } + if (!lease_send_request(lease, DLM_GET_LEASE)) + goto err; + + if (!lease_recv_fd(lease)) + goto err; return lease; + +err: + saved_errno = errno; + dlm_release_lease(lease); + errno = saved_errno; + return NULL; } void dlm_release_lease(struct dlm_lease *lease) @@ -156,6 +178,7 @@ void dlm_release_lease(struct dlm_lease *lease) if (!lease) return; + lease_send_request(lease, DLM_RELEASE_LEASE); close(lease->lease_fd); close(lease->dlm_server_sock); free(lease); diff --git a/libdlmclient/test/test-socket-server.c b/libdlmclient/test/test-socket-server.c index 281aaf7..6aaa4e4 100644 --- a/libdlmclient/test/test-socket-server.c +++ b/libdlmclient/test/test-socket-server.c @@ -25,6 +25,7 @@ #include <sys/un.h> #include <unistd.h> +#include "dlm-protocol.h" #include "socket-path.h" #include "test-helpers.h" @@ -56,6 +57,13 @@ static void send_fd_list_over_socket(int socket, int nfds, int *fds) free(buf); } +static void expect_client_command(int socket, enum dlm_opcode opcode) +{ + struct dlm_client_request req; + ck_assert_int_eq(receive_dlm_client_request(socket, &req), true); + ck_assert_int_eq(req.opcode, opcode); +} + struct server_state { pthread_t tid; pthread_mutex_t lock; @@ -77,7 +85,7 @@ static void *test_server_thread(void *arg) ck_assert_int_eq( sockaddr_set_lease_server_path(&address, config->lease_name), true); - int server = socket(PF_UNIX, SOCK_STREAM, 0); + int server = socket(PF_UNIX, SOCK_SEQPACKET, 0); ck_assert_int_ge(server, 0); unlink(address.sun_path); @@ -102,6 +110,8 @@ static void *test_server_thread(void *arg) return NULL; } + expect_client_command(client, DLM_GET_LEASE); + if (config->send_no_data) goto done; @@ -120,6 +130,7 @@ static void *test_server_thread(void *arg) config->fds[i] = get_dummy_fd(); send_fd_list_over_socket(client, config->nfds, config->fds); + expect_client_command(client, DLM_RELEASE_LEASE); done: close(client); close(server); |