xref: /freebsd/sbin/hastd/proto_socketpair.c (revision 0f2bd1e89db1a2f09268edea21e0ead329e092df)
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 	return (proto_common_send(fd, data, size));
144 }
145 
146 static int
147 sp_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 
180 static int
181 sp_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 
202 static bool
203 sp_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 
210 static void
211 sp_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 
219 static void
220 sp_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 
228 static void
229 sp_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 
255 static 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 
270 static __constructor void
271 sp_ctor(void)
272 {
273 
274 	proto_register(&sp_proto, false);
275 }
276