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