Coverage Report

Created: 2025-07-01 07:00

/src/openssh/atomicio.c
Line
Count
Source (jump to first uncovered line)
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
0
{
54
0
  char *s = _s;
55
0
  size_t pos = 0;
56
0
  ssize_t res;
57
0
  struct pollfd pfd;
58
59
0
  pfd.fd = fd;
60
0
#ifndef BROKEN_READ_COMPARISON
61
0
  pfd.events = f == read ? POLLIN : POLLOUT;
62
#else
63
  pfd.events = POLLIN|POLLOUT;
64
#endif
65
0
  while (n > pos) {
66
0
    res = (f) (fd, s + pos, n - pos);
67
0
    switch (res) {
68
0
    case -1:
69
0
      if (errno == EINTR) {
70
        /* possible SIGALARM, update callback */
71
0
        if (cb != NULL && cb(cb_arg, 0) == -1) {
72
0
          errno = EINTR;
73
0
          return pos;
74
0
        }
75
0
        continue;
76
0
      } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
77
0
        (void)poll(&pfd, 1, -1);
78
0
        continue;
79
0
      }
80
0
      return 0;
81
0
    case 0:
82
0
      errno = EPIPE;
83
0
      return pos;
84
0
    default:
85
0
      pos += (size_t)res;
86
0
      if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
87
0
        errno = EINTR;
88
0
        return pos;
89
0
      }
90
0
    }
91
0
  }
92
0
  return pos;
93
0
}
94
95
size_t
96
atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
97
0
{
98
0
  return atomicio6(f, fd, _s, n, NULL, NULL);
99
0
}
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
0
{
109
0
  size_t pos = 0, rem;
110
0
  ssize_t res;
111
0
  struct iovec iov_array[IOV_MAX], *iov = iov_array;
112
0
  struct pollfd pfd;
113
114
0
  if (iovcnt < 0 || iovcnt > IOV_MAX) {
115
0
    errno = EINVAL;
116
0
    return 0;
117
0
  }
118
  /* Make a copy of the iov array because we may modify it below */
119
0
  memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
120
121
0
  pfd.fd = fd;
122
0
#ifndef BROKEN_READV_COMPARISON
123
0
  pfd.events = f == readv ? POLLIN : POLLOUT;
124
#else
125
  pfd.events = POLLIN|POLLOUT;
126
#endif
127
0
  for (; iovcnt > 0 && iov[0].iov_len > 0;) {
128
0
    res = (f) (fd, iov, iovcnt);
129
0
    switch (res) {
130
0
    case -1:
131
0
      if (errno == EINTR) {
132
        /* possible SIGALARM, update callback */
133
0
        if (cb != NULL && cb(cb_arg, 0) == -1) {
134
0
          errno = EINTR;
135
0
          return pos;
136
0
        }
137
0
        continue;
138
0
      } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
139
0
        (void)poll(&pfd, 1, -1);
140
0
        continue;
141
0
      }
142
0
      return 0;
143
0
    case 0:
144
0
      errno = EPIPE;
145
0
      return pos;
146
0
    default:
147
0
      rem = (size_t)res;
148
0
      pos += rem;
149
      /* skip completed iov entries */
150
0
      while (iovcnt > 0 && rem >= iov[0].iov_len) {
151
0
        rem -= iov[0].iov_len;
152
0
        iov++;
153
0
        iovcnt--;
154
0
      }
155
      /* This shouldn't happen... */
156
0
      if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
157
0
        errno = EFAULT;
158
0
        return 0;
159
0
      }
160
0
      if (iovcnt == 0)
161
0
        break;
162
      /* update pointer in partially complete iov */
163
0
      iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
164
0
      iov[0].iov_len -= rem;
165
0
    }
166
0
    if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
167
0
      errno = EINTR;
168
0
      return pos;
169
0
    }
170
0
  }
171
0
  return pos;
172
0
}
173
174
size_t
175
atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
176
    const struct iovec *_iov, int iovcnt)
177
0
{
178
0
  return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
179
0
}