1*aa772005SRobert Watson /*-
2*aa772005SRobert Watson * Copyright (c) 2009-2010 The FreeBSD Foundation
3*aa772005SRobert Watson * All rights reserved.
4*aa772005SRobert Watson *
5*aa772005SRobert Watson * This software was developed by Pawel Jakub Dawidek under sponsorship from
6*aa772005SRobert Watson * the FreeBSD Foundation.
7*aa772005SRobert Watson *
8*aa772005SRobert Watson * Redistribution and use in source and binary forms, with or without
9*aa772005SRobert Watson * modification, are permitted provided that the following conditions
10*aa772005SRobert Watson * are met:
11*aa772005SRobert Watson * 1. Redistributions of source code must retain the above copyright
12*aa772005SRobert Watson * notice, this list of conditions and the following disclaimer.
13*aa772005SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright
14*aa772005SRobert Watson * notice, this list of conditions and the following disclaimer in the
15*aa772005SRobert Watson * documentation and/or other materials provided with the distribution.
16*aa772005SRobert Watson *
17*aa772005SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18*aa772005SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*aa772005SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*aa772005SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21*aa772005SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*aa772005SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*aa772005SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*aa772005SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*aa772005SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*aa772005SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*aa772005SRobert Watson * SUCH DAMAGE.
28*aa772005SRobert Watson */
29*aa772005SRobert Watson
30*aa772005SRobert Watson #include <sys/types.h>
31*aa772005SRobert Watson #include <sys/socket.h>
32*aa772005SRobert Watson
33*aa772005SRobert Watson #include <errno.h>
34*aa772005SRobert Watson #include <stdbool.h>
35*aa772005SRobert Watson #include <stdint.h>
36*aa772005SRobert Watson #include <stdio.h>
37*aa772005SRobert Watson #include <string.h>
38*aa772005SRobert Watson #include <unistd.h>
39*aa772005SRobert Watson
40*aa772005SRobert Watson #include "pjdlog.h"
41*aa772005SRobert Watson #include "proto_impl.h"
42*aa772005SRobert Watson
43*aa772005SRobert Watson #define SP_CTX_MAGIC 0x50c3741
44*aa772005SRobert Watson struct sp_ctx {
45*aa772005SRobert Watson int sp_magic;
46*aa772005SRobert Watson int sp_fd[2];
47*aa772005SRobert Watson int sp_side;
48*aa772005SRobert Watson #define SP_SIDE_UNDEF 0
49*aa772005SRobert Watson #define SP_SIDE_CLIENT 1
50*aa772005SRobert Watson #define SP_SIDE_SERVER 2
51*aa772005SRobert Watson };
52*aa772005SRobert Watson
53*aa772005SRobert Watson static void sp_close(void *ctx);
54*aa772005SRobert Watson
55*aa772005SRobert Watson static int
sp_connect(const char * srcaddr,const char * dstaddr,int timeout,void ** ctxp)56*aa772005SRobert Watson sp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
57*aa772005SRobert Watson {
58*aa772005SRobert Watson struct sp_ctx *spctx;
59*aa772005SRobert Watson int error;
60*aa772005SRobert Watson
61*aa772005SRobert Watson PJDLOG_ASSERT(dstaddr != NULL);
62*aa772005SRobert Watson PJDLOG_ASSERT(timeout >= -1);
63*aa772005SRobert Watson
64*aa772005SRobert Watson if (strcmp(dstaddr, "socketpair://") != 0)
65*aa772005SRobert Watson return (-1);
66*aa772005SRobert Watson
67*aa772005SRobert Watson PJDLOG_ASSERT(srcaddr == NULL);
68*aa772005SRobert Watson
69*aa772005SRobert Watson spctx = malloc(sizeof(*spctx));
70*aa772005SRobert Watson if (spctx == NULL)
71*aa772005SRobert Watson return (errno);
72*aa772005SRobert Watson
73*aa772005SRobert Watson if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
74*aa772005SRobert Watson error = errno;
75*aa772005SRobert Watson free(spctx);
76*aa772005SRobert Watson return (error);
77*aa772005SRobert Watson }
78*aa772005SRobert Watson
79*aa772005SRobert Watson spctx->sp_side = SP_SIDE_UNDEF;
80*aa772005SRobert Watson spctx->sp_magic = SP_CTX_MAGIC;
81*aa772005SRobert Watson *ctxp = spctx;
82*aa772005SRobert Watson
83*aa772005SRobert Watson return (0);
84*aa772005SRobert Watson }
85*aa772005SRobert Watson
86*aa772005SRobert Watson static int
sp_wrap(int fd,bool client,void ** ctxp)87*aa772005SRobert Watson sp_wrap(int fd, bool client, void **ctxp)
88*aa772005SRobert Watson {
89*aa772005SRobert Watson struct sp_ctx *spctx;
90*aa772005SRobert Watson
91*aa772005SRobert Watson PJDLOG_ASSERT(fd >= 0);
92*aa772005SRobert Watson
93*aa772005SRobert Watson spctx = malloc(sizeof(*spctx));
94*aa772005SRobert Watson if (spctx == NULL)
95*aa772005SRobert Watson return (errno);
96*aa772005SRobert Watson
97*aa772005SRobert Watson if (client) {
98*aa772005SRobert Watson spctx->sp_side = SP_SIDE_CLIENT;
99*aa772005SRobert Watson spctx->sp_fd[0] = fd;
100*aa772005SRobert Watson spctx->sp_fd[1] = -1;
101*aa772005SRobert Watson } else {
102*aa772005SRobert Watson spctx->sp_side = SP_SIDE_SERVER;
103*aa772005SRobert Watson spctx->sp_fd[0] = -1;
104*aa772005SRobert Watson spctx->sp_fd[1] = fd;
105*aa772005SRobert Watson }
106*aa772005SRobert Watson spctx->sp_magic = SP_CTX_MAGIC;
107*aa772005SRobert Watson *ctxp = spctx;
108*aa772005SRobert Watson
109*aa772005SRobert Watson return (0);
110*aa772005SRobert Watson }
111*aa772005SRobert Watson
112*aa772005SRobert Watson static int
sp_send(void * ctx,const unsigned char * data,size_t size,int fd)113*aa772005SRobert Watson sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
114*aa772005SRobert Watson {
115*aa772005SRobert Watson struct sp_ctx *spctx = ctx;
116*aa772005SRobert Watson int sock;
117*aa772005SRobert Watson
118*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL);
119*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
120*aa772005SRobert Watson
121*aa772005SRobert Watson switch (spctx->sp_side) {
122*aa772005SRobert Watson case SP_SIDE_UNDEF:
123*aa772005SRobert Watson /*
124*aa772005SRobert Watson * If the first operation done by the caller is proto_send(),
125*aa772005SRobert Watson * we assume this is the client.
126*aa772005SRobert Watson */
127*aa772005SRobert Watson /* FALLTHROUGH */
128*aa772005SRobert Watson spctx->sp_side = SP_SIDE_CLIENT;
129*aa772005SRobert Watson /* Close other end. */
130*aa772005SRobert Watson close(spctx->sp_fd[1]);
131*aa772005SRobert Watson spctx->sp_fd[1] = -1;
132*aa772005SRobert Watson case SP_SIDE_CLIENT:
133*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
134*aa772005SRobert Watson sock = spctx->sp_fd[0];
135*aa772005SRobert Watson break;
136*aa772005SRobert Watson case SP_SIDE_SERVER:
137*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
138*aa772005SRobert Watson sock = spctx->sp_fd[1];
139*aa772005SRobert Watson break;
140*aa772005SRobert Watson default:
141*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
142*aa772005SRobert Watson }
143*aa772005SRobert Watson
144*aa772005SRobert Watson /* Someone is just trying to decide about side. */
145*aa772005SRobert Watson if (data == NULL)
146*aa772005SRobert Watson return (0);
147*aa772005SRobert Watson
148*aa772005SRobert Watson return (proto_common_send(sock, data, size, fd));
149*aa772005SRobert Watson }
150*aa772005SRobert Watson
151*aa772005SRobert Watson static int
sp_recv(void * ctx,unsigned char * data,size_t size,int * fdp)152*aa772005SRobert Watson sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
153*aa772005SRobert Watson {
154*aa772005SRobert Watson struct sp_ctx *spctx = ctx;
155*aa772005SRobert Watson int sock;
156*aa772005SRobert Watson
157*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL);
158*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
159*aa772005SRobert Watson
160*aa772005SRobert Watson switch (spctx->sp_side) {
161*aa772005SRobert Watson case SP_SIDE_UNDEF:
162*aa772005SRobert Watson /*
163*aa772005SRobert Watson * If the first operation done by the caller is proto_recv(),
164*aa772005SRobert Watson * we assume this is the server.
165*aa772005SRobert Watson */
166*aa772005SRobert Watson /* FALLTHROUGH */
167*aa772005SRobert Watson spctx->sp_side = SP_SIDE_SERVER;
168*aa772005SRobert Watson /* Close other end. */
169*aa772005SRobert Watson close(spctx->sp_fd[0]);
170*aa772005SRobert Watson spctx->sp_fd[0] = -1;
171*aa772005SRobert Watson case SP_SIDE_SERVER:
172*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
173*aa772005SRobert Watson sock = spctx->sp_fd[1];
174*aa772005SRobert Watson break;
175*aa772005SRobert Watson case SP_SIDE_CLIENT:
176*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
177*aa772005SRobert Watson sock = spctx->sp_fd[0];
178*aa772005SRobert Watson break;
179*aa772005SRobert Watson default:
180*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
181*aa772005SRobert Watson }
182*aa772005SRobert Watson
183*aa772005SRobert Watson /* Someone is just trying to decide about side. */
184*aa772005SRobert Watson if (data == NULL)
185*aa772005SRobert Watson return (0);
186*aa772005SRobert Watson
187*aa772005SRobert Watson return (proto_common_recv(sock, data, size, fdp));
188*aa772005SRobert Watson }
189*aa772005SRobert Watson
190*aa772005SRobert Watson static int
sp_descriptor(const void * ctx)191*aa772005SRobert Watson sp_descriptor(const void *ctx)
192*aa772005SRobert Watson {
193*aa772005SRobert Watson const struct sp_ctx *spctx = ctx;
194*aa772005SRobert Watson
195*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL);
196*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
197*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
198*aa772005SRobert Watson spctx->sp_side == SP_SIDE_SERVER);
199*aa772005SRobert Watson
200*aa772005SRobert Watson switch (spctx->sp_side) {
201*aa772005SRobert Watson case SP_SIDE_CLIENT:
202*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
203*aa772005SRobert Watson return (spctx->sp_fd[0]);
204*aa772005SRobert Watson case SP_SIDE_SERVER:
205*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
206*aa772005SRobert Watson return (spctx->sp_fd[1]);
207*aa772005SRobert Watson }
208*aa772005SRobert Watson
209*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
210*aa772005SRobert Watson }
211*aa772005SRobert Watson
212*aa772005SRobert Watson static void
sp_close(void * ctx)213*aa772005SRobert Watson sp_close(void *ctx)
214*aa772005SRobert Watson {
215*aa772005SRobert Watson struct sp_ctx *spctx = ctx;
216*aa772005SRobert Watson
217*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL);
218*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
219*aa772005SRobert Watson
220*aa772005SRobert Watson switch (spctx->sp_side) {
221*aa772005SRobert Watson case SP_SIDE_UNDEF:
222*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
223*aa772005SRobert Watson close(spctx->sp_fd[0]);
224*aa772005SRobert Watson spctx->sp_fd[0] = -1;
225*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
226*aa772005SRobert Watson close(spctx->sp_fd[1]);
227*aa772005SRobert Watson spctx->sp_fd[1] = -1;
228*aa772005SRobert Watson break;
229*aa772005SRobert Watson case SP_SIDE_CLIENT:
230*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
231*aa772005SRobert Watson close(spctx->sp_fd[0]);
232*aa772005SRobert Watson spctx->sp_fd[0] = -1;
233*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
234*aa772005SRobert Watson break;
235*aa772005SRobert Watson case SP_SIDE_SERVER:
236*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
237*aa772005SRobert Watson close(spctx->sp_fd[1]);
238*aa772005SRobert Watson spctx->sp_fd[1] = -1;
239*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
240*aa772005SRobert Watson break;
241*aa772005SRobert Watson default:
242*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
243*aa772005SRobert Watson }
244*aa772005SRobert Watson
245*aa772005SRobert Watson spctx->sp_magic = 0;
246*aa772005SRobert Watson free(spctx);
247*aa772005SRobert Watson }
248*aa772005SRobert Watson
249*aa772005SRobert Watson static struct proto sp_proto = {
250*aa772005SRobert Watson .prt_name = "socketpair",
251*aa772005SRobert Watson .prt_connect = sp_connect,
252*aa772005SRobert Watson .prt_wrap = sp_wrap,
253*aa772005SRobert Watson .prt_send = sp_send,
254*aa772005SRobert Watson .prt_recv = sp_recv,
255*aa772005SRobert Watson .prt_descriptor = sp_descriptor,
256*aa772005SRobert Watson .prt_close = sp_close
257*aa772005SRobert Watson };
258*aa772005SRobert Watson
259*aa772005SRobert Watson static __constructor void
sp_ctor(void)260*aa772005SRobert Watson sp_ctor(void)
261*aa772005SRobert Watson {
262*aa772005SRobert Watson
263*aa772005SRobert Watson proto_register(&sp_proto, false);
264*aa772005SRobert Watson }
265