hast_proto.c revision 220523
1/*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sbin/hastd/hast_proto.c 220523 2011-04-10 15:28:37Z trociny $"); 33 34#include <sys/endian.h> 35 36#include <assert.h> 37#include <errno.h> 38#include <strings.h> 39 40#include <hast.h> 41#include <ebuf.h> 42#include <nv.h> 43#include <pjdlog.h> 44#include <proto.h> 45 46#ifdef HAVE_CRYPTO 47#include "hast_checksum.h" 48#endif 49#include "hast_compression.h" 50#include "hast_proto.h" 51 52struct hast_main_header { 53 /* Protocol version. */ 54 uint8_t version; 55 /* Size of nv headers. */ 56 uint32_t size; 57} __packed; 58 59typedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **, 60 size_t *, bool *); 61typedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **, 62 size_t *, bool *); 63 64struct hast_pipe_stage { 65 const char *hps_name; 66 hps_send_t *hps_send; 67 hps_recv_t *hps_recv; 68}; 69 70static struct hast_pipe_stage pipeline[] = { 71 { "compression", compression_send, compression_recv }, 72 { "checksum", checksum_send, checksum_recv } 73}; 74 75/* 76 * Send the given nv structure via conn. 77 * We keep headers in nv structure and pass data in separate argument. 78 * There can be no data at all (data is NULL then). 79 */ 80int 81hast_proto_send(const struct hast_resource *res, struct proto_conn *conn, 82 struct nv *nv, const void *data, size_t size) 83{ 84 struct hast_main_header hdr; 85 struct ebuf *eb; 86 bool freedata; 87 void *dptr, *hptr; 88 size_t hsize; 89 int ret; 90 91 dptr = (void *)(uintptr_t)data; 92 freedata = false; 93 ret = -1; 94 95 if (data != NULL) { 96 unsigned int ii; 97 98 for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]); 99 ii++) { 100 (void)pipeline[ii].hps_send(res, nv, &dptr, &size, 101 &freedata); 102 } 103 nv_add_uint32(nv, size, "size"); 104 if (nv_error(nv) != 0) { 105 errno = nv_error(nv); 106 goto end; 107 } 108 } 109 110 eb = nv_hton(nv); 111 if (eb == NULL) 112 goto end; 113 114 hdr.version = HAST_PROTO_VERSION; 115 hdr.size = htole32((uint32_t)ebuf_size(eb)); 116 if (ebuf_add_head(eb, &hdr, sizeof(hdr)) < 0) 117 goto end; 118 119 hptr = ebuf_data(eb, &hsize); 120 if (proto_send(conn, hptr, hsize) < 0) 121 goto end; 122 if (data != NULL && proto_send(conn, dptr, size) < 0) 123 goto end; 124 125 ret = 0; 126end: 127 if (freedata) 128 free(dptr); 129 return (ret); 130} 131 132int 133hast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp) 134{ 135 struct hast_main_header hdr; 136 struct nv *nv; 137 struct ebuf *eb; 138 void *hptr; 139 140 eb = NULL; 141 nv = NULL; 142 143 if (proto_recv(conn, &hdr, sizeof(hdr)) < 0) 144 goto fail; 145 146 if (hdr.version != HAST_PROTO_VERSION) { 147 errno = ERPCMISMATCH; 148 goto fail; 149 } 150 151 hdr.size = le32toh(hdr.size); 152 153 eb = ebuf_alloc(hdr.size); 154 if (eb == NULL) 155 goto fail; 156 if (ebuf_add_tail(eb, NULL, hdr.size) < 0) 157 goto fail; 158 hptr = ebuf_data(eb, NULL); 159 assert(hptr != NULL); 160 if (proto_recv(conn, hptr, hdr.size) < 0) 161 goto fail; 162 nv = nv_ntoh(eb); 163 if (nv == NULL) 164 goto fail; 165 166 *nvp = nv; 167 return (0); 168fail: 169 if (eb != NULL) 170 ebuf_free(eb); 171 return (-1); 172} 173 174int 175hast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn, 176 struct nv *nv, void *data, size_t size) 177{ 178 unsigned int ii; 179 bool freedata; 180 size_t dsize; 181 void *dptr; 182 int ret; 183 184 assert(data != NULL); 185 assert(size > 0); 186 187 ret = -1; 188 freedata = false; 189 dptr = data; 190 191 dsize = nv_get_uint32(nv, "size"); 192 if (dsize > size) { 193 errno = EINVAL; 194 goto end; 195 } else if (dsize == 0) { 196 (void)nv_set_error(nv, 0); 197 } else { 198 if (proto_recv(conn, data, dsize) < 0) 199 goto end; 200 for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0; 201 ii--) { 202 ret = pipeline[ii - 1].hps_recv(res, nv, &dptr, 203 &dsize, &freedata); 204 if (ret == -1) 205 goto end; 206 } 207 ret = -1; 208 if (dsize > size) { 209 errno = EINVAL; 210 goto end; 211 } 212 if (dptr != data) 213 bcopy(dptr, data, dsize); 214 } 215 216 ret = 0; 217end: 218 if (freedata) 219 free(dptr); 220 return (ret); 221} 222 223int 224hast_proto_recv(const struct hast_resource *res, struct proto_conn *conn, 225 struct nv **nvp, void *data, size_t size) 226{ 227 struct nv *nv; 228 int ret; 229 230 ret = hast_proto_recv_hdr(conn, &nv); 231 if (ret < 0) 232 return (ret); 233 ret = hast_proto_recv_data(res, conn, nv, data, size); 234 if (ret < 0) 235 nv_free(nv); 236 else 237 *nvp = nv; 238 return (ret); 239} 240