hast_proto.c revision 229509
12886Sphk/*-
22886Sphk * Copyright (c) 2009-2010 The FreeBSD Foundation
32926Sphk * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
42926Sphk * All rights reserved.
53833Sphk *
65014Sphk * This software was developed by Pawel Jakub Dawidek under sponsorship from
72926Sphk * the FreeBSD Foundation.
82886Sphk *
92886Sphk * Redistribution and use in source and binary forms, with or without
103833Sphk * modification, are permitted provided that the following conditions
113833Sphk * are met:
122886Sphk * 1. Redistributions of source code must retain the above copyright
132886Sphk *    notice, this list of conditions and the following disclaimer.
142886Sphk * 2. Redistributions in binary form must reproduce the above copyright
152886Sphk *    notice, this list of conditions and the following disclaimer in the
162886Sphk *    documentation and/or other materials provided with the distribution.
172886Sphk *
182886Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
192886Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
202886Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
212886Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
222886Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
232886Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
242886Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
252886Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
262886Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
272886Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
282886Sphk * SUCH DAMAGE.
295014Sphk */
305014Sphk
315014Sphk#include <sys/cdefs.h>
325014Sphk__FBSDID("$FreeBSD: stable/9/sbin/hastd/hast_proto.c 229509 2012-01-04 17:22:10Z trociny $");
332886Sphk
342886Sphk#include <sys/endian.h>
355014Sphk
365014Sphk#include <errno.h>
375014Sphk#include <strings.h>
385014Sphk
395014Sphk#include <hast.h>
405014Sphk#include <ebuf.h>
415014Sphk#include <nv.h>
425014Sphk#include <pjdlog.h>
435014Sphk#include <proto.h>
445014Sphk
455014Sphk#ifdef HAVE_CRYPTO
465014Sphk#include "hast_checksum.h"
472886Sphk#endif
482886Sphk#include "hast_compression.h"
492886Sphk#include "hast_proto.h"
502886Sphk
512886Sphkstruct hast_main_header {
522886Sphk	/* Protocol version. */
532886Sphk	uint8_t		version;
542886Sphk	/* Size of nv headers. */
552886Sphk	uint32_t	size;
562886Sphk} __packed;
572886Sphk
582886Sphktypedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **,
592886Sphk    size_t *, bool *);
602886Sphktypedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **,
612886Sphk    size_t *, bool *);
622886Sphk
632886Sphkstruct hast_pipe_stage {
642886Sphk	const char	*hps_name;
652886Sphk	hps_send_t	*hps_send;
662886Sphk	hps_recv_t	*hps_recv;
672886Sphk};
682886Sphk
692886Sphkstatic struct hast_pipe_stage pipeline[] = {
702886Sphk	{ "compression", compression_send, compression_recv },
712886Sphk#ifdef HAVE_CRYPTO
722886Sphk	{ "checksum", checksum_send, checksum_recv }
732886Sphk#endif
742886Sphk};
752886Sphk
762886Sphk/*
772886Sphk * Send the given nv structure via conn.
782886Sphk * We keep headers in nv structure and pass data in separate argument.
792886Sphk * There can be no data at all (data is NULL then).
802886Sphk */
812886Sphkint
822886Sphkhast_proto_send(const struct hast_resource *res, struct proto_conn *conn,
832886Sphk    struct nv *nv, const void *data, size_t size)
842886Sphk{
852886Sphk	struct hast_main_header hdr;
862886Sphk	struct ebuf *eb;
872886Sphk	bool freedata;
882886Sphk	void *dptr, *hptr;
892886Sphk	size_t hsize;
902886Sphk	int ret;
912886Sphk
922886Sphk	dptr = (void *)(uintptr_t)data;
932886Sphk	freedata = false;
942948Sphk	ret = -1;
952971Sphk
962926Sphk	if (data != NULL) {
972926Sphk		unsigned int ii;
983112Sphk
992971Sphk		for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]);
1002926Sphk		    ii++) {
1012926Sphk			(void)pipeline[ii].hps_send(res, nv, &dptr, &size,
1022926Sphk			    &freedata);
1032926Sphk		}
1042926Sphk		nv_add_uint32(nv, size, "size");
1052926Sphk		if (nv_error(nv) != 0) {
1062886Sphk			errno = nv_error(nv);
1072926Sphk			goto end;
1082926Sphk		}
1092886Sphk	}
1102926Sphk
1112886Sphk	eb = nv_hton(nv);
1122886Sphk	if (eb == NULL)
1132926Sphk		goto end;
1142886Sphk
1152886Sphk	hdr.version = HAST_PROTO_VERSION;
1162886Sphk	hdr.size = htole32((uint32_t)ebuf_size(eb));
1172886Sphk	if (ebuf_add_head(eb, &hdr, sizeof(hdr)) < 0)
1182886Sphk		goto end;
1192886Sphk
1202886Sphk	hptr = ebuf_data(eb, &hsize);
1212886Sphk	if (proto_send(conn, hptr, hsize) < 0)
1222886Sphk		goto end;
1232886Sphk	if (data != NULL && proto_send(conn, dptr, size) < 0)
1242886Sphk		goto end;
1252886Sphk
1262886Sphk	ret = 0;
1272886Sphkend:
1282886Sphk	if (freedata)
1292886Sphk		free(dptr);
1303833Sphk	return (ret);
1313833Sphk}
1323833Sphk
1335014Sphkint
1342886Sphkhast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp)
1352886Sphk{
1362926Sphk	struct hast_main_header hdr;
1372926Sphk	struct nv *nv;
1382926Sphk	struct ebuf *eb;
1392926Sphk	void *hptr;
1402926Sphk
1412886Sphk	eb = NULL;
1422886Sphk	nv = NULL;
1432886Sphk
1442886Sphk	if (proto_recv(conn, &hdr, sizeof(hdr)) < 0)
1455014Sphk		goto fail;
1465014Sphk
1475014Sphk	if (hdr.version != HAST_PROTO_VERSION) {
1485014Sphk		errno = ERPCMISMATCH;
1495014Sphk		goto fail;
1505014Sphk	}
1515014Sphk
1525014Sphk	hdr.size = le32toh(hdr.size);
1535014Sphk
1545014Sphk	eb = ebuf_alloc(hdr.size);
1555014Sphk	if (eb == NULL)
1565014Sphk		goto fail;
1575014Sphk	if (ebuf_add_tail(eb, NULL, hdr.size) < 0)
1585014Sphk		goto fail;
1595014Sphk	hptr = ebuf_data(eb, NULL);
1605014Sphk	PJDLOG_ASSERT(hptr != NULL);
1615014Sphk	if (proto_recv(conn, hptr, hdr.size) < 0)
1625014Sphk		goto fail;
1635014Sphk	nv = nv_ntoh(eb);
1645014Sphk	if (nv == NULL)
1655014Sphk		goto fail;
1665014Sphk
1675014Sphk	*nvp = nv;
1685014Sphk	return (0);
1695014Sphkfail:
1705014Sphk	if (eb != NULL)
1715014Sphk		ebuf_free(eb);
1725014Sphk	return (-1);
1735014Sphk}
1742886Sphk
1752886Sphkint
1762886Sphkhast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn,
1772886Sphk    struct nv *nv, void *data, size_t size)
1782886Sphk{
1792886Sphk	unsigned int ii;
1802886Sphk	bool freedata;
1812886Sphk	size_t dsize;
1822886Sphk	void *dptr;
1832886Sphk	int ret;
1842886Sphk
1852926Sphk	PJDLOG_ASSERT(data != NULL);
1862886Sphk	PJDLOG_ASSERT(size > 0);
1872886Sphk
1882886Sphk	ret = -1;
1892886Sphk	freedata = false;
1903112Sphk	dptr = data;
1912886Sphk
1922886Sphk	dsize = nv_get_uint32(nv, "size");
1933112Sphk	if (dsize > size) {
1943833Sphk		errno = EINVAL;
1952886Sphk		goto end;
1963112Sphk	} else if (dsize == 0) {
1973833Sphk		(void)nv_set_error(nv, 0);
1983112Sphk	} else {
1993112Sphk		if (proto_recv(conn, data, dsize) < 0)
2003112Sphk			goto end;
2012926Sphk		for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0;
2023833Sphk		    ii--) {
2032926Sphk			ret = pipeline[ii - 1].hps_recv(res, nv, &dptr,
2043833Sphk			    &dsize, &freedata);
2053833Sphk			if (ret == -1)
2065014Sphk				goto end;
2075014Sphk		}
2085014Sphk		ret = -1;
2095014Sphk		if (dsize > size) {
210			errno = EINVAL;
211			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