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#include <sys/types.h>
34204076Spjd#include <sys/socket.h>
35204076Spjd
36204076Spjd#include <errno.h>
37204076Spjd#include <stdbool.h>
38204076Spjd#include <stdint.h>
39204076Spjd#include <stdio.h>
40204076Spjd#include <string.h>
41204076Spjd#include <unistd.h>
42204076Spjd
43218138Spjd#include "pjdlog.h"
44204076Spjd#include "proto_impl.h"
45204076Spjd
46204076Spjd#define	SP_CTX_MAGIC	0x50c3741
47204076Spjdstruct sp_ctx {
48204076Spjd	int			sp_magic;
49204076Spjd	int			sp_fd[2];
50204076Spjd	int			sp_side;
51204076Spjd#define	SP_SIDE_UNDEF		0
52204076Spjd#define	SP_SIDE_CLIENT		1
53204076Spjd#define	SP_SIDE_SERVER		2
54204076Spjd};
55204076Spjd
56204076Spjdstatic void sp_close(void *ctx);
57204076Spjd
58204076Spjdstatic int
59219818Spjdsp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
60204076Spjd{
61204076Spjd	struct sp_ctx *spctx;
62204076Spjd	int ret;
63204076Spjd
64219818Spjd	if (strcmp(dstaddr, "socketpair://") != 0)
65204076Spjd		return (-1);
66204076Spjd
67219818Spjd	PJDLOG_ASSERT(srcaddr == NULL);
68219818Spjd
69204076Spjd	spctx = malloc(sizeof(*spctx));
70204076Spjd	if (spctx == NULL)
71204076Spjd		return (errno);
72204076Spjd
73231017Strociny	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
74204076Spjd		ret = errno;
75204076Spjd		free(spctx);
76204076Spjd		return (ret);
77204076Spjd	}
78204076Spjd
79204076Spjd	spctx->sp_side = SP_SIDE_UNDEF;
80204076Spjd	spctx->sp_magic = SP_CTX_MAGIC;
81204076Spjd	*ctxp = spctx;
82204076Spjd
83204076Spjd	return (0);
84204076Spjd}
85204076Spjd
86204076Spjdstatic int
87218194Spjdsp_send(void *ctx, const unsigned char *data, size_t size, int fd)
88204076Spjd{
89204076Spjd	struct sp_ctx *spctx = ctx;
90218194Spjd	int sock;
91204076Spjd
92218138Spjd	PJDLOG_ASSERT(spctx != NULL);
93218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
94204076Spjd
95204076Spjd	switch (spctx->sp_side) {
96204076Spjd	case SP_SIDE_UNDEF:
97204076Spjd		/*
98204076Spjd		 * If the first operation done by the caller is proto_send(),
99218194Spjd		 * we assume this is the client.
100204076Spjd		 */
101204076Spjd		/* FALLTHROUGH */
102204076Spjd		spctx->sp_side = SP_SIDE_CLIENT;
103204076Spjd		/* Close other end. */
104204076Spjd		close(spctx->sp_fd[1]);
105218138Spjd		spctx->sp_fd[1] = -1;
106204076Spjd	case SP_SIDE_CLIENT:
107218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
108218194Spjd		sock = spctx->sp_fd[0];
109204076Spjd		break;
110204076Spjd	case SP_SIDE_SERVER:
111218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
112218194Spjd		sock = spctx->sp_fd[1];
113204076Spjd		break;
114204076Spjd	default:
115218138Spjd		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
116204076Spjd	}
117204076Spjd
118212036Spjd	/* Someone is just trying to decide about side. */
119212036Spjd	if (data == NULL)
120212036Spjd		return (0);
121212036Spjd
122218194Spjd	return (proto_common_send(sock, data, size, fd));
123204076Spjd}
124204076Spjd
125204076Spjdstatic int
126218194Spjdsp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
127204076Spjd{
128204076Spjd	struct sp_ctx *spctx = ctx;
129204076Spjd	int fd;
130204076Spjd
131218138Spjd	PJDLOG_ASSERT(spctx != NULL);
132218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
133204076Spjd
134204076Spjd	switch (spctx->sp_side) {
135204076Spjd	case SP_SIDE_UNDEF:
136204076Spjd		/*
137204076Spjd		 * If the first operation done by the caller is proto_recv(),
138218194Spjd		 * we assume this is the server.
139204076Spjd		 */
140204076Spjd		/* FALLTHROUGH */
141204076Spjd		spctx->sp_side = SP_SIDE_SERVER;
142204076Spjd		/* Close other end. */
143204076Spjd		close(spctx->sp_fd[0]);
144218138Spjd		spctx->sp_fd[0] = -1;
145204076Spjd	case SP_SIDE_SERVER:
146218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
147204076Spjd		fd = spctx->sp_fd[1];
148204076Spjd		break;
149204076Spjd	case SP_SIDE_CLIENT:
150218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
151204076Spjd		fd = spctx->sp_fd[0];
152204076Spjd		break;
153204076Spjd	default:
154218138Spjd		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
155204076Spjd	}
156204076Spjd
157212036Spjd	/* Someone is just trying to decide about side. */
158212036Spjd	if (data == NULL)
159212036Spjd		return (0);
160212036Spjd
161218194Spjd	return (proto_common_recv(fd, data, size, fdp));
162204076Spjd}
163204076Spjd
164204076Spjdstatic int
165204076Spjdsp_descriptor(const void *ctx)
166204076Spjd{
167204076Spjd	const struct sp_ctx *spctx = ctx;
168204076Spjd
169218138Spjd	PJDLOG_ASSERT(spctx != NULL);
170218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
171218138Spjd	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
172204076Spjd	    spctx->sp_side == SP_SIDE_SERVER);
173204076Spjd
174204076Spjd	switch (spctx->sp_side) {
175204076Spjd	case SP_SIDE_CLIENT:
176218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
177204076Spjd		return (spctx->sp_fd[0]);
178204076Spjd	case SP_SIDE_SERVER:
179218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
180204076Spjd		return (spctx->sp_fd[1]);
181204076Spjd	}
182204076Spjd
183218138Spjd	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
184204076Spjd}
185204076Spjd
186204076Spjdstatic void
187204076Spjdsp_close(void *ctx)
188204076Spjd{
189204076Spjd	struct sp_ctx *spctx = ctx;
190204076Spjd
191218138Spjd	PJDLOG_ASSERT(spctx != NULL);
192218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
193204076Spjd
194204076Spjd	switch (spctx->sp_side) {
195204076Spjd	case SP_SIDE_UNDEF:
196218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
197204076Spjd		close(spctx->sp_fd[0]);
198218138Spjd		spctx->sp_fd[0] = -1;
199218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
200204076Spjd		close(spctx->sp_fd[1]);
201218138Spjd		spctx->sp_fd[1] = -1;
202204076Spjd		break;
203204076Spjd	case SP_SIDE_CLIENT:
204218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
205204076Spjd		close(spctx->sp_fd[0]);
206218138Spjd		spctx->sp_fd[0] = -1;
207218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
208204076Spjd		break;
209204076Spjd	case SP_SIDE_SERVER:
210218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
211204076Spjd		close(spctx->sp_fd[1]);
212218138Spjd		spctx->sp_fd[1] = -1;
213218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
214204076Spjd		break;
215204076Spjd	default:
216218138Spjd		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
217204076Spjd	}
218204076Spjd
219204076Spjd	spctx->sp_magic = 0;
220204076Spjd	free(spctx);
221204076Spjd}
222204076Spjd
223219873Spjdstatic struct proto sp_proto = {
224219873Spjd	.prt_name = "socketpair",
225219873Spjd	.prt_client = sp_client,
226219873Spjd	.prt_send = sp_send,
227219873Spjd	.prt_recv = sp_recv,
228219873Spjd	.prt_descriptor = sp_descriptor,
229219873Spjd	.prt_close = sp_close
230204076Spjd};
231204076Spjd
232204076Spjdstatic __constructor void
233204076Spjdsp_ctor(void)
234204076Spjd{
235204076Spjd
236210869Spjd	proto_register(&sp_proto, false);
237204076Spjd}
238