static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply, int len) { NBDClient *client = req->client; int csock = client->sock; ssize_t rc, ret; qemu_co_mutex_lock(&client->send_lock); qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, nbd_restart_write, client); client->send_coroutine = qemu_coroutine_self(); if (!len) { rc = nbd_send_reply(csock, reply); } else { socket_set_cork(csock, 1); rc = nbd_send_reply(csock, reply); if (rc >= 0) { ret = qemu_co_send(csock, req->data, len); if (ret != len) { rc = -EIO; } } socket_set_cork(csock, 0); } client->send_coroutine = NULL; qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, NULL, client); qemu_co_mutex_unlock(&client->send_lock); return rc; }
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly, uint8_t *data, int data_size) { struct nbd_request request; struct nbd_reply reply; TRACE("Reading request."); if (nbd_receive_request(csock, &request) == -1) return -1; if (request.len > data_size) { LOG("len (%u) is larger than max len (%u)", request.len, data_size); errno = EINVAL; return -1; } if ((request.from + request.len) < request.from) { LOG("integer overflow detected! " "you're probably being attacked"); errno = EINVAL; return -1; } if ((request.from + request.len) > size) { LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 ", Offset: %" PRIu64 "\n", request.from, request.len, (uint64_t)size, dev_offset); LOG("requested operation past EOF--bad client?"); errno = EINVAL; return -1; } TRACE("Decoding type"); 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, request.len / 512) == -1) { LOG("reading from file failed"); errno = EINVAL; return -1; } *offset += request.len; TRACE("Read %u byte(s)", request.len); if (nbd_send_reply(csock, &reply) == -1) return -1; TRACE("Sending data to client"); if (write_sync(csock, data, request.len) != request.len) { 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; }