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