2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <sys/socket.h>
44 #include "proto_impl.h"
46 #define SP_CTX_MAGIC 0x50c3741
51 #define SP_SIDE_UNDEF 0
52 #define SP_SIDE_CLIENT 1
53 #define SP_SIDE_SERVER 2
56 static void sp_close(void *ctx);
59 sp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
64 if (strcmp(dstaddr, "socketpair://") != 0)
67 PJDLOG_ASSERT(srcaddr == NULL);
69 spctx = malloc(sizeof(*spctx));
73 if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
79 spctx->sp_side = SP_SIDE_UNDEF;
80 spctx->sp_magic = SP_CTX_MAGIC;
87 sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
89 struct sp_ctx *spctx = ctx;
92 PJDLOG_ASSERT(spctx != NULL);
93 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
95 switch (spctx->sp_side) {
98 * If the first operation done by the caller is proto_send(),
99 * we assume this is the client.
102 spctx->sp_side = SP_SIDE_CLIENT;
103 /* Close other end. */
104 close(spctx->sp_fd[1]);
105 spctx->sp_fd[1] = -1;
107 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
108 sock = spctx->sp_fd[0];
111 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
112 sock = spctx->sp_fd[1];
115 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
118 /* Someone is just trying to decide about side. */
122 return (proto_common_send(sock, data, size, fd));
126 sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
128 struct sp_ctx *spctx = ctx;
131 PJDLOG_ASSERT(spctx != NULL);
132 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
134 switch (spctx->sp_side) {
137 * If the first operation done by the caller is proto_recv(),
138 * we assume this is the server.
141 spctx->sp_side = SP_SIDE_SERVER;
142 /* Close other end. */
143 close(spctx->sp_fd[0]);
144 spctx->sp_fd[0] = -1;
146 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
147 fd = spctx->sp_fd[1];
150 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
151 fd = spctx->sp_fd[0];
154 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
157 /* Someone is just trying to decide about side. */
161 return (proto_common_recv(fd, data, size, fdp));
165 sp_descriptor(const void *ctx)
167 const struct sp_ctx *spctx = ctx;
169 PJDLOG_ASSERT(spctx != NULL);
170 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
171 PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
172 spctx->sp_side == SP_SIDE_SERVER);
174 switch (spctx->sp_side) {
176 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
177 return (spctx->sp_fd[0]);
179 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
180 return (spctx->sp_fd[1]);
183 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
189 struct sp_ctx *spctx = ctx;
191 PJDLOG_ASSERT(spctx != NULL);
192 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
194 switch (spctx->sp_side) {
196 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
197 close(spctx->sp_fd[0]);
198 spctx->sp_fd[0] = -1;
199 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
200 close(spctx->sp_fd[1]);
201 spctx->sp_fd[1] = -1;
204 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
205 close(spctx->sp_fd[0]);
206 spctx->sp_fd[0] = -1;
207 PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
210 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
211 close(spctx->sp_fd[1]);
212 spctx->sp_fd[1] = -1;
213 PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
216 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
223 static struct proto sp_proto = {
224 .prt_name = "socketpair",
225 .prt_client = sp_client,
228 .prt_descriptor = sp_descriptor,
229 .prt_close = sp_close
232 static __constructor void
236 proto_register(&sp_proto, false);