Statistics
| Branch: | Revision:

root / nbd.c @ 616cbc78

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

260 7a5ca864 bellard
   Server         Client
261 7a5ca864 bellard

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