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