dbe26097c8e61e6d73cdce43e9a9ad9b4abb4b5c
[src/drm-lease-manager.git] / libdlmclient / dlmclient.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 "dlmclient.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 <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <unistd.h>
31
32 void dlm_enable_debug_log(bool enable)
33 {
34         dlm_log_enable_debug(enable);
35 }
36
37 struct dlm_lease {
38         int dlm_server_sock;
39         int lease_fd;
40 };
41
42 static bool lease_connect(struct dlm_lease *lease, const char *name)
43 {
44         struct sockaddr_un sa = {
45             .sun_family = AF_UNIX,
46         };
47
48         if (!sockaddr_set_lease_server_path(&sa, name))
49                 return false;
50
51         int dlm_server_sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
52         if (dlm_server_sock < 0) {
53                 DEBUG_LOG("Socket creation failed: %s\n", strerror(errno));
54                 return false;
55         }
56
57         while (connect(dlm_server_sock, (struct sockaddr *)&sa,
58                        sizeof(struct sockaddr_un)) == -1) {
59                 if (errno == EINTR)
60                         continue;
61                 DEBUG_LOG("Cannot connect to %s: %s\n", sa.sun_path,
62                           strerror(errno));
63                 close(dlm_server_sock);
64                 return false;
65         }
66         lease->dlm_server_sock = dlm_server_sock;
67         return true;
68 }
69
70 static bool lease_send_request(struct dlm_lease *lease, enum dlm_opcode opcode)
71 {
72         struct dlm_client_request request = {
73             .opcode = opcode,
74         };
75
76         if (!send_dlm_client_request(lease->dlm_server_sock, &request)) {
77                 DEBUG_LOG("Socket data send error: %s\n", strerror(errno));
78                 return false;
79         }
80         return true;
81 }
82
83 static bool lease_recv_fd(struct dlm_lease *lease)
84 {
85         lease->lease_fd = receive_lease_fd(lease->dlm_server_sock);
86
87         if (lease->lease_fd < 0)
88                 goto err;
89
90         return true;
91
92 err:
93         switch (errno) {
94         case EACCES:
95                 DEBUG_LOG("Lease request rejected by DRM lease manager\n");
96                 break;
97         case EPROTO:
98                 DEBUG_LOG("Unexpected data received from lease manager\n");
99                 break;
100         default:
101                 DEBUG_LOG("Lease manager receive data error: %s\n",
102                           strerror(errno));
103                 break;
104         }
105         return false;
106 }
107
108 struct dlm_lease *dlm_get_lease(const char *name)
109 {
110         int saved_errno;
111         struct dlm_lease *lease = calloc(1, sizeof(struct dlm_lease));
112         if (!lease) {
113                 DEBUG_LOG("can't allocate memory : %s\n", strerror(errno));
114                 return NULL;
115         }
116
117         if (!lease_connect(lease, name)) {
118                 free(lease);
119                 return NULL;
120         }
121
122         if (!lease_send_request(lease, DLM_GET_LEASE))
123                 goto err;
124
125         if (!lease_recv_fd(lease))
126                 goto err;
127
128         return lease;
129
130 err:
131         saved_errno = errno;
132         dlm_release_lease(lease);
133         errno = saved_errno;
134         return NULL;
135 }
136
137 void dlm_release_lease(struct dlm_lease *lease)
138 {
139         if (!lease)
140                 return;
141
142         lease_send_request(lease, DLM_RELEASE_LEASE);
143         close(lease->lease_fd);
144         close(lease->dlm_server_sock);
145         free(lease);
146 }
147
148 int dlm_lease_fd(struct dlm_lease *lease)
149 {
150         if (!lease)
151                 return -1;
152
153         return lease->lease_fd;
154 }