xref: /freebsd/sbin/hastd/proto_socketpair.c (revision a3cf0ef5a295c885c895fabfd56470c0d1db322d)
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$");
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
48 struct 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 
57 static void sp_close(void *ctx);
58 
59 static int
60 sp_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 
85 static int
86 sp_connect(void *ctx __unused)
87 {
88 
89 	assert(!"proto_connect() not supported on socketpairs");
90 	abort();
91 }
92 
93 static int
94 sp_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 
104 static int
105 sp_accept(void *ctx __unused, void **newctxp __unused)
106 {
107 
108 	assert(!"proto_server() not supported on socketpairs");
109 	abort();
110 }
111 
112 static int
113 sp_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 
150 static int
151 sp_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 
188 static int
189 sp_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 
210 static bool
211 sp_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 
218 static void
219 sp_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 
227 static void
228 sp_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 
236 static void
237 sp_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 
263 static 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 
278 static __constructor void
279 sp_ctor(void)
280 {
281 
282 	proto_register(&sp_proto, false);
283 }
284