xref: /freebsd/sbin/hastd/proto_socketpair.c (revision 5c2bc3db201a4fe8d7911cf816bea104d5dc2138)
132115b10SPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
432115b10SPawel Jakub Dawidek  * Copyright (c) 2009-2010 The FreeBSD Foundation
532115b10SPawel Jakub Dawidek  *
632115b10SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
732115b10SPawel Jakub Dawidek  * the FreeBSD Foundation.
832115b10SPawel Jakub Dawidek  *
932115b10SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1032115b10SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1132115b10SPawel Jakub Dawidek  * are met:
1232115b10SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1332115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1432115b10SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1532115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1632115b10SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1732115b10SPawel Jakub Dawidek  *
1832115b10SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1932115b10SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2032115b10SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2132115b10SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2232115b10SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2332115b10SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2432115b10SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2532115b10SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2632115b10SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2732115b10SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2832115b10SPawel Jakub Dawidek  * SUCH DAMAGE.
2932115b10SPawel Jakub Dawidek  */
3032115b10SPawel Jakub Dawidek 
3132115b10SPawel Jakub Dawidek #include <sys/types.h>
3232115b10SPawel Jakub Dawidek #include <sys/socket.h>
3332115b10SPawel Jakub Dawidek 
3432115b10SPawel Jakub Dawidek #include <errno.h>
3532115b10SPawel Jakub Dawidek #include <stdbool.h>
3632115b10SPawel Jakub Dawidek #include <stdint.h>
3732115b10SPawel Jakub Dawidek #include <stdio.h>
3832115b10SPawel Jakub Dawidek #include <string.h>
3932115b10SPawel Jakub Dawidek #include <unistd.h>
4032115b10SPawel Jakub Dawidek 
412ec483c5SPawel Jakub Dawidek #include "pjdlog.h"
4232115b10SPawel Jakub Dawidek #include "proto_impl.h"
4332115b10SPawel Jakub Dawidek 
4432115b10SPawel Jakub Dawidek #define	SP_CTX_MAGIC	0x50c3741
4532115b10SPawel Jakub Dawidek struct sp_ctx {
4632115b10SPawel Jakub Dawidek 	int			sp_magic;
4732115b10SPawel Jakub Dawidek 	int			sp_fd[2];
4832115b10SPawel Jakub Dawidek 	int			sp_side;
4932115b10SPawel Jakub Dawidek #define	SP_SIDE_UNDEF		0
5032115b10SPawel Jakub Dawidek #define	SP_SIDE_CLIENT		1
5132115b10SPawel Jakub Dawidek #define	SP_SIDE_SERVER		2
5232115b10SPawel Jakub Dawidek };
5332115b10SPawel Jakub Dawidek 
5432115b10SPawel Jakub Dawidek static void sp_close(void *ctx);
5532115b10SPawel Jakub Dawidek 
5632115b10SPawel Jakub Dawidek static int
570b626a28SPawel Jakub Dawidek sp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
5832115b10SPawel Jakub Dawidek {
5932115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx;
6032115b10SPawel Jakub Dawidek 	int ret;
6132115b10SPawel Jakub Dawidek 
620b626a28SPawel Jakub Dawidek 	if (strcmp(dstaddr, "socketpair://") != 0)
6332115b10SPawel Jakub Dawidek 		return (-1);
6432115b10SPawel Jakub Dawidek 
650b626a28SPawel Jakub Dawidek 	PJDLOG_ASSERT(srcaddr == NULL);
660b626a28SPawel Jakub Dawidek 
6732115b10SPawel Jakub Dawidek 	spctx = malloc(sizeof(*spctx));
6832115b10SPawel Jakub Dawidek 	if (spctx == NULL)
6932115b10SPawel Jakub Dawidek 		return (errno);
7032115b10SPawel Jakub Dawidek 
712b1b224dSPawel Jakub Dawidek 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
7232115b10SPawel Jakub Dawidek 		ret = errno;
7332115b10SPawel Jakub Dawidek 		free(spctx);
7432115b10SPawel Jakub Dawidek 		return (ret);
7532115b10SPawel Jakub Dawidek 	}
7632115b10SPawel Jakub Dawidek 
7732115b10SPawel Jakub Dawidek 	spctx->sp_side = SP_SIDE_UNDEF;
7832115b10SPawel Jakub Dawidek 	spctx->sp_magic = SP_CTX_MAGIC;
7932115b10SPawel Jakub Dawidek 	*ctxp = spctx;
8032115b10SPawel Jakub Dawidek 
8132115b10SPawel Jakub Dawidek 	return (0);
8232115b10SPawel Jakub Dawidek }
8332115b10SPawel Jakub Dawidek 
8432115b10SPawel Jakub Dawidek static int
8501ab52c0SPawel Jakub Dawidek sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
8632115b10SPawel Jakub Dawidek {
8732115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx = ctx;
8801ab52c0SPawel Jakub Dawidek 	int sock;
8932115b10SPawel Jakub Dawidek 
902ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
912ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
9232115b10SPawel Jakub Dawidek 
9332115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
9432115b10SPawel Jakub Dawidek 	case SP_SIDE_UNDEF:
9532115b10SPawel Jakub Dawidek 		/*
9632115b10SPawel Jakub Dawidek 		 * If the first operation done by the caller is proto_send(),
9701ab52c0SPawel Jakub Dawidek 		 * we assume this is the client.
9832115b10SPawel Jakub Dawidek 		 */
9932115b10SPawel Jakub Dawidek 		/* FALLTHROUGH */
10032115b10SPawel Jakub Dawidek 		spctx->sp_side = SP_SIDE_CLIENT;
10132115b10SPawel Jakub Dawidek 		/* Close other end. */
10232115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[1]);
1032ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[1] = -1;
10432115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
1052ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
10601ab52c0SPawel Jakub Dawidek 		sock = spctx->sp_fd[0];
10732115b10SPawel Jakub Dawidek 		break;
10832115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
1092ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
11001ab52c0SPawel Jakub Dawidek 		sock = spctx->sp_fd[1];
11132115b10SPawel Jakub Dawidek 		break;
11232115b10SPawel Jakub Dawidek 	default:
1132ec483c5SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
11432115b10SPawel Jakub Dawidek 	}
11532115b10SPawel Jakub Dawidek 
116eea2deaaSPawel Jakub Dawidek 	/* Someone is just trying to decide about side. */
117eea2deaaSPawel Jakub Dawidek 	if (data == NULL)
118eea2deaaSPawel Jakub Dawidek 		return (0);
119eea2deaaSPawel Jakub Dawidek 
12001ab52c0SPawel Jakub Dawidek 	return (proto_common_send(sock, data, size, fd));
12132115b10SPawel Jakub Dawidek }
12232115b10SPawel Jakub Dawidek 
12332115b10SPawel Jakub Dawidek static int
12401ab52c0SPawel Jakub Dawidek sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
12532115b10SPawel Jakub Dawidek {
12632115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx = ctx;
12732115b10SPawel Jakub Dawidek 	int fd;
12832115b10SPawel Jakub Dawidek 
1292ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
1302ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
13132115b10SPawel Jakub Dawidek 
13232115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
13332115b10SPawel Jakub Dawidek 	case SP_SIDE_UNDEF:
13432115b10SPawel Jakub Dawidek 		/*
13532115b10SPawel Jakub Dawidek 		 * If the first operation done by the caller is proto_recv(),
13601ab52c0SPawel Jakub Dawidek 		 * we assume this is the server.
13732115b10SPawel Jakub Dawidek 		 */
13832115b10SPawel Jakub Dawidek 		/* FALLTHROUGH */
13932115b10SPawel Jakub Dawidek 		spctx->sp_side = SP_SIDE_SERVER;
14032115b10SPawel Jakub Dawidek 		/* Close other end. */
14132115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[0]);
1422ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[0] = -1;
14332115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
1442ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
14532115b10SPawel Jakub Dawidek 		fd = spctx->sp_fd[1];
14632115b10SPawel Jakub Dawidek 		break;
14732115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
1482ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
14932115b10SPawel Jakub Dawidek 		fd = spctx->sp_fd[0];
15032115b10SPawel Jakub Dawidek 		break;
15132115b10SPawel Jakub Dawidek 	default:
1522ec483c5SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
15332115b10SPawel Jakub Dawidek 	}
15432115b10SPawel Jakub Dawidek 
155eea2deaaSPawel Jakub Dawidek 	/* Someone is just trying to decide about side. */
156eea2deaaSPawel Jakub Dawidek 	if (data == NULL)
157eea2deaaSPawel Jakub Dawidek 		return (0);
158eea2deaaSPawel Jakub Dawidek 
15901ab52c0SPawel Jakub Dawidek 	return (proto_common_recv(fd, data, size, fdp));
1608046c499SPawel Jakub Dawidek }
1618046c499SPawel Jakub Dawidek 
1628046c499SPawel Jakub Dawidek static int
16332115b10SPawel Jakub Dawidek sp_descriptor(const void *ctx)
16432115b10SPawel Jakub Dawidek {
16532115b10SPawel Jakub Dawidek 	const struct sp_ctx *spctx = ctx;
16632115b10SPawel Jakub Dawidek 
1672ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
1682ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
1692ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
17032115b10SPawel Jakub Dawidek 	    spctx->sp_side == SP_SIDE_SERVER);
17132115b10SPawel Jakub Dawidek 
17232115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
17332115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
1742ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
17532115b10SPawel Jakub Dawidek 		return (spctx->sp_fd[0]);
17632115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
1772ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
17832115b10SPawel Jakub Dawidek 		return (spctx->sp_fd[1]);
17932115b10SPawel Jakub Dawidek 	}
18032115b10SPawel Jakub Dawidek 
1812ec483c5SPawel Jakub Dawidek 	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
18232115b10SPawel Jakub Dawidek }
18332115b10SPawel Jakub Dawidek 
18432115b10SPawel Jakub Dawidek static void
18532115b10SPawel Jakub Dawidek sp_close(void *ctx)
18632115b10SPawel Jakub Dawidek {
18732115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx = ctx;
18832115b10SPawel Jakub Dawidek 
1892ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
1902ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
19132115b10SPawel Jakub Dawidek 
19232115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
19332115b10SPawel Jakub Dawidek 	case SP_SIDE_UNDEF:
1942ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
19532115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[0]);
1962ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[0] = -1;
1972ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
19832115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[1]);
1992ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[1] = -1;
20032115b10SPawel Jakub Dawidek 		break;
20132115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
2022ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
20332115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[0]);
2042ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[0] = -1;
2052ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
20632115b10SPawel Jakub Dawidek 		break;
20732115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
2082ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
20932115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[1]);
2102ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[1] = -1;
2112ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
21232115b10SPawel Jakub Dawidek 		break;
21332115b10SPawel Jakub Dawidek 	default:
2142ec483c5SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
21532115b10SPawel Jakub Dawidek 	}
21632115b10SPawel Jakub Dawidek 
21732115b10SPawel Jakub Dawidek 	spctx->sp_magic = 0;
21832115b10SPawel Jakub Dawidek 	free(spctx);
21932115b10SPawel Jakub Dawidek }
22032115b10SPawel Jakub Dawidek 
221e2eabb44SPawel Jakub Dawidek static struct proto sp_proto = {
222e2eabb44SPawel Jakub Dawidek 	.prt_name = "socketpair",
223e2eabb44SPawel Jakub Dawidek 	.prt_client = sp_client,
224e2eabb44SPawel Jakub Dawidek 	.prt_send = sp_send,
225e2eabb44SPawel Jakub Dawidek 	.prt_recv = sp_recv,
226e2eabb44SPawel Jakub Dawidek 	.prt_descriptor = sp_descriptor,
227e2eabb44SPawel Jakub Dawidek 	.prt_close = sp_close
22832115b10SPawel Jakub Dawidek };
22932115b10SPawel Jakub Dawidek 
23032115b10SPawel Jakub Dawidek static __constructor void
23132115b10SPawel Jakub Dawidek sp_ctor(void)
23232115b10SPawel Jakub Dawidek {
23332115b10SPawel Jakub Dawidek 
23450692f84SPawel Jakub Dawidek 	proto_register(&sp_proto, false);
23532115b10SPawel Jakub Dawidek }
236