xref: /freebsd/sbin/hastd/proto_socketpair.c (revision e2eabb44d7ec3bacd0fa4fe203a71cdc5fbc740b)
132115b10SPawel Jakub Dawidek /*-
232115b10SPawel Jakub Dawidek  * Copyright (c) 2009-2010 The FreeBSD Foundation
332115b10SPawel Jakub Dawidek  * All rights reserved.
432115b10SPawel Jakub Dawidek  *
532115b10SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
632115b10SPawel Jakub Dawidek  * the FreeBSD Foundation.
732115b10SPawel Jakub Dawidek  *
832115b10SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
932115b10SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1032115b10SPawel Jakub Dawidek  * are met:
1132115b10SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1232115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1332115b10SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1432115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1532115b10SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1632115b10SPawel Jakub Dawidek  *
1732115b10SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1832115b10SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1932115b10SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2032115b10SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2132115b10SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2232115b10SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2332115b10SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2432115b10SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2532115b10SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2632115b10SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2732115b10SPawel Jakub Dawidek  * SUCH DAMAGE.
2832115b10SPawel Jakub Dawidek  */
2932115b10SPawel Jakub Dawidek 
3032115b10SPawel Jakub Dawidek #include <sys/cdefs.h>
3132115b10SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
3232115b10SPawel Jakub Dawidek 
3332115b10SPawel Jakub Dawidek #include <sys/types.h>
3432115b10SPawel Jakub Dawidek #include <sys/socket.h>
3532115b10SPawel Jakub Dawidek 
3632115b10SPawel Jakub Dawidek #include <errno.h>
3732115b10SPawel Jakub Dawidek #include <stdbool.h>
3832115b10SPawel Jakub Dawidek #include <stdint.h>
3932115b10SPawel Jakub Dawidek #include <stdio.h>
4032115b10SPawel Jakub Dawidek #include <string.h>
4132115b10SPawel Jakub Dawidek #include <unistd.h>
4232115b10SPawel Jakub Dawidek 
432ec483c5SPawel Jakub Dawidek #include "pjdlog.h"
4432115b10SPawel Jakub Dawidek #include "proto_impl.h"
4532115b10SPawel Jakub Dawidek 
4632115b10SPawel Jakub Dawidek #define	SP_CTX_MAGIC	0x50c3741
4732115b10SPawel Jakub Dawidek struct sp_ctx {
4832115b10SPawel Jakub Dawidek 	int			sp_magic;
4932115b10SPawel Jakub Dawidek 	int			sp_fd[2];
5032115b10SPawel Jakub Dawidek 	int			sp_side;
5132115b10SPawel Jakub Dawidek #define	SP_SIDE_UNDEF		0
5232115b10SPawel Jakub Dawidek #define	SP_SIDE_CLIENT		1
5332115b10SPawel Jakub Dawidek #define	SP_SIDE_SERVER		2
5432115b10SPawel Jakub Dawidek };
5532115b10SPawel Jakub Dawidek 
5632115b10SPawel Jakub Dawidek static void sp_close(void *ctx);
5732115b10SPawel Jakub Dawidek 
5832115b10SPawel Jakub Dawidek static int
590b626a28SPawel Jakub Dawidek sp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
6032115b10SPawel Jakub Dawidek {
6132115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx;
6232115b10SPawel Jakub Dawidek 	int ret;
6332115b10SPawel Jakub Dawidek 
640b626a28SPawel Jakub Dawidek 	if (strcmp(dstaddr, "socketpair://") != 0)
6532115b10SPawel Jakub Dawidek 		return (-1);
6632115b10SPawel Jakub Dawidek 
670b626a28SPawel Jakub Dawidek 	PJDLOG_ASSERT(srcaddr == NULL);
680b626a28SPawel Jakub Dawidek 
6932115b10SPawel Jakub Dawidek 	spctx = malloc(sizeof(*spctx));
7032115b10SPawel Jakub Dawidek 	if (spctx == NULL)
7132115b10SPawel Jakub Dawidek 		return (errno);
7232115b10SPawel Jakub Dawidek 
7332115b10SPawel Jakub Dawidek 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
7432115b10SPawel Jakub Dawidek 		ret = errno;
7532115b10SPawel Jakub Dawidek 		free(spctx);
7632115b10SPawel Jakub Dawidek 		return (ret);
7732115b10SPawel Jakub Dawidek 	}
7832115b10SPawel Jakub Dawidek 
7932115b10SPawel Jakub Dawidek 	spctx->sp_side = SP_SIDE_UNDEF;
8032115b10SPawel Jakub Dawidek 	spctx->sp_magic = SP_CTX_MAGIC;
8132115b10SPawel Jakub Dawidek 	*ctxp = spctx;
8232115b10SPawel Jakub Dawidek 
8332115b10SPawel Jakub Dawidek 	return (0);
8432115b10SPawel Jakub Dawidek }
8532115b10SPawel Jakub Dawidek 
8632115b10SPawel Jakub Dawidek static int
8701ab52c0SPawel Jakub Dawidek sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
8832115b10SPawel Jakub Dawidek {
8932115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx = ctx;
9001ab52c0SPawel Jakub Dawidek 	int sock;
9132115b10SPawel Jakub Dawidek 
922ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
932ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
9432115b10SPawel Jakub Dawidek 
9532115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
9632115b10SPawel Jakub Dawidek 	case SP_SIDE_UNDEF:
9732115b10SPawel Jakub Dawidek 		/*
9832115b10SPawel Jakub Dawidek 		 * If the first operation done by the caller is proto_send(),
9901ab52c0SPawel Jakub Dawidek 		 * we assume this is the client.
10032115b10SPawel Jakub Dawidek 		 */
10132115b10SPawel Jakub Dawidek 		/* FALLTHROUGH */
10232115b10SPawel Jakub Dawidek 		spctx->sp_side = SP_SIDE_CLIENT;
10332115b10SPawel Jakub Dawidek 		/* Close other end. */
10432115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[1]);
1052ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[1] = -1;
10632115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
1072ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
10801ab52c0SPawel Jakub Dawidek 		sock = spctx->sp_fd[0];
10932115b10SPawel Jakub Dawidek 		break;
11032115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
1112ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
11201ab52c0SPawel Jakub Dawidek 		sock = spctx->sp_fd[1];
11332115b10SPawel Jakub Dawidek 		break;
11432115b10SPawel Jakub Dawidek 	default:
1152ec483c5SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
11632115b10SPawel Jakub Dawidek 	}
11732115b10SPawel Jakub Dawidek 
118eea2deaaSPawel Jakub Dawidek 	/* Someone is just trying to decide about side. */
119eea2deaaSPawel Jakub Dawidek 	if (data == NULL)
120eea2deaaSPawel Jakub Dawidek 		return (0);
121eea2deaaSPawel Jakub Dawidek 
12201ab52c0SPawel Jakub Dawidek 	return (proto_common_send(sock, data, size, fd));
12332115b10SPawel Jakub Dawidek }
12432115b10SPawel Jakub Dawidek 
12532115b10SPawel Jakub Dawidek static int
12601ab52c0SPawel Jakub Dawidek sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
12732115b10SPawel Jakub Dawidek {
12832115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx = ctx;
12932115b10SPawel Jakub Dawidek 	int fd;
13032115b10SPawel Jakub Dawidek 
1312ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
1322ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
13332115b10SPawel Jakub Dawidek 
13432115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
13532115b10SPawel Jakub Dawidek 	case SP_SIDE_UNDEF:
13632115b10SPawel Jakub Dawidek 		/*
13732115b10SPawel Jakub Dawidek 		 * If the first operation done by the caller is proto_recv(),
13801ab52c0SPawel Jakub Dawidek 		 * we assume this is the server.
13932115b10SPawel Jakub Dawidek 		 */
14032115b10SPawel Jakub Dawidek 		/* FALLTHROUGH */
14132115b10SPawel Jakub Dawidek 		spctx->sp_side = SP_SIDE_SERVER;
14232115b10SPawel Jakub Dawidek 		/* Close other end. */
14332115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[0]);
1442ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[0] = -1;
14532115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
1462ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
14732115b10SPawel Jakub Dawidek 		fd = spctx->sp_fd[1];
14832115b10SPawel Jakub Dawidek 		break;
14932115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
1502ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
15132115b10SPawel Jakub Dawidek 		fd = spctx->sp_fd[0];
15232115b10SPawel Jakub Dawidek 		break;
15332115b10SPawel Jakub Dawidek 	default:
1542ec483c5SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
15532115b10SPawel Jakub Dawidek 	}
15632115b10SPawel Jakub Dawidek 
157eea2deaaSPawel Jakub Dawidek 	/* Someone is just trying to decide about side. */
158eea2deaaSPawel Jakub Dawidek 	if (data == NULL)
159eea2deaaSPawel Jakub Dawidek 		return (0);
160eea2deaaSPawel Jakub Dawidek 
16101ab52c0SPawel Jakub Dawidek 	return (proto_common_recv(fd, data, size, fdp));
1628046c499SPawel Jakub Dawidek }
1638046c499SPawel Jakub Dawidek 
1648046c499SPawel Jakub Dawidek static int
16532115b10SPawel Jakub Dawidek sp_descriptor(const void *ctx)
16632115b10SPawel Jakub Dawidek {
16732115b10SPawel Jakub Dawidek 	const struct sp_ctx *spctx = ctx;
16832115b10SPawel Jakub Dawidek 
1692ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
1702ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
1712ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
17232115b10SPawel Jakub Dawidek 	    spctx->sp_side == SP_SIDE_SERVER);
17332115b10SPawel Jakub Dawidek 
17432115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
17532115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
1762ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
17732115b10SPawel Jakub Dawidek 		return (spctx->sp_fd[0]);
17832115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
1792ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
18032115b10SPawel Jakub Dawidek 		return (spctx->sp_fd[1]);
18132115b10SPawel Jakub Dawidek 	}
18232115b10SPawel Jakub Dawidek 
1832ec483c5SPawel Jakub Dawidek 	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
18432115b10SPawel Jakub Dawidek }
18532115b10SPawel Jakub Dawidek 
18632115b10SPawel Jakub Dawidek static void
18732115b10SPawel Jakub Dawidek sp_close(void *ctx)
18832115b10SPawel Jakub Dawidek {
18932115b10SPawel Jakub Dawidek 	struct sp_ctx *spctx = ctx;
19032115b10SPawel Jakub Dawidek 
1912ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx != NULL);
1922ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
19332115b10SPawel Jakub Dawidek 
19432115b10SPawel Jakub Dawidek 	switch (spctx->sp_side) {
19532115b10SPawel Jakub Dawidek 	case SP_SIDE_UNDEF:
1962ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
19732115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[0]);
1982ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[0] = -1;
1992ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
20032115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[1]);
2012ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[1] = -1;
20232115b10SPawel Jakub Dawidek 		break;
20332115b10SPawel Jakub Dawidek 	case SP_SIDE_CLIENT:
2042ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
20532115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[0]);
2062ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[0] = -1;
2072ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
20832115b10SPawel Jakub Dawidek 		break;
20932115b10SPawel Jakub Dawidek 	case SP_SIDE_SERVER:
2102ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
21132115b10SPawel Jakub Dawidek 		close(spctx->sp_fd[1]);
2122ec483c5SPawel Jakub Dawidek 		spctx->sp_fd[1] = -1;
2132ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
21432115b10SPawel Jakub Dawidek 		break;
21532115b10SPawel Jakub Dawidek 	default:
2162ec483c5SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
21732115b10SPawel Jakub Dawidek 	}
21832115b10SPawel Jakub Dawidek 
21932115b10SPawel Jakub Dawidek 	spctx->sp_magic = 0;
22032115b10SPawel Jakub Dawidek 	free(spctx);
22132115b10SPawel Jakub Dawidek }
22232115b10SPawel Jakub Dawidek 
223*e2eabb44SPawel Jakub Dawidek static struct proto sp_proto = {
224*e2eabb44SPawel Jakub Dawidek 	.prt_name = "socketpair",
225*e2eabb44SPawel Jakub Dawidek 	.prt_client = sp_client,
226*e2eabb44SPawel Jakub Dawidek 	.prt_send = sp_send,
227*e2eabb44SPawel Jakub Dawidek 	.prt_recv = sp_recv,
228*e2eabb44SPawel Jakub Dawidek 	.prt_descriptor = sp_descriptor,
229*e2eabb44SPawel Jakub Dawidek 	.prt_close = sp_close
23032115b10SPawel Jakub Dawidek };
23132115b10SPawel Jakub Dawidek 
23232115b10SPawel Jakub Dawidek static __constructor void
23332115b10SPawel Jakub Dawidek sp_ctor(void)
23432115b10SPawel Jakub Dawidek {
23532115b10SPawel Jakub Dawidek 
23650692f84SPawel Jakub Dawidek 	proto_register(&sp_proto, false);
23732115b10SPawel Jakub Dawidek }
238