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