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 }