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
sp_client(const char * srcaddr,const char * dstaddr,void ** ctxp)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
sp_send(void * ctx,const unsigned char * data,size_t size,int fd)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
sp_recv(void * ctx,unsigned char * data,size_t size,int * fdp)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
sp_descriptor(const void * ctx)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
sp_close(void * ctx)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
sp_ctor(void)231 sp_ctor(void)
232 {
233
234 proto_register(&sp_proto, false);
235 }
236