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/types.h>
31 #include <sys/socket.h>
41 #include "proto_impl.h"
43 #define SP_CTX_MAGIC 0x50c3741
48 #define SP_SIDE_UNDEF 0
49 #define SP_SIDE_CLIENT 1
50 #define SP_SIDE_SERVER 2
53 static void sp_close(void *ctx);
56 sp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
61 PJDLOG_ASSERT(dstaddr != NULL);
62 PJDLOG_ASSERT(timeout >= -1);
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_wrap(int fd, bool client, void **ctxp)
91 PJDLOG_ASSERT(fd >= 0);
93 spctx = malloc(sizeof(*spctx));
98 spctx->sp_side = SP_SIDE_CLIENT;
100 spctx->sp_fd[1] = -1;
102 spctx->sp_side = SP_SIDE_SERVER;
103 spctx->sp_fd[0] = -1;
104 spctx->sp_fd[1] = fd;
106 spctx->sp_magic = SP_CTX_MAGIC;
113 sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
115 struct sp_ctx *spctx = ctx;
118 PJDLOG_ASSERT(spctx != NULL);
119 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
121 switch (spctx->sp_side) {
124 * If the first operation done by the caller is proto_send(),
125 * we assume this is the client.
128 spctx->sp_side = SP_SIDE_CLIENT;
129 /* Close other end. */
130 close(spctx->sp_fd[1]);
131 spctx->sp_fd[1] = -1;
133 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
134 sock = spctx->sp_fd[0];
137 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
138 sock = spctx->sp_fd[1];
141 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
144 /* Someone is just trying to decide about side. */
148 return (proto_common_send(sock, data, size, fd));
152 sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
154 struct sp_ctx *spctx = ctx;
157 PJDLOG_ASSERT(spctx != NULL);
158 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
160 switch (spctx->sp_side) {
163 * If the first operation done by the caller is proto_recv(),
164 * we assume this is the server.
167 spctx->sp_side = SP_SIDE_SERVER;
168 /* Close other end. */
169 close(spctx->sp_fd[0]);
170 spctx->sp_fd[0] = -1;
172 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
173 sock = spctx->sp_fd[1];
176 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
177 sock = spctx->sp_fd[0];
180 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
183 /* Someone is just trying to decide about side. */
187 return (proto_common_recv(sock, data, size, fdp));
191 sp_descriptor(const void *ctx)
193 const struct sp_ctx *spctx = ctx;
195 PJDLOG_ASSERT(spctx != NULL);
196 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
197 PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
198 spctx->sp_side == SP_SIDE_SERVER);
200 switch (spctx->sp_side) {
202 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
203 return (spctx->sp_fd[0]);
205 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
206 return (spctx->sp_fd[1]);
209 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
215 struct sp_ctx *spctx = ctx;
217 PJDLOG_ASSERT(spctx != NULL);
218 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
220 switch (spctx->sp_side) {
222 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
223 close(spctx->sp_fd[0]);
224 spctx->sp_fd[0] = -1;
225 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
226 close(spctx->sp_fd[1]);
227 spctx->sp_fd[1] = -1;
230 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
231 close(spctx->sp_fd[0]);
232 spctx->sp_fd[0] = -1;
233 PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
236 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
237 close(spctx->sp_fd[1]);
238 spctx->sp_fd[1] = -1;
239 PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
242 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
249 static struct proto sp_proto = {
250 .prt_name = "socketpair",
251 .prt_connect = sp_connect,
255 .prt_descriptor = sp_descriptor,
256 .prt_close = sp_close
259 static __constructor void
263 proto_register(&sp_proto, false);