Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (c) 2006 Damien Miller. All rights reserved.
      3  * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
      4  * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "includes.h"
     29 RCSID("$OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp $");
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include "atomicio.h"
     34 
     35 /*
     36  * ensure all of data on socket comes through. f==read || f==write
     37  */
     38 ssize_t
     39 atomicio(f, fd, _s, n)
     40 	ssize_t (*f) ();
     41 	int fd;
     42 	void *_s;
     43 	size_t n;
     44 {
     45 	char *s = _s;
     46 	ssize_t res, pos = 0;
     47 
     48 	while (n > pos) {
     49 		res = (f) (fd, s + pos, n - pos);
     50 		switch (res) {
     51 		case -1:
     52 #ifdef EWOULDBLOCK
     53 			if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
     54 #else
     55 			if (errno == EINTR || errno == EAGAIN)
     56 #endif
     57 				continue;
     58 			/* FALLTHROUGH */
     59 		case 0:
     60 			return (res);
     61 		default:
     62 			pos += res;
     63 		}
     64 	}
     65 	return (pos);
     66 }
     67 
     68 /*
     69  * ensure all of data on socket comes through. f==readv || f==writev
     70  */
     71 size_t
     72 atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
     73     const struct iovec *_iov, int iovcnt)
     74 {
     75 	size_t pos = 0, rem;
     76 	ssize_t res;
     77 	struct iovec iov_array[IOV_MAX], *iov = iov_array;
     78 
     79 	if (iovcnt > IOV_MAX) {
     80 		errno = EINVAL;
     81 		return 0;
     82 	}
     83 	/* Make a copy of the iov array because we may modify it below */
     84 	memcpy(iov, _iov, iovcnt * sizeof(*_iov));
     85 
     86 	for (; iovcnt > 0 && iov[0].iov_len > 0;) {
     87 		res = (f) (fd, iov, iovcnt);
     88 		switch (res) {
     89 		case -1:
     90 			if (errno == EINTR || errno == EAGAIN)
     91 				continue;
     92 			return 0;
     93 		case 0:
     94 			errno = EPIPE;
     95 			return pos;
     96 		default:
     97 			rem = (size_t)res;
     98 			pos += rem;
     99 			/* skip completed iov entries */
    100 			while (iovcnt > 0 && rem >= iov[0].iov_len) {
    101 				rem -= iov[0].iov_len;
    102 				iov++;
    103 				iovcnt--;
    104 			}
    105 			/* This shouldn't happen... */
    106 			if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
    107 				errno = EFAULT;
    108 				return 0;
    109 			}
    110 			if (iovcnt == 0)
    111 				break;
    112 			/* update pointer in partially complete iov */
    113 			iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
    114 			iov[0].iov_len -= rem;
    115 		}
    116 	}
    117 	return pos;
    118 }
    119