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