1*c939d236Sderaadt /* $OpenBSD: atomicio.c,v 1.2 2012/12/04 02:38:51 deraadt Exp $ */
2330f45acSmbalmer /*
3330f45acSmbalmer * Copyright (c) 2006 Damien Miller. All rights reserved.
4330f45acSmbalmer * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
5330f45acSmbalmer * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
6330f45acSmbalmer * All rights reserved.
7330f45acSmbalmer *
8330f45acSmbalmer * Redistribution and use in source and binary forms, with or without
9330f45acSmbalmer * modification, are permitted provided that the following conditions
10330f45acSmbalmer * are met:
11330f45acSmbalmer * 1. Redistributions of source code must retain the above copyright
12330f45acSmbalmer * notice, this list of conditions and the following disclaimer.
13330f45acSmbalmer * 2. Redistributions in binary form must reproduce the above copyright
14330f45acSmbalmer * notice, this list of conditions and the following disclaimer in the
15330f45acSmbalmer * documentation and/or other materials provided with the distribution.
16330f45acSmbalmer *
17330f45acSmbalmer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18330f45acSmbalmer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19330f45acSmbalmer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20330f45acSmbalmer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21330f45acSmbalmer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22330f45acSmbalmer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23330f45acSmbalmer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24330f45acSmbalmer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25330f45acSmbalmer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26330f45acSmbalmer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27330f45acSmbalmer */
28330f45acSmbalmer
29*c939d236Sderaadt #include <sys/types.h>
30330f45acSmbalmer #include <sys/uio.h>
31330f45acSmbalmer
32330f45acSmbalmer #include <errno.h>
33330f45acSmbalmer #include <poll.h>
34330f45acSmbalmer #include <string.h>
35*c939d236Sderaadt #include <limits.h>
36330f45acSmbalmer #include <unistd.h>
37330f45acSmbalmer
38330f45acSmbalmer #include "atomicio.h"
39330f45acSmbalmer
40330f45acSmbalmer /*
41330f45acSmbalmer * ensure all of data on socket comes through. f==read || f==vwrite
42330f45acSmbalmer */
43330f45acSmbalmer size_t
atomicio(ssize_t (* f)(int,void *,size_t),int fd,void * _s,size_t n)44330f45acSmbalmer atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
45330f45acSmbalmer {
46330f45acSmbalmer char *s = _s;
47330f45acSmbalmer size_t pos = 0;
48330f45acSmbalmer ssize_t res;
49330f45acSmbalmer struct pollfd pfd;
50330f45acSmbalmer
51330f45acSmbalmer pfd.fd = fd;
52330f45acSmbalmer pfd.events = f == read ? POLLIN : POLLOUT;
53330f45acSmbalmer while (n > pos) {
54330f45acSmbalmer res = (f) (fd, s + pos, n - pos);
55330f45acSmbalmer switch (res) {
56330f45acSmbalmer case -1:
57330f45acSmbalmer if (errno == EINTR)
58330f45acSmbalmer continue;
59330f45acSmbalmer if (errno == EAGAIN) {
60330f45acSmbalmer (void)poll(&pfd, 1, -1);
61330f45acSmbalmer continue;
62330f45acSmbalmer }
63330f45acSmbalmer return 0;
64330f45acSmbalmer case 0:
65330f45acSmbalmer errno = EPIPE;
66330f45acSmbalmer return pos;
67330f45acSmbalmer default:
68330f45acSmbalmer pos += (size_t)res;
69330f45acSmbalmer }
70330f45acSmbalmer }
71330f45acSmbalmer return (pos);
72330f45acSmbalmer }
73330f45acSmbalmer
74330f45acSmbalmer /*
75330f45acSmbalmer * ensure all of data on socket comes through. f==readv || f==writev
76330f45acSmbalmer */
77330f45acSmbalmer size_t
atomiciov(ssize_t (* f)(int,const struct iovec *,int),int fd,const struct iovec * _iov,int iovcnt)78330f45acSmbalmer atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
79330f45acSmbalmer const struct iovec *_iov, int iovcnt)
80330f45acSmbalmer {
81330f45acSmbalmer size_t pos = 0, rem;
82330f45acSmbalmer ssize_t res;
83330f45acSmbalmer struct iovec iov_array[IOV_MAX], *iov = iov_array;
84330f45acSmbalmer struct pollfd pfd;
85330f45acSmbalmer
86330f45acSmbalmer if (iovcnt > IOV_MAX) {
87330f45acSmbalmer errno = EINVAL;
88330f45acSmbalmer return 0;
89330f45acSmbalmer }
90330f45acSmbalmer /* Make a copy of the iov array because we may modify it below */
91330f45acSmbalmer memcpy(iov, _iov, iovcnt * sizeof(*_iov));
92330f45acSmbalmer
93330f45acSmbalmer pfd.fd = fd;
94330f45acSmbalmer pfd.events = f == readv ? POLLIN : POLLOUT;
95330f45acSmbalmer for (; iovcnt > 0 && iov[0].iov_len > 0;) {
96330f45acSmbalmer res = (f) (fd, iov, iovcnt);
97330f45acSmbalmer switch (res) {
98330f45acSmbalmer case -1:
99330f45acSmbalmer if (errno == EINTR)
100330f45acSmbalmer continue;
101330f45acSmbalmer if (errno == EAGAIN) {
102330f45acSmbalmer (void)poll(&pfd, 1, -1);
103330f45acSmbalmer continue;
104330f45acSmbalmer }
105330f45acSmbalmer return 0;
106330f45acSmbalmer case 0:
107330f45acSmbalmer errno = EPIPE;
108330f45acSmbalmer return pos;
109330f45acSmbalmer default:
110330f45acSmbalmer rem = (size_t)res;
111330f45acSmbalmer pos += rem;
112330f45acSmbalmer /* skip completed iov entries */
113330f45acSmbalmer while (iovcnt > 0 && rem >= iov[0].iov_len) {
114330f45acSmbalmer rem -= iov[0].iov_len;
115330f45acSmbalmer iov++;
116330f45acSmbalmer iovcnt--;
117330f45acSmbalmer }
118330f45acSmbalmer /* This shouldn't happen... */
119330f45acSmbalmer if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
120330f45acSmbalmer errno = EFAULT;
121330f45acSmbalmer return 0;
122330f45acSmbalmer }
123330f45acSmbalmer if (iovcnt == 0)
124330f45acSmbalmer break;
125330f45acSmbalmer /* update pointer in partially complete iov */
126330f45acSmbalmer iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
127330f45acSmbalmer iov[0].iov_len -= rem;
128330f45acSmbalmer }
129330f45acSmbalmer }
130330f45acSmbalmer return pos;
131330f45acSmbalmer }
132