atomicio.c revision 262566
1220297Sadrian/* $OpenBSD: atomicio.c,v 1.26 2010/09/22 22:58:51 djm Exp $ */
2220297Sadrian/*
3220297Sadrian * Copyright (c) 2006 Damien Miller. All rights reserved.
4220297Sadrian * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
5220297Sadrian * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
6220297Sadrian * All rights reserved.
7220297Sadrian *
8220297Sadrian * Redistribution and use in source and binary forms, with or without
9220297Sadrian * modification, are permitted provided that the following conditions
10220297Sadrian * are met:
11220297Sadrian * 1. Redistributions of source code must retain the above copyright
12220297Sadrian *    notice, this list of conditions and the following disclaimer.
13220297Sadrian * 2. Redistributions in binary form must reproduce the above copyright
14220297Sadrian *    notice, this list of conditions and the following disclaimer in the
15220297Sadrian *    documentation and/or other materials provided with the distribution.
16220297Sadrian *
17220297Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18220297Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19220297Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20220297Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21220297Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22220297Sadrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23220297Sadrian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24220297Sadrian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25220297Sadrian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26220297Sadrian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27220297Sadrian */
28220297Sadrian
29220297Sadrian#include "includes.h"
30220297Sadrian
31220297Sadrian#include <sys/param.h>
32220297Sadrian#include <sys/uio.h>
33220297Sadrian
34220297Sadrian#include <errno.h>
35220297Sadrian#ifdef HAVE_POLL_H
36220297Sadrian#include <poll.h>
37220297Sadrian#else
38220297Sadrian# ifdef HAVE_SYS_POLL_H
39220297Sadrian#  include <sys/poll.h>
40220297Sadrian# endif
41220297Sadrian#endif
42220297Sadrian#include <string.h>
43220297Sadrian#include <unistd.h>
44220297Sadrian
45220297Sadrian#include "atomicio.h"
46220297Sadrian
47220297Sadrian/*
48220297Sadrian * ensure all of data on socket comes through. f==read || f==vwrite
49220297Sadrian */
50220297Sadriansize_t
51220297Sadrianatomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
52220297Sadrian    int (*cb)(void *, size_t), void *cb_arg)
53220297Sadrian{
54220297Sadrian	char *s = _s;
55220297Sadrian	size_t pos = 0;
56220297Sadrian	ssize_t res;
57220297Sadrian	struct pollfd pfd;
58220297Sadrian
59220297Sadrian#ifndef BROKEN_READ_COMPARISON
60220297Sadrian	pfd.fd = fd;
61220297Sadrian	pfd.events = f == read ? POLLIN : POLLOUT;
62220297Sadrian#endif
63220297Sadrian	while (n > pos) {
64220297Sadrian		res = (f) (fd, s + pos, n - pos);
65220297Sadrian		switch (res) {
66220297Sadrian		case -1:
67220297Sadrian			if (errno == EINTR)
68220297Sadrian				continue;
69220297Sadrian			if (errno == EAGAIN || errno == EWOULDBLOCK) {
70220297Sadrian#ifndef BROKEN_READ_COMPARISON
71220297Sadrian				(void)poll(&pfd, 1, -1);
72220297Sadrian#endif
73220297Sadrian				continue;
74220297Sadrian			}
75220297Sadrian			return 0;
76220297Sadrian		case 0:
77220297Sadrian			errno = EPIPE;
78220297Sadrian			return pos;
79220297Sadrian		default:
80220297Sadrian			pos += (size_t)res;
81220297Sadrian			if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
82220297Sadrian				errno = EINTR;
83220297Sadrian				return pos;
84220297Sadrian			}
85220297Sadrian		}
86220297Sadrian	}
87220297Sadrian	return pos;
88220297Sadrian}
89220297Sadrian
90220297Sadriansize_t
91220297Sadrianatomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
92220297Sadrian{
93220297Sadrian	return atomicio6(f, fd, _s, n, NULL, NULL);
94220297Sadrian}
95278278Shselasky
96220297Sadrian/*
97220297Sadrian * ensure all of data on socket comes through. f==readv || f==writev
98220297Sadrian */
99220297Sadriansize_t
100220297Sadrianatomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
101220297Sadrian    const struct iovec *_iov, int iovcnt,
102220297Sadrian    int (*cb)(void *, size_t), void *cb_arg)
103220297Sadrian{
104220297Sadrian	size_t pos = 0, rem;
105220297Sadrian	ssize_t res;
106220297Sadrian	struct iovec iov_array[IOV_MAX], *iov = iov_array;
107220297Sadrian	struct pollfd pfd;
108220297Sadrian
109220297Sadrian	if (iovcnt > IOV_MAX) {
110220297Sadrian		errno = EINVAL;
111220297Sadrian		return 0;
112220297Sadrian	}
113220297Sadrian	/* Make a copy of the iov array because we may modify it below */
114220297Sadrian	memcpy(iov, _iov, iovcnt * sizeof(*_iov));
115220297Sadrian
116220297Sadrian#ifndef BROKEN_READV_COMPARISON
117220297Sadrian	pfd.fd = fd;
118220297Sadrian	pfd.events = f == readv ? POLLIN : POLLOUT;
119220297Sadrian#endif
120220297Sadrian	for (; iovcnt > 0 && iov[0].iov_len > 0;) {
121220297Sadrian		res = (f) (fd, iov, iovcnt);
122220297Sadrian		switch (res) {
123220297Sadrian		case -1:
124220297Sadrian			if (errno == EINTR)
125220297Sadrian				continue;
126220297Sadrian			if (errno == EAGAIN || errno == EWOULDBLOCK) {
127220297Sadrian#ifndef BROKEN_READV_COMPARISON
128220297Sadrian				(void)poll(&pfd, 1, -1);
129220297Sadrian#endif
130220297Sadrian				continue;
131220297Sadrian			}
132220297Sadrian			return 0;
133220297Sadrian		case 0:
134220297Sadrian			errno = EPIPE;
135220297Sadrian			return pos;
136220297Sadrian		default:
137220297Sadrian			rem = (size_t)res;
138220297Sadrian			pos += rem;
139220297Sadrian			/* skip completed iov entries */
140220297Sadrian			while (iovcnt > 0 && rem >= iov[0].iov_len) {
141220297Sadrian				rem -= iov[0].iov_len;
142220297Sadrian				iov++;
143220297Sadrian				iovcnt--;
144220297Sadrian			}
145220297Sadrian			/* This shouldn't happen... */
146220297Sadrian			if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
147220297Sadrian				errno = EFAULT;
148220297Sadrian				return 0;
149220297Sadrian			}
150220297Sadrian			if (iovcnt == 0)
151220297Sadrian				break;
152220297Sadrian			/* update pointer in partially complete iov */
153220297Sadrian			iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
154220297Sadrian			iov[0].iov_len -= rem;
155220297Sadrian		}
156220297Sadrian		if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
157220297Sadrian			errno = EINTR;
158220297Sadrian			return pos;
159220297Sadrian		}
160220297Sadrian	}
161220297Sadrian	return pos;
162220297Sadrian}
163220297Sadrian
164220297Sadriansize_t
165220297Sadrianatomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
166220297Sadrian    const struct iovec *_iov, int iovcnt)
167220297Sadrian{
168220297Sadrian	return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
169220297Sadrian}
170220297Sadrian