atomicio.c revision 162852
1162852Sdes/* $OpenBSD: atomicio.c,v 1.23 2006/08/03 03:34:41 deraadt Exp $ */ 257429Smarkm/* 3162852Sdes * Copyright (c) 2006 Damien Miller. All rights reserved. 4149749Sdes * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 576259Sgreen * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 657429Smarkm * All rights reserved. 757429Smarkm * 857429Smarkm * Redistribution and use in source and binary forms, with or without 957429Smarkm * modification, are permitted provided that the following conditions 1057429Smarkm * are met: 1157429Smarkm * 1. Redistributions of source code must retain the above copyright 1257429Smarkm * notice, this list of conditions and the following disclaimer. 1357429Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1457429Smarkm * notice, this list of conditions and the following disclaimer in the 1557429Smarkm * documentation and/or other materials provided with the distribution. 1657429Smarkm * 1757429Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1857429Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1957429Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2057429Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2157429Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2257429Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2357429Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2457429Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2557429Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2657429Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2757429Smarkm */ 2857429Smarkm 2957429Smarkm#include "includes.h" 3057429Smarkm 31162852Sdes#include <sys/param.h> 32162852Sdes#include <sys/uio.h> 33162852Sdes 34162852Sdes#include <errno.h> 35162852Sdes#include <string.h> 36162852Sdes 3776259Sgreen#include "atomicio.h" 3857429Smarkm 3957429Smarkm/* 40124208Sdes * ensure all of data on socket comes through. f==read || f==vwrite 4157429Smarkm */ 42149749Sdessize_t 43162852Sdesatomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 4457429Smarkm{ 4558582Skris char *s = _s; 46149749Sdes size_t pos = 0; 47149749Sdes ssize_t res; 4857429Smarkm 4957429Smarkm while (n > pos) { 5057429Smarkm res = (f) (fd, s + pos, n - pos); 5157429Smarkm switch (res) { 5257429Smarkm case -1: 5398937Sdes#ifdef EWOULDBLOCK 5498937Sdes if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) 5598937Sdes#else 5657429Smarkm if (errno == EINTR || errno == EAGAIN) 5798937Sdes#endif 5857429Smarkm continue; 59149749Sdes return 0; 6057429Smarkm case 0: 61149749Sdes errno = EPIPE; 62149749Sdes return pos; 6357429Smarkm default: 64162852Sdes pos += (size_t)res; 6557429Smarkm } 6657429Smarkm } 6757429Smarkm return (pos); 6857429Smarkm} 69162852Sdes 70162852Sdes/* 71162852Sdes * ensure all of data on socket comes through. f==readv || f==writev 72162852Sdes */ 73162852Sdessize_t 74162852Sdesatomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, 75162852Sdes const struct iovec *_iov, int iovcnt) 76162852Sdes{ 77162852Sdes size_t pos = 0, rem; 78162852Sdes ssize_t res; 79162852Sdes struct iovec iov_array[IOV_MAX], *iov = iov_array; 80162852Sdes 81162852Sdes if (iovcnt > IOV_MAX) { 82162852Sdes errno = EINVAL; 83162852Sdes return 0; 84162852Sdes } 85162852Sdes /* Make a copy of the iov array because we may modify it below */ 86162852Sdes memcpy(iov, _iov, iovcnt * sizeof(*_iov)); 87162852Sdes 88162852Sdes for (; iovcnt > 0 && iov[0].iov_len > 0;) { 89162852Sdes res = (f) (fd, iov, iovcnt); 90162852Sdes switch (res) { 91162852Sdes case -1: 92162852Sdes if (errno == EINTR || errno == EAGAIN) 93162852Sdes continue; 94162852Sdes return 0; 95162852Sdes case 0: 96162852Sdes errno = EPIPE; 97162852Sdes return pos; 98162852Sdes default: 99162852Sdes rem = (size_t)res; 100162852Sdes pos += rem; 101162852Sdes /* skip completed iov entries */ 102162852Sdes while (iovcnt > 0 && rem >= iov[0].iov_len) { 103162852Sdes rem -= iov[0].iov_len; 104162852Sdes iov++; 105162852Sdes iovcnt--; 106162852Sdes } 107162852Sdes /* This shouldn't happen... */ 108162852Sdes if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { 109162852Sdes errno = EFAULT; 110162852Sdes return 0; 111162852Sdes } 112162852Sdes if (iovcnt == 0) 113162852Sdes break; 114162852Sdes /* update pointer in partially complete iov */ 115162852Sdes iov[0].iov_base = ((char *)iov[0].iov_base) + rem; 116162852Sdes iov[0].iov_len -= rem; 117162852Sdes } 118162852Sdes } 119162852Sdes return pos; 120162852Sdes} 121