ninebuf.c revision 1.1 1 /* $NetBSD: ninebuf.c,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: ninebuf.c,v 1.1 2007/04/21 14:21:43 pooka Exp $");
31 #endif /* !lint */
32
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/vnode.h>
36
37 #include <assert.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <util.h>
42 #include <unistd.h>
43
44 #include "ninepuffs.h"
45
46 /*
47 * Originally from my psshfs implementation. Maybe need to look into
48 * unifying these at some level, although there are minor variations.
49 *
50 * Such as the fact that 9P is a little endian protocol ....
51 */
52
53 int
54 p9pbuf_read(struct puffs9p *p9p, struct p9pbuf *pb)
55 {
56 ssize_t n;
57
58 assert(pb->state != P9PBUF_PUT);
59
60 again:
61 n = read(p9p->servsock, pb->buf+pb->offset, pb->remain);
62 switch (n) {
63 case 0:
64 errno = EIO;
65 return -1;
66 case -1:
67 if (errno == EAGAIN)
68 return 0;
69 return -1;
70 default:
71 pb->offset += n;
72 pb->remain -= n;
73 }
74
75 if (pb->remain != 0)
76 return 0;
77
78 /* ok, at least there's something to do */
79 assert(pb->state == P9PBUF_GETLEN || pb->state == P9PBUF_GETDATA);
80
81 if (pb->state == P9PBUF_GETLEN) {
82 uint32_t len;
83
84 memcpy(&len, pb->buf, 4);
85 pb->remain = le32toh(len) - 4;
86 assert(pb->remain <= pb->len); /* XXX */
87 pb->offset = 0;
88
89 pb->state = P9PBUF_GETDATA;
90 goto again;
91
92 } else if (pb->state == P9PBUF_GETDATA) {
93 pb->remain = pb->offset;
94 pb->offset = 0;
95
96 pb->state = P9PBUF_GETREADY;
97
98 /* sloppy */
99 if (!p9pbuf_get_1(pb, &pb->type))
100 errx(1, "invalid server response, no type");
101 if (!p9pbuf_get_2(pb, &pb->tagid))
102 errx(1, "invalid server response, no tag");
103
104 return 1;
105 }
106
107 return -1; /* XXX: impossible */
108 }
109
110 int
111 p9pbuf_write(struct puffs9p *p9p, struct p9pbuf *pb)
112 {
113 ssize_t n;
114
115 if (pb->state == P9PBUF_PUT) {
116 uint32_t len;
117
118 len = htole32(pb->offset);
119 memcpy(pb->buf, &len, sizeof(len));
120
121 pb->remain = pb->offset;
122 pb->offset = 0;
123
124 pb->state = P9PBUF_PUTDONE;
125 }
126
127 assert(pb->state == P9PBUF_PUTDONE);
128
129 n = write(p9p->servsock, pb->buf + pb->offset, pb->remain);
130 if (n == 0) {
131 errno = EIO;
132 return -1;
133 }
134
135 if (n == -1) {
136 if (errno == EAGAIN)
137 return 0;
138 else
139 return -1;
140 }
141
142 pb->offset += n;
143 pb->remain -= n;
144
145 if (pb->remain == 0)
146 return 1;
147 else
148 return 0;
149 }
150
151 struct p9pbuf *
152 p9pbuf_make(size_t reqsize, int incoming)
153 {
154 struct p9pbuf *pb;
155
156 pb = emalloc(sizeof(struct p9pbuf));
157 memset(pb, 0, sizeof(struct p9pbuf));
158 pb->buf = emalloc(reqsize);
159 pb->len = reqsize;
160
161 p9pbuf_recycle(pb, incoming);
162
163 return pb;
164 }
165
166 void
167 p9pbuf_destroy(struct p9pbuf *pb)
168 {
169
170 free(pb->buf);
171 free(pb);
172 }
173
174 void
175 p9pbuf_recycle(struct p9pbuf *pb, int incoming)
176 {
177
178 if (incoming) {
179 pb->offset = 0;
180 pb->remain = 4;
181 pb->state = P9PBUF_GETLEN;
182 } else {
183 /* save space for len */
184 pb->remain = pb->len - 4;
185 pb->offset = 4;
186
187 pb->state = P9PBUF_PUT;
188 }
189 }
190
191 /*
192 * allow put 1,2,4,8 in the middle and do *not* adjust remain
193 * in that case. However, do check the extending is possible
194 * only from the end
195 */
196
197 int
198 p9pbuf_put_1(struct p9pbuf *pb, uint8_t val)
199 {
200
201 assert(pb->state == P9PBUF_PUT);
202
203 P9PB_CHECK(pb, 1);
204
205 memcpy(pb->buf + pb->offset, &val, 1);
206 if (pb->offset + pb->remain == pb->len)
207 pb->remain -= 1;
208 pb->offset += 1;
209
210 return 0;
211 }
212
213 int
214 p9pbuf_put_2(struct p9pbuf *pb, uint16_t val)
215 {
216
217 assert(pb->state == P9PBUF_PUT);
218
219 P9PB_CHECK(pb, 2);
220
221 HTOLE16(val);
222 memcpy(pb->buf + pb->offset, &val, 2);
223 if (pb->offset + pb->remain == pb->len)
224 pb->remain -= 2;
225 else
226 assert(pb->offset + pb->remain + 2 <= pb->len);
227 pb->offset += 2;
228
229 return 0;
230 }
231
232 int
233 p9pbuf_put_4(struct p9pbuf *pb, uint32_t val)
234 {
235
236 assert(pb->state == P9PBUF_PUT);
237
238 P9PB_CHECK(pb, 4);
239
240 HTOLE32(val);
241 memcpy(pb->buf + pb->offset, &val, 4);
242 if (pb->offset + pb->remain == pb->len)
243 pb->remain -= 4;
244 else
245 assert(pb->offset + pb->remain + 4 <= pb->len);
246 pb->offset += 4;
247
248 return 0;
249 }
250
251 int
252 p9pbuf_put_8(struct p9pbuf *pb, uint64_t val)
253 {
254
255 assert(pb->state == P9PBUF_PUT);
256
257 P9PB_CHECK(pb, 8);
258
259 HTOLE64(val);
260 memcpy(pb->buf + pb->offset, &val, 8);
261 if (pb->offset + pb->remain == pb->len)
262 pb->remain -= 8;
263 else
264 assert(pb->offset + pb->remain + 8 <= pb->len);
265 pb->offset += 8;
266
267 return 0;
268 }
269
270 int
271 p9pbuf_put_data(struct p9pbuf *pb, const void *data, uint16_t dlen)
272 {
273
274 assert(pb->state == P9PBUF_PUT);
275
276 P9PB_CHECK(pb, dlen + 2);
277
278 p9pbuf_put_2(pb, dlen);
279 memcpy(pb->buf + pb->offset, data, dlen);
280 pb->offset += dlen;
281 pb->remain -= dlen;
282
283 return 0;
284 }
285
286 int
287 p9pbuf_put_str(struct p9pbuf *pb, const char *str)
288 {
289
290 return p9pbuf_put_data(pb, str, strlen(str));
291 }
292
293 int
294 p9pbuf_write_data(struct p9pbuf *pb, uint8_t *data, uint32_t dlen)
295 {
296
297 assert(pb->state == P9PBUF_PUT);
298
299 P9PB_CHECK(pb, dlen);
300 memcpy(pb->buf + pb->offset, data, dlen);
301 pb->offset += dlen;
302 pb->remain -= dlen;
303
304 return 0;
305 }
306
307 int
308 p9pbuf_get_1(struct p9pbuf *pb, uint8_t *val)
309 {
310
311 assert(pb->state == P9PBUF_GETREADY);
312
313 if (pb->remain < 1)
314 return 0;
315
316 memcpy(val, pb->buf + pb->offset, 1);
317 pb->offset += 1;
318 pb->remain -= 1;
319
320 return 1;
321 }
322
323 int
324 p9pbuf_get_2(struct p9pbuf *pb, uint16_t *val)
325 {
326 uint16_t v;
327
328 assert(pb->state == P9PBUF_GETREADY);
329
330 if (pb->remain < 2)
331 return 0;
332
333 memcpy(&v, pb->buf + pb->offset, 2);
334 pb->offset += 2;
335 pb->remain -= 2;
336
337 *val = le16toh(v);
338
339 return 1;
340 }
341
342 int
343 p9pbuf_get_4(struct p9pbuf *pb, uint32_t *val)
344 {
345 uint32_t v;
346
347 assert(pb->state == P9PBUF_GETREADY);
348
349 if (pb->remain < 4)
350 return 0;
351
352 memcpy(&v, pb->buf + pb->offset, 4);
353 pb->offset += 4;
354 pb->remain -= 4;
355
356 *val = le32toh(v);
357
358 return 1;
359 }
360
361 int
362 p9pbuf_get_8(struct p9pbuf *pb, uint64_t *val)
363 {
364 uint64_t v;
365
366 assert(pb->state == P9PBUF_GETREADY);
367
368 if (pb->remain < 8)
369 return 0;
370
371 memcpy(&v, pb->buf + pb->offset, 8);
372 pb->offset += 8;
373 pb->remain -= 8;
374
375 *val = le64toh(v);
376
377 return 1;
378 }
379
380 int
381 p9pbuf_get_data(struct p9pbuf *pb, uint8_t **dp, uint16_t *dlenp)
382 {
383 uint8_t *d;
384 uint16_t len;
385
386 assert(pb->state == P9PBUF_GETREADY);
387
388 if (!(p9pbuf_get_2(pb, &len)))
389 return 0;
390
391 if (pb->remain < len)
392 return 0;
393
394 if (dp) {
395 d = emalloc(len+1);
396 memcpy(d, pb->buf + pb->offset, len);
397 d[len] = '\0';
398 *dp = d;
399 }
400
401 pb->offset += len;
402 pb->remain -= len;
403
404 if (dlenp)
405 *dlenp = len;
406
407 return 1;
408 }
409
410 int
411 p9pbuf_read_data(struct p9pbuf *pb, uint8_t *buf, uint32_t dlen)
412 {
413
414 assert(pb->state == P9PBUF_GETREADY);
415
416 if (pb->remain < dlen)
417 return 0;
418
419 memcpy(buf, pb->buf + pb->offset, dlen);
420 pb->offset += dlen;
421 pb->remain -= dlen;
422
423 return 1;
424 }
425
426 int
427 p9pbuf_get_str(struct p9pbuf *pb, char **dp, uint16_t *dlenp)
428 {
429
430 return p9pbuf_get_data(pb, (uint8_t **)dp, dlenp);
431 }
432
433 int
434 p9pbuf_tell(struct p9pbuf *pb)
435 {
436
437 return pb->offset;
438 }
439
440 int
441 p9pbuf_remaining(struct p9pbuf *pb)
442 {
443
444 return pb->remain;
445 }
446
447 void
448 p9pbuf_seekset(struct p9pbuf *pb, int newoff)
449 {
450
451 if (newoff > pb->offset)
452 pb->remain -= newoff - pb->offset;
453 pb->offset = newoff;
454 }
455