xref: /freebsd/contrib/lib9p/transport/socket.c (revision 067bb8206d86526a72c7e7ba6285103b2cad3ad3)
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
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 	int sockets[2];
77134e1779SJakub Wojciech Klama 
78134e1779SJakub Wojciech Klama 	memset(&hints, 0, sizeof(hints));
79134e1779SJakub Wojciech Klama 	hints.ai_family = PF_UNSPEC;
80134e1779SJakub Wojciech Klama 	hints.ai_socktype = SOCK_STREAM;
81134e1779SJakub Wojciech Klama 	err = getaddrinfo(host, port, &hints, &res0);
82134e1779SJakub Wojciech Klama 
83134e1779SJakub Wojciech Klama 	if (err)
84134e1779SJakub Wojciech Klama 		return (-1);
85134e1779SJakub Wojciech Klama 
86134e1779SJakub Wojciech Klama 	for (res = res0; res; res = res->ai_next) {
87134e1779SJakub Wojciech Klama 		int s = socket(res->ai_family, res->ai_socktype,
88134e1779SJakub Wojciech Klama 		    res->ai_protocol);
89134e1779SJakub Wojciech Klama 
90134e1779SJakub Wojciech Klama 		val = 1;
91134e1779SJakub Wojciech Klama 		setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
92134e1779SJakub Wojciech Klama 
93134e1779SJakub Wojciech Klama 		if (s < 0)
94134e1779SJakub Wojciech Klama 			continue;
95134e1779SJakub Wojciech Klama 
96134e1779SJakub Wojciech Klama 		if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
97134e1779SJakub Wojciech Klama 			close(s);
98134e1779SJakub Wojciech Klama 			continue;
99134e1779SJakub Wojciech Klama 		}
100134e1779SJakub Wojciech Klama 
101134e1779SJakub Wojciech Klama 		sockets[nsockets] = s;
102134e1779SJakub Wojciech Klama 		EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0,
103134e1779SJakub Wojciech Klama 		    0, 0);
104134e1779SJakub Wojciech Klama 		listen(s, 10);
105134e1779SJakub Wojciech Klama 	}
106134e1779SJakub Wojciech Klama 
107134e1779SJakub Wojciech Klama 	if (nsockets < 1) {
108134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "bind(): %s", strerror(errno));
109134e1779SJakub Wojciech Klama 		return(-1);
110134e1779SJakub Wojciech Klama 	}
111134e1779SJakub Wojciech Klama 
112134e1779SJakub Wojciech Klama 	kq = kqueue();
113134e1779SJakub Wojciech Klama 
114134e1779SJakub Wojciech Klama 	if (kevent(kq, kev, nsockets, NULL, 0, NULL) < 0) {
115134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
116134e1779SJakub Wojciech Klama 		return (-1);
117134e1779SJakub Wojciech Klama 	}
118134e1779SJakub Wojciech Klama 
119134e1779SJakub Wojciech Klama 	for (;;) {
120134e1779SJakub Wojciech Klama 		evs = kevent(kq, NULL, 0, event, nsockets, NULL);
121134e1779SJakub Wojciech Klama 		if (evs < 0) {
122134e1779SJakub Wojciech Klama 			if (errno == EINTR)
123134e1779SJakub Wojciech Klama 				continue;
124134e1779SJakub Wojciech Klama 
125134e1779SJakub Wojciech Klama 			L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
126134e1779SJakub Wojciech Klama 			return (-1);
127134e1779SJakub Wojciech Klama 		}
128134e1779SJakub Wojciech Klama 
129134e1779SJakub Wojciech Klama 		for (i = 0; i < evs; i++) {
130134e1779SJakub Wojciech Klama 			struct sockaddr client_addr;
131134e1779SJakub Wojciech Klama 			socklen_t client_addr_len = sizeof(client_addr);
132134e1779SJakub Wojciech Klama 			int news = accept((int)event[i].ident, &client_addr,
133134e1779SJakub Wojciech Klama 			    &client_addr_len);
134134e1779SJakub Wojciech Klama 
135134e1779SJakub Wojciech Klama 			if (news < 0) {
136134e1779SJakub Wojciech Klama 				L9P_LOG(L9P_WARNING, "accept(): %s",
137134e1779SJakub Wojciech Klama 				    strerror(errno));
138134e1779SJakub Wojciech Klama 				continue;
139134e1779SJakub Wojciech Klama 			}
140134e1779SJakub Wojciech Klama 
141134e1779SJakub Wojciech Klama 			l9p_socket_accept(server, news, &client_addr,
142134e1779SJakub Wojciech Klama 			    client_addr_len);
143134e1779SJakub Wojciech Klama 		}
144134e1779SJakub Wojciech Klama 	}
145134e1779SJakub Wojciech Klama 
146134e1779SJakub Wojciech Klama }
147134e1779SJakub Wojciech Klama 
148134e1779SJakub Wojciech Klama void
149134e1779SJakub Wojciech Klama l9p_socket_accept(struct l9p_server *server, int conn_fd,
150134e1779SJakub Wojciech Klama     struct sockaddr *client_addr, socklen_t client_addr_len)
151134e1779SJakub Wojciech Klama {
152134e1779SJakub Wojciech Klama 	struct l9p_socket_softc *sc;
153134e1779SJakub Wojciech Klama 	struct l9p_connection *conn;
154134e1779SJakub Wojciech Klama 	char host[NI_MAXHOST + 1];
155134e1779SJakub Wojciech Klama 	char serv[NI_MAXSERV + 1];
156134e1779SJakub Wojciech Klama 	int err;
157134e1779SJakub Wojciech Klama 
158134e1779SJakub Wojciech Klama 	err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv,
159134e1779SJakub Wojciech Klama 	    NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
160134e1779SJakub Wojciech Klama 
161134e1779SJakub Wojciech Klama 	if (err != 0) {
162134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_WARNING, "cannot look up client name: %s",
163134e1779SJakub Wojciech Klama 		    gai_strerror(err));
164134e1779SJakub Wojciech Klama 	} else {
165134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv);
166134e1779SJakub Wojciech Klama 	}
167134e1779SJakub Wojciech Klama 
168134e1779SJakub Wojciech Klama 	if (l9p_connection_init(server, &conn) != 0) {
169134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "cannot create new connection");
170134e1779SJakub Wojciech Klama 		return;
171134e1779SJakub Wojciech Klama 	}
172134e1779SJakub Wojciech Klama 
173134e1779SJakub Wojciech Klama 	sc = l9p_calloc(1, sizeof(*sc));
174134e1779SJakub Wojciech Klama 	sc->ls_conn = conn;
175134e1779SJakub Wojciech Klama 	sc->ls_fd = conn_fd;
176134e1779SJakub Wojciech Klama 
177134e1779SJakub Wojciech Klama 	/*
178134e1779SJakub Wojciech Klama 	 * Fill in transport handler functions and aux argument.
179134e1779SJakub Wojciech Klama 	 */
180134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_aux = sc;
181134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_get_response_buffer = l9p_socket_get_response_buffer;
182134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_send_response = l9p_socket_send_response;
183134e1779SJakub Wojciech Klama 	conn->lc_lt.lt_drop_response = l9p_socket_drop_response;
184134e1779SJakub Wojciech Klama 
185134e1779SJakub Wojciech Klama 	err = pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc);
186134e1779SJakub Wojciech Klama 	if (err) {
187134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR,
188134e1779SJakub Wojciech Klama 		    "pthread_create (for connection from %s:%s): error %s",
189134e1779SJakub Wojciech Klama 		    host, serv, strerror(err));
190134e1779SJakub Wojciech Klama 		l9p_connection_close(sc->ls_conn);
191134e1779SJakub Wojciech Klama 		free(sc);
192134e1779SJakub Wojciech Klama 	}
193134e1779SJakub Wojciech Klama }
194134e1779SJakub Wojciech Klama 
195134e1779SJakub Wojciech Klama static void *
196134e1779SJakub Wojciech Klama l9p_socket_thread(void *arg)
197134e1779SJakub Wojciech Klama {
198134e1779SJakub Wojciech Klama 	struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
199134e1779SJakub Wojciech Klama 	struct iovec iov;
200134e1779SJakub Wojciech Klama 	void *buf;
201134e1779SJakub Wojciech Klama 	size_t length;
202134e1779SJakub Wojciech Klama 
203134e1779SJakub Wojciech Klama 	for (;;) {
204134e1779SJakub Wojciech Klama 		if (l9p_socket_readmsg(sc, &buf, &length) != 0)
205134e1779SJakub Wojciech Klama 			break;
206134e1779SJakub Wojciech Klama 
207134e1779SJakub Wojciech Klama 		iov.iov_base = buf;
208134e1779SJakub Wojciech Klama 		iov.iov_len = length;
209134e1779SJakub Wojciech Klama 		l9p_connection_recv(sc->ls_conn, &iov, 1, NULL);
210134e1779SJakub Wojciech Klama 		free(buf);
211134e1779SJakub Wojciech Klama 	}
212134e1779SJakub Wojciech Klama 
213134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_INFO, "connection closed");
214134e1779SJakub Wojciech Klama 	l9p_connection_close(sc->ls_conn);
215134e1779SJakub Wojciech Klama 	free(sc);
216134e1779SJakub Wojciech Klama 	return (NULL);
217134e1779SJakub Wojciech Klama }
218134e1779SJakub Wojciech Klama 
219134e1779SJakub Wojciech Klama static int
220134e1779SJakub Wojciech Klama l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size)
221134e1779SJakub Wojciech Klama {
222134e1779SJakub Wojciech Klama 	uint32_t msize;
223134e1779SJakub Wojciech Klama 	size_t toread;
224134e1779SJakub Wojciech Klama 	ssize_t ret;
225134e1779SJakub Wojciech Klama 	void *buffer;
226134e1779SJakub Wojciech Klama 	int fd = sc->ls_fd;
227134e1779SJakub Wojciech Klama 
228134e1779SJakub Wojciech Klama 	assert(fd > 0);
229134e1779SJakub Wojciech Klama 
230134e1779SJakub Wojciech Klama 	buffer = l9p_malloc(sizeof(uint32_t));
231134e1779SJakub Wojciech Klama 
232134e1779SJakub Wojciech Klama 	ret = xread(fd, buffer, sizeof(uint32_t));
233134e1779SJakub Wojciech Klama 	if (ret < 0) {
234134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
235134e1779SJakub Wojciech Klama 		return (-1);
236134e1779SJakub Wojciech Klama 	}
237134e1779SJakub Wojciech Klama 
238134e1779SJakub Wojciech Klama 	if (ret != sizeof(uint32_t)) {
239134e1779SJakub Wojciech Klama 		if (ret == 0)
240134e1779SJakub Wojciech Klama 			L9P_LOG(L9P_DEBUG, "%p: EOF", (void *)sc->ls_conn);
241134e1779SJakub Wojciech Klama 		else
242134e1779SJakub Wojciech Klama 			L9P_LOG(L9P_ERROR,
243134e1779SJakub Wojciech Klama 			    "short read: %zd bytes of %zd expected",
244134e1779SJakub Wojciech Klama 			    ret, sizeof(uint32_t));
245134e1779SJakub Wojciech Klama 		return (-1);
246134e1779SJakub Wojciech Klama 	}
247134e1779SJakub Wojciech Klama 
248134e1779SJakub Wojciech Klama 	msize = le32toh(*(uint32_t *)buffer);
249134e1779SJakub Wojciech Klama 	toread = msize - sizeof(uint32_t);
250134e1779SJakub Wojciech Klama 	buffer = l9p_realloc(buffer, msize);
251134e1779SJakub Wojciech Klama 
252134e1779SJakub Wojciech Klama 	ret = xread(fd, (char *)buffer + sizeof(uint32_t), toread);
253134e1779SJakub Wojciech Klama 	if (ret < 0) {
254134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
255134e1779SJakub Wojciech Klama 		return (-1);
256134e1779SJakub Wojciech Klama 	}
257134e1779SJakub Wojciech Klama 
258134e1779SJakub Wojciech Klama 	if (ret != (ssize_t)toread) {
259134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "short read: %zd bytes of %zd expected",
260134e1779SJakub Wojciech Klama 		    ret, toread);
261134e1779SJakub Wojciech Klama 		return (-1);
262134e1779SJakub Wojciech Klama 	}
263134e1779SJakub Wojciech Klama 
264134e1779SJakub Wojciech Klama 	*size = msize;
265134e1779SJakub Wojciech Klama 	*buf = buffer;
266134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d",
267134e1779SJakub Wojciech Klama 	    (void *)sc->ls_conn, buffer, msize);
268134e1779SJakub Wojciech Klama 
269134e1779SJakub Wojciech Klama 	return (0);
270134e1779SJakub Wojciech Klama }
271134e1779SJakub Wojciech Klama 
272134e1779SJakub Wojciech Klama static int
273134e1779SJakub Wojciech Klama l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov,
274134e1779SJakub Wojciech Klama     size_t *niovp, void *arg __unused)
275134e1779SJakub Wojciech Klama {
276134e1779SJakub Wojciech Klama 	size_t size = req->lr_conn->lc_msize;
277134e1779SJakub Wojciech Klama 	void *buf;
278134e1779SJakub Wojciech Klama 
279134e1779SJakub Wojciech Klama 	buf = l9p_malloc(size);
280134e1779SJakub Wojciech Klama 	iov[0].iov_base = buf;
281134e1779SJakub Wojciech Klama 	iov[0].iov_len = size;
282134e1779SJakub Wojciech Klama 
283134e1779SJakub Wojciech Klama 	*niovp = 1;
284134e1779SJakub Wojciech Klama 	return (0);
285134e1779SJakub Wojciech Klama }
286134e1779SJakub Wojciech Klama 
287134e1779SJakub Wojciech Klama static int
288134e1779SJakub Wojciech Klama l9p_socket_send_response(struct l9p_request *req __unused,
289134e1779SJakub Wojciech Klama     const struct iovec *iov, const size_t niov __unused, const size_t iolen,
290134e1779SJakub Wojciech Klama     void *arg)
291134e1779SJakub Wojciech Klama {
292134e1779SJakub Wojciech Klama 	struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
293134e1779SJakub Wojciech Klama 
294134e1779SJakub Wojciech Klama 	assert(sc->ls_fd >= 0);
295134e1779SJakub Wojciech Klama 
296134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg,
297134e1779SJakub Wojciech Klama 	    iov[0].iov_base, iolen);
298134e1779SJakub Wojciech Klama 
299134e1779SJakub Wojciech Klama 	if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) {
300134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno));
301134e1779SJakub Wojciech Klama 		return (-1);
302134e1779SJakub Wojciech Klama 	}
303134e1779SJakub Wojciech Klama 
304134e1779SJakub Wojciech Klama 	free(iov[0].iov_base);
305134e1779SJakub Wojciech Klama 	return (0);
306134e1779SJakub Wojciech Klama }
307134e1779SJakub Wojciech Klama 
308134e1779SJakub Wojciech Klama static void
309134e1779SJakub Wojciech Klama l9p_socket_drop_response(struct l9p_request *req __unused,
310*067bb820SJakub Wojciech Klama     const struct iovec *iov, size_t niov __unused, void *arg __unused)
311134e1779SJakub Wojciech Klama {
312134e1779SJakub Wojciech Klama 
313134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_DEBUG, "%p: drop buf=%p", arg, iov[0].iov_base);
314134e1779SJakub Wojciech Klama 	free(iov[0].iov_base);
315134e1779SJakub Wojciech Klama }
316134e1779SJakub Wojciech Klama 
317134e1779SJakub Wojciech Klama static ssize_t
318134e1779SJakub Wojciech Klama xread(int fd, void *buf, size_t count)
319134e1779SJakub Wojciech Klama {
320134e1779SJakub Wojciech Klama 	size_t done = 0;
321134e1779SJakub Wojciech Klama 	ssize_t ret;
322134e1779SJakub Wojciech Klama 
323134e1779SJakub Wojciech Klama 	while (done < count) {
324134e1779SJakub Wojciech Klama 		ret = read(fd, (char *)buf + done, count - done);
325134e1779SJakub Wojciech Klama 		if (ret < 0) {
326134e1779SJakub Wojciech Klama 			if (errno == EINTR)
327134e1779SJakub Wojciech Klama 				continue;
328134e1779SJakub Wojciech Klama 
329134e1779SJakub Wojciech Klama 			return (-1);
330134e1779SJakub Wojciech Klama 		}
331134e1779SJakub Wojciech Klama 
332134e1779SJakub Wojciech Klama 		if (ret == 0)
333134e1779SJakub Wojciech Klama 			return ((ssize_t)done);
334134e1779SJakub Wojciech Klama 
335134e1779SJakub Wojciech Klama 		done += (size_t)ret;
336134e1779SJakub Wojciech Klama 	}
337134e1779SJakub Wojciech Klama 
338134e1779SJakub Wojciech Klama 	return ((ssize_t)done);
339134e1779SJakub Wojciech Klama }
340134e1779SJakub Wojciech Klama 
341134e1779SJakub Wojciech Klama static ssize_t
342134e1779SJakub Wojciech Klama xwrite(int fd, void *buf, size_t count)
343134e1779SJakub Wojciech Klama {
344134e1779SJakub Wojciech Klama 	size_t done = 0;
345134e1779SJakub Wojciech Klama 	ssize_t ret;
346134e1779SJakub Wojciech Klama 
347134e1779SJakub Wojciech Klama 	while (done < count) {
348134e1779SJakub Wojciech Klama 		ret = write(fd, (char *)buf + done, count - done);
349134e1779SJakub Wojciech Klama 		if (ret < 0) {
350134e1779SJakub Wojciech Klama 			if (errno == EINTR)
351134e1779SJakub Wojciech Klama 				continue;
352134e1779SJakub Wojciech Klama 
353134e1779SJakub Wojciech Klama 			return (-1);
354134e1779SJakub Wojciech Klama 		}
355134e1779SJakub Wojciech Klama 
356134e1779SJakub Wojciech Klama 		if (ret == 0)
357134e1779SJakub Wojciech Klama 			return ((ssize_t)done);
358134e1779SJakub Wojciech Klama 
359134e1779SJakub Wojciech Klama 		done += (size_t)ret;
360134e1779SJakub Wojciech Klama 	}
361134e1779SJakub Wojciech Klama 
362134e1779SJakub Wojciech Klama 	return ((ssize_t)done);
363134e1779SJakub Wojciech Klama }
364