atomicio.c revision 162852
1219019Sgabor/* $OpenBSD: atomicio.c,v 1.23 2006/08/03 03:34:41 deraadt Exp $ */
2264497Stijl/*
3219019Sgabor * Copyright (c) 2006 Damien Miller. All rights reserved.
4219019Sgabor * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
5219019Sgabor * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
6219019Sgabor * All rights reserved.
7219019Sgabor *
8219019Sgabor * Redistribution and use in source and binary forms, with or without
9219019Sgabor * modification, are permitted provided that the following conditions
10219019Sgabor * are met:
11219019Sgabor * 1. Redistributions of source code must retain the above copyright
12219019Sgabor *    notice, this list of conditions and the following disclaimer.
13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
14219019Sgabor *    notice, this list of conditions and the following disclaimer in the
15219019Sgabor *    documentation and/or other materials provided with the distribution.
16219019Sgabor *
17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18219019Sgabor * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19219019Sgabor * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20219019Sgabor * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21219019Sgabor * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22219019Sgabor * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23219019Sgabor * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24219019Sgabor * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25219019Sgabor * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26219019Sgabor * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27219019Sgabor */
28219019Sgabor
29219019Sgabor#include "includes.h"
30219019Sgabor
31219019Sgabor#include <sys/param.h>
32219019Sgabor#include <sys/uio.h>
33219019Sgabor
34219019Sgabor#include <errno.h>
35219019Sgabor#include <string.h>
36219019Sgabor
37219019Sgabor#include "atomicio.h"
38219019Sgabor
39219019Sgabor/*
40219019Sgabor * ensure all of data on socket comes through. f==read || f==vwrite
41219019Sgabor */
42219019Sgaborsize_t
43219019Sgaboratomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
44219019Sgabor{
45219019Sgabor	char *s = _s;
46219019Sgabor	size_t pos = 0;
47219019Sgabor	ssize_t res;
48219019Sgabor
49219019Sgabor	while (n > pos) {
50219019Sgabor		res = (f) (fd, s + pos, n - pos);
51219019Sgabor		switch (res) {
52219019Sgabor		case -1:
53219019Sgabor#ifdef EWOULDBLOCK
54219019Sgabor			if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
55219019Sgabor#else
56219019Sgabor			if (errno == EINTR || errno == EAGAIN)
57219019Sgabor#endif
58219019Sgabor				continue;
59219019Sgabor			return 0;
60219019Sgabor		case 0:
61219019Sgabor			errno = EPIPE;
62219019Sgabor			return pos;
63219019Sgabor		default:
64219019Sgabor			pos += (size_t)res;
65219019Sgabor		}
66219019Sgabor	}
67219019Sgabor	return (pos);
68219019Sgabor}
69219019Sgabor
70219019Sgabor/*
71219019Sgabor * ensure all of data on socket comes through. f==readv || f==writev
72219019Sgabor */
73219019Sgaborsize_t
74219019Sgaboratomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
75219019Sgabor    const struct iovec *_iov, int iovcnt)
76219019Sgabor{
77219019Sgabor	size_t pos = 0, rem;
78260264Sdim	ssize_t res;
79219019Sgabor	struct iovec iov_array[IOV_MAX], *iov = iov_array;
80219019Sgabor
81219019Sgabor	if (iovcnt > IOV_MAX) {
82219019Sgabor		errno = EINVAL;
83219019Sgabor		return 0;
84219019Sgabor	}
85219019Sgabor	/* Make a copy of the iov array because we may modify it below */
86219019Sgabor	memcpy(iov, _iov, iovcnt * sizeof(*_iov));
87219019Sgabor
88219019Sgabor	for (; iovcnt > 0 && iov[0].iov_len > 0;) {
89219019Sgabor		res = (f) (fd, iov, iovcnt);
90219019Sgabor		switch (res) {
91219019Sgabor		case -1:
92219019Sgabor			if (errno == EINTR || errno == EAGAIN)
93219019Sgabor				continue;
94219019Sgabor			return 0;
95219019Sgabor		case 0:
96260264Sdim			errno = EPIPE;
97219019Sgabor			return pos;
98219019Sgabor		default:
99219019Sgabor			rem = (size_t)res;
100219019Sgabor			pos += rem;
101219019Sgabor			/* skip completed iov entries */
102219019Sgabor			while (iovcnt > 0 && rem >= iov[0].iov_len) {
103219019Sgabor				rem -= iov[0].iov_len;
104219019Sgabor				iov++;
105219019Sgabor				iovcnt--;
106219019Sgabor			}
107219019Sgabor			/* This shouldn't happen... */
108219019Sgabor			if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
109219019Sgabor				errno = EFAULT;
110219019Sgabor				return 0;
111219019Sgabor			}
112219019Sgabor			if (iovcnt == 0)
113219019Sgabor				break;
114219019Sgabor			/* update pointer in partially complete iov */
115219019Sgabor			iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
116219019Sgabor			iov[0].iov_len -= rem;
117219019Sgabor		}
118219019Sgabor	}
119219019Sgabor	return pos;
120219019Sgabor}
121219019Sgabor