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>
45 #include "proto_impl.h"
47 #define SP_CTX_MAGIC 0x50c3741
52 #define SP_SIDE_UNDEF 0
53 #define SP_SIDE_CLIENT 1
54 #define SP_SIDE_SERVER 2
57 static void sp_close(void *ctx);
60 sp_client(const char *addr, void **ctxp)
65 if (strcmp(addr, "socketpair://") != 0)
68 spctx = malloc(sizeof(*spctx));
72 if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
78 spctx->sp_side = SP_SIDE_UNDEF;
79 spctx->sp_magic = SP_CTX_MAGIC;
86 sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
88 struct sp_ctx *spctx = ctx;
91 PJDLOG_ASSERT(spctx != NULL);
92 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
94 switch (spctx->sp_side) {
97 * If the first operation done by the caller is proto_send(),
98 * we assume this is the client.
101 spctx->sp_side = SP_SIDE_CLIENT;
102 /* Close other end. */
103 close(spctx->sp_fd[1]);
104 spctx->sp_fd[1] = -1;
106 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
107 sock = spctx->sp_fd[0];
110 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
111 sock = spctx->sp_fd[1];
114 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
117 /* Someone is just trying to decide about side. */
121 return (proto_common_send(sock, data, size, fd));
125 sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
127 struct sp_ctx *spctx = ctx;
130 PJDLOG_ASSERT(spctx != NULL);
131 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
133 switch (spctx->sp_side) {
136 * If the first operation done by the caller is proto_recv(),
137 * we assume this is the server.
140 spctx->sp_side = SP_SIDE_SERVER;
141 /* Close other end. */
142 close(spctx->sp_fd[0]);
143 spctx->sp_fd[0] = -1;
145 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
146 fd = spctx->sp_fd[1];
149 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
150 fd = spctx->sp_fd[0];
153 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
156 /* Someone is just trying to decide about side. */
160 return (proto_common_recv(fd, data, size, fdp));
164 sp_descriptor(const void *ctx)
166 const struct sp_ctx *spctx = ctx;
168 PJDLOG_ASSERT(spctx != NULL);
169 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
170 PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
171 spctx->sp_side == SP_SIDE_SERVER);
173 switch (spctx->sp_side) {
175 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
176 return (spctx->sp_fd[0]);
178 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
179 return (spctx->sp_fd[1]);
182 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
188 struct sp_ctx *spctx = ctx;
190 PJDLOG_ASSERT(spctx != NULL);
191 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
193 switch (spctx->sp_side) {
195 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
196 close(spctx->sp_fd[0]);
197 spctx->sp_fd[0] = -1;
198 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
199 close(spctx->sp_fd[1]);
200 spctx->sp_fd[1] = -1;
203 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
204 close(spctx->sp_fd[0]);
205 spctx->sp_fd[0] = -1;
206 PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
209 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
210 close(spctx->sp_fd[1]);
211 spctx->sp_fd[1] = -1;
212 PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
215 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
222 static struct hast_proto sp_proto = {
223 .hp_name = "socketpair",
224 .hp_client = sp_client,
227 .hp_descriptor = sp_descriptor,
231 static __constructor void
235 proto_register(&sp_proto, false);