1*18de8d7fSPeter Avalos /* $OpenBSD: atomicio.c,v 1.25 2007/06/25 12:02:27 dtucker Exp $ */ 2*18de8d7fSPeter Avalos /* 3*18de8d7fSPeter Avalos * Copyright (c) 2006 Damien Miller. All rights reserved. 4*18de8d7fSPeter Avalos * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 5*18de8d7fSPeter Avalos * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 6*18de8d7fSPeter Avalos * All rights reserved. 7*18de8d7fSPeter Avalos * 8*18de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 9*18de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 10*18de8d7fSPeter Avalos * are met: 11*18de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 12*18de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 13*18de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 14*18de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 15*18de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 16*18de8d7fSPeter Avalos * 17*18de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18*18de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19*18de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20*18de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21*18de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22*18de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23*18de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*18de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25*18de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26*18de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*18de8d7fSPeter Avalos */ 28*18de8d7fSPeter Avalos 29*18de8d7fSPeter Avalos #include "includes.h" 30*18de8d7fSPeter Avalos 31*18de8d7fSPeter Avalos #include <sys/param.h> 32*18de8d7fSPeter Avalos #include <sys/uio.h> 33*18de8d7fSPeter Avalos 34*18de8d7fSPeter Avalos #include <errno.h> 35*18de8d7fSPeter Avalos #ifdef HAVE_POLL_H 36*18de8d7fSPeter Avalos #include <poll.h> 37*18de8d7fSPeter Avalos #else 38*18de8d7fSPeter Avalos # ifdef HAVE_SYS_POLL_H 39*18de8d7fSPeter Avalos # include <sys/poll.h> 40*18de8d7fSPeter Avalos # endif 41*18de8d7fSPeter Avalos #endif 42*18de8d7fSPeter Avalos #include <string.h> 43*18de8d7fSPeter Avalos #include <unistd.h> 44*18de8d7fSPeter Avalos 45*18de8d7fSPeter Avalos #include "atomicio.h" 46*18de8d7fSPeter Avalos 47*18de8d7fSPeter Avalos /* 48*18de8d7fSPeter Avalos * ensure all of data on socket comes through. f==read || f==vwrite 49*18de8d7fSPeter Avalos */ 50*18de8d7fSPeter Avalos size_t 51*18de8d7fSPeter Avalos atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 52*18de8d7fSPeter Avalos { 53*18de8d7fSPeter Avalos char *s = _s; 54*18de8d7fSPeter Avalos size_t pos = 0; 55*18de8d7fSPeter Avalos ssize_t res; 56*18de8d7fSPeter Avalos struct pollfd pfd; 57*18de8d7fSPeter Avalos 58*18de8d7fSPeter Avalos pfd.fd = fd; 59*18de8d7fSPeter Avalos pfd.events = f == read ? POLLIN : POLLOUT; 60*18de8d7fSPeter Avalos while (n > pos) { 61*18de8d7fSPeter Avalos res = (f) (fd, s + pos, n - pos); 62*18de8d7fSPeter Avalos switch (res) { 63*18de8d7fSPeter Avalos case -1: 64*18de8d7fSPeter Avalos if (errno == EINTR) 65*18de8d7fSPeter Avalos continue; 66*18de8d7fSPeter Avalos if (errno == EAGAIN || errno == EWOULDBLOCK) { 67*18de8d7fSPeter Avalos (void)poll(&pfd, 1, -1); 68*18de8d7fSPeter Avalos continue; 69*18de8d7fSPeter Avalos } 70*18de8d7fSPeter Avalos return 0; 71*18de8d7fSPeter Avalos case 0: 72*18de8d7fSPeter Avalos errno = EPIPE; 73*18de8d7fSPeter Avalos return pos; 74*18de8d7fSPeter Avalos default: 75*18de8d7fSPeter Avalos pos += (size_t)res; 76*18de8d7fSPeter Avalos } 77*18de8d7fSPeter Avalos } 78*18de8d7fSPeter Avalos return (pos); 79*18de8d7fSPeter Avalos } 80*18de8d7fSPeter Avalos 81*18de8d7fSPeter Avalos /* 82*18de8d7fSPeter Avalos * ensure all of data on socket comes through. f==readv || f==writev 83*18de8d7fSPeter Avalos */ 84*18de8d7fSPeter Avalos size_t 85*18de8d7fSPeter Avalos atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, 86*18de8d7fSPeter Avalos const struct iovec *_iov, int iovcnt) 87*18de8d7fSPeter Avalos { 88*18de8d7fSPeter Avalos size_t pos = 0, rem; 89*18de8d7fSPeter Avalos ssize_t res; 90*18de8d7fSPeter Avalos struct iovec iov_array[IOV_MAX], *iov = iov_array; 91*18de8d7fSPeter Avalos struct pollfd pfd; 92*18de8d7fSPeter Avalos 93*18de8d7fSPeter Avalos if (iovcnt > IOV_MAX) { 94*18de8d7fSPeter Avalos errno = EINVAL; 95*18de8d7fSPeter Avalos return 0; 96*18de8d7fSPeter Avalos } 97*18de8d7fSPeter Avalos /* Make a copy of the iov array because we may modify it below */ 98*18de8d7fSPeter Avalos memcpy(iov, _iov, iovcnt * sizeof(*_iov)); 99*18de8d7fSPeter Avalos 100*18de8d7fSPeter Avalos #ifndef BROKEN_READV_COMPARISON 101*18de8d7fSPeter Avalos pfd.fd = fd; 102*18de8d7fSPeter Avalos pfd.events = f == readv ? POLLIN : POLLOUT; 103*18de8d7fSPeter Avalos #endif 104*18de8d7fSPeter Avalos for (; iovcnt > 0 && iov[0].iov_len > 0;) { 105*18de8d7fSPeter Avalos res = (f) (fd, iov, iovcnt); 106*18de8d7fSPeter Avalos switch (res) { 107*18de8d7fSPeter Avalos case -1: 108*18de8d7fSPeter Avalos if (errno == EINTR) 109*18de8d7fSPeter Avalos continue; 110*18de8d7fSPeter Avalos if (errno == EAGAIN || errno == EWOULDBLOCK) { 111*18de8d7fSPeter Avalos #ifndef BROKEN_READV_COMPARISON 112*18de8d7fSPeter Avalos (void)poll(&pfd, 1, -1); 113*18de8d7fSPeter Avalos #endif 114*18de8d7fSPeter Avalos continue; 115*18de8d7fSPeter Avalos } 116*18de8d7fSPeter Avalos return 0; 117*18de8d7fSPeter Avalos case 0: 118*18de8d7fSPeter Avalos errno = EPIPE; 119*18de8d7fSPeter Avalos return pos; 120*18de8d7fSPeter Avalos default: 121*18de8d7fSPeter Avalos rem = (size_t)res; 122*18de8d7fSPeter Avalos pos += rem; 123*18de8d7fSPeter Avalos /* skip completed iov entries */ 124*18de8d7fSPeter Avalos while (iovcnt > 0 && rem >= iov[0].iov_len) { 125*18de8d7fSPeter Avalos rem -= iov[0].iov_len; 126*18de8d7fSPeter Avalos iov++; 127*18de8d7fSPeter Avalos iovcnt--; 128*18de8d7fSPeter Avalos } 129*18de8d7fSPeter Avalos /* This shouldn't happen... */ 130*18de8d7fSPeter Avalos if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { 131*18de8d7fSPeter Avalos errno = EFAULT; 132*18de8d7fSPeter Avalos return 0; 133*18de8d7fSPeter Avalos } 134*18de8d7fSPeter Avalos if (iovcnt == 0) 135*18de8d7fSPeter Avalos break; 136*18de8d7fSPeter Avalos /* update pointer in partially complete iov */ 137*18de8d7fSPeter Avalos iov[0].iov_base = ((char *)iov[0].iov_base) + rem; 138*18de8d7fSPeter Avalos iov[0].iov_len -= rem; 139*18de8d7fSPeter Avalos } 140*18de8d7fSPeter Avalos } 141*18de8d7fSPeter Avalos return pos; 142*18de8d7fSPeter Avalos } 143