atomicio.c revision 262566
1220297Sadrian/* $OpenBSD: atomicio.c,v 1.26 2010/09/22 22:58:51 djm Exp $ */ 2220297Sadrian/* 3220297Sadrian * Copyright (c) 2006 Damien Miller. All rights reserved. 4220297Sadrian * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 5220297Sadrian * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 6220297Sadrian * All rights reserved. 7220297Sadrian * 8220297Sadrian * Redistribution and use in source and binary forms, with or without 9220297Sadrian * modification, are permitted provided that the following conditions 10220297Sadrian * are met: 11220297Sadrian * 1. Redistributions of source code must retain the above copyright 12220297Sadrian * notice, this list of conditions and the following disclaimer. 13220297Sadrian * 2. Redistributions in binary form must reproduce the above copyright 14220297Sadrian * notice, this list of conditions and the following disclaimer in the 15220297Sadrian * documentation and/or other materials provided with the distribution. 16220297Sadrian * 17220297Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18220297Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19220297Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20220297Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21220297Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22220297Sadrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23220297Sadrian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24220297Sadrian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25220297Sadrian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26220297Sadrian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27220297Sadrian */ 28220297Sadrian 29220297Sadrian#include "includes.h" 30220297Sadrian 31220297Sadrian#include <sys/param.h> 32220297Sadrian#include <sys/uio.h> 33220297Sadrian 34220297Sadrian#include <errno.h> 35220297Sadrian#ifdef HAVE_POLL_H 36220297Sadrian#include <poll.h> 37220297Sadrian#else 38220297Sadrian# ifdef HAVE_SYS_POLL_H 39220297Sadrian# include <sys/poll.h> 40220297Sadrian# endif 41220297Sadrian#endif 42220297Sadrian#include <string.h> 43220297Sadrian#include <unistd.h> 44220297Sadrian 45220297Sadrian#include "atomicio.h" 46220297Sadrian 47220297Sadrian/* 48220297Sadrian * ensure all of data on socket comes through. f==read || f==vwrite 49220297Sadrian */ 50220297Sadriansize_t 51220297Sadrianatomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n, 52220297Sadrian int (*cb)(void *, size_t), void *cb_arg) 53220297Sadrian{ 54220297Sadrian char *s = _s; 55220297Sadrian size_t pos = 0; 56220297Sadrian ssize_t res; 57220297Sadrian struct pollfd pfd; 58220297Sadrian 59220297Sadrian#ifndef BROKEN_READ_COMPARISON 60220297Sadrian pfd.fd = fd; 61220297Sadrian pfd.events = f == read ? POLLIN : POLLOUT; 62220297Sadrian#endif 63220297Sadrian while (n > pos) { 64220297Sadrian res = (f) (fd, s + pos, n - pos); 65220297Sadrian switch (res) { 66220297Sadrian case -1: 67220297Sadrian if (errno == EINTR) 68220297Sadrian continue; 69220297Sadrian if (errno == EAGAIN || errno == EWOULDBLOCK) { 70220297Sadrian#ifndef BROKEN_READ_COMPARISON 71220297Sadrian (void)poll(&pfd, 1, -1); 72220297Sadrian#endif 73220297Sadrian continue; 74220297Sadrian } 75220297Sadrian return 0; 76220297Sadrian case 0: 77220297Sadrian errno = EPIPE; 78220297Sadrian return pos; 79220297Sadrian default: 80220297Sadrian pos += (size_t)res; 81220297Sadrian if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { 82220297Sadrian errno = EINTR; 83220297Sadrian return pos; 84220297Sadrian } 85220297Sadrian } 86220297Sadrian } 87220297Sadrian return pos; 88220297Sadrian} 89220297Sadrian 90220297Sadriansize_t 91220297Sadrianatomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 92220297Sadrian{ 93220297Sadrian return atomicio6(f, fd, _s, n, NULL, NULL); 94220297Sadrian} 95278278Shselasky 96220297Sadrian/* 97220297Sadrian * ensure all of data on socket comes through. f==readv || f==writev 98220297Sadrian */ 99220297Sadriansize_t 100220297Sadrianatomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd, 101220297Sadrian const struct iovec *_iov, int iovcnt, 102220297Sadrian int (*cb)(void *, size_t), void *cb_arg) 103220297Sadrian{ 104220297Sadrian size_t pos = 0, rem; 105220297Sadrian ssize_t res; 106220297Sadrian struct iovec iov_array[IOV_MAX], *iov = iov_array; 107220297Sadrian struct pollfd pfd; 108220297Sadrian 109220297Sadrian if (iovcnt > IOV_MAX) { 110220297Sadrian errno = EINVAL; 111220297Sadrian return 0; 112220297Sadrian } 113220297Sadrian /* Make a copy of the iov array because we may modify it below */ 114220297Sadrian memcpy(iov, _iov, iovcnt * sizeof(*_iov)); 115220297Sadrian 116220297Sadrian#ifndef BROKEN_READV_COMPARISON 117220297Sadrian pfd.fd = fd; 118220297Sadrian pfd.events = f == readv ? POLLIN : POLLOUT; 119220297Sadrian#endif 120220297Sadrian for (; iovcnt > 0 && iov[0].iov_len > 0;) { 121220297Sadrian res = (f) (fd, iov, iovcnt); 122220297Sadrian switch (res) { 123220297Sadrian case -1: 124220297Sadrian if (errno == EINTR) 125220297Sadrian continue; 126220297Sadrian if (errno == EAGAIN || errno == EWOULDBLOCK) { 127220297Sadrian#ifndef BROKEN_READV_COMPARISON 128220297Sadrian (void)poll(&pfd, 1, -1); 129220297Sadrian#endif 130220297Sadrian continue; 131220297Sadrian } 132220297Sadrian return 0; 133220297Sadrian case 0: 134220297Sadrian errno = EPIPE; 135220297Sadrian return pos; 136220297Sadrian default: 137220297Sadrian rem = (size_t)res; 138220297Sadrian pos += rem; 139220297Sadrian /* skip completed iov entries */ 140220297Sadrian while (iovcnt > 0 && rem >= iov[0].iov_len) { 141220297Sadrian rem -= iov[0].iov_len; 142220297Sadrian iov++; 143220297Sadrian iovcnt--; 144220297Sadrian } 145220297Sadrian /* This shouldn't happen... */ 146220297Sadrian if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { 147220297Sadrian errno = EFAULT; 148220297Sadrian return 0; 149220297Sadrian } 150220297Sadrian if (iovcnt == 0) 151220297Sadrian break; 152220297Sadrian /* update pointer in partially complete iov */ 153220297Sadrian iov[0].iov_base = ((char *)iov[0].iov_base) + rem; 154220297Sadrian iov[0].iov_len -= rem; 155220297Sadrian } 156220297Sadrian if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { 157220297Sadrian errno = EINTR; 158220297Sadrian return pos; 159220297Sadrian } 160220297Sadrian } 161220297Sadrian return pos; 162220297Sadrian} 163220297Sadrian 164220297Sadriansize_t 165220297Sadrianatomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, 166220297Sadrian const struct iovec *_iov, int iovcnt) 167220297Sadrian{ 168220297Sadrian return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL); 169220297Sadrian} 170220297Sadrian