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