1 /* Copyright 2020-2021 IGEL Co., Ltd.
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "lease-server.h"
18 #include "dlm-protocol.h"
20 #include "socket-path.h"
27 #include <sys/epoll.h>
29 #include <sys/socket.h>
31 #include <sys/types.h>
35 #define SOCK_LOCK_SUFFIX ".lock"
38 * An 'active' client is one that either
40 * - is requesting ownership of a lease (which will
41 * disconnect the current owner if granted)
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.
47 #define ACTIVE_CLIENTS 2
53 struct ls_server *server;
54 struct ls_client *client;
59 struct ls_socket socket;
60 struct ls_server *serv;
65 struct lease_handle *lease_handle;
66 struct sockaddr_un address;
67 int server_socket_lock;
69 struct ls_socket listen;
70 struct ls_client clients[ACTIVE_CLIENTS];
76 struct ls_server *servers;
80 static void client_connect(struct ls *ls, struct ls_server *serv)
82 int cfd = accept(serv->listen.fd, NULL, NULL);
84 DEBUG_LOG("accept failed on %s: %s\n", serv->address.sun_path,
89 struct ls_client *client = NULL;
91 for (int i = 0; i < ACTIVE_CLIENTS; i++) {
92 if (!serv->clients[i].is_connected) {
93 client = &serv->clients[i];
102 client->socket.fd = cfd;
104 struct epoll_event ev = {
106 .data.ptr = &client->socket,
108 if (epoll_ctl(ls->epoll_fd, EPOLL_CTL_ADD, cfd, &ev)) {
109 DEBUG_LOG("epoll_ctl add failed: %s\n", strerror(errno));
114 client->is_connected = true;
117 static int parse_client_request(struct ls_socket *client)
120 struct dlm_client_request hdr;
121 if (!receive_dlm_client_request(client->fd, &hdr))
124 switch (hdr.opcode) {
126 ret = LS_REQ_GET_LEASE;
128 case DLM_RELEASE_LEASE:
129 ret = LS_REQ_RELEASE_LEASE;
132 ERROR_LOG("Unexpected client request received\n");
139 static int create_socket_lock(struct sockaddr_un *addr)
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,
148 if (len < 0 || len >= lockfile_len) {
149 DEBUG_LOG("Can't create socket lock filename\n");
153 lock_fd = open(lockfile, O_CREAT | O_RDWR,
154 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
157 ERROR_LOG("Cannot access runtime directory\n");
161 if (flock(lock_fd, LOCK_EX | LOCK_NB)) {
163 "socket %s: in use. Possible duplicate lease name or "
164 "mutiple drm-lease-manager instances running\n",
173 static bool server_setup(struct ls *ls, struct ls_server *serv,
174 struct lease_handle *lease_handle)
176 struct sockaddr_un *address = &serv->address;
178 if (!sockaddr_set_lease_server_path(address, lease_handle->name))
181 int socket_lock = create_socket_lock(address);
185 /* The socket address is now owned by this instance, so any existing
186 * sockets can safely be removed */
187 unlink(address->sun_path);
189 address->sun_family = AF_UNIX;
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));
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);
204 if (listen(server_socket, 0)) {
205 DEBUG_LOG("listen failed on %s: %s\n", address->sun_path,
207 close(server_socket);
208 unlink(address->sun_path);
212 for (int i = 0; i < ACTIVE_CLIENTS; i++) {
213 struct ls_client *client = &serv->clients[i];
215 client->socket.client = client;
218 serv->lease_handle = lease_handle;
219 serv->server_socket_lock = socket_lock;
221 serv->listen.fd = server_socket;
222 serv->listen.server = serv;
223 serv->listen.is_server = true;
225 struct epoll_event ev = {
227 .data.ptr = &serv->listen,
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);
237 INFO_LOG("Lease server (%s) initialized at %s\n", lease_handle->name,
242 static void server_shutdown(struct ls *ls, struct ls_server *serv)
244 if (unlink(serv->address.sun_path)) {
245 WARN_LOG("Server socket %s delete failed: %s\n",
246 serv->address.sun_path, strerror(errno));
249 epoll_ctl(ls->epoll_fd, EPOLL_CTL_DEL, serv->listen.fd, NULL);
250 close(serv->listen.fd);
252 for (int i = 0; i < ACTIVE_CLIENTS; i++)
253 ls_disconnect_client(ls, &serv->clients[i]);
255 close(serv->server_socket_lock);
258 struct ls *ls_create(struct lease_handle **lease_handles, int count)
260 assert(lease_handles);
263 struct ls *ls = calloc(1, sizeof(struct ls));
265 DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
269 ls->servers = calloc(count, sizeof(struct ls_server));
271 DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
275 ls->epoll_fd = epoll_create1(0);
276 if (ls->epoll_fd < 0) {
277 DEBUG_LOG("epoll_create failed: %s\n", strerror(errno));
281 for (int i = 0; i < count; i++) {
282 if (!server_setup(ls, &ls->servers[i], lease_handles[i]))
292 void ls_destroy(struct ls *ls)
296 for (int i = 0; i < ls->nservers; i++)
297 server_shutdown(ls, &ls->servers[i]);
304 bool ls_get_request(struct ls *ls, struct ls_req *req)
310 while (request < 0) {
311 struct epoll_event ev;
312 if (epoll_wait(ls->epoll_fd, &ev, 1, -1) < 0) {
315 DEBUG_LOG("epoll_wait failed: %s\n", strerror(errno));
319 struct ls_socket *sock = ev.data.ptr;
322 if (sock->is_server) {
323 if (ev.events & POLLIN)
324 client_connect(ls, sock->server);
328 if (ev.events & POLLIN)
329 request = parse_client_request(sock);
331 if (request < 0 && (ev.events & POLLHUP))
332 request = LS_REQ_CLIENT_DISCONNECT;
334 struct ls_client *client = sock->client;
335 struct ls_server *server = client->serv;
337 req->lease_handle = server->lease_handle;
338 req->client = client;
344 bool ls_send_fd(struct ls *ls, struct ls_client *client, int fd)
349 struct ls_server *serv = client->serv;
354 if (!send_lease_fd(client->socket.fd, fd)) {
355 DEBUG_LOG("sendmsg failed on %s: %s\n", serv->address.sun_path,
361 INFO_LOG("Lease request granted on %s\n",
362 serv->address.sun_path);
367 void ls_disconnect_client(struct ls *ls, struct ls_client *client)
372 if (!client->is_connected)
375 epoll_ctl(ls->epoll_fd, EPOLL_CTL_DEL, client->socket.fd, NULL);
376 close(client->socket.fd);
377 client->is_connected = false;