1*84d9c625SLionel Sambuc /* $NetBSD: requests.c,v 1.24 2013/01/23 20:22:34 riastradh Exp $ */
2*84d9c625SLionel Sambuc
3*84d9c625SLionel Sambuc /*
4*84d9c625SLionel Sambuc * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5*84d9c625SLionel Sambuc *
6*84d9c625SLionel Sambuc * Development of this software was supported by the
7*84d9c625SLionel Sambuc * Research Foundation of Helsinki University of Technology
8*84d9c625SLionel Sambuc *
9*84d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
10*84d9c625SLionel Sambuc * modification, are permitted provided that the following conditions
11*84d9c625SLionel Sambuc * are met:
12*84d9c625SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
13*84d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
14*84d9c625SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
15*84d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
16*84d9c625SLionel Sambuc * documentation and/or other materials provided with the distribution.
17*84d9c625SLionel Sambuc *
18*84d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19*84d9c625SLionel Sambuc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20*84d9c625SLionel Sambuc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21*84d9c625SLionel Sambuc * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*84d9c625SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*84d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24*84d9c625SLionel Sambuc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*84d9c625SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*84d9c625SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*84d9c625SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*84d9c625SLionel Sambuc * SUCH DAMAGE.
29*84d9c625SLionel Sambuc */
30*84d9c625SLionel Sambuc
31*84d9c625SLionel Sambuc #include <sys/cdefs.h>
32*84d9c625SLionel Sambuc #if !defined(lint)
33*84d9c625SLionel Sambuc __RCSID("$NetBSD: requests.c,v 1.24 2013/01/23 20:22:34 riastradh Exp $");
34*84d9c625SLionel Sambuc #endif /* !lint */
35*84d9c625SLionel Sambuc
36*84d9c625SLionel Sambuc #include <sys/types.h>
37*84d9c625SLionel Sambuc #include <sys/ioctl.h>
38*84d9c625SLionel Sambuc #include <sys/queue.h>
39*84d9c625SLionel Sambuc #include <sys/socket.h>
40*84d9c625SLionel Sambuc
41*84d9c625SLionel Sambuc #include <dev/putter/putter.h>
42*84d9c625SLionel Sambuc
43*84d9c625SLionel Sambuc #include <assert.h>
44*84d9c625SLionel Sambuc #include <errno.h>
45*84d9c625SLionel Sambuc #include <puffs.h>
46*84d9c625SLionel Sambuc #include <stdio.h>
47*84d9c625SLionel Sambuc #include <stdlib.h>
48*84d9c625SLionel Sambuc #include <unistd.h>
49*84d9c625SLionel Sambuc
50*84d9c625SLionel Sambuc #include "puffs_priv.h"
51*84d9c625SLionel Sambuc
52*84d9c625SLionel Sambuc /*
53*84d9c625SLionel Sambuc * Read a frame from the upstream provider. First read the frame
54*84d9c625SLionel Sambuc * length and after this read the actual contents. Yes, optimize
55*84d9c625SLionel Sambuc * me some day.
56*84d9c625SLionel Sambuc */
57*84d9c625SLionel Sambuc /*ARGSUSED*/
58*84d9c625SLionel Sambuc int
puffs__fsframe_read(struct puffs_usermount * pu,struct puffs_framebuf * pb,int fd,int * done)59*84d9c625SLionel Sambuc puffs__fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
60*84d9c625SLionel Sambuc int fd, int *done)
61*84d9c625SLionel Sambuc {
62*84d9c625SLionel Sambuc struct putter_hdr phdr;
63*84d9c625SLionel Sambuc void *win;
64*84d9c625SLionel Sambuc size_t howmuch, winlen, curoff;
65*84d9c625SLionel Sambuc ssize_t n;
66*84d9c625SLionel Sambuc int lenstate;
67*84d9c625SLionel Sambuc
68*84d9c625SLionel Sambuc /* How much to read? */
69*84d9c625SLionel Sambuc the_next_level:
70*84d9c625SLionel Sambuc curoff = puffs_framebuf_telloff(pb);
71*84d9c625SLionel Sambuc if (curoff < sizeof(struct putter_hdr)) {
72*84d9c625SLionel Sambuc howmuch = sizeof(struct putter_hdr) - curoff;
73*84d9c625SLionel Sambuc lenstate = 1;
74*84d9c625SLionel Sambuc } else {
75*84d9c625SLionel Sambuc puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
76*84d9c625SLionel Sambuc /*LINTED*/
77*84d9c625SLionel Sambuc howmuch = phdr.pth_framelen - curoff;
78*84d9c625SLionel Sambuc lenstate = 0;
79*84d9c625SLionel Sambuc }
80*84d9c625SLionel Sambuc
81*84d9c625SLionel Sambuc if (puffs_framebuf_reserve_space(pb, howmuch) == -1)
82*84d9c625SLionel Sambuc return errno;
83*84d9c625SLionel Sambuc
84*84d9c625SLionel Sambuc /* Read contents */
85*84d9c625SLionel Sambuc while (howmuch) {
86*84d9c625SLionel Sambuc winlen = howmuch;
87*84d9c625SLionel Sambuc curoff = puffs_framebuf_telloff(pb);
88*84d9c625SLionel Sambuc if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
89*84d9c625SLionel Sambuc return errno;
90*84d9c625SLionel Sambuc n = read(fd, win, winlen);
91*84d9c625SLionel Sambuc switch (n) {
92*84d9c625SLionel Sambuc case 0:
93*84d9c625SLionel Sambuc return ECONNRESET;
94*84d9c625SLionel Sambuc case -1:
95*84d9c625SLionel Sambuc if (errno == EAGAIN)
96*84d9c625SLionel Sambuc return 0;
97*84d9c625SLionel Sambuc return errno;
98*84d9c625SLionel Sambuc default:
99*84d9c625SLionel Sambuc howmuch -= n;
100*84d9c625SLionel Sambuc puffs_framebuf_seekset(pb, curoff + n);
101*84d9c625SLionel Sambuc break;
102*84d9c625SLionel Sambuc }
103*84d9c625SLionel Sambuc }
104*84d9c625SLionel Sambuc
105*84d9c625SLionel Sambuc if (lenstate)
106*84d9c625SLionel Sambuc goto the_next_level;
107*84d9c625SLionel Sambuc
108*84d9c625SLionel Sambuc puffs_framebuf_seekset(pb, 0);
109*84d9c625SLionel Sambuc *done = 1;
110*84d9c625SLionel Sambuc return 0;
111*84d9c625SLionel Sambuc }
112*84d9c625SLionel Sambuc
113*84d9c625SLionel Sambuc /*
114*84d9c625SLionel Sambuc * Write a frame upstream
115*84d9c625SLionel Sambuc */
116*84d9c625SLionel Sambuc /*ARGSUSED*/
117*84d9c625SLionel Sambuc int
puffs__fsframe_write(struct puffs_usermount * pu,struct puffs_framebuf * pb,int fd,int * done)118*84d9c625SLionel Sambuc puffs__fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
119*84d9c625SLionel Sambuc int fd, int *done)
120*84d9c625SLionel Sambuc {
121*84d9c625SLionel Sambuc void *win;
122*84d9c625SLionel Sambuc uint64_t flen;
123*84d9c625SLionel Sambuc size_t winlen, howmuch, curoff;
124*84d9c625SLionel Sambuc ssize_t n;
125*84d9c625SLionel Sambuc int rv;
126*84d9c625SLionel Sambuc
127*84d9c625SLionel Sambuc /*
128*84d9c625SLionel Sambuc * Finalize it if we haven't written anything yet (or we're still
129*84d9c625SLionel Sambuc * attempting to write the first byte)
130*84d9c625SLionel Sambuc *
131*84d9c625SLionel Sambuc * XXX: this shouldn't be here
132*84d9c625SLionel Sambuc */
133*84d9c625SLionel Sambuc if (puffs_framebuf_telloff(pb) == 0) {
134*84d9c625SLionel Sambuc struct puffs_req *preq;
135*84d9c625SLionel Sambuc
136*84d9c625SLionel Sambuc winlen = sizeof(struct puffs_req);
137*84d9c625SLionel Sambuc rv = puffs_framebuf_getwindow(pb, 0, (void *)&preq, &winlen);
138*84d9c625SLionel Sambuc if (rv == -1)
139*84d9c625SLionel Sambuc return errno;
140*84d9c625SLionel Sambuc preq->preq_pth.pth_framelen = flen = preq->preq_buflen;
141*84d9c625SLionel Sambuc } else {
142*84d9c625SLionel Sambuc struct putter_hdr phdr;
143*84d9c625SLionel Sambuc
144*84d9c625SLionel Sambuc puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
145*84d9c625SLionel Sambuc flen = phdr.pth_framelen;
146*84d9c625SLionel Sambuc }
147*84d9c625SLionel Sambuc
148*84d9c625SLionel Sambuc /*
149*84d9c625SLionel Sambuc * Then write it. Chances are if we are talking to the kernel it'll
150*84d9c625SLionel Sambuc * just shlosh in all at once, but if we're e.g. talking to the
151*84d9c625SLionel Sambuc * network it might take a few tries.
152*84d9c625SLionel Sambuc */
153*84d9c625SLionel Sambuc /*LINTED*/
154*84d9c625SLionel Sambuc howmuch = flen - puffs_framebuf_telloff(pb);
155*84d9c625SLionel Sambuc
156*84d9c625SLionel Sambuc while (howmuch) {
157*84d9c625SLionel Sambuc winlen = howmuch;
158*84d9c625SLionel Sambuc curoff = puffs_framebuf_telloff(pb);
159*84d9c625SLionel Sambuc if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
160*84d9c625SLionel Sambuc return errno;
161*84d9c625SLionel Sambuc
162*84d9c625SLionel Sambuc /*
163*84d9c625SLionel Sambuc * XXX: we know from the framebuf implementation that we
164*84d9c625SLionel Sambuc * will always managed to map the entire window. But if
165*84d9c625SLionel Sambuc * that changes, this will catch it. Then we can do stuff
166*84d9c625SLionel Sambuc * iov stuff instead.
167*84d9c625SLionel Sambuc */
168*84d9c625SLionel Sambuc assert(winlen == howmuch);
169*84d9c625SLionel Sambuc
170*84d9c625SLionel Sambuc /* XXX: want NOSIGNAL if writing to a pipe */
171*84d9c625SLionel Sambuc #if 0
172*84d9c625SLionel Sambuc n = send(fd, win, winlen, MSG_NOSIGNAL);
173*84d9c625SLionel Sambuc #else
174*84d9c625SLionel Sambuc n = write(fd, win, winlen);
175*84d9c625SLionel Sambuc #endif
176*84d9c625SLionel Sambuc switch (n) {
177*84d9c625SLionel Sambuc case 0:
178*84d9c625SLionel Sambuc return ECONNRESET;
179*84d9c625SLionel Sambuc case -1:
180*84d9c625SLionel Sambuc if (errno == EAGAIN)
181*84d9c625SLionel Sambuc return 0;
182*84d9c625SLionel Sambuc return errno;
183*84d9c625SLionel Sambuc default:
184*84d9c625SLionel Sambuc howmuch -= n;
185*84d9c625SLionel Sambuc puffs_framebuf_seekset(pb, curoff + n);
186*84d9c625SLionel Sambuc break;
187*84d9c625SLionel Sambuc }
188*84d9c625SLionel Sambuc }
189*84d9c625SLionel Sambuc
190*84d9c625SLionel Sambuc *done = 1;
191*84d9c625SLionel Sambuc return 0;
192*84d9c625SLionel Sambuc }
193*84d9c625SLionel Sambuc
194*84d9c625SLionel Sambuc /*
195*84d9c625SLionel Sambuc * Compare if "pb1" is a response to a previously sent frame pb2.
196*84d9c625SLionel Sambuc * More often than not "pb1" is not a response to anything but
197*84d9c625SLionel Sambuc * rather a fresh request from the kernel.
198*84d9c625SLionel Sambuc */
199*84d9c625SLionel Sambuc /*ARGSUSED*/
200*84d9c625SLionel Sambuc int
puffs__fsframe_cmp(struct puffs_usermount * pu,struct puffs_framebuf * pb1,struct puffs_framebuf * pb2,int * notresp)201*84d9c625SLionel Sambuc puffs__fsframe_cmp(struct puffs_usermount *pu,
202*84d9c625SLionel Sambuc struct puffs_framebuf *pb1, struct puffs_framebuf *pb2, int *notresp)
203*84d9c625SLionel Sambuc {
204*84d9c625SLionel Sambuc struct puffs_req *preq1, *preq2;
205*84d9c625SLionel Sambuc size_t winlen;
206*84d9c625SLionel Sambuc int rv;
207*84d9c625SLionel Sambuc
208*84d9c625SLionel Sambuc /* map incoming preq */
209*84d9c625SLionel Sambuc winlen = sizeof(struct puffs_req);
210*84d9c625SLionel Sambuc rv = puffs_framebuf_getwindow(pb1, 0, (void *)&preq1, &winlen);
211*84d9c625SLionel Sambuc assert(rv == 0); /* frames are always at least puffs_req in size */
212*84d9c625SLionel Sambuc assert(winlen == sizeof(struct puffs_req));
213*84d9c625SLionel Sambuc
214*84d9c625SLionel Sambuc /*
215*84d9c625SLionel Sambuc * Check if this is not a response in this slot. That's the
216*84d9c625SLionel Sambuc * likely case.
217*84d9c625SLionel Sambuc */
218*84d9c625SLionel Sambuc if ((preq1->preq_opclass & PUFFSOPFLAG_ISRESPONSE) == 0) {
219*84d9c625SLionel Sambuc *notresp = 1;
220*84d9c625SLionel Sambuc return 0;
221*84d9c625SLionel Sambuc }
222*84d9c625SLionel Sambuc
223*84d9c625SLionel Sambuc /* map second preq */
224*84d9c625SLionel Sambuc winlen = sizeof(struct puffs_req);
225*84d9c625SLionel Sambuc rv = puffs_framebuf_getwindow(pb2, 0, (void *)&preq2, &winlen);
226*84d9c625SLionel Sambuc assert(rv == 0); /* frames are always at least puffs_req in size */
227*84d9c625SLionel Sambuc assert(winlen == sizeof(struct puffs_req));
228*84d9c625SLionel Sambuc
229*84d9c625SLionel Sambuc /* then compare: resid equal? */
230*84d9c625SLionel Sambuc return preq1->preq_id != preq2->preq_id;
231*84d9c625SLionel Sambuc }
232*84d9c625SLionel Sambuc
233*84d9c625SLionel Sambuc void
puffs__fsframe_gotframe(struct puffs_usermount * pu,struct puffs_framebuf * pb)234*84d9c625SLionel Sambuc puffs__fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
235*84d9c625SLionel Sambuc {
236*84d9c625SLionel Sambuc
237*84d9c625SLionel Sambuc puffs_framebuf_seekset(pb, 0);
238*84d9c625SLionel Sambuc puffs__ml_dispatch(pu, pb);
239*84d9c625SLionel Sambuc }
240