xref: /netbsd/lib/libpuffs/requests.c (revision 04973f74)
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/cdefs.h>
32 #if !defined(lint)
33 __RCSID("$NetBSD: requests.c,v 1.23 2008/01/29 14:54:08 pooka 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
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
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
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
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