xref: /freebsd/sbin/hastd/proto_socketpair.c (revision 2668e76d6e764c5c361156ffa3d39eb02ce8e5d9)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2009-2010 The FreeBSD Foundation
5  *
6  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 
34 #include <errno.h>
35 #include <stdbool.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "pjdlog.h"
42 #include "proto_impl.h"
43 
44 #define	SP_CTX_MAGIC	0x50c3741
45 struct sp_ctx {
46 	int			sp_magic;
47 	int			sp_fd[2];
48 	int			sp_side;
49 #define	SP_SIDE_UNDEF		0
50 #define	SP_SIDE_CLIENT		1
51 #define	SP_SIDE_SERVER		2
52 };
53 
54 static void sp_close(void *ctx);
55 
56 static int
57 sp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
58 {
59 	struct sp_ctx *spctx;
60 	int ret;
61 
62 	if (strcmp(dstaddr, "socketpair://") != 0)
63 		return (-1);
64 
65 	PJDLOG_ASSERT(srcaddr == NULL);
66 
67 	spctx = malloc(sizeof(*spctx));
68 	if (spctx == NULL)
69 		return (errno);
70 
71 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
72 		ret = errno;
73 		free(spctx);
74 		return (ret);
75 	}
76 
77 	spctx->sp_side = SP_SIDE_UNDEF;
78 	spctx->sp_magic = SP_CTX_MAGIC;
79 	*ctxp = spctx;
80 
81 	return (0);
82 }
83 
84 static int
85 sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
86 {
87 	struct sp_ctx *spctx = ctx;
88 	int sock;
89 
90 	PJDLOG_ASSERT(spctx != NULL);
91 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
92 
93 	switch (spctx->sp_side) {
94 	case SP_SIDE_UNDEF:
95 		/*
96 		 * If the first operation done by the caller is proto_send(),
97 		 * we assume this is the client.
98 		 */
99 		/* FALLTHROUGH */
100 		spctx->sp_side = SP_SIDE_CLIENT;
101 		/* Close other end. */
102 		close(spctx->sp_fd[1]);
103 		spctx->sp_fd[1] = -1;
104 	case SP_SIDE_CLIENT:
105 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
106 		sock = spctx->sp_fd[0];
107 		break;
108 	case SP_SIDE_SERVER:
109 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
110 		sock = spctx->sp_fd[1];
111 		break;
112 	default:
113 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
114 	}
115 
116 	/* Someone is just trying to decide about side. */
117 	if (data == NULL)
118 		return (0);
119 
120 	return (proto_common_send(sock, data, size, fd));
121 }
122 
123 static int
124 sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
125 {
126 	struct sp_ctx *spctx = ctx;
127 	int fd;
128 
129 	PJDLOG_ASSERT(spctx != NULL);
130 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
131 
132 	switch (spctx->sp_side) {
133 	case SP_SIDE_UNDEF:
134 		/*
135 		 * If the first operation done by the caller is proto_recv(),
136 		 * we assume this is the server.
137 		 */
138 		/* FALLTHROUGH */
139 		spctx->sp_side = SP_SIDE_SERVER;
140 		/* Close other end. */
141 		close(spctx->sp_fd[0]);
142 		spctx->sp_fd[0] = -1;
143 	case SP_SIDE_SERVER:
144 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
145 		fd = spctx->sp_fd[1];
146 		break;
147 	case SP_SIDE_CLIENT:
148 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
149 		fd = spctx->sp_fd[0];
150 		break;
151 	default:
152 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
153 	}
154 
155 	/* Someone is just trying to decide about side. */
156 	if (data == NULL)
157 		return (0);
158 
159 	return (proto_common_recv(fd, data, size, fdp));
160 }
161 
162 static int
163 sp_descriptor(const void *ctx)
164 {
165 	const struct sp_ctx *spctx = ctx;
166 
167 	PJDLOG_ASSERT(spctx != NULL);
168 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
169 	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
170 	    spctx->sp_side == SP_SIDE_SERVER);
171 
172 	switch (spctx->sp_side) {
173 	case SP_SIDE_CLIENT:
174 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
175 		return (spctx->sp_fd[0]);
176 	case SP_SIDE_SERVER:
177 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
178 		return (spctx->sp_fd[1]);
179 	}
180 
181 	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
182 }
183 
184 static void
185 sp_close(void *ctx)
186 {
187 	struct sp_ctx *spctx = ctx;
188 
189 	PJDLOG_ASSERT(spctx != NULL);
190 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
191 
192 	switch (spctx->sp_side) {
193 	case SP_SIDE_UNDEF:
194 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
195 		close(spctx->sp_fd[0]);
196 		spctx->sp_fd[0] = -1;
197 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
198 		close(spctx->sp_fd[1]);
199 		spctx->sp_fd[1] = -1;
200 		break;
201 	case SP_SIDE_CLIENT:
202 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
203 		close(spctx->sp_fd[0]);
204 		spctx->sp_fd[0] = -1;
205 		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
206 		break;
207 	case SP_SIDE_SERVER:
208 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
209 		close(spctx->sp_fd[1]);
210 		spctx->sp_fd[1] = -1;
211 		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
212 		break;
213 	default:
214 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
215 	}
216 
217 	spctx->sp_magic = 0;
218 	free(spctx);
219 }
220 
221 static struct proto sp_proto = {
222 	.prt_name = "socketpair",
223 	.prt_client = sp_client,
224 	.prt_send = sp_send,
225 	.prt_recv = sp_recv,
226 	.prt_descriptor = sp_descriptor,
227 	.prt_close = sp_close
228 };
229 
230 static __constructor void
231 sp_ctor(void)
232 {
233 
234 	proto_register(&sp_proto, false);
235 }
236