Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssh/atomicio.c
34677 views
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
29
#include "includes.h"
30
31
#include <sys/uio.h>
32
33
#include <errno.h>
34
#ifdef HAVE_POLL_H
35
#include <poll.h>
36
#else
37
# ifdef HAVE_SYS_POLL_H
38
# include <sys/poll.h>
39
# endif
40
#endif
41
#include <string.h>
42
#include <unistd.h>
43
#include <limits.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
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
char *s = _s;
55
size_t pos = 0;
56
ssize_t res;
57
struct pollfd pfd;
58
59
pfd.fd = fd;
60
#ifndef BROKEN_READ_COMPARISON
61
pfd.events = f == read ? POLLIN : POLLOUT;
62
#else
63
pfd.events = POLLIN|POLLOUT;
64
#endif
65
while (n > pos) {
66
res = (f) (fd, s + pos, n - pos);
67
switch (res) {
68
case -1:
69
if (errno == EINTR) {
70
/* possible SIGALARM, update callback */
71
if (cb != NULL && cb(cb_arg, 0) == -1) {
72
errno = EINTR;
73
return pos;
74
}
75
continue;
76
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
77
(void)poll(&pfd, 1, -1);
78
continue;
79
}
80
return 0;
81
case 0:
82
errno = EPIPE;
83
return pos;
84
default:
85
pos += (size_t)res;
86
if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
87
errno = EINTR;
88
return pos;
89
}
90
}
91
}
92
return pos;
93
}
94
95
size_t
96
atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
97
{
98
return atomicio6(f, fd, _s, n, NULL, NULL);
99
}
100
101
/*
102
* ensure all of data on socket comes through. f==readv || f==writev
103
*/
104
size_t
105
atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
106
const struct iovec *_iov, int iovcnt,
107
int (*cb)(void *, size_t), void *cb_arg)
108
{
109
size_t pos = 0, rem;
110
ssize_t res;
111
struct iovec iov_array[IOV_MAX], *iov = iov_array;
112
struct pollfd pfd;
113
114
if (iovcnt < 0 || iovcnt > IOV_MAX) {
115
errno = EINVAL;
116
return 0;
117
}
118
/* Make a copy of the iov array because we may modify it below */
119
memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
120
121
pfd.fd = fd;
122
#ifndef BROKEN_READV_COMPARISON
123
pfd.events = f == readv ? POLLIN : POLLOUT;
124
#else
125
pfd.events = POLLIN|POLLOUT;
126
#endif
127
for (; iovcnt > 0 && iov[0].iov_len > 0;) {
128
res = (f) (fd, iov, iovcnt);
129
switch (res) {
130
case -1:
131
if (errno == EINTR) {
132
/* possible SIGALARM, update callback */
133
if (cb != NULL && cb(cb_arg, 0) == -1) {
134
errno = EINTR;
135
return pos;
136
}
137
continue;
138
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
139
(void)poll(&pfd, 1, -1);
140
continue;
141
}
142
return 0;
143
case 0:
144
errno = EPIPE;
145
return pos;
146
default:
147
rem = (size_t)res;
148
pos += rem;
149
/* skip completed iov entries */
150
while (iovcnt > 0 && rem >= iov[0].iov_len) {
151
rem -= iov[0].iov_len;
152
iov++;
153
iovcnt--;
154
}
155
/* This shouldn't happen... */
156
if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
157
errno = EFAULT;
158
return 0;
159
}
160
if (iovcnt == 0)
161
break;
162
/* update pointer in partially complete iov */
163
iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
164
iov[0].iov_len -= rem;
165
}
166
if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
167
errno = EINTR;
168
return pos;
169
}
170
}
171
return pos;
172
}
173
174
size_t
175
atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
176
const struct iovec *_iov, int iovcnt)
177
{
178
return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
179
}
180
181