Statistics
| Branch: | Revision:

root / nbd.c @ caa88be0

History | View | Annotate | Download (10.6 kB)

1 7a5ca864 bellard
/*\
2 7a5ca864 bellard
 *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
3 7a5ca864 bellard
 *
4 7a5ca864 bellard
 *  Network Block Device
5 7a5ca864 bellard
 *
6 7a5ca864 bellard
 *  This program is free software; you can redistribute it and/or modify
7 7a5ca864 bellard
 *  it under the terms of the GNU General Public License as published by
8 7a5ca864 bellard
 *  the Free Software Foundation; under version 2 of the License.
9 7a5ca864 bellard
 *
10 7a5ca864 bellard
 *  This program is distributed in the hope that it will be useful,
11 7a5ca864 bellard
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 7a5ca864 bellard
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 7a5ca864 bellard
 *  GNU General Public License for more details.
14 7a5ca864 bellard
 *
15 7a5ca864 bellard
 *  You should have received a copy of the GNU General Public License
16 7a5ca864 bellard
 *  along with this program; if not, write to the Free Software
17 7a5ca864 bellard
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 7a5ca864 bellard
\*/
19 7a5ca864 bellard
20 7a5ca864 bellard
#include "nbd.h"
21 7a5ca864 bellard
22 7a5ca864 bellard
#include <errno.h>
23 7a5ca864 bellard
#include <string.h>
24 7a5ca864 bellard
#include <sys/ioctl.h>
25 7a5ca864 bellard
#include <ctype.h>
26 7a5ca864 bellard
#include <inttypes.h>
27 7a5ca864 bellard
#include <sys/socket.h>
28 7a5ca864 bellard
#include <netinet/in.h>
29 7a5ca864 bellard
#include <netinet/tcp.h>
30 7a5ca864 bellard
#include <arpa/inet.h>
31 7a5ca864 bellard
#include <netdb.h>
32 7a5ca864 bellard
33 7a5ca864 bellard
extern int verbose;
34 7a5ca864 bellard
35 7a5ca864 bellard
#define LOG(msg, ...) do { \
36 7a5ca864 bellard
    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
37 7a5ca864 bellard
            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
38 7a5ca864 bellard
} while(0)
39 7a5ca864 bellard
40 7a5ca864 bellard
#define TRACE(msg, ...) do { \
41 7a5ca864 bellard
    if (verbose) LOG(msg, ## __VA_ARGS__); \
42 7a5ca864 bellard
} while(0)
43 7a5ca864 bellard
44 7a5ca864 bellard
/* This is all part of the "official" NBD API */
45 7a5ca864 bellard
46 7a5ca864 bellard
#define NBD_REQUEST_MAGIC       0x25609513
47 7a5ca864 bellard
#define NBD_REPLY_MAGIC         0x67446698
48 7a5ca864 bellard
49 7a5ca864 bellard
#define NBD_SET_SOCK            _IO(0xab, 0)
50 7a5ca864 bellard
#define NBD_SET_BLKSIZE         _IO(0xab, 1)
51 7a5ca864 bellard
#define NBD_SET_SIZE            _IO(0xab, 2)
52 7a5ca864 bellard
#define NBD_DO_IT               _IO(0xab, 3)
53 7a5ca864 bellard
#define NBD_CLEAR_SOCK          _IO(0xab, 4)
54 7a5ca864 bellard
#define NBD_CLEAR_QUE           _IO(0xab, 5)
55 7a5ca864 bellard
#define NBD_PRINT_DEBUG                _IO(0xab, 6)
56 7a5ca864 bellard
#define NBD_SET_SIZE_BLOCKS        _IO(0xab, 7)
57 7a5ca864 bellard
#define NBD_DISCONNECT          _IO(0xab, 8)
58 7a5ca864 bellard
59 7a5ca864 bellard
/* That's all folks */
60 7a5ca864 bellard
61 7a5ca864 bellard
#define read_sync(fd, buffer, size) wr_sync(fd, buffer, size, true)
62 7a5ca864 bellard
#define write_sync(fd, buffer, size) wr_sync(fd, buffer, size, false)
63 7a5ca864 bellard
64 7a5ca864 bellard
static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
65 7a5ca864 bellard
{
66 7a5ca864 bellard
    size_t offset = 0;
67 7a5ca864 bellard
68 7a5ca864 bellard
    while (offset < size) {
69 7a5ca864 bellard
        ssize_t len;
70 7a5ca864 bellard
71 7a5ca864 bellard
        if (do_read) {
72 7a5ca864 bellard
            len = read(fd, buffer + offset, size - offset);
73 7a5ca864 bellard
        } else {
74 7a5ca864 bellard
            len = write(fd, buffer + offset, size - offset);
75 7a5ca864 bellard
        }
76 7a5ca864 bellard
77 7a5ca864 bellard
        /* recoverable error */
78 7a5ca864 bellard
        if (len == -1 && errno == EAGAIN) {
79 7a5ca864 bellard
            continue;
80 7a5ca864 bellard
        }
81 7a5ca864 bellard
82 7a5ca864 bellard
        /* eof */
83 7a5ca864 bellard
        if (len == 0) {
84 7a5ca864 bellard
            break;
85 7a5ca864 bellard
        }
86 7a5ca864 bellard
87 7a5ca864 bellard
        /* unrecoverable error */
88 7a5ca864 bellard
        if (len == -1) {
89 7a5ca864 bellard
            return 0;
90 7a5ca864 bellard
        }
91 7a5ca864 bellard
92 7a5ca864 bellard
        offset += len;
93 7a5ca864 bellard
    }
94 7a5ca864 bellard
95 7a5ca864 bellard
    return offset;
96 7a5ca864 bellard
}
97 7a5ca864 bellard
98 7a5ca864 bellard
static int tcp_socket_outgoing(const char *address, uint16_t port)
99 7a5ca864 bellard
{
100 7a5ca864 bellard
    int s;
101 7a5ca864 bellard
    struct in_addr in;
102 7a5ca864 bellard
    struct sockaddr_in addr;
103 7a5ca864 bellard
    int serrno;
104 7a5ca864 bellard
105 7a5ca864 bellard
    s = socket(PF_INET, SOCK_STREAM, 0);
106 7a5ca864 bellard
    if (s == -1) {
107 7a5ca864 bellard
        return -1;
108 7a5ca864 bellard
    }
109 7a5ca864 bellard
110 7a5ca864 bellard
    if (inet_aton(address, &in) == 0) {
111 7a5ca864 bellard
        struct hostent *ent;
112 7a5ca864 bellard
113 7a5ca864 bellard
        ent = gethostbyname(address);
114 7a5ca864 bellard
        if (ent == NULL) {
115 7a5ca864 bellard
            goto error;
116 7a5ca864 bellard
        }
117 7a5ca864 bellard
118 7a5ca864 bellard
        memcpy(&in, ent->h_addr, sizeof(in));
119 7a5ca864 bellard
    }
120 7a5ca864 bellard
121 7a5ca864 bellard
    addr.sin_family = AF_INET;
122 7a5ca864 bellard
    addr.sin_port = htons(port);
123 7a5ca864 bellard
    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
124 7a5ca864 bellard
125 7a5ca864 bellard
    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
126 7a5ca864 bellard
        goto error;
127 7a5ca864 bellard
    }
128 7a5ca864 bellard
129 7a5ca864 bellard
    return s;
130 7a5ca864 bellard
error:
131 7a5ca864 bellard
    serrno = errno;
132 7a5ca864 bellard
    close(s);
133 7a5ca864 bellard
    errno = serrno;
134 7a5ca864 bellard
    return -1;
135 7a5ca864 bellard
}
136 7a5ca864 bellard
137 7a5ca864 bellard
int tcp_socket_incoming(const char *address, uint16_t port)
138 7a5ca864 bellard
{
139 7a5ca864 bellard
    int s;
140 7a5ca864 bellard
    struct in_addr in;
141 7a5ca864 bellard
    struct sockaddr_in addr;
142 7a5ca864 bellard
    int serrno;
143 7a5ca864 bellard
    int opt;
144 7a5ca864 bellard
145 7a5ca864 bellard
    s = socket(PF_INET, SOCK_STREAM, 0);
146 7a5ca864 bellard
    if (s == -1) {
147 7a5ca864 bellard
        return -1;
148 7a5ca864 bellard
    }
149 7a5ca864 bellard
150 7a5ca864 bellard
    if (inet_aton(address, &in) == 0) {
151 7a5ca864 bellard
        struct hostent *ent;
152 7a5ca864 bellard
153 7a5ca864 bellard
        ent = gethostbyname(address);
154 7a5ca864 bellard
        if (ent == NULL) {
155 7a5ca864 bellard
            goto error;
156 7a5ca864 bellard
        }
157 7a5ca864 bellard
158 7a5ca864 bellard
        memcpy(&in, ent->h_addr, sizeof(in));
159 7a5ca864 bellard
    }
160 7a5ca864 bellard
161 7a5ca864 bellard
    addr.sin_family = AF_INET;
162 7a5ca864 bellard
    addr.sin_port = htons(port);
163 7a5ca864 bellard
    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
164 7a5ca864 bellard
165 7a5ca864 bellard
    opt = 1;
166 7a5ca864 bellard
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
167 7a5ca864 bellard
        goto error;
168 7a5ca864 bellard
    }
169 7a5ca864 bellard
170 7a5ca864 bellard
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
171 7a5ca864 bellard
        goto error;
172 7a5ca864 bellard
    }
173 7a5ca864 bellard
174 7a5ca864 bellard
    if (listen(s, 128) == -1) {
175 7a5ca864 bellard
        goto error;
176 7a5ca864 bellard
    }
177 7a5ca864 bellard
178 7a5ca864 bellard
    return s;
179 7a5ca864 bellard
error:
180 7a5ca864 bellard
    serrno = errno;
181 7a5ca864 bellard
    close(s);
182 7a5ca864 bellard
    errno = serrno;
183 7a5ca864 bellard
    return -1;
184 7a5ca864 bellard
}
185 7a5ca864 bellard
186 7a5ca864 bellard
/* Basic flow
187 7a5ca864 bellard

188 7a5ca864 bellard
   Server         Client
189 7a5ca864 bellard

190 7a5ca864 bellard
   Negotiate
191 7a5ca864 bellard
                  Request
192 7a5ca864 bellard
   Response
193 7a5ca864 bellard
                  Request
194 7a5ca864 bellard
   Response
195 7a5ca864 bellard
                  ...
196 7a5ca864 bellard
   ...
197 7a5ca864 bellard
                  Request (type == 2)
198 7a5ca864 bellard
*/
199 7a5ca864 bellard
200 7a5ca864 bellard
int nbd_negotiate(BlockDriverState *bs, int csock, off_t size)
201 7a5ca864 bellard
{
202 7a5ca864 bellard
        char buf[8 + 8 + 8 + 128];
203 7a5ca864 bellard
204 7a5ca864 bellard
        /* Negotiate
205 7a5ca864 bellard
           [ 0 ..   7]   passwd   ("NBDMAGIC")
206 7a5ca864 bellard
           [ 8 ..  15]   magic    (0x00420281861253)
207 7a5ca864 bellard
           [16 ..  23]   size
208 7a5ca864 bellard
           [24 .. 151]   reserved (0)
209 7a5ca864 bellard
         */
210 7a5ca864 bellard
211 7a5ca864 bellard
        TRACE("Beginning negotiation.");
212 7a5ca864 bellard
        memcpy(buf, "NBDMAGIC", 8);
213 7a5ca864 bellard
        cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
214 7a5ca864 bellard
        cpu_to_be64w((uint64_t*)(buf + 16), size);
215 7a5ca864 bellard
        memset(buf + 24, 0, 128);
216 7a5ca864 bellard
217 7a5ca864 bellard
        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
218 7a5ca864 bellard
                LOG("write failed");
219 7a5ca864 bellard
                errno = EINVAL;
220 7a5ca864 bellard
                return -1;
221 7a5ca864 bellard
        }
222 7a5ca864 bellard
223 7a5ca864 bellard
        TRACE("Negotation succeeded.");
224 7a5ca864 bellard
225 7a5ca864 bellard
        return 0;
226 7a5ca864 bellard
}
227 7a5ca864 bellard
228 7a5ca864 bellard
int nbd_receive_negotiate(int fd, int csock)
229 7a5ca864 bellard
{
230 7a5ca864 bellard
        char buf[8 + 8 + 8 + 128];
231 7a5ca864 bellard
        uint64_t magic;
232 7a5ca864 bellard
        off_t size;
233 7a5ca864 bellard
        size_t blocksize;
234 7a5ca864 bellard
235 7a5ca864 bellard
        TRACE("Receiving negotation.");
236 7a5ca864 bellard
237 7a5ca864 bellard
        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
238 7a5ca864 bellard
                LOG("read failed");
239 7a5ca864 bellard
                errno = EINVAL;
240 7a5ca864 bellard
                return -1;
241 7a5ca864 bellard
        }
242 7a5ca864 bellard
243 7a5ca864 bellard
        magic = be64_to_cpup((uint64_t*)(buf + 8));
244 7a5ca864 bellard
        size = be64_to_cpup((uint64_t*)(buf + 16));
245 7a5ca864 bellard
        blocksize = 1024;
246 7a5ca864 bellard
247 7a5ca864 bellard
        TRACE("Magic is %c%c%c%c%c%c%c%c",
248 7a5ca864 bellard
              isprint(buf[0]) ? buf[0] : '.',
249 7a5ca864 bellard
              isprint(buf[1]) ? buf[1] : '.',
250 7a5ca864 bellard
              isprint(buf[2]) ? buf[2] : '.',
251 7a5ca864 bellard
              isprint(buf[3]) ? buf[3] : '.',
252 7a5ca864 bellard
              isprint(buf[4]) ? buf[4] : '.',
253 7a5ca864 bellard
              isprint(buf[5]) ? buf[5] : '.',
254 7a5ca864 bellard
              isprint(buf[6]) ? buf[6] : '.',
255 7a5ca864 bellard
              isprint(buf[7]) ? buf[7] : '.');
256 7a5ca864 bellard
        TRACE("Magic is 0x%" PRIx64, magic);
257 7a5ca864 bellard
        TRACE("Size is %" PRIu64, size);
258 7a5ca864 bellard
259 7a5ca864 bellard
        if (memcmp(buf, "NBDMAGIC", 8) != 0) {
260 7a5ca864 bellard
                LOG("Invalid magic received");
261 7a5ca864 bellard
                errno = EINVAL;
262 7a5ca864 bellard
                return -1;
263 7a5ca864 bellard
        }
264 7a5ca864 bellard
265 7a5ca864 bellard
        TRACE("Checking magic");
266 7a5ca864 bellard
267 7a5ca864 bellard
        if (magic != 0x00420281861253LL) {
268 7a5ca864 bellard
                LOG("Bad magic received");
269 7a5ca864 bellard
                errno = EINVAL;
270 7a5ca864 bellard
                return -1;
271 7a5ca864 bellard
        }
272 7a5ca864 bellard
273 7a5ca864 bellard
        TRACE("Setting block size to %lu", (unsigned long)blocksize);
274 7a5ca864 bellard
275 7a5ca864 bellard
        if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
276 7a5ca864 bellard
                int serrno = errno;
277 7a5ca864 bellard
                LOG("Failed setting NBD block size");
278 7a5ca864 bellard
                errno = serrno;
279 7a5ca864 bellard
                return -1;
280 7a5ca864 bellard
        }
281 7a5ca864 bellard
282 7a5ca864 bellard
        TRACE("Setting size to %llu block(s)",
283 7a5ca864 bellard
              (unsigned long long)(size / blocksize));
284 7a5ca864 bellard
285 7a5ca864 bellard
        if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
286 7a5ca864 bellard
                int serrno = errno;
287 7a5ca864 bellard
                LOG("Failed setting size (in blocks)");
288 7a5ca864 bellard
                errno = serrno;
289 7a5ca864 bellard
                return -1;
290 7a5ca864 bellard
        }
291 7a5ca864 bellard
292 7a5ca864 bellard
        TRACE("Clearing NBD socket");
293 7a5ca864 bellard
294 7a5ca864 bellard
        if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
295 7a5ca864 bellard
                int serrno = errno;
296 7a5ca864 bellard
                LOG("Failed clearing NBD socket");
297 7a5ca864 bellard
                errno = serrno;
298 7a5ca864 bellard
                return -1;
299 7a5ca864 bellard
        }
300 7a5ca864 bellard
301 7a5ca864 bellard
        TRACE("Setting NBD socket");
302 7a5ca864 bellard
303 7a5ca864 bellard
        if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
304 7a5ca864 bellard
                int serrno = errno;
305 7a5ca864 bellard
                LOG("Failed to set NBD socket");
306 7a5ca864 bellard
                errno = serrno;
307 7a5ca864 bellard
                return -1;
308 7a5ca864 bellard
        }
309 7a5ca864 bellard
310 7a5ca864 bellard
        TRACE("Negotiation ended");
311 7a5ca864 bellard
312 7a5ca864 bellard
        return 0;
313 7a5ca864 bellard
}
314 7a5ca864 bellard
315 7a5ca864 bellard
int nbd_disconnect(int fd)
316 7a5ca864 bellard
{
317 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_QUE);
318 7a5ca864 bellard
        ioctl(fd, NBD_DISCONNECT);
319 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_SOCK);
320 7a5ca864 bellard
        return 0;
321 7a5ca864 bellard
}
322 7a5ca864 bellard
323 7a5ca864 bellard
int nbd_client(int fd, int csock)
324 7a5ca864 bellard
{
325 7a5ca864 bellard
        int ret;
326 7a5ca864 bellard
        int serrno;
327 7a5ca864 bellard
328 7a5ca864 bellard
        TRACE("Doing NBD loop");
329 7a5ca864 bellard
330 7a5ca864 bellard
        ret = ioctl(fd, NBD_DO_IT);
331 7a5ca864 bellard
        serrno = errno;
332 7a5ca864 bellard
333 7a5ca864 bellard
        TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
334 7a5ca864 bellard
335 7a5ca864 bellard
        TRACE("Clearing NBD queue");
336 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_QUE);
337 7a5ca864 bellard
338 7a5ca864 bellard
        TRACE("Clearing NBD socket");
339 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_SOCK);
340 7a5ca864 bellard
341 7a5ca864 bellard
        errno = serrno;
342 7a5ca864 bellard
        return ret;
343 7a5ca864 bellard
}
344 7a5ca864 bellard
345 7a5ca864 bellard
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly)
346 7a5ca864 bellard
{
347 7a5ca864 bellard
#ifndef _REENTRANT
348 7a5ca864 bellard
        static uint8_t data[1024 * 1024]; // keep this off of the stack
349 7a5ca864 bellard
#else
350 7a5ca864 bellard
        uint8_t data[1024 * 1024];
351 7a5ca864 bellard
#endif
352 7a5ca864 bellard
        uint8_t buf[4 + 4 + 8 + 8 + 4];
353 7a5ca864 bellard
        uint32_t magic;
354 7a5ca864 bellard
        uint32_t type;
355 7a5ca864 bellard
        uint64_t from;
356 7a5ca864 bellard
        uint32_t len;
357 7a5ca864 bellard
358 7a5ca864 bellard
        TRACE("Reading request.");
359 7a5ca864 bellard
360 7a5ca864 bellard
        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
361 7a5ca864 bellard
                LOG("read failed");
362 7a5ca864 bellard
                errno = EINVAL;
363 7a5ca864 bellard
                return -1;
364 7a5ca864 bellard
        }
365 7a5ca864 bellard
366 7a5ca864 bellard
        /* Request
367 7a5ca864 bellard
          [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
368 7a5ca864 bellard
          [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
369 7a5ca864 bellard
          [ 8 .. 15]   handle
370 7a5ca864 bellard
          [16 .. 23]   from
371 7a5ca864 bellard
          [24 .. 27]   len
372 7a5ca864 bellard
         */
373 7a5ca864 bellard
374 7a5ca864 bellard
        magic = be32_to_cpup((uint32_t*)buf);
375 7a5ca864 bellard
        type  = be32_to_cpup((uint32_t*)(buf + 4));
376 7a5ca864 bellard
        from  = be64_to_cpup((uint64_t*)(buf + 16));
377 7a5ca864 bellard
        len   = be32_to_cpup((uint32_t*)(buf + 24));
378 7a5ca864 bellard
379 7a5ca864 bellard
        TRACE("Got request: "
380 7a5ca864 bellard
              "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
381 7a5ca864 bellard
              magic, type, from, len);
382 7a5ca864 bellard
383 7a5ca864 bellard
384 7a5ca864 bellard
        if (magic != NBD_REQUEST_MAGIC) {
385 7a5ca864 bellard
                LOG("invalid magic (got 0x%x)", magic);
386 7a5ca864 bellard
                errno = EINVAL;
387 7a5ca864 bellard
                return -1;
388 7a5ca864 bellard
        }
389 7a5ca864 bellard
390 7a5ca864 bellard
        if (len > sizeof(data)) {
391 dcf3a079 ths
                LOG("len (%u) is larger than max len (%u)",
392 7a5ca864 bellard
                    len, sizeof(data));
393 7a5ca864 bellard
                errno = EINVAL;
394 7a5ca864 bellard
                return -1;
395 7a5ca864 bellard
        }
396 7a5ca864 bellard
397 7a5ca864 bellard
        if ((from + len) < from) {
398 7a5ca864 bellard
                LOG("integer overflow detected! "
399 7a5ca864 bellard
                    "you're probably being attacked");
400 7a5ca864 bellard
                errno = EINVAL;
401 7a5ca864 bellard
                return -1;
402 7a5ca864 bellard
        }
403 7a5ca864 bellard
404 7a5ca864 bellard
        if ((from + len) > size) {
405 7a5ca864 bellard
                LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
406 7a5ca864 bellard
                    ", Offset: %" PRIu64 "\n",
407 7a5ca864 bellard
                     from, len, size, dev_offset);
408 7a5ca864 bellard
                LOG("requested operation past EOF--bad client?");
409 7a5ca864 bellard
                errno = EINVAL;
410 7a5ca864 bellard
                return -1;
411 7a5ca864 bellard
        }
412 7a5ca864 bellard
413 7a5ca864 bellard
        /* Reply
414 7a5ca864 bellard
         [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
415 7a5ca864 bellard
         [ 4 ..  7]    error   (0 == no error)
416 7a5ca864 bellard
         [ 7 .. 15]    handle
417 7a5ca864 bellard
         */
418 7a5ca864 bellard
        cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
419 7a5ca864 bellard
        cpu_to_be32w((uint32_t*)(buf + 4), 0);
420 7a5ca864 bellard
421 7a5ca864 bellard
        TRACE("Decoding type");
422 7a5ca864 bellard
423 7a5ca864 bellard
        switch (type) {
424 7a5ca864 bellard
        case 0:
425 7a5ca864 bellard
                TRACE("Request type is READ");
426 7a5ca864 bellard
427 7a5ca864 bellard
                if (bdrv_read(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
428 7a5ca864 bellard
                        LOG("reading from file failed");
429 7a5ca864 bellard
                        errno = EINVAL;
430 7a5ca864 bellard
                        return -1;
431 7a5ca864 bellard
                }
432 7a5ca864 bellard
                *offset += len;
433 7a5ca864 bellard
434 7a5ca864 bellard
                TRACE("Read %u byte(s)", len);
435 7a5ca864 bellard
436 7a5ca864 bellard
                TRACE("Sending OK response");
437 7a5ca864 bellard
438 7a5ca864 bellard
                if (write_sync(csock, buf, 16) != 16) {
439 7a5ca864 bellard
                        LOG("writing to socket failed");
440 7a5ca864 bellard
                        errno = EINVAL;
441 7a5ca864 bellard
                        return -1;
442 7a5ca864 bellard
                }
443 7a5ca864 bellard
444 7a5ca864 bellard
                TRACE("Sending data to client");
445 7a5ca864 bellard
446 7a5ca864 bellard
                if (write_sync(csock, data, len) != len) {
447 7a5ca864 bellard
                        LOG("writing to socket failed");
448 7a5ca864 bellard
                        errno = EINVAL;
449 7a5ca864 bellard
                        return -1;
450 7a5ca864 bellard
                }
451 7a5ca864 bellard
                break;
452 7a5ca864 bellard
        case 1:
453 7a5ca864 bellard
                TRACE("Request type is WRITE");
454 7a5ca864 bellard
455 7a5ca864 bellard
                TRACE("Reading %u byte(s)", len);
456 7a5ca864 bellard
457 7a5ca864 bellard
                if (read_sync(csock, data, len) != len) {
458 7a5ca864 bellard
                        LOG("reading from socket failed");
459 7a5ca864 bellard
                        errno = EINVAL;
460 7a5ca864 bellard
                        return -1;
461 7a5ca864 bellard
                }
462 7a5ca864 bellard
463 7a5ca864 bellard
                if (readonly) {
464 7a5ca864 bellard
                        TRACE("Server is read-only, return error");
465 7a5ca864 bellard
466 7a5ca864 bellard
                        cpu_to_be32w((uint32_t*)(buf + 4), 1);
467 7a5ca864 bellard
                } else {
468 7a5ca864 bellard
                        TRACE("Writing to device");
469 7a5ca864 bellard
470 7a5ca864 bellard
                        if (bdrv_write(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
471 7a5ca864 bellard
                                LOG("writing to file failed");
472 7a5ca864 bellard
                                errno = EINVAL;
473 7a5ca864 bellard
                                return -1;
474 7a5ca864 bellard
                        }
475 7a5ca864 bellard
476 7a5ca864 bellard
                        *offset += len;
477 7a5ca864 bellard
                }
478 7a5ca864 bellard
479 7a5ca864 bellard
                TRACE("Sending response to client");
480 7a5ca864 bellard
481 7a5ca864 bellard
                if (write_sync(csock, buf, 16) != 16) {
482 7a5ca864 bellard
                        LOG("writing to socket failed");
483 7a5ca864 bellard
                        errno = EINVAL;
484 7a5ca864 bellard
                        return -1;
485 7a5ca864 bellard
                }
486 7a5ca864 bellard
                break;
487 7a5ca864 bellard
        case 2:
488 7a5ca864 bellard
                TRACE("Request type is DISCONNECT");
489 7a5ca864 bellard
                errno = 0;
490 7a5ca864 bellard
                return 1;
491 7a5ca864 bellard
        default:
492 7a5ca864 bellard
                LOG("invalid request type (%u) received", type);
493 7a5ca864 bellard
                errno = EINVAL;
494 7a5ca864 bellard
                return -1;
495 7a5ca864 bellard
        }
496 7a5ca864 bellard
497 7a5ca864 bellard
        TRACE("Request/Reply complete");
498 7a5ca864 bellard
499 7a5ca864 bellard
        return 0;
500 7a5ca864 bellard
}