Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include <errno.h>
7 : #include <stdio.h>
8 : #include <stdlib.h>
9 : #include <string.h>
10 : #include <sys/stat.h>
11 : #include <unistd.h>
12 :
13 : #include "core/helper.h"
14 : #include "core/logger.h"
15 : #include "core/request.h"
16 : #include "core/response.h"
17 :
18 : #define BF_PERM_755 (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
19 :
20 0 : static ssize_t _bf_recv_in_buff(int fd, void *buf, size_t buf_len)
21 : {
22 : ssize_t bytes_read = 0;
23 : ssize_t r;
24 :
25 0 : bf_assert(buf);
26 :
27 : do {
28 : /// @todo Add a timeout to the socket to prevent blocking forever.
29 0 : r = read(fd, buf + bytes_read, buf_len - bytes_read);
30 0 : if (r < 0) {
31 0 : (void)fprintf(stderr, "can't read from the socket: %s\n",
32 0 : bf_strerror(errno));
33 0 : return -errno;
34 : }
35 :
36 0 : bytes_read += r;
37 0 : } while (r && (size_t)bytes_read != buf_len);
38 :
39 : return bytes_read;
40 : }
41 :
42 0 : static ssize_t _bf_send_from_buff(int fd, void *buf, size_t buf_len)
43 : {
44 : ssize_t bytes_sent = 0;
45 : ssize_t r;
46 :
47 0 : bf_assert(buf);
48 :
49 0 : while ((size_t)bytes_sent < buf_len) {
50 0 : r = write(fd, buf + bytes_sent, buf_len - bytes_sent);
51 0 : if (r < 0) {
52 0 : (void)fprintf(stderr, "can't write to socket: %s\n",
53 0 : bf_strerror(errno));
54 0 : return -errno;
55 : }
56 :
57 0 : bytes_sent += r;
58 : }
59 :
60 : return bytes_sent;
61 : }
62 :
63 0 : int bf_send_request(int fd, const struct bf_request *request)
64 : {
65 : ssize_t r;
66 :
67 0 : bf_assert(request);
68 :
69 0 : r = _bf_send_from_buff(fd, (void *)request, bf_request_size(request));
70 0 : if (r < 0) {
71 0 : (void)fprintf(stderr, "Failed to send request: %s\n",
72 0 : bf_strerror(errno));
73 0 : return -errno;
74 : }
75 :
76 0 : if ((size_t)r != bf_request_size(request)) {
77 0 : (void)fprintf(stderr,
78 : "Failed to send request: %lu bytes sent, %ld expected\n",
79 : (size_t)r, bf_request_size(request));
80 0 : return -EIO;
81 : }
82 :
83 : return 0;
84 : }
85 :
86 0 : int bf_recv_request(int fd, struct bf_request **request)
87 : {
88 : struct bf_request req;
89 0 : _cleanup_bf_request_ struct bf_request *_request = NULL;
90 : ssize_t r;
91 :
92 0 : bf_assert(request);
93 :
94 0 : r = _bf_recv_in_buff(fd, &req, sizeof(req));
95 0 : if (r < 0)
96 0 : return (int)r;
97 :
98 0 : if ((size_t)r != sizeof(req)) {
99 0 : (void)fprintf(stderr,
100 : "failed to read request: %lu bytes read, %lu expected\n",
101 : (size_t)r, sizeof(req));
102 0 : return -EIO;
103 : }
104 :
105 0 : _request = malloc(bf_request_size(&req));
106 0 : if (!_request) {
107 0 : (void)fprintf(stderr, "failed to allocate request: %s\n",
108 0 : bf_strerror(errno));
109 0 : return -errno;
110 : }
111 :
112 0 : memcpy(_request, &req, sizeof(req));
113 :
114 0 : r = _bf_recv_in_buff(fd, _request->data, _request->data_len);
115 0 : if (r < 0)
116 0 : return (int)r;
117 :
118 0 : if ((size_t)r != _request->data_len) {
119 0 : (void)fprintf(stderr,
120 : "failed to read request: %lu bytes read, %lu expected\n",
121 : (size_t)r, _request->data_len);
122 0 : return -EIO;
123 : }
124 :
125 0 : *request = TAKE_PTR(_request);
126 :
127 0 : return 0;
128 : }
129 :
130 0 : int bf_send_response(int fd, struct bf_response *response)
131 : {
132 : ssize_t r;
133 :
134 0 : bf_assert(response);
135 :
136 0 : r = _bf_send_from_buff(fd, (void *)response, bf_response_size(response));
137 0 : if (r < 0) {
138 0 : (void)fprintf(stderr, "Failed to send response: %s\n",
139 0 : bf_strerror(errno));
140 0 : return -errno;
141 : }
142 :
143 0 : if ((size_t)r != bf_response_size(response)) {
144 0 : (void)fprintf(stderr,
145 : "Failed to send response: %lu bytes sent, %ld expected\n",
146 : r, bf_response_size(response));
147 0 : return -EIO;
148 : }
149 :
150 : return 0;
151 : }
152 :
153 0 : int bf_recv_response(int fd, struct bf_response **response)
154 : {
155 : struct bf_response res;
156 0 : _cleanup_bf_response_ struct bf_response *_response = NULL;
157 : ssize_t r;
158 :
159 0 : bf_assert(response);
160 :
161 0 : r = _bf_recv_in_buff(fd, &res, sizeof(res));
162 0 : if (r < 0)
163 0 : return -errno;
164 :
165 0 : if ((size_t)r != sizeof(res)) {
166 0 : (void)fprintf(stderr,
167 : "failed to read response: %lu bytes read, %lu expected\n",
168 : (size_t)r, sizeof(res));
169 0 : return -EIO;
170 : }
171 :
172 0 : _response = malloc(bf_response_size(&res));
173 0 : if (!_response) {
174 0 : (void)fprintf(stderr, "failed to allocate response: %s\n",
175 0 : bf_strerror(errno));
176 0 : return -errno;
177 : }
178 :
179 0 : memcpy(_response, &res, sizeof(res));
180 :
181 0 : r = _bf_recv_in_buff(fd, _response->data, _response->data_len);
182 0 : if (r < 0)
183 0 : return (int)r;
184 :
185 0 : if (_response->type == BF_RES_SUCCESS && (size_t)r != _response->data_len) {
186 0 : (void)fprintf(stderr,
187 : "failed to read response: %lu bytes read, %lu expected\n",
188 : (size_t)r, _response->data_len);
189 0 : return -EIO;
190 : }
191 :
192 0 : *response = TAKE_PTR(_response);
193 :
194 0 : return 0;
195 : }
196 :
197 0 : int bf_ensure_dir(const char *dir)
198 : {
199 : struct stat stats;
200 : int r;
201 :
202 0 : bf_assert(dir);
203 :
204 0 : r = access(dir, R_OK | W_OK);
205 0 : if (r && errno == ENOENT) {
206 0 : if (mkdir(dir, BF_PERM_755) == 0)
207 : return 0;
208 :
209 0 : return bf_err_r(errno, "failed to create directory '%s'", dir);
210 : }
211 : if (r)
212 0 : return bf_err_r(errno, "no R/W permissions on '%s'", dir);
213 :
214 0 : if (stat(dir, &stats) != 0 || !S_ISDIR(stats.st_mode))
215 0 : return bf_err_r(-EINVAL, "'%s' is not a valid directory", dir);
216 :
217 : return 0;
218 : }
|