1219820Sjeff/* $NetBSD: atomicio.c,v 1.9 2019/04/20 17:16:40 christos Exp $ */ 2219820Sjeff/* $OpenBSD: atomicio.c,v 1.30 2019/01/24 02:42:23 dtucker Exp $ */ 3219820Sjeff/* 4219820Sjeff * Copyright (c) 2006 Damien Miller. All rights reserved. 5219820Sjeff * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 6219820Sjeff * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 7219820Sjeff * All rights reserved. 8219820Sjeff * 9219820Sjeff * Redistribution and use in source and binary forms, with or without 10219820Sjeff * modification, are permitted provided that the following conditions 11219820Sjeff * are met: 12219820Sjeff * 1. Redistributions of source code must retain the above copyright 13219820Sjeff * notice, this list of conditions and the following disclaimer. 14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 15219820Sjeff * notice, this list of conditions and the following disclaimer in the 16219820Sjeff * documentation and/or other materials provided with the distribution. 17219820Sjeff * 18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28219820Sjeff */ 29219820Sjeff 30219820Sjeff#include "includes.h" 31219820Sjeff__RCSID("$NetBSD: atomicio.c,v 1.9 2019/04/20 17:16:40 christos Exp $"); 32219820Sjeff#include <sys/param.h> 33219820Sjeff#include <sys/uio.h> 34219820Sjeff 35219820Sjeff#include <errno.h> 36219820Sjeff#include <poll.h> 37219820Sjeff#include <string.h> 38219820Sjeff#include <unistd.h> 39219820Sjeff#include <limits.h> 40219820Sjeff 41219820Sjeff#include "atomicio.h" 42219820Sjeff 43219820Sjeff/* 44219820Sjeff * ensure all of data on socket comes through. f==read || f==vwrite 45219820Sjeff */ 46219820Sjeffsize_t 47219820Sjeffatomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n, 48219820Sjeff int (*cb)(void *, size_t), void *cb_arg) 49219820Sjeff{ 50219820Sjeff char *s = _s; 51219820Sjeff size_t pos = 0; 52219820Sjeff ssize_t res; 53219820Sjeff struct pollfd pfd; 54219820Sjeff 55219820Sjeff pfd.fd = fd; 56219820Sjeff /* 57219820Sjeff * check for vwrite instead of read to avoid read being renamed 58219820Sjeff * by SSP issues 59219820Sjeff */ 60219820Sjeff pfd.events = f == vwrite ? POLLOUT : POLLIN; 61219820Sjeff while (n > pos) { 62219820Sjeff res = (f) (fd, s + pos, n - pos); 63219820Sjeff switch (res) { 64219820Sjeff case -1: 65219820Sjeff if (errno == EINTR) { 66219820Sjeff /* possible SIGALARM, update callback */ 67219820Sjeff if (cb != NULL && cb(cb_arg, 0) == -1) { 68219820Sjeff errno = EINTR; 69219820Sjeff return pos; 70219820Sjeff } 71219820Sjeff continue; 72219820Sjeff } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 73219820Sjeff (void)poll(&pfd, 1, -1); 74219820Sjeff continue; 75219820Sjeff } 76219820Sjeff return 0; 77219820Sjeff case 0: 78219820Sjeff errno = EPIPE; 79219820Sjeff return pos; 80219820Sjeff default: 81219820Sjeff pos += (size_t)res; 82219820Sjeff if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { 83219820Sjeff errno = EINTR; 84219820Sjeff return pos; 85219820Sjeff } 86219820Sjeff } 87219820Sjeff } 88219820Sjeff return pos; 89219820Sjeff} 90219820Sjeff 91219820Sjeffsize_t 92219820Sjeffatomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 93219820Sjeff{ 94219820Sjeff return atomicio6(f, fd, _s, n, NULL, NULL); 95219820Sjeff} 96219820Sjeff 97219820Sjeff/* 98219820Sjeff * ensure all of data on socket comes through. f==readv || f==writev 99219820Sjeff */ 100219820Sjeffsize_t 101219820Sjeffatomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd, 102219820Sjeff const struct iovec *_iov, int iovcnt, 103219820Sjeff int (*cb)(void *, size_t), void *cb_arg) 104219820Sjeff{ 105219820Sjeff size_t pos = 0, rem; 106219820Sjeff ssize_t res; 107219820Sjeff struct iovec iov_array[IOV_MAX], *iov = iov_array; 108219820Sjeff struct pollfd pfd; 109219820Sjeff 110219820Sjeff if (iovcnt < 0 || iovcnt > IOV_MAX) { 111219820Sjeff errno = EINVAL; 112219820Sjeff return 0; 113219820Sjeff } 114219820Sjeff /* Make a copy of the iov array because we may modify it below */ 115219820Sjeff memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov)); 116219820Sjeff 117219820Sjeff pfd.fd = fd; 118219820Sjeff pfd.events = f == readv ? POLLIN : POLLOUT; 119219820Sjeff for (; iovcnt > 0 && iov[0].iov_len > 0;) { 120219820Sjeff res = (f) (fd, iov, iovcnt); 121219820Sjeff switch (res) { 122219820Sjeff case -1: 123219820Sjeff if (errno == EINTR) { 124219820Sjeff /* possible SIGALARM, update callback */ 125219820Sjeff if (cb != NULL && cb(cb_arg, 0) == -1) { 126219820Sjeff errno = EINTR; 127219820Sjeff return pos; 128219820Sjeff } 129219820Sjeff continue; 130219820Sjeff } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 131219820Sjeff (void)poll(&pfd, 1, -1); 132219820Sjeff continue; 133219820Sjeff } 134219820Sjeff return 0; 135219820Sjeff case 0: 136219820Sjeff errno = EPIPE; 137219820Sjeff return pos; 138219820Sjeff default: 139219820Sjeff rem = (size_t)res; 140219820Sjeff pos += rem; 141219820Sjeff /* skip completed iov entries */ 142219820Sjeff while (iovcnt > 0 && rem >= iov[0].iov_len) { 143219820Sjeff rem -= iov[0].iov_len; 144219820Sjeff iov++; 145219820Sjeff iovcnt--; 146219820Sjeff } 147219820Sjeff /* This shouldn't happen... */ 148219820Sjeff if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { 149219820Sjeff errno = EFAULT; 150219820Sjeff return 0; 151219820Sjeff } 152219820Sjeff if (iovcnt == 0) 153219820Sjeff break; 154219820Sjeff /* update pointer in partially complete iov */ 155219820Sjeff iov[0].iov_base = ((char *)iov[0].iov_base) + rem; 156219820Sjeff iov[0].iov_len -= rem; 157219820Sjeff } 158219820Sjeff if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { 159219820Sjeff errno = EINTR; 160219820Sjeff return pos; 161219820Sjeff } 162219820Sjeff } 163219820Sjeff return pos; 164219820Sjeff} 165219820Sjeff 166219820Sjeffsize_t 167219820Sjeffatomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, 168219820Sjeff const struct iovec *_iov, int iovcnt) 169219820Sjeff{ 170219820Sjeff return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL); 171219820Sjeff} 172219820Sjeff