Statistics
| Branch: | Revision:

root / nbd.c @ c1568af5

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

259 7a5ca864 bellard
   Server         Client
260 7a5ca864 bellard

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