1 /* $NetBSD: atomicio.c,v 1.2 2009/06/07 22:38:46 christos Exp $ */ 2 /* $OpenBSD: atomicio.c,v 1.25 2007/06/25 12:02:27 dtucker 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.2 2009/06/07 22:38:46 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 */ 45 size_t 46 atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 47 { 48 char *s = _s; 49 size_t pos = 0; 50 ssize_t res; 51 struct pollfd pfd; 52 53 pfd.fd = fd; 54 pfd.events = f == read ? POLLIN : POLLOUT; 55 while (n > pos) { 56 res = (f) (fd, s + pos, n - pos); 57 switch (res) { 58 case -1: 59 if (errno == EINTR) 60 continue; 61 if (errno == EAGAIN) { 62 (void)poll(&pfd, 1, -1); 63 continue; 64 } 65 return 0; 66 case 0: 67 errno = EPIPE; 68 return pos; 69 default: 70 pos += (size_t)res; 71 } 72 } 73 return (pos); 74 } 75 76 /* 77 * ensure all of data on socket comes through. f==readv || f==writev 78 */ 79 size_t 80 atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, 81 const struct iovec *_iov, int iovcnt) 82 { 83 size_t pos = 0, rem; 84 ssize_t res; 85 struct iovec iov_array[IOV_MAX], *iov = iov_array; 86 struct pollfd pfd; 87 88 if (iovcnt > IOV_MAX) { 89 errno = EINVAL; 90 return 0; 91 } 92 /* Make a copy of the iov array because we may modify it below */ 93 memcpy(iov, _iov, iovcnt * sizeof(*_iov)); 94 95 pfd.fd = fd; 96 pfd.events = f == readv ? POLLIN : POLLOUT; 97 for (; iovcnt > 0 && iov[0].iov_len > 0;) { 98 res = (f) (fd, iov, iovcnt); 99 switch (res) { 100 case -1: 101 if (errno == EINTR) 102 continue; 103 if (errno == EAGAIN) { 104 (void)poll(&pfd, 1, -1); 105 continue; 106 } 107 return 0; 108 case 0: 109 errno = EPIPE; 110 return pos; 111 default: 112 rem = (size_t)res; 113 pos += rem; 114 /* skip completed iov entries */ 115 while (iovcnt > 0 && rem >= iov[0].iov_len) { 116 rem -= iov[0].iov_len; 117 iov++; 118 iovcnt--; 119 } 120 /* This shouldn't happen... */ 121 if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { 122 errno = EFAULT; 123 return 0; 124 } 125 if (iovcnt == 0) 126 break; 127 /* update pointer in partially complete iov */ 128 iov[0].iov_base = ((char *)iov[0].iov_base) + rem; 129 iov[0].iov_len -= rem; 130 } 131 } 132 return pos; 133 } 134