xref: /freebsd-src/sbin/hastd/proto.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 
315571414cSPawel Jakub Dawidek #include <sys/types.h>
3232115b10SPawel Jakub Dawidek #include <sys/queue.h>
335571414cSPawel Jakub Dawidek #include <sys/socket.h>
3432115b10SPawel Jakub Dawidek 
3532115b10SPawel Jakub Dawidek #include <errno.h>
3632115b10SPawel Jakub Dawidek #include <stdint.h>
3701ab52c0SPawel Jakub Dawidek #include <string.h>
385ee17035SPawel Jakub Dawidek #include <strings.h>
3932115b10SPawel Jakub Dawidek 
402ec483c5SPawel Jakub Dawidek #include "pjdlog.h"
4132115b10SPawel Jakub Dawidek #include "proto.h"
4232115b10SPawel Jakub Dawidek #include "proto_impl.h"
4332115b10SPawel Jakub Dawidek 
4432115b10SPawel Jakub Dawidek #define	PROTO_CONN_MAGIC	0x907041c
4532115b10SPawel Jakub Dawidek struct proto_conn {
4632115b10SPawel Jakub Dawidek 	int		 pc_magic;
47e2eabb44SPawel Jakub Dawidek 	struct proto	*pc_proto;
4832115b10SPawel Jakub Dawidek 	void		*pc_ctx;
4932115b10SPawel Jakub Dawidek 	int		 pc_side;
5032115b10SPawel Jakub Dawidek #define	PROTO_SIDE_CLIENT		0
5132115b10SPawel Jakub Dawidek #define	PROTO_SIDE_SERVER_LISTEN	1
5232115b10SPawel Jakub Dawidek #define	PROTO_SIDE_SERVER_WORK		2
5332115b10SPawel Jakub Dawidek };
5432115b10SPawel Jakub Dawidek 
55e2eabb44SPawel Jakub Dawidek static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
5632115b10SPawel Jakub Dawidek 
5732115b10SPawel Jakub Dawidek void
58e2eabb44SPawel Jakub Dawidek proto_register(struct proto *proto, bool isdefault)
5932115b10SPawel Jakub Dawidek {
6050692f84SPawel Jakub Dawidek 	static bool seen_default = false;
6132115b10SPawel Jakub Dawidek 
6250692f84SPawel Jakub Dawidek 	if (!isdefault)
63e2eabb44SPawel Jakub Dawidek 		TAILQ_INSERT_HEAD(&protos, proto, prt_next);
6450692f84SPawel Jakub Dawidek 	else {
652ec483c5SPawel Jakub Dawidek 		PJDLOG_ASSERT(!seen_default);
6650692f84SPawel Jakub Dawidek 		seen_default = true;
67e2eabb44SPawel Jakub Dawidek 		TAILQ_INSERT_TAIL(&protos, proto, prt_next);
6850692f84SPawel Jakub Dawidek 	}
6932115b10SPawel Jakub Dawidek }
7032115b10SPawel Jakub Dawidek 
715ee17035SPawel Jakub Dawidek static struct proto_conn *
72e2eabb44SPawel Jakub Dawidek proto_alloc(struct proto *proto, int side)
735ee17035SPawel Jakub Dawidek {
745ee17035SPawel Jakub Dawidek 	struct proto_conn *conn;
755ee17035SPawel Jakub Dawidek 
765ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(proto != NULL);
775ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
785ee17035SPawel Jakub Dawidek 	    side == PROTO_SIDE_SERVER_LISTEN ||
795ee17035SPawel Jakub Dawidek 	    side == PROTO_SIDE_SERVER_WORK);
805ee17035SPawel Jakub Dawidek 
815ee17035SPawel Jakub Dawidek 	conn = malloc(sizeof(*conn));
825ee17035SPawel Jakub Dawidek 	if (conn != NULL) {
835ee17035SPawel Jakub Dawidek 		conn->pc_proto = proto;
845ee17035SPawel Jakub Dawidek 		conn->pc_side = side;
855ee17035SPawel Jakub Dawidek 		conn->pc_magic = PROTO_CONN_MAGIC;
865ee17035SPawel Jakub Dawidek 	}
875ee17035SPawel Jakub Dawidek 	return (conn);
885ee17035SPawel Jakub Dawidek }
895ee17035SPawel Jakub Dawidek 
905ee17035SPawel Jakub Dawidek static void
915ee17035SPawel Jakub Dawidek proto_free(struct proto_conn *conn)
925ee17035SPawel Jakub Dawidek {
935ee17035SPawel Jakub Dawidek 
945ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
955ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
965ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
975ee17035SPawel Jakub Dawidek 	    conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
985ee17035SPawel Jakub Dawidek 	    conn->pc_side == PROTO_SIDE_SERVER_WORK);
995ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
1005ee17035SPawel Jakub Dawidek 
1015ee17035SPawel Jakub Dawidek 	bzero(conn, sizeof(*conn));
1025ee17035SPawel Jakub Dawidek 	free(conn);
1035ee17035SPawel Jakub Dawidek }
1045ee17035SPawel Jakub Dawidek 
10532115b10SPawel Jakub Dawidek static int
1060b626a28SPawel Jakub Dawidek proto_common_setup(const char *srcaddr, const char *dstaddr,
1070b626a28SPawel Jakub Dawidek     struct proto_conn **connp, int side)
10832115b10SPawel Jakub Dawidek {
109e2eabb44SPawel Jakub Dawidek 	struct proto *proto;
11032115b10SPawel Jakub Dawidek 	struct proto_conn *conn;
11132115b10SPawel Jakub Dawidek 	void *ctx;
11232115b10SPawel Jakub Dawidek 	int ret;
11332115b10SPawel Jakub Dawidek 
1145ee17035SPawel Jakub Dawidek 	PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
1155ee17035SPawel Jakub Dawidek 	    side == PROTO_SIDE_SERVER_LISTEN);
11632115b10SPawel Jakub Dawidek 
117e2eabb44SPawel Jakub Dawidek 	TAILQ_FOREACH(proto, &protos, prt_next) {
1188dd94e23SPawel Jakub Dawidek 		if (side == PROTO_SIDE_CLIENT) {
119e2eabb44SPawel Jakub Dawidek 			if (proto->prt_client == NULL)
1208dd94e23SPawel Jakub Dawidek 				ret = -1;
1218dd94e23SPawel Jakub Dawidek 			else
122e2eabb44SPawel Jakub Dawidek 				ret = proto->prt_client(srcaddr, dstaddr, &ctx);
1238dd94e23SPawel Jakub Dawidek 		} else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
124e2eabb44SPawel Jakub Dawidek 			if (proto->prt_server == NULL)
1258dd94e23SPawel Jakub Dawidek 				ret = -1;
1268dd94e23SPawel Jakub Dawidek 			else
127e2eabb44SPawel Jakub Dawidek 				ret = proto->prt_server(dstaddr, &ctx);
1288dd94e23SPawel Jakub Dawidek 		}
12932115b10SPawel Jakub Dawidek 		/*
13032115b10SPawel Jakub Dawidek 		 * ret == 0  - success
1310b626a28SPawel Jakub Dawidek 		 * ret == -1 - dstaddr is not for this protocol
1324b85a12fSUlrich Spörlein 		 * ret > 0   - right protocol, but an error occurred
13332115b10SPawel Jakub Dawidek 		 */
13432115b10SPawel Jakub Dawidek 		if (ret >= 0)
13532115b10SPawel Jakub Dawidek 			break;
13632115b10SPawel Jakub Dawidek 	}
13732115b10SPawel Jakub Dawidek 	if (proto == NULL) {
13832115b10SPawel Jakub Dawidek 		/* Unrecognized address. */
13932115b10SPawel Jakub Dawidek 		errno = EINVAL;
14032115b10SPawel Jakub Dawidek 		return (-1);
14132115b10SPawel Jakub Dawidek 	}
14232115b10SPawel Jakub Dawidek 	if (ret > 0) {
1434b85a12fSUlrich Spörlein 		/* An error occurred. */
14432115b10SPawel Jakub Dawidek 		errno = ret;
14532115b10SPawel Jakub Dawidek 		return (-1);
14632115b10SPawel Jakub Dawidek 	}
1475ee17035SPawel Jakub Dawidek 	conn = proto_alloc(proto, side);
1485ee17035SPawel Jakub Dawidek 	if (conn == NULL) {
149e2eabb44SPawel Jakub Dawidek 		if (proto->prt_close != NULL)
150e2eabb44SPawel Jakub Dawidek 			proto->prt_close(ctx);
1515ee17035SPawel Jakub Dawidek 		errno = ENOMEM;
1525ee17035SPawel Jakub Dawidek 		return (-1);
1535ee17035SPawel Jakub Dawidek 	}
15432115b10SPawel Jakub Dawidek 	conn->pc_ctx = ctx;
15532115b10SPawel Jakub Dawidek 	*connp = conn;
1565ee17035SPawel Jakub Dawidek 
15732115b10SPawel Jakub Dawidek 	return (0);
15832115b10SPawel Jakub Dawidek }
15932115b10SPawel Jakub Dawidek 
16032115b10SPawel Jakub Dawidek int
1610b626a28SPawel Jakub Dawidek proto_client(const char *srcaddr, const char *dstaddr,
1620b626a28SPawel Jakub Dawidek     struct proto_conn **connp)
16332115b10SPawel Jakub Dawidek {
16432115b10SPawel Jakub Dawidek 
1650b626a28SPawel Jakub Dawidek 	return (proto_common_setup(srcaddr, dstaddr, connp, PROTO_SIDE_CLIENT));
16632115b10SPawel Jakub Dawidek }
16732115b10SPawel Jakub Dawidek 
16832115b10SPawel Jakub Dawidek int
1699d70b24bSPawel Jakub Dawidek proto_connect(struct proto_conn *conn, int timeout)
17032115b10SPawel Jakub Dawidek {
17132115b10SPawel Jakub Dawidek 	int ret;
17232115b10SPawel Jakub Dawidek 
1732ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
1742ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
1752ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
1762ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
177e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_connect != NULL);
1781c193322SPawel Jakub Dawidek 	PJDLOG_ASSERT(timeout >= -1);
17932115b10SPawel Jakub Dawidek 
180e2eabb44SPawel Jakub Dawidek 	ret = conn->pc_proto->prt_connect(conn->pc_ctx, timeout);
18132115b10SPawel Jakub Dawidek 	if (ret != 0) {
18232115b10SPawel Jakub Dawidek 		errno = ret;
18332115b10SPawel Jakub Dawidek 		return (-1);
18432115b10SPawel Jakub Dawidek 	}
18532115b10SPawel Jakub Dawidek 
18632115b10SPawel Jakub Dawidek 	return (0);
18732115b10SPawel Jakub Dawidek }
18832115b10SPawel Jakub Dawidek 
18932115b10SPawel Jakub Dawidek int
1901c193322SPawel Jakub Dawidek proto_connect_wait(struct proto_conn *conn, int timeout)
1911c193322SPawel Jakub Dawidek {
1921c193322SPawel Jakub Dawidek 	int ret;
1931c193322SPawel Jakub Dawidek 
1941c193322SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
1951c193322SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
1961c193322SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
1971c193322SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
198e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_connect_wait != NULL);
1991c193322SPawel Jakub Dawidek 	PJDLOG_ASSERT(timeout >= 0);
2001c193322SPawel Jakub Dawidek 
201e2eabb44SPawel Jakub Dawidek 	ret = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
2021c193322SPawel Jakub Dawidek 	if (ret != 0) {
2031c193322SPawel Jakub Dawidek 		errno = ret;
2041c193322SPawel Jakub Dawidek 		return (-1);
2051c193322SPawel Jakub Dawidek 	}
2061c193322SPawel Jakub Dawidek 
2071c193322SPawel Jakub Dawidek 	return (0);
2081c193322SPawel Jakub Dawidek }
2091c193322SPawel Jakub Dawidek 
2101c193322SPawel Jakub Dawidek int
21132115b10SPawel Jakub Dawidek proto_server(const char *addr, struct proto_conn **connp)
21232115b10SPawel Jakub Dawidek {
21332115b10SPawel Jakub Dawidek 
2140b626a28SPawel Jakub Dawidek 	return (proto_common_setup(NULL, addr, connp, PROTO_SIDE_SERVER_LISTEN));
21532115b10SPawel Jakub Dawidek }
21632115b10SPawel Jakub Dawidek 
21732115b10SPawel Jakub Dawidek int
21832115b10SPawel Jakub Dawidek proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
21932115b10SPawel Jakub Dawidek {
22032115b10SPawel Jakub Dawidek 	struct proto_conn *newconn;
22132115b10SPawel Jakub Dawidek 	int ret;
22232115b10SPawel Jakub Dawidek 
2232ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
2242ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
2252ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
2262ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
227e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_accept != NULL);
22832115b10SPawel Jakub Dawidek 
2295ee17035SPawel Jakub Dawidek 	newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
23032115b10SPawel Jakub Dawidek 	if (newconn == NULL)
23132115b10SPawel Jakub Dawidek 		return (-1);
23232115b10SPawel Jakub Dawidek 
233e2eabb44SPawel Jakub Dawidek 	ret = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
23432115b10SPawel Jakub Dawidek 	if (ret != 0) {
2355ee17035SPawel Jakub Dawidek 		proto_free(newconn);
23632115b10SPawel Jakub Dawidek 		errno = ret;
23732115b10SPawel Jakub Dawidek 		return (-1);
23832115b10SPawel Jakub Dawidek 	}
23932115b10SPawel Jakub Dawidek 
24032115b10SPawel Jakub Dawidek 	*newconnp = newconn;
24132115b10SPawel Jakub Dawidek 
24232115b10SPawel Jakub Dawidek 	return (0);
24332115b10SPawel Jakub Dawidek }
24432115b10SPawel Jakub Dawidek 
24532115b10SPawel Jakub Dawidek int
246b938cdccSPawel Jakub Dawidek proto_send(const struct proto_conn *conn, const void *data, size_t size)
24732115b10SPawel Jakub Dawidek {
24832115b10SPawel Jakub Dawidek 	int ret;
24932115b10SPawel Jakub Dawidek 
2502ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
2512ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
2522ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
253e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
25432115b10SPawel Jakub Dawidek 
255e2eabb44SPawel Jakub Dawidek 	ret = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
25632115b10SPawel Jakub Dawidek 	if (ret != 0) {
25732115b10SPawel Jakub Dawidek 		errno = ret;
25832115b10SPawel Jakub Dawidek 		return (-1);
25932115b10SPawel Jakub Dawidek 	}
26032115b10SPawel Jakub Dawidek 	return (0);
26132115b10SPawel Jakub Dawidek }
26232115b10SPawel Jakub Dawidek 
26332115b10SPawel Jakub Dawidek int
264b938cdccSPawel Jakub Dawidek proto_recv(const struct proto_conn *conn, void *data, size_t size)
26532115b10SPawel Jakub Dawidek {
26632115b10SPawel Jakub Dawidek 	int ret;
26732115b10SPawel Jakub Dawidek 
2682ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
2692ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
2702ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
271e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
27232115b10SPawel Jakub Dawidek 
273e2eabb44SPawel Jakub Dawidek 	ret = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
27432115b10SPawel Jakub Dawidek 	if (ret != 0) {
27532115b10SPawel Jakub Dawidek 		errno = ret;
27632115b10SPawel Jakub Dawidek 		return (-1);
27732115b10SPawel Jakub Dawidek 	}
27832115b10SPawel Jakub Dawidek 	return (0);
27932115b10SPawel Jakub Dawidek }
28032115b10SPawel Jakub Dawidek 
28132115b10SPawel Jakub Dawidek int
28201ab52c0SPawel Jakub Dawidek proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
2838046c499SPawel Jakub Dawidek {
28401ab52c0SPawel Jakub Dawidek 	const char *protoname;
28501ab52c0SPawel Jakub Dawidek 	int ret, fd;
2868046c499SPawel Jakub Dawidek 
2878046c499SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
2888046c499SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
2898046c499SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
290e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
29101ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(mconn != NULL);
29201ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(mconn->pc_magic == PROTO_CONN_MAGIC);
29301ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(mconn->pc_proto != NULL);
29401ab52c0SPawel Jakub Dawidek 	fd = proto_descriptor(mconn);
29501ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
296e2eabb44SPawel Jakub Dawidek 	protoname = mconn->pc_proto->prt_name;
29701ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(protoname != NULL);
2988046c499SPawel Jakub Dawidek 
2994d70e06fSMikolaj Golub 	ret = conn->pc_proto->prt_send(conn->pc_ctx,
3004d70e06fSMikolaj Golub 	    (const unsigned char *)protoname, strlen(protoname) + 1, fd);
30101ab52c0SPawel Jakub Dawidek 	proto_close(mconn);
3028046c499SPawel Jakub Dawidek 	if (ret != 0) {
3038046c499SPawel Jakub Dawidek 		errno = ret;
3048046c499SPawel Jakub Dawidek 		return (-1);
3058046c499SPawel Jakub Dawidek 	}
3068046c499SPawel Jakub Dawidek 	return (0);
3078046c499SPawel Jakub Dawidek }
3088046c499SPawel Jakub Dawidek 
3098046c499SPawel Jakub Dawidek int
31001ab52c0SPawel Jakub Dawidek proto_connection_recv(const struct proto_conn *conn, bool client,
31101ab52c0SPawel Jakub Dawidek     struct proto_conn **newconnp)
3128046c499SPawel Jakub Dawidek {
31301ab52c0SPawel Jakub Dawidek 	char protoname[128];
314e2eabb44SPawel Jakub Dawidek 	struct proto *proto;
31501ab52c0SPawel Jakub Dawidek 	struct proto_conn *newconn;
31601ab52c0SPawel Jakub Dawidek 	int ret, fd;
3178046c499SPawel Jakub Dawidek 
3188046c499SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
3198046c499SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
3208046c499SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
321e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
32201ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(newconnp != NULL);
3238046c499SPawel Jakub Dawidek 
32401ab52c0SPawel Jakub Dawidek 	bzero(protoname, sizeof(protoname));
32501ab52c0SPawel Jakub Dawidek 
3264d70e06fSMikolaj Golub 	ret = conn->pc_proto->prt_recv(conn->pc_ctx, (unsigned char *)protoname,
32701ab52c0SPawel Jakub Dawidek 	    sizeof(protoname) - 1, &fd);
3288046c499SPawel Jakub Dawidek 	if (ret != 0) {
3298046c499SPawel Jakub Dawidek 		errno = ret;
3308046c499SPawel Jakub Dawidek 		return (-1);
3318046c499SPawel Jakub Dawidek 	}
33201ab52c0SPawel Jakub Dawidek 
33301ab52c0SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
33401ab52c0SPawel Jakub Dawidek 
335e2eabb44SPawel Jakub Dawidek 	TAILQ_FOREACH(proto, &protos, prt_next) {
336e2eabb44SPawel Jakub Dawidek 		if (strcmp(proto->prt_name, protoname) == 0)
33701ab52c0SPawel Jakub Dawidek 			break;
33801ab52c0SPawel Jakub Dawidek 	}
33901ab52c0SPawel Jakub Dawidek 	if (proto == NULL) {
34001ab52c0SPawel Jakub Dawidek 		errno = EINVAL;
34101ab52c0SPawel Jakub Dawidek 		return (-1);
34201ab52c0SPawel Jakub Dawidek 	}
34301ab52c0SPawel Jakub Dawidek 
34401ab52c0SPawel Jakub Dawidek 	newconn = proto_alloc(proto,
34501ab52c0SPawel Jakub Dawidek 	    client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
34601ab52c0SPawel Jakub Dawidek 	if (newconn == NULL)
34701ab52c0SPawel Jakub Dawidek 		return (-1);
348e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
349e2eabb44SPawel Jakub Dawidek 	ret = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
35001ab52c0SPawel Jakub Dawidek 	if (ret != 0) {
35101ab52c0SPawel Jakub Dawidek 		proto_free(newconn);
35201ab52c0SPawel Jakub Dawidek 		errno = ret;
35301ab52c0SPawel Jakub Dawidek 		return (-1);
35401ab52c0SPawel Jakub Dawidek 	}
35501ab52c0SPawel Jakub Dawidek 
35601ab52c0SPawel Jakub Dawidek 	*newconnp = newconn;
35701ab52c0SPawel Jakub Dawidek 
3588046c499SPawel Jakub Dawidek 	return (0);
3598046c499SPawel Jakub Dawidek }
3608046c499SPawel Jakub Dawidek 
3618046c499SPawel Jakub Dawidek int
36232115b10SPawel Jakub Dawidek proto_descriptor(const struct proto_conn *conn)
36332115b10SPawel Jakub Dawidek {
36432115b10SPawel Jakub Dawidek 
3652ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
3662ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
3672ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
368e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_descriptor != NULL);
36932115b10SPawel Jakub Dawidek 
370e2eabb44SPawel Jakub Dawidek 	return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
37132115b10SPawel Jakub Dawidek }
37232115b10SPawel Jakub Dawidek 
37332115b10SPawel Jakub Dawidek bool
37432115b10SPawel Jakub Dawidek proto_address_match(const struct proto_conn *conn, const char *addr)
37532115b10SPawel Jakub Dawidek {
37632115b10SPawel Jakub Dawidek 
3772ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
3782ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
3792ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
380e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_address_match != NULL);
38132115b10SPawel Jakub Dawidek 
382e2eabb44SPawel Jakub Dawidek 	return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
38332115b10SPawel Jakub Dawidek }
38432115b10SPawel Jakub Dawidek 
38532115b10SPawel Jakub Dawidek void
38632115b10SPawel Jakub Dawidek proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
38732115b10SPawel Jakub Dawidek {
38832115b10SPawel Jakub Dawidek 
3892ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
3902ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
3912ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
392e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_local_address != NULL);
39332115b10SPawel Jakub Dawidek 
394e2eabb44SPawel Jakub Dawidek 	conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
39532115b10SPawel Jakub Dawidek }
39632115b10SPawel Jakub Dawidek 
39732115b10SPawel Jakub Dawidek void
39832115b10SPawel Jakub Dawidek proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
39932115b10SPawel Jakub Dawidek {
40032115b10SPawel Jakub Dawidek 
4012ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
4022ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
4032ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
404e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_remote_address != NULL);
40532115b10SPawel Jakub Dawidek 
406e2eabb44SPawel Jakub Dawidek 	conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
40732115b10SPawel Jakub Dawidek }
40832115b10SPawel Jakub Dawidek 
4095571414cSPawel Jakub Dawidek int
4105571414cSPawel Jakub Dawidek proto_timeout(const struct proto_conn *conn, int timeout)
4115571414cSPawel Jakub Dawidek {
4125571414cSPawel Jakub Dawidek 	struct timeval tv;
4135571414cSPawel Jakub Dawidek 	int fd;
4145571414cSPawel Jakub Dawidek 
4152ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
4162ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
4172ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
4185571414cSPawel Jakub Dawidek 
4195571414cSPawel Jakub Dawidek 	fd = proto_descriptor(conn);
4202b1b224dSPawel Jakub Dawidek 	if (fd == -1)
4215571414cSPawel Jakub Dawidek 		return (-1);
4225571414cSPawel Jakub Dawidek 
4235571414cSPawel Jakub Dawidek 	tv.tv_sec = timeout;
4245571414cSPawel Jakub Dawidek 	tv.tv_usec = 0;
4252b1b224dSPawel Jakub Dawidek 	if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1)
4265571414cSPawel Jakub Dawidek 		return (-1);
4272b1b224dSPawel Jakub Dawidek 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
4285571414cSPawel Jakub Dawidek 		return (-1);
4295571414cSPawel Jakub Dawidek 
4305571414cSPawel Jakub Dawidek 	return (0);
4315571414cSPawel Jakub Dawidek }
4325571414cSPawel Jakub Dawidek 
43332115b10SPawel Jakub Dawidek void
43432115b10SPawel Jakub Dawidek proto_close(struct proto_conn *conn)
43532115b10SPawel Jakub Dawidek {
43632115b10SPawel Jakub Dawidek 
4372ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn != NULL);
4382ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
4392ec483c5SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto != NULL);
440e2eabb44SPawel Jakub Dawidek 	PJDLOG_ASSERT(conn->pc_proto->prt_close != NULL);
44132115b10SPawel Jakub Dawidek 
442e2eabb44SPawel Jakub Dawidek 	conn->pc_proto->prt_close(conn->pc_ctx);
4435ee17035SPawel Jakub Dawidek 	proto_free(conn);
44432115b10SPawel Jakub Dawidek }
445