a7e319043a958a082c58bc92f88b34b1f454f62d
[src/drm-lease-manager.git] / drm-lease-manager / lease-server.c
1 /* Copyright 2020-2021 IGEL Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include "lease-server.h"
17
18 #include "dlm-protocol.h"
19 #include "log.h"
20 #include "socket-path.h"
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <stdlib.h>
27 #include <sys/epoll.h>
28 #include <sys/file.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/un.h>
33 #include <unistd.h>
34
35 #define SOCK_LOCK_SUFFIX ".lock"
36
37 /* ACTIVE_CLIENTS
38  * An 'active' client is one that either
39  *  - owns a lease, or
40  *  - is requesting ownership of a lease (which will
41  *    disconnect the current owner if granted)
42  *
43  * There can only be at most one of each kind of client at the same
44  * time. Any other client connections are queued in the
45  * listen() backlog, waiting to be accept()'ed.
46  */
47 #define ACTIVE_CLIENTS 2
48
49 struct ls_socket {
50         int fd;
51         bool is_server;
52         union {
53                 struct ls_server *server;
54                 struct ls_client *client;
55         };
56 };
57
58 struct ls_client {
59         struct ls_socket socket;
60         struct ls_server *serv;
61         bool is_connected;
62 };
63
64 struct ls_server {
65         struct lease_handle *lease_handle;
66         struct sockaddr_un address;
67         int server_socket_lock;
68
69         struct ls_socket listen;
70         struct ls_client clients[ACTIVE_CLIENTS];
71 };
72
73 struct ls {
74         int epoll_fd;
75
76         struct ls_server *servers;
77         int nservers;
78 };
79
80 static void client_connect(struct ls *ls, struct ls_server *serv)
81 {
82         int cfd = accept(serv->listen.fd, NULL, NULL);
83         if (cfd < 0) {
84                 DEBUG_LOG("accept failed on %s: %s\n", serv->address.sun_path,
85                           strerror(errno));
86                 return;
87         }
88
89         struct ls_client *client = NULL;
90
91         for (int i = 0; i < ACTIVE_CLIENTS; i++) {
92                 if (!serv->clients[i].is_connected) {
93                         client = &serv->clients[i];
94                         break;
95                 }
96         }
97         if (!client) {
98                 close(cfd);
99                 return;
100         }
101
102         client->socket.fd = cfd;
103
104         struct epoll_event ev = {
105             .events = POLLIN,
106             .data.ptr = &client->socket,
107         };
108         if (epoll_ctl(ls->epoll_fd, EPOLL_CTL_ADD, cfd, &ev)) {
109                 DEBUG_LOG("epoll_ctl add failed: %s\n", strerror(errno));
110                 close(cfd);
111                 return;
112         }
113
114         client->is_connected = true;
115 }
116
117 static int parse_client_request(struct ls_socket *client)
118 {
119         int ret = -1;
120         struct dlm_client_request hdr;
121         if (!receive_dlm_client_request(client->fd, &hdr))
122                 return ret;
123
124         switch (hdr.opcode) {
125         case DLM_GET_LEASE:
126                 ret = LS_REQ_GET_LEASE;
127                 break;
128         case DLM_RELEASE_LEASE:
129                 ret = LS_REQ_RELEASE_LEASE;
130                 break;
131         default:
132                 ERROR_LOG("Unexpected client request received\n");
133                 break;
134         };
135
136         return ret;
137 }
138
139 static int create_socket_lock(struct sockaddr_un *addr)
140 {
141         int lock_fd;
142
143         int lockfile_len = sizeof(addr->sun_path) + sizeof(SOCK_LOCK_SUFFIX);
144         char lockfile[lockfile_len];
145         int len = snprintf(lockfile, lockfile_len, "%s%s", addr->sun_path,
146                            SOCK_LOCK_SUFFIX);
147
148         if (len < 0 || len >= lockfile_len) {
149                 DEBUG_LOG("Can't create socket lock filename\n");
150                 return -1;
151         }
152
153         lock_fd = open(lockfile, O_CREAT | O_RDWR,
154                        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
155
156         if (lock_fd < 0) {
157                 ERROR_LOG("Cannot access runtime directory\n");
158                 return -1;
159         }
160
161         if (flock(lock_fd, LOCK_EX | LOCK_NB)) {
162                 ERROR_LOG(
163                     "socket %s: in use.  Possible duplicate lease name or "
164                     "mutiple drm-lease-manager instances running\n",
165                     addr->sun_path);
166                 close(lock_fd);
167                 return -1;
168         }
169
170         return lock_fd;
171 }
172
173 static bool server_setup(struct ls *ls, struct ls_server *serv,
174                          struct lease_handle *lease_handle)
175 {
176         struct sockaddr_un *address = &serv->address;
177
178         if (!sockaddr_set_lease_server_path(address, lease_handle->name))
179                 return false;
180
181         int socket_lock = create_socket_lock(address);
182         if (socket_lock < 0)
183                 return false;
184
185         /* The socket address is now owned by this instance, so any existing
186          * sockets can safely be removed */
187         unlink(address->sun_path);
188
189         address->sun_family = AF_UNIX;
190
191         int server_socket = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0);
192         if (server_socket < 0) {
193                 DEBUG_LOG("Socket creation failed: %s\n", strerror(errno));
194                 return false;
195         }
196
197         if (bind(server_socket, (struct sockaddr *)address, sizeof(*address))) {
198                 ERROR_LOG("Failed to create named socket at %s: %s\n",
199                           address->sun_path, strerror(errno));
200                 close(server_socket);
201                 return false;
202         }
203
204         if (listen(server_socket, 0)) {
205                 DEBUG_LOG("listen failed on %s: %s\n", address->sun_path,
206                           strerror(errno));
207                 close(server_socket);
208                 unlink(address->sun_path);
209                 return false;
210         }
211
212         for (int i = 0; i < ACTIVE_CLIENTS; i++) {
213                 struct ls_client *client = &serv->clients[i];
214                 client->serv = serv;
215                 client->socket.client = client;
216         }
217
218         serv->lease_handle = lease_handle;
219         serv->server_socket_lock = socket_lock;
220
221         serv->listen.fd = server_socket;
222         serv->listen.server = serv;
223         serv->listen.is_server = true;
224
225         struct epoll_event ev = {
226             .events = POLLIN,
227             .data.ptr = &serv->listen,
228         };
229
230         if (epoll_ctl(ls->epoll_fd, EPOLL_CTL_ADD, server_socket, &ev)) {
231                 DEBUG_LOG("epoll_ctl add failed: %s\n", strerror(errno));
232                 close(server_socket);
233                 unlink(address->sun_path);
234                 return false;
235         }
236
237         INFO_LOG("Lease server (%s) initialized at %s\n", lease_handle->name,
238                  address->sun_path);
239         return true;
240 }
241
242 static void server_shutdown(struct ls *ls, struct ls_server *serv)
243 {
244         if (unlink(serv->address.sun_path)) {
245                 WARN_LOG("Server socket %s delete failed: %s\n",
246                          serv->address.sun_path, strerror(errno));
247         }
248
249         epoll_ctl(ls->epoll_fd, EPOLL_CTL_DEL, serv->listen.fd, NULL);
250         close(serv->listen.fd);
251
252         for (int i = 0; i < ACTIVE_CLIENTS; i++)
253                 ls_disconnect_client(ls, &serv->clients[i]);
254
255         close(serv->server_socket_lock);
256 }
257
258 struct ls *ls_create(struct lease_handle **lease_handles, int count)
259 {
260         assert(lease_handles);
261         assert(count > 0);
262
263         struct ls *ls = calloc(1, sizeof(struct ls));
264         if (!ls) {
265                 DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
266                 return NULL;
267         }
268
269         ls->servers = calloc(count, sizeof(struct ls_server));
270         if (!ls->servers) {
271                 DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
272                 goto err;
273         }
274
275         ls->epoll_fd = epoll_create1(0);
276         if (ls->epoll_fd < 0) {
277                 DEBUG_LOG("epoll_create failed: %s\n", strerror(errno));
278                 goto err;
279         }
280
281         for (int i = 0; i < count; i++) {
282                 if (!server_setup(ls, &ls->servers[i], lease_handles[i]))
283                         goto err;
284                 ls->nservers++;
285         }
286         return ls;
287 err:
288         ls_destroy(ls);
289         return NULL;
290 }
291
292 void ls_destroy(struct ls *ls)
293 {
294         assert(ls);
295
296         for (int i = 0; i < ls->nservers; i++)
297                 server_shutdown(ls, &ls->servers[i]);
298
299         close(ls->epoll_fd);
300         free(ls->servers);
301         free(ls);
302 }
303
304 bool ls_get_request(struct ls *ls, struct ls_req *req)
305 {
306         assert(ls);
307         assert(req);
308
309         int request = -1;
310         while (request < 0) {
311                 struct epoll_event ev;
312                 if (epoll_wait(ls->epoll_fd, &ev, 1, -1) < 0) {
313                         if (errno == EINTR)
314                                 continue;
315                         DEBUG_LOG("epoll_wait failed: %s\n", strerror(errno));
316                         return false;
317                 }
318
319                 struct ls_socket *sock = ev.data.ptr;
320                 assert(sock);
321
322                 if (sock->is_server) {
323                         if (ev.events & POLLIN)
324                                 client_connect(ls, sock->server);
325                         continue;
326                 }
327
328                 if (ev.events & POLLIN)
329                         request = parse_client_request(sock);
330
331                 if (request < 0 && (ev.events & POLLHUP))
332                         request = LS_REQ_CLIENT_DISCONNECT;
333
334                 struct ls_client *client = sock->client;
335                 struct ls_server *server = client->serv;
336
337                 req->lease_handle = server->lease_handle;
338                 req->client = client;
339                 req->type = request;
340         }
341         return true;
342 }
343
344 bool ls_send_fd(struct ls *ls, struct ls_client *client, int fd)
345 {
346         assert(ls);
347         assert(client);
348
349         struct ls_server *serv = client->serv;
350
351         if (fd < 0)
352                 return false;
353
354         if (!send_lease_fd(client->socket.fd, fd)) {
355                 DEBUG_LOG("sendmsg failed on %s: %s\n", serv->address.sun_path,
356                           strerror(errno));
357                 return false;
358         }
359
360         if (fd > 0)
361                 INFO_LOG("Lease request granted on %s\n",
362                          serv->address.sun_path);
363
364         return true;
365 }
366
367 void ls_disconnect_client(struct ls *ls, struct ls_client *client)
368 {
369         assert(ls);
370         assert(client);
371
372         if (!client->is_connected)
373                 return;
374
375         epoll_ctl(ls->epoll_fd, EPOLL_CTL_DEL, client->socket.fd, NULL);
376         close(client->socket.fd);
377         client->is_connected = false;
378 }