Merge branch 'vendor/BYACC'
[dragonfly.git] / lib / libpuffs / requests.c
1 /*      $NetBSD: requests.c,v 1.23 2008/01/29 14:54:08 pooka 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/types.h>
32 #include <sys/ioctl.h>
33 #include <sys/queue.h>
34 #include <sys/socket.h>
35
36 #include <dev/misc/putter/putter.h>
37
38 #include <assert.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43
44 #include "puffs.h"
45 #include "puffs_priv.h"
46
47 /*
48  * Read a frame from the upstream provider.  First read the frame
49  * length and after this read the actual contents.  Yes, optimize
50  * me some day.
51  */
52 /*ARGSUSED*/
53 int
54 puffs__fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
55         int fd, int *done)
56 {
57         struct putter_hdr phdr;
58         void *win;
59         size_t howmuch, winlen, curoff;
60         ssize_t n;
61         int lenstate;
62
63         /* How much to read? */
64  the_next_level:
65         curoff = puffs_framebuf_telloff(pb);
66         if (curoff < sizeof(struct putter_hdr)) {
67                 howmuch = sizeof(struct putter_hdr) - curoff;
68                 lenstate = 1;
69         } else {
70                 puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
71                 /*LINTED*/
72                 howmuch = phdr.pth_framelen - curoff;
73                 lenstate = 0;
74         }
75
76         if (puffs_framebuf_reserve_space(pb, howmuch) == -1)
77                 return errno;
78
79         /* Read contents */
80         while (howmuch) {
81                 winlen = howmuch;
82                 curoff = puffs_framebuf_telloff(pb);
83                 if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
84                         return errno;
85                 n = read(fd, win, winlen);
86                 switch (n) {
87                 case 0:
88                         return ECONNRESET;
89                 case -1:
90                         if (errno == EAGAIN)
91                                 return 0;
92                         return errno;
93                 default:
94                         howmuch -= n;
95                         puffs_framebuf_seekset(pb, curoff + n);
96                         break;
97                 }
98         }
99
100         if (lenstate)
101                 goto the_next_level;
102
103         puffs_framebuf_seekset(pb, 0);
104         *done = 1;
105         return 0;
106 }
107
108 /*
109  * Write a frame upstream
110  */
111 /*ARGSUSED*/
112 int
113 puffs__fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
114         int fd, int *done)
115 {
116         void *win;
117         uint64_t flen;
118         size_t winlen, howmuch, curoff;
119         ssize_t n;
120         int rv;
121
122         /*
123          * Finalize it if we haven't written anything yet (or we're still
124          * attempting to write the first byte)
125          *
126          * XXX: this shouldn't be here
127          */
128         if (puffs_framebuf_telloff(pb) == 0) {
129                 struct puffs_req *preq;
130
131                 winlen = sizeof(struct puffs_req);
132                 rv = puffs_framebuf_getwindow(pb, 0, (void *)&preq, &winlen);
133                 if (rv == -1)
134                         return errno;
135                 preq->preq_pth.pth_framelen = flen = preq->preq_buflen;
136         } else {
137                 struct putter_hdr phdr;
138
139                 puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
140                 flen = phdr.pth_framelen;
141         }
142
143         /*
144          * Then write it.  Chances are if we are talking to the kernel it'll
145          * just shlosh in all at once, but if we're e.g. talking to the
146          * network it might take a few tries.
147          */
148         /*LINTED*/
149         howmuch = flen - puffs_framebuf_telloff(pb);
150
151         while (howmuch) {
152                 winlen = howmuch;
153                 curoff = puffs_framebuf_telloff(pb);
154                 if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
155                         return errno;
156
157                 /*
158                  * XXX: we know from the framebuf implementation that we
159                  * will always managed to map the entire window.  But if
160                  * that changes, this will catch it.  Then we can do stuff
161                  * iov stuff instead.
162                  */
163                 assert(winlen == howmuch);
164
165                 /* XXX: want NOSIGNAL if writing to a pipe */
166 #if 0
167                 n = send(fd, win, winlen, MSG_NOSIGNAL);
168 #else
169                 n = write(fd, win, winlen);
170 #endif
171                 switch (n) {
172                 case 0:
173                         return ECONNRESET;
174                 case -1:
175                         if (errno == EAGAIN)
176                                 return 0;
177                         return errno;
178                 default:
179                         howmuch -= n;
180                         puffs_framebuf_seekset(pb, curoff + n);
181                         break;
182                 }
183         }
184
185         *done = 1;
186         return 0;
187 }
188
189 /*
190  * Compare if "pb1" is a response to a previously sent frame pb2.
191  * More often than not "pb1" is not a response to anything but
192  * rather a fresh request from the kernel.
193  */
194 /*ARGSUSED*/
195 int
196 puffs__fsframe_cmp(struct puffs_usermount *pu,
197         struct puffs_framebuf *pb1, struct puffs_framebuf *pb2, int *notresp)
198 {
199         struct puffs_req *preq1, *preq2;
200         size_t winlen;
201         int rv;
202
203         /* map incoming preq */
204         winlen = sizeof(struct puffs_req);
205         rv = puffs_framebuf_getwindow(pb1, 0, (void *)&preq1, &winlen);
206         assert(rv == 0); /* frames are always at least puffs_req in size */
207         assert(winlen = sizeof(struct puffs_req));
208
209         /*
210          * Check if this is not a response in this slot.  That's the
211          * likely case.
212          */
213         if ((preq1->preq_opclass & PUFFSOPFLAG_ISRESPONSE) == 0) {
214                 *notresp = 1;
215                 return 0;
216         }
217
218         /* map second preq */
219         winlen = sizeof(struct puffs_req);
220         rv = puffs_framebuf_getwindow(pb2, 0, (void *)&preq2, &winlen);
221         assert(rv == 0); /* frames are always at least puffs_req in size */
222         assert(winlen = sizeof(struct puffs_req));
223
224         /* then compare: resid equal? */
225         return preq1->preq_id != preq2->preq_id;
226 }
227
228 void
229 puffs__fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
230 {
231
232         puffs_framebuf_seekset(pb, 0);
233         puffs__ml_dispatch(pu, pb);
234 }