2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2009-2010 The FreeBSD Foundation
7 * This software was developed by Pawel Jakub Dawidek under sponsorship from
8 * the FreeBSD Foundation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include <sys/types.h>
36 #include <sys/socket.h>
46 #include "proto_impl.h"
48 #define SP_CTX_MAGIC 0x50c3741
53 #define SP_SIDE_UNDEF 0
54 #define SP_SIDE_CLIENT 1
55 #define SP_SIDE_SERVER 2
58 static void sp_close(void *ctx);
61 sp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
66 if (strcmp(dstaddr, "socketpair://") != 0)
69 PJDLOG_ASSERT(srcaddr == NULL);
71 spctx = malloc(sizeof(*spctx));
75 if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
81 spctx->sp_side = SP_SIDE_UNDEF;
82 spctx->sp_magic = SP_CTX_MAGIC;
89 sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
91 struct sp_ctx *spctx = ctx;
94 PJDLOG_ASSERT(spctx != NULL);
95 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
97 switch (spctx->sp_side) {
100 * If the first operation done by the caller is proto_send(),
101 * we assume this is the client.
104 spctx->sp_side = SP_SIDE_CLIENT;
105 /* Close other end. */
106 close(spctx->sp_fd[1]);
107 spctx->sp_fd[1] = -1;
109 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
110 sock = spctx->sp_fd[0];
113 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
114 sock = spctx->sp_fd[1];
117 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
120 /* Someone is just trying to decide about side. */
124 return (proto_common_send(sock, data, size, fd));
128 sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
130 struct sp_ctx *spctx = ctx;
133 PJDLOG_ASSERT(spctx != NULL);
134 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
136 switch (spctx->sp_side) {
139 * If the first operation done by the caller is proto_recv(),
140 * we assume this is the server.
143 spctx->sp_side = SP_SIDE_SERVER;
144 /* Close other end. */
145 close(spctx->sp_fd[0]);
146 spctx->sp_fd[0] = -1;
148 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
149 fd = spctx->sp_fd[1];
152 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
153 fd = spctx->sp_fd[0];
156 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
159 /* Someone is just trying to decide about side. */
163 return (proto_common_recv(fd, data, size, fdp));
167 sp_descriptor(const void *ctx)
169 const struct sp_ctx *spctx = ctx;
171 PJDLOG_ASSERT(spctx != NULL);
172 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
173 PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
174 spctx->sp_side == SP_SIDE_SERVER);
176 switch (spctx->sp_side) {
178 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
179 return (spctx->sp_fd[0]);
181 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
182 return (spctx->sp_fd[1]);
185 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
191 struct sp_ctx *spctx = ctx;
193 PJDLOG_ASSERT(spctx != NULL);
194 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
196 switch (spctx->sp_side) {
198 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
199 close(spctx->sp_fd[0]);
200 spctx->sp_fd[0] = -1;
201 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
202 close(spctx->sp_fd[1]);
203 spctx->sp_fd[1] = -1;
206 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
207 close(spctx->sp_fd[0]);
208 spctx->sp_fd[0] = -1;
209 PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
212 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
213 close(spctx->sp_fd[1]);
214 spctx->sp_fd[1] = -1;
215 PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
218 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
225 static struct proto sp_proto = {
226 .prt_name = "socketpair",
227 .prt_client = sp_client,
230 .prt_descriptor = sp_descriptor,
231 .prt_close = sp_close
234 static __constructor void
238 proto_register(&sp_proto, false);