2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 /* UDS - UNIX Domain Socket */
35 #include <sys/types.h>
36 #include <sys/socket.h>
47 #include "proto_impl.h"
49 #define UDS_CTX_MAGIC 0xd541c
52 struct sockaddr_un uc_sun;
55 #define UDS_SIDE_CLIENT 0
56 #define UDS_SIDE_SERVER_LISTEN 1
57 #define UDS_SIDE_SERVER_WORK 2
61 static void uds_close(void *ctx);
64 uds_addr(const char *addr, struct sockaddr_un *sunp)
70 if (strncasecmp(addr, "uds://", 6) == 0)
72 else if (strncasecmp(addr, "unix://", 7) == 0)
74 else if (addr[0] == '/' && /* If it starts from /... */
75 strstr(addr, "://") == NULL)/* ...and there is no prefix... */
76 ; /* ...we assume its us. */
80 sunp->sun_family = AF_UNIX;
81 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
82 sizeof(sunp->sun_path)) {
83 return (ENAMETOOLONG);
85 sunp->sun_len = SUN_LEN(sunp);
91 uds_common_setup(const char *addr, void **ctxp, int side)
96 uctx = malloc(sizeof(*uctx));
100 /* Parse given address. */
101 if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
106 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
107 if (uctx->uc_fd == -1) {
113 uctx->uc_side = side;
115 uctx->uc_magic = UDS_CTX_MAGIC;
122 uds_client(const char *srcaddr, const char *dstaddr, void **ctxp)
126 ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT);
130 PJDLOG_ASSERT(srcaddr == NULL);
136 uds_connect(void *ctx, int timeout)
138 struct uds_ctx *uctx = ctx;
140 PJDLOG_ASSERT(uctx != NULL);
141 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
142 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
143 PJDLOG_ASSERT(uctx->uc_fd >= 0);
144 PJDLOG_ASSERT(timeout >= -1);
146 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
147 sizeof(uctx->uc_sun)) == -1) {
155 uds_connect_wait(void *ctx, int timeout)
157 struct uds_ctx *uctx = ctx;
159 PJDLOG_ASSERT(uctx != NULL);
160 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
161 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
162 PJDLOG_ASSERT(uctx->uc_fd >= 0);
163 PJDLOG_ASSERT(timeout >= 0);
169 uds_server(const char *addr, void **ctxp)
171 struct uds_ctx *uctx;
174 ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
180 (void)unlink(uctx->uc_sun.sun_path);
181 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
182 sizeof(uctx->uc_sun)) == -1) {
187 uctx->uc_owner = getpid();
188 if (listen(uctx->uc_fd, 8) == -1) {
198 uds_accept(void *ctx, void **newctxp)
200 struct uds_ctx *uctx = ctx;
201 struct uds_ctx *newuctx;
205 PJDLOG_ASSERT(uctx != NULL);
206 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
207 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
208 PJDLOG_ASSERT(uctx->uc_fd >= 0);
210 newuctx = malloc(sizeof(*newuctx));
214 fromlen = sizeof(newuctx->uc_sun);
215 newuctx->uc_fd = accept(uctx->uc_fd,
216 (struct sockaddr *)&newuctx->uc_sun, &fromlen);
217 if (newuctx->uc_fd == -1) {
223 newuctx->uc_side = UDS_SIDE_SERVER_WORK;
224 newuctx->uc_magic = UDS_CTX_MAGIC;
231 uds_send(void *ctx, const unsigned char *data, size_t size, int fd)
233 struct uds_ctx *uctx = ctx;
235 PJDLOG_ASSERT(uctx != NULL);
236 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
237 PJDLOG_ASSERT(uctx->uc_fd >= 0);
239 return (proto_common_send(uctx->uc_fd, data, size, fd));
243 uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
245 struct uds_ctx *uctx = ctx;
247 PJDLOG_ASSERT(uctx != NULL);
248 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
249 PJDLOG_ASSERT(uctx->uc_fd >= 0);
251 return (proto_common_recv(uctx->uc_fd, data, size, fdp));
255 uds_descriptor(const void *ctx)
257 const struct uds_ctx *uctx = ctx;
259 PJDLOG_ASSERT(uctx != NULL);
260 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
262 return (uctx->uc_fd);
266 uds_local_address(const void *ctx, char *addr, size_t size)
268 const struct uds_ctx *uctx = ctx;
269 struct sockaddr_un sun;
272 PJDLOG_ASSERT(uctx != NULL);
273 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
274 PJDLOG_ASSERT(addr != NULL);
276 sunlen = sizeof(sun);
277 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
278 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
281 PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
282 if (sun.sun_path[0] == '\0') {
283 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
286 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
290 uds_remote_address(const void *ctx, char *addr, size_t size)
292 const struct uds_ctx *uctx = ctx;
293 struct sockaddr_un sun;
296 PJDLOG_ASSERT(uctx != NULL);
297 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
298 PJDLOG_ASSERT(addr != NULL);
300 sunlen = sizeof(sun);
301 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
302 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
305 PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
306 if (sun.sun_path[0] == '\0') {
307 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
310 snprintf(addr, size, "uds://%s", sun.sun_path);
316 struct uds_ctx *uctx = ctx;
318 PJDLOG_ASSERT(uctx != NULL);
319 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
321 if (uctx->uc_fd >= 0)
324 * Unlink the socket only if we are the owner and this is descriptor
327 if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
328 uctx->uc_owner == getpid()) {
329 PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
330 if (unlink(uctx->uc_sun.sun_path) == -1) {
331 pjdlog_errno(LOG_WARNING,
332 "Unable to unlink socket file %s",
333 uctx->uc_sun.sun_path);
341 static struct proto uds_proto = {
343 .prt_client = uds_client,
344 .prt_connect = uds_connect,
345 .prt_connect_wait = uds_connect_wait,
346 .prt_server = uds_server,
347 .prt_accept = uds_accept,
348 .prt_send = uds_send,
349 .prt_recv = uds_recv,
350 .prt_descriptor = uds_descriptor,
351 .prt_local_address = uds_local_address,
352 .prt_remote_address = uds_remote_address,
353 .prt_close = uds_close
356 static __constructor void
360 proto_register(&uds_proto, false);