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