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 */
46 #include "proto_impl.h"
48 #define UDS_CTX_MAGIC 0xd541c
51 struct sockaddr_un uc_sun;
54 #define UDS_SIDE_CLIENT 0
55 #define UDS_SIDE_SERVER_LISTEN 1
56 #define UDS_SIDE_SERVER_WORK 2
59 static void uds_close(void *ctx);
62 uds_addr(const char *addr, struct sockaddr_un *sunp)
68 if (strncasecmp(addr, "uds://", 6) == 0)
70 else if (strncasecmp(addr, "unix://", 7) == 0)
72 else if (addr[0] == '/' && /* If it starts from /... */
73 strstr(addr, "://") == NULL)/* ...and there is no prefix... */
74 ; /* ...we assume its us. */
78 sunp->sun_family = AF_UNIX;
79 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
80 sizeof(sunp->sun_path)) {
81 return (ENAMETOOLONG);
83 sunp->sun_len = SUN_LEN(sunp);
89 uds_common_setup(const char *addr, void **ctxp, int side)
94 uctx = malloc(sizeof(*uctx));
98 /* Parse given address. */
99 if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
104 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
105 if (uctx->uc_fd == -1) {
111 uctx->uc_side = side;
112 uctx->uc_magic = UDS_CTX_MAGIC;
119 uds_client(const char *addr, void **ctxp)
122 return (uds_common_setup(addr, ctxp, UDS_SIDE_CLIENT));
126 uds_connect(void *ctx)
128 struct uds_ctx *uctx = ctx;
130 assert(uctx != NULL);
131 assert(uctx->uc_magic == UDS_CTX_MAGIC);
132 assert(uctx->uc_side == UDS_SIDE_CLIENT);
133 assert(uctx->uc_fd >= 0);
135 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
136 sizeof(uctx->uc_sun)) < 0) {
144 uds_server(const char *addr, void **ctxp)
146 struct uds_ctx *uctx;
149 ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
155 unlink(uctx->uc_sun.sun_path);
156 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
157 sizeof(uctx->uc_sun)) < 0) {
162 if (listen(uctx->uc_fd, 8) < 0) {
172 uds_accept(void *ctx, void **newctxp)
174 struct uds_ctx *uctx = ctx;
175 struct uds_ctx *newuctx;
179 assert(uctx != NULL);
180 assert(uctx->uc_magic == UDS_CTX_MAGIC);
181 assert(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
182 assert(uctx->uc_fd >= 0);
184 newuctx = malloc(sizeof(*newuctx));
188 fromlen = sizeof(uctx->uc_sun);
189 newuctx->uc_fd = accept(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
191 if (newuctx->uc_fd < 0) {
197 newuctx->uc_side = UDS_SIDE_SERVER_WORK;
198 newuctx->uc_magic = UDS_CTX_MAGIC;
205 uds_send(void *ctx, const unsigned char *data, size_t size)
207 struct uds_ctx *uctx = ctx;
209 assert(uctx != NULL);
210 assert(uctx->uc_magic == UDS_CTX_MAGIC);
211 assert(uctx->uc_fd >= 0);
213 return (proto_common_send(uctx->uc_fd, data, size));
217 uds_recv(void *ctx, unsigned char *data, size_t size)
219 struct uds_ctx *uctx = ctx;
221 assert(uctx != NULL);
222 assert(uctx->uc_magic == UDS_CTX_MAGIC);
223 assert(uctx->uc_fd >= 0);
225 return (proto_common_recv(uctx->uc_fd, data, size));
229 uds_descriptor(const void *ctx)
231 const struct uds_ctx *uctx = ctx;
233 assert(uctx != NULL);
234 assert(uctx->uc_magic == UDS_CTX_MAGIC);
236 return (uctx->uc_fd);
240 uds_address_match(const void *ctx __unused, const char *addr __unused)
243 assert(!"proto_address_match() not supported on UNIX domain sockets");
248 uds_local_address(const void *ctx, char *addr, size_t size)
250 const struct uds_ctx *uctx = ctx;
251 struct sockaddr_un sun;
254 assert(uctx != NULL);
255 assert(uctx->uc_magic == UDS_CTX_MAGIC);
256 assert(addr != NULL);
258 sunlen = sizeof(sun);
259 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
260 strlcpy(addr, "N/A", size);
263 assert(sun.sun_family == AF_UNIX);
264 if (sun.sun_path[0] == '\0') {
265 strlcpy(addr, "N/A", size);
268 snprintf(addr, size, "uds://%s", sun.sun_path);
272 uds_remote_address(const void *ctx, char *addr, size_t size)
274 const struct uds_ctx *uctx = ctx;
275 struct sockaddr_un sun;
278 assert(uctx != NULL);
279 assert(uctx->uc_magic == UDS_CTX_MAGIC);
280 assert(addr != NULL);
282 sunlen = sizeof(sun);
283 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
284 strlcpy(addr, "N/A", size);
287 assert(sun.sun_family == AF_UNIX);
288 if (sun.sun_path[0] == '\0') {
289 strlcpy(addr, "N/A", size);
292 snprintf(addr, size, "uds://%s", sun.sun_path);
298 struct uds_ctx *uctx = ctx;
300 assert(uctx != NULL);
301 assert(uctx->uc_magic == UDS_CTX_MAGIC);
303 if (uctx->uc_fd >= 0)
305 unlink(uctx->uc_sun.sun_path);
310 static struct hast_proto uds_proto = {
312 .hp_client = uds_client,
313 .hp_connect = uds_connect,
314 .hp_server = uds_server,
315 .hp_accept = uds_accept,
318 .hp_descriptor = uds_descriptor,
319 .hp_address_match = uds_address_match,
320 .hp_local_address = uds_local_address,
321 .hp_remote_address = uds_remote_address,
322 .hp_close = uds_close
325 static __constructor void
329 proto_register(&uds_proto);