1204076Spjd/*-
2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation
3204076Spjd * All rights reserved.
4204076Spjd *
5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6204076Spjd * the FreeBSD Foundation.
7204076Spjd *
8204076Spjd * Redistribution and use in source and binary forms, with or without
9204076Spjd * modification, are permitted provided that the following conditions
10204076Spjd * are met:
11204076Spjd * 1. Redistributions of source code must retain the above copyright
12204076Spjd *    notice, this list of conditions and the following disclaimer.
13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
14204076Spjd *    notice, this list of conditions and the following disclaimer in the
15204076Spjd *    documentation and/or other materials provided with the distribution.
16204076Spjd *
17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27204076Spjd * SUCH DAMAGE.
28204076Spjd */
29204076Spjd
30204076Spjd#include <sys/cdefs.h>
31204076Spjd__FBSDID("$FreeBSD$");
32204076Spjd
33204076Spjd/* UDS - UNIX Domain Socket */
34204076Spjd
35218465Spjd#include <sys/types.h>
36219873Spjd#include <sys/socket.h>
37204076Spjd#include <sys/un.h>
38204076Spjd
39204076Spjd#include <errno.h>
40204076Spjd#include <stdbool.h>
41204076Spjd#include <stdint.h>
42204076Spjd#include <stdio.h>
43204076Spjd#include <string.h>
44204076Spjd#include <unistd.h>
45204076Spjd
46210876Spjd#include "pjdlog.h"
47204076Spjd#include "proto_impl.h"
48204076Spjd
49204076Spjd#define	UDS_CTX_MAGIC	0xd541c
50204076Spjdstruct uds_ctx {
51204076Spjd	int			uc_magic;
52204076Spjd	struct sockaddr_un	uc_sun;
53204076Spjd	int			uc_fd;
54204076Spjd	int			uc_side;
55204076Spjd#define	UDS_SIDE_CLIENT		0
56204076Spjd#define	UDS_SIDE_SERVER_LISTEN	1
57204076Spjd#define	UDS_SIDE_SERVER_WORK	2
58218464Spjd	pid_t			uc_owner;
59204076Spjd};
60204076Spjd
61204076Spjdstatic void uds_close(void *ctx);
62204076Spjd
63204076Spjdstatic int
64204076Spjduds_addr(const char *addr, struct sockaddr_un *sunp)
65204076Spjd{
66204076Spjd
67204076Spjd	if (addr == NULL)
68204076Spjd		return (-1);
69204076Spjd
70204076Spjd	if (strncasecmp(addr, "uds://", 6) == 0)
71204076Spjd		addr += 6;
72204076Spjd	else if (strncasecmp(addr, "unix://", 7) == 0)
73204076Spjd		addr += 7;
74204076Spjd	else if (addr[0] == '/' &&	/* If it starts from /... */
75204076Spjd	    strstr(addr, "://") == NULL)/* ...and there is no prefix... */
76204076Spjd		;			/* ...we assume its us. */
77204076Spjd	else
78204076Spjd		return (-1);
79204076Spjd
80204076Spjd	sunp->sun_family = AF_UNIX;
81204076Spjd	if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
82204076Spjd	    sizeof(sunp->sun_path)) {
83204076Spjd		return (ENAMETOOLONG);
84204076Spjd	}
85204076Spjd	sunp->sun_len = SUN_LEN(sunp);
86204076Spjd
87204076Spjd	return (0);
88204076Spjd}
89204076Spjd
90204076Spjdstatic int
91204076Spjduds_common_setup(const char *addr, void **ctxp, int side)
92204076Spjd{
93204076Spjd	struct uds_ctx *uctx;
94204076Spjd	int ret;
95204076Spjd
96204076Spjd	uctx = malloc(sizeof(*uctx));
97204076Spjd	if (uctx == NULL)
98204076Spjd		return (errno);
99204076Spjd
100204076Spjd	/* Parse given address. */
101204076Spjd	if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
102204076Spjd		free(uctx);
103204076Spjd		return (ret);
104204076Spjd	}
105204076Spjd
106204076Spjd	uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
107204076Spjd	if (uctx->uc_fd == -1) {
108204076Spjd		ret = errno;
109204076Spjd		free(uctx);
110204076Spjd		return (ret);
111204076Spjd	}
112204076Spjd
113204076Spjd	uctx->uc_side = side;
114218464Spjd	uctx->uc_owner = 0;
115204076Spjd	uctx->uc_magic = UDS_CTX_MAGIC;
116204076Spjd	*ctxp = uctx;
117204076Spjd
118204076Spjd	return (0);
119204076Spjd}
120204076Spjd
121204076Spjdstatic int
122219818Spjduds_client(const char *srcaddr, const char *dstaddr, void **ctxp)
123204076Spjd{
124219818Spjd	int ret;
125204076Spjd
126219818Spjd	ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT);
127219818Spjd	if (ret != 0)
128219818Spjd		return (ret);
129219818Spjd
130219818Spjd	PJDLOG_ASSERT(srcaddr == NULL);
131219818Spjd
132219818Spjd	return (0);
133204076Spjd}
134204076Spjd
135204076Spjdstatic int
136218192Spjduds_connect(void *ctx, int timeout)
137204076Spjd{
138204076Spjd	struct uds_ctx *uctx = ctx;
139204076Spjd
140218138Spjd	PJDLOG_ASSERT(uctx != NULL);
141218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
142218138Spjd	PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
143218138Spjd	PJDLOG_ASSERT(uctx->uc_fd >= 0);
144218193Spjd	PJDLOG_ASSERT(timeout >= -1);
145204076Spjd
146204076Spjd	if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
147229945Spjd	    sizeof(uctx->uc_sun)) == -1) {
148204076Spjd		return (errno);
149204076Spjd	}
150204076Spjd
151204076Spjd	return (0);
152204076Spjd}
153204076Spjd
154204076Spjdstatic int
155218193Spjduds_connect_wait(void *ctx, int timeout)
156218193Spjd{
157218193Spjd	struct uds_ctx *uctx = ctx;
158218193Spjd
159218193Spjd	PJDLOG_ASSERT(uctx != NULL);
160218193Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
161218193Spjd	PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
162218193Spjd	PJDLOG_ASSERT(uctx->uc_fd >= 0);
163218193Spjd	PJDLOG_ASSERT(timeout >= 0);
164218193Spjd
165218193Spjd	return (0);
166218193Spjd}
167218193Spjd
168218193Spjdstatic int
169204076Spjduds_server(const char *addr, void **ctxp)
170204076Spjd{
171204076Spjd	struct uds_ctx *uctx;
172204076Spjd	int ret;
173204076Spjd
174204076Spjd	ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
175204076Spjd	if (ret != 0)
176204076Spjd		return (ret);
177204076Spjd
178204076Spjd	uctx = *ctxp;
179204076Spjd
180218464Spjd	(void)unlink(uctx->uc_sun.sun_path);
181204076Spjd	if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
182229945Spjd	    sizeof(uctx->uc_sun)) == -1) {
183204076Spjd		ret = errno;
184204076Spjd		uds_close(uctx);
185204076Spjd		return (ret);
186204076Spjd	}
187218464Spjd	uctx->uc_owner = getpid();
188229945Spjd	if (listen(uctx->uc_fd, 8) == -1) {
189204076Spjd		ret = errno;
190204076Spjd		uds_close(uctx);
191204076Spjd		return (ret);
192204076Spjd	}
193204076Spjd
194204076Spjd	return (0);
195204076Spjd}
196204076Spjd
197204076Spjdstatic int
198204076Spjduds_accept(void *ctx, void **newctxp)
199204076Spjd{
200204076Spjd	struct uds_ctx *uctx = ctx;
201204076Spjd	struct uds_ctx *newuctx;
202204076Spjd	socklen_t fromlen;
203204076Spjd	int ret;
204204076Spjd
205218138Spjd	PJDLOG_ASSERT(uctx != NULL);
206218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
207218138Spjd	PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
208218138Spjd	PJDLOG_ASSERT(uctx->uc_fd >= 0);
209204076Spjd
210204076Spjd	newuctx = malloc(sizeof(*newuctx));
211204076Spjd	if (newuctx == NULL)
212204076Spjd		return (errno);
213204076Spjd
214218464Spjd	fromlen = sizeof(newuctx->uc_sun);
215218464Spjd	newuctx->uc_fd = accept(uctx->uc_fd,
216218464Spjd	    (struct sockaddr *)&newuctx->uc_sun, &fromlen);
217229945Spjd	if (newuctx->uc_fd == -1) {
218204076Spjd		ret = errno;
219204076Spjd		free(newuctx);
220204076Spjd		return (ret);
221204076Spjd	}
222204076Spjd
223204076Spjd	newuctx->uc_side = UDS_SIDE_SERVER_WORK;
224204076Spjd	newuctx->uc_magic = UDS_CTX_MAGIC;
225204076Spjd	*newctxp = newuctx;
226204076Spjd
227204076Spjd	return (0);
228204076Spjd}
229204076Spjd
230204076Spjdstatic int
231218194Spjduds_send(void *ctx, const unsigned char *data, size_t size, int fd)
232204076Spjd{
233204076Spjd	struct uds_ctx *uctx = ctx;
234204076Spjd
235218138Spjd	PJDLOG_ASSERT(uctx != NULL);
236218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
237218138Spjd	PJDLOG_ASSERT(uctx->uc_fd >= 0);
238204076Spjd
239218194Spjd	return (proto_common_send(uctx->uc_fd, data, size, fd));
240204076Spjd}
241204076Spjd
242204076Spjdstatic int
243218194Spjduds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
244204076Spjd{
245204076Spjd	struct uds_ctx *uctx = ctx;
246204076Spjd
247218138Spjd	PJDLOG_ASSERT(uctx != NULL);
248218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
249218138Spjd	PJDLOG_ASSERT(uctx->uc_fd >= 0);
250204076Spjd
251218194Spjd	return (proto_common_recv(uctx->uc_fd, data, size, fdp));
252204076Spjd}
253204076Spjd
254204076Spjdstatic int
255204076Spjduds_descriptor(const void *ctx)
256204076Spjd{
257204076Spjd	const struct uds_ctx *uctx = ctx;
258204076Spjd
259218138Spjd	PJDLOG_ASSERT(uctx != NULL);
260218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
261204076Spjd
262204076Spjd	return (uctx->uc_fd);
263204076Spjd}
264204076Spjd
265204076Spjdstatic void
266204076Spjduds_local_address(const void *ctx, char *addr, size_t size)
267204076Spjd{
268204076Spjd	const struct uds_ctx *uctx = ctx;
269204076Spjd	struct sockaddr_un sun;
270204076Spjd	socklen_t sunlen;
271204076Spjd
272218138Spjd	PJDLOG_ASSERT(uctx != NULL);
273218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
274218138Spjd	PJDLOG_ASSERT(addr != NULL);
275204076Spjd
276204076Spjd	sunlen = sizeof(sun);
277229945Spjd	if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
278210876Spjd		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
279204076Spjd		return;
280204076Spjd	}
281218138Spjd	PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
282204076Spjd	if (sun.sun_path[0] == '\0') {
283210876Spjd		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
284204076Spjd		return;
285204076Spjd	}
286210876Spjd	PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
287204076Spjd}
288204076Spjd
289204076Spjdstatic void
290204076Spjduds_remote_address(const void *ctx, char *addr, size_t size)
291204076Spjd{
292204076Spjd	const struct uds_ctx *uctx = ctx;
293204076Spjd	struct sockaddr_un sun;
294204076Spjd	socklen_t sunlen;
295204076Spjd
296218138Spjd	PJDLOG_ASSERT(uctx != NULL);
297218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
298218138Spjd	PJDLOG_ASSERT(addr != NULL);
299204076Spjd
300204076Spjd	sunlen = sizeof(sun);
301229945Spjd	if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) {
302210876Spjd		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
303204076Spjd		return;
304204076Spjd	}
305218138Spjd	PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
306204076Spjd	if (sun.sun_path[0] == '\0') {
307210876Spjd		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
308204076Spjd		return;
309204076Spjd	}
310204076Spjd	snprintf(addr, size, "uds://%s", sun.sun_path);
311204076Spjd}
312204076Spjd
313204076Spjdstatic void
314204076Spjduds_close(void *ctx)
315204076Spjd{
316204076Spjd	struct uds_ctx *uctx = ctx;
317204076Spjd
318218138Spjd	PJDLOG_ASSERT(uctx != NULL);
319218138Spjd	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
320204076Spjd
321204076Spjd	if (uctx->uc_fd >= 0)
322204076Spjd		close(uctx->uc_fd);
323218464Spjd	/*
324218464Spjd	 * Unlink the socket only if we are the owner and this is descriptor
325218464Spjd	 * we listen on.
326218464Spjd	 */
327218464Spjd	if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
328218464Spjd	    uctx->uc_owner == getpid()) {
329218474Spjd		PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
330218474Spjd		if (unlink(uctx->uc_sun.sun_path) == -1) {
331218474Spjd			pjdlog_errno(LOG_WARNING,
332218474Spjd			    "Unable to unlink socket file %s",
333218474Spjd			    uctx->uc_sun.sun_path);
334218474Spjd		}
335218464Spjd	}
336218464Spjd	uctx->uc_owner = 0;
337204076Spjd	uctx->uc_magic = 0;
338204076Spjd	free(uctx);
339204076Spjd}
340204076Spjd
341219873Spjdstatic struct proto uds_proto = {
342219873Spjd	.prt_name = "uds",
343219873Spjd	.prt_client = uds_client,
344219873Spjd	.prt_connect = uds_connect,
345219873Spjd	.prt_connect_wait = uds_connect_wait,
346219873Spjd	.prt_server = uds_server,
347219873Spjd	.prt_accept = uds_accept,
348219873Spjd	.prt_send = uds_send,
349219873Spjd	.prt_recv = uds_recv,
350219873Spjd	.prt_descriptor = uds_descriptor,
351219873Spjd	.prt_local_address = uds_local_address,
352219873Spjd	.prt_remote_address = uds_remote_address,
353219873Spjd	.prt_close = uds_close
354204076Spjd};
355204076Spjd
356204076Spjdstatic __constructor void
357204076Spjduds_ctor(void)
358204076Spjd{
359204076Spjd
360210869Spjd	proto_register(&uds_proto, false);
361204076Spjd}
362