proto_socketpair.c revision 219818
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: head/sbin/hastd/proto_socketpair.c 219818 2011-03-21 08:54:59Z pjd $");
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
43204076Spjd#include "hast.h"
44218138Spjd#include "pjdlog.h"
45204076Spjd#include "proto_impl.h"
46204076Spjd
47204076Spjd#define	SP_CTX_MAGIC	0x50c3741
48204076Spjdstruct sp_ctx {
49204076Spjd	int			sp_magic;
50204076Spjd	int			sp_fd[2];
51204076Spjd	int			sp_side;
52204076Spjd#define	SP_SIDE_UNDEF		0
53204076Spjd#define	SP_SIDE_CLIENT		1
54204076Spjd#define	SP_SIDE_SERVER		2
55204076Spjd};
56204076Spjd
57204076Spjdstatic void sp_close(void *ctx);
58204076Spjd
59204076Spjdstatic int
60219818Spjdsp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
61204076Spjd{
62204076Spjd	struct sp_ctx *spctx;
63204076Spjd	int ret;
64204076Spjd
65219818Spjd	if (strcmp(dstaddr, "socketpair://") != 0)
66204076Spjd		return (-1);
67204076Spjd
68219818Spjd	PJDLOG_ASSERT(srcaddr == NULL);
69219818Spjd
70204076Spjd	spctx = malloc(sizeof(*spctx));
71204076Spjd	if (spctx == NULL)
72204076Spjd		return (errno);
73204076Spjd
74204076Spjd	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
75204076Spjd		ret = errno;
76204076Spjd		free(spctx);
77204076Spjd		return (ret);
78204076Spjd	}
79204076Spjd
80204076Spjd	spctx->sp_side = SP_SIDE_UNDEF;
81204076Spjd	spctx->sp_magic = SP_CTX_MAGIC;
82204076Spjd	*ctxp = spctx;
83204076Spjd
84204076Spjd	return (0);
85204076Spjd}
86204076Spjd
87204076Spjdstatic int
88218194Spjdsp_send(void *ctx, const unsigned char *data, size_t size, int fd)
89204076Spjd{
90204076Spjd	struct sp_ctx *spctx = ctx;
91218194Spjd	int sock;
92204076Spjd
93218138Spjd	PJDLOG_ASSERT(spctx != NULL);
94218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
95204076Spjd
96204076Spjd	switch (spctx->sp_side) {
97204076Spjd	case SP_SIDE_UNDEF:
98204076Spjd		/*
99204076Spjd		 * If the first operation done by the caller is proto_send(),
100218194Spjd		 * we assume this is the client.
101204076Spjd		 */
102204076Spjd		/* FALLTHROUGH */
103204076Spjd		spctx->sp_side = SP_SIDE_CLIENT;
104204076Spjd		/* Close other end. */
105204076Spjd		close(spctx->sp_fd[1]);
106218138Spjd		spctx->sp_fd[1] = -1;
107204076Spjd	case SP_SIDE_CLIENT:
108218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
109218194Spjd		sock = spctx->sp_fd[0];
110204076Spjd		break;
111204076Spjd	case SP_SIDE_SERVER:
112218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
113218194Spjd		sock = spctx->sp_fd[1];
114204076Spjd		break;
115204076Spjd	default:
116218138Spjd		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
117204076Spjd	}
118204076Spjd
119212036Spjd	/* Someone is just trying to decide about side. */
120212036Spjd	if (data == NULL)
121212036Spjd		return (0);
122212036Spjd
123218194Spjd	return (proto_common_send(sock, data, size, fd));
124204076Spjd}
125204076Spjd
126204076Spjdstatic int
127218194Spjdsp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
128204076Spjd{
129204076Spjd	struct sp_ctx *spctx = ctx;
130204076Spjd	int fd;
131204076Spjd
132218138Spjd	PJDLOG_ASSERT(spctx != NULL);
133218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
134204076Spjd
135204076Spjd	switch (spctx->sp_side) {
136204076Spjd	case SP_SIDE_UNDEF:
137204076Spjd		/*
138204076Spjd		 * If the first operation done by the caller is proto_recv(),
139218194Spjd		 * we assume this is the server.
140204076Spjd		 */
141204076Spjd		/* FALLTHROUGH */
142204076Spjd		spctx->sp_side = SP_SIDE_SERVER;
143204076Spjd		/* Close other end. */
144204076Spjd		close(spctx->sp_fd[0]);
145218138Spjd		spctx->sp_fd[0] = -1;
146204076Spjd	case SP_SIDE_SERVER:
147218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
148204076Spjd		fd = spctx->sp_fd[1];
149204076Spjd		break;
150204076Spjd	case SP_SIDE_CLIENT:
151218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
152204076Spjd		fd = spctx->sp_fd[0];
153204076Spjd		break;
154204076Spjd	default:
155218138Spjd		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
156204076Spjd	}
157204076Spjd
158212036Spjd	/* Someone is just trying to decide about side. */
159212036Spjd	if (data == NULL)
160212036Spjd		return (0);
161212036Spjd
162218194Spjd	return (proto_common_recv(fd, data, size, fdp));
163204076Spjd}
164204076Spjd
165204076Spjdstatic int
166204076Spjdsp_descriptor(const void *ctx)
167204076Spjd{
168204076Spjd	const struct sp_ctx *spctx = ctx;
169204076Spjd
170218138Spjd	PJDLOG_ASSERT(spctx != NULL);
171218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
172218138Spjd	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
173204076Spjd	    spctx->sp_side == SP_SIDE_SERVER);
174204076Spjd
175204076Spjd	switch (spctx->sp_side) {
176204076Spjd	case SP_SIDE_CLIENT:
177218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
178204076Spjd		return (spctx->sp_fd[0]);
179204076Spjd	case SP_SIDE_SERVER:
180218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
181204076Spjd		return (spctx->sp_fd[1]);
182204076Spjd	}
183204076Spjd
184218138Spjd	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
185204076Spjd}
186204076Spjd
187204076Spjdstatic void
188204076Spjdsp_close(void *ctx)
189204076Spjd{
190204076Spjd	struct sp_ctx *spctx = ctx;
191204076Spjd
192218138Spjd	PJDLOG_ASSERT(spctx != NULL);
193218138Spjd	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
194204076Spjd
195204076Spjd	switch (spctx->sp_side) {
196204076Spjd	case SP_SIDE_UNDEF:
197218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
198204076Spjd		close(spctx->sp_fd[0]);
199218138Spjd		spctx->sp_fd[0] = -1;
200218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
201204076Spjd		close(spctx->sp_fd[1]);
202218138Spjd		spctx->sp_fd[1] = -1;
203204076Spjd		break;
204204076Spjd	case SP_SIDE_CLIENT:
205218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
206204076Spjd		close(spctx->sp_fd[0]);
207218138Spjd		spctx->sp_fd[0] = -1;
208218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
209204076Spjd		break;
210204076Spjd	case SP_SIDE_SERVER:
211218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
212204076Spjd		close(spctx->sp_fd[1]);
213218138Spjd		spctx->sp_fd[1] = -1;
214218138Spjd		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
215204076Spjd		break;
216204076Spjd	default:
217218138Spjd		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
218204076Spjd	}
219204076Spjd
220204076Spjd	spctx->sp_magic = 0;
221204076Spjd	free(spctx);
222204076Spjd}
223204076Spjd
224204076Spjdstatic struct hast_proto sp_proto = {
225204076Spjd	.hp_name = "socketpair",
226204076Spjd	.hp_client = sp_client,
227204076Spjd	.hp_send = sp_send,
228204076Spjd	.hp_recv = sp_recv,
229204076Spjd	.hp_descriptor = sp_descriptor,
230204076Spjd	.hp_close = sp_close
231204076Spjd};
232204076Spjd
233204076Spjdstatic __constructor void
234204076Spjdsp_ctor(void)
235204076Spjd{
236204076Spjd
237210869Spjd	proto_register(&sp_proto, false);
238204076Spjd}
239