19f304aafSPeter Avalos /* $OpenBSD: atomicio.c,v 1.26 2010/09/22 22:58:51 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2006 Damien Miller. All rights reserved. 418de8d7fSPeter Avalos * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 518de8d7fSPeter Avalos * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 618de8d7fSPeter Avalos * All rights reserved. 718de8d7fSPeter Avalos * 818de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 918de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 1018de8d7fSPeter Avalos * are met: 1118de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 1218de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1318de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1418de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1518de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1618de8d7fSPeter Avalos * 1718de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1818de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1918de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2018de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2118de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2218de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2318de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2418de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2518de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2618de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2718de8d7fSPeter Avalos */ 2818de8d7fSPeter Avalos 2918de8d7fSPeter Avalos #include "includes.h" 3018de8d7fSPeter Avalos 3118de8d7fSPeter Avalos #include <sys/param.h> 3218de8d7fSPeter Avalos #include <sys/uio.h> 3318de8d7fSPeter Avalos 3418de8d7fSPeter Avalos #include <errno.h> 3518de8d7fSPeter Avalos #ifdef HAVE_POLL_H 3618de8d7fSPeter Avalos #include <poll.h> 3718de8d7fSPeter Avalos #else 3818de8d7fSPeter Avalos # ifdef HAVE_SYS_POLL_H 3918de8d7fSPeter Avalos # include <sys/poll.h> 4018de8d7fSPeter Avalos # endif 4118de8d7fSPeter Avalos #endif 4218de8d7fSPeter Avalos #include <string.h> 4318de8d7fSPeter Avalos #include <unistd.h> 4418de8d7fSPeter Avalos 4518de8d7fSPeter Avalos #include "atomicio.h" 4618de8d7fSPeter Avalos 4718de8d7fSPeter Avalos /* 4818de8d7fSPeter Avalos * ensure all of data on socket comes through. f==read || f==vwrite 4918de8d7fSPeter Avalos */ 5018de8d7fSPeter Avalos size_t 519f304aafSPeter Avalos atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n, 529f304aafSPeter Avalos int (*cb)(void *, size_t), void *cb_arg) 5318de8d7fSPeter Avalos { 5418de8d7fSPeter Avalos char *s = _s; 5518de8d7fSPeter Avalos size_t pos = 0; 5618de8d7fSPeter Avalos ssize_t res; 5718de8d7fSPeter Avalos struct pollfd pfd; 5818de8d7fSPeter Avalos 59*36e94dc5SPeter Avalos #ifndef BROKEN_READ_COMPARISON 6018de8d7fSPeter Avalos pfd.fd = fd; 6118de8d7fSPeter Avalos pfd.events = f == read ? POLLIN : POLLOUT; 62*36e94dc5SPeter Avalos #endif 6318de8d7fSPeter Avalos while (n > pos) { 6418de8d7fSPeter Avalos res = (f) (fd, s + pos, n - pos); 6518de8d7fSPeter Avalos switch (res) { 6618de8d7fSPeter Avalos case -1: 6718de8d7fSPeter Avalos if (errno == EINTR) 6818de8d7fSPeter Avalos continue; 6918de8d7fSPeter Avalos if (errno == EAGAIN || errno == EWOULDBLOCK) { 70*36e94dc5SPeter Avalos #ifndef BROKEN_READ_COMPARISON 7118de8d7fSPeter Avalos (void)poll(&pfd, 1, -1); 72*36e94dc5SPeter Avalos #endif 7318de8d7fSPeter Avalos continue; 7418de8d7fSPeter Avalos } 7518de8d7fSPeter Avalos return 0; 7618de8d7fSPeter Avalos case 0: 7718de8d7fSPeter Avalos errno = EPIPE; 7818de8d7fSPeter Avalos return pos; 7918de8d7fSPeter Avalos default: 8018de8d7fSPeter Avalos pos += (size_t)res; 819f304aafSPeter Avalos if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { 829f304aafSPeter Avalos errno = EINTR; 839f304aafSPeter Avalos return pos; 8418de8d7fSPeter Avalos } 8518de8d7fSPeter Avalos } 869f304aafSPeter Avalos } 879f304aafSPeter Avalos return pos; 889f304aafSPeter Avalos } 899f304aafSPeter Avalos 909f304aafSPeter Avalos size_t 919f304aafSPeter Avalos atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 929f304aafSPeter Avalos { 939f304aafSPeter Avalos return atomicio6(f, fd, _s, n, NULL, NULL); 9418de8d7fSPeter Avalos } 9518de8d7fSPeter Avalos 9618de8d7fSPeter Avalos /* 9718de8d7fSPeter Avalos * ensure all of data on socket comes through. f==readv || f==writev 9818de8d7fSPeter Avalos */ 9918de8d7fSPeter Avalos size_t 1009f304aafSPeter Avalos atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd, 1019f304aafSPeter Avalos const struct iovec *_iov, int iovcnt, 1029f304aafSPeter Avalos int (*cb)(void *, size_t), void *cb_arg) 10318de8d7fSPeter Avalos { 10418de8d7fSPeter Avalos size_t pos = 0, rem; 10518de8d7fSPeter Avalos ssize_t res; 10618de8d7fSPeter Avalos struct iovec iov_array[IOV_MAX], *iov = iov_array; 10718de8d7fSPeter Avalos struct pollfd pfd; 10818de8d7fSPeter Avalos 10918de8d7fSPeter Avalos if (iovcnt > IOV_MAX) { 11018de8d7fSPeter Avalos errno = EINVAL; 11118de8d7fSPeter Avalos return 0; 11218de8d7fSPeter Avalos } 11318de8d7fSPeter Avalos /* Make a copy of the iov array because we may modify it below */ 11418de8d7fSPeter Avalos memcpy(iov, _iov, iovcnt * sizeof(*_iov)); 11518de8d7fSPeter Avalos 11618de8d7fSPeter Avalos #ifndef BROKEN_READV_COMPARISON 11718de8d7fSPeter Avalos pfd.fd = fd; 11818de8d7fSPeter Avalos pfd.events = f == readv ? POLLIN : POLLOUT; 11918de8d7fSPeter Avalos #endif 12018de8d7fSPeter Avalos for (; iovcnt > 0 && iov[0].iov_len > 0;) { 12118de8d7fSPeter Avalos res = (f) (fd, iov, iovcnt); 12218de8d7fSPeter Avalos switch (res) { 12318de8d7fSPeter Avalos case -1: 12418de8d7fSPeter Avalos if (errno == EINTR) 12518de8d7fSPeter Avalos continue; 12618de8d7fSPeter Avalos if (errno == EAGAIN || errno == EWOULDBLOCK) { 12718de8d7fSPeter Avalos #ifndef BROKEN_READV_COMPARISON 12818de8d7fSPeter Avalos (void)poll(&pfd, 1, -1); 12918de8d7fSPeter Avalos #endif 13018de8d7fSPeter Avalos continue; 13118de8d7fSPeter Avalos } 13218de8d7fSPeter Avalos return 0; 13318de8d7fSPeter Avalos case 0: 13418de8d7fSPeter Avalos errno = EPIPE; 13518de8d7fSPeter Avalos return pos; 13618de8d7fSPeter Avalos default: 13718de8d7fSPeter Avalos rem = (size_t)res; 13818de8d7fSPeter Avalos pos += rem; 13918de8d7fSPeter Avalos /* skip completed iov entries */ 14018de8d7fSPeter Avalos while (iovcnt > 0 && rem >= iov[0].iov_len) { 14118de8d7fSPeter Avalos rem -= iov[0].iov_len; 14218de8d7fSPeter Avalos iov++; 14318de8d7fSPeter Avalos iovcnt--; 14418de8d7fSPeter Avalos } 14518de8d7fSPeter Avalos /* This shouldn't happen... */ 14618de8d7fSPeter Avalos if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { 14718de8d7fSPeter Avalos errno = EFAULT; 14818de8d7fSPeter Avalos return 0; 14918de8d7fSPeter Avalos } 15018de8d7fSPeter Avalos if (iovcnt == 0) 15118de8d7fSPeter Avalos break; 15218de8d7fSPeter Avalos /* update pointer in partially complete iov */ 15318de8d7fSPeter Avalos iov[0].iov_base = ((char *)iov[0].iov_base) + rem; 15418de8d7fSPeter Avalos iov[0].iov_len -= rem; 15518de8d7fSPeter Avalos } 1569f304aafSPeter Avalos if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { 1579f304aafSPeter Avalos errno = EINTR; 1589f304aafSPeter Avalos return pos; 1599f304aafSPeter Avalos } 16018de8d7fSPeter Avalos } 16118de8d7fSPeter Avalos return pos; 16218de8d7fSPeter Avalos } 1639f304aafSPeter Avalos 1649f304aafSPeter Avalos size_t 1659f304aafSPeter Avalos atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, 1669f304aafSPeter Avalos const struct iovec *_iov, int iovcnt) 1679f304aafSPeter Avalos { 1689f304aafSPeter Avalos return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL); 1699f304aafSPeter Avalos } 170