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