Statistics
| Branch: | Revision:

root / nbd.c @ d6e58090

History | View | Annotate | Download (16.4 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 5dc2eec9 Andreas Färber
#if defined(__sun__) || defined(__HAIKU__)
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 5fe16888 Laurent Vivier
#define NBD_REPLY_SIZE                (4 + 4 + 8)
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 1d45f8b5 Laurent Vivier
#define NBD_OPT_EXPORT_NAME        (1 << 0)
67 1d45f8b5 Laurent Vivier
68 7a5ca864 bellard
/* That's all folks */
69 7a5ca864 bellard
70 75818250 ths
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
71 75818250 ths
#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
72 7a5ca864 bellard
73 75818250 ths
size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
74 7a5ca864 bellard
{
75 7a5ca864 bellard
    size_t offset = 0;
76 7a5ca864 bellard
77 7a5ca864 bellard
    while (offset < size) {
78 7a5ca864 bellard
        ssize_t len;
79 7a5ca864 bellard
80 7a5ca864 bellard
        if (do_read) {
81 03ff3ca3 aliguori
            len = recv(fd, buffer + offset, size - offset, 0);
82 7a5ca864 bellard
        } else {
83 03ff3ca3 aliguori
            len = send(fd, buffer + offset, size - offset, 0);
84 7a5ca864 bellard
        }
85 7a5ca864 bellard
86 03ff3ca3 aliguori
        if (len == -1)
87 03ff3ca3 aliguori
            errno = socket_error();
88 03ff3ca3 aliguori
89 7a5ca864 bellard
        /* recoverable error */
90 75818250 ths
        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
91 7a5ca864 bellard
            continue;
92 7a5ca864 bellard
        }
93 7a5ca864 bellard
94 7a5ca864 bellard
        /* eof */
95 7a5ca864 bellard
        if (len == 0) {
96 7a5ca864 bellard
            break;
97 7a5ca864 bellard
        }
98 7a5ca864 bellard
99 7a5ca864 bellard
        /* unrecoverable error */
100 7a5ca864 bellard
        if (len == -1) {
101 7a5ca864 bellard
            return 0;
102 7a5ca864 bellard
        }
103 7a5ca864 bellard
104 7a5ca864 bellard
        offset += len;
105 7a5ca864 bellard
    }
106 7a5ca864 bellard
107 7a5ca864 bellard
    return offset;
108 7a5ca864 bellard
}
109 7a5ca864 bellard
110 75818250 ths
int tcp_socket_outgoing(const char *address, uint16_t port)
111 7a5ca864 bellard
{
112 7a5ca864 bellard
    int s;
113 7a5ca864 bellard
    struct in_addr in;
114 7a5ca864 bellard
    struct sockaddr_in addr;
115 7a5ca864 bellard
116 7a5ca864 bellard
    s = socket(PF_INET, SOCK_STREAM, 0);
117 7a5ca864 bellard
    if (s == -1) {
118 7a5ca864 bellard
        return -1;
119 7a5ca864 bellard
    }
120 7a5ca864 bellard
121 7a5ca864 bellard
    if (inet_aton(address, &in) == 0) {
122 7a5ca864 bellard
        struct hostent *ent;
123 7a5ca864 bellard
124 7a5ca864 bellard
        ent = gethostbyname(address);
125 7a5ca864 bellard
        if (ent == NULL) {
126 7a5ca864 bellard
            goto error;
127 7a5ca864 bellard
        }
128 7a5ca864 bellard
129 7a5ca864 bellard
        memcpy(&in, ent->h_addr, sizeof(in));
130 7a5ca864 bellard
    }
131 7a5ca864 bellard
132 7a5ca864 bellard
    addr.sin_family = AF_INET;
133 7a5ca864 bellard
    addr.sin_port = htons(port);
134 7a5ca864 bellard
    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
135 7a5ca864 bellard
136 7a5ca864 bellard
    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
137 7a5ca864 bellard
        goto error;
138 7a5ca864 bellard
    }
139 7a5ca864 bellard
140 7a5ca864 bellard
    return s;
141 7a5ca864 bellard
error:
142 03ff3ca3 aliguori
    closesocket(s);
143 7a5ca864 bellard
    return -1;
144 7a5ca864 bellard
}
145 7a5ca864 bellard
146 7a5ca864 bellard
int tcp_socket_incoming(const char *address, uint16_t port)
147 7a5ca864 bellard
{
148 7a5ca864 bellard
    int s;
149 7a5ca864 bellard
    struct in_addr in;
150 7a5ca864 bellard
    struct sockaddr_in addr;
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 0a656f5f malc
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
175 0a656f5f malc
                   (const void *) &opt, sizeof(opt)) == -1) {
176 7a5ca864 bellard
        goto error;
177 7a5ca864 bellard
    }
178 7a5ca864 bellard
179 7a5ca864 bellard
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
180 7a5ca864 bellard
        goto error;
181 7a5ca864 bellard
    }
182 7a5ca864 bellard
183 7a5ca864 bellard
    if (listen(s, 128) == -1) {
184 7a5ca864 bellard
        goto error;
185 7a5ca864 bellard
    }
186 7a5ca864 bellard
187 7a5ca864 bellard
    return s;
188 7a5ca864 bellard
error:
189 03ff3ca3 aliguori
    closesocket(s);
190 7a5ca864 bellard
    return -1;
191 7a5ca864 bellard
}
192 7a5ca864 bellard
193 03ff3ca3 aliguori
#ifndef _WIN32
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
199 cd831bd7 ths
    s = socket(PF_UNIX, SOCK_STREAM, 0);
200 cd831bd7 ths
    if (s == -1) {
201 cd831bd7 ths
        return -1;
202 cd831bd7 ths
    }
203 cd831bd7 ths
204 cd831bd7 ths
    memset(&addr, 0, sizeof(addr));
205 cd831bd7 ths
    addr.sun_family = AF_UNIX;
206 cd831bd7 ths
    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
207 cd831bd7 ths
208 cd831bd7 ths
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
209 cd831bd7 ths
        goto error;
210 cd831bd7 ths
    }
211 cd831bd7 ths
212 cd831bd7 ths
    if (listen(s, 128) == -1) {
213 cd831bd7 ths
        goto error;
214 cd831bd7 ths
    }
215 cd831bd7 ths
216 cd831bd7 ths
    return s;
217 cd831bd7 ths
error:
218 03ff3ca3 aliguori
    closesocket(s);
219 cd831bd7 ths
    return -1;
220 cd831bd7 ths
}
221 cd831bd7 ths
222 cd831bd7 ths
int unix_socket_outgoing(const char *path)
223 cd831bd7 ths
{
224 cd831bd7 ths
    int s;
225 cd831bd7 ths
    struct sockaddr_un addr;
226 cd831bd7 ths
227 cd831bd7 ths
    s = socket(PF_UNIX, SOCK_STREAM, 0);
228 cd831bd7 ths
    if (s == -1) {
229 cd831bd7 ths
        return -1;
230 cd831bd7 ths
    }
231 cd831bd7 ths
232 cd831bd7 ths
    memset(&addr, 0, sizeof(addr));
233 cd831bd7 ths
    addr.sun_family = AF_UNIX;
234 cd831bd7 ths
    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
235 cd831bd7 ths
236 cd831bd7 ths
    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
237 cd831bd7 ths
        goto error;
238 cd831bd7 ths
    }
239 cd831bd7 ths
240 cd831bd7 ths
    return s;
241 cd831bd7 ths
error:
242 03ff3ca3 aliguori
    closesocket(s);
243 03ff3ca3 aliguori
    return -1;
244 03ff3ca3 aliguori
}
245 03ff3ca3 aliguori
#else
246 03ff3ca3 aliguori
int unix_socket_incoming(const char *path)
247 03ff3ca3 aliguori
{
248 03ff3ca3 aliguori
    errno = ENOTSUP;
249 cd831bd7 ths
    return -1;
250 cd831bd7 ths
}
251 cd831bd7 ths
252 03ff3ca3 aliguori
int unix_socket_outgoing(const char *path)
253 03ff3ca3 aliguori
{
254 03ff3ca3 aliguori
    errno = ENOTSUP;
255 03ff3ca3 aliguori
    return -1;
256 03ff3ca3 aliguori
}
257 03ff3ca3 aliguori
#endif
258 03ff3ca3 aliguori
259 cd831bd7 ths
260 7a5ca864 bellard
/* Basic flow
261 7a5ca864 bellard

262 7a5ca864 bellard
   Server         Client
263 7a5ca864 bellard

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