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