Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/hastd/proto_uds.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2009-2010 The FreeBSD Foundation
5
*
6
* This software was developed by Pawel Jakub Dawidek under sponsorship from
7
* the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
#include <sys/cdefs.h>
32
/* UDS - UNIX Domain Socket */
33
34
#include <sys/types.h>
35
#include <sys/socket.h>
36
#include <sys/un.h>
37
38
#include <errno.h>
39
#include <stdbool.h>
40
#include <stdint.h>
41
#include <stdio.h>
42
#include <string.h>
43
#include <unistd.h>
44
45
#include "pjdlog.h"
46
#include "proto_impl.h"
47
48
#define UDS_CTX_MAGIC 0xd541c
49
struct uds_ctx {
50
int uc_magic;
51
struct sockaddr_un uc_sun;
52
int uc_fd;
53
int uc_side;
54
#define UDS_SIDE_CLIENT 0
55
#define UDS_SIDE_SERVER_LISTEN 1
56
#define UDS_SIDE_SERVER_WORK 2
57
pid_t uc_owner;
58
};
59
60
static void uds_close(void *ctx);
61
62
static int
63
uds_addr(const char *addr, struct sockaddr_un *sunp)
64
{
65
66
if (addr == NULL)
67
return (-1);
68
69
if (strncasecmp(addr, "uds://", 6) == 0)
70
addr += 6;
71
else if (strncasecmp(addr, "unix://", 7) == 0)
72
addr += 7;
73
else if (addr[0] == '/' && /* If it starts from /... */
74
strstr(addr, "://") == NULL)/* ...and there is no prefix... */
75
; /* ...we assume its us. */
76
else
77
return (-1);
78
79
sunp->sun_family = AF_UNIX;
80
if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
81
sizeof(sunp->sun_path)) {
82
return (ENAMETOOLONG);
83
}
84
sunp->sun_len = SUN_LEN(sunp);
85
86
return (0);
87
}
88
89
static int
90
uds_common_setup(const char *addr, void **ctxp, int side)
91
{
92
struct uds_ctx *uctx;
93
int ret;
94
95
uctx = malloc(sizeof(*uctx));
96
if (uctx == NULL)
97
return (errno);
98
99
/* Parse given address. */
100
if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
101
free(uctx);
102
return (ret);
103
}
104
105
uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
106
if (uctx->uc_fd == -1) {
107
ret = errno;
108
free(uctx);
109
return (ret);
110
}
111
112
uctx->uc_side = side;
113
uctx->uc_owner = 0;
114
uctx->uc_magic = UDS_CTX_MAGIC;
115
*ctxp = uctx;
116
117
return (0);
118
}
119
120
static int
121
uds_client(const char *srcaddr, const char *dstaddr, void **ctxp)
122
{
123
int ret;
124
125
ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT);
126
if (ret != 0)
127
return (ret);
128
129
PJDLOG_ASSERT(srcaddr == NULL);
130
131
return (0);
132
}
133
134
static int
135
uds_connect(void *ctx, int timeout)
136
{
137
struct uds_ctx *uctx = ctx;
138
139
PJDLOG_ASSERT(uctx != NULL);
140
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
141
PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
142
PJDLOG_ASSERT(uctx->uc_fd >= 0);
143
PJDLOG_ASSERT(timeout >= -1);
144
145
if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
146
sizeof(uctx->uc_sun)) == -1) {
147
return (errno);
148
}
149
150
return (0);
151
}
152
153
static int
154
uds_connect_wait(void *ctx, int timeout)
155
{
156
struct uds_ctx *uctx = ctx;
157
158
PJDLOG_ASSERT(uctx != NULL);
159
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
160
PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
161
PJDLOG_ASSERT(uctx->uc_fd >= 0);
162
PJDLOG_ASSERT(timeout >= 0);
163
164
return (0);
165
}
166
167
static int
168
uds_server(const char *addr, void **ctxp)
169
{
170
struct uds_ctx *uctx;
171
int ret;
172
173
ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
174
if (ret != 0)
175
return (ret);
176
177
uctx = *ctxp;
178
179
(void)unlink(uctx->uc_sun.sun_path);
180
if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
181
sizeof(uctx->uc_sun)) == -1) {
182
ret = errno;
183
uds_close(uctx);
184
return (ret);
185
}
186
uctx->uc_owner = getpid();
187
if (listen(uctx->uc_fd, 8) == -1) {
188
ret = errno;
189
uds_close(uctx);
190
return (ret);
191
}
192
193
return (0);
194
}
195
196
static int
197
uds_accept(void *ctx, void **newctxp)
198
{
199
struct uds_ctx *uctx = ctx;
200
struct uds_ctx *newuctx;
201
socklen_t fromlen;
202
int ret;
203
204
PJDLOG_ASSERT(uctx != NULL);
205
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
206
PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
207
PJDLOG_ASSERT(uctx->uc_fd >= 0);
208
209
newuctx = malloc(sizeof(*newuctx));
210
if (newuctx == NULL)
211
return (errno);
212
213
fromlen = sizeof(newuctx->uc_sun);
214
newuctx->uc_fd = accept(uctx->uc_fd,
215
(struct sockaddr *)&newuctx->uc_sun, &fromlen);
216
if (newuctx->uc_fd == -1) {
217
ret = errno;
218
free(newuctx);
219
return (ret);
220
}
221
222
newuctx->uc_side = UDS_SIDE_SERVER_WORK;
223
newuctx->uc_magic = UDS_CTX_MAGIC;
224
*newctxp = newuctx;
225
226
return (0);
227
}
228
229
static int
230
uds_send(void *ctx, const unsigned char *data, size_t size, int fd)
231
{
232
struct uds_ctx *uctx = ctx;
233
234
PJDLOG_ASSERT(uctx != NULL);
235
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
236
PJDLOG_ASSERT(uctx->uc_fd >= 0);
237
238
return (proto_common_send(uctx->uc_fd, data, size, fd));
239
}
240
241
static int
242
uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
243
{
244
struct uds_ctx *uctx = ctx;
245
246
PJDLOG_ASSERT(uctx != NULL);
247
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
248
PJDLOG_ASSERT(uctx->uc_fd >= 0);
249
250
return (proto_common_recv(uctx->uc_fd, data, size, fdp));
251
}
252
253
static int
254
uds_descriptor(const void *ctx)
255
{
256
const struct uds_ctx *uctx = ctx;
257
258
PJDLOG_ASSERT(uctx != NULL);
259
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
260
261
return (uctx->uc_fd);
262
}
263
264
static void
265
uds_local_address(const void *ctx, char *addr, size_t size)
266
{
267
const struct uds_ctx *uctx = ctx;
268
struct sockaddr_un sun;
269
socklen_t sunlen;
270
271
PJDLOG_ASSERT(uctx != NULL);
272
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
273
PJDLOG_ASSERT(addr != NULL);
274
275
sunlen = sizeof(sun);
276
if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
277
PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
278
return;
279
}
280
PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
281
if (sun.sun_path[0] == '\0') {
282
PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
283
return;
284
}
285
PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
286
}
287
288
static void
289
uds_remote_address(const void *ctx, char *addr, size_t size)
290
{
291
const struct uds_ctx *uctx = ctx;
292
struct sockaddr_un sun;
293
socklen_t sunlen;
294
295
PJDLOG_ASSERT(uctx != NULL);
296
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
297
PJDLOG_ASSERT(addr != NULL);
298
299
sunlen = sizeof(sun);
300
if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
301
PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
302
return;
303
}
304
PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
305
if (sun.sun_path[0] == '\0') {
306
PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
307
return;
308
}
309
snprintf(addr, size, "uds://%s", sun.sun_path);
310
}
311
312
static void
313
uds_close(void *ctx)
314
{
315
struct uds_ctx *uctx = ctx;
316
317
PJDLOG_ASSERT(uctx != NULL);
318
PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
319
320
if (uctx->uc_fd >= 0)
321
close(uctx->uc_fd);
322
/*
323
* Unlink the socket only if we are the owner and this is descriptor
324
* we listen on.
325
*/
326
if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
327
uctx->uc_owner == getpid()) {
328
PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
329
if (unlink(uctx->uc_sun.sun_path) == -1) {
330
pjdlog_errno(LOG_WARNING,
331
"Unable to unlink socket file %s",
332
uctx->uc_sun.sun_path);
333
}
334
}
335
uctx->uc_owner = 0;
336
uctx->uc_magic = 0;
337
free(uctx);
338
}
339
340
static struct proto uds_proto = {
341
.prt_name = "uds",
342
.prt_client = uds_client,
343
.prt_connect = uds_connect,
344
.prt_connect_wait = uds_connect_wait,
345
.prt_server = uds_server,
346
.prt_accept = uds_accept,
347
.prt_send = uds_send,
348
.prt_recv = uds_recv,
349
.prt_descriptor = uds_descriptor,
350
.prt_local_address = uds_local_address,
351
.prt_remote_address = uds_remote_address,
352
.prt_close = uds_close
353
};
354
355
static __constructor void
356
uds_ctor(void)
357
{
358
359
proto_register(&uds_proto, false);
360
}
361
362