proto_socketpair.c revision 212036
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 212036 2010-08-30 23:16:45Z 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	/* Someone is just trying to decide about side. */
144	if (data == NULL)
145		return (0);
146
147	return (proto_common_send(fd, data, size));
148}
149
150static int
151sp_recv(void *ctx, unsigned char *data, size_t size)
152{
153	struct sp_ctx *spctx = ctx;
154	int fd;
155
156	assert(spctx != NULL);
157	assert(spctx->sp_magic == SP_CTX_MAGIC);
158
159	switch (spctx->sp_side) {
160	case SP_SIDE_UNDEF:
161		/*
162		 * If the first operation done by the caller is proto_recv(),
163		 * we assume this the server.
164		 */
165		/* FALLTHROUGH */
166		spctx->sp_side = SP_SIDE_SERVER;
167		/* Close other end. */
168		close(spctx->sp_fd[0]);
169	case SP_SIDE_SERVER:
170		assert(spctx->sp_fd[1] >= 0);
171		fd = spctx->sp_fd[1];
172		break;
173	case SP_SIDE_CLIENT:
174		assert(spctx->sp_fd[0] >= 0);
175		fd = spctx->sp_fd[0];
176		break;
177	default:
178		abort();
179	}
180
181	/* Someone is just trying to decide about side. */
182	if (data == NULL)
183		return (0);
184
185	return (proto_common_recv(fd, data, size));
186}
187
188static int
189sp_descriptor(const void *ctx)
190{
191	const struct sp_ctx *spctx = ctx;
192
193	assert(spctx != NULL);
194	assert(spctx->sp_magic == SP_CTX_MAGIC);
195	assert(spctx->sp_side == SP_SIDE_CLIENT ||
196	    spctx->sp_side == SP_SIDE_SERVER);
197
198	switch (spctx->sp_side) {
199	case SP_SIDE_CLIENT:
200		assert(spctx->sp_fd[0] >= 0);
201		return (spctx->sp_fd[0]);
202	case SP_SIDE_SERVER:
203		assert(spctx->sp_fd[1] >= 0);
204		return (spctx->sp_fd[1]);
205	}
206
207	abort();
208}
209
210static bool
211sp_address_match(const void *ctx __unused, const char *addr __unused)
212{
213
214	assert(!"proto_address_match() not supported on socketpairs");
215	abort();
216}
217
218static void
219sp_local_address(const void *ctx __unused, char *addr __unused,
220    size_t size __unused)
221{
222
223	assert(!"proto_local_address() not supported on socketpairs");
224	abort();
225}
226
227static void
228sp_remote_address(const void *ctx __unused, char *addr __unused,
229    size_t size __unused)
230{
231
232	assert(!"proto_remote_address() not supported on socketpairs");
233	abort();
234}
235
236static void
237sp_close(void *ctx)
238{
239	struct sp_ctx *spctx = ctx;
240
241	assert(spctx != NULL);
242	assert(spctx->sp_magic == SP_CTX_MAGIC);
243
244	switch (spctx->sp_side) {
245	case SP_SIDE_UNDEF:
246		close(spctx->sp_fd[0]);
247		close(spctx->sp_fd[1]);
248		break;
249	case SP_SIDE_CLIENT:
250		close(spctx->sp_fd[0]);
251		break;
252	case SP_SIDE_SERVER:
253		close(spctx->sp_fd[1]);
254		break;
255	default:
256		abort();
257	}
258
259	spctx->sp_magic = 0;
260	free(spctx);
261}
262
263static struct hast_proto sp_proto = {
264	.hp_name = "socketpair",
265	.hp_client = sp_client,
266	.hp_connect = sp_connect,
267	.hp_server = sp_server,
268	.hp_accept = sp_accept,
269	.hp_send = sp_send,
270	.hp_recv = sp_recv,
271	.hp_descriptor = sp_descriptor,
272	.hp_address_match = sp_address_match,
273	.hp_local_address = sp_local_address,
274	.hp_remote_address = sp_remote_address,
275	.hp_close = sp_close
276};
277
278static __constructor void
279sp_ctor(void)
280{
281
282	proto_register(&sp_proto, false);
283}
284