2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2009-2010 The FreeBSD Foundation
7 * This software was developed by Pawel Jakub Dawidek under sponsorship from
8 * the FreeBSD Foundation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 /* UDS - UNIX Domain Socket */
37 #include <sys/types.h>
38 #include <sys/socket.h>
49 #include "proto_impl.h"
51 #define UDS_CTX_MAGIC 0xd541c
54 struct sockaddr_un uc_sun;
57 #define UDS_SIDE_CLIENT 0
58 #define UDS_SIDE_SERVER_LISTEN 1
59 #define UDS_SIDE_SERVER_WORK 2
63 static void uds_close(void *ctx);
66 uds_addr(const char *addr, struct sockaddr_un *sunp)
72 if (strncasecmp(addr, "uds://", 6) == 0)
74 else if (strncasecmp(addr, "unix://", 7) == 0)
76 else if (addr[0] == '/' && /* If it starts from /... */
77 strstr(addr, "://") == NULL)/* ...and there is no prefix... */
78 ; /* ...we assume its us. */
82 sunp->sun_family = AF_UNIX;
83 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
84 sizeof(sunp->sun_path)) {
85 return (ENAMETOOLONG);
87 sunp->sun_len = SUN_LEN(sunp);
93 uds_common_setup(const char *addr, void **ctxp, int side)
98 uctx = malloc(sizeof(*uctx));
102 /* Parse given address. */
103 if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
108 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
109 if (uctx->uc_fd == -1) {
115 uctx->uc_side = side;
117 uctx->uc_magic = UDS_CTX_MAGIC;
124 uds_client(const char *srcaddr, const char *dstaddr, void **ctxp)
128 ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT);
132 PJDLOG_ASSERT(srcaddr == NULL);
138 uds_connect(void *ctx, int timeout)
140 struct uds_ctx *uctx = ctx;
142 PJDLOG_ASSERT(uctx != NULL);
143 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
144 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
145 PJDLOG_ASSERT(uctx->uc_fd >= 0);
146 PJDLOG_ASSERT(timeout >= -1);
148 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
149 sizeof(uctx->uc_sun)) == -1) {
157 uds_connect_wait(void *ctx, int timeout)
159 struct uds_ctx *uctx = ctx;
161 PJDLOG_ASSERT(uctx != NULL);
162 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
163 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
164 PJDLOG_ASSERT(uctx->uc_fd >= 0);
165 PJDLOG_ASSERT(timeout >= 0);
171 uds_server(const char *addr, void **ctxp)
173 struct uds_ctx *uctx;
176 ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
182 (void)unlink(uctx->uc_sun.sun_path);
183 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
184 sizeof(uctx->uc_sun)) == -1) {
189 uctx->uc_owner = getpid();
190 if (listen(uctx->uc_fd, 8) == -1) {
200 uds_accept(void *ctx, void **newctxp)
202 struct uds_ctx *uctx = ctx;
203 struct uds_ctx *newuctx;
207 PJDLOG_ASSERT(uctx != NULL);
208 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
209 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
210 PJDLOG_ASSERT(uctx->uc_fd >= 0);
212 newuctx = malloc(sizeof(*newuctx));
216 fromlen = sizeof(newuctx->uc_sun);
217 newuctx->uc_fd = accept(uctx->uc_fd,
218 (struct sockaddr *)&newuctx->uc_sun, &fromlen);
219 if (newuctx->uc_fd == -1) {
225 newuctx->uc_side = UDS_SIDE_SERVER_WORK;
226 newuctx->uc_magic = UDS_CTX_MAGIC;
233 uds_send(void *ctx, const unsigned char *data, size_t size, int fd)
235 struct uds_ctx *uctx = ctx;
237 PJDLOG_ASSERT(uctx != NULL);
238 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
239 PJDLOG_ASSERT(uctx->uc_fd >= 0);
241 return (proto_common_send(uctx->uc_fd, data, size, fd));
245 uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
247 struct uds_ctx *uctx = ctx;
249 PJDLOG_ASSERT(uctx != NULL);
250 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
251 PJDLOG_ASSERT(uctx->uc_fd >= 0);
253 return (proto_common_recv(uctx->uc_fd, data, size, fdp));
257 uds_descriptor(const void *ctx)
259 const struct uds_ctx *uctx = ctx;
261 PJDLOG_ASSERT(uctx != NULL);
262 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
264 return (uctx->uc_fd);
268 uds_local_address(const void *ctx, char *addr, size_t size)
270 const struct uds_ctx *uctx = ctx;
271 struct sockaddr_un sun;
274 PJDLOG_ASSERT(uctx != NULL);
275 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
276 PJDLOG_ASSERT(addr != NULL);
278 sunlen = sizeof(sun);
279 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
280 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
283 PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
284 if (sun.sun_path[0] == '\0') {
285 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
288 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
292 uds_remote_address(const void *ctx, char *addr, size_t size)
294 const struct uds_ctx *uctx = ctx;
295 struct sockaddr_un sun;
298 PJDLOG_ASSERT(uctx != NULL);
299 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
300 PJDLOG_ASSERT(addr != NULL);
302 sunlen = sizeof(sun);
303 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
304 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
307 PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
308 if (sun.sun_path[0] == '\0') {
309 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
312 snprintf(addr, size, "uds://%s", sun.sun_path);
318 struct uds_ctx *uctx = ctx;
320 PJDLOG_ASSERT(uctx != NULL);
321 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
323 if (uctx->uc_fd >= 0)
326 * Unlink the socket only if we are the owner and this is descriptor
329 if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
330 uctx->uc_owner == getpid()) {
331 PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
332 if (unlink(uctx->uc_sun.sun_path) == -1) {
333 pjdlog_errno(LOG_WARNING,
334 "Unable to unlink socket file %s",
335 uctx->uc_sun.sun_path);
343 static struct proto uds_proto = {
345 .prt_client = uds_client,
346 .prt_connect = uds_connect,
347 .prt_connect_wait = uds_connect_wait,
348 .prt_server = uds_server,
349 .prt_accept = uds_accept,
350 .prt_send = uds_send,
351 .prt_recv = uds_recv,
352 .prt_descriptor = uds_descriptor,
353 .prt_local_address = uds_local_address,
354 .prt_remote_address = uds_remote_address,
355 .prt_close = uds_close
358 static __constructor void
362 proto_register(&uds_proto, false);