hast_proto.c revision 219351
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 219351 2011-03-06 22:56:14Z pjd $"); 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_proto.h" 50 51struct hast_main_header { 52 /* Protocol version. */ 53 uint8_t version; 54 /* Size of nv headers. */ 55 uint32_t size; 56} __packed; 57 58typedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **, 59 size_t *, bool *); 60typedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **, 61 size_t *, bool *); 62 63struct hast_pipe_stage { 64 const char *hps_name; 65 hps_send_t *hps_send; 66 hps_recv_t *hps_recv; 67}; 68 69static struct hast_pipe_stage pipeline[] = { 70 { "checksum", checksum_send, checksum_recv } 71}; 72 73/* 74 * Send the given nv structure via conn. 75 * We keep headers in nv structure and pass data in separate argument. 76 * There can be no data at all (data is NULL then). 77 */ 78int 79hast_proto_send(const struct hast_resource *res, struct proto_conn *conn, 80 struct nv *nv, const void *data, size_t size) 81{ 82 struct hast_main_header hdr; 83 struct ebuf *eb; 84 bool freedata; 85 void *dptr, *hptr; 86 size_t hsize; 87 int ret; 88 89 dptr = (void *)(uintptr_t)data; 90 freedata = false; 91 ret = -1; 92 93 if (data != NULL) { 94 unsigned int ii; 95 96 for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]); 97 ii++) { 98 (void)pipeline[ii].hps_send(res, nv, &dptr, &size, 99 &freedata); 100 } 101 nv_add_uint32(nv, size, "size"); 102 if (nv_error(nv) != 0) { 103 errno = nv_error(nv); 104 goto end; 105 } 106 } 107 108 eb = nv_hton(nv); 109 if (eb == NULL) 110 goto end; 111 112 hdr.version = HAST_PROTO_VERSION; 113 hdr.size = htole32((uint32_t)ebuf_size(eb)); 114 if (ebuf_add_head(eb, &hdr, sizeof(hdr)) < 0) 115 goto end; 116 117 hptr = ebuf_data(eb, &hsize); 118 if (proto_send(conn, hptr, hsize) < 0) 119 goto end; 120 if (data != NULL && proto_send(conn, dptr, size) < 0) 121 goto end; 122 123 ret = 0; 124end: 125 if (freedata) 126 free(dptr); 127 return (ret); 128} 129 130int 131hast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp) 132{ 133 struct hast_main_header hdr; 134 struct nv *nv; 135 struct ebuf *eb; 136 void *hptr; 137 138 eb = NULL; 139 nv = NULL; 140 141 if (proto_recv(conn, &hdr, sizeof(hdr)) < 0) 142 goto fail; 143 144 if (hdr.version != HAST_PROTO_VERSION) { 145 errno = ERPCMISMATCH; 146 goto fail; 147 } 148 149 hdr.size = le32toh(hdr.size); 150 151 eb = ebuf_alloc(hdr.size); 152 if (eb == NULL) 153 goto fail; 154 if (ebuf_add_tail(eb, NULL, hdr.size) < 0) 155 goto fail; 156 hptr = ebuf_data(eb, NULL); 157 assert(hptr != NULL); 158 if (proto_recv(conn, hptr, hdr.size) < 0) 159 goto fail; 160 nv = nv_ntoh(eb); 161 if (nv == NULL) 162 goto fail; 163 164 *nvp = nv; 165 return (0); 166fail: 167 if (eb != NULL) 168 ebuf_free(eb); 169 return (-1); 170} 171 172int 173hast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn, 174 struct nv *nv, void *data, size_t size) 175{ 176 unsigned int ii; 177 bool freedata; 178 size_t dsize; 179 void *dptr; 180 int ret; 181 182 assert(data != NULL); 183 assert(size > 0); 184 185 ret = -1; 186 freedata = false; 187 dptr = data; 188 189 dsize = nv_get_uint32(nv, "size"); 190 if (dsize == 0) 191 (void)nv_set_error(nv, 0); 192 else { 193 if (proto_recv(conn, data, dsize) < 0) 194 goto end; 195 for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0; 196 ii--) { 197 ret = pipeline[ii - 1].hps_recv(res, nv, &dptr, 198 &dsize, &freedata); 199 if (ret == -1) 200 goto end; 201 } 202 ret = -1; 203 if (dsize > size) { 204 errno = EINVAL; 205 goto end; 206 } 207 if (dptr != data) 208 bcopy(dptr, data, dsize); 209 } 210 211 ret = 0; 212end: 213 if (freedata) 214 free(dptr); 215 return (ret); 216} 217 218int 219hast_proto_recv(const struct hast_resource *res, struct proto_conn *conn, 220 struct nv **nvp, void *data, size_t size) 221{ 222 struct nv *nv; 223 size_t dsize; 224 int ret; 225 226 ret = hast_proto_recv_hdr(conn, &nv); 227 if (ret < 0) 228 return (ret); 229 dsize = nv_get_uint32(nv, "size"); 230 if (dsize == 0) 231 (void)nv_set_error(nv, 0); 232 else 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