1 /* $OpenBSD: atomicio.c,v 1.10 2011/01/08 00:47:19 jeremy Exp $ */ 2 /* 3 * Copyright (c) 2006 Damien Miller. All rights reserved. 4 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 5 * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 31 #include <errno.h> 32 #include <poll.h> 33 #include <unistd.h> 34 35 #include "atomicio.h" 36 37 /* 38 * ensure all of data on socket comes through. f==read || f==vwrite 39 */ 40 size_t 41 atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) 42 { 43 char *s = _s; 44 size_t pos = 0; 45 ssize_t res; 46 struct pollfd pfd; 47 48 pfd.fd = fd; 49 pfd.events = f == read ? POLLIN : POLLOUT; 50 while (n > pos) { 51 res = (f) (fd, s + pos, n - pos); 52 switch (res) { 53 case -1: 54 if (errno == EINTR) 55 continue; 56 if ((errno == EAGAIN) || (errno == ENOBUFS)) { 57 (void)poll(&pfd, 1, -1); 58 continue; 59 } 60 return 0; 61 case 0: 62 errno = EPIPE; 63 return pos; 64 default: 65 pos += (size_t)res; 66 } 67 } 68 return (pos); 69 } 70