xref: /freebsd/sbin/hastd/hast_proto.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
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
51fee97b0SPawel Jakub Dawidek  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
632115b10SPawel Jakub Dawidek  * All rights reserved.
732115b10SPawel Jakub Dawidek  *
832115b10SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
932115b10SPawel Jakub Dawidek  * the FreeBSD Foundation.
1032115b10SPawel Jakub Dawidek  *
1132115b10SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1232115b10SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1332115b10SPawel Jakub Dawidek  * are met:
1432115b10SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1532115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1632115b10SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1732115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1832115b10SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1932115b10SPawel Jakub Dawidek  *
2032115b10SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
2132115b10SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2232115b10SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2332115b10SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2432115b10SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2532115b10SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2632115b10SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2732115b10SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2832115b10SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2932115b10SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3032115b10SPawel Jakub Dawidek  * SUCH DAMAGE.
3132115b10SPawel Jakub Dawidek  */
3232115b10SPawel Jakub Dawidek 
3332115b10SPawel Jakub Dawidek #include <sys/cdefs.h>
3432115b10SPawel Jakub Dawidek #include <sys/endian.h>
3532115b10SPawel Jakub Dawidek 
3632115b10SPawel Jakub Dawidek #include <errno.h>
3732115b10SPawel Jakub Dawidek #include <strings.h>
3832115b10SPawel Jakub Dawidek 
3932115b10SPawel Jakub Dawidek #include <hast.h>
4032115b10SPawel Jakub Dawidek #include <ebuf.h>
4132115b10SPawel Jakub Dawidek #include <nv.h>
4232115b10SPawel Jakub Dawidek #include <pjdlog.h>
4332115b10SPawel Jakub Dawidek #include <proto.h>
4432115b10SPawel Jakub Dawidek 
451fee97b0SPawel Jakub Dawidek #include "hast_checksum.h"
468cd3d45aSPawel Jakub Dawidek #include "hast_compression.h"
4732115b10SPawel Jakub Dawidek #include "hast_proto.h"
4832115b10SPawel Jakub Dawidek 
4932115b10SPawel Jakub Dawidek struct hast_main_header {
5032115b10SPawel Jakub Dawidek 	/* Protocol version. */
5132115b10SPawel Jakub Dawidek 	uint8_t		version;
5232115b10SPawel Jakub Dawidek 	/* Size of nv headers. */
5332115b10SPawel Jakub Dawidek 	uint32_t	size;
5432115b10SPawel Jakub Dawidek } __packed;
5532115b10SPawel Jakub Dawidek 
56b938cdccSPawel Jakub Dawidek typedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **,
57b938cdccSPawel Jakub Dawidek     size_t *, bool *);
58b938cdccSPawel Jakub Dawidek typedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **,
59b938cdccSPawel Jakub Dawidek     size_t *, bool *);
6032115b10SPawel Jakub Dawidek 
6132115b10SPawel Jakub Dawidek struct hast_pipe_stage {
6232115b10SPawel Jakub Dawidek 	const char	*hps_name;
6332115b10SPawel Jakub Dawidek 	hps_send_t	*hps_send;
6432115b10SPawel Jakub Dawidek 	hps_recv_t	*hps_recv;
6532115b10SPawel Jakub Dawidek };
6632115b10SPawel Jakub Dawidek 
6732115b10SPawel Jakub Dawidek static struct hast_pipe_stage pipeline[] = {
688cd3d45aSPawel Jakub Dawidek 	{ "compression", compression_send, compression_recv },
6932115b10SPawel Jakub Dawidek 	{ "checksum", checksum_send, checksum_recv }
7032115b10SPawel Jakub Dawidek };
7132115b10SPawel Jakub Dawidek 
7232115b10SPawel Jakub Dawidek /*
7332115b10SPawel Jakub Dawidek  * Send the given nv structure via conn.
7432115b10SPawel Jakub Dawidek  * We keep headers in nv structure and pass data in separate argument.
7532115b10SPawel Jakub Dawidek  * There can be no data at all (data is NULL then).
7632115b10SPawel Jakub Dawidek  */
7732115b10SPawel Jakub Dawidek int
hast_proto_send(const struct hast_resource * res,struct proto_conn * conn,struct nv * nv,const void * data,size_t size)78b938cdccSPawel Jakub Dawidek hast_proto_send(const struct hast_resource *res, struct proto_conn *conn,
7932115b10SPawel Jakub Dawidek     struct nv *nv, const void *data, size_t size)
8032115b10SPawel Jakub Dawidek {
8132115b10SPawel Jakub Dawidek 	struct hast_main_header hdr;
8232115b10SPawel Jakub Dawidek 	struct ebuf *eb;
8332115b10SPawel Jakub Dawidek 	bool freedata;
8432115b10SPawel Jakub Dawidek 	void *dptr, *hptr;
8532115b10SPawel Jakub Dawidek 	size_t hsize;
8632115b10SPawel Jakub Dawidek 	int ret;
8732115b10SPawel Jakub Dawidek 
8832115b10SPawel Jakub Dawidek 	dptr = (void *)(uintptr_t)data;
8932115b10SPawel Jakub Dawidek 	freedata = false;
9032115b10SPawel Jakub Dawidek 	ret = -1;
9132115b10SPawel Jakub Dawidek 
9232115b10SPawel Jakub Dawidek 	if (data != NULL) {
9332115b10SPawel Jakub Dawidek 		unsigned int ii;
9432115b10SPawel Jakub Dawidek 
9532115b10SPawel Jakub Dawidek 		for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]);
9632115b10SPawel Jakub Dawidek 		    ii++) {
971fee97b0SPawel Jakub Dawidek 			(void)pipeline[ii].hps_send(res, nv, &dptr, &size,
9832115b10SPawel Jakub Dawidek 			    &freedata);
9932115b10SPawel Jakub Dawidek 		}
10032115b10SPawel Jakub Dawidek 		nv_add_uint32(nv, size, "size");
10132115b10SPawel Jakub Dawidek 		if (nv_error(nv) != 0) {
10232115b10SPawel Jakub Dawidek 			errno = nv_error(nv);
10332115b10SPawel Jakub Dawidek 			goto end;
10432115b10SPawel Jakub Dawidek 		}
10532115b10SPawel Jakub Dawidek 	}
10632115b10SPawel Jakub Dawidek 
10732115b10SPawel Jakub Dawidek 	eb = nv_hton(nv);
10832115b10SPawel Jakub Dawidek 	if (eb == NULL)
10932115b10SPawel Jakub Dawidek 		goto end;
11032115b10SPawel Jakub Dawidek 
111d6e636c9SPawel Jakub Dawidek 	hdr.version = res != NULL ? res->hr_version : HAST_PROTO_VERSION;
11232115b10SPawel Jakub Dawidek 	hdr.size = htole32((uint32_t)ebuf_size(eb));
1132b1b224dSPawel Jakub Dawidek 	if (ebuf_add_head(eb, &hdr, sizeof(hdr)) == -1)
11432115b10SPawel Jakub Dawidek 		goto end;
11532115b10SPawel Jakub Dawidek 
11632115b10SPawel Jakub Dawidek 	hptr = ebuf_data(eb, &hsize);
1172b1b224dSPawel Jakub Dawidek 	if (proto_send(conn, hptr, hsize) == -1)
11832115b10SPawel Jakub Dawidek 		goto end;
1192b1b224dSPawel Jakub Dawidek 	if (data != NULL && proto_send(conn, dptr, size) == -1)
12032115b10SPawel Jakub Dawidek 		goto end;
12132115b10SPawel Jakub Dawidek 
12232115b10SPawel Jakub Dawidek 	ret = 0;
12332115b10SPawel Jakub Dawidek end:
12432115b10SPawel Jakub Dawidek 	if (freedata)
12532115b10SPawel Jakub Dawidek 		free(dptr);
12632115b10SPawel Jakub Dawidek 	return (ret);
12732115b10SPawel Jakub Dawidek }
12832115b10SPawel Jakub Dawidek 
12932115b10SPawel Jakub Dawidek int
hast_proto_recv_hdr(const struct proto_conn * conn,struct nv ** nvp)130b938cdccSPawel Jakub Dawidek hast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp)
13132115b10SPawel Jakub Dawidek {
13232115b10SPawel Jakub Dawidek 	struct hast_main_header hdr;
13332115b10SPawel Jakub Dawidek 	struct nv *nv;
13432115b10SPawel Jakub Dawidek 	struct ebuf *eb;
13532115b10SPawel Jakub Dawidek 	void *hptr;
13632115b10SPawel Jakub Dawidek 
13732115b10SPawel Jakub Dawidek 	eb = NULL;
13832115b10SPawel Jakub Dawidek 	nv = NULL;
13932115b10SPawel Jakub Dawidek 
1402b1b224dSPawel Jakub Dawidek 	if (proto_recv(conn, &hdr, sizeof(hdr)) == -1)
14132115b10SPawel Jakub Dawidek 		goto fail;
14232115b10SPawel Jakub Dawidek 
143d6e636c9SPawel Jakub Dawidek 	if (hdr.version > HAST_PROTO_VERSION) {
14432115b10SPawel Jakub Dawidek 		errno = ERPCMISMATCH;
14532115b10SPawel Jakub Dawidek 		goto fail;
14632115b10SPawel Jakub Dawidek 	}
14732115b10SPawel Jakub Dawidek 
14832115b10SPawel Jakub Dawidek 	hdr.size = le32toh(hdr.size);
14932115b10SPawel Jakub Dawidek 
15032115b10SPawel Jakub Dawidek 	eb = ebuf_alloc(hdr.size);
15132115b10SPawel Jakub Dawidek 	if (eb == NULL)
15232115b10SPawel Jakub Dawidek 		goto fail;
1532b1b224dSPawel Jakub Dawidek 	if (ebuf_add_tail(eb, NULL, hdr.size) == -1)
15432115b10SPawel Jakub Dawidek 		goto fail;
15532115b10SPawel Jakub Dawidek 	hptr = ebuf_data(eb, NULL);
156adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(hptr != NULL);
1572b1b224dSPawel Jakub Dawidek 	if (proto_recv(conn, hptr, hdr.size) == -1)
15832115b10SPawel Jakub Dawidek 		goto fail;
15932115b10SPawel Jakub Dawidek 	nv = nv_ntoh(eb);
16032115b10SPawel Jakub Dawidek 	if (nv == NULL)
16132115b10SPawel Jakub Dawidek 		goto fail;
16232115b10SPawel Jakub Dawidek 
16332115b10SPawel Jakub Dawidek 	*nvp = nv;
16432115b10SPawel Jakub Dawidek 	return (0);
16532115b10SPawel Jakub Dawidek fail:
166a58b195eSPawel Jakub Dawidek 	if (eb != NULL)
16732115b10SPawel Jakub Dawidek 		ebuf_free(eb);
16832115b10SPawel Jakub Dawidek 	return (-1);
16932115b10SPawel Jakub Dawidek }
17032115b10SPawel Jakub Dawidek 
17132115b10SPawel Jakub Dawidek int
hast_proto_recv_data(const struct hast_resource * res,struct proto_conn * conn,struct nv * nv,void * data,size_t size)172b938cdccSPawel Jakub Dawidek hast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn,
17332115b10SPawel Jakub Dawidek     struct nv *nv, void *data, size_t size)
17432115b10SPawel Jakub Dawidek {
17532115b10SPawel Jakub Dawidek 	unsigned int ii;
17632115b10SPawel Jakub Dawidek 	bool freedata;
17732115b10SPawel Jakub Dawidek 	size_t dsize;
17832115b10SPawel Jakub Dawidek 	void *dptr;
17932115b10SPawel Jakub Dawidek 	int ret;
18032115b10SPawel Jakub Dawidek 
181adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(data != NULL);
182adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(size > 0);
18332115b10SPawel Jakub Dawidek 
18432115b10SPawel Jakub Dawidek 	ret = -1;
18532115b10SPawel Jakub Dawidek 	freedata = false;
18632115b10SPawel Jakub Dawidek 	dptr = data;
18732115b10SPawel Jakub Dawidek 
18832115b10SPawel Jakub Dawidek 	dsize = nv_get_uint32(nv, "size");
1891d521b1cSMikolaj Golub 	if (dsize > size) {
1901d521b1cSMikolaj Golub 		errno = EINVAL;
1911d521b1cSMikolaj Golub 		goto end;
1921d521b1cSMikolaj Golub 	} else if (dsize == 0) {
19332115b10SPawel Jakub Dawidek 		(void)nv_set_error(nv, 0);
1941d521b1cSMikolaj Golub 	} else {
1952b1b224dSPawel Jakub Dawidek 		if (proto_recv(conn, data, dsize) == -1)
19632115b10SPawel Jakub Dawidek 			goto end;
19732115b10SPawel Jakub Dawidek 		for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0;
19832115b10SPawel Jakub Dawidek 		    ii--) {
19932115b10SPawel Jakub Dawidek 			ret = pipeline[ii - 1].hps_recv(res, nv, &dptr,
20032115b10SPawel Jakub Dawidek 			    &dsize, &freedata);
20132115b10SPawel Jakub Dawidek 			if (ret == -1)
20232115b10SPawel Jakub Dawidek 				goto end;
20332115b10SPawel Jakub Dawidek 		}
20432115b10SPawel Jakub Dawidek 		ret = -1;
2051fee97b0SPawel Jakub Dawidek 		if (dsize > size) {
2061fee97b0SPawel Jakub Dawidek 			errno = EINVAL;
20732115b10SPawel Jakub Dawidek 			goto end;
2081fee97b0SPawel Jakub Dawidek 		}
20932115b10SPawel Jakub Dawidek 		if (dptr != data)
21032115b10SPawel Jakub Dawidek 			bcopy(dptr, data, dsize);
21132115b10SPawel Jakub Dawidek 	}
21232115b10SPawel Jakub Dawidek 
21332115b10SPawel Jakub Dawidek 	ret = 0;
21432115b10SPawel Jakub Dawidek end:
21532115b10SPawel Jakub Dawidek 	if (freedata)
21632115b10SPawel Jakub Dawidek 		free(dptr);
21732115b10SPawel Jakub Dawidek 	return (ret);
21832115b10SPawel Jakub Dawidek }
219