Home | History | Annotate | Line # | Download | only in mount_9p
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