Statistics
| Branch: | Revision:

root / nbd.c @ 63242a00

History | View | Annotate | Download (13.6 kB)

1 75818250 ths
/*
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 75818250 ths
 */
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 7e00eb9b aliguori
#ifdef __sun__
26 7e00eb9b aliguori
#include <sys/ioccom.h>
27 7e00eb9b aliguori
#endif
28 7a5ca864 bellard
#include <ctype.h>
29 7a5ca864 bellard
#include <inttypes.h>
30 7a5ca864 bellard
#include <sys/socket.h>
31 cd831bd7 ths
#include <sys/un.h>
32 7a5ca864 bellard
#include <netinet/in.h>
33 7a5ca864 bellard
#include <netinet/tcp.h>
34 7a5ca864 bellard
#include <arpa/inet.h>
35 7a5ca864 bellard
#include <netdb.h>
36 7a5ca864 bellard
37 75818250 ths
#if defined(QEMU_NBD)
38 7a5ca864 bellard
extern int verbose;
39 75818250 ths
#else
40 75818250 ths
static int verbose = 0;
41 75818250 ths
#endif
42 75818250 ths
43 75818250 ths
#define TRACE(msg, ...) do { \
44 75818250 ths
    if (verbose) LOG(msg, ## __VA_ARGS__); \
45 75818250 ths
} while(0)
46 7a5ca864 bellard
47 7a5ca864 bellard
#define LOG(msg, ...) do { \
48 7a5ca864 bellard
    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
49 7a5ca864 bellard
            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
50 7a5ca864 bellard
} while(0)
51 7a5ca864 bellard
52 7a5ca864 bellard
/* This is all part of the "official" NBD API */
53 7a5ca864 bellard
54 7a5ca864 bellard
#define NBD_REQUEST_MAGIC       0x25609513
55 7a5ca864 bellard
#define NBD_REPLY_MAGIC         0x67446698
56 7a5ca864 bellard
57 7a5ca864 bellard
#define NBD_SET_SOCK            _IO(0xab, 0)
58 7a5ca864 bellard
#define NBD_SET_BLKSIZE         _IO(0xab, 1)
59 7a5ca864 bellard
#define NBD_SET_SIZE            _IO(0xab, 2)
60 7a5ca864 bellard
#define NBD_DO_IT               _IO(0xab, 3)
61 7a5ca864 bellard
#define NBD_CLEAR_SOCK          _IO(0xab, 4)
62 7a5ca864 bellard
#define NBD_CLEAR_QUE           _IO(0xab, 5)
63 7a5ca864 bellard
#define NBD_PRINT_DEBUG                _IO(0xab, 6)
64 7a5ca864 bellard
#define NBD_SET_SIZE_BLOCKS        _IO(0xab, 7)
65 7a5ca864 bellard
#define NBD_DISCONNECT          _IO(0xab, 8)
66 7a5ca864 bellard
67 7a5ca864 bellard
/* That's all folks */
68 7a5ca864 bellard
69 75818250 ths
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
70 75818250 ths
#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
71 7a5ca864 bellard
72 75818250 ths
size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
73 7a5ca864 bellard
{
74 7a5ca864 bellard
    size_t offset = 0;
75 7a5ca864 bellard
76 7a5ca864 bellard
    while (offset < size) {
77 7a5ca864 bellard
        ssize_t len;
78 7a5ca864 bellard
79 7a5ca864 bellard
        if (do_read) {
80 7a5ca864 bellard
            len = read(fd, buffer + offset, size - offset);
81 7a5ca864 bellard
        } else {
82 7a5ca864 bellard
            len = write(fd, buffer + offset, size - offset);
83 7a5ca864 bellard
        }
84 7a5ca864 bellard
85 7a5ca864 bellard
        /* recoverable error */
86 75818250 ths
        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
87 7a5ca864 bellard
            continue;
88 7a5ca864 bellard
        }
89 7a5ca864 bellard
90 7a5ca864 bellard
        /* eof */
91 7a5ca864 bellard
        if (len == 0) {
92 7a5ca864 bellard
            break;
93 7a5ca864 bellard
        }
94 7a5ca864 bellard
95 7a5ca864 bellard
        /* unrecoverable error */
96 7a5ca864 bellard
        if (len == -1) {
97 7a5ca864 bellard
            return 0;
98 7a5ca864 bellard
        }
99 7a5ca864 bellard
100 7a5ca864 bellard
        offset += len;
101 7a5ca864 bellard
    }
102 7a5ca864 bellard
103 7a5ca864 bellard
    return offset;
104 7a5ca864 bellard
}
105 7a5ca864 bellard
106 75818250 ths
int tcp_socket_outgoing(const char *address, uint16_t port)
107 7a5ca864 bellard
{
108 7a5ca864 bellard
    int s;
109 7a5ca864 bellard
    struct in_addr in;
110 7a5ca864 bellard
    struct sockaddr_in addr;
111 7a5ca864 bellard
    int serrno;
112 7a5ca864 bellard
113 7a5ca864 bellard
    s = socket(PF_INET, SOCK_STREAM, 0);
114 7a5ca864 bellard
    if (s == -1) {
115 7a5ca864 bellard
        return -1;
116 7a5ca864 bellard
    }
117 7a5ca864 bellard
118 7a5ca864 bellard
    if (inet_aton(address, &in) == 0) {
119 7a5ca864 bellard
        struct hostent *ent;
120 7a5ca864 bellard
121 7a5ca864 bellard
        ent = gethostbyname(address);
122 7a5ca864 bellard
        if (ent == NULL) {
123 7a5ca864 bellard
            goto error;
124 7a5ca864 bellard
        }
125 7a5ca864 bellard
126 7a5ca864 bellard
        memcpy(&in, ent->h_addr, sizeof(in));
127 7a5ca864 bellard
    }
128 7a5ca864 bellard
129 7a5ca864 bellard
    addr.sin_family = AF_INET;
130 7a5ca864 bellard
    addr.sin_port = htons(port);
131 7a5ca864 bellard
    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
132 7a5ca864 bellard
133 7a5ca864 bellard
    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
134 7a5ca864 bellard
        goto error;
135 7a5ca864 bellard
    }
136 7a5ca864 bellard
137 7a5ca864 bellard
    return s;
138 7a5ca864 bellard
error:
139 7a5ca864 bellard
    serrno = errno;
140 7a5ca864 bellard
    close(s);
141 7a5ca864 bellard
    errno = serrno;
142 7a5ca864 bellard
    return -1;
143 7a5ca864 bellard
}
144 7a5ca864 bellard
145 7a5ca864 bellard
int tcp_socket_incoming(const char *address, uint16_t port)
146 7a5ca864 bellard
{
147 7a5ca864 bellard
    int s;
148 7a5ca864 bellard
    struct in_addr in;
149 7a5ca864 bellard
    struct sockaddr_in addr;
150 7a5ca864 bellard
    int serrno;
151 7a5ca864 bellard
    int opt;
152 7a5ca864 bellard
153 7a5ca864 bellard
    s = socket(PF_INET, SOCK_STREAM, 0);
154 7a5ca864 bellard
    if (s == -1) {
155 7a5ca864 bellard
        return -1;
156 7a5ca864 bellard
    }
157 7a5ca864 bellard
158 7a5ca864 bellard
    if (inet_aton(address, &in) == 0) {
159 7a5ca864 bellard
        struct hostent *ent;
160 7a5ca864 bellard
161 7a5ca864 bellard
        ent = gethostbyname(address);
162 7a5ca864 bellard
        if (ent == NULL) {
163 7a5ca864 bellard
            goto error;
164 7a5ca864 bellard
        }
165 7a5ca864 bellard
166 7a5ca864 bellard
        memcpy(&in, ent->h_addr, sizeof(in));
167 7a5ca864 bellard
    }
168 7a5ca864 bellard
169 7a5ca864 bellard
    addr.sin_family = AF_INET;
170 7a5ca864 bellard
    addr.sin_port = htons(port);
171 7a5ca864 bellard
    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
172 7a5ca864 bellard
173 7a5ca864 bellard
    opt = 1;
174 7a5ca864 bellard
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
175 7a5ca864 bellard
        goto error;
176 7a5ca864 bellard
    }
177 7a5ca864 bellard
178 7a5ca864 bellard
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
179 7a5ca864 bellard
        goto error;
180 7a5ca864 bellard
    }
181 7a5ca864 bellard
182 7a5ca864 bellard
    if (listen(s, 128) == -1) {
183 7a5ca864 bellard
        goto error;
184 7a5ca864 bellard
    }
185 7a5ca864 bellard
186 7a5ca864 bellard
    return s;
187 7a5ca864 bellard
error:
188 7a5ca864 bellard
    serrno = errno;
189 7a5ca864 bellard
    close(s);
190 7a5ca864 bellard
    errno = serrno;
191 7a5ca864 bellard
    return -1;
192 7a5ca864 bellard
}
193 7a5ca864 bellard
194 cd831bd7 ths
int unix_socket_incoming(const char *path)
195 cd831bd7 ths
{
196 cd831bd7 ths
    int s;
197 cd831bd7 ths
    struct sockaddr_un addr;
198 cd831bd7 ths
    int serrno;
199 cd831bd7 ths
200 cd831bd7 ths
    s = socket(PF_UNIX, SOCK_STREAM, 0);
201 cd831bd7 ths
    if (s == -1) {
202 cd831bd7 ths
        return -1;
203 cd831bd7 ths
    }
204 cd831bd7 ths
205 cd831bd7 ths
    memset(&addr, 0, sizeof(addr));
206 cd831bd7 ths
    addr.sun_family = AF_UNIX;
207 cd831bd7 ths
    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
208 cd831bd7 ths
209 cd831bd7 ths
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
210 cd831bd7 ths
        goto error;
211 cd831bd7 ths
    }
212 cd831bd7 ths
213 cd831bd7 ths
    if (listen(s, 128) == -1) {
214 cd831bd7 ths
        goto error;
215 cd831bd7 ths
    }
216 cd831bd7 ths
217 cd831bd7 ths
    return s;
218 cd831bd7 ths
error:
219 cd831bd7 ths
    serrno = errno;
220 cd831bd7 ths
    close(s);
221 cd831bd7 ths
    errno = serrno;
222 cd831bd7 ths
    return -1;
223 cd831bd7 ths
}
224 cd831bd7 ths
225 cd831bd7 ths
int unix_socket_outgoing(const char *path)
226 cd831bd7 ths
{
227 cd831bd7 ths
    int s;
228 cd831bd7 ths
    struct sockaddr_un addr;
229 cd831bd7 ths
    int serrno;
230 cd831bd7 ths
231 cd831bd7 ths
    s = socket(PF_UNIX, SOCK_STREAM, 0);
232 cd831bd7 ths
    if (s == -1) {
233 cd831bd7 ths
        return -1;
234 cd831bd7 ths
    }
235 cd831bd7 ths
236 cd831bd7 ths
    memset(&addr, 0, sizeof(addr));
237 cd831bd7 ths
    addr.sun_family = AF_UNIX;
238 cd831bd7 ths
    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
239 cd831bd7 ths
240 cd831bd7 ths
    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
241 cd831bd7 ths
        goto error;
242 cd831bd7 ths
    }
243 cd831bd7 ths
244 cd831bd7 ths
    return s;
245 cd831bd7 ths
error:
246 cd831bd7 ths
    serrno = errno;
247 cd831bd7 ths
    close(s);
248 cd831bd7 ths
    errno = serrno;
249 cd831bd7 ths
    return -1;
250 cd831bd7 ths
}
251 cd831bd7 ths
252 cd831bd7 ths
253 7a5ca864 bellard
/* Basic flow
254 7a5ca864 bellard

255 7a5ca864 bellard
   Server         Client
256 7a5ca864 bellard

257 7a5ca864 bellard
   Negotiate
258 7a5ca864 bellard
                  Request
259 7a5ca864 bellard
   Response
260 7a5ca864 bellard
                  Request
261 7a5ca864 bellard
   Response
262 7a5ca864 bellard
                  ...
263 7a5ca864 bellard
   ...
264 7a5ca864 bellard
                  Request (type == 2)
265 7a5ca864 bellard
*/
266 7a5ca864 bellard
267 27982661 aliguori
int nbd_negotiate(int csock, off_t size)
268 7a5ca864 bellard
{
269 7a5ca864 bellard
        char buf[8 + 8 + 8 + 128];
270 7a5ca864 bellard
271 7a5ca864 bellard
        /* Negotiate
272 7a5ca864 bellard
           [ 0 ..   7]   passwd   ("NBDMAGIC")
273 7a5ca864 bellard
           [ 8 ..  15]   magic    (0x00420281861253)
274 7a5ca864 bellard
           [16 ..  23]   size
275 7a5ca864 bellard
           [24 .. 151]   reserved (0)
276 7a5ca864 bellard
         */
277 7a5ca864 bellard
278 7a5ca864 bellard
        TRACE("Beginning negotiation.");
279 7a5ca864 bellard
        memcpy(buf, "NBDMAGIC", 8);
280 7a5ca864 bellard
        cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
281 7a5ca864 bellard
        cpu_to_be64w((uint64_t*)(buf + 16), size);
282 7a5ca864 bellard
        memset(buf + 24, 0, 128);
283 7a5ca864 bellard
284 7a5ca864 bellard
        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
285 7a5ca864 bellard
                LOG("write failed");
286 7a5ca864 bellard
                errno = EINVAL;
287 7a5ca864 bellard
                return -1;
288 7a5ca864 bellard
        }
289 7a5ca864 bellard
290 7a5ca864 bellard
        TRACE("Negotation succeeded.");
291 7a5ca864 bellard
292 7a5ca864 bellard
        return 0;
293 7a5ca864 bellard
}
294 7a5ca864 bellard
295 cd831bd7 ths
int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
296 7a5ca864 bellard
{
297 7a5ca864 bellard
        char buf[8 + 8 + 8 + 128];
298 7a5ca864 bellard
        uint64_t magic;
299 7a5ca864 bellard
300 7a5ca864 bellard
        TRACE("Receiving negotation.");
301 7a5ca864 bellard
302 7a5ca864 bellard
        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
303 7a5ca864 bellard
                LOG("read failed");
304 7a5ca864 bellard
                errno = EINVAL;
305 7a5ca864 bellard
                return -1;
306 7a5ca864 bellard
        }
307 7a5ca864 bellard
308 7a5ca864 bellard
        magic = be64_to_cpup((uint64_t*)(buf + 8));
309 cd831bd7 ths
        *size = be64_to_cpup((uint64_t*)(buf + 16));
310 cd831bd7 ths
        *blocksize = 1024;
311 7a5ca864 bellard
312 7a5ca864 bellard
        TRACE("Magic is %c%c%c%c%c%c%c%c",
313 7a5ca864 bellard
              isprint(buf[0]) ? buf[0] : '.',
314 7a5ca864 bellard
              isprint(buf[1]) ? buf[1] : '.',
315 7a5ca864 bellard
              isprint(buf[2]) ? buf[2] : '.',
316 7a5ca864 bellard
              isprint(buf[3]) ? buf[3] : '.',
317 7a5ca864 bellard
              isprint(buf[4]) ? buf[4] : '.',
318 7a5ca864 bellard
              isprint(buf[5]) ? buf[5] : '.',
319 7a5ca864 bellard
              isprint(buf[6]) ? buf[6] : '.',
320 7a5ca864 bellard
              isprint(buf[7]) ? buf[7] : '.');
321 7a5ca864 bellard
        TRACE("Magic is 0x%" PRIx64, magic);
322 cd831bd7 ths
        TRACE("Size is %" PRIu64, *size);
323 7a5ca864 bellard
324 7a5ca864 bellard
        if (memcmp(buf, "NBDMAGIC", 8) != 0) {
325 7a5ca864 bellard
                LOG("Invalid magic received");
326 7a5ca864 bellard
                errno = EINVAL;
327 7a5ca864 bellard
                return -1;
328 7a5ca864 bellard
        }
329 7a5ca864 bellard
330 7a5ca864 bellard
        TRACE("Checking magic");
331 7a5ca864 bellard
332 7a5ca864 bellard
        if (magic != 0x00420281861253LL) {
333 7a5ca864 bellard
                LOG("Bad magic received");
334 7a5ca864 bellard
                errno = EINVAL;
335 7a5ca864 bellard
                return -1;
336 7a5ca864 bellard
        }
337 cd831bd7 ths
        return 0;
338 cd831bd7 ths
}
339 7a5ca864 bellard
340 cd831bd7 ths
int nbd_init(int fd, int csock, off_t size, size_t blocksize)
341 cd831bd7 ths
{
342 7a5ca864 bellard
        TRACE("Setting block size to %lu", (unsigned long)blocksize);
343 7a5ca864 bellard
344 7a5ca864 bellard
        if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
345 7a5ca864 bellard
                int serrno = errno;
346 7a5ca864 bellard
                LOG("Failed setting NBD block size");
347 7a5ca864 bellard
                errno = serrno;
348 7a5ca864 bellard
                return -1;
349 7a5ca864 bellard
        }
350 7a5ca864 bellard
351 7a5ca864 bellard
        TRACE("Setting size to %llu block(s)",
352 7a5ca864 bellard
              (unsigned long long)(size / blocksize));
353 7a5ca864 bellard
354 7a5ca864 bellard
        if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
355 7a5ca864 bellard
                int serrno = errno;
356 7a5ca864 bellard
                LOG("Failed setting size (in blocks)");
357 7a5ca864 bellard
                errno = serrno;
358 7a5ca864 bellard
                return -1;
359 7a5ca864 bellard
        }
360 7a5ca864 bellard
361 7a5ca864 bellard
        TRACE("Clearing NBD socket");
362 7a5ca864 bellard
363 7a5ca864 bellard
        if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
364 7a5ca864 bellard
                int serrno = errno;
365 7a5ca864 bellard
                LOG("Failed clearing NBD socket");
366 7a5ca864 bellard
                errno = serrno;
367 7a5ca864 bellard
                return -1;
368 7a5ca864 bellard
        }
369 7a5ca864 bellard
370 7a5ca864 bellard
        TRACE("Setting NBD socket");
371 7a5ca864 bellard
372 7a5ca864 bellard
        if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
373 7a5ca864 bellard
                int serrno = errno;
374 7a5ca864 bellard
                LOG("Failed to set NBD socket");
375 7a5ca864 bellard
                errno = serrno;
376 7a5ca864 bellard
                return -1;
377 7a5ca864 bellard
        }
378 7a5ca864 bellard
379 7a5ca864 bellard
        TRACE("Negotiation ended");
380 7a5ca864 bellard
381 7a5ca864 bellard
        return 0;
382 7a5ca864 bellard
}
383 7a5ca864 bellard
384 7a5ca864 bellard
int nbd_disconnect(int fd)
385 7a5ca864 bellard
{
386 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_QUE);
387 7a5ca864 bellard
        ioctl(fd, NBD_DISCONNECT);
388 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_SOCK);
389 7a5ca864 bellard
        return 0;
390 7a5ca864 bellard
}
391 7a5ca864 bellard
392 7a5ca864 bellard
int nbd_client(int fd, int csock)
393 7a5ca864 bellard
{
394 7a5ca864 bellard
        int ret;
395 7a5ca864 bellard
        int serrno;
396 7a5ca864 bellard
397 7a5ca864 bellard
        TRACE("Doing NBD loop");
398 7a5ca864 bellard
399 7a5ca864 bellard
        ret = ioctl(fd, NBD_DO_IT);
400 7a5ca864 bellard
        serrno = errno;
401 7a5ca864 bellard
402 7a5ca864 bellard
        TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
403 7a5ca864 bellard
404 7a5ca864 bellard
        TRACE("Clearing NBD queue");
405 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_QUE);
406 7a5ca864 bellard
407 7a5ca864 bellard
        TRACE("Clearing NBD socket");
408 7a5ca864 bellard
        ioctl(fd, NBD_CLEAR_SOCK);
409 7a5ca864 bellard
410 7a5ca864 bellard
        errno = serrno;
411 7a5ca864 bellard
        return ret;
412 7a5ca864 bellard
}
413 7a5ca864 bellard
414 75818250 ths
int nbd_send_request(int csock, struct nbd_request *request)
415 7a5ca864 bellard
{
416 7a5ca864 bellard
        uint8_t buf[4 + 4 + 8 + 8 + 4];
417 7a5ca864 bellard
418 75818250 ths
        cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
419 75818250 ths
        cpu_to_be32w((uint32_t*)(buf + 4), request->type);
420 75818250 ths
        cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
421 75818250 ths
        cpu_to_be64w((uint64_t*)(buf + 16), request->from);
422 75818250 ths
        cpu_to_be32w((uint32_t*)(buf + 24), request->len);
423 75818250 ths
424 75818250 ths
        TRACE("Sending request to client");
425 75818250 ths
426 75818250 ths
        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
427 75818250 ths
                LOG("writing to socket failed");
428 75818250 ths
                errno = EINVAL;
429 75818250 ths
                return -1;
430 75818250 ths
        }
431 75818250 ths
        return 0;
432 75818250 ths
}
433 75818250 ths
434 75818250 ths
435 75818250 ths
static int nbd_receive_request(int csock, struct nbd_request *request)
436 75818250 ths
{
437 75818250 ths
        uint8_t buf[4 + 4 + 8 + 8 + 4];
438 75818250 ths
        uint32_t magic;
439 7a5ca864 bellard
440 7a5ca864 bellard
        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
441 7a5ca864 bellard
                LOG("read failed");
442 7a5ca864 bellard
                errno = EINVAL;
443 7a5ca864 bellard
                return -1;
444 7a5ca864 bellard
        }
445 7a5ca864 bellard
446 7a5ca864 bellard
        /* Request
447 75818250 ths
           [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
448 75818250 ths
           [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
449 75818250 ths
           [ 8 .. 15]   handle
450 75818250 ths
           [16 .. 23]   from
451 75818250 ths
           [24 .. 27]   len
452 7a5ca864 bellard
         */
453 7a5ca864 bellard
454 7a5ca864 bellard
        magic = be32_to_cpup((uint32_t*)buf);
455 75818250 ths
        request->type  = be32_to_cpup((uint32_t*)(buf + 4));
456 75818250 ths
        request->handle = be64_to_cpup((uint64_t*)(buf + 8));
457 75818250 ths
        request->from  = be64_to_cpup((uint64_t*)(buf + 16));
458 75818250 ths
        request->len   = be32_to_cpup((uint32_t*)(buf + 24));
459 7a5ca864 bellard
460 7a5ca864 bellard
        TRACE("Got request: "
461 7a5ca864 bellard
              "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
462 75818250 ths
              magic, request->type, request->from, request->len);
463 7a5ca864 bellard
464 7a5ca864 bellard
        if (magic != NBD_REQUEST_MAGIC) {
465 7a5ca864 bellard
                LOG("invalid magic (got 0x%x)", magic);
466 7a5ca864 bellard
                errno = EINVAL;
467 7a5ca864 bellard
                return -1;
468 7a5ca864 bellard
        }
469 d94888e3 malc
        return 0;
470 75818250 ths
}
471 75818250 ths
472 75818250 ths
int nbd_receive_reply(int csock, struct nbd_reply *reply)
473 75818250 ths
{
474 75818250 ths
        uint8_t buf[4 + 4 + 8];
475 75818250 ths
        uint32_t magic;
476 75818250 ths
477 75818250 ths
        memset(buf, 0xAA, sizeof(buf));
478 75818250 ths
479 75818250 ths
        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
480 75818250 ths
                LOG("read failed");
481 75818250 ths
                errno = EINVAL;
482 75818250 ths
                return -1;
483 75818250 ths
        }
484 75818250 ths
485 75818250 ths
        /* Reply
486 75818250 ths
           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
487 75818250 ths
           [ 4 ..  7]    error   (0 == no error)
488 75818250 ths
           [ 7 .. 15]    handle
489 75818250 ths
         */
490 75818250 ths
491 75818250 ths
        magic = be32_to_cpup((uint32_t*)buf);
492 75818250 ths
        reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
493 75818250 ths
        reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
494 75818250 ths
495 75818250 ths
        TRACE("Got reply: "
496 75818250 ths
              "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
497 75818250 ths
              magic, reply->error, reply->handle);
498 75818250 ths
499 75818250 ths
        if (magic != NBD_REPLY_MAGIC) {
500 75818250 ths
                LOG("invalid magic (got 0x%x)", magic);
501 75818250 ths
                errno = EINVAL;
502 75818250 ths
                return -1;
503 75818250 ths
        }
504 75818250 ths
        return 0;
505 75818250 ths
}
506 75818250 ths
507 75818250 ths
static int nbd_send_reply(int csock, struct nbd_reply *reply)
508 75818250 ths
{
509 75818250 ths
        uint8_t buf[4 + 4 + 8];
510 75818250 ths
511 75818250 ths
        /* Reply
512 75818250 ths
           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
513 75818250 ths
           [ 4 ..  7]    error   (0 == no error)
514 75818250 ths
           [ 7 .. 15]    handle
515 75818250 ths
         */
516 75818250 ths
        cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
517 75818250 ths
        cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
518 75818250 ths
        cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
519 75818250 ths
520 75818250 ths
        TRACE("Sending response to client");
521 75818250 ths
522 75818250 ths
        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
523 75818250 ths
                LOG("writing to socket failed");
524 75818250 ths
                errno = EINVAL;
525 75818250 ths
                return -1;
526 75818250 ths
        }
527 75818250 ths
        return 0;
528 75818250 ths
}
529 7a5ca864 bellard
530 75818250 ths
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
531 75818250 ths
             off_t *offset, bool readonly, uint8_t *data, int data_size)
532 75818250 ths
{
533 75818250 ths
        struct nbd_request request;
534 75818250 ths
        struct nbd_reply reply;
535 75818250 ths
536 75818250 ths
        TRACE("Reading request.");
537 75818250 ths
538 75818250 ths
        if (nbd_receive_request(csock, &request) == -1)
539 75818250 ths
                return -1;
540 75818250 ths
541 75818250 ths
        if (request.len > data_size) {
542 2f726488 ths
                LOG("len (%u) is larger than max len (%u)",
543 75818250 ths
                    request.len, data_size);
544 7a5ca864 bellard
                errno = EINVAL;
545 7a5ca864 bellard
                return -1;
546 7a5ca864 bellard
        }
547 7a5ca864 bellard
548 75818250 ths
        if ((request.from + request.len) < request.from) {
549 7a5ca864 bellard
                LOG("integer overflow detected! "
550 7a5ca864 bellard
                    "you're probably being attacked");
551 7a5ca864 bellard
                errno = EINVAL;
552 7a5ca864 bellard
                return -1;
553 7a5ca864 bellard
        }
554 7a5ca864 bellard
555 75818250 ths
        if ((request.from + request.len) > size) {
556 7a5ca864 bellard
                LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
557 7a5ca864 bellard
                    ", Offset: %" PRIu64 "\n",
558 75818250 ths
                     request.from, request.len, size, dev_offset);
559 7a5ca864 bellard
                LOG("requested operation past EOF--bad client?");
560 7a5ca864 bellard
                errno = EINVAL;
561 7a5ca864 bellard
                return -1;
562 7a5ca864 bellard
        }
563 7a5ca864 bellard
564 7a5ca864 bellard
        TRACE("Decoding type");
565 7a5ca864 bellard
566 75818250 ths
        reply.handle = request.handle;
567 75818250 ths
        reply.error = 0;
568 75818250 ths
569 75818250 ths
        switch (request.type) {
570 75818250 ths
        case NBD_CMD_READ:
571 7a5ca864 bellard
                TRACE("Request type is READ");
572 7a5ca864 bellard
573 75818250 ths
                if (bdrv_read(bs, (request.from + dev_offset) / 512, data,
574 75818250 ths
                              request.len / 512) == -1) {
575 7a5ca864 bellard
                        LOG("reading from file failed");
576 7a5ca864 bellard
                        errno = EINVAL;
577 7a5ca864 bellard
                        return -1;
578 7a5ca864 bellard
                }
579 75818250 ths
                *offset += request.len;
580 7a5ca864 bellard
581 75818250 ths
                TRACE("Read %u byte(s)", request.len);
582 7a5ca864 bellard
583 75818250 ths
                if (nbd_send_reply(csock, &reply) == -1)
584 7a5ca864 bellard
                        return -1;
585 7a5ca864 bellard
586 7a5ca864 bellard
                TRACE("Sending data to client");
587 7a5ca864 bellard
588 75818250 ths
                if (write_sync(csock, data, request.len) != request.len) {
589 7a5ca864 bellard
                        LOG("writing to socket failed");
590 7a5ca864 bellard
                        errno = EINVAL;
591 7a5ca864 bellard
                        return -1;
592 7a5ca864 bellard
                }
593 7a5ca864 bellard
                break;
594 75818250 ths
        case NBD_CMD_WRITE:
595 7a5ca864 bellard
                TRACE("Request type is WRITE");
596 7a5ca864 bellard
597 75818250 ths
                TRACE("Reading %u byte(s)", request.len);
598 7a5ca864 bellard
599 75818250 ths
                if (read_sync(csock, data, request.len) != request.len) {
600 7a5ca864 bellard
                        LOG("reading from socket failed");
601 7a5ca864 bellard
                        errno = EINVAL;
602 7a5ca864 bellard
                        return -1;
603 7a5ca864 bellard
                }
604 7a5ca864 bellard
605 7a5ca864 bellard
                if (readonly) {
606 7a5ca864 bellard
                        TRACE("Server is read-only, return error");
607 75818250 ths
                        reply.error = 1;
608 7a5ca864 bellard
                } else {
609 7a5ca864 bellard
                        TRACE("Writing to device");
610 7a5ca864 bellard
611 75818250 ths
                        if (bdrv_write(bs, (request.from + dev_offset) / 512,
612 75818250 ths
                                       data, request.len / 512) == -1) {
613 7a5ca864 bellard
                                LOG("writing to file failed");
614 7a5ca864 bellard
                                errno = EINVAL;
615 7a5ca864 bellard
                                return -1;
616 7a5ca864 bellard
                        }
617 7a5ca864 bellard
618 75818250 ths
                        *offset += request.len;
619 7a5ca864 bellard
                }
620 7a5ca864 bellard
621 75818250 ths
                if (nbd_send_reply(csock, &reply) == -1)
622 7a5ca864 bellard
                        return -1;
623 7a5ca864 bellard
                break;
624 75818250 ths
        case NBD_CMD_DISC:
625 7a5ca864 bellard
                TRACE("Request type is DISCONNECT");
626 7a5ca864 bellard
                errno = 0;
627 7a5ca864 bellard
                return 1;
628 7a5ca864 bellard
        default:
629 75818250 ths
                LOG("invalid request type (%u) received", request.type);
630 7a5ca864 bellard
                errno = EINVAL;
631 7a5ca864 bellard
                return -1;
632 7a5ca864 bellard
        }
633 7a5ca864 bellard
634 7a5ca864 bellard
        TRACE("Request/Reply complete");
635 7a5ca864 bellard
636 7a5ca864 bellard
        return 0;
637 7a5ca864 bellard
}