proto_socketpair.c revision 212036
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 212036 2010-08-30 23:16:45Z pjd $");
32204076Spjd
33204076Spjd#include <sys/types.h>
34204076Spjd#include <sys/socket.h>
35204076Spjd
36204076Spjd#include <assert.h>
37204076Spjd#include <errno.h>
38204076Spjd#include <stdbool.h>
39204076Spjd#include <stdint.h>
40204076Spjd#include <stdio.h>
41204076Spjd#include <string.h>
42204076Spjd#include <unistd.h>
43204076Spjd
44204076Spjd#include "hast.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
60204076Spjdsp_client(const char *addr, void **ctxp)
61204076Spjd{
62204076Spjd	struct sp_ctx *spctx;
63204076Spjd	int ret;
64204076Spjd
65204076Spjd	if (strcmp(addr, "socketpair://") != 0)
66204076Spjd		return (-1);
67204076Spjd
68204076Spjd	spctx = malloc(sizeof(*spctx));
69204076Spjd	if (spctx == NULL)
70204076Spjd		return (errno);
71204076Spjd
72204076Spjd	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
73204076Spjd		ret = errno;
74204076Spjd		free(spctx);
75204076Spjd		return (ret);
76204076Spjd	}
77204076Spjd
78204076Spjd	spctx->sp_side = SP_SIDE_UNDEF;
79204076Spjd	spctx->sp_magic = SP_CTX_MAGIC;
80204076Spjd	*ctxp = spctx;
81204076Spjd
82204076Spjd	return (0);
83204076Spjd}
84204076Spjd
85204076Spjdstatic int
86204076Spjdsp_connect(void *ctx __unused)
87204076Spjd{
88204076Spjd
89204076Spjd	assert(!"proto_connect() not supported on socketpairs");
90204076Spjd	abort();
91204076Spjd}
92204076Spjd
93204076Spjdstatic int
94204177Spjdsp_server(const char *addr, void **ctxp __unused)
95204076Spjd{
96204076Spjd
97204177Spjd	if (strcmp(addr, "socketpair://") != 0)
98204177Spjd		return (-1);
99204177Spjd
100204076Spjd	assert(!"proto_server() not supported on socketpairs");
101204076Spjd	abort();
102204076Spjd}
103204076Spjd
104204076Spjdstatic int
105204076Spjdsp_accept(void *ctx __unused, void **newctxp __unused)
106204076Spjd{
107204076Spjd
108204076Spjd	assert(!"proto_server() not supported on socketpairs");
109204076Spjd	abort();
110204076Spjd}
111204076Spjd
112204076Spjdstatic int
113204076Spjdsp_send(void *ctx, const unsigned char *data, size_t size)
114204076Spjd{
115204076Spjd	struct sp_ctx *spctx = ctx;
116204076Spjd	int fd;
117204076Spjd
118204076Spjd	assert(spctx != NULL);
119204076Spjd	assert(spctx->sp_magic == SP_CTX_MAGIC);
120204076Spjd
121204076Spjd	switch (spctx->sp_side) {
122204076Spjd	case SP_SIDE_UNDEF:
123204076Spjd		/*
124204076Spjd		 * If the first operation done by the caller is proto_send(),
125204076Spjd		 * we assume this the client.
126204076Spjd		 */
127204076Spjd		/* FALLTHROUGH */
128204076Spjd		spctx->sp_side = SP_SIDE_CLIENT;
129204076Spjd		/* Close other end. */
130204076Spjd		close(spctx->sp_fd[1]);
131204076Spjd	case SP_SIDE_CLIENT:
132204076Spjd		assert(spctx->sp_fd[0] >= 0);
133204076Spjd		fd = spctx->sp_fd[0];
134204076Spjd		break;
135204076Spjd	case SP_SIDE_SERVER:
136204076Spjd		assert(spctx->sp_fd[1] >= 0);
137204076Spjd		fd = spctx->sp_fd[1];
138204076Spjd		break;
139204076Spjd	default:
140204076Spjd		abort();
141204076Spjd	}
142204076Spjd
143212036Spjd	/* Someone is just trying to decide about side. */
144212036Spjd	if (data == NULL)
145212036Spjd		return (0);
146212036Spjd
147204076Spjd	return (proto_common_send(fd, data, size));
148204076Spjd}
149204076Spjd
150204076Spjdstatic int
151204076Spjdsp_recv(void *ctx, unsigned char *data, size_t size)
152204076Spjd{
153204076Spjd	struct sp_ctx *spctx = ctx;
154204076Spjd	int fd;
155204076Spjd
156204076Spjd	assert(spctx != NULL);
157204076Spjd	assert(spctx->sp_magic == SP_CTX_MAGIC);
158204076Spjd
159204076Spjd	switch (spctx->sp_side) {
160204076Spjd	case SP_SIDE_UNDEF:
161204076Spjd		/*
162204076Spjd		 * If the first operation done by the caller is proto_recv(),
163204076Spjd		 * we assume this the server.
164204076Spjd		 */
165204076Spjd		/* FALLTHROUGH */
166204076Spjd		spctx->sp_side = SP_SIDE_SERVER;
167204076Spjd		/* Close other end. */
168204076Spjd		close(spctx->sp_fd[0]);
169204076Spjd	case SP_SIDE_SERVER:
170204076Spjd		assert(spctx->sp_fd[1] >= 0);
171204076Spjd		fd = spctx->sp_fd[1];
172204076Spjd		break;
173204076Spjd	case SP_SIDE_CLIENT:
174204076Spjd		assert(spctx->sp_fd[0] >= 0);
175204076Spjd		fd = spctx->sp_fd[0];
176204076Spjd		break;
177204076Spjd	default:
178204076Spjd		abort();
179204076Spjd	}
180204076Spjd
181212036Spjd	/* Someone is just trying to decide about side. */
182212036Spjd	if (data == NULL)
183212036Spjd		return (0);
184212036Spjd
185204076Spjd	return (proto_common_recv(fd, data, size));
186204076Spjd}
187204076Spjd
188204076Spjdstatic int
189204076Spjdsp_descriptor(const void *ctx)
190204076Spjd{
191204076Spjd	const struct sp_ctx *spctx = ctx;
192204076Spjd
193204076Spjd	assert(spctx != NULL);
194204076Spjd	assert(spctx->sp_magic == SP_CTX_MAGIC);
195204076Spjd	assert(spctx->sp_side == SP_SIDE_CLIENT ||
196204076Spjd	    spctx->sp_side == SP_SIDE_SERVER);
197204076Spjd
198204076Spjd	switch (spctx->sp_side) {
199204076Spjd	case SP_SIDE_CLIENT:
200204076Spjd		assert(spctx->sp_fd[0] >= 0);
201204076Spjd		return (spctx->sp_fd[0]);
202204076Spjd	case SP_SIDE_SERVER:
203204076Spjd		assert(spctx->sp_fd[1] >= 0);
204204076Spjd		return (spctx->sp_fd[1]);
205204076Spjd	}
206204076Spjd
207204076Spjd	abort();
208204076Spjd}
209204076Spjd
210204076Spjdstatic bool
211204076Spjdsp_address_match(const void *ctx __unused, const char *addr __unused)
212204076Spjd{
213204076Spjd
214204076Spjd	assert(!"proto_address_match() not supported on socketpairs");
215204076Spjd	abort();
216204076Spjd}
217204076Spjd
218204076Spjdstatic void
219204076Spjdsp_local_address(const void *ctx __unused, char *addr __unused,
220204076Spjd    size_t size __unused)
221204076Spjd{
222204076Spjd
223204076Spjd	assert(!"proto_local_address() not supported on socketpairs");
224204076Spjd	abort();
225204076Spjd}
226204076Spjd
227204076Spjdstatic void
228204076Spjdsp_remote_address(const void *ctx __unused, char *addr __unused,
229204076Spjd    size_t size __unused)
230204076Spjd{
231204076Spjd
232204076Spjd	assert(!"proto_remote_address() not supported on socketpairs");
233204076Spjd	abort();
234204076Spjd}
235204076Spjd
236204076Spjdstatic void
237204076Spjdsp_close(void *ctx)
238204076Spjd{
239204076Spjd	struct sp_ctx *spctx = ctx;
240204076Spjd
241204076Spjd	assert(spctx != NULL);
242204076Spjd	assert(spctx->sp_magic == SP_CTX_MAGIC);
243204076Spjd
244204076Spjd	switch (spctx->sp_side) {
245204076Spjd	case SP_SIDE_UNDEF:
246204076Spjd		close(spctx->sp_fd[0]);
247204076Spjd		close(spctx->sp_fd[1]);
248204076Spjd		break;
249204076Spjd	case SP_SIDE_CLIENT:
250204076Spjd		close(spctx->sp_fd[0]);
251204076Spjd		break;
252204076Spjd	case SP_SIDE_SERVER:
253204076Spjd		close(spctx->sp_fd[1]);
254204076Spjd		break;
255204076Spjd	default:
256204076Spjd		abort();
257204076Spjd	}
258204076Spjd
259204076Spjd	spctx->sp_magic = 0;
260204076Spjd	free(spctx);
261204076Spjd}
262204076Spjd
263204076Spjdstatic struct hast_proto sp_proto = {
264204076Spjd	.hp_name = "socketpair",
265204076Spjd	.hp_client = sp_client,
266204076Spjd	.hp_connect = sp_connect,
267204076Spjd	.hp_server = sp_server,
268204076Spjd	.hp_accept = sp_accept,
269204076Spjd	.hp_send = sp_send,
270204076Spjd	.hp_recv = sp_recv,
271204076Spjd	.hp_descriptor = sp_descriptor,
272204076Spjd	.hp_address_match = sp_address_match,
273204076Spjd	.hp_local_address = sp_local_address,
274204076Spjd	.hp_remote_address = sp_remote_address,
275204076Spjd	.hp_close = sp_close
276204076Spjd};
277204076Spjd
278204076Spjdstatic __constructor void
279204076Spjdsp_ctor(void)
280204076Spjd{
281204076Spjd
282210869Spjd	proto_register(&sp_proto, false);
283204076Spjd}
284