hast_proto.c revision 256281
176195Sbrian/*-
276195Sbrian * Copyright (c) 2009-2010 The FreeBSD Foundation
378412Sbrian * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
478412Sbrian * All rights reserved.
578412Sbrian *
676195Sbrian * This software was developed by Pawel Jakub Dawidek under sponsorship from
776195Sbrian * the FreeBSD Foundation.
876195Sbrian *
976195Sbrian * Redistribution and use in source and binary forms, with or without
1076195Sbrian * modification, are permitted provided that the following conditions
1176195Sbrian * are met:
1276195Sbrian * 1. Redistributions of source code must retain the above copyright
1376195Sbrian *    notice, this list of conditions and the following disclaimer.
1476195Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1576195Sbrian *    notice, this list of conditions and the following disclaimer in the
1676195Sbrian *    documentation and/or other materials provided with the distribution.
1776195Sbrian *
1876195Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1976195Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2076195Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2176195Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2276195Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2376195Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2476195Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2576195Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2676195Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2776195Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2876195Sbrian * SUCH DAMAGE.
2976195Sbrian */
3076195Sbrian
3176195Sbrian#include <sys/cdefs.h>
3276195Sbrian__FBSDID("$FreeBSD: stable/10/sbin/hastd/hast_proto.c 246922 2013-02-17 21:12:34Z pjd $");
3376195Sbrian
3476195Sbrian#include <sys/endian.h>
3576195Sbrian
3676195Sbrian#include <errno.h>
3776195Sbrian#include <strings.h>
3876195Sbrian
3976195Sbrian#include <hast.h>
4076195Sbrian#include <ebuf.h>
4176195Sbrian#include <nv.h>
4276195Sbrian#include <pjdlog.h>
4376327Sbrian#include <proto.h>
4476327Sbrian
4576196Sbrian#ifdef HAVE_CRYPTO
4676195Sbrian#include "hast_checksum.h"
4776196Sbrian#endif
4876195Sbrian#include "hast_compression.h"
4976195Sbrian#include "hast_proto.h"
5076195Sbrian
5176195Sbrianstruct hast_main_header {
5276195Sbrian	/* Protocol version. */
5376195Sbrian	uint8_t		version;
5476195Sbrian	/* Size of nv headers. */
5576195Sbrian	uint32_t	size;
5676195Sbrian} __packed;
5776195Sbrian
5876195Sbriantypedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **,
5976195Sbrian    size_t *, bool *);
6076195Sbriantypedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **,
6176195Sbrian    size_t *, bool *);
6276195Sbrian
6376195Sbrianstruct hast_pipe_stage {
6476195Sbrian	const char	*hps_name;
6576195Sbrian	hps_send_t	*hps_send;
6676195Sbrian	hps_recv_t	*hps_recv;
6776195Sbrian};
6876195Sbrian
6976195Sbrianstatic struct hast_pipe_stage pipeline[] = {
7076195Sbrian	{ "compression", compression_send, compression_recv },
7176195Sbrian#ifdef HAVE_CRYPTO
7276195Sbrian	{ "checksum", checksum_send, checksum_recv }
7376195Sbrian#endif
7476195Sbrian};
7576195Sbrian
7676195Sbrian/*
7776195Sbrian * Send the given nv structure via conn.
7876195Sbrian * We keep headers in nv structure and pass data in separate argument.
7976195Sbrian * There can be no data at all (data is NULL then).
8076195Sbrian */
8176195Sbrianint
8276195Sbrianhast_proto_send(const struct hast_resource *res, struct proto_conn *conn,
8376195Sbrian    struct nv *nv, const void *data, size_t size)
8476195Sbrian{
8576195Sbrian	struct hast_main_header hdr;
8676195Sbrian	struct ebuf *eb;
8776195Sbrian	bool freedata;
8876195Sbrian	void *dptr, *hptr;
8976195Sbrian	size_t hsize;
9076195Sbrian	int ret;
9176195Sbrian
9276195Sbrian	dptr = (void *)(uintptr_t)data;
9376195Sbrian	freedata = false;
9476195Sbrian	ret = -1;
9576195Sbrian
9676195Sbrian	if (data != NULL) {
9776195Sbrian		unsigned int ii;
9876195Sbrian
9976195Sbrian		for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]);
10076195Sbrian		    ii++) {
10176195Sbrian			(void)pipeline[ii].hps_send(res, nv, &dptr, &size,
10276195Sbrian			    &freedata);
10376195Sbrian		}
10476195Sbrian		nv_add_uint32(nv, size, "size");
10576195Sbrian		if (nv_error(nv) != 0) {
10676195Sbrian			errno = nv_error(nv);
10776195Sbrian			goto end;
10876195Sbrian		}
10976195Sbrian	}
11076195Sbrian
11176195Sbrian	eb = nv_hton(nv);
11276195Sbrian	if (eb == NULL)
11376195Sbrian		goto end;
11476195Sbrian
11576195Sbrian	hdr.version = res != NULL ? res->hr_version : HAST_PROTO_VERSION;
11676195Sbrian	hdr.size = htole32((uint32_t)ebuf_size(eb));
11776195Sbrian	if (ebuf_add_head(eb, &hdr, sizeof(hdr)) == -1)
11876195Sbrian		goto end;
11976195Sbrian
12076195Sbrian	hptr = ebuf_data(eb, &hsize);
12176195Sbrian	if (proto_send(conn, hptr, hsize) == -1)
12276195Sbrian		goto end;
12376195Sbrian	if (data != NULL && proto_send(conn, dptr, size) == -1)
12476195Sbrian		goto end;
12576195Sbrian
12676195Sbrian	ret = 0;
12776195Sbrianend:
12876195Sbrian	if (freedata)
12976195Sbrian		free(dptr);
13076195Sbrian	return (ret);
13176195Sbrian}
13276195Sbrian
13376195Sbrianint
13476195Sbrianhast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp)
13576195Sbrian{
13676195Sbrian	struct hast_main_header hdr;
13776195Sbrian	struct nv *nv;
13876195Sbrian	struct ebuf *eb;
13976195Sbrian	void *hptr;
14076195Sbrian
14176195Sbrian	eb = NULL;
14276195Sbrian	nv = NULL;
14376195Sbrian
14476195Sbrian	if (proto_recv(conn, &hdr, sizeof(hdr)) == -1)
14576195Sbrian		goto fail;
14676195Sbrian
14776195Sbrian	if (hdr.version > HAST_PROTO_VERSION) {
14876195Sbrian		errno = ERPCMISMATCH;
14976195Sbrian		goto fail;
15076195Sbrian	}
15176195Sbrian
15276195Sbrian	hdr.size = le32toh(hdr.size);
15376195Sbrian
15476195Sbrian	eb = ebuf_alloc(hdr.size);
15576195Sbrian	if (eb == NULL)
15676195Sbrian		goto fail;
15776195Sbrian	if (ebuf_add_tail(eb, NULL, hdr.size) == -1)
15876195Sbrian		goto fail;
15976195Sbrian	hptr = ebuf_data(eb, NULL);
16076195Sbrian	PJDLOG_ASSERT(hptr != NULL);
16176195Sbrian	if (proto_recv(conn, hptr, hdr.size) == -1)
16276195Sbrian		goto fail;
16376195Sbrian	nv = nv_ntoh(eb);
16476195Sbrian	if (nv == NULL)
16576195Sbrian		goto fail;
16676195Sbrian
16776195Sbrian	*nvp = nv;
16876195Sbrian	return (0);
16976195Sbrianfail:
17076195Sbrian	if (eb != NULL)
17176195Sbrian		ebuf_free(eb);
17276195Sbrian	return (-1);
17376195Sbrian}
17476195Sbrian
17576195Sbrianint
17676195Sbrianhast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn,
17776195Sbrian    struct nv *nv, void *data, size_t size)
17876195Sbrian{
17976195Sbrian	unsigned int ii;
18076195Sbrian	bool freedata;
18176195Sbrian	size_t dsize;
18276195Sbrian	void *dptr;
18376195Sbrian	int ret;
18476195Sbrian
18576195Sbrian	PJDLOG_ASSERT(data != NULL);
18676705Sbrian	PJDLOG_ASSERT(size > 0);
18776195Sbrian
18876195Sbrian	ret = -1;
18976195Sbrian	freedata = false;
19076195Sbrian	dptr = data;
19176195Sbrian
19276195Sbrian	dsize = nv_get_uint32(nv, "size");
19376195Sbrian	if (dsize > size) {
19476195Sbrian		errno = EINVAL;
19576195Sbrian		goto end;
19676195Sbrian	} else if (dsize == 0) {
19776195Sbrian		(void)nv_set_error(nv, 0);
19876195Sbrian	} else {
19976195Sbrian		if (proto_recv(conn, data, dsize) == -1)
20076195Sbrian			goto end;
20176195Sbrian		for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0;
20276195Sbrian		    ii--) {
20376195Sbrian			ret = pipeline[ii - 1].hps_recv(res, nv, &dptr,
20476195Sbrian			    &dsize, &freedata);
20576195Sbrian			if (ret == -1)
20676195Sbrian				goto end;
20776195Sbrian		}
20876195Sbrian		ret = -1;
20976195Sbrian		if (dsize > size) {
21076195Sbrian			errno = EINVAL;
21176195Sbrian			goto end;
212		}
213		if (dptr != data)
214			bcopy(dptr, data, dsize);
215	}
216
217	ret = 0;
218end:
219	if (freedata)
220		free(dptr);
221	return (ret);
222}
223