Add lease request and release protocol 36/26236/1
authorDamian Hobson-Garcia <dhobsong@igel.co.jp>
Fri, 19 Feb 2021 03:52:55 +0000 (03:52 +0000)
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>
Tue, 6 Apr 2021 06:58:47 +0000 (15:58 +0900)
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

common/dlm-protocol.c [new file with mode: 0644]
common/dlm-protocol.h [new file with mode: 0644]
common/meson.build
drm-lease-manager/lease-server.c
drm-lease-manager/test/test-socket-client.c
libdlmclient/dlmclient.c
libdlmclient/test/test-socket-server.c

diff --git a/common/dlm-protocol.c b/common/dlm-protocol.c
new file mode 100644 (file)
index 0000000..4fc87b2
--- /dev/null
@@ -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 (file)
index 0000000..44785e5
--- /dev/null
@@ -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
index e465fa5..663c1ce 100644 (file)
@@ -1,4 +1,5 @@
 libdlmcommon_sources = [
+        'dlm-protocol.c',
         'socket-path.c',
         'log.c'
 ]
index c57316e..ac4dd01 100644 (file)
@@ -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;
index 260437a..9d191ff 100644 (file)
@@ -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;
 }
index 32493d3..03c08a8 100644 (file)
@@ -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);
index 281aaf7..6aaa4e4 100644 (file)
@@ -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);