[BACK]Return to io.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rsync

Annotation of src/usr.bin/rsync/io.c, Revision 1.11

1.11    ! benno       1: /*     $Id: io.c,v 1.10 2019/02/18 21:34:54 benno Exp $ */
1.1       benno       2: /*
                      3:  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: #include <sys/stat.h>
                     18:
                     19: #include <assert.h>
                     20: #include <endian.h>
                     21: #include <errno.h>
                     22: #include <poll.h>
                     23: #include <stdint.h>
                     24: #include <stdio.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
                     27: #include <unistd.h>
                     28:
                     29: #include "extern.h"
1.7       florian    30:
                     31: /*
                     32:  * A non-blocking check to see whether there's POLLIN data in fd.
                     33:  * Returns <0 on failure, 0 if there's no data, >0 if there is.
                     34:  */
1.1       benno      35: int
                     36: io_read_check(struct sess *sess, int fd)
                     37: {
                     38:        struct pollfd   pfd;
                     39:
                     40:        pfd.fd = fd;
                     41:        pfd.events = POLLIN;
                     42:
                     43:        if (poll(&pfd, 1, 0) < 0) {
                     44:                ERR(sess, "poll");
                     45:                return -1;
                     46:        }
1.7       florian    47:        return (pfd.revents & POLLIN);
1.1       benno      48: }
                     49:
                     50: /*
                     51:  * Write buffer to non-blocking descriptor.
                     52:  * Returns zero on failure, non-zero on success (zero or more bytes).
1.7       florian    53:  * On success, fills in "sz" with the amount written.
1.1       benno      54:  */
                     55: static int
1.5       deraadt    56: io_write_nonblocking(struct sess *sess, int fd, const void *buf, size_t bsz,
                     57:     size_t *sz)
1.1       benno      58: {
                     59:        struct pollfd   pfd;
                     60:        ssize_t         wsz;
1.6       florian    61:        int             c;
1.1       benno      62:
                     63:        *sz = 0;
                     64:
1.4       deraadt    65:        if (bsz == 0)
1.1       benno      66:                return 1;
                     67:
                     68:        pfd.fd = fd;
                     69:        pfd.events = POLLOUT;
                     70:
1.7       florian    71:        /* Poll and check for all possible errors. */
                     72:
1.6       florian    73:        if ((c = poll(&pfd, 1, POLL_TIMEOUT)) == -1) {
1.1       benno      74:                ERR(sess, "poll");
                     75:                return 0;
1.6       florian    76:        } else if (c == 0) {
                     77:                ERRX(sess, "poll: timeout");
                     78:                return 0;
1.7       florian    79:        } else if ((pfd.revents & (POLLERR|POLLNVAL))) {
1.1       benno      80:                ERRX(sess, "poll: bad fd");
                     81:                return 0;
                     82:        } else if ((pfd.revents & POLLHUP)) {
                     83:                ERRX(sess, "poll: hangup");
                     84:                return 0;
1.3       deraadt    85:        } else if (!(pfd.revents & POLLOUT)) {
1.1       benno      86:                ERRX(sess, "poll: unknown event");
                     87:                return 0;
                     88:        }
                     89:
1.7       florian    90:        /* Now the non-blocking write. */
                     91:
1.1       benno      92:        if ((wsz = write(fd, buf, bsz)) < 0) {
                     93:                ERR(sess, "write");
                     94:                return 0;
                     95:        }
                     96:
                     97:        *sz = wsz;
                     98:        return 1;
                     99: }
                    100:
                    101: /*
                    102:  * Blocking write of the full size of the buffer.
                    103:  * Returns 0 on failure, non-zero on success (all bytes written).
                    104:  */
                    105: static int
1.5       deraadt   106: io_write_blocking(struct sess *sess, int fd, const void *buf, size_t sz)
1.1       benno     107: {
                    108:        size_t          wsz;
                    109:        int             c;
                    110:
                    111:        while (sz > 0) {
                    112:                c = io_write_nonblocking(sess, fd, buf, sz, &wsz);
1.3       deraadt   113:                if (!c) {
1.1       benno     114:                        ERRX1(sess, "io_write_nonblocking");
                    115:                        return 0;
1.4       deraadt   116:                } else if (wsz == 0) {
1.1       benno     117:                        ERRX(sess, "io_write_nonblocking: short write");
                    118:                        return 0;
                    119:                }
                    120:                buf += wsz;
                    121:                sz -= wsz;
                    122:        }
                    123:
                    124:        return 1;
                    125: }
                    126:
                    127: /*
                    128:  * Write "buf" of size "sz" to non-blocking descriptor.
                    129:  * Returns zero on failure, non-zero on success (all bytes written to
                    130:  * the descriptor).
                    131:  */
                    132: int
                    133: io_write_buf(struct sess *sess, int fd, const void *buf, size_t sz)
                    134: {
                    135:        int32_t  tag, tagbuf;
                    136:        size_t   wsz;
                    137:        int      c;
                    138:
1.3       deraadt   139:        if (!sess->mplex_writes) {
1.1       benno     140:                c = io_write_blocking(sess, fd, buf, sz);
                    141:                sess->total_write += sz;
                    142:                return c;
                    143:        }
                    144:
                    145:        while (sz > 0) {
                    146:                wsz = sz & 0xFFFFFF;
                    147:                tag = (7 << 24) + wsz;
                    148:                tagbuf = htole32(tag);
1.3       deraadt   149:                if (!io_write_blocking(sess, fd, &tagbuf, sizeof(tagbuf))) {
1.1       benno     150:                        ERRX1(sess, "io_write_blocking");
                    151:                        return 0;
                    152:                }
1.3       deraadt   153:                if (!io_write_blocking(sess, fd, buf, wsz)) {
1.1       benno     154:                        ERRX1(sess, "io_write_blocking");
                    155:                        return 0;
                    156:                }
                    157:                sess->total_write += wsz;
                    158:                sz -= wsz;
                    159:                buf += wsz;
                    160:        }
                    161:
                    162:        return 1;
                    163: }
                    164:
                    165: /*
                    166:  * Write "line" (NUL-terminated) followed by a newline.
                    167:  * Returns zero on failure, non-zero on succcess.
                    168:  */
                    169: int
                    170: io_write_line(struct sess *sess, int fd, const char *line)
                    171: {
                    172:
1.3       deraadt   173:        if (!io_write_buf(sess, fd, line, strlen(line)))
1.1       benno     174:                ERRX1(sess, "io_write_buf");
1.3       deraadt   175:        else if (!io_write_byte(sess, fd, '\n'))
1.1       benno     176:                ERRX1(sess, "io_write_byte");
                    177:        else
                    178:                return 1;
                    179:
                    180:        return 0;
                    181: }
                    182:
                    183: /*
                    184:  * Read buffer from non-blocking descriptor.
                    185:  * Returns zero on failure, non-zero on success (zero or more bytes).
                    186:  */
                    187: static int
                    188: io_read_nonblocking(struct sess *sess,
                    189:        int fd, void *buf, size_t bsz, size_t *sz)
                    190: {
                    191:        struct pollfd   pfd;
                    192:        ssize_t         rsz;
1.6       florian   193:        int             c;
1.1       benno     194:
                    195:        *sz = 0;
                    196:
1.4       deraadt   197:        if (bsz == 0)
1.1       benno     198:                return 1;
                    199:
                    200:        pfd.fd = fd;
                    201:        pfd.events = POLLIN;
                    202:
1.7       florian   203:        /* Poll and check for all possible errors. */
                    204:
1.6       florian   205:        if ((c = poll(&pfd, 1, POLL_TIMEOUT)) == -1) {
1.1       benno     206:                ERR(sess, "poll");
                    207:                return 0;
1.6       florian   208:        } else if (c == 0) {
                    209:                ERRX(sess, "poll: timeout");
                    210:                return 0;
1.7       florian   211:        } else if ((pfd.revents & (POLLERR|POLLNVAL))) {
1.1       benno     212:                ERRX(sess, "poll: bad fd");
                    213:                return 0;
1.3       deraadt   214:        } else if (!(pfd.revents & (POLLIN|POLLHUP))) {
1.1       benno     215:                ERRX(sess, "poll: unknown event");
                    216:                return 0;
                    217:        }
                    218:
1.7       florian   219:        /* Now the non-blocking read, checking for EOF. */
                    220:
1.1       benno     221:        if ((rsz = read(fd, buf, bsz)) < 0) {
                    222:                ERR(sess, "read");
                    223:                return 0;
1.4       deraadt   224:        } else if (rsz == 0) {
1.1       benno     225:                ERRX(sess, "unexpected end of file");
                    226:                return 0;
                    227:        }
                    228:
                    229:        *sz = rsz;
                    230:        return 1;
                    231: }
                    232:
                    233: /*
                    234:  * Blocking read of the full size of the buffer.
                    235:  * This can be called from either the error type message or a regular
                    236:  * message---or for that matter, multiplexed or not.
                    237:  * Returns 0 on failure, non-zero on success (all bytes read).
                    238:  */
                    239: static int
                    240: io_read_blocking(struct sess *sess,
                    241:        int fd, void *buf, size_t sz)
                    242: {
                    243:        size_t   rsz;
                    244:        int      c;
                    245:
                    246:        while (sz > 0) {
                    247:                c = io_read_nonblocking(sess, fd, buf, sz, &rsz);
1.3       deraadt   248:                if (!c) {
1.1       benno     249:                        ERRX1(sess, "io_read_nonblocking");
                    250:                        return 0;
1.4       deraadt   251:                } else if (rsz == 0) {
1.1       benno     252:                        ERRX(sess, "io_read_nonblocking: short read");
                    253:                        return 0;
                    254:                }
                    255:                buf += rsz;
                    256:                sz -= rsz;
                    257:        }
                    258:
                    259:        return 1;
                    260: }
                    261:
                    262: /*
                    263:  * When we do a lot of writes in a row (such as when the sender emits
                    264:  * the file list), the server might be sending us multiplexed log
                    265:  * messages.
                    266:  * If it sends too many, it clogs the socket.
                    267:  * This function looks into the read buffer and clears out any log
                    268:  * messages pending.
                    269:  * If called when there are valid data reads available, this function
                    270:  * does nothing.
                    271:  * Returns zero on failure, non-zero on success.
                    272:  */
                    273: int
                    274: io_read_flush(struct sess *sess, int fd)
                    275: {
                    276:        int32_t  tagbuf, tag;
                    277:        char     mpbuf[1024];
                    278:
                    279:        if (sess->mplex_read_remain)
                    280:                return 1;
                    281:
                    282:        /*
                    283:         * First, read the 4-byte multiplex tag.
                    284:         * The first byte is the tag identifier (7 for normal
                    285:         * data, !7 for out-of-band data), the last three are
                    286:         * for the remaining data size.
                    287:         */
                    288:
1.3       deraadt   289:        if (!io_read_blocking(sess, fd, &tagbuf, sizeof(tagbuf))) {
1.1       benno     290:                ERRX1(sess, "io_read_blocking");
                    291:                return 0;
                    292:        }
                    293:        tag = le32toh(tagbuf);
                    294:        sess->mplex_read_remain = tag & 0xFFFFFF;
                    295:        tag >>= 24;
1.4       deraadt   296:        if (tag == 7)
1.1       benno     297:                return 1;
                    298:
                    299:        tag -= 7;
                    300:
                    301:        if (sess->mplex_read_remain > sizeof(mpbuf)) {
                    302:                ERRX(sess, "multiplex buffer overflow");
                    303:                return 0;
1.4       deraadt   304:        } else if (sess->mplex_read_remain == 0)
1.1       benno     305:                return 1;
                    306:
1.11    ! benno     307:        if (!io_read_blocking(sess, fd,
        !           308:            mpbuf, sess->mplex_read_remain)) {
1.1       benno     309:                ERRX1(sess, "io_read_blocking");
                    310:                return 0;
                    311:        }
1.4       deraadt   312:        if (mpbuf[sess->mplex_read_remain - 1] == '\n')
1.1       benno     313:                mpbuf[--sess->mplex_read_remain] = '\0';
                    314:
                    315:        /*
                    316:         * Always print the server's messages, as the server
                    317:         * will control its own log levelling.
                    318:         */
                    319:
                    320:        LOG0(sess, "%.*s", (int)sess->mplex_read_remain, mpbuf);
                    321:        sess->mplex_read_remain = 0;
                    322:
1.2       benno     323:        /*
1.1       benno     324:         * I only know that a tag of one means an error.
                    325:         * This means that we should exit.
                    326:         */
                    327:
1.4       deraadt   328:        if (tag == 1) {
1.1       benno     329:                ERRX1(sess, "error from remote host");
                    330:                return 0;
                    331:        }
                    332:        return 1;
                    333: }
                    334:
                    335: /*
                    336:  * Read buffer from non-blocking descriptor, possibly in multiplex read
                    337:  * mode.
                    338:  * Returns zero on failure, non-zero on success (all bytes read from
                    339:  * the descriptor).
                    340:  */
                    341: int
                    342: io_read_buf(struct sess *sess, int fd, void *buf, size_t sz)
                    343: {
                    344:        size_t   rsz;
                    345:        int      c;
                    346:
                    347:        /* If we're not multiplexing, read directly. */
                    348:
1.3       deraadt   349:        if (!sess->mplex_reads) {
1.4       deraadt   350:                assert(sess->mplex_read_remain == 0);
1.1       benno     351:                c = io_read_blocking(sess, fd, buf, sz);
                    352:                sess->total_read += sz;
                    353:                return c;
                    354:        }
                    355:
                    356:        while (sz > 0) {
                    357:                /*
                    358:                 * First, check to see if we have any regular data
                    359:                 * hanging around waiting to be read.
                    360:                 * If so, read the lesser of that data and whatever
                    361:                 * amount we currently want.
                    362:                 */
                    363:
                    364:                if (sess->mplex_read_remain) {
                    365:                        rsz = sess->mplex_read_remain < sz ?
                    366:                                sess->mplex_read_remain : sz;
1.3       deraadt   367:                        if (!io_read_blocking(sess, fd, buf, rsz)) {
1.1       benno     368:                                ERRX1(sess, "io_read_blocking");
                    369:                                return 0;
                    370:                        }
                    371:                        sz -= rsz;
                    372:                        sess->mplex_read_remain -= rsz;
                    373:                        buf += rsz;
                    374:                        sess->total_read += rsz;
                    375:                        continue;
                    376:                }
                    377:
1.4       deraadt   378:                assert(sess->mplex_read_remain == 0);
1.3       deraadt   379:                if (!io_read_flush(sess, fd)) {
1.1       benno     380:                        ERRX1(sess, "io_read_flush");
                    381:                        return 0;
                    382:                }
                    383:        }
                    384:
                    385:        return 1;
                    386: }
                    387:
1.7       florian   388: /*
                    389:  * Like io_write_buf(), but for a long (which is a composite type).
                    390:  * Returns zero on failure, non-zero on success.
                    391:  */
1.1       benno     392: int
                    393: io_write_long(struct sess *sess, int fd, int64_t val)
                    394: {
                    395:        int64_t nv;
                    396:
                    397:        /* Short-circuit: send as an integer if possible. */
                    398:
1.7       florian   399:        if (val <= INT32_MAX && val >= 0) {
                    400:                if (!io_write_int(sess, fd, (int32_t)val)) {
                    401:                        ERRX1(sess, "io_write_int");
                    402:                        return 0;
                    403:                }
                    404:                return 1;
                    405:        }
1.1       benno     406:
                    407:        /* Otherwise, pad with max integer, then send 64-bit. */
                    408:
                    409:        nv = htole64(val);
                    410:
1.3       deraadt   411:        if (!io_write_int(sess, fd, INT32_MAX))
1.7       florian   412:                ERRX1(sess, "io_write_int");
1.3       deraadt   413:        else if (!io_write_buf(sess, fd, &nv, sizeof(int64_t)))
1.7       florian   414:                ERRX1(sess, "io_write_buf");
1.1       benno     415:        else
                    416:                return 1;
                    417:
                    418:        return 0;
                    419: }
                    420:
1.7       florian   421: /*
                    422:  * Like io_write_buf(), but for an integer.
                    423:  * Returns zero on failure, non-zero on success.
                    424:  */
1.1       benno     425: int
                    426: io_write_int(struct sess *sess, int fd, int32_t val)
                    427: {
                    428:        int32_t nv;
                    429:
                    430:        nv = htole32(val);
                    431:
1.3       deraadt   432:        if (!io_write_buf(sess, fd, &nv, sizeof(int32_t))) {
1.7       florian   433:                ERRX1(sess, "io_write_buf");
1.1       benno     434:                return 0;
                    435:        }
                    436:        return 1;
                    437: }
                    438:
                    439: /*
                    440:  * A simple assertion-protected memory copy from th einput "val" or size
                    441:  * "valsz" into our buffer "buf", full size "buflen", position "bufpos".
                    442:  * Increases our "bufpos" appropriately.
                    443:  * This has no return value, but will assert() if the size of the buffer
                    444:  * is insufficient for the new data.
                    445:  */
                    446: void
1.2       benno     447: io_buffer_buf(struct sess *sess, void *buf,
1.1       benno     448:        size_t *bufpos, size_t buflen, const void *val, size_t valsz)
                    449: {
                    450:
                    451:        assert(*bufpos + valsz <= buflen);
                    452:        memcpy(buf + *bufpos, val, valsz);
                    453:        *bufpos += valsz;
                    454: }
                    455:
                    456: /*
1.7       florian   457:  * Like io_buffer_buf(), but also accomodating for multiplexing codes.
                    458:  * This should NEVER be passed to io_write_buf(), but instead passed
                    459:  * directly to a write operation.
                    460:  */
                    461: void
                    462: io_lowbuffer_buf(struct sess *sess, void *buf,
                    463:        size_t *bufpos, size_t buflen, const void *val, size_t valsz)
                    464: {
                    465:        int32_t tagbuf;
                    466:
1.9       deraadt   467:        if (valsz == 0)
1.7       florian   468:                return;
                    469:
                    470:        if (!sess->mplex_writes) {
                    471:                io_buffer_buf(sess, buf, bufpos, buflen, val, valsz);
                    472:                return;
                    473:        }
                    474:
                    475:        assert(*bufpos + valsz + sizeof(int32_t) <= buflen);
                    476:        assert(valsz == (valsz & 0xFFFFFF));
                    477:        tagbuf = htole32((7 << 24) + valsz);
                    478:
                    479:        io_buffer_int(sess, buf, bufpos, buflen, tagbuf);
                    480:        io_buffer_buf(sess, buf, bufpos, buflen, val, valsz);
                    481: }
                    482:
                    483: /*
                    484:  * Allocate the space needed for io_lowbuffer_buf() and friends.
                    485:  * This should be called for *each* lowbuffer operation, so:
                    486:  *   io_lowbuffer_alloc(... sizeof(int32_t));
                    487:  *   io_lowbuffer_int(...);
                    488:  *   io_lowbuffer_alloc(... sizeof(int32_t));
                    489:  *   io_lowbuffer_int(...);
                    490:  * And not sizeof(int32_t) * 2 or whatnot.
                    491:  * Returns zero on failure, non-zero on succes.
                    492:  */
                    493: int
                    494: io_lowbuffer_alloc(struct sess *sess, void **buf,
                    495:        size_t *bufsz, size_t *bufmax, size_t sz)
                    496: {
                    497:        void    *pp;
                    498:        size_t   extra;
                    499:
                    500:        extra = sess->mplex_writes ? sizeof(int32_t) : 0;
                    501:
                    502:        if (*bufsz + sz + extra > *bufmax) {
                    503:                pp = realloc(*buf, *bufsz + sz + extra);
                    504:                if (pp == NULL) {
                    505:                        ERR(sess, "realloc");
                    506:                        return 0;
                    507:                }
                    508:                *buf = pp;
                    509:                *bufmax = *bufsz + sz + extra;
                    510:        }
                    511:        *bufsz += sz + extra;
                    512:        return 1;
                    513: }
                    514:
                    515: /*
                    516:  * Like io_lowbuffer_buf(), but for a single integer.
                    517:  */
                    518: void
                    519: io_lowbuffer_int(struct sess *sess, void *buf,
                    520:        size_t *bufpos, size_t buflen, int32_t val)
                    521: {
                    522:        int32_t nv = htole32(val);
                    523:
                    524:        io_lowbuffer_buf(sess, buf, bufpos, buflen, &nv, sizeof(int32_t));
                    525: }
                    526:
                    527: /*
                    528:  * Like io_buffer_buf(), but for a single integer.
1.1       benno     529:  */
                    530: void
1.2       benno     531: io_buffer_int(struct sess *sess, void *buf,
1.1       benno     532:        size_t *bufpos, size_t buflen, int32_t val)
                    533: {
                    534:        int32_t nv = htole32(val);
                    535:
1.4       deraadt   536:        io_buffer_buf(sess, buf, bufpos, buflen, &nv, sizeof(int32_t));
1.1       benno     537: }
                    538:
1.7       florian   539: /*
                    540:  * Like io_read_buf(), but for a long >=0.
                    541:  * Returns zero on failure, non-zero on success.
                    542:  */
1.1       benno     543: int
                    544: io_read_ulong(struct sess *sess, int fd, uint64_t *val)
                    545: {
                    546:        int64_t oval;
                    547:
1.3       deraadt   548:        if (!io_read_long(sess, fd, &oval)) {
1.7       florian   549:                ERRX1(sess, "io_read_long");
1.1       benno     550:                return 0;
                    551:        } else if (oval < 0) {
                    552:                ERRX(sess, "io_read_size: negative value");
                    553:                return 1;
                    554:        }
                    555:
                    556:        *val = oval;
                    557:        return 1;
                    558: }
                    559:
1.7       florian   560: /*
                    561:  * Like io_read_buf(), but for a long.
                    562:  * Returns zero on failure, non-zero on success.
                    563:  */
1.1       benno     564: int
                    565: io_read_long(struct sess *sess, int fd, int64_t *val)
                    566: {
                    567:        int64_t oval;
                    568:        int32_t sval;
                    569:
                    570:        /* Start with the short-circuit: read as an int. */
                    571:
1.3       deraadt   572:        if (!io_read_int(sess, fd, &sval)) {
1.7       florian   573:                ERRX1(sess, "io_read_int");
1.1       benno     574:                return 0;
1.4       deraadt   575:        } else if (sval != INT32_MAX) {
1.1       benno     576:                *val = sval;
                    577:                return 1;
                    578:        }
                    579:
                    580:        /* If the int is maximal, read as 64 bits. */
                    581:
1.3       deraadt   582:        if (!io_read_buf(sess, fd, &oval, sizeof(int64_t))) {
1.7       florian   583:                ERRX1(sess, "io_read_buf");
1.1       benno     584:                return 0;
                    585:        }
                    586:
                    587:        *val = le64toh(oval);
                    588:        return 1;
                    589: }
                    590:
                    591: /*
                    592:  * One thing we often need to do is read a size_t.
                    593:  * These are transmitted as int32_t, so make sure that the value
                    594:  * transmitted is not out of range.
                    595:  * FIXME: I assume that size_t can handle int32_t's max.
1.7       florian   596:  * Returns zero on failure, non-zero on success.
1.1       benno     597:  */
                    598: int
                    599: io_read_size(struct sess *sess, int fd, size_t *val)
                    600: {
                    601:        int32_t oval;
                    602:
1.3       deraadt   603:        if (!io_read_int(sess, fd, &oval)) {
1.7       florian   604:                ERRX1(sess, "io_read_int");
1.1       benno     605:                return 0;
                    606:        } else if (oval < 0) {
                    607:                ERRX(sess, "io_read_size: negative value");
                    608:                return 0;
                    609:        }
                    610:
                    611:        *val = oval;
                    612:        return 1;
                    613: }
                    614:
1.7       florian   615: /*
                    616:  * Like io_read_buf(), but for an integer.
                    617:  * Returns zero on failure, non-zero on success.
                    618:  */
1.1       benno     619: int
                    620: io_read_int(struct sess *sess, int fd, int32_t *val)
                    621: {
                    622:        int32_t oval;
                    623:
1.3       deraadt   624:        if (!io_read_buf(sess, fd, &oval, sizeof(int32_t))) {
1.7       florian   625:                ERRX1(sess, "io_read_buf");
1.1       benno     626:                return 0;
                    627:        }
                    628:
                    629:        *val = le32toh(oval);
                    630:        return 1;
                    631: }
                    632:
                    633: /*
                    634:  * Copies "valsz" from "buf", full size "bufsz" at position" bufpos",
                    635:  * into "val".
                    636:  * Calls assert() if the source doesn't have enough data.
                    637:  * Increases "bufpos" to the new position.
                    638:  */
                    639: void
1.2       benno     640: io_unbuffer_buf(struct sess *sess, const void *buf,
1.1       benno     641:        size_t *bufpos, size_t bufsz, void *val, size_t valsz)
                    642: {
                    643:
                    644:        assert(*bufpos + valsz <= bufsz);
                    645:        memcpy(val, buf + *bufpos, valsz);
                    646:        *bufpos += valsz;
                    647: }
                    648:
                    649: /*
1.7       florian   650:  * Calls io_unbuffer_buf() and converts.
1.1       benno     651:  */
                    652: void
1.2       benno     653: io_unbuffer_int(struct sess *sess, const void *buf,
1.1       benno     654:        size_t *bufpos, size_t bufsz, int32_t *val)
                    655: {
                    656:        int32_t oval;
                    657:
1.5       deraadt   658:        io_unbuffer_buf(sess, buf, bufpos, bufsz, &oval, sizeof(int32_t));
1.1       benno     659:        *val = le32toh(oval);
                    660: }
                    661:
1.7       florian   662: /*
                    663:  * Calls io_unbuffer_buf() and converts.
                    664:  */
1.1       benno     665: int
1.2       benno     666: io_unbuffer_size(struct sess *sess, const void *buf,
1.1       benno     667:        size_t *bufpos, size_t bufsz, size_t *val)
                    668: {
                    669:        int32_t oval;
                    670:
                    671:        io_unbuffer_int(sess, buf, bufpos, bufsz, &oval);
                    672:        if (oval < 0) {
                    673:                ERRX(sess, "io_unbuffer_size: negative value");
                    674:                return 0;
                    675:        }
                    676:        *val = oval;
                    677:        return 1;
                    678: }
                    679:
1.7       florian   680: /*
                    681:  * Like io_read_buf(), but for a single byte >=0.
                    682:  * Returns zero on failure, non-zero on success.
                    683:  */
1.1       benno     684: int
                    685: io_read_byte(struct sess *sess, int fd, uint8_t *val)
                    686: {
                    687:
1.3       deraadt   688:        if (!io_read_buf(sess, fd, val, sizeof(uint8_t))) {
1.7       florian   689:                ERRX1(sess, "io_read_buf");
1.1       benno     690:                return 0;
                    691:        }
                    692:        return 1;
                    693: }
                    694:
1.7       florian   695: /*
                    696:  * Like io_write_buf(), but for a single byte.
                    697:  * Returns zero on failure, non-zero on success.
                    698:  */
1.1       benno     699: int
                    700: io_write_byte(struct sess *sess, int fd, uint8_t val)
                    701: {
                    702:
1.3       deraadt   703:        if (!io_write_buf(sess, fd, &val, sizeof(uint8_t))) {
1.7       florian   704:                ERRX1(sess, "io_write_buf");
1.1       benno     705:                return 0;
                    706:        }
                    707:        return 1;
                    708: }