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