xref: /freebsd/contrib/lib9p/transport/socket.c (revision b07549f3c15637af6064d2f52b572f239f5ba870)
1134e1779SJakub Wojciech Klama /*
2134e1779SJakub Wojciech Klama  * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
3134e1779SJakub Wojciech Klama  * All rights reserved
4134e1779SJakub Wojciech Klama  *
5134e1779SJakub Wojciech Klama  * Redistribution and use in source and binary forms, with or without
6134e1779SJakub Wojciech Klama  * modification, are permitted providing that the following conditions
7134e1779SJakub Wojciech Klama  * are met:
8134e1779SJakub Wojciech Klama  * 1. Redistributions of source code must retain the above copyright
9134e1779SJakub Wojciech Klama  *    notice, this list of conditions and the following disclaimer.
10134e1779SJakub Wojciech Klama  * 2. Redistributions in binary form must reproduce the above copyright
11134e1779SJakub Wojciech Klama  *    notice, this list of conditions and the following disclaimer in the
12134e1779SJakub Wojciech Klama  *    documentation and/or other materials provided with the distribution.
13134e1779SJakub Wojciech Klama  *
14134e1779SJakub Wojciech Klama  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15134e1779SJakub Wojciech Klama  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16134e1779SJakub Wojciech Klama  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17134e1779SJakub Wojciech Klama  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18134e1779SJakub Wojciech Klama  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19134e1779SJakub Wojciech Klama  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20134e1779SJakub Wojciech Klama  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21134e1779SJakub Wojciech Klama  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22134e1779SJakub Wojciech Klama  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23134e1779SJakub Wojciech Klama  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24134e1779SJakub Wojciech Klama  * POSSIBILITY OF SUCH DAMAGE.
25134e1779SJakub Wojciech Klama  *
26134e1779SJakub Wojciech Klama  */
27134e1779SJakub Wojciech Klama 
28134e1779SJakub Wojciech Klama #include <stdlib.h>
29134e1779SJakub Wojciech Klama #include <errno.h>
30134e1779SJakub Wojciech Klama #include <string.h>
31134e1779SJakub Wojciech Klama #include <unistd.h>
32134e1779SJakub Wojciech Klama #include <pthread.h>
33134e1779SJakub Wojciech Klama #include <assert.h>
34134e1779SJakub Wojciech Klama #include <sys/types.h>
35134e1779SJakub Wojciech Klama #ifdef __APPLE__
36134e1779SJakub Wojciech Klama # include "../apple_endian.h"
37134e1779SJakub Wojciech Klama #else
38134e1779SJakub Wojciech Klama # include <sys/endian.h>
39134e1779SJakub Wojciech Klama #endif
40134e1779SJakub Wojciech Klama #include <sys/socket.h>
41134e1779SJakub Wojciech Klama #include <sys/event.h>
42134e1779SJakub Wojciech Klama #include <sys/uio.h>
43134e1779SJakub Wojciech Klama #include <netdb.h>
44134e1779SJakub Wojciech Klama #include "../lib9p.h"
45134e1779SJakub Wojciech Klama #include "../lib9p_impl.h"
46134e1779SJakub Wojciech Klama #include "../log.h"
47134e1779SJakub Wojciech Klama #include "socket.h"
48134e1779SJakub Wojciech Klama 
49134e1779SJakub Wojciech Klama struct l9p_socket_softc
50134e1779SJakub Wojciech Klama {
51134e1779SJakub Wojciech Klama 	struct l9p_connection *ls_conn;
52134e1779SJakub Wojciech Klama 	struct sockaddr ls_sockaddr;
53134e1779SJakub Wojciech Klama 	socklen_t ls_socklen;
54134e1779SJakub Wojciech Klama 	pthread_t ls_thread;
55134e1779SJakub Wojciech Klama 	int ls_fd;
56134e1779SJakub Wojciech Klama };
57134e1779SJakub Wojciech Klama 
58134e1779SJakub Wojciech Klama static int l9p_socket_readmsg(struct l9p_socket_softc *, void **, size_t *);
59134e1779SJakub Wojciech Klama static int l9p_socket_get_response_buffer(struct l9p_request *,
60134e1779SJakub Wojciech Klama     struct iovec *, size_t *, void *);
61134e1779SJakub Wojciech Klama static int l9p_socket_send_response(struct l9p_request *, const struct iovec *,
62134e1779SJakub Wojciech Klama     const size_t, const size_t, void *);
63134e1779SJakub Wojciech Klama static void l9p_socket_drop_response(struct l9p_request *, const struct iovec *,
64134e1779SJakub Wojciech Klama     size_t, void *);
65134e1779SJakub Wojciech Klama static void *l9p_socket_thread(void *);
66134e1779SJakub Wojciech Klama static ssize_t xread(int, void *, size_t);
67134e1779SJakub Wojciech Klama static ssize_t xwrite(int, void *, size_t);
68134e1779SJakub Wojciech Klama 
69134e1779SJakub Wojciech Klama int
l9p_start_server(struct l9p_server * server,const char * host,const char * port)70134e1779SJakub Wojciech Klama l9p_start_server(struct l9p_server *server, const char *host, const char *port)
71134e1779SJakub Wojciech Klama {
72134e1779SJakub Wojciech Klama 	struct addrinfo *res, *res0, hints;
73134e1779SJakub Wojciech Klama 	struct kevent kev[2];
74134e1779SJakub Wojciech Klama 	struct kevent event[2];
75134e1779SJakub Wojciech Klama 	int err, kq, i, val, evs, nsockets = 0;
76134e1779SJakub Wojciech Klama 
77134e1779SJakub Wojciech Klama 	memset(&hints, 0, sizeof(hints));
78134e1779SJakub Wojciech Klama 	hints.ai_family = PF_UNSPEC;
79134e1779SJakub Wojciech Klama 	hints.ai_socktype = SOCK_STREAM;
80134e1779SJakub Wojciech Klama 	err = getaddrinfo(host, port, &hints, &res0);
81134e1779SJakub Wojciech Klama 
82134e1779SJakub Wojciech Klama 	if (err)
83134e1779SJakub Wojciech Klama 		return (-1);
84134e1779SJakub Wojciech Klama 
85134e1779SJakub Wojciech Klama 	for (res = res0; res; res = res->ai_next) {
86134e1779SJakub Wojciech Klama 		int s = socket(res->ai_family, res->ai_socktype,
87134e1779SJakub Wojciech Klama 		    res->ai_protocol);
88134e1779SJakub Wojciech Klama 
89134e1779SJakub Wojciech Klama 		val = 1;
90134e1779SJakub Wojciech Klama 		setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
91134e1779SJakub Wojciech Klama 
92134e1779SJakub Wojciech Klama 		if (s < 0)
93134e1779SJakub Wojciech Klama 			continue;
94134e1779SJakub Wojciech Klama 
95134e1779SJakub Wojciech Klama 		if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
96134e1779SJakub Wojciech Klama 			close(s);
97134e1779SJakub Wojciech Klama 			continue;
98134e1779SJakub Wojciech Klama 		}
99134e1779SJakub Wojciech Klama 
100134e1779SJakub Wojciech Klama 		EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0,
101134e1779SJakub Wojciech Klama 		    0, 0);
102134e1779SJakub Wojciech Klama 		listen(s, 10);
103134e1779SJakub Wojciech Klama 	}
104134e1779SJakub Wojciech Klama 
105134e1779SJakub Wojciech Klama 	if (nsockets < 1) {
106134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "bind(): %s", strerror(errno));
107134e1779SJakub Wojciech Klama 		return(-1);
108134e1779SJakub Wojciech Klama 	}
109134e1779SJakub Wojciech Klama 
110134e1779SJakub Wojciech Klama 	kq = kqueue();
111134e1779SJakub Wojciech Klama 
112134e1779SJakub Wojciech Klama 	if (kevent(kq, kev, nsockets, NULL, 0, NULL) < 0) {
113134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
114134e1779SJakub Wojciech Klama 		return (-1);
115134e1779SJakub Wojciech Klama 	}
116134e1779SJakub Wojciech Klama 
117134e1779SJakub Wojciech Klama 	for (;;) {
118134e1779SJakub Wojciech Klama 		evs = kevent(kq, NULL, 0, event, nsockets, NULL);
119134e1779SJakub Wojciech Klama 		if (evs < 0) {
120134e1779SJakub Wojciech Klama 			if (errno == EINTR)
121134e1779SJakub Wojciech Klama 				continue;
122134e1779SJakub Wojciech Klama 
123134e1779SJakub Wojciech Klama 			L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
124134e1779SJakub Wojciech Klama 			return (-1);
125134e1779SJakub Wojciech Klama 		}
126134e1779SJakub Wojciech Klama 
127134e1779SJakub Wojciech Klama 		for (i = 0; i < evs; i++) {
128134e1779SJakub Wojciech Klama 			struct sockaddr client_addr;
129134e1779SJakub Wojciech Klama 			socklen_t client_addr_len = sizeof(client_addr);
130134e1779SJakub Wojciech Klama 			int news = accept((int)event[i].ident, &client_addr,
131134e1779SJakub Wojciech Klama 			    &client_addr_len);
132134e1779SJakub Wojciech Klama 
133134e1779SJakub Wojciech Klama 			if (news < 0) {
134134e1779SJakub Wojciech Klama 				L9P_LOG(L9P_WARNING, "accept(): %s",
135134e1779SJakub Wojciech Klama 				    strerror(errno));
136134e1779SJakub Wojciech Klama 				continue;
137134e1779SJakub Wojciech Klama 			}
138134e1779SJakub Wojciech Klama 
139134e1779SJakub Wojciech Klama 			l9p_socket_accept(server, news, &client_addr,
140134e1779SJakub Wojciech Klama 			    client_addr_len);
141134e1779SJakub Wojciech Klama 		}
142134e1779SJakub Wojciech Klama 	}
143134e1779SJakub Wojciech Klama 
144134e1779SJakub Wojciech Klama }
145134e1779SJakub Wojciech Klama 
146134e1779SJakub Wojciech Klama void
l9p_socket_accept(struct l9p_server * server,int conn_fd,struct sockaddr * client_addr,socklen_t client_addr_len)147134e1779SJakub Wojciech Klama l9p_socket_accept(struct l9p_server *server, int conn_fd,
148134e1779SJakub Wojciech Klama     struct sockaddr *client_addr, socklen_t client_addr_len)
149134e1779SJakub Wojciech Klama {
150134e1779SJakub Wojciech Klama 	struct l9p_socket_softc *sc;
151134e1779SJakub Wojciech Klama 	struct l9p_connection *conn;
152134e1779SJakub Wojciech Klama 	char host[NI_MAXHOST + 1];
153134e1779SJakub Wojciech Klama 	char serv[NI_MAXSERV + 1];
154134e1779SJakub Wojciech Klama 	int err;
155134e1779SJakub Wojciech Klama 
156134e1779SJakub Wojciech Klama 	err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv,
157134e1779SJakub Wojciech Klama 	    NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
158134e1779SJakub Wojciech Klama 
159134e1779SJakub Wojciech Klama 	if (err != 0) {
160134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_WARNING, "cannot look up client name: %s",
161134e1779SJakub Wojciech Klama 		    gai_strerror(err));
162134e1779SJakub Wojciech Klama 	} else {
163134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv);
164134e1779SJakub Wojciech Klama 	}
165134e1779SJakub Wojciech Klama 
166134e1779SJakub Wojciech Klama 	if (l9p_connection_init(server, &conn) != 0) {
167134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "cannot create new connection");
168134e1779SJakub Wojciech Klama 		return;
169134e1779SJakub Wojciech Klama 	}
170134e1779SJakub Wojciech Klama 
171134e1779SJakub Wojciech Klama 	sc = l9p_calloc(1, sizeof(*sc));
172134e1779SJakub Wojciech Klama 	sc->ls_conn = conn;
173134e1779SJakub Wojciech Klama 	sc->ls_fd = conn_fd;
174134e1779SJakub Wojciech Klama 
175134e1779SJakub Wojciech Klama 	/*
176134e1779SJakub Wojciech Klama 	 * Fill in transport handler functions and aux argument.
177134e1779SJakub Wojciech Klama 	 */
178134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_aux = sc;
179134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_get_response_buffer = l9p_socket_get_response_buffer;
180134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_send_response = l9p_socket_send_response;
181134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_drop_response = l9p_socket_drop_response;
182134e1779SJakub Wojciech Klama 
183134e1779SJakub Wojciech Klama 	err = pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc);
184134e1779SJakub Wojciech Klama 	if (err) {
185134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR,
186134e1779SJakub Wojciech Klama 		    "pthread_create (for connection from %s:%s): error %s",
187134e1779SJakub Wojciech Klama 		    host, serv, strerror(err));
188134e1779SJakub Wojciech Klama 		l9p_connection_close(sc->ls_conn);
189134e1779SJakub Wojciech Klama 		free(sc);
190134e1779SJakub Wojciech Klama 	}
191134e1779SJakub Wojciech Klama }
192134e1779SJakub Wojciech Klama 
193134e1779SJakub Wojciech Klama static void *
l9p_socket_thread(void * arg)194134e1779SJakub Wojciech Klama l9p_socket_thread(void *arg)
195134e1779SJakub Wojciech Klama {
196134e1779SJakub Wojciech Klama 	struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
197134e1779SJakub Wojciech Klama 	struct iovec iov;
198134e1779SJakub Wojciech Klama 	void *buf;
199134e1779SJakub Wojciech Klama 	size_t length;
200134e1779SJakub Wojciech Klama 
201134e1779SJakub Wojciech Klama 	for (;;) {
202134e1779SJakub Wojciech Klama 		if (l9p_socket_readmsg(sc, &buf, &length) != 0)
203134e1779SJakub Wojciech Klama 			break;
204134e1779SJakub Wojciech Klama 
205134e1779SJakub Wojciech Klama 		iov.iov_base = buf;
206134e1779SJakub Wojciech Klama 		iov.iov_len = length;
207134e1779SJakub Wojciech Klama 		l9p_connection_recv(sc->ls_conn, &iov, 1, NULL);
208134e1779SJakub Wojciech Klama 		free(buf);
209134e1779SJakub Wojciech Klama 	}
210134e1779SJakub Wojciech Klama 
211134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_INFO, "connection closed");
212134e1779SJakub Wojciech Klama 	l9p_connection_close(sc->ls_conn);
213134e1779SJakub Wojciech Klama 	free(sc);
214134e1779SJakub Wojciech Klama 	return (NULL);
215134e1779SJakub Wojciech Klama }
216134e1779SJakub Wojciech Klama 
217134e1779SJakub Wojciech Klama static int
l9p_socket_readmsg(struct l9p_socket_softc * sc,void ** buf,size_t * size)218134e1779SJakub Wojciech Klama l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size)
219134e1779SJakub Wojciech Klama {
220134e1779SJakub Wojciech Klama 	uint32_t msize;
221134e1779SJakub Wojciech Klama 	size_t toread;
222134e1779SJakub Wojciech Klama 	ssize_t ret;
223134e1779SJakub Wojciech Klama 	void *buffer;
224134e1779SJakub Wojciech Klama 	int fd = sc->ls_fd;
225134e1779SJakub Wojciech Klama 
226134e1779SJakub Wojciech Klama 	assert(fd > 0);
227134e1779SJakub Wojciech Klama 
228134e1779SJakub Wojciech Klama 	buffer = l9p_malloc(sizeof(uint32_t));
229134e1779SJakub Wojciech Klama 
230134e1779SJakub Wojciech Klama 	ret = xread(fd, buffer, sizeof(uint32_t));
231134e1779SJakub Wojciech Klama 	if (ret < 0) {
232134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
233134e1779SJakub Wojciech Klama 		return (-1);
234134e1779SJakub Wojciech Klama 	}
235134e1779SJakub Wojciech Klama 
236134e1779SJakub Wojciech Klama 	if (ret != sizeof(uint32_t)) {
237134e1779SJakub Wojciech Klama 		if (ret == 0)
238134e1779SJakub Wojciech Klama 			L9P_LOG(L9P_DEBUG, "%p: EOF", (void *)sc->ls_conn);
239134e1779SJakub Wojciech Klama 		else
240134e1779SJakub Wojciech Klama 			L9P_LOG(L9P_ERROR,
241134e1779SJakub Wojciech Klama 			    "short read: %zd bytes of %zd expected",
242134e1779SJakub Wojciech Klama 			    ret, sizeof(uint32_t));
243134e1779SJakub Wojciech Klama 		return (-1);
244134e1779SJakub Wojciech Klama 	}
245134e1779SJakub Wojciech Klama 
246134e1779SJakub Wojciech Klama 	msize = le32toh(*(uint32_t *)buffer);
247134e1779SJakub Wojciech Klama 	toread = msize - sizeof(uint32_t);
248134e1779SJakub Wojciech Klama 	buffer = l9p_realloc(buffer, msize);
249134e1779SJakub Wojciech Klama 
250134e1779SJakub Wojciech Klama 	ret = xread(fd, (char *)buffer + sizeof(uint32_t), toread);
251134e1779SJakub Wojciech Klama 	if (ret < 0) {
252134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
253134e1779SJakub Wojciech Klama 		return (-1);
254134e1779SJakub Wojciech Klama 	}
255134e1779SJakub Wojciech Klama 
256134e1779SJakub Wojciech Klama 	if (ret != (ssize_t)toread) {
257134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "short read: %zd bytes of %zd expected",
258134e1779SJakub Wojciech Klama 		    ret, toread);
259134e1779SJakub Wojciech Klama 		return (-1);
260134e1779SJakub Wojciech Klama 	}
261134e1779SJakub Wojciech Klama 
262134e1779SJakub Wojciech Klama 	*size = msize;
263134e1779SJakub Wojciech Klama 	*buf = buffer;
264134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d",
265134e1779SJakub Wojciech Klama 	    (void *)sc->ls_conn, buffer, msize);
266134e1779SJakub Wojciech Klama 
267134e1779SJakub Wojciech Klama 	return (0);
268134e1779SJakub Wojciech Klama }
269134e1779SJakub Wojciech Klama 
270134e1779SJakub Wojciech Klama static int
l9p_socket_get_response_buffer(struct l9p_request * req,struct iovec * iov,size_t * niovp,void * arg __unused)271134e1779SJakub Wojciech Klama l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov,
272134e1779SJakub Wojciech Klama     size_t *niovp, void *arg __unused)
273134e1779SJakub Wojciech Klama {
274134e1779SJakub Wojciech Klama 	size_t size = req->lr_conn->lc_msize;
275134e1779SJakub Wojciech Klama 	void *buf;
276134e1779SJakub Wojciech Klama 
277134e1779SJakub Wojciech Klama 	buf = l9p_malloc(size);
278134e1779SJakub Wojciech Klama 	iov[0].iov_base = buf;
279134e1779SJakub Wojciech Klama 	iov[0].iov_len = size;
280134e1779SJakub Wojciech Klama 
281134e1779SJakub Wojciech Klama 	*niovp = 1;
282134e1779SJakub Wojciech Klama 	return (0);
283134e1779SJakub Wojciech Klama }
284134e1779SJakub Wojciech Klama 
285134e1779SJakub Wojciech Klama static int
l9p_socket_send_response(struct l9p_request * req __unused,const struct iovec * iov,const size_t niov __unused,const size_t iolen,void * arg)286134e1779SJakub Wojciech Klama l9p_socket_send_response(struct l9p_request *req __unused,
287134e1779SJakub Wojciech Klama     const struct iovec *iov, const size_t niov __unused, const size_t iolen,
288134e1779SJakub Wojciech Klama     void *arg)
289134e1779SJakub Wojciech Klama {
290134e1779SJakub Wojciech Klama 	struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
291134e1779SJakub Wojciech Klama 
292134e1779SJakub Wojciech Klama 	assert(sc->ls_fd >= 0);
293134e1779SJakub Wojciech Klama 
294134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg,
295134e1779SJakub Wojciech Klama 	    iov[0].iov_base, iolen);
296134e1779SJakub Wojciech Klama 
297134e1779SJakub Wojciech Klama 	if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) {
298134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno));
299134e1779SJakub Wojciech Klama 		return (-1);
300134e1779SJakub Wojciech Klama 	}
301134e1779SJakub Wojciech Klama 
302134e1779SJakub Wojciech Klama 	free(iov[0].iov_base);
303134e1779SJakub Wojciech Klama 	return (0);
304134e1779SJakub Wojciech Klama }
305134e1779SJakub Wojciech Klama 
306134e1779SJakub Wojciech Klama static void
l9p_socket_drop_response(struct l9p_request * req __unused,const struct iovec * iov,size_t niov __unused,void * arg __unused)307134e1779SJakub Wojciech Klama l9p_socket_drop_response(struct l9p_request *req __unused,
308*067bb820SJakub Wojciech Klama     const struct iovec *iov, size_t niov __unused, void *arg __unused)
309134e1779SJakub Wojciech Klama {
310134e1779SJakub Wojciech Klama 
311134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_DEBUG, "%p: drop buf=%p", arg, iov[0].iov_base);
312134e1779SJakub Wojciech Klama 	free(iov[0].iov_base);
313134e1779SJakub Wojciech Klama }
314134e1779SJakub Wojciech Klama 
315134e1779SJakub Wojciech Klama static ssize_t
xread(int fd,void * buf,size_t count)316134e1779SJakub Wojciech Klama xread(int fd, void *buf, size_t count)
317134e1779SJakub Wojciech Klama {
318134e1779SJakub Wojciech Klama 	size_t done = 0;
319134e1779SJakub Wojciech Klama 	ssize_t ret;
320134e1779SJakub Wojciech Klama 
321134e1779SJakub Wojciech Klama 	while (done < count) {
322134e1779SJakub Wojciech Klama 		ret = read(fd, (char *)buf + done, count - done);
323134e1779SJakub Wojciech Klama 		if (ret < 0) {
324134e1779SJakub Wojciech Klama 			if (errno == EINTR)
325134e1779SJakub Wojciech Klama 				continue;
326134e1779SJakub Wojciech Klama 
327134e1779SJakub Wojciech Klama 			return (-1);
328134e1779SJakub Wojciech Klama 		}
329134e1779SJakub Wojciech Klama 
330134e1779SJakub Wojciech Klama 		if (ret == 0)
331134e1779SJakub Wojciech Klama 			return ((ssize_t)done);
332134e1779SJakub Wojciech Klama 
333134e1779SJakub Wojciech Klama 		done += (size_t)ret;
334134e1779SJakub Wojciech Klama 	}
335134e1779SJakub Wojciech Klama 
336134e1779SJakub Wojciech Klama 	return ((ssize_t)done);
337134e1779SJakub Wojciech Klama }
338134e1779SJakub Wojciech Klama 
339134e1779SJakub Wojciech Klama static ssize_t
xwrite(int fd,void * buf,size_t count)340134e1779SJakub Wojciech Klama xwrite(int fd, void *buf, size_t count)
341134e1779SJakub Wojciech Klama {
342134e1779SJakub Wojciech Klama 	size_t done = 0;
343134e1779SJakub Wojciech Klama 	ssize_t ret;
344134e1779SJakub Wojciech Klama 
345134e1779SJakub Wojciech Klama 	while (done < count) {
346134e1779SJakub Wojciech Klama 		ret = write(fd, (char *)buf + done, count - done);
347134e1779SJakub Wojciech Klama 		if (ret < 0) {
348134e1779SJakub Wojciech Klama 			if (errno == EINTR)
349134e1779SJakub Wojciech Klama 				continue;
350134e1779SJakub Wojciech Klama 
351134e1779SJakub Wojciech Klama 			return (-1);
352134e1779SJakub Wojciech Klama 		}
353134e1779SJakub Wojciech Klama 
354134e1779SJakub Wojciech Klama 		if (ret == 0)
355134e1779SJakub Wojciech Klama 			return ((ssize_t)done);
356134e1779SJakub Wojciech Klama 
357134e1779SJakub Wojciech Klama 		done += (size_t)ret;
358134e1779SJakub Wojciech Klama 	}
359134e1779SJakub Wojciech Klama 
360134e1779SJakub Wojciech Klama 	return ((ssize_t)done);
361134e1779SJakub Wojciech Klama }
362