proto_socketpair.c revision 210869
1/*-
2 * Copyright (c) 2009-2010 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sbin/hastd/proto_socketpair.c 210869 2010-08-05 17:56:41Z pjd $");
32
33#include <sys/types.h>
34#include <sys/socket.h>
35
36#include <assert.h>
37#include <errno.h>
38#include <stdbool.h>
39#include <stdint.h>
40#include <stdio.h>
41#include <string.h>
42#include <unistd.h>
43
44#include "hast.h"
45#include "proto_impl.h"
46
47#define	SP_CTX_MAGIC	0x50c3741
48struct sp_ctx {
49	int			sp_magic;
50	int			sp_fd[2];
51	int			sp_side;
52#define	SP_SIDE_UNDEF		0
53#define	SP_SIDE_CLIENT		1
54#define	SP_SIDE_SERVER		2
55};
56
57static void sp_close(void *ctx);
58
59static int
60sp_client(const char *addr, void **ctxp)
61{
62	struct sp_ctx *spctx;
63	int ret;
64
65	if (strcmp(addr, "socketpair://") != 0)
66		return (-1);
67
68	spctx = malloc(sizeof(*spctx));
69	if (spctx == NULL)
70		return (errno);
71
72	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
73		ret = errno;
74		free(spctx);
75		return (ret);
76	}
77
78	spctx->sp_side = SP_SIDE_UNDEF;
79	spctx->sp_magic = SP_CTX_MAGIC;
80	*ctxp = spctx;
81
82	return (0);
83}
84
85static int
86sp_connect(void *ctx __unused)
87{
88
89	assert(!"proto_connect() not supported on socketpairs");
90	abort();
91}
92
93static int
94sp_server(const char *addr, void **ctxp __unused)
95{
96
97	if (strcmp(addr, "socketpair://") != 0)
98		return (-1);
99
100	assert(!"proto_server() not supported on socketpairs");
101	abort();
102}
103
104static int
105sp_accept(void *ctx __unused, void **newctxp __unused)
106{
107
108	assert(!"proto_server() not supported on socketpairs");
109	abort();
110}
111
112static int
113sp_send(void *ctx, const unsigned char *data, size_t size)
114{
115	struct sp_ctx *spctx = ctx;
116	int fd;
117
118	assert(spctx != NULL);
119	assert(spctx->sp_magic == SP_CTX_MAGIC);
120
121	switch (spctx->sp_side) {
122	case SP_SIDE_UNDEF:
123		/*
124		 * If the first operation done by the caller is proto_send(),
125		 * we assume this the client.
126		 */
127		/* FALLTHROUGH */
128		spctx->sp_side = SP_SIDE_CLIENT;
129		/* Close other end. */
130		close(spctx->sp_fd[1]);
131	case SP_SIDE_CLIENT:
132		assert(spctx->sp_fd[0] >= 0);
133		fd = spctx->sp_fd[0];
134		break;
135	case SP_SIDE_SERVER:
136		assert(spctx->sp_fd[1] >= 0);
137		fd = spctx->sp_fd[1];
138		break;
139	default:
140		abort();
141	}
142
143	return (proto_common_send(fd, data, size));
144}
145
146static int
147sp_recv(void *ctx, unsigned char *data, size_t size)
148{
149	struct sp_ctx *spctx = ctx;
150	int fd;
151
152	assert(spctx != NULL);
153	assert(spctx->sp_magic == SP_CTX_MAGIC);
154
155	switch (spctx->sp_side) {
156	case SP_SIDE_UNDEF:
157		/*
158		 * If the first operation done by the caller is proto_recv(),
159		 * we assume this the server.
160		 */
161		/* FALLTHROUGH */
162		spctx->sp_side = SP_SIDE_SERVER;
163		/* Close other end. */
164		close(spctx->sp_fd[0]);
165	case SP_SIDE_SERVER:
166		assert(spctx->sp_fd[1] >= 0);
167		fd = spctx->sp_fd[1];
168		break;
169	case SP_SIDE_CLIENT:
170		assert(spctx->sp_fd[0] >= 0);
171		fd = spctx->sp_fd[0];
172		break;
173	default:
174		abort();
175	}
176
177	return (proto_common_recv(fd, data, size));
178}
179
180static int
181sp_descriptor(const void *ctx)
182{
183	const struct sp_ctx *spctx = ctx;
184
185	assert(spctx != NULL);
186	assert(spctx->sp_magic == SP_CTX_MAGIC);
187	assert(spctx->sp_side == SP_SIDE_CLIENT ||
188	    spctx->sp_side == SP_SIDE_SERVER);
189
190	switch (spctx->sp_side) {
191	case SP_SIDE_CLIENT:
192		assert(spctx->sp_fd[0] >= 0);
193		return (spctx->sp_fd[0]);
194	case SP_SIDE_SERVER:
195		assert(spctx->sp_fd[1] >= 0);
196		return (spctx->sp_fd[1]);
197	}
198
199	abort();
200}
201
202static bool
203sp_address_match(const void *ctx __unused, const char *addr __unused)
204{
205
206	assert(!"proto_address_match() not supported on socketpairs");
207	abort();
208}
209
210static void
211sp_local_address(const void *ctx __unused, char *addr __unused,
212    size_t size __unused)
213{
214
215	assert(!"proto_local_address() not supported on socketpairs");
216	abort();
217}
218
219static void
220sp_remote_address(const void *ctx __unused, char *addr __unused,
221    size_t size __unused)
222{
223
224	assert(!"proto_remote_address() not supported on socketpairs");
225	abort();
226}
227
228static void
229sp_close(void *ctx)
230{
231	struct sp_ctx *spctx = ctx;
232
233	assert(spctx != NULL);
234	assert(spctx->sp_magic == SP_CTX_MAGIC);
235
236	switch (spctx->sp_side) {
237	case SP_SIDE_UNDEF:
238		close(spctx->sp_fd[0]);
239		close(spctx->sp_fd[1]);
240		break;
241	case SP_SIDE_CLIENT:
242		close(spctx->sp_fd[0]);
243		break;
244	case SP_SIDE_SERVER:
245		close(spctx->sp_fd[1]);
246		break;
247	default:
248		abort();
249	}
250
251	spctx->sp_magic = 0;
252	free(spctx);
253}
254
255static struct hast_proto sp_proto = {
256	.hp_name = "socketpair",
257	.hp_client = sp_client,
258	.hp_connect = sp_connect,
259	.hp_server = sp_server,
260	.hp_accept = sp_accept,
261	.hp_send = sp_send,
262	.hp_recv = sp_recv,
263	.hp_descriptor = sp_descriptor,
264	.hp_address_match = sp_address_match,
265	.hp_local_address = sp_local_address,
266	.hp_remote_address = sp_remote_address,
267	.hp_close = sp_close
268};
269
270static __constructor void
271sp_ctor(void)
272{
273
274	proto_register(&sp_proto, false);
275}
276