1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3219351Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 4204076Spjd * All rights reserved. 5204076Spjd * 6204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 7204076Spjd * the FreeBSD Foundation. 8204076Spjd * 9204076Spjd * Redistribution and use in source and binary forms, with or without 10204076Spjd * modification, are permitted provided that the following conditions 11204076Spjd * are met: 12204076Spjd * 1. Redistributions of source code must retain the above copyright 13204076Spjd * notice, this list of conditions and the following disclaimer. 14204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 15204076Spjd * notice, this list of conditions and the following disclaimer in the 16204076Spjd * documentation and/or other materials provided with the distribution. 17204076Spjd * 18204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28204076Spjd * SUCH DAMAGE. 29204076Spjd */ 30204076Spjd 31204076Spjd#include <sys/cdefs.h> 32204076Spjd__FBSDID("$FreeBSD$"); 33204076Spjd 34204076Spjd#include <sys/endian.h> 35204076Spjd 36204076Spjd#include <errno.h> 37204076Spjd#include <strings.h> 38204076Spjd 39204076Spjd#include <hast.h> 40204076Spjd#include <ebuf.h> 41204076Spjd#include <nv.h> 42204076Spjd#include <pjdlog.h> 43204076Spjd#include <proto.h> 44204076Spjd 45219351Spjd#ifdef HAVE_CRYPTO 46219351Spjd#include "hast_checksum.h" 47219351Spjd#endif 48219354Spjd#include "hast_compression.h" 49204076Spjd#include "hast_proto.h" 50204076Spjd 51204076Spjdstruct hast_main_header { 52204076Spjd /* Protocol version. */ 53204076Spjd uint8_t version; 54204076Spjd /* Size of nv headers. */ 55204076Spjd uint32_t size; 56204076Spjd} __packed; 57204076Spjd 58212033Spjdtypedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **, 59212033Spjd size_t *, bool *); 60212033Spjdtypedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **, 61212033Spjd size_t *, bool *); 62204076Spjd 63204076Spjdstruct hast_pipe_stage { 64204076Spjd const char *hps_name; 65204076Spjd hps_send_t *hps_send; 66204076Spjd hps_recv_t *hps_recv; 67204076Spjd}; 68204076Spjd 69204076Spjdstatic struct hast_pipe_stage pipeline[] = { 70219354Spjd { "compression", compression_send, compression_recv }, 71221078Strociny#ifdef HAVE_CRYPTO 72204076Spjd { "checksum", checksum_send, checksum_recv } 73221078Strociny#endif 74204076Spjd}; 75204076Spjd 76204076Spjd/* 77204076Spjd * Send the given nv structure via conn. 78204076Spjd * We keep headers in nv structure and pass data in separate argument. 79204076Spjd * There can be no data at all (data is NULL then). 80204076Spjd */ 81204076Spjdint 82212033Spjdhast_proto_send(const struct hast_resource *res, struct proto_conn *conn, 83204076Spjd struct nv *nv, const void *data, size_t size) 84204076Spjd{ 85204076Spjd struct hast_main_header hdr; 86204076Spjd struct ebuf *eb; 87204076Spjd bool freedata; 88204076Spjd void *dptr, *hptr; 89204076Spjd size_t hsize; 90204076Spjd int ret; 91204076Spjd 92204076Spjd dptr = (void *)(uintptr_t)data; 93204076Spjd freedata = false; 94204076Spjd ret = -1; 95204076Spjd 96204076Spjd if (data != NULL) { 97204076Spjd unsigned int ii; 98204076Spjd 99204076Spjd for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]); 100204076Spjd ii++) { 101219351Spjd (void)pipeline[ii].hps_send(res, nv, &dptr, &size, 102204076Spjd &freedata); 103204076Spjd } 104204076Spjd nv_add_uint32(nv, size, "size"); 105204076Spjd if (nv_error(nv) != 0) { 106204076Spjd errno = nv_error(nv); 107204076Spjd goto end; 108204076Spjd } 109204076Spjd } 110204076Spjd 111204076Spjd eb = nv_hton(nv); 112204076Spjd if (eb == NULL) 113204076Spjd goto end; 114204076Spjd 115249236Strociny hdr.version = res != NULL ? res->hr_version : HAST_PROTO_VERSION; 116204076Spjd hdr.size = htole32((uint32_t)ebuf_size(eb)); 117231017Strociny if (ebuf_add_head(eb, &hdr, sizeof(hdr)) == -1) 118204076Spjd goto end; 119204076Spjd 120204076Spjd hptr = ebuf_data(eb, &hsize); 121231017Strociny if (proto_send(conn, hptr, hsize) == -1) 122204076Spjd goto end; 123231017Strociny if (data != NULL && proto_send(conn, dptr, size) == -1) 124204076Spjd goto end; 125204076Spjd 126204076Spjd ret = 0; 127204076Spjdend: 128204076Spjd if (freedata) 129204076Spjd free(dptr); 130204076Spjd return (ret); 131204076Spjd} 132204076Spjd 133204076Spjdint 134212033Spjdhast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp) 135204076Spjd{ 136204076Spjd struct hast_main_header hdr; 137204076Spjd struct nv *nv; 138204076Spjd struct ebuf *eb; 139204076Spjd void *hptr; 140204076Spjd 141204076Spjd eb = NULL; 142204076Spjd nv = NULL; 143204076Spjd 144231017Strociny if (proto_recv(conn, &hdr, sizeof(hdr)) == -1) 145204076Spjd goto fail; 146204076Spjd 147249236Strociny if (hdr.version > HAST_PROTO_VERSION) { 148204076Spjd errno = ERPCMISMATCH; 149204076Spjd goto fail; 150204076Spjd } 151204076Spjd 152204076Spjd hdr.size = le32toh(hdr.size); 153204076Spjd 154204076Spjd eb = ebuf_alloc(hdr.size); 155204076Spjd if (eb == NULL) 156204076Spjd goto fail; 157231017Strociny if (ebuf_add_tail(eb, NULL, hdr.size) == -1) 158204076Spjd goto fail; 159204076Spjd hptr = ebuf_data(eb, NULL); 160229509Strociny PJDLOG_ASSERT(hptr != NULL); 161231017Strociny if (proto_recv(conn, hptr, hdr.size) == -1) 162204076Spjd goto fail; 163204076Spjd nv = nv_ntoh(eb); 164204076Spjd if (nv == NULL) 165204076Spjd goto fail; 166204076Spjd 167204076Spjd *nvp = nv; 168204076Spjd return (0); 169204076Spjdfail: 170209175Spjd if (eb != NULL) 171204076Spjd ebuf_free(eb); 172204076Spjd return (-1); 173204076Spjd} 174204076Spjd 175204076Spjdint 176212033Spjdhast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn, 177204076Spjd struct nv *nv, void *data, size_t size) 178204076Spjd{ 179204076Spjd unsigned int ii; 180204076Spjd bool freedata; 181204076Spjd size_t dsize; 182204076Spjd void *dptr; 183204076Spjd int ret; 184204076Spjd 185229509Strociny PJDLOG_ASSERT(data != NULL); 186229509Strociny PJDLOG_ASSERT(size > 0); 187204076Spjd 188204076Spjd ret = -1; 189204076Spjd freedata = false; 190204076Spjd dptr = data; 191204076Spjd 192204076Spjd dsize = nv_get_uint32(nv, "size"); 193220522Strociny if (dsize > size) { 194220522Strociny errno = EINVAL; 195220522Strociny goto end; 196220522Strociny } else if (dsize == 0) { 197204076Spjd (void)nv_set_error(nv, 0); 198220522Strociny } else { 199231017Strociny if (proto_recv(conn, data, dsize) == -1) 200204076Spjd goto end; 201204076Spjd for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0; 202204076Spjd ii--) { 203204076Spjd ret = pipeline[ii - 1].hps_recv(res, nv, &dptr, 204204076Spjd &dsize, &freedata); 205204076Spjd if (ret == -1) 206204076Spjd goto end; 207204076Spjd } 208204076Spjd ret = -1; 209219351Spjd if (dsize > size) { 210219351Spjd errno = EINVAL; 211204076Spjd goto end; 212219351Spjd } 213204076Spjd if (dptr != data) 214204076Spjd bcopy(dptr, data, dsize); 215204076Spjd } 216204076Spjd 217204076Spjd ret = 0; 218204076Spjdend: 219204076Spjd if (freedata) 220204076Spjd free(dptr); 221204076Spjd return (ret); 222204076Spjd} 223