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 */
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
60 static void uds_close(void *ctx);
63 uds_addr(const char *addr, struct sockaddr_un *sunp)
69 if (strncasecmp(addr, "uds://", 6) == 0)
71 else if (strncasecmp(addr, "unix://", 7) == 0)
73 else if (addr[0] == '/' && /* If it starts from /... */
74 strstr(addr, "://") == NULL)/* ...and there is no prefix... */
75 ; /* ...we assume its us. */
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);
84 sunp->sun_len = SUN_LEN(sunp);
90 uds_common_setup(const char *addr, void **ctxp, int side)
95 uctx = malloc(sizeof(*uctx));
99 /* Parse given address. */
100 if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
105 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
106 if (uctx->uc_fd == -1) {
112 uctx->uc_side = side;
113 uctx->uc_magic = UDS_CTX_MAGIC;
120 uds_client(const char *addr, void **ctxp)
123 return (uds_common_setup(addr, ctxp, UDS_SIDE_CLIENT));
127 uds_connect(void *ctx)
129 struct uds_ctx *uctx = ctx;
131 assert(uctx != NULL);
132 assert(uctx->uc_magic == UDS_CTX_MAGIC);
133 assert(uctx->uc_side == UDS_SIDE_CLIENT);
134 assert(uctx->uc_fd >= 0);
136 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
137 sizeof(uctx->uc_sun)) < 0) {
145 uds_server(const char *addr, void **ctxp)
147 struct uds_ctx *uctx;
150 ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
156 unlink(uctx->uc_sun.sun_path);
157 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
158 sizeof(uctx->uc_sun)) < 0) {
163 if (listen(uctx->uc_fd, 8) < 0) {
173 uds_accept(void *ctx, void **newctxp)
175 struct uds_ctx *uctx = ctx;
176 struct uds_ctx *newuctx;
180 assert(uctx != NULL);
181 assert(uctx->uc_magic == UDS_CTX_MAGIC);
182 assert(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
183 assert(uctx->uc_fd >= 0);
185 newuctx = malloc(sizeof(*newuctx));
189 fromlen = sizeof(uctx->uc_sun);
190 newuctx->uc_fd = accept(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
192 if (newuctx->uc_fd < 0) {
198 newuctx->uc_side = UDS_SIDE_SERVER_WORK;
199 newuctx->uc_magic = UDS_CTX_MAGIC;
206 uds_send(void *ctx, const unsigned char *data, size_t size)
208 struct uds_ctx *uctx = ctx;
210 assert(uctx != NULL);
211 assert(uctx->uc_magic == UDS_CTX_MAGIC);
212 assert(uctx->uc_fd >= 0);
214 return (proto_common_send(uctx->uc_fd, data, size));
218 uds_recv(void *ctx, unsigned char *data, size_t size)
220 struct uds_ctx *uctx = ctx;
222 assert(uctx != NULL);
223 assert(uctx->uc_magic == UDS_CTX_MAGIC);
224 assert(uctx->uc_fd >= 0);
226 return (proto_common_recv(uctx->uc_fd, data, size));
230 uds_descriptor(const void *ctx)
232 const struct uds_ctx *uctx = ctx;
234 assert(uctx != NULL);
235 assert(uctx->uc_magic == UDS_CTX_MAGIC);
237 return (uctx->uc_fd);
241 uds_address_match(const void *ctx __unused, const char *addr __unused)
244 assert(!"proto_address_match() not supported on UNIX domain sockets");
249 uds_local_address(const void *ctx, char *addr, size_t size)
251 const struct uds_ctx *uctx = ctx;
252 struct sockaddr_un sun;
255 assert(uctx != NULL);
256 assert(uctx->uc_magic == UDS_CTX_MAGIC);
257 assert(addr != NULL);
259 sunlen = sizeof(sun);
260 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
261 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
264 assert(sun.sun_family == AF_UNIX);
265 if (sun.sun_path[0] == '\0') {
266 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
269 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
273 uds_remote_address(const void *ctx, char *addr, size_t size)
275 const struct uds_ctx *uctx = ctx;
276 struct sockaddr_un sun;
279 assert(uctx != NULL);
280 assert(uctx->uc_magic == UDS_CTX_MAGIC);
281 assert(addr != NULL);
283 sunlen = sizeof(sun);
284 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
285 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
288 assert(sun.sun_family == AF_UNIX);
289 if (sun.sun_path[0] == '\0') {
290 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
293 snprintf(addr, size, "uds://%s", sun.sun_path);
299 struct uds_ctx *uctx = ctx;
301 assert(uctx != NULL);
302 assert(uctx->uc_magic == UDS_CTX_MAGIC);
304 if (uctx->uc_fd >= 0)
306 unlink(uctx->uc_sun.sun_path);
311 static struct hast_proto uds_proto = {
313 .hp_client = uds_client,
314 .hp_connect = uds_connect,
315 .hp_server = uds_server,
316 .hp_accept = uds_accept,
319 .hp_descriptor = uds_descriptor,
320 .hp_address_match = uds_address_match,
321 .hp_local_address = uds_local_address,
322 .hp_remote_address = uds_remote_address,
323 .hp_close = uds_close
326 static __constructor void
330 proto_register(&uds_proto, false);