proto_socketpair.c revision 219873
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2009-2010 The FreeBSD Foundation
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * This software was developed by Pawel Jakub Dawidek under sponsorship from
61590Srgrimes * the FreeBSD Foundation.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#include <sys/cdefs.h>
311590Srgrimes__FBSDID("$FreeBSD: head/sbin/hastd/proto_socketpair.c 219873 2011-03-22 16:21:11Z pjd $");
321590Srgrimes
331590Srgrimes#include <sys/types.h>
341590Srgrimes#include <sys/socket.h>
351590Srgrimes
361590Srgrimes#include <errno.h>
3762833Swsanchez#include <stdbool.h>
3862833Swsanchez#include <stdint.h>
391590Srgrimes#include <stdio.h>
401590Srgrimes#include <string.h>
4162833Swsanchez#include <unistd.h>
4294587Sobrien
431590Srgrimes#include "pjdlog.h"
44141104Sharti#include "proto_impl.h"
45141104Sharti
461590Srgrimes#define	SP_CTX_MAGIC	0x50c3741
47141133Shartistruct sp_ctx {
48141104Sharti	int			sp_magic;
49141104Sharti	int			sp_fd[2];
50141104Sharti	int			sp_side;
51146345Sharti#define	SP_SIDE_UNDEF		0
52146345Sharti#define	SP_SIDE_CLIENT		1
53228992Suqs#define	SP_SIDE_SERVER		2
54146345Sharti};
55146345Sharti
56228992Suqsstatic void sp_close(void *ctx);
57146345Sharti
58146543Shartistatic int
59146345Shartisp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
60146345Sharti{
615814Sjkh	struct sp_ctx *spctx;
62146345Sharti	int ret;
63146345Sharti
64146345Sharti	if (strcmp(dstaddr, "socketpair://") != 0)
65146345Sharti		return (-1);
66146345Sharti
67146345Sharti	PJDLOG_ASSERT(srcaddr == NULL);
68146345Sharti
69146345Sharti	spctx = malloc(sizeof(*spctx));
70146345Sharti	if (spctx == NULL)
71146345Sharti		return (errno);
725814Sjkh
735814Sjkh	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
74146345Sharti		ret = errno;
755814Sjkh		free(spctx);
76138232Sharti		return (ret);
77146345Sharti	}
78146345Sharti
79146345Sharti	spctx->sp_side = SP_SIDE_UNDEF;
80146345Sharti	spctx->sp_magic = SP_CTX_MAGIC;
81146345Sharti	*ctxp = spctx;
82146345Sharti
83146345Sharti	return (0);
84146345Sharti}
85146345Sharti
86146345Shartistatic int
87146345Shartisp_send(void *ctx, const unsigned char *data, size_t size, int fd)
88146345Sharti{
89146345Sharti	struct sp_ctx *spctx = ctx;
90146345Sharti	int sock;
91146345Sharti
92146345Sharti	PJDLOG_ASSERT(spctx != NULL);
93146345Sharti	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
94146345Sharti
955814Sjkh	switch (spctx->sp_side) {
965814Sjkh	case SP_SIDE_UNDEF:
971590Srgrimes		/*
981590Srgrimes		 * If the first operation done by the caller is proto_send(),
99138547Sharti		 * we assume this is the client.
1001590Srgrimes		 */
1011590Srgrimes		/* FALLTHROUGH */
1021590Srgrimes		spctx->sp_side = SP_SIDE_CLIENT;
1031590Srgrimes		/* Close other end. */
1041590Srgrimes		close(spctx->sp_fd[1]);
105138547Sharti		spctx->sp_fd[1] = -1;
1061590Srgrimes	case SP_SIDE_CLIENT:
10794584Sobrien		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
10894584Sobrien		sock = spctx->sp_fd[0];
1091590Srgrimes		break;
1101590Srgrimes	case SP_SIDE_SERVER:
11194638Sobrien		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
11294638Sobrien		sock = spctx->sp_fd[1];
1131590Srgrimes		break;
1141590Srgrimes	default:
115138264Sharti		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
1161590Srgrimes	}
1171590Srgrimes
11894638Sobrien	/* Someone is just trying to decide about side. */
1191590Srgrimes	if (data == NULL)
1201590Srgrimes		return (0);
12194638Sobrien
12294638Sobrien	return (proto_common_send(sock, data, size, fd));
12394638Sobrien}
12494638Sobrien
12594638Sobrienstatic int
12694638Sobriensp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
1271590Srgrimes{
1281590Srgrimes	struct sp_ctx *spctx = ctx;
12994638Sobrien	int fd;
13094638Sobrien
1311590Srgrimes	PJDLOG_ASSERT(spctx != NULL);
132138232Sharti	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
1331590Srgrimes
1341590Srgrimes	switch (spctx->sp_side) {
135146345Sharti	case SP_SIDE_UNDEF:
136146345Sharti		/*
137146345Sharti		 * If the first operation done by the caller is proto_recv(),
138146345Sharti		 * we assume this is the server.
1391590Srgrimes		 */
140146345Sharti		/* FALLTHROUGH */
141146345Sharti		spctx->sp_side = SP_SIDE_SERVER;
1421590Srgrimes		/* Close other end. */
143146345Sharti		close(spctx->sp_fd[0]);
144146345Sharti		spctx->sp_fd[0] = -1;
145146345Sharti	case SP_SIDE_SERVER:
1461590Srgrimes		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
1471590Srgrimes		fd = spctx->sp_fd[1];
1481590Srgrimes		break;
1491590Srgrimes	case SP_SIDE_CLIENT:
1501590Srgrimes		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
151146345Sharti		fd = spctx->sp_fd[0];
1521590Srgrimes		break;
153209951Semaste	default:
154146345Sharti		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
155146345Sharti	}
156146345Sharti
157146345Sharti	/* Someone is just trying to decide about side. */
158146345Sharti	if (data == NULL)
1591590Srgrimes		return (0);
1601590Srgrimes
1611590Srgrimes	return (proto_common_recv(fd, data, size, fdp));
1621590Srgrimes}
163146345Sharti
164146345Shartistatic int
1651590Srgrimessp_descriptor(const void *ctx)
1661590Srgrimes{
167146345Sharti	const struct sp_ctx *spctx = ctx;
168146345Sharti
169146345Sharti	PJDLOG_ASSERT(spctx != NULL);
1701590Srgrimes	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
171146345Sharti	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
172146345Sharti	    spctx->sp_side == SP_SIDE_SERVER);
173146345Sharti
174124966Sru	switch (spctx->sp_side) {
175124966Sru	case SP_SIDE_CLIENT:
176146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
177146345Sharti		return (spctx->sp_fd[0]);
178146345Sharti	case SP_SIDE_SERVER:
179146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
180146345Sharti		return (spctx->sp_fd[1]);
181146345Sharti	}
182146345Sharti
183146345Sharti	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
184146345Sharti}
185146345Sharti
186124840Srustatic void
1871590Srgrimessp_close(void *ctx)
1881590Srgrimes{
1895814Sjkh	struct sp_ctx *spctx = ctx;
190146345Sharti
191146345Sharti	PJDLOG_ASSERT(spctx != NULL);
192146345Sharti	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
193146345Sharti
1941590Srgrimes	switch (spctx->sp_side) {
195146345Sharti	case SP_SIDE_UNDEF:
196146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
197146345Sharti		close(spctx->sp_fd[0]);
1981590Srgrimes		spctx->sp_fd[0] = -1;
1991590Srgrimes		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
2001590Srgrimes		close(spctx->sp_fd[1]);
2011590Srgrimes		spctx->sp_fd[1] = -1;
2021590Srgrimes		break;
2031590Srgrimes	case SP_SIDE_CLIENT:
204146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
205146345Sharti		close(spctx->sp_fd[0]);
206146345Sharti		spctx->sp_fd[0] = -1;
207146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
208146345Sharti		break;
2095814Sjkh	case SP_SIDE_SERVER:
210146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
211146345Sharti		close(spctx->sp_fd[1]);
212146345Sharti		spctx->sp_fd[1] = -1;
213146345Sharti		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
2141590Srgrimes		break;
215146345Sharti	default:
216146345Sharti		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
217146345Sharti	}
218146345Sharti
219146345Sharti	spctx->sp_magic = 0;
220146345Sharti	free(spctx);
221146345Sharti}
2225814Sjkh
2235814Sjkhstatic struct proto sp_proto = {
224146345Sharti	.prt_name = "socketpair",
225146345Sharti	.prt_client = sp_client,
226146345Sharti	.prt_send = sp_send,
227146345Sharti	.prt_recv = sp_recv,
228146345Sharti	.prt_descriptor = sp_descriptor,
229146345Sharti	.prt_close = sp_close
230146345Sharti};
231146345Sharti
232146345Shartistatic __constructor void
233146345Shartisp_ctor(void)
234146345Sharti{
235146345Sharti
236146345Sharti	proto_register(&sp_proto, false);
237146345Sharti}
238146345Sharti