1*aa693e99SJason King /*
2*aa693e99SJason King  * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
3*aa693e99SJason King  * All rights reserved
4*aa693e99SJason King  *
5*aa693e99SJason King  * Redistribution and use in source and binary forms, with or without
6*aa693e99SJason King  * modification, are permitted providing that the following conditions
7*aa693e99SJason King  * are met:
8*aa693e99SJason King  * 1. Redistributions of source code must retain the above copyright
9*aa693e99SJason King  *    notice, this list of conditions and the following disclaimer.
10*aa693e99SJason King  * 2. Redistributions in binary form must reproduce the above copyright
11*aa693e99SJason King  *    notice, this list of conditions and the following disclaimer in the
12*aa693e99SJason King  *    documentation and/or other materials provided with the distribution.
13*aa693e99SJason King  *
14*aa693e99SJason King  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*aa693e99SJason King  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16*aa693e99SJason King  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*aa693e99SJason King  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18*aa693e99SJason King  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*aa693e99SJason King  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*aa693e99SJason King  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*aa693e99SJason King  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22*aa693e99SJason King  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23*aa693e99SJason King  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24*aa693e99SJason King  * POSSIBILITY OF SUCH DAMAGE.
25*aa693e99SJason King  *
26*aa693e99SJason King  * Copyright 2021 Joyent, Inc.
27*aa693e99SJason King  */
28*aa693e99SJason King 
29*aa693e99SJason King #include <stdlib.h>
30*aa693e99SJason King #include <errno.h>
31*aa693e99SJason King #include <string.h>
32*aa693e99SJason King #include <unistd.h>
33*aa693e99SJason King #include <pthread.h>
34*aa693e99SJason King #include <assert.h>
35*aa693e99SJason King #include <sys/types.h>
36*aa693e99SJason King #ifdef __APPLE__
37*aa693e99SJason King # include "../apple_endian.h"
38*aa693e99SJason King #elif __illumos__
39*aa693e99SJason King # include <sys/param.h>
40*aa693e99SJason King # include <port.h>
41*aa693e99SJason King # include "../illumos_endian.h"
42*aa693e99SJason King #else
43*aa693e99SJason King # include <sys/endian.h>
44*aa693e99SJason King #endif
45*aa693e99SJason King #include <sys/socket.h>
46*aa693e99SJason King #ifndef __illumos__
47*aa693e99SJason King # include <sys/event.h>
48*aa693e99SJason King #endif
49*aa693e99SJason King #include <sys/uio.h>
50*aa693e99SJason King #include <netdb.h>
51*aa693e99SJason King #include "../lib9p.h"
52*aa693e99SJason King #include "../lib9p_impl.h"
53*aa693e99SJason King #include "../log.h"
54*aa693e99SJason King #include "socket.h"
55*aa693e99SJason King 
56*aa693e99SJason King struct l9p_socket_softc
57*aa693e99SJason King {
58*aa693e99SJason King 	struct l9p_connection *ls_conn;
59*aa693e99SJason King 	struct sockaddr ls_sockaddr;
60*aa693e99SJason King 	socklen_t ls_socklen;
61*aa693e99SJason King 	pthread_t ls_thread;
62*aa693e99SJason King 	int ls_fd;
63*aa693e99SJason King };
64*aa693e99SJason King 
65*aa693e99SJason King #ifdef __FreeBSD__
66*aa693e99SJason King struct event_svr {
67*aa693e99SJason King 	struct kevent *ev_kev;
68*aa693e99SJason King 	struct kevent *ev_event;
69*aa693e99SJason King 	int ev_kq;
70*aa693e99SJason King };
71*aa693e99SJason King #elif __illumos__
72*aa693e99SJason King struct event_svr {
73*aa693e99SJason King 	port_event_t *ev_pe;
74*aa693e99SJason King 	int ev_port;
75*aa693e99SJason King };
76*aa693e99SJason King #else
77*aa693e99SJason King #error "No event server defined"
78*aa693e99SJason King #endif
79*aa693e99SJason King 
80*aa693e99SJason King static int l9p_init_event_svr(struct event_svr *, uint_t);
81*aa693e99SJason King static uint_t l9p_get_server_addrs(const char *, const char *,
82*aa693e99SJason King     struct addrinfo **);
83*aa693e99SJason King static uint_t l9p_bind_addrs(struct event_svr *, struct addrinfo *, uint_t,
84*aa693e99SJason King     int **);
85*aa693e99SJason King static int l9p_event_get(struct l9p_server *, struct event_svr *, uint_t,
86*aa693e99SJason King     void (*cb)(struct l9p_server *, int));
87*aa693e99SJason King static int l9p_socket_readmsg(struct l9p_socket_softc *, void **, size_t *);
88*aa693e99SJason King static int l9p_socket_get_response_buffer(struct l9p_request *,
89*aa693e99SJason King     struct iovec *, size_t *, void *);
90*aa693e99SJason King static int l9p_socket_send_response(struct l9p_request *, const struct iovec *,
91*aa693e99SJason King     const size_t, const size_t, void *);
92*aa693e99SJason King static void l9p_socket_drop_response(struct l9p_request *, const struct iovec *,
93*aa693e99SJason King     size_t, void *);
94*aa693e99SJason King static void *l9p_socket_thread(void *);
95*aa693e99SJason King static ssize_t xread(int, void *, size_t);
96*aa693e99SJason King static ssize_t xwrite(int, void *, size_t);
97*aa693e99SJason King 
98*aa693e99SJason King int
l9p_start_server(struct l9p_server * server,const char * host,const char * port)99*aa693e99SJason King l9p_start_server(struct l9p_server *server, const char *host, const char *port)
100*aa693e99SJason King {
101*aa693e99SJason King 	struct addrinfo *res = NULL;
102*aa693e99SJason King 	int *sockets = NULL;
103*aa693e99SJason King 	uint_t naddrs = 0;
104*aa693e99SJason King 	uint_t nsockets = 0;
105*aa693e99SJason King 	uint_t i;
106*aa693e99SJason King 	struct event_svr esvr;
107*aa693e99SJason King 
108*aa693e99SJason King 	naddrs = l9p_get_server_addrs(host, port, &res);
109*aa693e99SJason King 	if (naddrs == 0)
110*aa693e99SJason King 		return (-1);
111*aa693e99SJason King 
112*aa693e99SJason King 	if (l9p_init_event_svr(&esvr, naddrs) != 0) {
113*aa693e99SJason King 		freeaddrinfo(res);
114*aa693e99SJason King 		return (-1);
115*aa693e99SJason King 	}
116*aa693e99SJason King 
117*aa693e99SJason King 	nsockets = l9p_bind_addrs(&esvr, res, naddrs, &sockets);
118*aa693e99SJason King 
119*aa693e99SJason King 	/*
120*aa693e99SJason King 	 * We don't need res, after this, so free it and NULL it to prevent
121*aa693e99SJason King 	 * any possible use after free.
122*aa693e99SJason King 	 */
123*aa693e99SJason King 	freeaddrinfo(res);
124*aa693e99SJason King 	res = NULL;
125*aa693e99SJason King 
126*aa693e99SJason King 	if (nsockets == 0)
127*aa693e99SJason King 		goto fail;
128*aa693e99SJason King 
129*aa693e99SJason King 	for (;;) {
130*aa693e99SJason King 		if (l9p_event_get(server, &esvr, nsockets,
131*aa693e99SJason King 		    l9p_socket_accept) < 0)
132*aa693e99SJason King 			break;
133*aa693e99SJason King 	}
134*aa693e99SJason King 
135*aa693e99SJason King 	/* We get here if something failed */
136*aa693e99SJason King 	for (i = 0; i < nsockets; i++)
137*aa693e99SJason King 		close(sockets[i]);
138*aa693e99SJason King 
139*aa693e99SJason King fail:
140*aa693e99SJason King 	free(sockets);
141*aa693e99SJason King 
142*aa693e99SJason King #ifdef __FreeBSD__
143*aa693e99SJason King 	close(esvr.ev_kq);
144*aa693e99SJason King 	free(esvr.ev_kev);
145*aa693e99SJason King 	free(esvr.ev_event);
146*aa693e99SJason King #elif __illumos__
147*aa693e99SJason King 	close(esvr.ev_port);
148*aa693e99SJason King 	free(esvr.ev_pe);
149*aa693e99SJason King #else
150*aa693e99SJason King #error "Port me"
151*aa693e99SJason King #endif
152*aa693e99SJason King 
153*aa693e99SJason King 	return (-1);
154*aa693e99SJason King }
155*aa693e99SJason King 
156*aa693e99SJason King static uint_t
l9p_get_server_addrs(const char * host,const char * port,struct addrinfo ** resp)157*aa693e99SJason King l9p_get_server_addrs(const char *host, const char *port, struct addrinfo **resp)
158*aa693e99SJason King {
159*aa693e99SJason King 	struct addrinfo *res, hints;
160*aa693e99SJason King 	uint_t naddrs;
161*aa693e99SJason King 	int rc;
162*aa693e99SJason King 
163*aa693e99SJason King 	memset(&hints, 0, sizeof(hints));
164*aa693e99SJason King 	hints.ai_family = PF_UNSPEC;
165*aa693e99SJason King 	hints.ai_socktype = SOCK_STREAM;
166*aa693e99SJason King 	rc = getaddrinfo(host, port, &hints, resp);
167*aa693e99SJason King 	if (rc > 0) {
168*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "getaddrinfo(): %s", gai_strerror(rc));
169*aa693e99SJason King 		return (0);
170*aa693e99SJason King 	}
171*aa693e99SJason King 
172*aa693e99SJason King 	naddrs = 0;
173*aa693e99SJason King 	for (res = *resp; res != NULL; res = res->ai_next)
174*aa693e99SJason King 		naddrs++;
175*aa693e99SJason King 
176*aa693e99SJason King 	if (naddrs == 0) {
177*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "no addresses found for %s:%s", host, port);
178*aa693e99SJason King 	}
179*aa693e99SJason King 
180*aa693e99SJason King 	return (naddrs);
181*aa693e99SJason King }
182*aa693e99SJason King 
183*aa693e99SJason King #ifdef __FreeBSD__
184*aa693e99SJason King static int
l9p_init_event_svr(struct event_svr * svr,uint_t nsockets)185*aa693e99SJason King l9p_init_event_svr(struct event_svr *svr, uint_t nsockets)
186*aa693e99SJason King {
187*aa693e99SJason King 	svr->ev_kev = calloc(nsockets, sizeof(struct kevent));
188*aa693e99SJason King 	if (svr->ev_kev == NULL) {
189*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "calloc(): %s", strerror(errno));
190*aa693e99SJason King 		return (-1);
191*aa693e99SJason King 	}
192*aa693e99SJason King 
193*aa693e99SJason King 	svr->ev_event = calloc(nsockets, sizeof(struct kevent));
194*aa693e99SJason King 	if (svr->ev_event == NULL) {
195*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "calloc(): %s", strerror(errno));
196*aa693e99SJason King 		free(svr->ev_key);
197*aa693e99SJason King 		svr->ev_key = NULL;
198*aa693e99SJason King 		return (-1);
199*aa693e99SJason King 	}
200*aa693e99SJason King 
201*aa693e99SJason King 	svr->ev_kq = kqueue();
202*aa693e99SJason King 	if (svr->ev_kq == -1) {
203*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "kqueue(): %s", strerror(errno));
204*aa693e99SJason King 		free(svr->ev_kev);
205*aa693e99SJason King 		free(svr->ev_event);
206*aa693e99SJason King 		svr->ev_kev = NULL;
207*aa693e99SJason King 		svr->ev_event = NULL;
208*aa693e99SJason King 		return (-1);
209*aa693e99SJason King 	}
210*aa693e99SJason King 
211*aa693e99SJason King 	return (0);
212*aa693e99SJason King }
213*aa693e99SJason King #elif __illumos__
214*aa693e99SJason King static int
l9p_init_event_svr(struct event_svr * svr,uint_t nsockets)215*aa693e99SJason King l9p_init_event_svr(struct event_svr *svr, uint_t nsockets)
216*aa693e99SJason King {
217*aa693e99SJason King 	svr->ev_pe = calloc(nsockets, sizeof(port_event_t));
218*aa693e99SJason King 	if (svr->ev_pe == NULL) {
219*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "calloc(): %s", strerror(errno));
220*aa693e99SJason King 		return (-1);
221*aa693e99SJason King 	}
222*aa693e99SJason King 
223*aa693e99SJason King 	svr->ev_port = port_create();
224*aa693e99SJason King 	if (svr->ev_port == -1) {
225*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "port_create(): %s", strerror(errno));
226*aa693e99SJason King 		return (-1);
227*aa693e99SJason King 	}
228*aa693e99SJason King 
229*aa693e99SJason King 	return (0);
230*aa693e99SJason King }
231*aa693e99SJason King #else
232*aa693e99SJason King #error "No event server defined"
233*aa693e99SJason King #endif
234*aa693e99SJason King 
235*aa693e99SJason King static uint_t
l9p_bind_addrs(struct event_svr * svr,struct addrinfo * addrs,uint_t naddrs,int ** socketsp)236*aa693e99SJason King l9p_bind_addrs(struct event_svr *svr, struct addrinfo *addrs, uint_t naddrs,
237*aa693e99SJason King     int **socketsp)
238*aa693e99SJason King {
239*aa693e99SJason King 	struct addrinfo *addr;
240*aa693e99SJason King 	uint_t i, j;
241*aa693e99SJason King 
242*aa693e99SJason King 	*socketsp = calloc(naddrs, sizeof(int));
243*aa693e99SJason King 	if (*socketsp == NULL) {
244*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "calloc(): %s", strerror(errno));
245*aa693e99SJason King 		return (0);
246*aa693e99SJason King 	}
247*aa693e99SJason King 
248*aa693e99SJason King 	for (i = 0, addr = addrs; addr != NULL; addr = addr->ai_next) {
249*aa693e99SJason King 		int s;
250*aa693e99SJason King 		int val = 1;
251*aa693e99SJason King 
252*aa693e99SJason King 		s = socket(addr->ai_family, addr->ai_socktype,
253*aa693e99SJason King 		    addr->ai_protocol);
254*aa693e99SJason King 		if (s == -1) {
255*aa693e99SJason King 			L9P_LOG(L9P_ERROR, "socket(): %s", strerror(errno));
256*aa693e99SJason King 			continue;
257*aa693e99SJason King 		}
258*aa693e99SJason King 
259*aa693e99SJason King 		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val,
260*aa693e99SJason King 		    sizeof(val)) < 0) {
261*aa693e99SJason King 			L9P_LOG(L9P_ERROR, "setsockopt(): %s", strerror(errno));
262*aa693e99SJason King 			close(s);
263*aa693e99SJason King 			continue;
264*aa693e99SJason King 		}
265*aa693e99SJason King 
266*aa693e99SJason King 		if (bind(s, addr->ai_addr, addr->ai_addrlen) < 0) {
267*aa693e99SJason King 			L9P_LOG(L9P_ERROR, "bind(): %s", strerror(errno));
268*aa693e99SJason King 			close(s);
269*aa693e99SJason King 			continue;
270*aa693e99SJason King 		}
271*aa693e99SJason King 
272*aa693e99SJason King 		if (listen(s, 10) < 0) {
273*aa693e99SJason King 			L9P_LOG(L9P_ERROR, "listen(): %s", strerror(errno));
274*aa693e99SJason King 			close(s);
275*aa693e99SJason King 			continue;
276*aa693e99SJason King 		}
277*aa693e99SJason King 
278*aa693e99SJason King #ifdef __FreeBSD__
279*aa693e99SJason King 		EV_SET(&svr->ev_kev[i], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0,
280*aa693e99SJason King 		    0, 0);
281*aa693e99SJason King #elif __illumos__
282*aa693e99SJason King 		if (port_associate(svr->ev_port, PORT_SOURCE_FD, s,
283*aa693e99SJason King 		    POLLIN|POLLHUP, NULL) < 0) {
284*aa693e99SJason King 			L9P_LOG(L9P_ERROR, "port_associate(%d): %s", s,
285*aa693e99SJason King 			    strerror(errno));
286*aa693e99SJason King 			close(s);
287*aa693e99SJason King 			continue;
288*aa693e99SJason King 		}
289*aa693e99SJason King #else
290*aa693e99SJason King #error "Port me"
291*aa693e99SJason King #endif
292*aa693e99SJason King 
293*aa693e99SJason King 		*socketsp[i++] = s;
294*aa693e99SJason King 	}
295*aa693e99SJason King 
296*aa693e99SJason King 	if (i < 1) {
297*aa693e99SJason King 		free(*socketsp);
298*aa693e99SJason King 		*socketsp = NULL;
299*aa693e99SJason King 		return (0);
300*aa693e99SJason King 	}
301*aa693e99SJason King 
302*aa693e99SJason King 	for (j = i; j < naddrs; j++)
303*aa693e99SJason King 		*socketsp[j++] = -1;
304*aa693e99SJason King 
305*aa693e99SJason King #ifdef __FreeBSD__
306*aa693e99SJason King 	if (kevent(svr->ev_kq, svr->ev_kev, i, NULL, 0, NULL) < 0) {
307*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
308*aa693e99SJason King 
309*aa693e99SJason King 		for (j = 0; j < i; j++)
310*aa693e99SJason King 			close(j);
311*aa693e99SJason King 
312*aa693e99SJason King 		free(*socketsp);
313*aa693e99SJason King 		*socketsp = NULL;
314*aa693e99SJason King 
315*aa693e99SJason King 		return (0);
316*aa693e99SJason King 	}
317*aa693e99SJason King #endif
318*aa693e99SJason King 
319*aa693e99SJason King 	return (i);
320*aa693e99SJason King }
321*aa693e99SJason King 
322*aa693e99SJason King #ifdef __FreeBSD__
323*aa693e99SJason King static int
l9p_event_get(struct l9p_server * l9svr,struct event_svr * esvr,uint_t nsockets,void (* cb)(struct l9p_server *,int))324*aa693e99SJason King l9p_event_get(struct l9p_server *l9svr, struct event_svr *esvr, uint_t nsockets,
325*aa693e99SJason King     void (*cb)(struct l9p_server *, int))
326*aa693e99SJason King {
327*aa693e99SJason King 	int i, evs;
328*aa693e99SJason King 
329*aa693e99SJason King 	evs = kevent(esvr->ev_kq, NULL, 0, esvr->ev_event, nsockets, NULL);
330*aa693e99SJason King 	if (evs < 0) {
331*aa693e99SJason King 		if (errno == EINTR)
332*aa693e99SJason King 			return (0);
333*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
334*aa693e99SJason King 		return (-1);
335*aa693e99SJason King 	}
336*aa693e99SJason King 
337*aa693e99SJason King 	for (i = 0; i < evs; i++)
338*aa693e99SJason King 		cb(l9svr, (int)sevr->ev_event[i].ident);
339*aa693e99SJason King 
340*aa693e99SJason King 	return (0);
341*aa693e99SJason King }
342*aa693e99SJason King #elif __illumos__
343*aa693e99SJason King static int
l9p_event_get(struct l9p_server * l9svr,struct event_svr * esvr,uint_t nsockets,void (* cb)(struct l9p_server *,int))344*aa693e99SJason King l9p_event_get(struct l9p_server *l9svr, struct event_svr *esvr, uint_t nsockets,
345*aa693e99SJason King     void (*cb)(struct l9p_server *, int))
346*aa693e99SJason King {
347*aa693e99SJason King 	uint_t evs = 1;
348*aa693e99SJason King 	int i;
349*aa693e99SJason King 
350*aa693e99SJason King 	if (port_getn(esvr->ev_port, esvr->ev_pe, nsockets, &evs, NULL) < 0) {
351*aa693e99SJason King 		if (errno == EINTR)
352*aa693e99SJason King 			return (0);
353*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "port_getn(): %s", strerror(errno));
354*aa693e99SJason King 		return (-1);
355*aa693e99SJason King 	}
356*aa693e99SJason King 
357*aa693e99SJason King 	for (i = 0; i < evs; i++) {
358*aa693e99SJason King 		if (esvr->ev_pe[i].portev_source != PORT_SOURCE_FD)
359*aa693e99SJason King 			continue;
360*aa693e99SJason King 
361*aa693e99SJason King 		cb(l9svr, (int)esvr->ev_pe[i].portev_object);
362*aa693e99SJason King 	}
363*aa693e99SJason King 
364*aa693e99SJason King 	return (0);
365*aa693e99SJason King }
366*aa693e99SJason King #else
367*aa693e99SJason King #error "Port me"
368*aa693e99SJason King #endif
369*aa693e99SJason King 
370*aa693e99SJason King void
l9p_socket_accept(struct l9p_server * server,int svr_fd)371*aa693e99SJason King l9p_socket_accept(struct l9p_server *server, int svr_fd)
372*aa693e99SJason King {
373*aa693e99SJason King 	struct l9p_socket_softc *sc;
374*aa693e99SJason King 	struct l9p_connection *conn;
375*aa693e99SJason King 	char host[NI_MAXHOST + 1];
376*aa693e99SJason King 	char serv[NI_MAXSERV + 1];
377*aa693e99SJason King 	struct sockaddr client_addr;
378*aa693e99SJason King 	socklen_t client_addr_len = sizeof(client_addr);
379*aa693e99SJason King 	int conn_fd, err;
380*aa693e99SJason King 
381*aa693e99SJason King 	conn_fd = accept(svr_fd, &client_addr, &client_addr_len);
382*aa693e99SJason King 	if (conn_fd < 0) {
383*aa693e99SJason King 		L9P_LOG(L9P_WARNING, "accept(): %s", strerror(errno));
384*aa693e99SJason King 		return;
385*aa693e99SJason King 	}
386*aa693e99SJason King 
387*aa693e99SJason King 	err = getnameinfo(&client_addr, client_addr_len, host, NI_MAXHOST,
388*aa693e99SJason King 	    serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
389*aa693e99SJason King 
390*aa693e99SJason King 	if (err != 0) {
391*aa693e99SJason King 		L9P_LOG(L9P_WARNING, "cannot look up client name: %s",
392*aa693e99SJason King 		    gai_strerror(err));
393*aa693e99SJason King 	} else {
394*aa693e99SJason King 		L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv);
395*aa693e99SJason King 	}
396*aa693e99SJason King 
397*aa693e99SJason King 	if (l9p_connection_init(server, &conn) != 0) {
398*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "cannot create new connection");
399*aa693e99SJason King 		return;
400*aa693e99SJason King 	}
401*aa693e99SJason King 
402*aa693e99SJason King 	sc = l9p_calloc(1, sizeof(*sc));
403*aa693e99SJason King 	sc->ls_conn = conn;
404*aa693e99SJason King 	sc->ls_fd = conn_fd;
405*aa693e99SJason King 
406*aa693e99SJason King 	/*
407*aa693e99SJason King 	 * Fill in transport handler functions and aux argument.
408*aa693e99SJason King 	 */
409*aa693e99SJason King 	conn->lc_lt.lt_aux = sc;
410*aa693e99SJason King 	conn->lc_lt.lt_get_response_buffer = l9p_socket_get_response_buffer;
411*aa693e99SJason King 	conn->lc_lt.lt_send_response = l9p_socket_send_response;
412*aa693e99SJason King 	conn->lc_lt.lt_drop_response = l9p_socket_drop_response;
413*aa693e99SJason King 
414*aa693e99SJason King 	err = pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc);
415*aa693e99SJason King 	if (err) {
416*aa693e99SJason King 		L9P_LOG(L9P_ERROR,
417*aa693e99SJason King 		    "pthread_create (for connection from %s:%s): error %s",
418*aa693e99SJason King 		    host, serv, strerror(err));
419*aa693e99SJason King 		l9p_connection_close(sc->ls_conn);
420*aa693e99SJason King 		free(sc);
421*aa693e99SJason King 	}
422*aa693e99SJason King }
423*aa693e99SJason King 
424*aa693e99SJason King static void *
l9p_socket_thread(void * arg)425*aa693e99SJason King l9p_socket_thread(void *arg)
426*aa693e99SJason King {
427*aa693e99SJason King 	struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
428*aa693e99SJason King 	struct iovec iov;
429*aa693e99SJason King 	void *buf;
430*aa693e99SJason King 	size_t length;
431*aa693e99SJason King 
432*aa693e99SJason King 	for (;;) {
433*aa693e99SJason King 		if (l9p_socket_readmsg(sc, &buf, &length) != 0)
434*aa693e99SJason King 			break;
435*aa693e99SJason King 
436*aa693e99SJason King 		iov.iov_base = buf;
437*aa693e99SJason King 		iov.iov_len = length;
438*aa693e99SJason King 		l9p_connection_recv(sc->ls_conn, &iov, 1, NULL);
439*aa693e99SJason King 		free(buf);
440*aa693e99SJason King 	}
441*aa693e99SJason King 
442*aa693e99SJason King 	L9P_LOG(L9P_INFO, "connection closed");
443*aa693e99SJason King 	l9p_connection_close(sc->ls_conn);
444*aa693e99SJason King 	free(sc);
445*aa693e99SJason King 	return (NULL);
446*aa693e99SJason King }
447*aa693e99SJason King 
448*aa693e99SJason King static int
l9p_socket_readmsg(struct l9p_socket_softc * sc,void ** buf,size_t * size)449*aa693e99SJason King l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size)
450*aa693e99SJason King {
451*aa693e99SJason King 	uint32_t msize;
452*aa693e99SJason King 	size_t toread;
453*aa693e99SJason King 	ssize_t ret;
454*aa693e99SJason King 	void *buffer;
455*aa693e99SJason King 	int fd = sc->ls_fd;
456*aa693e99SJason King 
457*aa693e99SJason King 	assert(fd > 0);
458*aa693e99SJason King 
459*aa693e99SJason King 	buffer = l9p_malloc(sizeof(uint32_t));
460*aa693e99SJason King 
461*aa693e99SJason King 	ret = xread(fd, buffer, sizeof(uint32_t));
462*aa693e99SJason King 	if (ret < 0) {
463*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
464*aa693e99SJason King 		return (-1);
465*aa693e99SJason King 	}
466*aa693e99SJason King 
467*aa693e99SJason King 	if (ret != sizeof(uint32_t)) {
468*aa693e99SJason King 		if (ret == 0) {
469*aa693e99SJason King 			L9P_LOG(L9P_DEBUG, "%p: EOF", (void *)sc->ls_conn);
470*aa693e99SJason King 		} else {
471*aa693e99SJason King 			L9P_LOG(L9P_ERROR,
472*aa693e99SJason King 			    "short read: %zd bytes of %zd expected",
473*aa693e99SJason King 			    ret, sizeof(uint32_t));
474*aa693e99SJason King 		}
475*aa693e99SJason King 		return (-1);
476*aa693e99SJason King 	}
477*aa693e99SJason King 
478*aa693e99SJason King 	msize = le32toh(*(uint32_t *)buffer);
479*aa693e99SJason King 	toread = msize - sizeof(uint32_t);
480*aa693e99SJason King 	buffer = l9p_realloc(buffer, msize);
481*aa693e99SJason King 
482*aa693e99SJason King 	ret = xread(fd, (char *)buffer + sizeof(uint32_t), toread);
483*aa693e99SJason King 	if (ret < 0) {
484*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
485*aa693e99SJason King 		return (-1);
486*aa693e99SJason King 	}
487*aa693e99SJason King 
488*aa693e99SJason King 	if (ret != (ssize_t)toread) {
489*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "short read: %zd bytes of %zd expected",
490*aa693e99SJason King 		    ret, toread);
491*aa693e99SJason King 		return (-1);
492*aa693e99SJason King 	}
493*aa693e99SJason King 
494*aa693e99SJason King 	*size = msize;
495*aa693e99SJason King 	*buf = buffer;
496*aa693e99SJason King 	L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d",
497*aa693e99SJason King 	    (void *)sc->ls_conn, buffer, msize);
498*aa693e99SJason King 
499*aa693e99SJason King 	return (0);
500*aa693e99SJason King }
501*aa693e99SJason King 
502*aa693e99SJason King static int
l9p_socket_get_response_buffer(struct l9p_request * req,struct iovec * iov,size_t * niovp,void * arg __unused)503*aa693e99SJason King l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov,
504*aa693e99SJason King     size_t *niovp, void *arg __unused)
505*aa693e99SJason King {
506*aa693e99SJason King 	size_t size = req->lr_conn->lc_msize;
507*aa693e99SJason King 	void *buf;
508*aa693e99SJason King 
509*aa693e99SJason King 	buf = l9p_malloc(size);
510*aa693e99SJason King 	iov[0].iov_base = buf;
511*aa693e99SJason King 	iov[0].iov_len = size;
512*aa693e99SJason King 
513*aa693e99SJason King 	*niovp = 1;
514*aa693e99SJason King 	return (0);
515*aa693e99SJason King }
516*aa693e99SJason King 
517*aa693e99SJason King 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)518*aa693e99SJason King l9p_socket_send_response(struct l9p_request *req __unused,
519*aa693e99SJason King     const struct iovec *iov, const size_t niov __unused, const size_t iolen,
520*aa693e99SJason King     void *arg)
521*aa693e99SJason King {
522*aa693e99SJason King 	struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
523*aa693e99SJason King 
524*aa693e99SJason King 	assert(sc->ls_fd >= 0);
525*aa693e99SJason King 
526*aa693e99SJason King 	L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg,
527*aa693e99SJason King 	    iov[0].iov_base, iolen);
528*aa693e99SJason King 
529*aa693e99SJason King 	if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) {
530*aa693e99SJason King 		L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno));
531*aa693e99SJason King 		return (-1);
532*aa693e99SJason King 	}
533*aa693e99SJason King 
534*aa693e99SJason King 	free(iov[0].iov_base);
535*aa693e99SJason King 	return (0);
536*aa693e99SJason King }
537*aa693e99SJason King 
538*aa693e99SJason King static void
l9p_socket_drop_response(struct l9p_request * req __unused,const struct iovec * iov,size_t niov __unused,void * arg)539*aa693e99SJason King l9p_socket_drop_response(struct l9p_request *req __unused,
540*aa693e99SJason King     const struct iovec *iov, size_t niov __unused, void *arg)
541*aa693e99SJason King {
542*aa693e99SJason King 
543*aa693e99SJason King 	L9P_LOG(L9P_DEBUG, "%p: drop buf=%p", arg, iov[0].iov_base);
544*aa693e99SJason King 	free(iov[0].iov_base);
545*aa693e99SJason King }
546*aa693e99SJason King 
547*aa693e99SJason King static ssize_t
xread(int fd,void * buf,size_t count)548*aa693e99SJason King xread(int fd, void *buf, size_t count)
549*aa693e99SJason King {
550*aa693e99SJason King 	size_t done = 0;
551*aa693e99SJason King 	ssize_t ret;
552*aa693e99SJason King 
553*aa693e99SJason King 	while (done < count) {
554*aa693e99SJason King 		ret = read(fd, (char *)buf + done, count - done);
555*aa693e99SJason King 		if (ret < 0) {
556*aa693e99SJason King 			if (errno == EINTR)
557*aa693e99SJason King 				continue;
558*aa693e99SJason King 
559*aa693e99SJason King 			return (-1);
560*aa693e99SJason King 		}
561*aa693e99SJason King 
562*aa693e99SJason King 		if (ret == 0)
563*aa693e99SJason King 			return ((ssize_t)done);
564*aa693e99SJason King 
565*aa693e99SJason King 		done += (size_t)ret;
566*aa693e99SJason King 	}
567*aa693e99SJason King 
568*aa693e99SJason King 	return ((ssize_t)done);
569*aa693e99SJason King }
570*aa693e99SJason King 
571*aa693e99SJason King static ssize_t
xwrite(int fd,void * buf,size_t count)572*aa693e99SJason King xwrite(int fd, void *buf, size_t count)
573*aa693e99SJason King {
574*aa693e99SJason King 	size_t done = 0;
575*aa693e99SJason King 	ssize_t ret;
576*aa693e99SJason King 
577*aa693e99SJason King 	while (done < count) {
578*aa693e99SJason King 		ret = write(fd, (char *)buf + done, count - done);
579*aa693e99SJason King 		if (ret < 0) {
580*aa693e99SJason King 			if (errno == EINTR)
581*aa693e99SJason King 				continue;
582*aa693e99SJason King 
583*aa693e99SJason King 			return (-1);
584*aa693e99SJason King 		}
585*aa693e99SJason King 
586*aa693e99SJason King 		if (ret == 0)
587*aa693e99SJason King 			return ((ssize_t)done);
588*aa693e99SJason King 
589*aa693e99SJason King 		done += (size_t)ret;
590*aa693e99SJason King 	}
591*aa693e99SJason King 
592*aa693e99SJason King 	return ((ssize_t)done);
593*aa693e99SJason King }
594