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