-int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly)
-{
-#ifndef _REENTRANT
- static uint8_t data[1024 * 1024]; // keep this off of the stack
-#else
- uint8_t data[1024 * 1024];
-#endif
- uint8_t buf[4 + 4 + 8 + 8 + 4];
- uint32_t magic;
- uint32_t type;
- uint64_t from;
- uint32_t len;
-
- TRACE("Reading request.");
-
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
- LOG("read failed");
- errno = EINVAL;
- return -1;
- }
-
- /* Request
- [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
- [ 4 .. 7] type (0 == READ, 1 == WRITE)
- [ 8 .. 15] handle
- [16 .. 23] from
- [24 .. 27] len
- */
-
- magic = be32_to_cpup((uint32_t*)buf);
- type = be32_to_cpup((uint32_t*)(buf + 4));
- from = be64_to_cpup((uint64_t*)(buf + 16));
- len = be32_to_cpup((uint32_t*)(buf + 24));
-
- TRACE("Got request: "
- "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
- magic, type, from, len);
-
-
- if (magic != NBD_REQUEST_MAGIC) {
- LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
- }
-
- if (len > sizeof(data)) {
- LOG("len (%u) is larger than max len (%lu)",
- len, (unsigned long)sizeof(data));
- errno = EINVAL;
- return -1;
- }
-
- if ((from + len) < from) {
- LOG("integer overflow detected! "
- "you're probably being attacked");
- errno = EINVAL;
- return -1;
- }
-
- if ((from + len) > size) {
- LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
- ", Offset: %" PRIu64 "\n",
- from, len, size, dev_offset);
- LOG("requested operation past EOF--bad client?");
- errno = EINVAL;
- return -1;
- }
-
- /* Reply
- [ 0 .. 3] magic (NBD_REPLY_MAGIC)
- [ 4 .. 7] error (0 == no error)
- [ 7 .. 15] handle
- */
- cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
- cpu_to_be32w((uint32_t*)(buf + 4), 0);
-
- TRACE("Decoding type");
-
- switch (type) {
- case 0:
- TRACE("Request type is READ");
-
- if (bdrv_read(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
- LOG("reading from file failed");
- errno = EINVAL;
- return -1;
- }
- *offset += len;
-
- TRACE("Read %u byte(s)", len);
-
- TRACE("Sending OK response");
-
- if (write_sync(csock, buf, 16) != 16) {
- LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
- }
-
- TRACE("Sending data to client");
-
- if (write_sync(csock, data, len) != len) {
- LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
- }
- break;
- case 1:
- TRACE("Request type is WRITE");
-
- TRACE("Reading %u byte(s)", len);
-
- if (read_sync(csock, data, len) != len) {
- LOG("reading from socket failed");
- errno = EINVAL;
- return -1;
- }
-
- if (readonly) {
- TRACE("Server is read-only, return error");
-
- cpu_to_be32w((uint32_t*)(buf + 4), 1);
- } else {
- TRACE("Writing to device");
-
- if (bdrv_write(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
- LOG("writing to file failed");
- errno = EINVAL;
- return -1;
- }
-
- *offset += len;
- }
-
- TRACE("Sending response to client");
-
- if (write_sync(csock, buf, 16) != 16) {
- LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
- }
- break;
- case 2:
- TRACE("Request type is DISCONNECT");
- errno = 0;
- return 1;
- default:
- LOG("invalid request type (%u) received", type);
- errno = EINVAL;
- return -1;
- }
-
- TRACE("Request/Reply complete");
-
- return 0;
+ reply.handle = request.handle;
+ reply.error = 0;
+
+ switch (request.type) {
+ case NBD_CMD_READ:
+ TRACE("Request type is READ");
+
+ if (bdrv_read(bs, (request.from + dev_offset) / 512,
+ data + NBD_REPLY_SIZE,
+ request.len / 512) == -1) {
+ LOG("reading from file failed");
+ errno = EINVAL;
+ return -1;
+ }
+ *offset += request.len;
+
+ TRACE("Read %u byte(s)", request.len);
+
+ /* Reply
+ [ 0 .. 3] magic (NBD_REPLY_MAGIC)
+ [ 4 .. 7] error (0 == no error)
+ [ 7 .. 15] handle
+ */
+
+ cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC);
+ cpu_to_be32w((uint32_t*)(data + 4), reply.error);
+ cpu_to_be64w((uint64_t*)(data + 8), reply.handle);
+
+ TRACE("Sending data to client");
+
+ if (write_sync(csock, data,
+ request.len + NBD_REPLY_SIZE) !=
+ request.len + NBD_REPLY_SIZE) {
+ LOG("writing to socket failed");
+ errno = EINVAL;
+ return -1;
+ }
+ break;
+ case NBD_CMD_WRITE:
+ TRACE("Request type is WRITE");
+
+ TRACE("Reading %u byte(s)", request.len);
+
+ if (read_sync(csock, data, request.len) != request.len) {
+ LOG("reading from socket failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (readonly) {
+ TRACE("Server is read-only, return error");
+ reply.error = 1;
+ } else {
+ TRACE("Writing to device");
+
+ if (bdrv_write(bs, (request.from + dev_offset) / 512,
+ data, request.len / 512) == -1) {
+ LOG("writing to file failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ *offset += request.len;
+ }
+
+ if (nbd_send_reply(csock, &reply) == -1)
+ return -1;
+ break;
+ case NBD_CMD_DISC:
+ TRACE("Request type is DISCONNECT");
+ errno = 0;
+ return 1;
+ default:
+ LOG("invalid request type (%u) received", request.type);
+ errno = EINVAL;
+ return -1;
+ }
+
+ TRACE("Request/Reply complete");
+
+ return 0;