Move lease fd send/receive to dlm-protocol
[src/drm-lease-manager.git] / common / dlm-protocol.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 "dlm-protocol.h"
17
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 bool receive_dlm_client_request(int socket, struct dlm_client_request *request)
25 {
26
27         ssize_t len;
28         struct iovec iov = {
29             .iov_base = request,
30             .iov_len = sizeof(*request),
31         };
32         struct msghdr msg = {
33             .msg_iov = &iov,
34             .msg_iovlen = 1,
35         };
36
37         while ((len = recvmsg(socket, &msg, 0)) < 0) {
38                 if (errno != EINTR)
39                         return false;
40         }
41
42         if (len != sizeof(*request)) {
43                 errno = EPROTO;
44                 return false;
45         }
46         return true;
47 }
48
49 bool send_dlm_client_request(int socket, struct dlm_client_request *request)
50 {
51         struct iovec iov = {
52             .iov_base = request,
53             .iov_len = sizeof(*request),
54         };
55
56         struct msghdr msg = {
57             .msg_iov = &iov,
58             .msg_iovlen = 1,
59         };
60
61         while (sendmsg(socket, &msg, 0) < 1) {
62                 if (errno != EINTR)
63                         return false;
64         }
65         return true;
66 }
67
68 int receive_lease_fd(int socket)
69 {
70         int lease_fd = -1;
71         char ctrl_buf[CMSG_SPACE(sizeof(lease_fd))];
72
73         char data;
74         struct iovec iov = {.iov_base = &data, .iov_len = sizeof(data)};
75         struct msghdr msg = {
76             .msg_iov = &iov,
77             .msg_iovlen = 1,
78             .msg_control = ctrl_buf,
79             .msg_controllen = sizeof(ctrl_buf),
80         };
81
82         ssize_t len;
83         while ((len = recvmsg(socket, &msg, 0)) <= 0) {
84                 if (len == 0) {
85                         errno = EACCES;
86                         goto err;
87                 }
88
89                 if (errno != EINTR)
90                         goto err;
91         }
92
93         struct cmsghdr *cmsg;
94         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
95              cmsg = CMSG_NXTHDR(&msg, cmsg)) {
96                 if (cmsg->cmsg_level == SOL_SOCKET &&
97                     cmsg->cmsg_type == SCM_RIGHTS) {
98                         int nfds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
99                         int *fds = (int *)CMSG_DATA(cmsg);
100
101                         if (nfds == 1) {
102                                 lease_fd = fds[0];
103                                 break;
104                         }
105
106                         /* Close any unexpected fds so we don't leak them. */
107                         for (int i = 0; i < nfds; i++)
108                                 close(fds[i]);
109                         break;
110                 }
111         }
112
113         if (lease_fd < 0) {
114                 errno = EPROTO;
115                 goto err;
116         }
117
118 err:
119         return lease_fd;
120 }
121
122 bool send_lease_fd(int socket, int lease)
123 {
124         char data;
125         struct iovec iov = {
126             .iov_base = &data,
127             .iov_len = sizeof(data),
128         };
129
130         char ctrl_buf[CMSG_SPACE(sizeof(lease))] = {0};
131
132         struct msghdr msg = {
133             .msg_iov = &iov,
134             .msg_iovlen = 1,
135             .msg_controllen = sizeof(ctrl_buf),
136             .msg_control = ctrl_buf,
137         };
138
139         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
140         cmsg->cmsg_level = SOL_SOCKET;
141         cmsg->cmsg_type = SCM_RIGHTS;
142         cmsg->cmsg_len = CMSG_LEN(sizeof(lease));
143         *((int *)CMSG_DATA(cmsg)) = lease;
144
145         if (sendmsg(socket, &msg, 0) < 0)
146                 return false;
147
148         return true;
149 }