Add option to hold lease on unexpected disconnect
[src/drm-lease-manager.git] / drm-lease-manager / main.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-manager.h"
17 #include "lease-server.h"
18 #include "log.h"
19
20 #include <assert.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 static void usage(const char *progname)
26 {
27         printf("Usage: %s [OPTIONS] [<DRM device>]\n\n"
28                "Options:\n"
29                "-h, --help \tPrint this help\n"
30                "-v, --verbose \tEnable verbose debug messages\n"
31                "-t, --lease-transfer \tAllow lease transfter to new clients\n"
32                "-k, --keep-on-crash \tDon't close lease on client crash\n",
33                progname);
34 }
35
36 const char *opts = "vtkh";
37 const struct option options[] = {
38     {"help", no_argument, NULL, 'h'},
39     {"verbose", no_argument, NULL, 'v'},
40     {"lease-transfer", no_argument, NULL, 't'},
41     {"keep-on-crash", no_argument, NULL, 'k'},
42     {NULL, 0, NULL, 0},
43 };
44
45 int main(int argc, char **argv)
46 {
47         char *device = "/dev/dri/card0";
48
49         bool debug_log = false;
50         bool can_transfer_leases = false;
51         bool keep_on_crash = false;
52
53         int c;
54         while ((c = getopt_long(argc, argv, opts, options, NULL)) != -1) {
55                 int ret = EXIT_FAILURE;
56                 switch (c) {
57                 case 'v':
58                         debug_log = true;
59                         break;
60                 case 't':
61                         can_transfer_leases = true;
62                         break;
63                 case 'k':
64                         keep_on_crash = true;
65                         break;
66                 case 'h':
67                         ret = EXIT_SUCCESS;
68                         /* fall through */
69                 default:
70                         usage(argv[0]);
71                         return ret;
72                 }
73         }
74
75         if (optind < argc)
76                 device = argv[optind];
77
78         dlm_log_enable_debug(debug_log);
79
80         struct lm *lm = lm_create(device);
81         if (!lm) {
82                 ERROR_LOG("DRM Lease initialization failed\n");
83                 return EXIT_FAILURE;
84         }
85
86         struct lease_handle **lease_handles = NULL;
87         int count_ids = lm_get_lease_handles(lm, &lease_handles);
88         assert(count_ids > 0);
89
90         struct ls *ls = ls_create(lease_handles, count_ids);
91         if (!ls) {
92                 lm_destroy(lm);
93                 ERROR_LOG("Client socket initialization failed\n");
94                 return EXIT_FAILURE;
95         }
96
97         struct ls_req req;
98         while (ls_get_request(ls, &req)) {
99                 switch (req.type) {
100                 case LS_REQ_GET_LEASE: {
101                         int fd = lm_lease_grant(lm, req.lease_handle);
102
103                         if (fd < 0 && can_transfer_leases)
104                                 fd = lm_lease_transfer(lm, req.lease_handle);
105
106                         if (fd < 0) {
107                                 ERROR_LOG(
108                                     "Can't fulfill lease request: lease=%s\n",
109                                     req.lease_handle->name);
110                                 ls_disconnect_client(ls, req.client);
111                                 break;
112                         }
113
114                         struct ls_client *active_client =
115                             req.lease_handle->user_data;
116                         if (active_client)
117                                 ls_disconnect_client(ls, active_client);
118
119                         req.lease_handle->user_data = req.client;
120
121                         if (!ls_send_fd(ls, req.client, fd)) {
122                                 ERROR_LOG(
123                                     "Client communication error: lease=%s\n",
124                                     req.lease_handle->name);
125                                 ls_disconnect_client(ls, req.client);
126                                 lm_lease_revoke(lm, req.lease_handle);
127                         }
128                         break;
129                 }
130                 case LS_REQ_RELEASE_LEASE:
131                 case LS_REQ_CLIENT_DISCONNECT:
132                         ls_disconnect_client(ls, req.client);
133                         req.lease_handle->user_data = NULL;
134                         lm_lease_revoke(lm, req.lease_handle);
135
136                         if (!keep_on_crash || req.type == LS_REQ_RELEASE_LEASE)
137                                 lm_lease_close(req.lease_handle);
138
139                         break;
140                 default:
141                         ERROR_LOG("Internal error: Invalid lease request\n");
142                         goto done;
143                 }
144         }
145 done:
146         ls_destroy(ls);
147         lm_destroy(lm);
148         return EXIT_FAILURE;
149 }