xref: /freebsd/sbin/hastd/proto_socketpair.c (revision 4ed925457ab06e83238a5db33e89ccc94b99a713)
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 __unused, void **ctxp __unused)
95 {
96 
97 	assert(!"proto_server() not supported on socketpairs");
98 	abort();
99 }
100 
101 static int
102 sp_accept(void *ctx __unused, void **newctxp __unused)
103 {
104 
105 	assert(!"proto_server() not supported on socketpairs");
106 	abort();
107 }
108 
109 static int
110 sp_send(void *ctx, const unsigned char *data, size_t size)
111 {
112 	struct sp_ctx *spctx = ctx;
113 	int fd;
114 
115 	assert(spctx != NULL);
116 	assert(spctx->sp_magic == SP_CTX_MAGIC);
117 
118 	switch (spctx->sp_side) {
119 	case SP_SIDE_UNDEF:
120 		/*
121 		 * If the first operation done by the caller is proto_send(),
122 		 * we assume this the client.
123 		 */
124 		/* FALLTHROUGH */
125 		spctx->sp_side = SP_SIDE_CLIENT;
126 		/* Close other end. */
127 		close(spctx->sp_fd[1]);
128 	case SP_SIDE_CLIENT:
129 		assert(spctx->sp_fd[0] >= 0);
130 		fd = spctx->sp_fd[0];
131 		break;
132 	case SP_SIDE_SERVER:
133 		assert(spctx->sp_fd[1] >= 0);
134 		fd = spctx->sp_fd[1];
135 		break;
136 	default:
137 		abort();
138 	}
139 
140 	return (proto_common_send(fd, data, size));
141 }
142 
143 static int
144 sp_recv(void *ctx, unsigned char *data, size_t size)
145 {
146 	struct sp_ctx *spctx = ctx;
147 	int fd;
148 
149 	assert(spctx != NULL);
150 	assert(spctx->sp_magic == SP_CTX_MAGIC);
151 
152 	switch (spctx->sp_side) {
153 	case SP_SIDE_UNDEF:
154 		/*
155 		 * If the first operation done by the caller is proto_recv(),
156 		 * we assume this the server.
157 		 */
158 		/* FALLTHROUGH */
159 		spctx->sp_side = SP_SIDE_SERVER;
160 		/* Close other end. */
161 		close(spctx->sp_fd[0]);
162 	case SP_SIDE_SERVER:
163 		assert(spctx->sp_fd[1] >= 0);
164 		fd = spctx->sp_fd[1];
165 		break;
166 	case SP_SIDE_CLIENT:
167 		assert(spctx->sp_fd[0] >= 0);
168 		fd = spctx->sp_fd[0];
169 		break;
170 	default:
171 		abort();
172 	}
173 
174 	return (proto_common_recv(fd, data, size));
175 }
176 
177 static int
178 sp_descriptor(const void *ctx)
179 {
180 	const struct sp_ctx *spctx = ctx;
181 
182 	assert(spctx != NULL);
183 	assert(spctx->sp_magic == SP_CTX_MAGIC);
184 	assert(spctx->sp_side == SP_SIDE_CLIENT ||
185 	    spctx->sp_side == SP_SIDE_SERVER);
186 
187 	switch (spctx->sp_side) {
188 	case SP_SIDE_CLIENT:
189 		assert(spctx->sp_fd[0] >= 0);
190 		return (spctx->sp_fd[0]);
191 	case SP_SIDE_SERVER:
192 		assert(spctx->sp_fd[1] >= 0);
193 		return (spctx->sp_fd[1]);
194 	}
195 
196 	abort();
197 }
198 
199 static bool
200 sp_address_match(const void *ctx __unused, const char *addr __unused)
201 {
202 
203 	assert(!"proto_address_match() not supported on socketpairs");
204 	abort();
205 }
206 
207 static void
208 sp_local_address(const void *ctx __unused, char *addr __unused,
209     size_t size __unused)
210 {
211 
212 	assert(!"proto_local_address() not supported on socketpairs");
213 	abort();
214 }
215 
216 static void
217 sp_remote_address(const void *ctx __unused, char *addr __unused,
218     size_t size __unused)
219 {
220 
221 	assert(!"proto_remote_address() not supported on socketpairs");
222 	abort();
223 }
224 
225 static void
226 sp_close(void *ctx)
227 {
228 	struct sp_ctx *spctx = ctx;
229 
230 	assert(spctx != NULL);
231 	assert(spctx->sp_magic == SP_CTX_MAGIC);
232 
233 	switch (spctx->sp_side) {
234 	case SP_SIDE_UNDEF:
235 		close(spctx->sp_fd[0]);
236 		close(spctx->sp_fd[1]);
237 		break;
238 	case SP_SIDE_CLIENT:
239 		close(spctx->sp_fd[0]);
240 		break;
241 	case SP_SIDE_SERVER:
242 		close(spctx->sp_fd[1]);
243 		break;
244 	default:
245 		abort();
246 	}
247 
248 	spctx->sp_magic = 0;
249 	free(spctx);
250 }
251 
252 static struct hast_proto sp_proto = {
253 	.hp_name = "socketpair",
254 	.hp_client = sp_client,
255 	.hp_connect = sp_connect,
256 	.hp_server = sp_server,
257 	.hp_accept = sp_accept,
258 	.hp_send = sp_send,
259 	.hp_recv = sp_recv,
260 	.hp_descriptor = sp_descriptor,
261 	.hp_address_match = sp_address_match,
262 	.hp_local_address = sp_local_address,
263 	.hp_remote_address = sp_remote_address,
264 	.hp_close = sp_close
265 };
266 
267 static __constructor void
268 sp_ctor(void)
269 {
270 
271 	proto_register(&sp_proto);
272 }
273