atomicio.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* $OpenBSD: atomicio.c,v 1.30 2019/01/24 02:42:23 dtucker 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. #include "includes.h"
  29. #include <sys/param.h>
  30. #include <sys/uio.h>
  31. #include <errno.h>
  32. #ifdef HAVE_POLL_H
  33. #include <poll.h>
  34. #else
  35. # ifdef HAVE_SYS_POLL_H
  36. # include <sys/poll.h>
  37. # endif
  38. #endif
  39. #include <string.h>
  40. #include <unistd.h>
  41. #include <limits.h>
  42. #include "atomicio.h"
  43. /*
  44. * ensure all of data on socket comes through. f==read || f==vwrite
  45. */
  46. size_t
  47. atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
  48. int (*cb)(void *, size_t), void *cb_arg)
  49. {
  50. char *s = _s;
  51. size_t pos = 0;
  52. ssize_t res;
  53. struct pollfd pfd;
  54. pfd.fd = fd;
  55. #ifndef BROKEN_READ_COMPARISON
  56. pfd.events = f == read ? POLLIN : POLLOUT;
  57. #else
  58. pfd.events = POLLIN|POLLOUT;
  59. #endif
  60. while (n > pos) {
  61. res = (f) (fd, s + pos, n - pos);
  62. switch (res) {
  63. case -1:
  64. if (errno == EINTR) {
  65. /* possible SIGALARM, update callback */
  66. if (cb != NULL && cb(cb_arg, 0) == -1) {
  67. errno = EINTR;
  68. return pos;
  69. }
  70. continue;
  71. } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
  72. (void)poll(&pfd, 1, -1);
  73. continue;
  74. }
  75. return 0;
  76. case 0:
  77. errno = EPIPE;
  78. return pos;
  79. default:
  80. pos += (size_t)res;
  81. if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
  82. errno = EINTR;
  83. return pos;
  84. }
  85. }
  86. }
  87. return pos;
  88. }
  89. size_t
  90. atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
  91. {
  92. return atomicio6(f, fd, _s, n, NULL, NULL);
  93. }
  94. /*
  95. * ensure all of data on socket comes through. f==readv || f==writev
  96. */
  97. size_t
  98. atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
  99. const struct iovec *_iov, int iovcnt,
  100. int (*cb)(void *, size_t), void *cb_arg)
  101. {
  102. size_t pos = 0, rem;
  103. ssize_t res;
  104. struct iovec iov_array[IOV_MAX], *iov = iov_array;
  105. struct pollfd pfd;
  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. pfd.fd = fd;
  113. #ifndef BROKEN_READV_COMPARISON
  114. pfd.events = f == readv ? POLLIN : POLLOUT;
  115. #else
  116. pfd.events = POLLIN|POLLOUT;
  117. #endif
  118. for (; iovcnt > 0 && iov[0].iov_len > 0;) {
  119. res = (f) (fd, iov, iovcnt);
  120. switch (res) {
  121. case -1:
  122. if (errno == EINTR) {
  123. /* possible SIGALARM, update callback */
  124. if (cb != NULL && cb(cb_arg, 0) == -1) {
  125. errno = EINTR;
  126. return pos;
  127. }
  128. continue;
  129. } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
  130. (void)poll(&pfd, 1, -1);
  131. continue;
  132. }
  133. return 0;
  134. case 0:
  135. errno = EPIPE;
  136. return pos;
  137. default:
  138. rem = (size_t)res;
  139. pos += rem;
  140. /* skip completed iov entries */
  141. while (iovcnt > 0 && rem >= iov[0].iov_len) {
  142. rem -= iov[0].iov_len;
  143. iov++;
  144. iovcnt--;
  145. }
  146. /* This shouldn't happen... */
  147. if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
  148. errno = EFAULT;
  149. return 0;
  150. }
  151. if (iovcnt == 0)
  152. break;
  153. /* update pointer in partially complete iov */
  154. iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
  155. iov[0].iov_len -= rem;
  156. }
  157. if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
  158. errno = EINTR;
  159. return pos;
  160. }
  161. }
  162. return pos;
  163. }
  164. size_t
  165. atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
  166. const struct iovec *_iov, int iovcnt)
  167. {
  168. return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
  169. }